boot: introduce a common structure for cpio target dirs

There are only a few target dirs we place resources in when generating
on-the-fly initrd cpios. These dirs have very specific attributes.
Instead of repeating this everywhere, let's encapsulate them in a new
explicit structure, that we can reuse at various places.

This is preparation for placing extra resources of Type #1 entry also in
them without having to encode access modes at multiple places
redundantly.
This commit is contained in:
Lennart Poettering
2026-04-21 08:30:26 +02:00
parent 426134b0e7
commit 0e98e6ccd1
3 changed files with 99 additions and 60 deletions
+74 -30
View File
@@ -56,8 +56,7 @@ static EFI_STATUS pack_cpio_one(
const char16_t *fname,
const void *contents,
size_t contents_size,
const char *target_dir_prefix,
uint32_t access_mode,
const CpioTarget *target,
uint32_t *inode_counter,
void **cpio_buffer,
size_t *cpio_buffer_size) {
@@ -67,7 +66,7 @@ static EFI_STATUS pack_cpio_one(
assert(fname);
assert(contents || contents_size == 0);
assert(target_dir_prefix);
assert(target);
assert(inode_counter);
assert(cpio_buffer);
assert(cpio_buffer_size);
@@ -84,7 +83,7 @@ static EFI_STATUS pack_cpio_one(
l = 6 + 13*8 + 1 + 1; /* Fixed CPIO header size, slash separator, and NUL byte after the file name */
target_dir_prefix_size = strlen8(target_dir_prefix);
target_dir_prefix_size = strlen8(target->directory);
if (l > SIZE_MAX - target_dir_prefix_size)
return EFI_OUT_OF_RESOURCES;
l += target_dir_prefix_size;
@@ -121,11 +120,11 @@ static EFI_STATUS pack_cpio_one(
a = mempcpy(a, "070701", 6); /* magic ID */
a = write_cpio_word(a, (*inode_counter)++); /* inode */
a = write_cpio_word(a, access_mode | 0100000 /* = S_IFREG */); /* mode */
a = write_cpio_word(a, 0); /* uid */
a = write_cpio_word(a, 0); /* gid */
a = write_cpio_word(a, 1); /* nlink */
a = write_cpio_word(a, (*inode_counter)++); /* inode */
a = write_cpio_word(a, target->access_mode | 0100000 /* = S_IFREG */); /* mode */
a = write_cpio_word(a, 0); /* uid */
a = write_cpio_word(a, 0); /* gid */
a = write_cpio_word(a, 1); /* nlink */
/* Note: we don't make any attempt to propagate the mtime here, for two reasons: it's a mess given
* that FAT usually is assumed to operate with timezoned timestamps, while UNIX does not. More
@@ -141,7 +140,7 @@ static EFI_STATUS pack_cpio_one(
a = write_cpio_word(a, target_dir_prefix_size + fname_size + 2); /* fname size */
a = write_cpio_word(a, 0); /* "crc" */
a = mempcpy(a, target_dir_prefix, target_dir_prefix_size);
a = mempcpy(a, target->directory, target_dir_prefix_size);
*(a++) = '/';
a = mangle_filename(a, fname);
@@ -226,15 +225,14 @@ static EFI_STATUS pack_cpio_dir(
}
static EFI_STATUS pack_cpio_prefix(
const char *path,
uint32_t dir_mode,
const CpioTarget *target,
uint32_t *inode_counter,
void **cpio_buffer,
size_t *cpio_buffer_size) {
EFI_STATUS err;
assert(path);
assert(target);
assert(inode_counter);
assert(cpio_buffer);
assert(cpio_buffer_size);
@@ -243,7 +241,7 @@ static EFI_STATUS pack_cpio_prefix(
* (similar to mkdir -p behaviour) all leading paths are created with 0555 access mode, only the
* final dir is created with the specified directory access mode. */
for (const char *p = path;;) {
for (const char *p = target->directory;;) {
const char *e;
e = strchr8(p, '/');
@@ -253,7 +251,7 @@ static EFI_STATUS pack_cpio_prefix(
if (e > p) {
_cleanup_free_ char *t = NULL;
t = xstrndup8(path, e - path);
t = xstrndup8(target->directory, e - target->directory);
if (!t)
return EFI_OUT_OF_RESOURCES;
@@ -265,7 +263,7 @@ static EFI_STATUS pack_cpio_prefix(
p = e + 1;
}
return pack_cpio_dir(path, dir_mode, inode_counter, cpio_buffer, cpio_buffer_size);
return pack_cpio_dir(target->directory, target->dir_mode, inode_counter, cpio_buffer, cpio_buffer_size);
}
static EFI_STATUS pack_cpio_trailer(
@@ -307,9 +305,7 @@ EFI_STATUS pack_cpio(
const char16_t *dropin_dir,
const char16_t *match_suffix,
const char16_t *exclude_suffix,
const char *target_dir_prefix,
uint32_t dir_mode,
uint32_t access_mode,
const CpioTarget *target,
uint32_t tpm_pcr,
const char16_t *tpm_description,
struct iovec *ret_buffer,
@@ -325,7 +321,7 @@ EFI_STATUS pack_cpio(
EFI_STATUS err;
assert(loaded_image);
assert(target_dir_prefix);
assert(target);
assert(ret_buffer);
if (!loaded_image->DeviceHandle)
@@ -400,7 +396,7 @@ EFI_STATUS pack_cpio(
/* Generate the leading directory inodes right before adding the first files, to the
* archive. Otherwise the cpio archive cannot be unpacked, since the leading dirs won't exist. */
err = pack_cpio_prefix(target_dir_prefix, dir_mode, &inode, &buffer, &buffer_size);
err = pack_cpio_prefix(target, &inode, &buffer, &buffer_size);
if (err != EFI_SUCCESS)
return log_error_status(err, "Failed to pack cpio prefix: %m");
@@ -417,8 +413,7 @@ EFI_STATUS pack_cpio(
err = pack_cpio_one(
items[i],
content, contentsize,
target_dir_prefix,
access_mode,
target,
&inode,
&buffer, &buffer_size);
if (err != EFI_SUCCESS)
@@ -453,10 +448,8 @@ nothing:
EFI_STATUS pack_cpio_literal(
const void *data,
size_t data_size,
const char *target_dir_prefix,
const CpioTarget *target,
const char16_t *target_filename,
uint32_t dir_mode,
uint32_t access_mode,
uint32_t tpm_pcr,
const char16_t *tpm_description,
struct iovec *ret_buffer,
@@ -468,22 +461,21 @@ EFI_STATUS pack_cpio_literal(
EFI_STATUS err;
assert(data || data_size == 0);
assert(target_dir_prefix);
assert(target);
assert(target_filename);
assert(ret_buffer);
/* Generate the leading directory inodes right before adding the first files, to the
* archive. Otherwise the cpio archive cannot be unpacked, since the leading dirs won't exist. */
err = pack_cpio_prefix(target_dir_prefix, dir_mode, &inode, &buffer, &buffer_size);
err = pack_cpio_prefix(target, &inode, &buffer, &buffer_size);
if (err != EFI_SUCCESS)
return log_error_status(err, "Failed to pack cpio prefix: %m");
err = pack_cpio_one(
target_filename,
data, data_size,
target_dir_prefix,
access_mode,
target,
&inode,
&buffer, &buffer_size);
if (err != EFI_SUCCESS)
@@ -505,3 +497,55 @@ EFI_STATUS pack_cpio_literal(
*ret_buffer = IOVEC_MAKE(TAKE_PTR(buffer), buffer_size);
return EFI_SUCCESS;
}
/* The following are canonical definitions of the various cpio target directories we place resources in. We
* define them here in a single canonical list of targets because we need to reuse them at various places
* (well, some of them at least), and we don't want the access modes to deviate slightly on each use. */
const CpioTarget cpio_target_credentials = {
.directory = ".extra/credentials",
.dir_mode = 0500,
.access_mode = 0400,
};
const CpioTarget cpio_target_global_credentials = {
.directory = ".extra/global_credentials",
.dir_mode = 0500,
.access_mode = 0400,
};
const CpioTarget cpio_target_sysext = {
.directory = ".extra/sysext",
.dir_mode = 0555,
.access_mode = 0444,
};
const CpioTarget cpio_target_global_sysext = {
.directory = ".extra/global_sysext",
.dir_mode = 0555,
.access_mode = 0444,
};
const CpioTarget cpio_target_confext = {
.directory = ".extra/confext",
.dir_mode = 0555,
.access_mode = 0444,
};
const CpioTarget cpio_target_global_confext = {
.directory = ".extra/global_confext",
.dir_mode = 0555,
.access_mode = 0444,
};
const CpioTarget cpio_target_meta = {
.directory = ".extra",
.dir_mode = 0555,
.access_mode = 0444,
};
const CpioTarget cpio_target_meta_secret = {
.directory = ".extra",
.dir_mode = 0555,
.access_mode = 0400,
};
+17 -6
View File
@@ -4,14 +4,18 @@
#include "efi.h"
#include "proto/loaded-image.h"
typedef struct CpioTarget {
const char *directory; /* Path to directory where to place resources */
uint32_t dir_mode; /* Access mode for the directory */
uint32_t access_mode; /* Access mode for the files in the directory */
} CpioTarget;
EFI_STATUS pack_cpio(
EFI_LOADED_IMAGE_PROTOCOL *loaded_image,
const char16_t *dropin_dir,
const char16_t *match_suffix,
const char16_t *exclude_suffix,
const char *target_dir_prefix,
uint32_t dir_mode,
uint32_t access_mode,
const CpioTarget *target,
uint32_t tpm_pcr,
const char16_t *tpm_description,
struct iovec *ret_buffer,
@@ -20,11 +24,18 @@ EFI_STATUS pack_cpio(
EFI_STATUS pack_cpio_literal(
const void *data,
size_t data_size,
const char *target_dir_prefix,
const CpioTarget *target,
const char16_t *target_filename,
uint32_t dir_mode,
uint32_t access_mode,
uint32_t tpm_pcr,
const char16_t *tpm_description,
struct iovec *ret_buffer,
bool *ret_measured);
extern const CpioTarget cpio_target_credentials;
extern const CpioTarget cpio_target_global_credentials;
extern const CpioTarget cpio_target_sysext;
extern const CpioTarget cpio_target_global_sysext;
extern const CpioTarget cpio_target_confext;
extern const CpioTarget cpio_target_global_confext;
extern const CpioTarget cpio_target_meta;
extern const CpioTarget cpio_target_meta_secret;
+8 -24
View File
@@ -862,9 +862,7 @@ static void generate_sidecar_initrds(
/* dropin_dir= */ NULL,
u".cred",
/* exclude_suffix= */ NULL,
".extra/credentials",
/* dir_mode= */ 0500,
/* access_mode= */ 0400,
&cpio_target_credentials,
/* tpm_pcr= */ TPM2_PCR_KERNEL_CONFIG,
u"Credentials initrd",
initrds + INITRD_CREDENTIAL,
@@ -875,9 +873,7 @@ static void generate_sidecar_initrds(
u"\\loader\\credentials",
u".cred",
/* exclude_suffix= */ NULL,
".extra/global_credentials",
/* dir_mode= */ 0500,
/* access_mode= */ 0400,
&cpio_target_global_credentials,
/* tpm_pcr= */ TPM2_PCR_KERNEL_CONFIG,
u"Global credentials initrd",
initrds + INITRD_GLOBAL_CREDENTIAL,
@@ -888,9 +884,7 @@ static void generate_sidecar_initrds(
/* dropin_dir= */ NULL,
u".raw", /* ideally we'd pick up only *.sysext.raw here, but for compat we pick up *.raw instead … */
u".confext.raw", /* … but then exclude *.confext.raw again */
".extra/sysext",
/* dir_mode= */ 0555,
/* access_mode= */ 0444,
&cpio_target_sysext,
/* tpm_pcr= */ TPM2_PCR_SYSEXTS,
u"System extension initrd",
initrds + INITRD_SYSEXT,
@@ -901,9 +895,7 @@ static void generate_sidecar_initrds(
u"\\loader\\extensions",
u".raw", /* as above */
u".confext.raw",
".extra/global_sysext",
/* dir_mode= */ 0555,
/* access_mode= */ 0444,
&cpio_target_global_sysext,
/* tpm_pcr= */ TPM2_PCR_SYSEXTS,
u"Global system extension initrd",
initrds + INITRD_GLOBAL_SYSEXT,
@@ -914,9 +906,7 @@ static void generate_sidecar_initrds(
/* dropin_dir= */ NULL,
u".confext.raw",
/* exclude_suffix= */ NULL,
".extra/confext",
/* dir_mode= */ 0555,
/* access_mode= */ 0444,
&cpio_target_confext,
/* tpm_pcr= */ TPM2_PCR_KERNEL_CONFIG,
u"Configuration extension initrd",
initrds + INITRD_CONFEXT,
@@ -927,9 +917,7 @@ static void generate_sidecar_initrds(
u"\\loader\\extensions",
u".confext.raw",
/* exclude_suffix= */ NULL,
".extra/global_confext",
/* dir_mode= */ 0555,
/* access_mode= */ 0444,
&cpio_target_global_confext,
/* tpm_pcr= */ TPM2_PCR_KERNEL_CONFIG,
u"Global configuration extension initrd",
initrds + INITRD_GLOBAL_CONFEXT,
@@ -980,10 +968,8 @@ static void generate_embedded_initrds(
(void) pack_cpio_literal(
(const uint8_t*) loaded_image->ImageBase + sections[t->section].memory_offset,
sections[t->section].memory_size,
".extra",
&cpio_target_meta,
t->filename,
/* dir_mode= */ 0555,
/* access_mode= */ 0444,
/* tpm_pcr= */ UINT32_MAX,
/* tpm_description= */ NULL,
initrds + t->initrd_index,
@@ -1004,10 +990,8 @@ static void generate_boot_secret_initrd(
(void) pack_cpio_literal(
boot_secret,
BOOT_SECRET_SIZE,
".extra",
&cpio_target_meta_secret,
u"boot-secret",
/* dir_mode= */ 0555,
/* access_mode= */ 0400,
/* tpm_pcr= */ UINT32_MAX,
/* tpm_description= */ NULL,
initrds + INITRD_BOOT_SECRET,