1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
7 static char *write_cpio_word(char *p
, uint32_t v
) {
8 static const char hex
[] = "0123456789abcdef";
12 /* Writes a CPIO header 8 character hex value */
14 for (UINTN i
= 0; i
< 8; i
++)
15 p
[7-i
] = hex
[(v
>> (4 * i
)) & 0xF];
20 static char *mangle_filename(char *p
, const char16_t
*f
) {
26 /* Basically converts UTF-16 to plain ASCII (note that we filtered non-ASCII filenames beforehand, so
27 * this operation is always safe) */
29 for (w
= p
; *f
!= 0; f
++) {
39 static char *pad4(char *p
, const char *start
) {
44 /* Appends NUL bytes to 'p', until the address is divisible by 4, when taken relative to 'start' */
46 while ((p
- start
) % 4 != 0)
52 static EFI_STATUS
pack_cpio_one(
53 const char16_t
*fname
,
56 const char *target_dir_prefix
,
58 uint32_t *inode_counter
,
60 UINTN
*cpio_buffer_size
) {
62 UINTN l
, target_dir_prefix_size
, fname_size
, q
;
66 assert(contents_size
|| contents_size
== 0);
67 assert(target_dir_prefix
);
68 assert(inode_counter
);
70 assert(cpio_buffer_size
);
72 /* Serializes one file in the cpio format understood by the kernel initrd logic.
74 * See: https://docs.kernel.org/driver-api/early-userspace/buffer-format.html */
76 if (contents_size
> UINT32_MAX
) /* cpio cannot deal with > 32bit file sizes */
77 return EFI_LOAD_ERROR
;
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
;
82 l
= 6 + 13*8 + 1 + 1; /* Fixed CPIO header size, slash separator, and NUL byte after the file name*/
84 target_dir_prefix_size
= strlen8(target_dir_prefix
);
85 if (l
> UINTN_MAX
- target_dir_prefix_size
)
86 return EFI_OUT_OF_RESOURCES
;
87 l
+= target_dir_prefix_size
;
89 fname_size
= strlen16(fname
);
90 if (l
> UINTN_MAX
- fname_size
)
91 return EFI_OUT_OF_RESOURCES
;
92 l
+= fname_size
; /* append space for file name */
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
;
98 /* Align the whole header to 4 byte size */
100 if (l
== UINTN_MAX
) /* overflow check */
101 return EFI_OUT_OF_RESOURCES
;
103 /* Align the contents to 4 byte size */
104 q
= ALIGN4(contents_size
);
105 if (q
== UINTN_MAX
) /* overflow check */
106 return EFI_OUT_OF_RESOURCES
;
108 if (l
> UINTN_MAX
- q
) /* overflow check */
109 return EFI_OUT_OF_RESOURCES
;
110 l
+= q
; /* Add contents to header */
112 if (*cpio_buffer_size
> UINTN_MAX
- l
) /* overflow check */
113 return EFI_OUT_OF_RESOURCES
;
114 a
= xrealloc(*cpio_buffer
, *cpio_buffer_size
, *cpio_buffer_size
+ l
);
117 a
= (char *) *cpio_buffer
+ *cpio_buffer_size
;
119 a
= mempcpy(a
, "070701", 6); /* magic ID */
121 a
= write_cpio_word(a
, (*inode_counter
)++); /* inode */
122 a
= write_cpio_word(a
, access_mode
| 0100000 /* = S_IFREG */); /* mode */
123 a
= write_cpio_word(a
, 0); /* uid */
124 a
= write_cpio_word(a
, 0); /* gid */
125 a
= write_cpio_word(a
, 1); /* nlink */
127 /* Note: we don't make any attempt to propagate the mtime here, for two reasons: it's a mess given
128 * that FAT usually is assumed to operate with timezoned timestamps, while UNIX does not. More
129 * importantly though: the modifications times would hamper our goals of providing stable
130 * measurements for the same boots. After all we extend the initrds we generate here into TPM2
132 a
= write_cpio_word(a
, 0); /* mtime */
133 a
= write_cpio_word(a
, contents_size
); /* size */
134 a
= write_cpio_word(a
, 0); /* major(dev) */
135 a
= write_cpio_word(a
, 0); /* minor(dev) */
136 a
= write_cpio_word(a
, 0); /* major(rdev) */
137 a
= write_cpio_word(a
, 0); /* minor(rdev) */
138 a
= write_cpio_word(a
, target_dir_prefix_size
+ fname_size
+ 2); /* fname size */
139 a
= write_cpio_word(a
, 0); /* "crc" */
141 a
= mempcpy(a
, target_dir_prefix
, target_dir_prefix_size
);
143 a
= mangle_filename(a
, fname
);
145 /* Pad to next multiple of 4 */
146 a
= pad4(a
, *cpio_buffer
);
148 a
= mempcpy(a
, contents
, contents_size
);
150 /* Pad to next multiple of 4 */
151 a
= pad4(a
, *cpio_buffer
);
153 assert(a
== (char *) *cpio_buffer
+ *cpio_buffer_size
+ l
);
154 *cpio_buffer_size
+= l
;
159 static EFI_STATUS
pack_cpio_dir(
161 uint32_t access_mode
,
162 uint32_t *inode_counter
,
164 UINTN
*cpio_buffer_size
) {
170 assert(inode_counter
);
172 assert(cpio_buffer_size
);
174 /* Serializes one directory inode in cpio format. Note that cpio archives must first create the dirs
175 * they want to place files in. */
177 if (*inode_counter
== UINT32_MAX
)
178 return EFI_OUT_OF_RESOURCES
;
180 l
= 6 + 13*8 + 1; /* Fixed CPIO header size, and NUL byte after the file name*/
182 path_size
= strlen8(path
);
183 if (l
> UINTN_MAX
- path_size
)
184 return EFI_OUT_OF_RESOURCES
;
187 /* Align the whole header to 4 byte size */
189 if (l
== UINTN_MAX
) /* overflow check */
190 return EFI_OUT_OF_RESOURCES
;
192 if (*cpio_buffer_size
> UINTN_MAX
- l
) /* overflow check */
193 return EFI_OUT_OF_RESOURCES
;
195 *cpio_buffer
= a
= xrealloc(*cpio_buffer
, *cpio_buffer_size
, *cpio_buffer_size
+ l
);
196 a
= (char *) *cpio_buffer
+ *cpio_buffer_size
;
198 a
= mempcpy(a
, "070701", 6); /* magic ID */
200 a
= write_cpio_word(a
, (*inode_counter
)++); /* inode */
201 a
= write_cpio_word(a
, access_mode
| 0040000 /* = S_IFDIR */); /* mode */
202 a
= write_cpio_word(a
, 0); /* uid */
203 a
= write_cpio_word(a
, 0); /* gid */
204 a
= write_cpio_word(a
, 1); /* nlink */
205 a
= write_cpio_word(a
, 0); /* mtime */
206 a
= write_cpio_word(a
, 0); /* size */
207 a
= write_cpio_word(a
, 0); /* major(dev) */
208 a
= write_cpio_word(a
, 0); /* minor(dev) */
209 a
= write_cpio_word(a
, 0); /* major(rdev) */
210 a
= write_cpio_word(a
, 0); /* minor(rdev) */
211 a
= write_cpio_word(a
, path_size
+ 1); /* fname size */
212 a
= write_cpio_word(a
, 0); /* "crc" */
214 a
= mempcpy(a
, path
, path_size
+ 1);
216 /* Pad to next multiple of 4 */
217 a
= pad4(a
, *cpio_buffer
);
219 assert(a
== (char *) *cpio_buffer
+ *cpio_buffer_size
+ l
);
221 *cpio_buffer_size
+= l
;
225 static EFI_STATUS
pack_cpio_prefix(
228 uint32_t *inode_counter
,
230 UINTN
*cpio_buffer_size
) {
235 assert(inode_counter
);
237 assert(cpio_buffer_size
);
239 /* Serializes directory inodes of all prefix paths of the specified path in cpio format. Note that
240 * (similar to mkdir -p behaviour) all leading paths are created with 0555 access mode, only the
241 * final dir is created with the specified directory access mode. */
243 for (const char *p
= path
;;) {
251 _cleanup_free_
char *t
= NULL
;
253 t
= xstrndup8(path
, e
- path
);
255 return EFI_OUT_OF_RESOURCES
;
257 err
= pack_cpio_dir(t
, 0555, inode_counter
, cpio_buffer
, cpio_buffer_size
);
258 if (err
!= EFI_SUCCESS
)
265 return pack_cpio_dir(path
, dir_mode
, inode_counter
, cpio_buffer
, cpio_buffer_size
);
268 static EFI_STATUS
pack_cpio_trailer(
270 UINTN
*cpio_buffer_size
) {
272 static const char trailer
[] =
287 "TRAILER!!!\0\0\0"; /* There's a fourth NUL byte appended here, because this is a string */
289 /* Generates the cpio trailer record that indicates the end of our initrd cpio archive */
292 assert(cpio_buffer_size
);
293 assert_cc(sizeof(trailer
) % 4 == 0);
295 *cpio_buffer
= xrealloc(*cpio_buffer
, *cpio_buffer_size
, *cpio_buffer_size
+ sizeof(trailer
));
296 memcpy((uint8_t*) *cpio_buffer
+ *cpio_buffer_size
, trailer
, sizeof(trailer
));
297 *cpio_buffer_size
+= sizeof(trailer
);
302 static EFI_STATUS
measure_cpio(
305 const uint32_t tpm_pcr
[],
307 const char16_t
*tpm_description
,
308 bool *ret_measured
) {
313 assert(buffer
|| buffer_size
== 0);
314 assert(tpm_pcr
|| n_tpm_pcr
== 0);
316 for (UINTN i
= 0; i
< n_tpm_pcr
; i
++) {
319 if (tpm_pcr
[i
] == UINT32_MAX
) /* Disabled */
324 POINTER_TO_PHYSICAL_ADDRESS(buffer
),
328 if (err
!= EFI_SUCCESS
) {
329 log_error_stall(L
"Unable to add initrd TPM measurement for PCR %u (%s), ignoring: %r", tpm_pcr
[i
], tpm_description
, err
);
334 if (measured
!= false)
339 *ret_measured
= measured
> 0;
344 EFI_STATUS
pack_cpio(
345 EFI_LOADED_IMAGE_PROTOCOL
*loaded_image
,
346 const char16_t
*dropin_dir
,
347 const char16_t
*match_suffix
,
348 const char *target_dir_prefix
,
350 uint32_t access_mode
,
351 const uint32_t tpm_pcr
[],
353 const char16_t
*tpm_description
,
355 UINTN
*ret_buffer_size
,
356 bool *ret_measured
) {
358 _cleanup_(file_closep
) EFI_FILE
*root
= NULL
, *extra_dir
= NULL
;
359 UINTN dirent_size
= 0, buffer_size
= 0, n_items
= 0, n_allocated
= 0;
360 _cleanup_free_ char16_t
*rel_dropin_dir
= NULL
;
361 _cleanup_free_ EFI_FILE_INFO
*dirent
= NULL
;
362 _cleanup_(strv_freep
) char16_t
**items
= NULL
;
363 _cleanup_free_
void *buffer
= NULL
;
364 uint32_t inode
= 1; /* inode counter, so that each item gets a new inode */
367 assert(loaded_image
);
368 assert(target_dir_prefix
);
369 assert(tpm_pcr
|| n_tpm_pcr
== 0);
371 assert(ret_buffer_size
);
373 if (!loaded_image
->DeviceHandle
)
376 err
= open_volume(loaded_image
->DeviceHandle
, &root
);
377 if (err
== EFI_UNSUPPORTED
)
378 /* Error will be unsupported if the bootloader doesn't implement the file system protocol on
379 * its file handles. */
381 if (err
!= EFI_SUCCESS
)
382 return log_error_status_stall(
383 err
, L
"Unable to open root directory: %r", err
);
386 dropin_dir
= rel_dropin_dir
= xpool_print(L
"%D.extra.d", loaded_image
->FilePath
);
388 err
= open_directory(root
, dropin_dir
, &extra_dir
);
389 if (err
== EFI_NOT_FOUND
)
390 /* No extra subdir, that's totally OK */
392 if (err
!= EFI_SUCCESS
)
393 return log_error_status_stall(err
, L
"Failed to open extra directory of loaded image: %r", err
);
396 _cleanup_free_ char16_t
*d
= NULL
;
398 err
= readdir_harder(extra_dir
, &dirent
, &dirent_size
);
399 if (err
!= EFI_SUCCESS
)
400 return log_error_status_stall(err
, L
"Failed to read extra directory of loaded image: %r", err
);
401 if (!dirent
) /* End of directory */
404 if (dirent
->FileName
[0] == '.')
406 if (FLAGS_SET(dirent
->Attribute
, EFI_FILE_DIRECTORY
))
408 if (match_suffix
&& !endswith_no_case(dirent
->FileName
, match_suffix
))
410 if (!is_ascii(dirent
->FileName
))
412 if (strlen16(dirent
->FileName
) > 255) /* Max filename size on Linux */
415 d
= xstrdup16(dirent
->FileName
);
417 if (n_items
+2 > n_allocated
) {
420 /* We allocate 16 entries at a time, as a matter of optimization */
421 if (n_items
> (UINTN_MAX
/ sizeof(uint16_t)) - 16) /* Overflow check, just in case */
425 items
= xrealloc(items
, n_allocated
* sizeof(uint16_t *), m
* sizeof(uint16_t *));
429 items
[n_items
++] = TAKE_PTR(d
);
430 items
[n_items
] = NULL
; /* Let's always NUL terminate, to make freeing via strv_free() easy */
434 /* Empty directory */
437 /* Now, sort the files we found, to make this uniform and stable (and to ensure the TPM measurements
438 * are not dependent on read order) */
439 sort_pointer_array((void**) items
, n_items
, (compare_pointer_func_t
) strcmp16
);
441 /* Generate the leading directory inodes right before adding the first files, to the
442 * archive. Otherwise the cpio archive cannot be unpacked, since the leading dirs won't exist. */
443 err
= pack_cpio_prefix(target_dir_prefix
, dir_mode
, &inode
, &buffer
, &buffer_size
);
444 if (err
!= EFI_SUCCESS
)
445 return log_error_status_stall(err
, L
"Failed to pack cpio prefix: %r", err
);
447 for (UINTN i
= 0; i
< n_items
; i
++) {
448 _cleanup_free_
char *content
= NULL
;
451 err
= file_read(extra_dir
, items
[i
], 0, 0, &content
, &contentsize
);
452 if (err
!= EFI_SUCCESS
) {
453 log_error_status_stall(err
, L
"Failed to read %s, ignoring: %r", items
[i
], err
);
459 content
, contentsize
,
463 &buffer
, &buffer_size
);
464 if (err
!= EFI_SUCCESS
)
465 return log_error_status_stall(err
, L
"Failed to pack cpio file %s: %r", dirent
->FileName
, err
);
468 err
= pack_cpio_trailer(&buffer
, &buffer_size
);
469 if (err
!= EFI_SUCCESS
)
470 return log_error_status_stall(err
, L
"Failed to pack cpio trailer: %r");
472 err
= measure_cpio(buffer
, buffer_size
, tpm_pcr
, n_tpm_pcr
, tpm_description
, ret_measured
);
473 if (err
!= EFI_SUCCESS
)
476 *ret_buffer
= TAKE_PTR(buffer
);
477 *ret_buffer_size
= buffer_size
;
483 *ret_buffer_size
= 0;
486 *ret_measured
= n_tpm_pcr
> 0;
491 EFI_STATUS
pack_cpio_literal(
494 const char *target_dir_prefix
,
495 const char16_t
*target_filename
,
497 uint32_t access_mode
,
498 const uint32_t tpm_pcr
[],
500 const char16_t
*tpm_description
,
502 UINTN
*ret_buffer_size
,
503 bool *ret_measured
) {
505 uint32_t inode
= 1; /* inode counter, so that each item gets a new inode */
506 _cleanup_free_
void *buffer
= NULL
;
510 assert(data
|| data_size
== 0);
511 assert(target_dir_prefix
);
512 assert(target_filename
);
513 assert(tpm_pcr
|| n_tpm_pcr
== 0);
515 assert(ret_buffer_size
);
517 /* Generate the leading directory inodes right before adding the first files, to the
518 * archive. Otherwise the cpio archive cannot be unpacked, since the leading dirs won't exist. */
520 err
= pack_cpio_prefix(target_dir_prefix
, dir_mode
, &inode
, &buffer
, &buffer_size
);
521 if (err
!= EFI_SUCCESS
)
522 return log_error_status_stall(err
, L
"Failed to pack cpio prefix: %r", err
);
530 &buffer
, &buffer_size
);
531 if (err
!= EFI_SUCCESS
)
532 return log_error_status_stall(err
, L
"Failed to pack cpio file %s: %r", target_filename
, err
);
534 err
= pack_cpio_trailer(&buffer
, &buffer_size
);
535 if (err
!= EFI_SUCCESS
)
536 return log_error_status_stall(err
, L
"Failed to pack cpio trailer: %r");
538 err
= measure_cpio(buffer
, buffer_size
, tpm_pcr
, n_tpm_pcr
, tpm_description
, ret_measured
);
539 if (err
!= EFI_SUCCESS
)
542 *ret_buffer
= TAKE_PTR(buffer
);
543 *ret_buffer_size
= buffer_size
;