initrd-cpio: add a variant that returns the credentials cpio in memory

systemd-firstboot wants to wrap the archive into a PE section rather
than pass a file to a VMM, hence split the memory part out of the temp
file writer, which becomes a wrapper around it.
This commit is contained in:
Adrian Reber committed 2026-11-04 07:13:40 +00:00
1 parent ad151a463d
commit f6b4e316e8
3 files changed
+57 -11

No files matched your search

+30 -11
View File
@@ -9,6 +9,7 @@
#include "fs-util.h"
#include "initrd-cpio.h"
#include "io-util.h"
#include "iovec-util.h"
#include "log.h"
#include "machine-credential.h"
#include "memory-util.h"
@@ -117,13 +118,11 @@ static void append_cpio_trailer(FILE *f) {
fwrite(trailer, 1, sizeof trailer, f);
}
int initrd_cpio_credentials_to_tempfile(
int initrd_cpio_credentials_to_memory(
const MachineCredentialContext *creds,
char **ret_path) {
struct iovec *ret) {
_cleanup_(memstream_done) MemStream m = {};
_cleanup_(unlink_and_freep) char *path = NULL;
_cleanup_close_ int fd = -EBADF;
_cleanup_(erase_and_freep) char *buf = NULL; /* holds plaintext credential bytes; scrub on free */
size_t buf_size = 0;
uint32_t inode = 1;
@@ -131,12 +130,7 @@ int initrd_cpio_credentials_to_tempfile(
int r;
assert(creds);
assert(ret_path);
if (creds->n_credentials == 0) {
*ret_path = NULL;
return 0;
}
assert(ret);
f = memstream_init(&m);
if (!f)
@@ -168,6 +162,31 @@ int initrd_cpio_credentials_to_tempfile(
if (r < 0)
return log_error_errno(r, "Failed to finalize credentials cpio: %m");
*ret = IOVEC_MAKE(TAKE_PTR(buf), buf_size);
return 0;
}
int initrd_cpio_credentials_to_tempfile(
const MachineCredentialContext *creds,
char **ret_path) {
_cleanup_(unlink_and_freep) char *path = NULL;
_cleanup_close_ int fd = -EBADF;
_cleanup_(iovec_done_erase) struct iovec cpio = {}; /* holds plaintext credential bytes; scrub on free */
int r;
assert(creds);
assert(ret_path);
if (creds->n_credentials == 0) {
*ret_path = NULL;
return 0;
}
r = initrd_cpio_credentials_to_memory(creds, &cpio);
if (r < 0)
return r;
r = tempfn_random_child(NULL, "credentials-cpio", &path);
if (r < 0)
return log_error_errno(r, "Failed to generate temp file name: %m");
@@ -176,7 +195,7 @@ int initrd_cpio_credentials_to_tempfile(
if (fd < 0)
return log_error_errno(fd, "Failed to create temp file %s: %m", path);
r = loop_write(fd, buf, buf_size);
r = loop_write(fd, cpio.iov_base, cpio.iov_len);
if (r < 0)
return log_error_errno(r, "Failed to write credentials cpio: %m");
+5
View File
@@ -12,3 +12,8 @@
int initrd_cpio_credentials_to_tempfile(
const MachineCredentialContext *creds,
char **ret_path);
/* Same, but returns the archive in memory. An archive is built even if there are no credentials. */
int initrd_cpio_credentials_to_memory(
const MachineCredentialContext *creds,
struct iovec *ret);
+22
View File
@@ -9,12 +9,34 @@
#include "fileio.h"
#include "fs-util.h"
#include "initrd-cpio.h"
#include "iovec-util.h"
#include "machine-credential.h"
#include "path-util.h"
#include "rm-rf.h"
#include "tests.h"
#include "tmpfile-util.h"
TEST(initrd_cpio_credentials_to_memory) {
_cleanup_(machine_credential_context_done) MachineCredentialContext creds = {};
_cleanup_(iovec_done) struct iovec empty = {}, archive = {};
/* Without credentials the archive still carries the directories and the trailer */
ASSERT_OK(initrd_cpio_credentials_to_memory(&creds, &empty));
ASSERT_NOT_NULL(empty.iov_base);
ASSERT_GT(empty.iov_len, 0U);
ASSERT_EQ(empty.iov_len % 4, 0U);
ASSERT_NOT_NULL(memmem(empty.iov_base, empty.iov_len, "TRAILER!!!", STRLEN("TRAILER!!!")));
ASSERT_NOT_NULL(memmem(empty.iov_base, empty.iov_len, ".extra/system_credentials", STRLEN(".extra/system_credentials")));
ASSERT_OK(machine_credential_add(&creds, "foo", "hello", 5));
ASSERT_OK(initrd_cpio_credentials_to_memory(&creds, &archive));
ASSERT_NOT_NULL(archive.iov_base);
ASSERT_GT(archive.iov_len, empty.iov_len);
ASSERT_NOT_NULL(memmem(archive.iov_base, archive.iov_len, ".extra/system_credentials/foo.cred", STRLEN(".extra/system_credentials/foo.cred")));
ASSERT_NOT_NULL(memmem(archive.iov_base, archive.iov_len, "hello", STRLEN("hello")));
ASSERT_NULL(memmem(empty.iov_base, empty.iov_len, "foo.cred", STRLEN("foo.cred")));
}
TEST_RET(initrd_cpio_credentials_basic) {
struct stat st;
size_t foo_size, bar_size;