• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <inttypes.h>
17 #include <limits.h>
18 #include <stdarg.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
21 #ifdef _WIN32
22 #  include <windows.h>
23 #endif
24 
25 /* ========== Memory allocation ========== */
26 
xmalloc(size_t size)27 void *xmalloc(size_t size)
28 {
29 	void *p = malloc(size);
30 
31 	if (!p)
32 		fatal_error("out of memory");
33 	return p;
34 }
35 
xzalloc(size_t size)36 void *xzalloc(size_t size)
37 {
38 	return memset(xmalloc(size), 0, size);
39 }
40 
xmemdup(const void * mem,size_t size)41 void *xmemdup(const void *mem, size_t size)
42 {
43 	return memcpy(xmalloc(size), mem, size);
44 }
45 
xstrdup(const char * s)46 char *xstrdup(const char *s)
47 {
48 	return xmemdup(s, strlen(s) + 1);
49 }
50 
51 /* ========== Error messages and assertions ========== */
52 
do_error_msg(const char * format,va_list va,int err)53 static void do_error_msg(const char *format, va_list va, int err)
54 {
55 	fputs("ERROR: ", stderr);
56 	vfprintf(stderr, format, va);
57 	if (err)
58 		fprintf(stderr, ": %s", strerror(err));
59 	putc('\n', stderr);
60 }
61 
error_msg(const char * format,...)62 void error_msg(const char *format, ...)
63 {
64 	va_list va;
65 
66 	va_start(va, format);
67 	do_error_msg(format, va, 0);
68 	va_end(va);
69 }
70 
error_msg_errno(const char * format,...)71 void error_msg_errno(const char *format, ...)
72 {
73 	va_list va;
74 
75 	va_start(va, format);
76 	do_error_msg(format, va, errno);
77 	va_end(va);
78 }
79 
fatal_error(const char * format,...)80 __noreturn void fatal_error(const char *format, ...)
81 {
82 	va_list va;
83 
84 	va_start(va, format);
85 	do_error_msg(format, va, 0);
86 	va_end(va);
87 	abort();
88 }
89 
assertion_failed(const char * expr,const char * file,int line)90 __noreturn void assertion_failed(const char *expr, const char *file, int line)
91 {
92 	fatal_error("Assertion failed: %s at %s:%d", expr, file, line);
93 }
94 
print_libfsverity_error(const char * msg)95 static void print_libfsverity_error(const char *msg)
96 {
97 	error_msg("%s", msg);
98 }
99 
install_libfsverity_error_handler(void)100 void install_libfsverity_error_handler(void)
101 {
102 	libfsverity_set_error_callback(print_libfsverity_error);
103 }
104 
105 /* ========== File utilities ========== */
106 
open_file(struct filedes * file,const char * filename,int flags,int mode)107 bool open_file(struct filedes *file, const char *filename, int flags, int mode)
108 {
109 	file->fd = open(filename, flags | O_BINARY, mode);
110 	if (file->fd < 0) {
111 		error_msg_errno("can't open '%s' for %s", filename,
112 				(flags & O_ACCMODE) == O_RDONLY ? "reading" :
113 				(flags & O_ACCMODE) == O_WRONLY ? "writing" :
114 				"reading and writing");
115 		return false;
116 	}
117 	file->name = xstrdup(filename);
118 	return true;
119 }
120 
get_file_size(struct filedes * file,u64 * size_ret)121 bool get_file_size(struct filedes *file, u64 *size_ret)
122 {
123 	struct stat stbuf;
124 
125 	if (fstat(file->fd, &stbuf) != 0) {
126 		error_msg_errno("can't stat file '%s'", file->name);
127 		return false;
128 	}
129 	*size_ret = stbuf.st_size;
130 	return true;
131 }
132 
preallocate_file(struct filedes * file,u64 size)133 bool preallocate_file(struct filedes *file, u64 size)
134 {
135 	int res;
136 
137 	if (size == 0)
138 		return true;
139 #ifdef _WIN32
140 	/* Not exactly the same as posix_fallocate(), but good enough... */
141 	res = _chsize_s(file->fd, size);
142 #else
143 	res = posix_fallocate(file->fd, 0, size);
144 #endif
145 	if (res != 0) {
146 		error_msg_errno("preallocating %" PRIu64 "-byte file '%s'",
147 				size, file->name);
148 		return false;
149 	}
150 	return true;
151 }
152 
full_read(struct filedes * file,void * buf,size_t count)153 bool full_read(struct filedes *file, void *buf, size_t count)
154 {
155 	while (count) {
156 		int n = read(file->fd, buf, min(count, INT_MAX));
157 
158 		if (n < 0) {
159 			error_msg_errno("reading from '%s'", file->name);
160 			return false;
161 		}
162 		if (n == 0) {
163 			error_msg("unexpected end-of-file on '%s'", file->name);
164 			return false;
165 		}
166 		buf += n;
167 		count -= n;
168 	}
169 	return true;
170 }
171 
full_write(struct filedes * file,const void * buf,size_t count)172 bool full_write(struct filedes *file, const void *buf, size_t count)
173 {
174 	while (count) {
175 		int n = write(file->fd, buf, min(count, INT_MAX));
176 
177 		if (n < 0) {
178 			error_msg_errno("writing to '%s'", file->name);
179 			return false;
180 		}
181 		buf += n;
182 		count -= n;
183 	}
184 	return true;
185 }
186 
raw_pwrite(int fd,const void * buf,int count,u64 offset)187 static int raw_pwrite(int fd, const void *buf, int count, u64 offset)
188 {
189 #ifdef _WIN32
190 	HANDLE h = (HANDLE)_get_osfhandle(fd);
191 	OVERLAPPED pos = { .Offset = offset, .OffsetHigh = offset >> 32 };
192 	DWORD written = 0;
193 
194 	/* Not exactly the same as pwrite(), but good enough... */
195 	if (!WriteFile(h, buf, count, &written, &pos)) {
196 		errno = EIO;
197 		return -1;
198 	}
199 	return written;
200 #else
201 	return pwrite(fd, buf, count, offset);
202 #endif
203 }
204 
full_pwrite(struct filedes * file,const void * buf,size_t count,u64 offset)205 bool full_pwrite(struct filedes *file, const void *buf, size_t count,
206 		 u64 offset)
207 {
208 	while (count) {
209 		int n = raw_pwrite(file->fd, buf, min(count, INT_MAX), offset);
210 
211 		if (n < 0) {
212 			error_msg_errno("writing to '%s'", file->name);
213 			return false;
214 		}
215 		buf += n;
216 		count -= n;
217 		offset += n;
218 	}
219 	return true;
220 }
221 
filedes_close(struct filedes * file)222 bool filedes_close(struct filedes *file)
223 {
224 	int res;
225 
226 	if (file->fd < 0)
227 		return true;
228 	res = close(file->fd);
229 	if (res != 0)
230 		error_msg_errno("closing '%s'", file->name);
231 	file->fd = -1;
232 	free(file->name);
233 	file->name = NULL;
234 	return res == 0;
235 }
236 
read_callback(void * file,void * buf,size_t count)237 int read_callback(void *file, void *buf, size_t count)
238 {
239 	errno = 0;
240 	if (!full_read(file, buf, count))
241 		return errno ? -errno : -EIO;
242 	return 0;
243 }
244 
245 /* ========== String utilities ========== */
246 
hex2bin_char(char c)247 static int hex2bin_char(char c)
248 {
249 	if (c >= '0' && c <= '9')
250 		return c - '0';
251 	if (c >= 'a' && c <= 'f')
252 		return 10 + (c - 'a');
253 	if (c >= 'A' && c <= 'F')
254 		return 10 + (c - 'A');
255 	return -1;
256 }
257 
hex2bin(const char * hex,u8 * bin,size_t bin_len)258 bool hex2bin(const char *hex, u8 *bin, size_t bin_len)
259 {
260 	size_t i;
261 
262 	if (strlen(hex) != 2 * bin_len)
263 		return false;
264 
265 	for (i = 0; i < bin_len; i++) {
266 		int hi = hex2bin_char(*hex++);
267 		int lo = hex2bin_char(*hex++);
268 
269 		if (hi < 0 || lo < 0)
270 			return false;
271 		bin[i] = (hi << 4) | lo;
272 	}
273 	return true;
274 }
275 
bin2hex_char(u8 nibble)276 static char bin2hex_char(u8 nibble)
277 {
278 	ASSERT(nibble <= 0xf);
279 
280 	if (nibble < 10)
281 		return '0' + nibble;
282 	return 'a' + (nibble - 10);
283 }
284 
bin2hex(const u8 * bin,size_t bin_len,char * hex)285 void bin2hex(const u8 *bin, size_t bin_len, char *hex)
286 {
287 	size_t i;
288 
289 	for (i = 0; i < bin_len; i++) {
290 		*hex++ = bin2hex_char(bin[i] >> 4);
291 		*hex++ = bin2hex_char(bin[i] & 0xf);
292 	}
293 	*hex = '\0';
294 }
295