blob: 3d85f6911f60d5601c8c56ef55bbe5126fbb5a94 [file] [log] [blame]
Bill Richardsoncf6e78d2014-08-27 15:50:25 -07001/*
2 * Copyright 2014 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
Bill Richardson15dc6fc2014-09-02 14:45:44 -07007#include <errno.h>
David Riley05987b12015-02-05 19:22:49 -08008#ifndef HAVE_MACOS
Bill Richardsone192e7f2014-09-23 12:49:26 -07009#include <linux/fs.h> /* For BLKGETSIZE64 */
David Riley05987b12015-02-05 19:22:49 -080010#endif
Bill Richardsone192e7f2014-09-23 12:49:26 -070011#include <stdarg.h>
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070012#include <stdint.h>
Bill Richardson15dc6fc2014-09-02 14:45:44 -070013#include <stdio.h>
14#include <stdlib.h>
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070015#include <string.h>
Bill Richardsone192e7f2014-09-23 12:49:26 -070016#include <sys/ioctl.h>
Bill Richardson15dc6fc2014-09-02 14:45:44 -070017#include <sys/mman.h>
18#include <sys/stat.h>
19#include <sys/types.h>
20#include <sys/wait.h>
21#include <unistd.h>
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070022
Bill Richardson25593382015-01-30 12:22:28 -080023#include "cgptlib_internal.h"
24#include "file_type.h"
Bill Richardsone192e7f2014-09-23 12:49:26 -070025#include "futility.h"
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070026#include "gbb_header.h"
27
Bill Richardsone192e7f2014-09-23 12:49:26 -070028int debugging_enabled;
29void Debug(const char *format, ...)
30{
31 if (!debugging_enabled)
32 return;
33
34 va_list ap;
35 va_start(ap, format);
36 fprintf(stderr, "DEBUG: ");
37 vfprintf(stderr, format, ap);
38 va_end(ap);
39}
40
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070041static int is_null_terminated(const char *s, int len)
42{
43 len--;
44 s += len;
45 while (len-- >= 0)
46 if (!*s--)
47 return 1;
48 return 0;
49}
50
51static inline uint32_t max(uint32_t a, uint32_t b)
52{
53 return a > b ? a : b;
54}
55
Bill Richardson25593382015-01-30 12:22:28 -080056enum futil_file_type recognize_gbb(uint8_t *buf, uint32_t len)
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070057{
Bill Richardson25593382015-01-30 12:22:28 -080058 GoogleBinaryBlockHeader *gbb = (GoogleBinaryBlockHeader *)buf;
59
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070060 if (memcmp(gbb->signature, GBB_SIGNATURE, GBB_SIGNATURE_SIZE))
Bill Richardson25593382015-01-30 12:22:28 -080061 return FILE_TYPE_UNKNOWN;
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070062 if (gbb->major_version > GBB_MAJOR_VER)
Bill Richardson25593382015-01-30 12:22:28 -080063 return FILE_TYPE_UNKNOWN;
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070064 if (sizeof(GoogleBinaryBlockHeader) > len)
Bill Richardson25593382015-01-30 12:22:28 -080065 return FILE_TYPE_UNKNOWN;
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070066
67 /* close enough */
Bill Richardson25593382015-01-30 12:22:28 -080068 return FILE_TYPE_GBB;
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070069}
70
71int futil_valid_gbb_header(GoogleBinaryBlockHeader *gbb, uint32_t len,
72 uint32_t *maxlen_ptr)
73{
Bill Richardson7ccd9ce2015-01-30 23:45:49 -080074 if (len < sizeof(GoogleBinaryBlockHeader))
75 return 0;
76
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070077 if (memcmp(gbb->signature, GBB_SIGNATURE, GBB_SIGNATURE_SIZE))
78 return 0;
79 if (gbb->major_version != GBB_MAJOR_VER)
80 return 0;
81
82 /* Check limits first, to help identify problems */
83 if (maxlen_ptr) {
84 uint32_t maxlen = gbb->header_size;
85 maxlen = max(maxlen,
86 gbb->hwid_offset + gbb->hwid_size);
87 maxlen = max(maxlen,
88 gbb->rootkey_offset + gbb->rootkey_size);
89 maxlen = max(maxlen,
90 gbb->bmpfv_offset + gbb->bmpfv_size);
91 maxlen = max(maxlen,
92 gbb->recovery_key_offset + gbb->recovery_key_size);
93 *maxlen_ptr = maxlen;
94 }
95
96 if (gbb->header_size != GBB_HEADER_SIZE || gbb->header_size > len)
97 return 0;
98 if (gbb->hwid_offset < GBB_HEADER_SIZE)
99 return 0;
100 if (gbb->hwid_offset + gbb->hwid_size > len)
101 return 0;
102 if (gbb->hwid_size) {
103 const char *s = (const char *)
104 ((uint8_t *)gbb + gbb->hwid_offset);
105 if (!is_null_terminated(s, gbb->hwid_size))
106 return 0;
107 }
108 if (gbb->rootkey_offset < GBB_HEADER_SIZE)
109 return 0;
110 if (gbb->rootkey_offset + gbb->rootkey_size > len)
111 return 0;
112
113 if (gbb->bmpfv_offset < GBB_HEADER_SIZE)
114 return 0;
115 if (gbb->bmpfv_offset + gbb->bmpfv_size > len)
116 return 0;
117 if (gbb->recovery_key_offset < GBB_HEADER_SIZE)
118 return 0;
119 if (gbb->recovery_key_offset + gbb->recovery_key_size > len)
120 return 0;
121
122 /* Seems legit... */
123 return 1;
124}
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700125
Bill Richardson6df3e332014-10-02 18:50:33 -0700126/* For GBB v1.2 and later, print the stored digest of the HWID (and whether
127 * it's correct). Return true if it is correct. */
128int print_hwid_digest(GoogleBinaryBlockHeader *gbb,
129 const char *banner, const char *footer)
130{
131 printf("%s", banner);
132
133 /* There isn't one for v1.1 and earlier, so assume it's good. */
134 if (gbb->minor_version < 2) {
135 printf("<none>%s", footer);
136 return 1;
137 }
138
139 uint8_t *buf = (uint8_t *)gbb;
140 char *hwid_str = (char *)(buf + gbb->hwid_offset);
141 int is_valid = 0;
Bill Richardsonb406c102014-12-03 14:10:13 -0800142 uint8_t *digest = DigestBuf(buf + gbb->hwid_offset,
Bill Richardson6df3e332014-10-02 18:50:33 -0700143 strlen(hwid_str),
144 SHA256_DIGEST_ALGORITHM);
145 if (digest) {
146 int i;
147 is_valid = 1;
148 /* print it, comparing as we go */
149 for (i = 0; i < SHA256_DIGEST_SIZE; i++) {
150 printf("%02x", gbb->hwid_digest[i]);
151 if (gbb->hwid_digest[i] != digest[i])
152 is_valid = 0;
153 }
154 free(digest);
155 }
156
157 printf(" %s", is_valid ? "valid" : "<invalid>");
158 printf("%s", footer);
159 return is_valid;
160}
161
162/* For GBB v1.2 and later, update the hwid_digest field. */
163void update_hwid_digest(GoogleBinaryBlockHeader *gbb)
164{
165 /* There isn't one for v1.1 and earlier */
166 if (gbb->minor_version < 2)
167 return;
168
169 uint8_t *buf = (uint8_t *)gbb;
170 char *hwid_str = (char *)(buf + gbb->hwid_offset);
Bill Richardsonb406c102014-12-03 14:10:13 -0800171 uint8_t *digest = DigestBuf(buf + gbb->hwid_offset,
Bill Richardson6df3e332014-10-02 18:50:33 -0700172 strlen(hwid_str),
173 SHA256_DIGEST_ALGORITHM);
174 memcpy(gbb->hwid_digest, digest, SHA256_DIGEST_SIZE);
175 free(digest);
176}
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700177
178/*
179 * TODO: All sorts of race conditions likely here, and everywhere this is used.
180 * Do we care? If so, fix it.
181 */
Bill Richardsone192e7f2014-09-23 12:49:26 -0700182void futil_copy_file_or_die(const char *infile, const char *outfile)
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700183{
184 pid_t pid;
185 int status;
186
Bill Richardsonb406c102014-12-03 14:10:13 -0800187 Debug("%s(%s, %s)\n", __func__, infile, outfile);
188
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700189 pid = fork();
190
191 if (pid < 0) {
192 fprintf(stderr, "Couldn't fork /bin/cp process: %s\n",
193 strerror(errno));
194 exit(1);
195 }
196
197 /* child */
198 if (!pid) {
199 execl("/bin/cp", "/bin/cp", infile, outfile, NULL);
200 fprintf(stderr, "Child couldn't exec /bin/cp: %s\n",
201 strerror(errno));
202 exit(1);
203 }
204
205 /* parent - wait for child to finish */
206 if (wait(&status) == -1) {
207 fprintf(stderr,
208 "Couldn't wait for /bin/cp process to exit: %s\n",
209 strerror(errno));
210 exit(1);
211 }
212
213 if (WIFEXITED(status)) {
214 status = WEXITSTATUS(status);
215 /* zero is normal exit */
216 if (!status)
217 return;
218 fprintf(stderr, "/bin/cp exited with status %d\n", status);
219 exit(1);
220 }
221
Bill Richardson779796f2014-09-23 11:47:40 -0700222 if (WIFSIGNALED(status)) {
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700223 status = WTERMSIG(status);
224 fprintf(stderr, "/bin/cp was killed with signal %d\n", status);
225 exit(1);
226 }
227
228 fprintf(stderr, "I have no idea what just happened\n");
229 exit(1);
230}
231
232
Bill Richardson25593382015-01-30 12:22:28 -0800233enum futil_file_err futil_map_file(int fd, int writeable,
234 uint8_t **buf, uint32_t *len)
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700235{
236 struct stat sb;
237 void *mmap_ptr;
238 uint32_t reasonable_len;
239
240 if (0 != fstat(fd, &sb)) {
241 fprintf(stderr, "Can't stat input file: %s\n",
242 strerror(errno));
Bill Richardson25593382015-01-30 12:22:28 -0800243 return FILE_ERR_STAT;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700244 }
245
David Riley05987b12015-02-05 19:22:49 -0800246#ifndef HAVE_MACOS
Bill Richardsone192e7f2014-09-23 12:49:26 -0700247 if (S_ISBLK(sb.st_mode))
248 ioctl(fd, BLKGETSIZE64, &sb.st_size);
David Riley05987b12015-02-05 19:22:49 -0800249#endif
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700250
251 /* If the image is larger than 2^32 bytes, it's wrong. */
252 if (sb.st_size < 0 || sb.st_size > UINT32_MAX) {
253 fprintf(stderr, "Image size is unreasonable\n");
Bill Richardson25593382015-01-30 12:22:28 -0800254 return FILE_ERR_SIZE;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700255 }
256 reasonable_len = (uint32_t)sb.st_size;
257
258 if (writeable)
259 mmap_ptr = mmap(0, sb.st_size,
260 PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
261 else
262 mmap_ptr = mmap(0, sb.st_size,
Bill Richardsone192e7f2014-09-23 12:49:26 -0700263 PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700264
265 if (mmap_ptr == (void *)-1) {
266 fprintf(stderr, "Can't mmap %s file: %s\n",
267 writeable ? "output" : "input",
268 strerror(errno));
Bill Richardson25593382015-01-30 12:22:28 -0800269 return FILE_ERR_MMAP;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700270 }
271
Bill Richardsone192e7f2014-09-23 12:49:26 -0700272 *buf = (uint8_t *)mmap_ptr;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700273 *len = reasonable_len;
Bill Richardson25593382015-01-30 12:22:28 -0800274 return FILE_ERR_NONE;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700275}
276
Bill Richardson25593382015-01-30 12:22:28 -0800277enum futil_file_err futil_unmap_file(int fd, int writeable,
278 uint8_t *buf, uint32_t len)
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700279{
Bill Richardsone192e7f2014-09-23 12:49:26 -0700280 void *mmap_ptr = buf;
Bill Richardson25593382015-01-30 12:22:28 -0800281 enum futil_file_err err = FILE_ERR_NONE;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700282
283 if (writeable &&
Bill Richardsone192e7f2014-09-23 12:49:26 -0700284 (0 != msync(mmap_ptr, len, MS_SYNC|MS_INVALIDATE))) {
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700285 fprintf(stderr, "msync failed: %s\n", strerror(errno));
Bill Richardson25593382015-01-30 12:22:28 -0800286 err = FILE_ERR_MSYNC;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700287 }
288
Bill Richardsone192e7f2014-09-23 12:49:26 -0700289 if (0 != munmap(mmap_ptr, len)) {
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700290 fprintf(stderr, "Can't munmap pointer: %s\n",
291 strerror(errno));
Bill Richardson25593382015-01-30 12:22:28 -0800292 if (err == FILE_ERR_NONE)
293 err = FILE_ERR_MUNMAP;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700294 }
295
Bill Richardson25593382015-01-30 12:22:28 -0800296 return err;
297}
298
299
300#define DISK_SECTOR_SIZE 512
301enum futil_file_type recognize_gpt(uint8_t *buf, uint32_t len)
302{
303 GptHeader *h;
304
305 /* GPT header starts at sector 1, is one sector long */
306 if (len < 2 * DISK_SECTOR_SIZE)
307 return FILE_TYPE_UNKNOWN;
308
309 h = (GptHeader *)(buf + DISK_SECTOR_SIZE);
310
311 if (memcmp(h->signature, GPT_HEADER_SIGNATURE,
312 GPT_HEADER_SIGNATURE_SIZE) &&
313 memcmp(h->signature, GPT_HEADER_SIGNATURE2,
314 GPT_HEADER_SIGNATURE_SIZE))
315 return FILE_TYPE_UNKNOWN;
316 if (h->revision != GPT_HEADER_REVISION)
317 return FILE_TYPE_UNKNOWN;
318 if (h->size < MIN_SIZE_OF_HEADER || h->size > MAX_SIZE_OF_HEADER)
319 return FILE_TYPE_UNKNOWN;
320
321 if (HeaderCrc(h) != h->header_crc32)
322 return FILE_TYPE_UNKNOWN;
323
324 return FILE_TYPE_CHROMIUMOS_DISK;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700325}