1 /* Copyright 2014 The ChromiumOS Authors
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 */
5
6 #include <assert.h>
7 #include <errno.h>
8 #include <fcntl.h>
9 #if !defined(HAVE_MACOS) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
10 #include <linux/fs.h> /* For BLKGETSIZE64 */
11 #include <sys/sendfile.h>
12 #else
13 #include <copyfile.h>
14 #endif
15 #include <stdarg.h>
16 #include <stdint.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <sys/ioctl.h>
21 #include <sys/mman.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 #include <sys/wait.h>
25 #include <unistd.h>
26
27 #include "2common.h"
28 #include "2sha.h"
29 #include "2sysincludes.h"
30 #include "cgptlib_internal.h"
31 #include "file_type.h"
32 #include "futility.h"
33 #include "futility_options.h"
34 #include "host_misc.h"
35
36 /* Default is to support everything we can */
37 enum vboot_version vboot_version = VBOOT_VERSION_ALL;
38
39 int debugging_enabled;
vb2ex_printf(const char * func,const char * format,...)40 void vb2ex_printf(const char *func, const char *format, ...)
41 {
42 if (!debugging_enabled)
43 return;
44
45 va_list ap;
46 va_start(ap, format);
47 if (func)
48 fprintf(stderr, "DEBUG: %s: ", func);
49 vfprintf(stderr, format, ap);
50 va_end(ap);
51 }
52
is_null_terminated(const char * s,int len)53 static int is_null_terminated(const char *s, int len)
54 {
55 len--;
56 s += len;
57 while (len-- >= 0)
58 if (!*s--)
59 return 1;
60 return 0;
61 }
62
max(uint32_t a,uint32_t b)63 static inline uint32_t max(uint32_t a, uint32_t b)
64 {
65 return a > b ? a : b;
66 }
67
ft_recognize_gbb(uint8_t * buf,uint32_t len)68 enum futil_file_type ft_recognize_gbb(uint8_t *buf, uint32_t len)
69 {
70 struct vb2_gbb_header *gbb = (struct vb2_gbb_header *)buf;
71
72 if (memcmp(gbb->signature, VB2_GBB_SIGNATURE, VB2_GBB_SIGNATURE_SIZE))
73 return FILE_TYPE_UNKNOWN;
74 if (gbb->major_version > VB2_GBB_MAJOR_VER)
75 return FILE_TYPE_UNKNOWN;
76 if (sizeof(struct vb2_gbb_header) > len)
77 return FILE_TYPE_UNKNOWN;
78
79 /* close enough */
80 return FILE_TYPE_GBB;
81 }
82
futil_valid_gbb_header(struct vb2_gbb_header * gbb,uint32_t len,uint32_t * maxlen_ptr)83 int futil_valid_gbb_header(struct vb2_gbb_header *gbb, uint32_t len,
84 uint32_t *maxlen_ptr)
85 {
86 if (len < sizeof(struct vb2_gbb_header))
87 return 0;
88
89 if (memcmp(gbb->signature, VB2_GBB_SIGNATURE, VB2_GBB_SIGNATURE_SIZE))
90 return 0;
91 if (gbb->major_version != VB2_GBB_MAJOR_VER)
92 return 0;
93
94 /* Check limits first, to help identify problems */
95 if (maxlen_ptr) {
96 uint32_t maxlen = gbb->header_size;
97 maxlen = max(maxlen,
98 gbb->hwid_offset + gbb->hwid_size);
99 maxlen = max(maxlen,
100 gbb->rootkey_offset + gbb->rootkey_size);
101 maxlen = max(maxlen,
102 gbb->bmpfv_offset + gbb->bmpfv_size);
103 maxlen = max(maxlen,
104 gbb->recovery_key_offset + gbb->recovery_key_size);
105 *maxlen_ptr = maxlen;
106 }
107
108 if (gbb->header_size != EXPECTED_VB2_GBB_HEADER_SIZE ||
109 gbb->header_size > len)
110 return 0;
111 if (gbb->hwid_offset < EXPECTED_VB2_GBB_HEADER_SIZE)
112 return 0;
113 if ((uint64_t)gbb->hwid_offset + gbb->hwid_size > len)
114 return 0;
115 if (gbb->hwid_size) {
116 const char *s = (const char *)
117 ((uint8_t *)gbb + gbb->hwid_offset);
118 if (!is_null_terminated(s, gbb->hwid_size))
119 return 0;
120 }
121 if (gbb->rootkey_offset < EXPECTED_VB2_GBB_HEADER_SIZE)
122 return 0;
123 if ((uint64_t)gbb->rootkey_offset + gbb->rootkey_size > len)
124 return 0;
125
126 if (gbb->bmpfv_offset < EXPECTED_VB2_GBB_HEADER_SIZE)
127 return 0;
128 if ((uint64_t)gbb->bmpfv_offset + gbb->bmpfv_size > len)
129 return 0;
130 if (gbb->recovery_key_offset < EXPECTED_VB2_GBB_HEADER_SIZE)
131 return 0;
132 if ((uint64_t)gbb->recovery_key_offset + gbb->recovery_key_size > len)
133 return 0;
134
135 /* Seems legit... */
136 return 1;
137 }
138
139 /* For GBB v1.2 and later, print the stored digest of the HWID (and whether
140 * it's correct). Return true if it is correct. */
print_hwid_digest(struct vb2_gbb_header * gbb,const char * banner)141 int print_hwid_digest(struct vb2_gbb_header *gbb, const char *banner)
142 {
143 FT_READABLE_PRINT("%s", banner);
144 FT_PARSEABLE_PRINT("hwid::digest::algorithm::2::SHA256\n");
145 FT_PARSEABLE_PRINT("hwid::digest::hex::");
146
147 /* There isn't one for v1.1 and earlier, so assume it's good. */
148 if (gbb->minor_version < 2) {
149 printf("<none>\n");
150 FT_PARSEABLE_PRINT("hwid::digest::ignored\n");
151 return 1;
152 }
153
154 uint8_t *buf = (uint8_t *)gbb;
155 char *hwid_str = (char *)(buf + gbb->hwid_offset);
156 int is_valid = 0;
157 struct vb2_hash hash;
158
159 if (VB2_SUCCESS == vb2_hash_calculate(false, buf + gbb->hwid_offset,
160 strlen(hwid_str), VB2_HASH_SHA256,
161 &hash)) {
162 int i;
163 is_valid = 1;
164 /* print it, comparing as we go */
165 for (i = 0; i < sizeof(hash.sha256); i++) {
166 printf("%02x", gbb->hwid_digest[i]);
167 if (gbb->hwid_digest[i] != hash.sha256[i])
168 is_valid = 0;
169 }
170 }
171
172 FT_PRINT_RAW("", "\n");
173 FT_PRINT(" %s\n", "hwid::digest::%s\n", is_valid ? "valid" : "invalid");
174 return is_valid;
175 }
176
177 /* Deprecated. Use futil_set_gbb_hwid in future. */
178 /* For GBB v1.2 and later, update the hwid_digest field. */
update_hwid_digest(struct vb2_gbb_header * gbb)179 void update_hwid_digest(struct vb2_gbb_header *gbb)
180 {
181 /* There isn't one for v1.1 and earlier */
182 if (gbb->minor_version < 2)
183 return;
184
185 uint8_t *buf = (uint8_t *)gbb;
186 char *hwid_str = (char *)(buf + gbb->hwid_offset);
187 struct vb2_hash hash;
188
189 vb2_hash_calculate(false, buf + gbb->hwid_offset, strlen(hwid_str),
190 VB2_HASH_SHA256, &hash);
191 memcpy(gbb->hwid_digest, hash.raw, sizeof(gbb->hwid_digest));
192 }
193
194 /* Sets the HWID string field inside a GBB header. */
futil_set_gbb_hwid(struct vb2_gbb_header * gbb,const char * hwid)195 int futil_set_gbb_hwid(struct vb2_gbb_header *gbb, const char *hwid)
196 {
197 uint8_t *to = (uint8_t *)gbb + gbb->hwid_offset;
198 struct vb2_hash hash;
199 size_t len;
200
201 assert(hwid);
202 len = strlen(hwid);
203 if (len >= gbb->hwid_size)
204 return -1;
205
206 /* Zero whole area so we won't have garbage after NUL. */
207 memset(to, 0, gbb->hwid_size);
208 memcpy(to, hwid, len);
209
210 /* major_version starts from 1 and digest must be updated since v1.2. */
211 if (gbb->major_version == 1 && gbb->minor_version < 2)
212 return 0;
213
214 VB2_TRY(vb2_hash_calculate(false, to, len, VB2_HASH_SHA256, &hash));
215 memcpy(gbb->hwid_digest, hash.raw, sizeof(gbb->hwid_digest));
216 return VB2_SUCCESS;
217 }
218
futil_copy_file(const char * infile,const char * outfile)219 int futil_copy_file(const char *infile, const char *outfile)
220 {
221 VB2_DEBUG("%s -> %s\n", infile, outfile);
222
223 int ifd, ofd;
224 if ((ifd = open(infile, O_RDONLY)) == -1) {
225 ERROR("Cannot open '%s', %s.\n", infile, strerror(errno));
226 return -1;
227 }
228 if ((ofd = creat(outfile, 0660)) == -1) {
229 ERROR("Cannot open '%s', %s.\n", outfile, strerror(errno));
230 close(ifd);
231 return -1;
232 }
233 struct stat finfo = {0};
234 if (fstat(ifd, &finfo) < 0) {
235 ERROR("Cannot fstat '%s' as %s.\n", infile, strerror(errno));
236 close (ifd);
237 close (ofd);
238 return -1;
239 }
240 #if !defined(HAVE_MACOS) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
241 ssize_t ret = sendfile(ofd, ifd, NULL, finfo.st_size);
242 #else
243 ssize_t ret = fcopyfile(ifd, ofd, 0, COPYFILE_ALL);
244 #endif
245 close(ifd);
246 close(ofd);
247 if (ret == -1) {
248 ERROR("Cannot copy '%s'->'%s', %s.\n", infile,
249 outfile, strerror(errno));
250 }
251 return ret;
252 }
253
futil_open_file(const char * infile,int * fd,enum file_mode mode)254 enum futil_file_err futil_open_file(const char *infile, int *fd,
255 enum file_mode mode)
256 {
257 if (mode == FILE_RW) {
258 VB2_DEBUG("open RW %s\n", infile);
259 *fd = open(infile, O_RDWR);
260 if (*fd < 0) {
261 ERROR("Can't open %s for writing: %s\n", infile,
262 strerror(errno));
263 return FILE_ERR_OPEN;
264 }
265 } else {
266 VB2_DEBUG("open RO %s\n", infile);
267 *fd = open(infile, O_RDONLY);
268 if (*fd < 0) {
269 ERROR("Can't open %s for reading: %s\n", infile,
270 strerror(errno));
271 return FILE_ERR_OPEN;
272 }
273 }
274 return FILE_ERR_NONE;
275 }
276
futil_close_file(int fd)277 enum futil_file_err futil_close_file(int fd)
278 {
279 if (fd >= 0 && close(fd)) {
280 ERROR("Closing ifd: %s\n", strerror(errno));
281 return FILE_ERR_CLOSE;
282 }
283 return FILE_ERR_NONE;
284 }
285
futil_map_file(int fd,enum file_mode mode,uint8_t ** buf,uint32_t * len)286 enum futil_file_err futil_map_file(int fd, enum file_mode mode,
287 uint8_t **buf, uint32_t *len)
288 {
289 struct stat sb;
290 void *mmap_ptr;
291 uint32_t reasonable_len;
292
293 if (0 != fstat(fd, &sb)) {
294 ERROR("Can't stat input file: %s\n", strerror(errno));
295 return FILE_ERR_STAT;
296 }
297
298 #if !defined(HAVE_MACOS) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
299 if (S_ISBLK(sb.st_mode))
300 ioctl(fd, BLKGETSIZE64, &sb.st_size);
301 #endif
302
303 /* If the image is larger than 2^32 bytes, it's wrong. */
304 if (sb.st_size < 0 || sb.st_size > UINT32_MAX) {
305 ERROR("Image size is unreasonable\n");
306 return FILE_ERR_SIZE;
307 }
308 reasonable_len = (uint32_t)sb.st_size;
309
310 if (mode == FILE_RW)
311 mmap_ptr = mmap(0, sb.st_size,
312 PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
313 else
314 mmap_ptr = mmap(0, sb.st_size,
315 PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
316
317 if (mmap_ptr == MAP_FAILED) {
318 ERROR("Can't mmap %s file: %s\n",
319 mode == FILE_RW ? "output" : "input", strerror(errno));
320 return FILE_ERR_MMAP;
321 }
322
323 *buf = (uint8_t *)mmap_ptr;
324 *len = reasonable_len;
325 return FILE_ERR_NONE;
326 }
327
futil_unmap_file(int fd,enum file_mode mode,uint8_t * buf,uint32_t len)328 enum futil_file_err futil_unmap_file(int fd, enum file_mode mode,
329 uint8_t *buf, uint32_t len)
330 {
331 void *mmap_ptr = buf;
332 enum futil_file_err err = FILE_ERR_NONE;
333
334 if (mode == FILE_RW &&
335 (0 != msync(mmap_ptr, len, MS_SYNC | MS_INVALIDATE))) {
336 ERROR("msync failed: %s\n", strerror(errno));
337 err = FILE_ERR_MSYNC;
338 }
339
340 if (0 != munmap(mmap_ptr, len)) {
341 ERROR("Can't munmap pointer: %s\n", strerror(errno));
342 if (err == FILE_ERR_NONE)
343 err = FILE_ERR_MUNMAP;
344 }
345
346 return err;
347 }
348
futil_open_and_map_file(const char * infile,int * fd,enum file_mode mode,uint8_t ** buf,uint32_t * len)349 enum futil_file_err futil_open_and_map_file(const char *infile, int *fd,
350 enum file_mode mode, uint8_t **buf,
351 uint32_t *len)
352 {
353 enum futil_file_err rv = futil_open_file(infile, fd, mode);
354 if (rv != FILE_ERR_NONE)
355 return rv;
356
357 rv = futil_map_file(*fd, mode, buf, len);
358 if (rv != FILE_ERR_NONE)
359 futil_close_file(*fd);
360
361 return rv;
362 }
363
futil_unmap_and_close_file(int fd,enum file_mode mode,uint8_t * buf,uint32_t len)364 enum futil_file_err futil_unmap_and_close_file(int fd, enum file_mode mode,
365 uint8_t *buf, uint32_t len)
366 {
367 enum futil_file_err rv = FILE_ERR_NONE;
368
369 if (buf)
370 rv = futil_unmap_file(fd, mode, buf, len);
371 if (rv != FILE_ERR_NONE)
372 return rv;
373
374 if (fd != -1)
375 return futil_close_file(fd);
376 else
377 return FILE_ERR_NONE;
378 }
379
380 #define DISK_SECTOR_SIZE 512
ft_recognize_gpt(uint8_t * buf,uint32_t len)381 enum futil_file_type ft_recognize_gpt(uint8_t *buf, uint32_t len)
382 {
383 GptHeader *h;
384
385 /* GPT header starts at sector 1, is one sector long */
386 if (len < 2 * DISK_SECTOR_SIZE)
387 return FILE_TYPE_UNKNOWN;
388
389 h = (GptHeader *)(buf + DISK_SECTOR_SIZE);
390
391 if (memcmp(h->signature, GPT_HEADER_SIGNATURE,
392 GPT_HEADER_SIGNATURE_SIZE) &&
393 memcmp(h->signature, GPT_HEADER_SIGNATURE2,
394 GPT_HEADER_SIGNATURE_SIZE))
395 return FILE_TYPE_UNKNOWN;
396 if (h->revision != GPT_HEADER_REVISION)
397 return FILE_TYPE_UNKNOWN;
398 if (h->size < MIN_SIZE_OF_HEADER || h->size > MAX_SIZE_OF_HEADER)
399 return FILE_TYPE_UNKNOWN;
400
401 if (HeaderCrc(h) != h->header_crc32)
402 return FILE_TYPE_UNKNOWN;
403
404 return FILE_TYPE_CHROMIUMOS_DISK;
405 }
406
parse_digest_or_die(uint8_t * buf,int len,const char * str)407 void parse_digest_or_die(uint8_t *buf, int len, const char *str)
408 {
409 if (!parse_hash(buf, len, str)) {
410 ERROR("Invalid DIGEST \"%s\"\n", str);
411 exit(1);
412 }
413 }
414
print_bytes(const void * ptr,size_t len)415 void print_bytes(const void *ptr, size_t len)
416 {
417 const uint8_t *buf = (const uint8_t *)ptr;
418
419 for (size_t i = 0; i < len; i++)
420 printf("%02x", *buf++);
421 }
422
write_to_file(const char * msg,const char * filename,uint8_t * start,size_t size)423 int write_to_file(const char *msg, const char *filename, uint8_t *start,
424 size_t size)
425 {
426 FILE *fp;
427 int r = 0;
428
429 fp = fopen(filename, "wb");
430 if (!fp) {
431 r = errno;
432 ERROR("Unable to open %s for writing: %s\n", filename,
433 strerror(r));
434 return r;
435 }
436
437 /* Don't write zero bytes */
438 if (size && 1 != fwrite(start, size, 1, fp)) {
439 r = errno;
440 ERROR("Unable to write to %s: %s\n", filename, strerror(r));
441 }
442
443 if (fclose(fp) != 0) {
444 int e = errno;
445 ERROR("Unable to close %s: %s\n", filename, strerror(e));
446 if (!r)
447 r = e;
448 }
449
450 if (!r && msg)
451 printf("%s %s\n", msg, filename);
452
453 return r;
454 }
455