1 // SPDX-License-Identifier: MIT
2 /*
3  * Utility functions for the 'fsverity' program
4  *
5  * Copyright 2018 Google LLC
6  *
7  * Use of this source code is governed by an MIT-style
8  * license that can be found in the LICENSE file or at
9  * https://opensource.org/licenses/MIT.
10  */
11 
12 #include "utils.h"
13 
14 #include <errno.h>
15 #include <fcntl.h>
16 #include <limits.h>
17 #include <stdarg.h>
18 #include <sys/stat.h>
19 #include <unistd.h>
20 
21 /* ========== Memory allocation ========== */
22 
xmalloc(size_t size)23 void *xmalloc(size_t size)
24 {
25 	void *p = malloc(size);
26 
27 	if (!p)
28 		fatal_error("out of memory");
29 	return p;
30 }
31 
xzalloc(size_t size)32 void *xzalloc(size_t size)
33 {
34 	return memset(xmalloc(size), 0, size);
35 }
36 
xmemdup(const void * mem,size_t size)37 void *xmemdup(const void *mem, size_t size)
38 {
39 	return memcpy(xmalloc(size), mem, size);
40 }
41 
xstrdup(const char * s)42 char *xstrdup(const char *s)
43 {
44 	return xmemdup(s, strlen(s) + 1);
45 }
46 
47 /* ========== Error messages and assertions ========== */
48 
do_error_msg(const char * format,va_list va,int err)49 static void do_error_msg(const char *format, va_list va, int err)
50 {
51 	fputs("ERROR: ", stderr);
52 	vfprintf(stderr, format, va);
53 	if (err)
54 		fprintf(stderr, ": %s", strerror(err));
55 	putc('\n', stderr);
56 }
57 
error_msg(const char * format,...)58 void error_msg(const char *format, ...)
59 {
60 	va_list va;
61 
62 	va_start(va, format);
63 	do_error_msg(format, va, 0);
64 	va_end(va);
65 }
66 
error_msg_errno(const char * format,...)67 void error_msg_errno(const char *format, ...)
68 {
69 	va_list va;
70 
71 	va_start(va, format);
72 	do_error_msg(format, va, errno);
73 	va_end(va);
74 }
75 
fatal_error(const char * format,...)76 __noreturn void fatal_error(const char *format, ...)
77 {
78 	va_list va;
79 
80 	va_start(va, format);
81 	do_error_msg(format, va, 0);
82 	va_end(va);
83 	abort();
84 }
85 
assertion_failed(const char * expr,const char * file,int line)86 __noreturn void assertion_failed(const char *expr, const char *file, int line)
87 {
88 	fatal_error("Assertion failed: %s at %s:%d", expr, file, line);
89 }
90 
print_libfsverity_error(const char * msg)91 static void print_libfsverity_error(const char *msg)
92 {
93 	error_msg("%s", msg);
94 }
95 
install_libfsverity_error_handler(void)96 void install_libfsverity_error_handler(void)
97 {
98 	libfsverity_set_error_callback(print_libfsverity_error);
99 }
100 
101 /* ========== File utilities ========== */
102 
open_file(struct filedes * file,const char * filename,int flags,int mode)103 bool open_file(struct filedes *file, const char *filename, int flags, int mode)
104 {
105 	file->fd = open(filename, flags | O_BINARY, mode);
106 	if (file->fd < 0) {
107 		error_msg_errno("can't open '%s' for %s", filename,
108 				(flags & O_ACCMODE) == O_RDONLY ? "reading" :
109 				(flags & O_ACCMODE) == O_WRONLY ? "writing" :
110 				"reading and writing");
111 		return false;
112 	}
113 	file->name = xstrdup(filename);
114 	return true;
115 }
116 
get_file_size(struct filedes * file,u64 * size_ret)117 bool get_file_size(struct filedes *file, u64 *size_ret)
118 {
119 	struct stat stbuf;
120 
121 	if (fstat(file->fd, &stbuf) != 0) {
122 		error_msg_errno("can't stat file '%s'", file->name);
123 		return false;
124 	}
125 	*size_ret = stbuf.st_size;
126 	return true;
127 }
128 
full_read(struct filedes * file,void * buf,size_t count)129 bool full_read(struct filedes *file, void *buf, size_t count)
130 {
131 	while (count) {
132 		int n = read(file->fd, buf, min(count, INT_MAX));
133 
134 		if (n < 0) {
135 			error_msg_errno("reading from '%s'", file->name);
136 			return false;
137 		}
138 		if (n == 0) {
139 			error_msg("unexpected end-of-file on '%s'", file->name);
140 			return false;
141 		}
142 		buf += n;
143 		count -= n;
144 	}
145 	return true;
146 }
147 
full_write(struct filedes * file,const void * buf,size_t count)148 bool full_write(struct filedes *file, const void *buf, size_t count)
149 {
150 	while (count) {
151 		int n = write(file->fd, buf, min(count, INT_MAX));
152 
153 		if (n < 0) {
154 			error_msg_errno("writing to '%s'", file->name);
155 			return false;
156 		}
157 		buf += n;
158 		count -= n;
159 	}
160 	return true;
161 }
162 
filedes_close(struct filedes * file)163 bool filedes_close(struct filedes *file)
164 {
165 	int res;
166 
167 	if (file->fd < 0)
168 		return true;
169 	res = close(file->fd);
170 	if (res != 0)
171 		error_msg_errno("closing '%s'", file->name);
172 	file->fd = -1;
173 	free(file->name);
174 	file->name = NULL;
175 	return res == 0;
176 }
177 
read_callback(void * file,void * buf,size_t count)178 int read_callback(void *file, void *buf, size_t count)
179 {
180 	errno = 0;
181 	if (!full_read(file, buf, count))
182 		return errno ? -errno : -EIO;
183 	return 0;
184 }
185 
186 /* ========== String utilities ========== */
187 
hex2bin_char(char c)188 static int hex2bin_char(char c)
189 {
190 	if (c >= '0' && c <= '9')
191 		return c - '0';
192 	if (c >= 'a' && c <= 'f')
193 		return 10 + (c - 'a');
194 	if (c >= 'A' && c <= 'F')
195 		return 10 + (c - 'A');
196 	return -1;
197 }
198 
hex2bin(const char * hex,u8 * bin,size_t bin_len)199 bool hex2bin(const char *hex, u8 *bin, size_t bin_len)
200 {
201 	size_t i;
202 
203 	if (strlen(hex) != 2 * bin_len)
204 		return false;
205 
206 	for (i = 0; i < bin_len; i++) {
207 		int hi = hex2bin_char(*hex++);
208 		int lo = hex2bin_char(*hex++);
209 
210 		if (hi < 0 || lo < 0)
211 			return false;
212 		bin[i] = (hi << 4) | lo;
213 	}
214 	return true;
215 }
216 
bin2hex_char(u8 nibble)217 static char bin2hex_char(u8 nibble)
218 {
219 	ASSERT(nibble <= 0xf);
220 
221 	if (nibble < 10)
222 		return '0' + nibble;
223 	return 'a' + (nibble - 10);
224 }
225 
bin2hex(const u8 * bin,size_t bin_len,char * hex)226 void bin2hex(const u8 *bin, size_t bin_len, char *hex)
227 {
228 	size_t i;
229 
230 	for (i = 0; i < bin_len; i++) {
231 		*hex++ = bin2hex_char(bin[i] >> 4);
232 		*hex++ = bin2hex_char(bin[i] & 0xf);
233 	}
234 	*hex = '\0';
235 }
236