]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/boot/efi/cpio.c
tree-wide: "<n>bit" → "<n>-bit"
[thirdparty/systemd.git] / src / boot / efi / cpio.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "cpio.h"
4 #include "device-path-util.h"
5 #include "measure.h"
6 #include "proto/device-path.h"
7 #include "util.h"
8
9 static char *write_cpio_word(char *p, uint32_t v) {
10 static const char hex[] = "0123456789abcdef";
11
12 assert(p);
13
14 /* Writes a CPIO header 8 character hex value */
15
16 for (size_t i = 0; i < 8; i++)
17 p[7-i] = hex[(v >> (4 * i)) & 0xF];
18
19 return p + 8;
20 }
21
22 static char *mangle_filename(char *p, const char16_t *f) {
23 char* w;
24
25 assert(p);
26 assert(f);
27
28 /* Basically converts UTF-16 to plain ASCII (note that we filtered non-ASCII filenames beforehand, so
29 * this operation is always safe) */
30
31 for (w = p; *f != 0; f++) {
32 assert(*f <= 0x7fu);
33
34 *(w++) = *f;
35 }
36
37 *(w++) = 0;
38 return w;
39 }
40
41 static char *pad4(char *p, const char *start) {
42 assert(p);
43 assert(start);
44 assert(p >= start);
45
46 /* Appends NUL bytes to 'p', until the address is divisible by 4, when taken relative to 'start' */
47
48 while ((p - start) % 4 != 0)
49 *(p++) = 0;
50
51 return p;
52 }
53
54 static EFI_STATUS pack_cpio_one(
55 const char16_t *fname,
56 const void *contents,
57 size_t contents_size,
58 const char *target_dir_prefix,
59 uint32_t access_mode,
60 uint32_t *inode_counter,
61 void **cpio_buffer,
62 size_t *cpio_buffer_size) {
63
64 size_t l, target_dir_prefix_size, fname_size, q;
65 char *a;
66
67 assert(fname);
68 assert(contents_size || contents_size == 0);
69 assert(target_dir_prefix);
70 assert(inode_counter);
71 assert(cpio_buffer);
72 assert(cpio_buffer_size);
73
74 /* Serializes one file in the cpio format understood by the kernel initrd logic.
75 *
76 * See: https://docs.kernel.org/driver-api/early-userspace/buffer-format.html */
77
78 if (contents_size > UINT32_MAX) /* cpio cannot deal with > 32-bit file sizes */
79 return EFI_LOAD_ERROR;
80
81 if (*inode_counter == UINT32_MAX) /* more than 2^32-1 inodes? yikes. cpio doesn't support that either */
82 return EFI_OUT_OF_RESOURCES;
83
84 l = 6 + 13*8 + 1 + 1; /* Fixed CPIO header size, slash separator, and NUL byte after the file name */
85
86 target_dir_prefix_size = strlen8(target_dir_prefix);
87 if (l > SIZE_MAX - target_dir_prefix_size)
88 return EFI_OUT_OF_RESOURCES;
89 l += target_dir_prefix_size;
90
91 fname_size = strlen16(fname);
92 if (l > SIZE_MAX - fname_size)
93 return EFI_OUT_OF_RESOURCES;
94 l += fname_size; /* append space for file name */
95
96 /* CPIO can't deal with fnames longer than 2^32-1 */
97 if (target_dir_prefix_size + fname_size >= UINT32_MAX)
98 return EFI_OUT_OF_RESOURCES;
99
100 /* Align the whole header to 4 byte size */
101 l = ALIGN4(l);
102 if (l == SIZE_MAX) /* overflow check */
103 return EFI_OUT_OF_RESOURCES;
104
105 /* Align the contents to 4 byte size */
106 q = ALIGN4(contents_size);
107 if (q == SIZE_MAX) /* overflow check */
108 return EFI_OUT_OF_RESOURCES;
109
110 if (l > SIZE_MAX - q) /* overflow check */
111 return EFI_OUT_OF_RESOURCES;
112 l += q; /* Add contents to header */
113
114 if (*cpio_buffer_size > SIZE_MAX - l) /* overflow check */
115 return EFI_OUT_OF_RESOURCES;
116 a = xrealloc(*cpio_buffer, *cpio_buffer_size, *cpio_buffer_size + l);
117
118 *cpio_buffer = a;
119 a = (char *) *cpio_buffer + *cpio_buffer_size;
120
121 a = mempcpy(a, "070701", 6); /* magic ID */
122
123 a = write_cpio_word(a, (*inode_counter)++); /* inode */
124 a = write_cpio_word(a, access_mode | 0100000 /* = S_IFREG */); /* mode */
125 a = write_cpio_word(a, 0); /* uid */
126 a = write_cpio_word(a, 0); /* gid */
127 a = write_cpio_word(a, 1); /* nlink */
128
129 /* Note: we don't make any attempt to propagate the mtime here, for two reasons: it's a mess given
130 * that FAT usually is assumed to operate with timezoned timestamps, while UNIX does not. More
131 * importantly though: the modifications times would hamper our goals of providing stable
132 * measurements for the same boots. After all we extend the initrds we generate here into TPM2
133 * PCRs. */
134 a = write_cpio_word(a, 0); /* mtime */
135 a = write_cpio_word(a, contents_size); /* size */
136 a = write_cpio_word(a, 0); /* major(dev) */
137 a = write_cpio_word(a, 0); /* minor(dev) */
138 a = write_cpio_word(a, 0); /* major(rdev) */
139 a = write_cpio_word(a, 0); /* minor(rdev) */
140 a = write_cpio_word(a, target_dir_prefix_size + fname_size + 2); /* fname size */
141 a = write_cpio_word(a, 0); /* "crc" */
142
143 a = mempcpy(a, target_dir_prefix, target_dir_prefix_size);
144 *(a++) = '/';
145 a = mangle_filename(a, fname);
146
147 /* Pad to next multiple of 4 */
148 a = pad4(a, *cpio_buffer);
149
150 a = mempcpy(a, contents, contents_size);
151
152 /* Pad to next multiple of 4 */
153 a = pad4(a, *cpio_buffer);
154
155 assert(a == (char *) *cpio_buffer + *cpio_buffer_size + l);
156 *cpio_buffer_size += l;
157
158 return EFI_SUCCESS;
159 }
160
161 static EFI_STATUS pack_cpio_dir(
162 const char *path,
163 uint32_t access_mode,
164 uint32_t *inode_counter,
165 void **cpio_buffer,
166 size_t *cpio_buffer_size) {
167
168 size_t l, path_size;
169 char *a;
170
171 assert(path);
172 assert(inode_counter);
173 assert(cpio_buffer);
174 assert(cpio_buffer_size);
175
176 /* Serializes one directory inode in cpio format. Note that cpio archives must first create the dirs
177 * they want to place files in. */
178
179 if (*inode_counter == UINT32_MAX)
180 return EFI_OUT_OF_RESOURCES;
181
182 l = 6 + 13*8 + 1; /* Fixed CPIO header size, and NUL byte after the file name */
183
184 path_size = strlen8(path);
185 if (l > SIZE_MAX - path_size)
186 return EFI_OUT_OF_RESOURCES;
187 l += path_size;
188
189 /* Align the whole header to 4 byte size */
190 l = ALIGN4(l);
191 if (l == SIZE_MAX) /* overflow check */
192 return EFI_OUT_OF_RESOURCES;
193
194 if (*cpio_buffer_size > SIZE_MAX - l) /* overflow check */
195 return EFI_OUT_OF_RESOURCES;
196
197 *cpio_buffer = a = xrealloc(*cpio_buffer, *cpio_buffer_size, *cpio_buffer_size + l);
198 a = (char *) *cpio_buffer + *cpio_buffer_size;
199
200 a = mempcpy(a, "070701", 6); /* magic ID */
201
202 a = write_cpio_word(a, (*inode_counter)++); /* inode */
203 a = write_cpio_word(a, access_mode | 0040000 /* = S_IFDIR */); /* mode */
204 a = write_cpio_word(a, 0); /* uid */
205 a = write_cpio_word(a, 0); /* gid */
206 a = write_cpio_word(a, 1); /* nlink */
207 a = write_cpio_word(a, 0); /* mtime */
208 a = write_cpio_word(a, 0); /* size */
209 a = write_cpio_word(a, 0); /* major(dev) */
210 a = write_cpio_word(a, 0); /* minor(dev) */
211 a = write_cpio_word(a, 0); /* major(rdev) */
212 a = write_cpio_word(a, 0); /* minor(rdev) */
213 a = write_cpio_word(a, path_size + 1); /* fname size */
214 a = write_cpio_word(a, 0); /* "crc" */
215
216 a = mempcpy(a, path, path_size + 1);
217
218 /* Pad to next multiple of 4 */
219 a = pad4(a, *cpio_buffer);
220
221 assert(a == (char *) *cpio_buffer + *cpio_buffer_size + l);
222
223 *cpio_buffer_size += l;
224 return EFI_SUCCESS;
225 }
226
227 static EFI_STATUS pack_cpio_prefix(
228 const char *path,
229 uint32_t dir_mode,
230 uint32_t *inode_counter,
231 void **cpio_buffer,
232 size_t *cpio_buffer_size) {
233
234 EFI_STATUS err;
235
236 assert(path);
237 assert(inode_counter);
238 assert(cpio_buffer);
239 assert(cpio_buffer_size);
240
241 /* Serializes directory inodes of all prefix paths of the specified path in cpio format. Note that
242 * (similar to mkdir -p behaviour) all leading paths are created with 0555 access mode, only the
243 * final dir is created with the specified directory access mode. */
244
245 for (const char *p = path;;) {
246 const char *e;
247
248 e = strchr8(p, '/');
249 if (!e)
250 break;
251
252 if (e > p) {
253 _cleanup_free_ char *t = NULL;
254
255 t = xstrndup8(path, e - path);
256 if (!t)
257 return EFI_OUT_OF_RESOURCES;
258
259 err = pack_cpio_dir(t, 0555, inode_counter, cpio_buffer, cpio_buffer_size);
260 if (err != EFI_SUCCESS)
261 return err;
262 }
263
264 p = e + 1;
265 }
266
267 return pack_cpio_dir(path, dir_mode, inode_counter, cpio_buffer, cpio_buffer_size);
268 }
269
270 static EFI_STATUS pack_cpio_trailer(
271 void **cpio_buffer,
272 size_t *cpio_buffer_size) {
273
274 static const char trailer[] =
275 "070701"
276 "00000000"
277 "00000000"
278 "00000000"
279 "00000000"
280 "00000001"
281 "00000000"
282 "00000000"
283 "00000000"
284 "00000000"
285 "00000000"
286 "00000000"
287 "0000000B"
288 "00000000"
289 "TRAILER!!!\0\0\0"; /* There's a fourth NUL byte appended here, because this is a string */
290
291 /* Generates the cpio trailer record that indicates the end of our initrd cpio archive */
292
293 assert(cpio_buffer);
294 assert(cpio_buffer_size);
295 assert_cc(sizeof(trailer) % 4 == 0);
296
297 *cpio_buffer = xrealloc(*cpio_buffer, *cpio_buffer_size, *cpio_buffer_size + sizeof(trailer));
298 memcpy((uint8_t*) *cpio_buffer + *cpio_buffer_size, trailer, sizeof(trailer));
299 *cpio_buffer_size += sizeof(trailer);
300
301 return EFI_SUCCESS;
302 }
303
304 EFI_STATUS pack_cpio(
305 EFI_LOADED_IMAGE_PROTOCOL *loaded_image,
306 const char16_t *dropin_dir,
307 const char16_t *match_suffix,
308 const char *target_dir_prefix,
309 uint32_t dir_mode,
310 uint32_t access_mode,
311 uint32_t tpm_pcr,
312 const char16_t *tpm_description,
313 void **ret_buffer,
314 size_t *ret_buffer_size,
315 bool *ret_measured) {
316
317 _cleanup_(file_closep) EFI_FILE *root = NULL, *extra_dir = NULL;
318 size_t dirent_size = 0, buffer_size = 0, n_items = 0, n_allocated = 0;
319 _cleanup_free_ char16_t *rel_dropin_dir = NULL;
320 _cleanup_free_ EFI_FILE_INFO *dirent = NULL;
321 _cleanup_(strv_freep) char16_t **items = NULL;
322 _cleanup_free_ void *buffer = NULL;
323 uint32_t inode = 1; /* inode counter, so that each item gets a new inode */
324 EFI_STATUS err;
325
326 assert(loaded_image);
327 assert(target_dir_prefix);
328 assert(ret_buffer);
329 assert(ret_buffer_size);
330
331 if (!loaded_image->DeviceHandle)
332 goto nothing;
333
334 err = open_volume(loaded_image->DeviceHandle, &root);
335 if (err == EFI_UNSUPPORTED)
336 /* Error will be unsupported if the bootloader doesn't implement the file system protocol on
337 * its file handles. */
338 goto nothing;
339 if (err != EFI_SUCCESS)
340 return log_error_status(err, "Unable to open root directory: %m");
341
342 if (!dropin_dir)
343 dropin_dir = rel_dropin_dir = get_extra_dir(loaded_image->FilePath);
344
345 err = open_directory(root, dropin_dir, &extra_dir);
346 if (err == EFI_NOT_FOUND)
347 /* No extra subdir, that's totally OK */
348 goto nothing;
349 if (err != EFI_SUCCESS)
350 return log_error_status(err, "Failed to open extra directory of loaded image: %m");
351
352 for (;;) {
353 _cleanup_free_ char16_t *d = NULL;
354
355 err = readdir(extra_dir, &dirent, &dirent_size);
356 if (err != EFI_SUCCESS)
357 return log_error_status(err, "Failed to read extra directory of loaded image: %m");
358 if (!dirent) /* End of directory */
359 break;
360
361 if (dirent->FileName[0] == '.')
362 continue;
363 if (FLAGS_SET(dirent->Attribute, EFI_FILE_DIRECTORY))
364 continue;
365 if (match_suffix && !endswith_no_case(dirent->FileName, match_suffix))
366 continue;
367 if (!is_ascii(dirent->FileName))
368 continue;
369 if (strlen16(dirent->FileName) > 255) /* Max filename size on Linux */
370 continue;
371
372 d = xstrdup16(dirent->FileName);
373
374 if (n_items+2 > n_allocated) {
375 /* We allocate 16 entries at a time, as a matter of optimization */
376 if (n_items > (SIZE_MAX / sizeof(uint16_t)) - 16) /* Overflow check, just in case */
377 return log_oom();
378
379 size_t m = n_items + 16;
380 items = xrealloc(items, n_allocated * sizeof(uint16_t *), m * sizeof(uint16_t *));
381 n_allocated = m;
382 }
383
384 items[n_items++] = TAKE_PTR(d);
385 items[n_items] = NULL; /* Let's always NUL terminate, to make freeing via strv_free() easy */
386 }
387
388 if (n_items == 0)
389 /* Empty directory */
390 goto nothing;
391
392 /* Now, sort the files we found, to make this uniform and stable (and to ensure the TPM measurements
393 * are not dependent on read order) */
394 sort_pointer_array((void**) items, n_items, (compare_pointer_func_t) strcmp16);
395
396 /* Generate the leading directory inodes right before adding the first files, to the
397 * archive. Otherwise the cpio archive cannot be unpacked, since the leading dirs won't exist. */
398 err = pack_cpio_prefix(target_dir_prefix, dir_mode, &inode, &buffer, &buffer_size);
399 if (err != EFI_SUCCESS)
400 return log_error_status(err, "Failed to pack cpio prefix: %m");
401
402 for (size_t i = 0; i < n_items; i++) {
403 _cleanup_free_ char *content = NULL;
404 size_t contentsize = 0; /* avoid false maybe-uninitialized warning */
405
406 err = file_read(extra_dir, items[i], 0, 0, &content, &contentsize);
407 if (err != EFI_SUCCESS) {
408 log_error_status(err, "Failed to read %ls, ignoring: %m", items[i]);
409 continue;
410 }
411
412 err = pack_cpio_one(
413 items[i],
414 content, contentsize,
415 target_dir_prefix,
416 access_mode,
417 &inode,
418 &buffer, &buffer_size);
419 if (err != EFI_SUCCESS)
420 return log_error_status(err, "Failed to pack cpio file %ls: %m", dirent->FileName);
421 }
422
423 err = pack_cpio_trailer(&buffer, &buffer_size);
424 if (err != EFI_SUCCESS)
425 return log_error_status(err, "Failed to pack cpio trailer: %m");
426
427 err = tpm_log_event(
428 tpm_pcr, POINTER_TO_PHYSICAL_ADDRESS(buffer), buffer_size, tpm_description, ret_measured);
429 if (err != EFI_SUCCESS)
430 return log_error_status(
431 err,
432 "Unable to add cpio TPM measurement for PCR %u (%ls), ignoring: %m",
433 tpm_pcr,
434 tpm_description);
435
436 *ret_buffer = TAKE_PTR(buffer);
437 *ret_buffer_size = buffer_size;
438
439 return EFI_SUCCESS;
440
441 nothing:
442 *ret_buffer = NULL;
443 *ret_buffer_size = 0;
444
445 if (ret_measured)
446 *ret_measured = false;
447
448 return EFI_SUCCESS;
449 }
450
451 EFI_STATUS pack_cpio_literal(
452 const void *data,
453 size_t data_size,
454 const char *target_dir_prefix,
455 const char16_t *target_filename,
456 uint32_t dir_mode,
457 uint32_t access_mode,
458 uint32_t tpm_pcr,
459 const char16_t *tpm_description,
460 void **ret_buffer,
461 size_t *ret_buffer_size,
462 bool *ret_measured) {
463
464 uint32_t inode = 1; /* inode counter, so that each item gets a new inode */
465 _cleanup_free_ void *buffer = NULL;
466 size_t buffer_size = 0;
467 EFI_STATUS err;
468
469 assert(data || data_size == 0);
470 assert(target_dir_prefix);
471 assert(target_filename);
472 assert(ret_buffer);
473 assert(ret_buffer_size);
474
475 /* Generate the leading directory inodes right before adding the first files, to the
476 * archive. Otherwise the cpio archive cannot be unpacked, since the leading dirs won't exist. */
477
478 err = pack_cpio_prefix(target_dir_prefix, dir_mode, &inode, &buffer, &buffer_size);
479 if (err != EFI_SUCCESS)
480 return log_error_status(err, "Failed to pack cpio prefix: %m");
481
482 err = pack_cpio_one(
483 target_filename,
484 data, data_size,
485 target_dir_prefix,
486 access_mode,
487 &inode,
488 &buffer, &buffer_size);
489 if (err != EFI_SUCCESS)
490 return log_error_status(err, "Failed to pack cpio file %ls: %m", target_filename);
491
492 err = pack_cpio_trailer(&buffer, &buffer_size);
493 if (err != EFI_SUCCESS)
494 return log_error_status(err, "Failed to pack cpio trailer: %m");
495
496 err = tpm_log_event(
497 tpm_pcr, POINTER_TO_PHYSICAL_ADDRESS(buffer), buffer_size, tpm_description, ret_measured);
498 if (err != EFI_SUCCESS)
499 return log_error_status(
500 err,
501 "Unable to add cpio TPM measurement for PCR %u (%ls), ignoring: %m",
502 tpm_pcr,
503 tpm_description);
504
505 *ret_buffer = TAKE_PTR(buffer);
506 *ret_buffer_size = buffer_size;
507
508 return EFI_SUCCESS;
509 }