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