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