systemd-252-28

Resolves: RHEL-1086,RHEL-16952
This commit is contained in:
Jan Macku 2024-02-20 16:13:49 +01:00
parent e5f65c3fc6
commit bed495948c
51 changed files with 11199 additions and 1 deletions

View File

@ -0,0 +1,47 @@
From b433a32f0d4328afc7a3dddb7dbab82d206663f7 Mon Sep 17 00:00:00 2001
From: Franck Bui <fbui@suse.com>
Date: Wed, 19 Oct 2022 15:27:04 +0200
Subject: [PATCH] random-seed: shorten a bit may_credit()
No functional change.
(cherry picked from commit 249d31b00a42aa016639bc0e9d708803d26f8f8f)
Related: RHEL-16952
---
src/random-seed/random-seed.c | 19 ++++++++-----------
1 file changed, 8 insertions(+), 11 deletions(-)
diff --git a/src/random-seed/random-seed.c b/src/random-seed/random-seed.c
index 82c29d0d7f..569b916f4a 100644
--- a/src/random-seed/random-seed.c
+++ b/src/random-seed/random-seed.c
@@ -87,20 +87,17 @@ static CreditEntropy may_credit(int seed_fd) {
/* Don't credit the random seed if we are in first-boot mode, because we are supposed to start from
* scratch. This is a safety precaution for cases where we people ship "golden" images with empty
* /etc but populated /var that contains a random seed. */
- if (access("/run/systemd/first-boot", F_OK) < 0) {
-
- if (errno != ENOENT) {
- log_warning_errno(errno, "Failed to check whether we are in first-boot mode, not crediting entropy: %m");
- return CREDIT_ENTROPY_NO_WAY;
- }
-
- /* If ENOENT all is good, we are not in first-boot mode. */
- } else {
- log_debug("Not crediting entropy, since booted in first-boot mode.");
+ r = RET_NERRNO(access("/run/systemd/first-boot", F_OK));
+ if (r == -ENOENT)
+ /* All is good, we are not in first-boot mode. */
+ return CREDIT_ENTROPY_YES_PLEASE;
+ if (r < 0) {
+ log_warning_errno(r, "Failed to check whether we are in first-boot mode, not crediting entropy: %m");
return CREDIT_ENTROPY_NO_WAY;
}
- return CREDIT_ENTROPY_YES_PLEASE;
+ log_debug("Not crediting entropy, since booted in first-boot mode.");
+ return CREDIT_ENTROPY_NO_WAY;
}
static int run(int argc, char *argv[]) {

View File

@ -0,0 +1,27 @@
From b8859311bceb0cd63a64c2fcc8967f0c6466d736 Mon Sep 17 00:00:00 2001
From: Franck Bui <fbui@suse.com>
Date: Wed, 19 Oct 2022 15:28:27 +0200
Subject: [PATCH] random-seed: make one more use of random_write_entropy()
No functional change.
(cherry picked from commit 141d1da021514be2cc7e7a903fa83b11f6054db6)
Related: RHEL-16952
---
src/random-seed/random-seed.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/random-seed/random-seed.c b/src/random-seed/random-seed.c
index 569b916f4a..d94005bdde 100644
--- a/src/random-seed/random-seed.c
+++ b/src/random-seed/random-seed.c
@@ -197,7 +197,7 @@ static int run(int argc, char *argv[]) {
if (r < 0)
log_debug_errno(r, "Failed to get machine ID, ignoring: %m");
else {
- r = loop_write(random_fd, &mid, sizeof(mid), false);
+ r = random_write_entropy(random_fd, &mid, sizeof(mid), /* credit= */ false);
if (r < 0)
log_debug_errno(r, "Failed to write machine ID to /dev/urandom, ignoring: %m");
}

View File

@ -0,0 +1,207 @@
From f6b55583600b4f8bfa2e7883d60685e2fb6c6b9d Mon Sep 17 00:00:00 2001
From: Franck Bui <fbui@suse.com>
Date: Wed, 19 Oct 2022 15:49:24 +0200
Subject: [PATCH] random-seed: use getopt()
It's not really necessary since systemd-random-seed is an internal tool for the
moment but this might change in future (to allow system installers to
initialize a random seed file for example).
Also introducing new options will be easier.
(cherry picked from commit 0d0c6639d4d61ff6cee43bc059c56a5170a0d280)
Related: RHEL-16952
---
src/random-seed/random-seed.c | 116 ++++++++++++++++++++++++++++++----
1 file changed, 103 insertions(+), 13 deletions(-)
diff --git a/src/random-seed/random-seed.c b/src/random-seed/random-seed.c
index d94005bdde..2ca2181ddb 100644
--- a/src/random-seed/random-seed.c
+++ b/src/random-seed/random-seed.c
@@ -2,6 +2,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <getopt.h>
#include <linux/random.h>
#include <sys/ioctl.h>
#if USE_SYS_RANDOM_H
@@ -22,20 +23,34 @@
#include "missing_random.h"
#include "missing_syscall.h"
#include "mkdir.h"
+#include "parse-argument.h"
#include "parse-util.h"
+#include "pretty-print.h"
#include "random-util.h"
+#include "string-table.h"
#include "string-util.h"
+#include "strv.h"
#include "sync-util.h"
#include "sha256.h"
+#include "terminal-util.h"
#include "util.h"
#include "xattr-util.h"
+typedef enum SeedAction {
+ ACTION_LOAD,
+ ACTION_SAVE,
+ _ACTION_MAX,
+ _ACTION_INVALID = -EINVAL,
+} SeedAction;
+
typedef enum CreditEntropy {
CREDIT_ENTROPY_NO_WAY,
CREDIT_ENTROPY_YES_PLEASE,
CREDIT_ENTROPY_YES_FORCED,
} CreditEntropy;
+static SeedAction arg_action = _ACTION_INVALID;
+
static CreditEntropy may_credit(int seed_fd) {
_cleanup_free_ char *creditable = NULL;
const char *e;
@@ -100,6 +115,78 @@ static CreditEntropy may_credit(int seed_fd) {
return CREDIT_ENTROPY_NO_WAY;
}
+static int help(int argc, char *argv[], void *userdata) {
+ _cleanup_free_ char *link = NULL;
+ int r;
+
+ r = terminal_urlify_man("systemd-random-seed", "8", &link);
+ if (r < 0)
+ return log_oom();
+
+ printf("%1$s [OPTIONS...] COMMAND\n"
+ "\n%5$sLoad and save the system random seed at boot and shutdown.%6$s\n"
+ "\n%3$sCommands:%4$s\n"
+ " load Load a random seed saved on disk into the kernel entropy pool\n"
+ " save Save a new random seed on disk\n"
+ "\n%3$sOptions:%4$s\n"
+ " -h --help Show this help\n"
+ " --version Show package version\n"
+ "\nSee the %2$s for details.\n",
+ program_invocation_short_name,
+ link,
+ ansi_underline(),
+ ansi_normal(),
+ ansi_highlight(),
+ ansi_normal());
+
+ return 0;
+}
+
+static const char* const seed_action_table[_ACTION_MAX] = {
+ [ACTION_LOAD] = "load",
+ [ACTION_SAVE] = "save",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(seed_action, SeedAction);
+
+static int parse_argv(int argc, char *argv[]) {
+ enum {
+ ARG_VERSION = 0x100,
+ };
+
+ static const struct option options[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, ARG_VERSION },
+ };
+
+ int c;
+
+ assert(argc >= 0);
+ assert(argv);
+
+ while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
+ switch (c) {
+ case 'h':
+ return help(0, NULL, NULL);
+ case ARG_VERSION:
+ return version();
+ case '?':
+ return -EINVAL;
+
+ default:
+ assert_not_reached();
+ }
+
+ if (optind + 1 != argc)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program requires one argument.");
+
+ arg_action = seed_action_from_string(argv[optind]);
+ if (arg_action < 0)
+ return log_error_errno(arg_action, "Unknown action '%s'", argv[optind]);
+
+ return 1;
+}
+
static int run(int argc, char *argv[]) {
bool read_seed_file, write_seed_file, synchronous, hashed_old_seed = false;
_cleanup_close_ int seed_fd = -1, random_fd = -1;
@@ -112,9 +199,9 @@ static int run(int argc, char *argv[]) {
log_setup();
- if (argc != 2)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "This program requires one argument.");
+ r = parse_argv(argc, argv);
+ if (r <= 0)
+ return r;
umask(0022);
@@ -124,11 +211,11 @@ static int run(int argc, char *argv[]) {
if (r < 0)
return log_error_errno(r, "Failed to create directory " RANDOM_SEED_DIR ": %m");
- /* When we load the seed we read it and write it to the device and then immediately update the saved seed with
- * new data, to make sure the next boot gets seeded differently. */
-
- if (streq(argv[1], "load")) {
+ /* When we load the seed we read it and write it to the device and then immediately update the saved
+ * seed with new data, to make sure the next boot gets seeded differently. */
+ switch (arg_action) {
+ case ACTION_LOAD:
seed_fd = open(RANDOM_SEED, O_RDWR|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600);
if (seed_fd < 0) {
int open_rw_error = -errno;
@@ -154,9 +241,9 @@ static int run(int argc, char *argv[]) {
read_seed_file = true;
synchronous = true; /* make this invocation a synchronous barrier for random pool initialization */
+ break;
- } else if (streq(argv[1], "save")) {
-
+ case ACTION_SAVE:
random_fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (random_fd < 0)
return log_error_errno(errno, "Failed to open /dev/urandom: %m");
@@ -168,14 +255,17 @@ static int run(int argc, char *argv[]) {
read_seed_file = false;
write_seed_file = true;
synchronous = false;
- } else
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Unknown verb '%s'.", argv[1]);
+ break;
+
+ default:
+ assert_not_reached();
+ }
if (fstat(seed_fd, &st) < 0)
return log_error_errno(errno, "Failed to stat() seed file " RANDOM_SEED ": %m");
- /* If the seed file is larger than what we expect, then honour the existing size and save/restore as much as it says */
+ /* If the seed file is larger than what we expect, then honour the existing size and save/restore as
+ * much as it says */
if ((uint64_t) st.st_size > buf_size)
buf_size = MIN(st.st_size, RANDOM_POOL_SIZE_MAX);

View File

@ -0,0 +1,79 @@
From b16d2d2da2d84552cfe7437d728ab8d65bacb03c Mon Sep 17 00:00:00 2001
From: Franck Bui <fbui@suse.com>
Date: Thu, 20 Oct 2022 08:45:02 +0200
Subject: [PATCH] random-seed: make the logic to calculate the number of bytes
read from the random seed file clearer
We want the size to lie within [/proc/sys/kernel/random/poolsize,RANDOM_POOL_SIZE_MAX]
interval. Let's make it more obvious.
Also move the logic in a dedicated function.
(cherry picked from commit 205138d88abf2e087440803ee046128092b722c6)
Related: RHEL-16952
---
src/random-seed/random-seed.c | 29 +++++++++++++++++++----------
1 file changed, 19 insertions(+), 10 deletions(-)
diff --git a/src/random-seed/random-seed.c b/src/random-seed/random-seed.c
index 2ca2181ddb..5b5629d817 100644
--- a/src/random-seed/random-seed.c
+++ b/src/random-seed/random-seed.c
@@ -115,6 +115,22 @@ static CreditEntropy may_credit(int seed_fd) {
return CREDIT_ENTROPY_NO_WAY;
}
+static int random_seed_size(int seed_fd, size_t *ret_size) {
+ struct stat st;
+
+ assert(ret_size);
+ assert(seed_fd >= 0);
+
+ if (fstat(seed_fd, &st) < 0)
+ return log_error_errno(errno, "Failed to stat() seed file " RANDOM_SEED ": %m");
+
+ /* If the seed file is larger than what the kernel expects, then honour the existing size and
+ * save/restore as much as it says */
+
+ *ret_size = CLAMP((uint64_t)st.st_size, random_pool_size(), RANDOM_POOL_SIZE_MAX);
+ return 0;
+}
+
static int help(int argc, char *argv[], void *userdata) {
_cleanup_free_ char *link = NULL;
int r;
@@ -193,7 +209,6 @@ static int run(int argc, char *argv[]) {
_cleanup_free_ void* buf = NULL;
struct sha256_ctx hash_state;
size_t buf_size;
- struct stat st;
ssize_t k, l;
int r;
@@ -205,8 +220,6 @@ static int run(int argc, char *argv[]) {
umask(0022);
- buf_size = random_pool_size();
-
r = mkdir_parents(RANDOM_SEED, 0755);
if (r < 0)
return log_error_errno(r, "Failed to create directory " RANDOM_SEED_DIR ": %m");
@@ -261,13 +274,9 @@ static int run(int argc, char *argv[]) {
assert_not_reached();
}
- if (fstat(seed_fd, &st) < 0)
- return log_error_errno(errno, "Failed to stat() seed file " RANDOM_SEED ": %m");
-
- /* If the seed file is larger than what we expect, then honour the existing size and save/restore as
- * much as it says */
- if ((uint64_t) st.st_size > buf_size)
- buf_size = MIN(st.st_size, RANDOM_POOL_SIZE_MAX);
+ r = random_seed_size(seed_fd, &buf_size);
+ if (r < 0)
+ return r;
buf = malloc(buf_size);
if (!buf)

View File

@ -0,0 +1,30 @@
From 494ebc9dc491ab378851ee75562796b32e9a98ea Mon Sep 17 00:00:00 2001
From: Franck Bui <fbui@suse.com>
Date: Thu, 20 Oct 2022 08:52:10 +0200
Subject: [PATCH] random-seed: no need to pass 'mode' argument when opening
/dev/urandom
The open() call is not supposed to create /dev/urandom.
No functional change.
(cherry picked from commit 4620c0af5dc7a46ed3e213568e99d8a82c44553d)
Related: RHEL-16952
---
src/random-seed/random-seed.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/random-seed/random-seed.c b/src/random-seed/random-seed.c
index 5b5629d817..4b8138ca03 100644
--- a/src/random-seed/random-seed.c
+++ b/src/random-seed/random-seed.c
@@ -248,7 +248,7 @@ static int run(int argc, char *argv[]) {
} else
write_seed_file = true;
- random_fd = open("/dev/urandom", O_RDWR|O_CLOEXEC|O_NOCTTY, 0600);
+ random_fd = open("/dev/urandom", O_RDWR|O_CLOEXEC|O_NOCTTY);
if (random_fd < 0)
return log_error_errno(errno, "Failed to open /dev/urandom: %m");

View File

@ -0,0 +1,372 @@
From d424c00790f478790be7388827113853b968023e Mon Sep 17 00:00:00 2001
From: Franck Bui <fbui@suse.com>
Date: Thu, 20 Oct 2022 09:39:12 +0200
Subject: [PATCH] random-seed: split out run()
No functional change.
(cherry picked from commit d3fa881aa1f4bffc097d63ed68d2e2a8ada813d0)
Related: RHEL-16952
---
src/random-seed/random-seed.c | 327 +++++++++++++++++++---------------
1 file changed, 184 insertions(+), 143 deletions(-)
diff --git a/src/random-seed/random-seed.c b/src/random-seed/random-seed.c
index 4b8138ca03..991e4b8ddd 100644
--- a/src/random-seed/random-seed.c
+++ b/src/random-seed/random-seed.c
@@ -131,6 +131,180 @@ static int random_seed_size(int seed_fd, size_t *ret_size) {
return 0;
}
+static int load_seed_file(
+ int seed_fd,
+ int urandom_fd,
+ size_t seed_size,
+ struct sha256_ctx **ret_hash_state) {
+
+ _cleanup_free_ void *buf = NULL;
+ CreditEntropy lets_credit;
+ sd_id128_t mid;
+ ssize_t k;
+ int r;
+
+ assert(seed_fd >= 0);
+ assert(urandom_fd >= 0);
+
+ /* First, let's write the machine ID into /dev/urandom, not crediting entropy. Why? As an extra
+ * protection against "golden images" that are put together sloppily, i.e. images which are
+ * duplicated on multiple systems but where the random seed file is not properly reset. Frequently
+ * the machine ID is properly reset on those systems however (simply because it's easier to notice,
+ * if it isn't due to address clashes and so on, while random seed equivalence is generally not
+ * noticed easily), hence let's simply write the machined ID into the random pool too. */
+ r = sd_id128_get_machine(&mid);
+ if (r < 0)
+ log_debug_errno(r, "Failed to get machine ID, ignoring: %m");
+ else {
+ r = random_write_entropy(urandom_fd, &mid, sizeof(mid), /* credit= */ false);
+ if (r < 0)
+ log_debug_errno(r, "Failed to write machine ID to /dev/urandom, ignoring: %m");
+ }
+
+ buf = malloc(seed_size);
+ if (!buf)
+ return log_oom();
+
+ k = loop_read(seed_fd, buf, seed_size, false);
+ if (k < 0) {
+ log_error_errno(k, "Failed to read seed from " RANDOM_SEED ": %m");
+ return 0;
+ }
+ if (k == 0) {
+ log_debug("Seed file " RANDOM_SEED " not yet initialized, proceeding.");
+ return 0;
+ }
+
+ /* If we're going to later write out a seed file, initialize a hash state with the contents of the
+ * seed file we just read, so that the new one can't regress in entropy. */
+ if (ret_hash_state) {
+ struct sha256_ctx *hash_state;
+
+ hash_state = malloc(sizeof(struct sha256_ctx));
+ if (!hash_state)
+ return log_oom();
+
+ sha256_init_ctx(hash_state);
+ sha256_process_bytes(&k, sizeof(k), hash_state); /* Hash length to distinguish from new seed. */
+ sha256_process_bytes(buf, k, hash_state);
+
+ *ret_hash_state = hash_state;
+ }
+
+ (void) lseek(seed_fd, 0, SEEK_SET);
+
+ lets_credit = may_credit(seed_fd);
+
+ /* Before we credit or use the entropy, let's make sure to securely drop the creditable xattr from
+ * the file, so that we never credit the same random seed again. Note that further down we'll write a
+ * new seed again, and likely mark it as credible again, hence this is just paranoia to close the
+ * short time window between the time we upload the random seed into the kernel and download the new
+ * one from it. */
+
+ if (fremovexattr(seed_fd, "user.random-seed-creditable") < 0) {
+ if (!ERRNO_IS_XATTR_ABSENT(errno))
+ log_warning_errno(errno, "Failed to remove extended attribute, ignoring: %m");
+
+ /* Otherwise, there was no creditable flag set, which is OK. */
+ } else {
+ r = fsync_full(seed_fd);
+ if (r < 0) {
+ log_warning_errno(r, "Failed to synchronize seed to disk, not crediting entropy: %m");
+
+ if (lets_credit == CREDIT_ENTROPY_YES_PLEASE)
+ lets_credit = CREDIT_ENTROPY_NO_WAY;
+ }
+ }
+
+ r = random_write_entropy(urandom_fd, buf, k,
+ IN_SET(lets_credit, CREDIT_ENTROPY_YES_PLEASE, CREDIT_ENTROPY_YES_FORCED));
+ if (r < 0)
+ log_error_errno(r, "Failed to write seed to /dev/urandom: %m");
+
+ return 0;
+}
+
+static int save_seed_file(
+ int seed_fd,
+ int urandom_fd,
+ size_t seed_size,
+ bool synchronous,
+ struct sha256_ctx *hash_state) {
+
+ _cleanup_free_ void *buf = NULL;
+ bool getrandom_worked = false;
+ ssize_t k, l;
+ int r;
+
+ assert(seed_fd >= 0);
+ assert(urandom_fd >= 0);
+
+ /* This is just a safety measure. Given that we are root and most likely created the file ourselves
+ * the mode and owner should be correct anyway. */
+ r = fchmod_and_chown(seed_fd, 0600, 0, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to adjust seed file ownership and access mode: %m");
+
+ buf = malloc(seed_size);
+ if (!buf)
+ return log_oom();
+
+ /* Let's make this whole job asynchronous, i.e. let's make ourselves a barrier for proper
+ * initialization of the random pool. */
+ k = getrandom(buf, seed_size, GRND_NONBLOCK);
+ if (k < 0 && errno == EAGAIN && synchronous) {
+ log_notice("Kernel entropy pool is not initialized yet, waiting until it is.");
+ k = getrandom(buf, seed_size, 0); /* retry synchronously */
+ }
+ if (k < 0)
+ log_debug_errno(errno, "Failed to read random data with getrandom(), falling back to /dev/urandom: %m");
+ else if ((size_t) k < seed_size)
+ log_debug("Short read from getrandom(), falling back to /dev/urandom.");
+ else
+ getrandom_worked = true;
+
+ if (!getrandom_worked) {
+ /* Retry with classic /dev/urandom */
+ k = loop_read(urandom_fd, buf, seed_size, false);
+ if (k < 0)
+ return log_error_errno(k, "Failed to read new seed from /dev/urandom: %m");
+ if (k == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "Got EOF while reading from /dev/urandom.");
+ }
+
+ /* If we previously read in a seed file, then hash the new seed into the old one, and replace the
+ * last 32 bytes of the seed with the hash output, so that the new seed file can't regress in
+ * entropy. */
+ if (hash_state) {
+ uint8_t hash[SHA256_DIGEST_SIZE];
+
+ sha256_process_bytes(&k, sizeof(k), hash_state); /* Hash length to distinguish from old seed. */
+ sha256_process_bytes(buf, k, hash_state);
+ sha256_finish_ctx(hash_state, hash);
+ l = MIN((size_t)k, sizeof(hash));
+ memcpy((uint8_t *)buf + k - l, hash, l);
+ }
+
+ r = loop_write(seed_fd, buf, (size_t) k, false);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write new random seed file: %m");
+
+ if (ftruncate(seed_fd, k) < 0)
+ return log_error_errno(r, "Failed to truncate random seed file: %m");
+
+ r = fsync_full(seed_fd);
+ if (r < 0)
+ return log_error_errno(r, "Failed to synchronize seed file: %m");
+
+ /* If we got this random seed data from getrandom() the data is suitable for crediting entropy later
+ * on. Let's keep that in mind by setting an extended attribute. on the file */
+ if (getrandom_worked)
+ if (fsetxattr(seed_fd, "user.random-seed-creditable", "1", 1, 0) < 0)
+ log_full_errno(ERRNO_IS_NOT_SUPPORTED(errno) ? LOG_DEBUG : LOG_WARNING, errno,
+ "Failed to mark seed file as creditable, ignoring: %m");
+ return 0;
+}
+
static int help(int argc, char *argv[], void *userdata) {
_cleanup_free_ char *link = NULL;
int r;
@@ -204,12 +378,10 @@ static int parse_argv(int argc, char *argv[]) {
}
static int run(int argc, char *argv[]) {
- bool read_seed_file, write_seed_file, synchronous, hashed_old_seed = false;
+ _cleanup_free_ struct sha256_ctx *hash_state = NULL;
_cleanup_close_ int seed_fd = -1, random_fd = -1;
- _cleanup_free_ void* buf = NULL;
- struct sha256_ctx hash_state;
- size_t buf_size;
- ssize_t k, l;
+ bool read_seed_file, write_seed_file, synchronous;
+ size_t seed_size;
int r;
log_setup();
@@ -274,149 +446,18 @@ static int run(int argc, char *argv[]) {
assert_not_reached();
}
- r = random_seed_size(seed_fd, &buf_size);
+ r = random_seed_size(seed_fd, &seed_size);
if (r < 0)
return r;
- buf = malloc(buf_size);
- if (!buf)
- return log_oom();
-
- if (read_seed_file) {
- sd_id128_t mid;
-
- /* First, let's write the machine ID into /dev/urandom, not crediting entropy. Why? As an
- * extra protection against "golden images" that are put together sloppily, i.e. images which
- * are duplicated on multiple systems but where the random seed file is not properly
- * reset. Frequently the machine ID is properly reset on those systems however (simply
- * because it's easier to notice, if it isn't due to address clashes and so on, while random
- * seed equivalence is generally not noticed easily), hence let's simply write the machined
- * ID into the random pool too. */
- r = sd_id128_get_machine(&mid);
- if (r < 0)
- log_debug_errno(r, "Failed to get machine ID, ignoring: %m");
- else {
- r = random_write_entropy(random_fd, &mid, sizeof(mid), /* credit= */ false);
- if (r < 0)
- log_debug_errno(r, "Failed to write machine ID to /dev/urandom, ignoring: %m");
- }
-
- k = loop_read(seed_fd, buf, buf_size, false);
- if (k < 0)
- log_error_errno(k, "Failed to read seed from " RANDOM_SEED ": %m");
- else if (k == 0)
- log_debug("Seed file " RANDOM_SEED " not yet initialized, proceeding.");
- else {
- CreditEntropy lets_credit;
-
- /* If we're going to later write out a seed file, initialize a hash state with
- * the contents of the seed file we just read, so that the new one can't regress
- * in entropy. */
- if (write_seed_file) {
- sha256_init_ctx(&hash_state);
- sha256_process_bytes(&k, sizeof(k), &hash_state); /* Hash length to distinguish from new seed. */
- sha256_process_bytes(buf, k, &hash_state);
- hashed_old_seed = true;
- }
-
- (void) lseek(seed_fd, 0, SEEK_SET);
-
- lets_credit = may_credit(seed_fd);
-
- /* Before we credit or use the entropy, let's make sure to securely drop the
- * creditable xattr from the file, so that we never credit the same random seed
- * again. Note that further down we'll write a new seed again, and likely mark it as
- * credible again, hence this is just paranoia to close the short time window between
- * the time we upload the random seed into the kernel and download the new one from
- * it. */
-
- if (fremovexattr(seed_fd, "user.random-seed-creditable") < 0) {
- if (!ERRNO_IS_XATTR_ABSENT(errno))
- log_warning_errno(errno, "Failed to remove extended attribute, ignoring: %m");
+ if (read_seed_file)
+ r = load_seed_file(seed_fd, random_fd, seed_size,
+ write_seed_file ? &hash_state : NULL);
- /* Otherwise, there was no creditable flag set, which is OK. */
- } else {
- r = fsync_full(seed_fd);
- if (r < 0) {
- log_warning_errno(r, "Failed to synchronize seed to disk, not crediting entropy: %m");
+ if (r >= 0 && write_seed_file)
+ r = save_seed_file(seed_fd, random_fd, seed_size, synchronous, hash_state);
- if (lets_credit == CREDIT_ENTROPY_YES_PLEASE)
- lets_credit = CREDIT_ENTROPY_NO_WAY;
- }
- }
-
- r = random_write_entropy(random_fd, buf, k,
- IN_SET(lets_credit, CREDIT_ENTROPY_YES_PLEASE, CREDIT_ENTROPY_YES_FORCED));
- if (r < 0)
- log_error_errno(r, "Failed to write seed to /dev/urandom: %m");
- }
- }
-
- if (write_seed_file) {
- bool getrandom_worked = false;
-
- /* This is just a safety measure. Given that we are root and most likely created the file
- * ourselves the mode and owner should be correct anyway. */
- r = fchmod_and_chown(seed_fd, 0600, 0, 0);
- if (r < 0)
- return log_error_errno(r, "Failed to adjust seed file ownership and access mode: %m");
-
- /* Let's make this whole job asynchronous, i.e. let's make ourselves a barrier for
- * proper initialization of the random pool. */
- k = getrandom(buf, buf_size, GRND_NONBLOCK);
- if (k < 0 && errno == EAGAIN && synchronous) {
- log_notice("Kernel entropy pool is not initialized yet, waiting until it is.");
- k = getrandom(buf, buf_size, 0); /* retry synchronously */
- }
- if (k < 0)
- log_debug_errno(errno, "Failed to read random data with getrandom(), falling back to /dev/urandom: %m");
- else if ((size_t) k < buf_size)
- log_debug("Short read from getrandom(), falling back to /dev/urandom.");
- else
- getrandom_worked = true;
-
- if (!getrandom_worked) {
- /* Retry with classic /dev/urandom */
- k = loop_read(random_fd, buf, buf_size, false);
- if (k < 0)
- return log_error_errno(k, "Failed to read new seed from /dev/urandom: %m");
- if (k == 0)
- return log_error_errno(SYNTHETIC_ERRNO(EIO),
- "Got EOF while reading from /dev/urandom.");
- }
-
- /* If we previously read in a seed file, then hash the new seed into the old one,
- * and replace the last 32 bytes of the seed with the hash output, so that the
- * new seed file can't regress in entropy. */
- if (hashed_old_seed) {
- uint8_t hash[SHA256_DIGEST_SIZE];
- sha256_process_bytes(&k, sizeof(k), &hash_state); /* Hash length to distinguish from old seed. */
- sha256_process_bytes(buf, k, &hash_state);
- sha256_finish_ctx(&hash_state, hash);
- l = MIN((size_t)k, sizeof(hash));
- memcpy((uint8_t *)buf + k - l, hash, l);
- }
-
- r = loop_write(seed_fd, buf, (size_t) k, false);
- if (r < 0)
- return log_error_errno(r, "Failed to write new random seed file: %m");
-
- if (ftruncate(seed_fd, k) < 0)
- return log_error_errno(r, "Failed to truncate random seed file: %m");
-
- r = fsync_full(seed_fd);
- if (r < 0)
- return log_error_errno(r, "Failed to synchronize seed file: %m");
-
- /* If we got this random seed data from getrandom() the data is suitable for crediting
- * entropy later on. Let's keep that in mind by setting an extended attribute. on the file */
- if (getrandom_worked)
- if (fsetxattr(seed_fd, "user.random-seed-creditable", "1", 1, 0) < 0)
- log_full_errno(ERRNO_IS_NOT_SUPPORTED(errno) ? LOG_DEBUG : LOG_WARNING, errno,
- "Failed to mark seed file as creditable, ignoring: %m");
- }
-
- return 0;
+ return r;
}
DEFINE_MAIN_FUNCTION(run);

View File

@ -0,0 +1,34 @@
From 20eeade12a2e914d9b5451dbb1f8807cd6719eac Mon Sep 17 00:00:00 2001
From: Franck Bui <fbui@suse.com>
Date: Thu, 20 Oct 2022 15:03:20 +0200
Subject: [PATCH] random_seed: minor improvement in run()
(cherry picked from commit 3f6fbfe6f1ae62b080c70dad6de5a65108e3d538)
Related: RHEL-16952
---
src/random-seed/random-seed.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/random-seed/random-seed.c b/src/random-seed/random-seed.c
index 991e4b8ddd..05fb5bb157 100644
--- a/src/random-seed/random-seed.c
+++ b/src/random-seed/random-seed.c
@@ -410,12 +410,12 @@ static int run(int argc, char *argv[]) {
seed_fd = open(RANDOM_SEED, O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (seed_fd < 0) {
bool missing = errno == ENOENT;
+ int level = missing ? LOG_DEBUG : LOG_ERR;
- log_full_errno(missing ? LOG_DEBUG : LOG_ERR,
- open_rw_error, "Failed to open " RANDOM_SEED " for writing: %m");
- r = log_full_errno(missing ? LOG_DEBUG : LOG_ERR,
- errno, "Failed to open " RANDOM_SEED " for reading: %m");
- return missing ? 0 : r;
+ log_full_errno(level, open_rw_error, "Failed to open " RANDOM_SEED " for writing: %m");
+ log_full_errno(level, errno, "Failed to open " RANDOM_SEED " for reading: %m");
+
+ return missing ? 0 : -errno;
}
} else
write_seed_file = true;

View File

@ -0,0 +1,37 @@
From 8990010d76cd48f8c166f586a8c6ae07cb1a749d Mon Sep 17 00:00:00 2001
From: Franck Bui <fbui@suse.com>
Date: Fri, 21 Oct 2022 15:08:43 +0200
Subject: [PATCH] random-seed: downgrade some messages
In these cases, we eat up the error and propagate success so we should log at
warning level only.
(cherry picked from commit ea37e1edf9bdaa5a90050d69454a132dc5d60360)
Related: RHEL-16952
---
src/random-seed/random-seed.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/random-seed/random-seed.c b/src/random-seed/random-seed.c
index 05fb5bb157..7782509572 100644
--- a/src/random-seed/random-seed.c
+++ b/src/random-seed/random-seed.c
@@ -167,7 +167,7 @@ static int load_seed_file(
k = loop_read(seed_fd, buf, seed_size, false);
if (k < 0) {
- log_error_errno(k, "Failed to read seed from " RANDOM_SEED ": %m");
+ log_warning_errno(k, "Failed to read seed from " RANDOM_SEED ": %m");
return 0;
}
if (k == 0) {
@@ -219,7 +219,7 @@ static int load_seed_file(
r = random_write_entropy(urandom_fd, buf, k,
IN_SET(lets_credit, CREDIT_ENTROPY_YES_PLEASE, CREDIT_ENTROPY_YES_FORCED));
if (r < 0)
- log_error_errno(r, "Failed to write seed to /dev/urandom: %m");
+ log_warning_errno(r, "Failed to write seed to /dev/urandom: %m");
return 0;
}

View File

@ -0,0 +1,33 @@
From 22a598fa626bf440127c1dd2a6b116514869752a Mon Sep 17 00:00:00 2001
From: Franck Bui <fbui@suse.com>
Date: Tue, 25 Oct 2022 13:54:10 +0200
Subject: [PATCH] random-seed: clarify one comment
(cherry picked from commit 46e0b5dca7fa5368bccbf30a7d2569d93d994a44)
Related: RHEL-16952
---
src/random-seed/random-seed.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/random-seed/random-seed.c b/src/random-seed/random-seed.c
index 7782509572..22ddf659ae 100644
--- a/src/random-seed/random-seed.c
+++ b/src/random-seed/random-seed.c
@@ -249,12 +249,13 @@ static int save_seed_file(
if (!buf)
return log_oom();
- /* Let's make this whole job asynchronous, i.e. let's make ourselves a barrier for proper
- * initialization of the random pool. */
k = getrandom(buf, seed_size, GRND_NONBLOCK);
if (k < 0 && errno == EAGAIN && synchronous) {
+ /* If we're asked to make ourselves a barrier for proper initialization of the random pool
+ * make this whole job synchronous by asking getrandom() to wait until the requested number
+ * of random bytes is available. */
log_notice("Kernel entropy pool is not initialized yet, waiting until it is.");
- k = getrandom(buf, seed_size, 0); /* retry synchronously */
+ k = getrandom(buf, seed_size, 0);
}
if (k < 0)
log_debug_errno(errno, "Failed to read random data with getrandom(), falling back to /dev/urandom: %m");

View File

@ -0,0 +1,100 @@
From 3dcd5325c72f656fbf97b71331bea1edc486f2d2 Mon Sep 17 00:00:00 2001
From: Franck Bui <fbui@suse.com>
Date: Mon, 24 Oct 2022 11:30:29 +0200
Subject: [PATCH] random-seed: make sure to load machine id even if the seed
file is missing
(cherry picked from commit a2f0dbb81004685d17f71fed48dc50027ccadb82)
Related: RHEL-16952
---
src/random-seed/random-seed.c | 49 +++++++++++++++++++++--------------
1 file changed, 29 insertions(+), 20 deletions(-)
diff --git a/src/random-seed/random-seed.c b/src/random-seed/random-seed.c
index 22ddf659ae..b548f92bbe 100644
--- a/src/random-seed/random-seed.c
+++ b/src/random-seed/random-seed.c
@@ -131,6 +131,27 @@ static int random_seed_size(int seed_fd, size_t *ret_size) {
return 0;
}
+static void load_machine_id(int urandom_fd) {
+ sd_id128_t mid;
+ int r;
+
+ assert(urandom_fd >= 0);
+
+ /* As an extra protection against "golden images" that are put together sloppily, i.e. images which
+ * are duplicated on multiple systems but where the random seed file is not properly
+ * reset. Frequently the machine ID is properly reset on those systems however (simply because it's
+ * easier to notice, if it isn't due to address clashes and so on, while random seed equivalence is
+ * generally not noticed easily), hence let's simply write the machined ID into the random pool
+ * too. */
+ r = sd_id128_get_machine(&mid);
+ if (r < 0)
+ return (void) log_debug_errno(r, "Failed to get machine ID, ignoring: %m");
+
+ r = random_write_entropy(urandom_fd, &mid, sizeof(mid), /* credit= */ false);
+ if (r < 0)
+ log_debug_errno(r, "Failed to write machine ID to /dev/urandom, ignoring: %m");
+}
+
static int load_seed_file(
int seed_fd,
int urandom_fd,
@@ -139,28 +160,12 @@ static int load_seed_file(
_cleanup_free_ void *buf = NULL;
CreditEntropy lets_credit;
- sd_id128_t mid;
ssize_t k;
int r;
assert(seed_fd >= 0);
assert(urandom_fd >= 0);
- /* First, let's write the machine ID into /dev/urandom, not crediting entropy. Why? As an extra
- * protection against "golden images" that are put together sloppily, i.e. images which are
- * duplicated on multiple systems but where the random seed file is not properly reset. Frequently
- * the machine ID is properly reset on those systems however (simply because it's easier to notice,
- * if it isn't due to address clashes and so on, while random seed equivalence is generally not
- * noticed easily), hence let's simply write the machined ID into the random pool too. */
- r = sd_id128_get_machine(&mid);
- if (r < 0)
- log_debug_errno(r, "Failed to get machine ID, ignoring: %m");
- else {
- r = random_write_entropy(urandom_fd, &mid, sizeof(mid), /* credit= */ false);
- if (r < 0)
- log_debug_errno(r, "Failed to write machine ID to /dev/urandom, ignoring: %m");
- }
-
buf = malloc(seed_size);
if (!buf)
return log_oom();
@@ -402,6 +407,14 @@ static int run(int argc, char *argv[]) {
switch (arg_action) {
case ACTION_LOAD:
+ random_fd = open("/dev/urandom", O_RDWR|O_CLOEXEC|O_NOCTTY);
+ if (random_fd < 0)
+ return log_error_errno(errno, "Failed to open /dev/urandom: %m");
+
+ /* First, let's write the machine ID into /dev/urandom, not crediting entropy. See
+ * load_machine_id() for an explanation why. */
+ load_machine_id(random_fd);
+
seed_fd = open(RANDOM_SEED, O_RDWR|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600);
if (seed_fd < 0) {
int open_rw_error = -errno;
@@ -421,10 +434,6 @@ static int run(int argc, char *argv[]) {
} else
write_seed_file = true;
- random_fd = open("/dev/urandom", O_RDWR|O_CLOEXEC|O_NOCTTY);
- if (random_fd < 0)
- return log_error_errno(errno, "Failed to open /dev/urandom: %m");
-
read_seed_file = true;
synchronous = true; /* make this invocation a synchronous barrier for random pool initialization */
break;

View File

@ -0,0 +1,87 @@
From 99294ed904d04eff1b1f05390e64d92f9d824853 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Fri, 11 Nov 2022 17:31:34 +0100
Subject: [PATCH] chase-symlinks: add new flag for prohibiting any following of
symlinks
This is useful when operating in the ESP, which is untrusted territory,
and where under no circumstances we should be tricked by symlinks into
doing anything we don't want to.
(cherry picked from commit d43e78b643535da398345d5ae680a96d7b65940e)
Related: RHEL-16952
---
src/basic/chase-symlinks.c | 18 ++++++++++++++++++
src/basic/chase-symlinks.h | 1 +
src/test/test-fs-util.c | 9 +++++++++
3 files changed, 28 insertions(+)
diff --git a/src/basic/chase-symlinks.c b/src/basic/chase-symlinks.c
index ac55311f4d..e10370d0d2 100644
--- a/src/basic/chase-symlinks.c
+++ b/src/basic/chase-symlinks.c
@@ -57,6 +57,21 @@ static int log_autofs_mount_point(int fd, const char *path, ChaseSymlinksFlags f
strna(n1), path);
}
+static int log_prohibited_symlink(int fd, ChaseSymlinksFlags flags) {
+ _cleanup_free_ char *n1 = NULL;
+
+ assert(fd >= 0);
+
+ if (!FLAGS_SET(flags, CHASE_WARN))
+ return -EREMCHG;
+
+ (void) fd_get_path(fd, &n1);
+
+ return log_warning_errno(SYNTHETIC_ERRNO(EREMCHG),
+ "Detected symlink where not symlink is allowed at %s, refusing.",
+ strna(n1));
+}
+
int chase_symlinks(
const char *path,
const char *original_root,
@@ -302,6 +317,9 @@ int chase_symlinks(
if (S_ISLNK(st.st_mode) && !((flags & CHASE_NOFOLLOW) && isempty(todo))) {
_cleanup_free_ char *destination = NULL;
+ if (flags & CHASE_PROHIBIT_SYMLINKS)
+ return log_prohibited_symlink(child, flags);
+
/* This is a symlink, in this case read the destination. But let's make sure we
* don't follow symlinks without bounds. */
if (--max_follow <= 0)
diff --git a/src/basic/chase-symlinks.h b/src/basic/chase-symlinks.h
index a9ee58f9f7..8f69bf3eed 100644
--- a/src/basic/chase-symlinks.h
+++ b/src/basic/chase-symlinks.h
@@ -17,6 +17,7 @@ typedef enum ChaseSymlinksFlags {
* right-most component refers to symlink, return O_PATH fd of the symlink. */
CHASE_WARN = 1 << 7, /* Emit an appropriate warning when an error is encountered.
* Note: this may do an NSS lookup, hence this flag cannot be used in PID 1. */
+ CHASE_PROHIBIT_SYMLINKS = 1 << 8, /* Refuse all symlinks */
} ChaseSymlinksFlags;
bool unsafe_transition(const struct stat *a, const struct stat *b);
diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c
index 9c1ced7591..16f04d6889 100644
--- a/src/test/test-fs-util.c
+++ b/src/test/test-fs-util.c
@@ -387,6 +387,15 @@ TEST(chase_symlinks) {
assert_se(path_equal(path_startswith(result, p), "usr"));
result = mfree(result);
+ /* Test CHASE_PROHIBIT_SYMLINKS */
+
+ assert_se(chase_symlinks("top/dot", temp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, NULL, NULL) == -EREMCHG);
+ assert_se(chase_symlinks("top/dot", temp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_WARN, NULL, NULL) == -EREMCHG);
+ assert_se(chase_symlinks("top/dotdot", temp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, NULL, NULL) == -EREMCHG);
+ assert_se(chase_symlinks("top/dotdot", temp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_WARN, NULL, NULL) == -EREMCHG);
+ assert_se(chase_symlinks("top/dot/dot", temp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, NULL, NULL) == -EREMCHG);
+ assert_se(chase_symlinks("top/dot/dot", temp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_WARN, NULL, NULL) == -EREMCHG);
+
cleanup:
assert_se(rm_rf(temp, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}

View File

@ -0,0 +1,141 @@
From 466da97e11cebf84a293789d0f4f38779244a5b3 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Fri, 11 Nov 2022 17:36:29 +0100
Subject: [PATCH] bootctl,bootspec: make use of CHASE_PROHIBIT_SYMLINKS
whenever we access the ESP/XBOOTLDR
Let's make use of the new flag whenever we access the ESP or XBOOTLDR.
The resources we make use of in these partitions can't possibly use
symlinks (because UEFI knows no symlink concept), and they are untrusted
territory, hence under no circumstances we should be tricked into
following symlinks that shouldn't be there in the first place.
Of course, you might argue thta ESP/XBOOTLDR are VFAT and thus don#t
know symlinks. But the thing is, they don#t have to be. Firmware can
support other file systems too, and people can use efifs to gain access
to arbitrary Linux file systems from EFI. Hence, let's better be safe
than sorry.
(cherry picked from commit b353d5eee9e8df0aa2f4cbb1bfb0a46a963ba78f)
Related: RHEL-16952
---
src/boot/bootctl.c | 18 +++++++++---------
src/shared/bootspec.c | 8 ++++----
2 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index a0ca2afec2..e830d45486 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -485,7 +485,7 @@ static int enumerate_binaries(
assert(previous);
assert(is_first);
- r = chase_symlinks_and_opendir(path, esp_path, CHASE_PREFIX_ROOT, &p, &d);
+ r = chase_symlinks_and_opendir(path, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &p, &d);
if (r == -ENOENT)
return 0;
if (r < 0)
@@ -918,10 +918,10 @@ static int copy_one_file(const char *esp_path, const char *name, bool force) {
if (!p)
return log_oom();
- r = chase_symlinks(p, root, CHASE_PREFIX_ROOT, &source_path, NULL);
+ r = chase_symlinks(p, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &source_path, NULL);
/* If we had a root directory to try, we didn't find it and we are in auto mode, retry on the host */
if (r == -ENOENT && root && arg_install_source == ARG_INSTALL_SOURCE_AUTO)
- r = chase_symlinks(p, NULL, CHASE_PREFIX_ROOT, &source_path, NULL);
+ r = chase_symlinks(p, NULL, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &source_path, NULL);
if (r < 0)
return log_error_errno(r,
"Failed to resolve path %s%s%s: %m",
@@ -933,7 +933,7 @@ static int copy_one_file(const char *esp_path, const char *name, bool force) {
if (!q)
return log_oom();
- r = chase_symlinks(q, esp_path, CHASE_PREFIX_ROOT | CHASE_NONEXISTENT, &dest_path, NULL);
+ r = chase_symlinks(q, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_NONEXISTENT, &dest_path, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve path %s under directory %s: %m", q, esp_path);
@@ -950,7 +950,7 @@ static int copy_one_file(const char *esp_path, const char *name, bool force) {
v = strjoina("/EFI/BOOT/BOOT", e);
ascii_strupper(strrchr(v, '/') + 1);
- r = chase_symlinks(v, esp_path, CHASE_PREFIX_ROOT | CHASE_NONEXISTENT, &default_dest_path, NULL);
+ r = chase_symlinks(v, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_NONEXISTENT, &default_dest_path, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve path %s under directory %s: %m", v, esp_path);
@@ -968,10 +968,10 @@ static int install_binaries(const char *esp_path, const char *arch, bool force)
_cleanup_free_ char *path = NULL;
int r;
- r = chase_symlinks_and_opendir(BOOTLIBDIR, root, CHASE_PREFIX_ROOT, &path, &d);
+ r = chase_symlinks_and_opendir(BOOTLIBDIR, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &path, &d);
/* If we had a root directory to try, we didn't find it and we are in auto mode, retry on the host */
if (r == -ENOENT && root && arg_install_source == ARG_INSTALL_SOURCE_AUTO)
- r = chase_symlinks_and_opendir(BOOTLIBDIR, NULL, CHASE_PREFIX_ROOT, &path, &d);
+ r = chase_symlinks_and_opendir(BOOTLIBDIR, NULL, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &path, &d);
if (r < 0)
return log_error_errno(r, "Failed to open boot loader directory %s%s: %m", strempty(root), BOOTLIBDIR);
@@ -1141,7 +1141,7 @@ static int install_variables(
return 0;
}
- r = chase_symlinks_and_access(path, esp_path, CHASE_PREFIX_ROOT, F_OK, NULL, NULL);
+ r = chase_symlinks_and_access(path, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, F_OK, NULL, NULL);
if (r == -ENOENT)
return 0;
if (r < 0)
@@ -1172,7 +1172,7 @@ static int remove_boot_efi(const char *esp_path) {
_cleanup_free_ char *p = NULL;
int r, c = 0;
- r = chase_symlinks_and_opendir("/EFI/BOOT", esp_path, CHASE_PREFIX_ROOT, &p, &d);
+ r = chase_symlinks_and_opendir("/EFI/BOOT", esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &p, &d);
if (r == -ENOENT)
return 0;
if (r < 0)
diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c
index fe44b5e9d2..9352416af5 100644
--- a/src/shared/bootspec.c
+++ b/src/shared/bootspec.c
@@ -507,7 +507,7 @@ static int boot_loader_read_conf_path(BootConfig *config, const char *root, cons
assert(config);
assert(path);
- r = chase_symlinks_and_fopen_unlocked(path, root, CHASE_PREFIX_ROOT, "re", &full, &f);
+ r = chase_symlinks_and_fopen_unlocked(path, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, "re", &full, &f);
if (r == -ENOENT)
return 0;
if (r < 0)
@@ -609,7 +609,7 @@ static int boot_entries_find_type1(
assert(root);
assert(dir);
- dir_fd = chase_symlinks_and_open(dir, root, CHASE_PREFIX_ROOT, O_DIRECTORY|O_CLOEXEC, &full);
+ dir_fd = chase_symlinks_and_open(dir, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, O_DIRECTORY|O_CLOEXEC, &full);
if (dir_fd == -ENOENT)
return 0;
if (dir_fd < 0)
@@ -869,7 +869,7 @@ static int boot_entries_find_unified(
assert(config);
assert(dir);
- r = chase_symlinks_and_opendir(dir, root, CHASE_PREFIX_ROOT, &full, &d);
+ r = chase_symlinks_and_opendir(dir, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &full, &d);
if (r == -ENOENT)
return 0;
if (r < 0)
@@ -1282,7 +1282,7 @@ static void boot_entry_file_list(
assert(p);
assert(ret_status);
- int status = chase_symlinks_and_access(p, root, CHASE_PREFIX_ROOT, F_OK, NULL, NULL);
+ int status = chase_symlinks_and_access(p, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, F_OK, NULL, NULL);
printf("%13s%s ", strempty(field), field ? ":" : " ");
if (status < 0) {

View File

@ -0,0 +1,863 @@
From bd5fbc8566124744d94d5f040016b9f4404dc2dc Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Wed, 9 Nov 2022 12:44:37 +0100
Subject: [PATCH] boot: implement kernel EFI RNG seed protocol with proper
hashing
Rather than passing seeds up to userspace via EFI variables, pass seeds
directly to the kernel's EFI stub loader, via LINUX_EFI_RANDOM_SEED_TABLE_GUID.
EFI variables can potentially leak and suffer from forward secrecy
issues, and processing these with userspace means that they are
initialized much too late in boot to be useful. In contrast,
LINUX_EFI_RANDOM_SEED_TABLE_GUID uses EFI configuration tables, and so
is hidden from userspace entirely, and is parsed extremely early on by
the kernel, so that every single call to get_random_bytes() by the
kernel is seeded.
In order to do this properly, we use a bit more robust hashing scheme,
and make sure that each input is properly memzeroed out after use. The
scheme is:
key = HASH(LABEL || sizeof(input1) || input1 || ... || sizeof(inputN) || inputN)
new_disk_seed = HASH(key || 0)
seed_for_linux = HASH(key || 1)
The various inputs are:
- LINUX_EFI_RANDOM_SEED_TABLE_GUID from prior bootloaders
- 256 bits of seed from EFI's RNG
- The (immutable) system token, from its EFI variable
- The prior on-disk seed
- The UEFI monotonic counter
- A timestamp
This also adjusts the secure boot semantics, so that the operation is
only aborted if it's not possible to get random bytes from EFI's RNG or
a prior boot stage. With the proper hashing scheme, this should make
boot seeds safe even on secure boot.
There is currently a bug in Linux's EFI stub in which if the EFI stub
manages to generate random bytes on its own using EFI's RNG, it will
ignore what the bootloader passes. That's annoying, but it means that
either way, via systemd-boot or via EFI stub's mechanism, the RNG *does*
get initialized in a good safe way. And this bug is now fixed in the
efi.git tree, and will hopefully be backported to older kernels.
As the kernel recommends, the resultant seeds are 256 bits and are
allocated using pool memory of type EfiACPIReclaimMemory, so that it
gets freed at the right moment in boot.
(cherry picked from commit 0be72218f1c90af5755ab40f94d047ee6864aea8)
Related: RHEL-16952
---
.../UninitializedVariableWithCleanup.ql | 2 +-
docs/BOOT_LOADER_INTERFACE.md | 9 +-
docs/RANDOM_SEEDS.md | 51 +--
man/systemd-boot.xml | 22 --
src/basic/random-util.h | 1 +
src/boot/bootctl.c | 30 +-
src/boot/efi/efi-string.h | 1 +
src/boot/efi/random-seed.c | 305 +++++++++---------
src/core/efi-random.c | 82 +----
src/core/efi-random.h | 2 +-
src/core/main.c | 4 +-
units/systemd-boot-system-token.service | 3 -
12 files changed, 218 insertions(+), 294 deletions(-)
diff --git a/.github/codeql-queries/UninitializedVariableWithCleanup.ql b/.github/codeql-queries/UninitializedVariableWithCleanup.ql
index e514111f28..dadc6cb1b5 100644
--- a/.github/codeql-queries/UninitializedVariableWithCleanup.ql
+++ b/.github/codeql-queries/UninitializedVariableWithCleanup.ql
@@ -20,7 +20,7 @@ import semmle.code.cpp.controlflow.StackVariableReachability
* since they don't do anything illegal even when the variable is uninitialized
*/
predicate cleanupFunctionDenyList(string fun) {
- fun = "erase_char"
+ fun = "erase_char" or fun = "erase_obj"
}
/**
diff --git a/docs/BOOT_LOADER_INTERFACE.md b/docs/BOOT_LOADER_INTERFACE.md
index fc9336085b..5be4d1ad17 100644
--- a/docs/BOOT_LOADER_INTERFACE.md
+++ b/docs/BOOT_LOADER_INTERFACE.md
@@ -80,12 +80,6 @@ variables. All EFI variables use the vendor UUID
* `1 << 5` → The boot loader supports looking for boot menu entries in the Extended Boot Loader Partition.
* `1 << 6` → The boot loader supports passing a random seed to the OS.
-* The EFI variable `LoaderRandomSeed` contains a binary random seed if set. It
- is set by the boot loader to pass an entropy seed read from the ESP to the OS.
- The system manager then credits this seed to the kernel's entropy pool. It is
- the responsibility of the boot loader to ensure the quality and integrity of
- the random seed.
-
* The EFI variable `LoaderSystemToken` contains binary random data,
persistently set by the OS installer. Boot loaders that support passing
random seeds to the OS should use this data and combine it with the random
@@ -107,8 +101,7 @@ that directory is empty, and only if no other file systems are mounted
there. The `systemctl reboot --boot-loader-entry=…` and `systemctl reboot
--boot-loader-menu=…` commands rely on the `LoaderFeatures` ,
`LoaderConfigTimeoutOneShot`, `LoaderEntries`, `LoaderEntryOneShot`
-variables. `LoaderRandomSeed` is read by PID during early boot and credited to
-the kernel's random pool.
+variables.
## Boot Loader Entry Identifiers
diff --git a/docs/RANDOM_SEEDS.md b/docs/RANDOM_SEEDS.md
index 3dc27f5552..b7240f0d89 100644
--- a/docs/RANDOM_SEEDS.md
+++ b/docs/RANDOM_SEEDS.md
@@ -197,28 +197,39 @@ boot, in order to ensure the entropy pool is filled up quickly.
generate sufficient data), to generate a new random seed file to store in
the ESP as well as a random seed to pass to the OS kernel. The new random
seed file for the ESP is then written to the ESP, ensuring this is completed
- before the OS is invoked. Very early during initialization PID 1 will read
- the random seed provided in the EFI variable and credit it fully to the
- kernel's entropy pool.
-
- This mechanism is able to safely provide an initialized entropy pool already
- in the `initrd` and guarantees that different seeds are passed from the boot
- loader to the OS on every boot (in a way that does not allow regeneration of
- an old seed file from a new seed file). Moreover, when an OS image is
- replicated between multiple images and the random seed is not reset, this
- will still result in different random seeds being passed to the OS, as the
- per-machine 'system token' is specific to the physical host, and not
- included in OS disk images. If the 'system token' is properly initialized
- and kept sufficiently secret it should not be possible to regenerate the
- entropy pool of different machines, even if this seed is the only source of
- entropy.
+ before the OS is invoked.
+
+ The kernel then reads the random seed that the boot loader passes to it, via
+ the EFI configuration table entry, `LINUX_EFI_RANDOM_SEED_TABLE_GUID`
+ (1ce1e5bc-7ceb-42f2-81e5-8aadf180f57b), which is allocated with pool memory
+ of type `EfiACPIReclaimMemory`. Its contents have the form:
+ ```
+ struct linux_efi_random_seed {
+ u32 size; // of the 'seed' array in bytes
+ u8 seed[];
+ };
+ ```
+ The size field is generally set to 32 bytes, and the seed field includes a
+ hashed representation of any prior seed in `LINUX_EFI_RANDOM_SEED_TABLE_GUID`
+ together with the new seed.
+
+ This mechanism is able to safely provide an initialized entropy pool before
+ userspace even starts and guarantees that different seeds are passed from
+ the boot loader to the OS on every boot (in a way that does not allow
+ regeneration of an old seed file from a new seed file). Moreover, when an OS
+ image is replicated between multiple images and the random seed is not
+ reset, this will still result in different random seeds being passed to the
+ OS, as the per-machine 'system token' is specific to the physical host, and
+ not included in OS disk images. If the 'system token' is properly
+ initialized and kept sufficiently secret it should not be possible to
+ regenerate the entropy pool of different machines, even if this seed is the
+ only source of entropy.
Note that the writes to the ESP needed to maintain the random seed should be
- minimal. The size of the random seed file is directly derived from the Linux
- kernel's entropy pool size, which defaults to 512 bytes. This means updating
- the random seed in the ESP should be doable safely with a single sector
- write (since hard-disk sectors typically happen to be 512 bytes long, too),
- which should be safe even with FAT file system drivers built into
+ minimal. Because the size of the random seed file is generally set to 32 bytes,
+ updating the random seed in the ESP should be doable safely with a single
+ sector write (since hard-disk sectors typically happen to be 512 bytes long,
+ too), which should be safe even with FAT file system drivers built into
low-quality EFI firmwares.
As a special restriction: in virtualized environments PID 1 will refrain
diff --git a/man/systemd-boot.xml b/man/systemd-boot.xml
index 57b66803fa..f96c4c6512 100644
--- a/man/systemd-boot.xml
+++ b/man/systemd-boot.xml
@@ -435,28 +435,6 @@
to view this data. </para></listitem>
</varlistentry>
- <varlistentry>
- <term><varname>LoaderRandomSeed</varname></term>
-
- <listitem><para>A binary random seed <command>systemd-boot</command> may optionally pass to the
- OS. This is a volatile EFI variable that is hashed at boot from the combination of a random seed
- stored in the ESP (in <filename>/loader/random-seed</filename>) and a "system token" persistently
- stored in the EFI variable <varname>LoaderSystemToken</varname> (see below). During early OS boot the
- system manager reads this variable and passes it to the OS kernel's random pool, crediting the full
- entropy it contains. This is an efficient way to ensure the system starts up with a fully initialized
- kernel random pool — as early as the initrd phase. <command>systemd-boot</command> reads
- the random seed from the ESP, combines it with the "system token", and both derives a new random seed
- to update in-place the seed stored in the ESP, and the random seed to pass to the OS from it via
- SHA256 hashing in counter mode. This ensures that different physical systems that boot the same
- "golden" OS image — i.e. containing the same random seed file in the ESP — will still pass a
- different random seed to the OS. It is made sure the random seed stored in the ESP is fully
- overwritten before the OS is booted, to ensure different random seed data is used between subsequent
- boots.</para>
-
- <para>See <ulink url="https://systemd.io/RANDOM_SEEDS">Random Seeds</ulink> for
- further information.</para></listitem>
- </varlistentry>
-
<varlistentry>
<term><varname>LoaderSystemToken</varname></term>
diff --git a/src/basic/random-util.h b/src/basic/random-util.h
index 7e6f66df4d..08b1a3599a 100644
--- a/src/basic/random-util.h
+++ b/src/basic/random-util.h
@@ -23,6 +23,7 @@ static inline uint32_t random_u32(void) {
/* Some limits on the pool sizes when we deal with the kernel random pool */
#define RANDOM_POOL_SIZE_MIN 1024U
#define RANDOM_POOL_SIZE_MAX (10U*1024U*1024U)
+#define RANDOM_EFI_SEED_SIZE 32U
size_t random_pool_size(void);
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index e830d45486..e23a72fd38 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -1894,8 +1894,6 @@ static int verb_status(int argc, char *argv[], void *userdata) {
printf("\n");
printf("%sRandom Seed:%s\n", ansi_underline(), ansi_normal());
- have = access(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderRandomSeed)), F_OK) >= 0;
- printf(" Passed to OS: %s\n", yes_no(have));
have = access(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderSystemToken)), F_OK) >= 0;
printf(" System Token: %s\n", have ? "set" : "not set");
@@ -1985,10 +1983,10 @@ static int verb_list(int argc, char *argv[], void *userdata) {
static int install_random_seed(const char *esp) {
_cleanup_(unlink_and_freep) char *tmp = NULL;
- _cleanup_free_ void *buffer = NULL;
+ unsigned char buffer[RANDOM_EFI_SEED_SIZE];
_cleanup_free_ char *path = NULL;
_cleanup_close_ int fd = -1;
- size_t sz, token_size;
+ size_t token_size;
ssize_t n;
int r;
@@ -1998,13 +1996,7 @@ static int install_random_seed(const char *esp) {
if (!path)
return log_oom();
- sz = random_pool_size();
-
- buffer = malloc(sz);
- if (!buffer)
- return log_oom();
-
- r = crypto_random_bytes(buffer, sz);
+ r = crypto_random_bytes(buffer, sizeof(buffer));
if (r < 0)
return log_error_errno(r, "Failed to acquire random seed: %m");
@@ -2025,10 +2017,10 @@ static int install_random_seed(const char *esp) {
return log_error_errno(fd, "Failed to open random seed file for writing: %m");
}
- n = write(fd, buffer, sz);
+ n = write(fd, buffer, sizeof(buffer));
if (n < 0)
return log_error_errno(errno, "Failed to write random seed file: %m");
- if ((size_t) n != sz)
+ if ((size_t) n != sizeof(buffer))
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short write while writing random seed file.");
if (rename(tmp, path) < 0)
@@ -2036,7 +2028,7 @@ static int install_random_seed(const char *esp) {
tmp = mfree(tmp);
- log_info("Random seed file %s successfully written (%zu bytes).", path, sz);
+ log_info("Random seed file %s successfully written (%zu bytes).", path, sizeof(buffer));
if (!arg_touch_variables)
return 0;
@@ -2088,16 +2080,16 @@ static int install_random_seed(const char *esp) {
if (r != -ENOENT)
return log_error_errno(r, "Failed to test system token validity: %m");
} else {
- if (token_size >= sz) {
+ if (token_size >= sizeof(buffer)) {
/* Let's avoid writes if we can, and initialize this only once. */
log_debug("System token already written, not updating.");
return 0;
}
- log_debug("Existing system token size (%zu) does not match our expectations (%zu), replacing.", token_size, sz);
+ log_debug("Existing system token size (%zu) does not match our expectations (%zu), replacing.", token_size, sizeof(buffer));
}
- r = crypto_random_bytes(buffer, sz);
+ r = crypto_random_bytes(buffer, sizeof(buffer));
if (r < 0)
return log_error_errno(r, "Failed to acquire random seed: %m");
@@ -2105,7 +2097,7 @@ static int install_random_seed(const char *esp) {
* and possibly get identification information or too much insight into the kernel's entropy pool
* state. */
RUN_WITH_UMASK(0077) {
- r = efi_set_variable(EFI_LOADER_VARIABLE(LoaderSystemToken), buffer, sz);
+ r = efi_set_variable(EFI_LOADER_VARIABLE(LoaderSystemToken), buffer, sizeof(buffer));
if (r < 0) {
if (!arg_graceful)
return log_error_errno(r, "Failed to write 'LoaderSystemToken' EFI variable: %m");
@@ -2115,7 +2107,7 @@ static int install_random_seed(const char *esp) {
else
log_warning_errno(r, "Unable to write 'LoaderSystemToken' EFI variable, ignoring: %m");
} else
- log_info("Successfully initialized system token in EFI variable with %zu bytes.", sz);
+ log_info("Successfully initialized system token in EFI variable with %zu bytes.", sizeof(buffer));
}
return 0;
diff --git a/src/boot/efi/efi-string.h b/src/boot/efi/efi-string.h
index 9b2a9ad1c5..25931a7d6e 100644
--- a/src/boot/efi/efi-string.h
+++ b/src/boot/efi/efi-string.h
@@ -124,6 +124,7 @@ static inline void *mempcpy(void * restrict dest, const void * restrict src, siz
memcpy(dest, src, n);
return (uint8_t *) dest + n;
}
+
#else
/* For unit testing. */
int efi_memcmp(const void *p1, const void *p2, size_t n);
diff --git a/src/boot/efi/random-seed.c b/src/boot/efi/random-seed.c
index 3c9df5bb54..c723160c0f 100644
--- a/src/boot/efi/random-seed.c
+++ b/src/boot/efi/random-seed.c
@@ -15,11 +15,24 @@
#define EFI_RNG_GUID &(const EFI_GUID) EFI_RNG_PROTOCOL_GUID
+struct linux_efi_random_seed {
+ uint32_t size;
+ uint8_t seed[];
+};
+
+#define LINUX_EFI_RANDOM_SEED_TABLE_GUID \
+ { 0x1ce1e5bc, 0x7ceb, 0x42f2, { 0x81, 0xe5, 0x8a, 0xad, 0xf1, 0x80, 0xf5, 0x7b } }
+
/* SHA256 gives us 256/8=32 bytes */
#define HASH_VALUE_SIZE 32
-static EFI_STATUS acquire_rng(UINTN size, void **ret) {
- _cleanup_free_ void *data = NULL;
+/* Linux's RNG is 256 bits, so let's provide this much */
+#define DESIRED_SEED_SIZE 32
+
+/* Some basic domain separation in case somebody uses this data elsewhere */
+#define HASH_LABEL "systemd-boot random seed label v1"
+
+static EFI_STATUS acquire_rng(void *ret, UINTN size) {
EFI_RNG_PROTOCOL *rng;
EFI_STATUS err;
@@ -33,126 +46,9 @@ static EFI_STATUS acquire_rng(UINTN size, void **ret) {
if (!rng)
return EFI_UNSUPPORTED;
- data = xmalloc(size);
-
- err = rng->GetRNG(rng, NULL, size, data);
+ err = rng->GetRNG(rng, NULL, size, ret);
if (err != EFI_SUCCESS)
return log_error_status_stall(err, L"Failed to acquire RNG data: %r", err);
-
- *ret = TAKE_PTR(data);
- return EFI_SUCCESS;
-}
-
-static void hash_once(
- const void *old_seed,
- const void *rng,
- UINTN size,
- const void *system_token,
- UINTN system_token_size,
- uint64_t uefi_monotonic_counter,
- UINTN counter,
- uint8_t ret[static HASH_VALUE_SIZE]) {
-
- /* This hashes together:
- *
- * 1. The contents of the old seed file
- * 2. Some random data acquired from the UEFI RNG (optional)
- * 3. Some 'system token' the installer installed as EFI variable (optional)
- * 4. The UEFI "monotonic counter" that increases with each boot
- * 5. A supplied counter value
- *
- * And writes the result to the specified buffer.
- */
-
- struct sha256_ctx hash;
-
- assert(old_seed);
- assert(system_token_size == 0 || system_token);
-
- sha256_init_ctx(&hash);
- sha256_process_bytes(old_seed, size, &hash);
- if (rng)
- sha256_process_bytes(rng, size, &hash);
- if (system_token_size > 0)
- sha256_process_bytes(system_token, system_token_size, &hash);
- sha256_process_bytes(&uefi_monotonic_counter, sizeof(uefi_monotonic_counter), &hash);
- sha256_process_bytes(&counter, sizeof(counter), &hash);
- sha256_finish_ctx(&hash, ret);
-}
-
-static EFI_STATUS hash_many(
- const void *old_seed,
- const void *rng,
- UINTN size,
- const void *system_token,
- UINTN system_token_size,
- uint64_t uefi_monotonic_counter,
- UINTN counter_start,
- UINTN n,
- void **ret) {
-
- _cleanup_free_ void *output = NULL;
-
- assert(old_seed);
- assert(system_token_size == 0 || system_token);
- assert(ret);
-
- /* Hashes the specified parameters in counter mode, generating n hash values, with the counter in the
- * range counter_start…counter_start+n-1. */
-
- output = xmalloc_multiply(HASH_VALUE_SIZE, n);
-
- for (UINTN i = 0; i < n; i++)
- hash_once(old_seed, rng, size,
- system_token, system_token_size,
- uefi_monotonic_counter,
- counter_start + i,
- (uint8_t*) output + (i * HASH_VALUE_SIZE));
-
- *ret = TAKE_PTR(output);
- return EFI_SUCCESS;
-}
-
-static EFI_STATUS mangle_random_seed(
- const void *old_seed,
- const void *rng,
- UINTN size,
- const void *system_token,
- UINTN system_token_size,
- uint64_t uefi_monotonic_counter,
- void **ret_new_seed,
- void **ret_for_kernel) {
-
- _cleanup_free_ void *new_seed = NULL, *for_kernel = NULL;
- EFI_STATUS err;
- UINTN n;
-
- assert(old_seed);
- assert(system_token_size == 0 || system_token);
- assert(ret_new_seed);
- assert(ret_for_kernel);
-
- /* This takes the old seed file contents, an (optional) random number acquired from the UEFI RNG, an
- * (optional) system 'token' installed once by the OS installer in an EFI variable, and hashes them
- * together in counter mode, generating a new seed (to replace the file on disk) and the seed for the
- * kernel. To keep things simple, the new seed and kernel data have the same size as the old seed and
- * RNG data. */
-
- n = (size + HASH_VALUE_SIZE - 1) / HASH_VALUE_SIZE;
-
- /* Begin hashing in counter mode at counter 0 for the new seed for the disk */
- err = hash_many(old_seed, rng, size, system_token, system_token_size, uefi_monotonic_counter, 0, n, &new_seed);
- if (err != EFI_SUCCESS)
- return err;
-
- /* Continue counting at 'n' for the seed for the kernel */
- err = hash_many(old_seed, rng, size, system_token, system_token_size, uefi_monotonic_counter, n, n, &for_kernel);
- if (err != EFI_SUCCESS)
- return err;
-
- *ret_new_seed = TAKE_PTR(new_seed);
- *ret_for_kernel = TAKE_PTR(for_kernel);
-
return EFI_SUCCESS;
}
@@ -164,6 +60,7 @@ static EFI_STATUS acquire_system_token(void **ret, UINTN *ret_size) {
assert(ret);
assert(ret_size);
+ *ret_size = 0;
err = efivar_get_raw(LOADER_GUID, L"LoaderSystemToken", &data, &size);
if (err != EFI_SUCCESS) {
if (err != EFI_NOT_FOUND)
@@ -221,32 +118,88 @@ static void validate_sha256(void) {
#endif
}
-EFI_STATUS process_random_seed(EFI_FILE *root_dir, RandomSeedMode mode) {
- _cleanup_free_ void *seed = NULL, *new_seed = NULL, *rng = NULL, *for_kernel = NULL, *system_token = NULL;
+EFI_STATUS process_random_seed(EFI_FILE *root_dir) {
+ uint8_t random_bytes[DESIRED_SEED_SIZE], hash_key[HASH_VALUE_SIZE];
+ _cleanup_free_ struct linux_efi_random_seed *new_seed_table = NULL;
+ struct linux_efi_random_seed *previous_seed_table = NULL;
+ _cleanup_free_ void *seed = NULL, *system_token = NULL;
_cleanup_(file_closep) EFI_FILE *handle = NULL;
- UINTN size, rsize, wsize, system_token_size = 0;
_cleanup_free_ EFI_FILE_INFO *info = NULL;
+ struct sha256_ctx hash;
uint64_t uefi_monotonic_counter = 0;
+ size_t size, rsize, wsize;
+ bool seeded_by_efi = false;
EFI_STATUS err;
+ EFI_TIME now;
+
+ CLEANUP_ERASE(random_bytes);
+ CLEANUP_ERASE(hash_key);
+ CLEANUP_ERASE(hash);
assert(root_dir);
+ assert_cc(DESIRED_SEED_SIZE == HASH_VALUE_SIZE);
validate_sha256();
if (mode == RANDOM_SEED_OFF)
return EFI_NOT_FOUND;
- /* Let's better be safe than sorry, and for now disable this logic in SecureBoot mode, so that we
- * don't credit a random seed that is not authenticated. */
- if (secure_boot_enabled())
- return EFI_NOT_FOUND;
+ /* hash = LABEL || sizeof(input1) || input1 || ... || sizeof(inputN) || inputN */
+ sha256_init_ctx(&hash);
+
+ /* Some basic domain separation in case somebody uses this data elsewhere */
+ sha256_process_bytes(HASH_LABEL, sizeof(HASH_LABEL) - 1, &hash);
+
+ for (size_t i = 0; i < ST->NumberOfTableEntries; ++i)
+ if (memcmp(&(const EFI_GUID)LINUX_EFI_RANDOM_SEED_TABLE_GUID,
+ &ST->ConfigurationTable[i].VendorGuid, sizeof(EFI_GUID)) == 0) {
+ previous_seed_table = ST->ConfigurationTable[i].VendorTable;
+ break;
+ }
+ if (!previous_seed_table) {
+ size = 0;
+ sha256_process_bytes(&size, sizeof(size), &hash);
+ } else {
+ size = previous_seed_table->size;
+ seeded_by_efi = size >= DESIRED_SEED_SIZE;
+ sha256_process_bytes(&size, sizeof(size), &hash);
+ sha256_process_bytes(previous_seed_table->seed, size, &hash);
+
+ /* Zero and free the previous seed table only at the end after we've managed to install a new
+ * one, so that in case this function fails or aborts, Linux still receives whatever the
+ * previous bootloader chain set. So, the next line of this block is not an explicit_bzero()
+ * call. */
+ }
+
+ /* Request some random data from the UEFI RNG. We don't need this to work safely, but it's a good
+ * idea to use it because it helps us for cases where users mistakenly include a random seed in
+ * golden master images that are replicated many times. */
+ err = acquire_rng(random_bytes, sizeof(random_bytes));
+ if (err != EFI_SUCCESS) {
+ size = 0;
+ /* If we can't get any randomness from EFI itself, then we'll only be relying on what's in
+ * ESP. But ESP is mutable, so if secure boot is enabled, we probably shouldn't trust that
+ * alone, in which case we bail out early. */
+ if (!seeded_by_efi && secure_boot_enabled())
+ return EFI_NOT_FOUND;
+ } else {
+ seeded_by_efi = true;
+ size = sizeof(random_bytes);
+ }
+ sha256_process_bytes(&size, sizeof(size), &hash);
+ sha256_process_bytes(random_bytes, size, &hash);
/* Get some system specific seed that the installer might have placed in an EFI variable. We include
* it in our hash. This is protection against golden master image sloppiness, and it remains on the
* system, even when disk images are duplicated or swapped out. */
- err = acquire_system_token(&system_token, &system_token_size);
- if (mode != RANDOM_SEED_ALWAYS && err != EFI_SUCCESS)
+ err = acquire_system_token(&system_token, &size);
+ if (mode != RANDOM_SEED_ALWAYS && (err != EFI_SUCCESS || size < DESIRED_SEED_SIZE) && !seeded_by_efi)
return err;
+ sha256_process_bytes(&size, sizeof(size), &hash);
+ if (system_token) {
+ sha256_process_bytes(system_token, size, &hash);
+ explicit_bzero_safe(system_token, size);
+ }
err = root_dir->Open(
root_dir,
@@ -262,7 +215,7 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir, RandomSeedMode mode) {
err = get_file_info_harder(handle, &info, NULL);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed to get file info for random seed: %r");
+ return log_error_status_stall(err, L"Failed to get file info for random seed: %r", err);
size = info->FileSize;
if (size < RANDOM_MAX_SIZE_MIN)
@@ -272,51 +225,105 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir, RandomSeedMode mode) {
return log_error_status_stall(EFI_INVALID_PARAMETER, L"Random seed file is too large.");
seed = xmalloc(size);
-
rsize = size;
err = handle->Read(handle, &rsize, seed);
if (err != EFI_SUCCESS)
return log_error_status_stall(err, L"Failed to read random seed file: %r", err);
- if (rsize != size)
+ if (rsize != size) {
+ explicit_bzero_safe(seed, rsize);
return log_error_status_stall(EFI_PROTOCOL_ERROR, L"Short read on random seed file.");
+ }
+
+ sha256_process_bytes(&size, sizeof(size), &hash);
+ sha256_process_bytes(seed, size, &hash);
+ explicit_bzero_safe(seed, size);
err = handle->SetPosition(handle, 0);
if (err != EFI_SUCCESS)
return log_error_status_stall(err, L"Failed to seek to beginning of random seed file: %r", err);
- /* Request some random data from the UEFI RNG. We don't need this to work safely, but it's a good
- * idea to use it because it helps us for cases where users mistakenly include a random seed in
- * golden master images that are replicated many times. */
- (void) acquire_rng(size, &rng); /* It's fine if this fails */
-
/* Let's also include the UEFI monotonic counter (which is supposedly increasing on every single
* boot) in the hash, so that even if the changes to the ESP for some reason should not be
* persistent, the random seed we generate will still be different on every single boot. */
err = BS->GetNextMonotonicCount(&uefi_monotonic_counter);
- if (err != EFI_SUCCESS)
+ if (err != EFI_SUCCESS && !seeded_by_efi)
return log_error_status_stall(err, L"Failed to acquire UEFI monotonic counter: %r", err);
-
- /* Calculate new random seed for the disk and what to pass to the kernel */
- err = mangle_random_seed(seed, rng, size, system_token, system_token_size, uefi_monotonic_counter, &new_seed, &for_kernel);
- if (err != EFI_SUCCESS)
- return err;
-
+ size = sizeof(uefi_monotonic_counter);
+ sha256_process_bytes(&size, sizeof(size), &hash);
+ sha256_process_bytes(&uefi_monotonic_counter, size, &hash);
+ err = RT->GetTime(&now, NULL);
+ size = err == EFI_SUCCESS ? sizeof(now) : 0; /* Known to be flaky, so don't bark on error. */
+ sha256_process_bytes(&size, sizeof(size), &hash);
+ sha256_process_bytes(&now, size, &hash);
+
+ /* hash_key = HASH(hash) */
+ sha256_finish_ctx(&hash, hash_key);
+
+ /* hash = hash_key || 0 */
+ sha256_init_ctx(&hash);
+ sha256_process_bytes(hash_key, sizeof(hash_key), &hash);
+ sha256_process_bytes(&(const uint8_t){ 0 }, sizeof(uint8_t), &hash);
+ /* random_bytes = HASH(hash) */
+ sha256_finish_ctx(&hash, random_bytes);
+
+ size = sizeof(random_bytes);
+ /* If the file size is too large, zero out the remaining bytes on disk, and then truncate. */
+ if (size < info->FileSize) {
+ err = handle->SetPosition(handle, size);
+ if (err != EFI_SUCCESS)
+ return log_error_status_stall(err, L"Failed to seek to offset of random seed file: %r", err);
+ wsize = info->FileSize - size;
+ err = handle->Write(handle, &wsize, seed /* All zeros now */);
+ if (err != EFI_SUCCESS)
+ return log_error_status_stall(err, L"Failed to write random seed file: %r", err);
+ if (wsize != info->FileSize - size)
+ return log_error_status_stall(EFI_PROTOCOL_ERROR, L"Short write on random seed file.");
+ err = handle->Flush(handle);
+ if (err != EFI_SUCCESS)
+ return log_error_status_stall(err, L"Failed to flush random seed file: %r", err);
+ err = handle->SetPosition(handle, 0);
+ if (err != EFI_SUCCESS)
+ return log_error_status_stall(err, L"Failed to seek to beginning of random seed file: %r", err);
+ info->FileSize = size;
+ err = handle->SetInfo(handle, &GenericFileInfo, info->Size, info);
+ if (err != EFI_SUCCESS)
+ return log_error_status_stall(err, L"Failed to truncate random seed file: %r", err);
+ }
/* Update the random seed on disk before we use it */
wsize = size;
- err = handle->Write(handle, &wsize, new_seed);
+ err = handle->Write(handle, &wsize, random_bytes);
if (err != EFI_SUCCESS)
return log_error_status_stall(err, L"Failed to write random seed file: %r", err);
if (wsize != size)
return log_error_status_stall(EFI_PROTOCOL_ERROR, L"Short write on random seed file.");
-
err = handle->Flush(handle);
if (err != EFI_SUCCESS)
return log_error_status_stall(err, L"Failed to flush random seed file: %r", err);
- /* We are good to go */
- err = efivar_set_raw(LOADER_GUID, L"LoaderRandomSeed", for_kernel, size, 0);
+ err = BS->AllocatePool(EfiACPIReclaimMemory, sizeof(*new_seed_table) + DESIRED_SEED_SIZE,
+ (void **) &new_seed_table);
+ if (err != EFI_SUCCESS)
+ return log_error_status_stall(err, L"Failed to allocate EFI table for random seed: %r", err);
+ new_seed_table->size = DESIRED_SEED_SIZE;
+
+ /* hash = hash_key || 1 */
+ sha256_init_ctx(&hash);
+ sha256_process_bytes(hash_key, sizeof(hash_key), &hash);
+ sha256_process_bytes(&(const uint8_t){ 1 }, sizeof(uint8_t), &hash);
+ /* new_seed_table->seed = HASH(hash) */
+ sha256_finish_ctx(&hash, new_seed_table->seed);
+
+ err = BS->InstallConfigurationTable(&(EFI_GUID)LINUX_EFI_RANDOM_SEED_TABLE_GUID, new_seed_table);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed to write random seed to EFI variable: %r", err);
+ return log_error_status_stall(err, L"Failed to install EFI table for random seed: %r", err);
+ TAKE_PTR(new_seed_table);
+
+ if (previous_seed_table) {
+ /* Now that we've succeeded in installing the new table, we can safely nuke the old one. */
+ explicit_bzero_safe(previous_seed_table->seed, previous_seed_table->size);
+ explicit_bzero_safe(previous_seed_table, sizeof(*previous_seed_table));
+ free(previous_seed_table);
+ }
return EFI_SUCCESS;
}
diff --git a/src/core/efi-random.c b/src/core/efi-random.c
index 4086b12739..61516775fc 100644
--- a/src/core/efi-random.c
+++ b/src/core/efi-random.c
@@ -12,79 +12,23 @@
#include "random-util.h"
#include "strv.h"
-/* If a random seed was passed by the boot loader in the LoaderRandomSeed EFI variable, let's credit it to
- * the kernel's random pool, but only once per boot. If this is run very early during initialization we can
- * instantly boot up with a filled random pool.
- *
- * This makes no judgement on the entropy passed, it's the job of the boot loader to only pass us a seed that
- * is suitably validated. */
-
-static void lock_down_efi_variables(void) {
+void lock_down_efi_variables(void) {
+ _cleanup_close_ int fd = -1;
int r;
+ fd = open(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderSystemToken)), O_RDONLY|O_CLOEXEC);
+ if (fd < 0) {
+ if (errno != ENOENT)
+ log_warning_errno(errno, "Unable to open LoaderSystemToken EFI variable, ignoring: %m");
+ return;
+ }
+
/* Paranoia: let's restrict access modes of these a bit, so that unprivileged users can't use them to
* identify the system or gain too much insight into what we might have credited to the entropy
* pool. */
- FOREACH_STRING(path,
- EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderRandomSeed)),
- EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderSystemToken))) {
-
- r = chattr_path(path, 0, FS_IMMUTABLE_FL, NULL);
- if (r == -ENOENT)
- continue;
- if (r < 0)
- log_warning_errno(r, "Failed to drop FS_IMMUTABLE_FL from %s, ignoring: %m", path);
-
- if (chmod(path, 0600) < 0)
- log_warning_errno(errno, "Failed to reduce access mode of %s, ignoring: %m", path);
- }
-}
-
-int efi_take_random_seed(void) {
- _cleanup_free_ void *value = NULL;
- size_t size;
- int r;
-
- /* Paranoia comes first. */
- lock_down_efi_variables();
-
- if (access("/run/systemd/efi-random-seed-taken", F_OK) < 0) {
- if (errno != ENOENT) {
- log_warning_errno(errno, "Failed to determine whether we already used the random seed token, not using it.");
- return 0;
- }
-
- /* ENOENT means we haven't used it yet. */
- } else {
- log_debug("EFI random seed already used, not using again.");
- return 0;
- }
-
- r = efi_get_variable(EFI_LOADER_VARIABLE(LoaderRandomSeed), NULL, &value, &size);
- if (r == -EOPNOTSUPP) {
- log_debug_errno(r, "System lacks EFI support, not initializing random seed from EFI variable.");
- return 0;
- }
- if (r == -ENOENT) {
- log_debug_errno(r, "Boot loader did not pass LoaderRandomSeed EFI variable, not crediting any entropy.");
- return 0;
- }
+ r = chattr_fd(fd, 0, FS_IMMUTABLE_FL, NULL);
if (r < 0)
- return log_warning_errno(r, "Failed to read LoaderRandomSeed EFI variable, ignoring: %m");
-
- if (size == 0)
- return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Random seed passed from boot loader has zero size? Ignoring.");
-
- /* Before we use the seed, let's mark it as used, so that we never credit it twice. Also, it's a nice
- * way to let users known that we successfully acquired entropy from the boot loader. */
- r = touch("/run/systemd/efi-random-seed-taken");
- if (r < 0)
- return log_warning_errno(r, "Unable to mark EFI random seed as used, not using it: %m");
-
- r = random_write_entropy(-1, value, size, true);
- if (r < 0)
- return log_warning_errno(errno, "Failed to credit entropy, ignoring: %m");
-
- log_info("Successfully credited entropy passed from boot loader.");
- return 1;
+ log_warning_errno(r, "Failed to drop FS_IMMUTABLE_FL from LoaderSystemToken EFI variable, ignoring: %m");
+ if (fchmod(fd, 0600) < 0)
+ log_warning_errno(errno, "Failed to reduce access mode of LoaderSystemToken EFI variable, ignoring: %m");
}
diff --git a/src/core/efi-random.h b/src/core/efi-random.h
index 7d20fff57d..87166c9e3f 100644
--- a/src/core/efi-random.h
+++ b/src/core/efi-random.h
@@ -1,4 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
-int efi_take_random_seed(void);
+void lock_down_efi_variables(void);
diff --git a/src/core/main.c b/src/core/main.c
index 126a4bce8c..e7b8e98bca 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -2840,8 +2840,8 @@ int main(int argc, char *argv[]) {
goto finish;
}
- /* The efivarfs is now mounted, let's read the random seed off it */
- (void) efi_take_random_seed();
+ /* The efivarfs is now mounted, let's lock down the system token. */
+ lock_down_efi_variables();
/* Cache command-line options passed from EFI variables */
if (!skip_setup)
diff --git a/units/systemd-boot-system-token.service b/units/systemd-boot-system-token.service
index 662a1fda04..5a56d7c331 100644
--- a/units/systemd-boot-system-token.service
+++ b/units/systemd-boot-system-token.service
@@ -26,9 +26,6 @@ ConditionPathExists=/sys/firmware/efi/efivars/LoaderFeatures-4a67b082-0a4c-41cf-
# Only run this if there is no system token defined yet, or …
ConditionPathExists=|!/sys/firmware/efi/efivars/LoaderSystemToken-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
-# … if the boot loader didn't pass the OS a random seed (and thus probably was missing the random seed file)
-ConditionPathExists=|!/sys/firmware/efi/efivars/LoaderRandomSeed-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
-
[Service]
Type=oneshot
RemainAfterExit=yes

View File

@ -0,0 +1,213 @@
From 461ba7436d539258744d03400490ef100095e093 Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Fri, 11 Nov 2022 15:22:35 +0100
Subject: [PATCH] random-seed: refresh EFI boot seed when writing a new seed
Since this runs at shutdown to write a new seed, we should also keep the
bootloader's seed maximally fresh by doing the same. So we follow the
same pattern - hash some new random bytes with the old seed to make a
new seed. We let this fail without warning, because it's just an
opportunistic thing. If the user happens to have set up the random seed
with bootctl, and the RNG is initialized, then things should be fine. If
not, we create a new seed if systemd-boot is in use. And if not, then we
just don't do anything.
(cherry picked from commit f913c784ad4c93894fd6cb2590738113dff5a694)
Related: RHEL-16952
---
src/random-seed/random-seed.c | 123 +++++++++++++++++++++++++++++++---
1 file changed, 112 insertions(+), 11 deletions(-)
diff --git a/src/random-seed/random-seed.c b/src/random-seed/random-seed.c
index b548f92bbe..54ec3aa7d5 100644
--- a/src/random-seed/random-seed.c
+++ b/src/random-seed/random-seed.c
@@ -15,7 +15,11 @@
#include "sd-id128.h"
#include "alloc-util.h"
+#include "build.h"
+#include "chase-symlinks.h"
+#include "efi-loader.h"
#include "fd-util.h"
+#include "find-esp.h"
#include "fs-util.h"
#include "io-util.h"
#include "log.h"
@@ -25,6 +29,7 @@
#include "mkdir.h"
#include "parse-argument.h"
#include "parse-util.h"
+#include "path-util.h"
#include "pretty-print.h"
#include "random-util.h"
#include "string-table.h"
@@ -185,7 +190,7 @@ static int load_seed_file(
if (ret_hash_state) {
struct sha256_ctx *hash_state;
- hash_state = malloc(sizeof(struct sha256_ctx));
+ hash_state = new(struct sha256_ctx, 1);
if (!hash_state)
return log_oom();
@@ -311,6 +316,101 @@ static int save_seed_file(
return 0;
}
+static int refresh_boot_seed(void) {
+ uint8_t buffer[RANDOM_EFI_SEED_SIZE];
+ struct sha256_ctx hash_state;
+ _cleanup_free_ void *seed_file_bytes = NULL;
+ _cleanup_free_ char *esp_path = NULL;
+ _cleanup_close_ int seed_fd = -1;
+ size_t len;
+ ssize_t r;
+
+ assert_cc(RANDOM_EFI_SEED_SIZE == SHA256_DIGEST_SIZE);
+
+ r = find_esp_and_warn(NULL, NULL, /* unprivileged_mode= */ false, &esp_path,
+ NULL, NULL, NULL, NULL, NULL);
+ if (r < 0) {
+ if (r == -ENOKEY) {
+ log_debug_errno(r, "Couldn't find any ESP, so not updating ESP random seed.");
+ return 0;
+ }
+ return r; /* find_esp_and_warn() already logged */
+ }
+
+ seed_fd = chase_symlinks_and_open("/loader/random-seed", esp_path,
+ CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS,
+ O_RDWR|O_CLOEXEC|O_NOCTTY, NULL);
+ if (seed_fd == -ENOENT) {
+ uint64_t features;
+
+ r = efi_loader_get_features(&features);
+ if (r == 0 && FLAGS_SET(features, EFI_LOADER_FEATURE_RANDOM_SEED)) {
+ int dir_fd = chase_symlinks_and_open("/loader", esp_path,
+ CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS,
+ O_DIRECTORY|O_CLOEXEC|O_NOCTTY, NULL);
+ if (dir_fd >= 0) {
+ seed_fd = openat(dir_fd, "random-seed", O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY, 0600);
+ close(dir_fd);
+ }
+ }
+ }
+ if (seed_fd < 0) {
+ log_debug_errno(seed_fd, "Failed to open EFI seed path: %m");
+ return 0;
+ }
+ r = random_seed_size(seed_fd, &len);
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine EFI seed path length: %m");
+ seed_file_bytes = malloc(len);
+ if (!seed_file_bytes)
+ return log_oom();
+ r = loop_read(seed_fd, seed_file_bytes, len, false);
+ if (r < 0)
+ return log_error_errno(r, "Failed to read EFI seed file: %m");
+
+ /* Hash the old seed in so that we never regress in entropy. */
+ sha256_init_ctx(&hash_state);
+ sha256_process_bytes(&r, sizeof(r), &hash_state);
+ sha256_process_bytes(seed_file_bytes, r, &hash_state);
+
+ /* We're doing this opportunistically, so if the seeding dance before didn't manage to initialize the
+ * RNG, there's no point in doing it here. Secondly, getrandom(GRND_NONBLOCK) has been around longer
+ * than EFI seeding anyway, so there's no point in having non-getrandom() fallbacks here. So if this
+ * fails, just return early to cut our losses. */
+ r = getrandom(buffer, sizeof(buffer), GRND_NONBLOCK);
+ if (r < 0) {
+ if (errno == EAGAIN) {
+ log_debug_errno(errno, "Random pool not initialized yet, so skipping EFI seed update");
+ return 0;
+ }
+ if (errno == ENOSYS) {
+ log_debug_errno(errno, "getrandom() not available, so skipping EFI seed update");
+ return 0;
+ }
+ return log_error_errno(errno, "Failed to generate random bytes for EFI seed: %m");
+ }
+ assert(r == sizeof(buffer));
+
+ /* Hash the new seed into the state containing the old one to generate our final seed. */
+ sha256_process_bytes(&r, sizeof(r), &hash_state);
+ sha256_process_bytes(buffer, r, &hash_state);
+ sha256_finish_ctx(&hash_state, buffer);
+
+ if (lseek(seed_fd, 0, SEEK_SET) < 0)
+ return log_error_errno(errno, "Failed to seek to beginning of EFI seed file: %m");
+ r = loop_write(seed_fd, buffer, sizeof(buffer), false);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write new EFI seed file: %m");
+ if (ftruncate(seed_fd, sizeof(buffer)) < 0)
+ return log_error_errno(errno, "Failed to truncate EFI seed file: %m");
+ r = fsync_full(seed_fd);
+ if (r < 0)
+ return log_error_errno(errno, "Failed to fsync EFI seed file: %m");
+
+ log_debug("Updated random seed in ESP");
+ return 0;
+}
+
static int help(int argc, char *argv[], void *userdata) {
_cleanup_free_ char *link = NULL;
int r;
@@ -402,15 +502,15 @@ static int run(int argc, char *argv[]) {
if (r < 0)
return log_error_errno(r, "Failed to create directory " RANDOM_SEED_DIR ": %m");
+ random_fd = open("/dev/urandom", O_RDWR|O_CLOEXEC|O_NOCTTY);
+ if (random_fd < 0)
+ return log_error_errno(errno, "Failed to open /dev/urandom: %m");
+
/* When we load the seed we read it and write it to the device and then immediately update the saved
* seed with new data, to make sure the next boot gets seeded differently. */
switch (arg_action) {
case ACTION_LOAD:
- random_fd = open("/dev/urandom", O_RDWR|O_CLOEXEC|O_NOCTTY);
- if (random_fd < 0)
- return log_error_errno(errno, "Failed to open /dev/urandom: %m");
-
/* First, let's write the machine ID into /dev/urandom, not crediting entropy. See
* load_machine_id() for an explanation why. */
load_machine_id(random_fd);
@@ -428,8 +528,10 @@ static int run(int argc, char *argv[]) {
log_full_errno(level, open_rw_error, "Failed to open " RANDOM_SEED " for writing: %m");
log_full_errno(level, errno, "Failed to open " RANDOM_SEED " for reading: %m");
+ r = -errno;
- return missing ? 0 : -errno;
+ (void) refresh_boot_seed();
+ return missing ? 0 : r;
}
} else
write_seed_file = true;
@@ -439,10 +541,7 @@ static int run(int argc, char *argv[]) {
break;
case ACTION_SAVE:
- random_fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
- if (random_fd < 0)
- return log_error_errno(errno, "Failed to open /dev/urandom: %m");
-
+ (void) refresh_boot_seed();
seed_fd = open(RANDOM_SEED, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600);
if (seed_fd < 0)
return log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m");
@@ -460,9 +559,11 @@ static int run(int argc, char *argv[]) {
if (r < 0)
return r;
- if (read_seed_file)
+ if (read_seed_file) {
r = load_seed_file(seed_fd, random_fd, seed_size,
write_seed_file ? &hash_state : NULL);
+ (void) refresh_boot_seed();
+ }
if (r >= 0 && write_seed_file)
r = save_seed_file(seed_fd, random_fd, seed_size, synchronous, hash_state);

View File

@ -0,0 +1,181 @@
From 4c15a3931701cca73d78bb09953e439e7125e020 Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Wed, 16 Nov 2022 19:27:50 +0100
Subject: [PATCH] random-seed: handle post-merge review nits
These are various misc things that came up after merging.
(cherry picked from commit 3daeef088410cdddef622007f95b0a1b4a439532)
Related: RHEL-16952
---
src/boot/bootctl.c | 2 +-
src/boot/efi/random-seed.c | 6 ++--
src/random-seed/random-seed.c | 61 ++++++++++++++++++-----------------
3 files changed, 36 insertions(+), 33 deletions(-)
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index e23a72fd38..8d45e11c2b 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -1983,7 +1983,7 @@ static int verb_list(int argc, char *argv[], void *userdata) {
static int install_random_seed(const char *esp) {
_cleanup_(unlink_and_freep) char *tmp = NULL;
- unsigned char buffer[RANDOM_EFI_SEED_SIZE];
+ uint8_t buffer[RANDOM_EFI_SEED_SIZE];
_cleanup_free_ char *path = NULL;
_cleanup_close_ int fd = -1;
size_t token_size;
diff --git a/src/boot/efi/random-seed.c b/src/boot/efi/random-seed.c
index c723160c0f..e11e345e88 100644
--- a/src/boot/efi/random-seed.c
+++ b/src/boot/efi/random-seed.c
@@ -60,7 +60,6 @@ static EFI_STATUS acquire_system_token(void **ret, UINTN *ret_size) {
assert(ret);
assert(ret_size);
- *ret_size = 0;
err = efivar_get_raw(LOADER_GUID, L"LoaderSystemToken", &data, &size);
if (err != EFI_SUCCESS) {
if (err != EFI_NOT_FOUND)
@@ -192,6 +191,7 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir) {
/* Get some system specific seed that the installer might have placed in an EFI variable. We include
* it in our hash. This is protection against golden master image sloppiness, and it remains on the
* system, even when disk images are duplicated or swapped out. */
+ size = 0;
err = acquire_system_token(&system_token, &size);
if (mode != RANDOM_SEED_ALWAYS && (err != EFI_SUCCESS || size < DESIRED_SEED_SIZE) && !seeded_by_efi)
return err;
@@ -251,6 +251,7 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir) {
size = sizeof(uefi_monotonic_counter);
sha256_process_bytes(&size, sizeof(size), &hash);
sha256_process_bytes(&uefi_monotonic_counter, size, &hash);
+
err = RT->GetTime(&now, NULL);
size = err == EFI_SUCCESS ? sizeof(now) : 0; /* Known to be flaky, so don't bark on error. */
sha256_process_bytes(&size, sizeof(size), &hash);
@@ -300,7 +301,8 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir) {
if (err != EFI_SUCCESS)
return log_error_status_stall(err, L"Failed to flush random seed file: %r", err);
- err = BS->AllocatePool(EfiACPIReclaimMemory, sizeof(*new_seed_table) + DESIRED_SEED_SIZE,
+ err = BS->AllocatePool(EfiACPIReclaimMemory,
+ offsetof(struct linux_efi_random_seed, seed) + DESIRED_SEED_SIZE,
(void **) &new_seed_table);
if (err != EFI_SUCCESS)
return log_error_status_stall(err, L"Failed to allocate EFI table for random seed: %r", err);
diff --git a/src/random-seed/random-seed.c b/src/random-seed/random-seed.c
index 54ec3aa7d5..ab1f942289 100644
--- a/src/random-seed/random-seed.c
+++ b/src/random-seed/random-seed.c
@@ -321,9 +321,10 @@ static int refresh_boot_seed(void) {
struct sha256_ctx hash_state;
_cleanup_free_ void *seed_file_bytes = NULL;
_cleanup_free_ char *esp_path = NULL;
- _cleanup_close_ int seed_fd = -1;
+ _cleanup_close_ int seed_fd = -1, dir_fd = -1;
size_t len;
- ssize_t r;
+ ssize_t n;
+ int r;
assert_cc(RANDOM_EFI_SEED_SIZE == SHA256_DIGEST_SIZE);
@@ -337,48 +338,48 @@ static int refresh_boot_seed(void) {
return r; /* find_esp_and_warn() already logged */
}
- seed_fd = chase_symlinks_and_open("/loader/random-seed", esp_path,
- CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS,
- O_RDWR|O_CLOEXEC|O_NOCTTY, NULL);
- if (seed_fd == -ENOENT) {
+ r = chase_symlinks("/loader", esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, NULL, &dir_fd);
+ if (r < 0) {
+ if (r == -ENOENT) {
+ log_debug_errno(r, "Couldn't find ESP loader directory, so not updating ESP random seed.");
+ return 0;
+ }
+ return log_error_errno(r, "Failed to open ESP loader directory: %m");
+ }
+ seed_fd = openat(dir_fd, "random-seed", O_NOFOLLOW|O_RDWR|O_CLOEXEC|O_NOCTTY);
+ if (seed_fd < 0 && errno == ENOENT) {
uint64_t features;
-
r = efi_loader_get_features(&features);
- if (r == 0 && FLAGS_SET(features, EFI_LOADER_FEATURE_RANDOM_SEED)) {
- int dir_fd = chase_symlinks_and_open("/loader", esp_path,
- CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS,
- O_DIRECTORY|O_CLOEXEC|O_NOCTTY, NULL);
- if (dir_fd >= 0) {
- seed_fd = openat(dir_fd, "random-seed", O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY, 0600);
- close(dir_fd);
- }
+ if (r == 0 && FLAGS_SET(features, EFI_LOADER_FEATURE_RANDOM_SEED))
+ seed_fd = openat(dir_fd, "random-seed", O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY, 0600);
+ else {
+ log_debug_errno(seed_fd, "Couldn't find ESP random seed, and not booted with systemd-boot, so not updating ESP random seed.");
+ return 0;
}
}
- if (seed_fd < 0) {
- log_debug_errno(seed_fd, "Failed to open EFI seed path: %m");
- return 0;
- }
+ if (seed_fd < 0)
+ return log_error_errno(errno, "Failed to open EFI seed path: %m");
r = random_seed_size(seed_fd, &len);
if (r < 0)
return log_error_errno(r, "Failed to determine EFI seed path length: %m");
seed_file_bytes = malloc(len);
if (!seed_file_bytes)
return log_oom();
- r = loop_read(seed_fd, seed_file_bytes, len, false);
- if (r < 0)
- return log_error_errno(r, "Failed to read EFI seed file: %m");
+ n = loop_read(seed_fd, seed_file_bytes, len, false);
+ if (n < 0)
+ return log_error_errno(n, "Failed to read EFI seed file: %m");
/* Hash the old seed in so that we never regress in entropy. */
sha256_init_ctx(&hash_state);
- sha256_process_bytes(&r, sizeof(r), &hash_state);
- sha256_process_bytes(seed_file_bytes, r, &hash_state);
+ sha256_process_bytes(&n, sizeof(n), &hash_state);
+ sha256_process_bytes(seed_file_bytes, n, &hash_state);
/* We're doing this opportunistically, so if the seeding dance before didn't manage to initialize the
* RNG, there's no point in doing it here. Secondly, getrandom(GRND_NONBLOCK) has been around longer
* than EFI seeding anyway, so there's no point in having non-getrandom() fallbacks here. So if this
* fails, just return early to cut our losses. */
- r = getrandom(buffer, sizeof(buffer), GRND_NONBLOCK);
- if (r < 0) {
+ n = getrandom(buffer, sizeof(buffer), GRND_NONBLOCK);
+ if (n < 0) {
if (errno == EAGAIN) {
log_debug_errno(errno, "Random pool not initialized yet, so skipping EFI seed update");
return 0;
@@ -389,11 +390,11 @@ static int refresh_boot_seed(void) {
}
return log_error_errno(errno, "Failed to generate random bytes for EFI seed: %m");
}
- assert(r == sizeof(buffer));
+ assert(n == sizeof(buffer));
/* Hash the new seed into the state containing the old one to generate our final seed. */
- sha256_process_bytes(&r, sizeof(r), &hash_state);
- sha256_process_bytes(buffer, r, &hash_state);
+ sha256_process_bytes(&n, sizeof(n), &hash_state);
+ sha256_process_bytes(buffer, n, &hash_state);
sha256_finish_ctx(&hash_state, buffer);
if (lseek(seed_fd, 0, SEEK_SET) < 0)
@@ -405,7 +406,7 @@ static int refresh_boot_seed(void) {
return log_error_errno(errno, "Failed to truncate EFI seed file: %m");
r = fsync_full(seed_fd);
if (r < 0)
- return log_error_errno(errno, "Failed to fsync EFI seed file: %m");
+ return log_error_errno(r, "Failed to fsync EFI seed file: %m");
log_debug("Updated random seed in ESP");
return 0;

View File

@ -0,0 +1,50 @@
From 2d6ce79b1d727cd85d3504706da9c2eca6dc72fe Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Wed, 16 Nov 2022 19:34:53 +0100
Subject: [PATCH] boot: do not truncate random seed file
There are concerns about the FAT file system driver exploding if we try
to do this, so just leave the bytes zeroed out instead.
(cherry picked from commit 5d29d07b342397a8ecc4bea96f53595a03dd94f1)
Related: RHEL-16952
---
src/boot/efi/random-seed.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/src/boot/efi/random-seed.c b/src/boot/efi/random-seed.c
index e11e345e88..471398fbf1 100644
--- a/src/boot/efi/random-seed.c
+++ b/src/boot/efi/random-seed.c
@@ -268,7 +268,7 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir) {
sha256_finish_ctx(&hash, random_bytes);
size = sizeof(random_bytes);
- /* If the file size is too large, zero out the remaining bytes on disk, and then truncate. */
+ /* If the file size is too large, zero out the remaining bytes on disk. */
if (size < info->FileSize) {
err = handle->SetPosition(handle, size);
if (err != EFI_SUCCESS)
@@ -285,10 +285,17 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir) {
err = handle->SetPosition(handle, 0);
if (err != EFI_SUCCESS)
return log_error_status_stall(err, L"Failed to seek to beginning of random seed file: %r", err);
- info->FileSize = size;
- err = handle->SetInfo(handle, &GenericFileInfo, info->Size, info);
- if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed to truncate random seed file: %r", err);
+
+ /* We could truncate the file here with something like:
+ *
+ * info->FileSize = size;
+ * err = handle->SetInfo(handle, &GenericFileInfo, info->Size, info);
+ * if (err != EFI_SUCCESS)
+ * return log_error_status_stall(err, L"Failed to truncate random seed file: %r", err);
+ *
+ * But this is considered slightly risky, because EFI filesystem drivers are a little bit
+ * flimsy. So instead we rely on userspace eventually truncating this when it writes a new
+ * seed. For now the best we do is zero it. */
}
/* Update the random seed on disk before we use it */
wsize = size;

View File

@ -0,0 +1,117 @@
From 36e71ba28d490bb3dba34df8eef472c1560e3772 Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Thu, 17 Nov 2022 16:11:44 +0100
Subject: [PATCH] bootctl: install system token on virtualized systems
Removing the virtualization check might not be the worst thing in the
world, and would potentially get many, many more systems properly seeded
rather than not seeded. There are a few reasons to consider this:
- In most QEMU setups and most guides on how to setup QEMU, a separate
pflash file is used for nvram variables, and this generally isn't
copied around.
- We're now hashing in a timestamp, which should provide some level of
differentiation, given that EFI_TIME has a nanoseconds field.
- The kernel itself will additionally hash in: a high resolution time
stamp, a cycle counter, RDRAND output, the VMGENID uniquely
identifying the virtual machine, any other seeds from the hypervisor
(like from FDT or setup_data).
- During early boot, the RNG is reseeded quite frequently to account for
the importance of early differentiation.
So maybe the mitigating factors make the actual feared problem
significantly less likely and therefore the pros of having file-based
seeding might outweigh the cons of weird misconfigured setups having a
hypothetical problem on first boot.
(cherry picked from commit a4eea6038c1c7f88adc6d6584d18ea60ea11b08f)
Related: RHEL-16952
---
docs/RANDOM_SEEDS.md | 15 ++++-----------
src/boot/bootctl.c | 20 --------------------
units/systemd-boot-system-token.service | 8 ++------
3 files changed, 6 insertions(+), 37 deletions(-)
diff --git a/docs/RANDOM_SEEDS.md b/docs/RANDOM_SEEDS.md
index b7240f0d89..a1134d6417 100644
--- a/docs/RANDOM_SEEDS.md
+++ b/docs/RANDOM_SEEDS.md
@@ -232,17 +232,10 @@ boot, in order to ensure the entropy pool is filled up quickly.
too), which should be safe even with FAT file system drivers built into
low-quality EFI firmwares.
- As a special restriction: in virtualized environments PID 1 will refrain
- from using this mechanism, for safety reasons. This is because on VM
- environments the EFI variable space and the disk space is generally not
- maintained physically separate (for example, `qemu` in EFI mode stores the
- variables in the ESP itself). The robustness towards sloppy OS image
- generation is the main purpose of maintaining the 'system token' however,
- and if the EFI variable storage is not kept physically separate from the OS
- image there's no point in it. That said, OS builders that know that they are
- not going to replicate the built image on multiple systems may opt to turn
- off the 'system token' concept by setting `random-seed-mode always` in the
- ESP's
+ If the system token is not desired but this seeding mechanism still is, OS
+ builders that know that they are not going to replicate the built image on
+ multiple systems may opt to turn off the 'system token' concept by setting
+ `random-seed-mode always` in the ESP's
[`/loader/loader.conf`](https://www.freedesktop.org/software/systemd/man/loader.conf.html)
file. If done, `systemd-boot` will use the random seed file even if no
system token is found in EFI variables.
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index 8d45e11c2b..d495c72bdd 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -2048,26 +2048,6 @@ static int install_random_seed(const char *esp) {
if (r < 0) {
if (r != -ENXIO)
log_warning_errno(r, "Failed to parse $SYSTEMD_WRITE_SYSTEM_TOKEN, ignoring.");
-
- if (detect_vm() > 0) {
- /* Let's not write a system token if we detect we are running in a VM
- * environment. Why? Our default security model for the random seed uses the system
- * token as a mechanism to ensure we are not vulnerable to golden master sloppiness
- * issues, i.e. that people initialize the random seed file, then copy the image to
- * many systems and end up with the same random seed in each that is assumed to be
- * valid but in reality is the same for all machines. By storing a system token in
- * the EFI variable space we can make sure that even though the random seeds on disk
- * are all the same they will be different on each system under the assumption that
- * the EFI variable space is maintained separate from the random seed storage. That
- * is generally the case on physical systems, as the ESP is stored on persistent
- * storage, and the EFI variables in NVRAM. However in virtualized environments this
- * is generally not true: the EFI variable set is typically stored along with the
- * disk image itself. For example, using the OVMF EFI firmware the EFI variables are
- * stored in a file in the ESP itself. */
-
- log_notice("Not installing system token, since we are running in a virtualized environment.");
- return 0;
- }
} else if (r == 0) {
log_notice("Not writing system token, because $SYSTEMD_WRITE_SYSTEM_TOKEN is set to false.");
return 0;
diff --git a/units/systemd-boot-system-token.service b/units/systemd-boot-system-token.service
index 5a56d7c331..689b902000 100644
--- a/units/systemd-boot-system-token.service
+++ b/units/systemd-boot-system-token.service
@@ -16,15 +16,11 @@ After=local-fs.target systemd-random-seed.service
Conflicts=shutdown.target initrd-switch-root.target
Before=shutdown.target initrd-switch-root.target
-# Don't run this in a VM environment, because there EFI variables are not
-# actually stored in NVRAM, independent of regular storage.
-ConditionVirtualization=no
-
# Only run this if the boot loader can support random seed initialization.
ConditionPathExists=/sys/firmware/efi/efivars/LoaderFeatures-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
-# Only run this if there is no system token defined yet, or …
-ConditionPathExists=|!/sys/firmware/efi/efivars/LoaderSystemToken-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
+# Only run this if there is no system token defined yet
+ConditionPathExists=!/sys/firmware/efi/efivars/LoaderSystemToken-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
[Service]
Type=oneshot

View File

@ -0,0 +1,221 @@
From 44f9f0e2e416b67c2ca46e9e36184f4a0bf1f1b0 Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Mon, 21 Nov 2022 16:40:24 +0100
Subject: [PATCH] boot: remove random-seed-mode
Now that the random seed is used on virtualized systems, there's no
point in having a random-seed-mode toggle switch. Let's just always
require it now, with the existing logic already being there to allow not
having it if EFI itself has an RNG. In other words, the logic for this
can now be automatic.
(cherry picked from commit 47b3e96647e18e8ca219c4792ab769344eea11bb)
Related: RHEL-16952
---
docs/RANDOM_SEEDS.md | 8 --------
man/loader.conf.xml | 19 -------------------
src/boot/efi/boot.c | 26 +-------------------------
src/boot/efi/random-seed.c | 5 +----
src/boot/efi/random-seed.h | 18 +-----------------
src/shared/bootspec.c | 3 +--
src/shared/bootspec.h | 1 -
7 files changed, 4 insertions(+), 76 deletions(-)
diff --git a/docs/RANDOM_SEEDS.md b/docs/RANDOM_SEEDS.md
index a1134d6417..4cb2bb9cfa 100644
--- a/docs/RANDOM_SEEDS.md
+++ b/docs/RANDOM_SEEDS.md
@@ -232,14 +232,6 @@ boot, in order to ensure the entropy pool is filled up quickly.
too), which should be safe even with FAT file system drivers built into
low-quality EFI firmwares.
- If the system token is not desired but this seeding mechanism still is, OS
- builders that know that they are not going to replicate the built image on
- multiple systems may opt to turn off the 'system token' concept by setting
- `random-seed-mode always` in the ESP's
- [`/loader/loader.conf`](https://www.freedesktop.org/software/systemd/man/loader.conf.html)
- file. If done, `systemd-boot` will use the random seed file even if no
- system token is found in EFI variables.
-
4. A kernel command line option `systemd.random_seed=` may be used to pass in a
base64 encoded seed to initialize the kernel's entropy pool from during
early service manager initialization. This option is only safe in testing
diff --git a/man/loader.conf.xml b/man/loader.conf.xml
index 7f173aec61..d937583da9 100644
--- a/man/loader.conf.xml
+++ b/man/loader.conf.xml
@@ -309,25 +309,6 @@ sign-efi-sig-list -c KEK.crt -k KEK.key db db.esl db.auth
encrypted drive to change. If PCR 4 is not measured, this setting can be disabled to speed
up booting into Windows.</para></listitem>
</varlistentry>
-
- <varlistentry>
- <term>random-seed-mode</term>
-
- <listitem><para>Takes one of <literal>off</literal>, <literal>with-system-token</literal> and
- <literal>always</literal>. If <literal>off</literal> no random seed data is read off the ESP, nor
- passed to the OS. If <literal>with-system-token</literal> (the default)
- <command>systemd-boot</command> will read a random seed from the ESP (from the file
- <filename>/loader/random-seed</filename>) only if the <varname>LoaderSystemToken</varname> EFI
- variable is set, and then derive the random seed to pass to the OS from the combination. If
- <literal>always</literal> the boot loader will do so even if <varname>LoaderSystemToken</varname> is
- not set. This mode is useful in environments where protection against OS image reuse is not a
- concern, and the random seed shall be used even with no further setup in place. Use <command>bootctl
- random-seed</command> to initialize both the random seed file in the ESP and the system token EFI
- variable.</para>
-
- <para>See <ulink url="https://systemd.io/RANDOM_SEEDS">Random Seeds</ulink> for further
- information.</para></listitem>
- </varlistentry>
</variablelist>
</refsect1>
diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
index 5944451e6a..4a64c2402d 100644
--- a/src/boot/efi/boot.c
+++ b/src/boot/efi/boot.c
@@ -97,7 +97,6 @@ typedef struct {
bool beep;
int64_t console_mode;
int64_t console_mode_efivar;
- RandomSeedMode random_seed_mode;
} Config;
/* These values have been chosen so that the transitions the user sees could
@@ -529,7 +528,6 @@ static void print_status(Config *config, char16_t *loaded_image_path) {
ps_bool(L" auto-firmware: %s\n", config->auto_firmware);
ps_bool(L" beep: %s\n", config->beep);
ps_bool(L" reboot-for-bitlocker: %s\n", config->reboot_for_bitlocker);
- ps_string(L" random-seed-mode: %s\n", random_seed_modes_table[config->random_seed_mode]);
switch (config->secure_boot_enroll) {
case ENROLL_OFF:
@@ -1273,27 +1271,6 @@ static void config_defaults_load_from_file(Config *config, char *content) {
}
continue;
}
-
- if (streq8(key, "random-seed-mode")) {
- if (streq8(value, "off"))
- config->random_seed_mode = RANDOM_SEED_OFF;
- else if (streq8(value, "with-system-token"))
- config->random_seed_mode = RANDOM_SEED_WITH_SYSTEM_TOKEN;
- else if (streq8(value, "always"))
- config->random_seed_mode = RANDOM_SEED_ALWAYS;
- else {
- bool on;
-
- err = parse_boolean(value, &on);
- if (err != EFI_SUCCESS) {
- log_error_stall(L"Error parsing 'random-seed-mode' config option: %a", value);
- continue;
- }
-
- config->random_seed_mode = on ? RANDOM_SEED_ALWAYS : RANDOM_SEED_OFF;
- }
- continue;
- }
}
}
@@ -1584,7 +1561,6 @@ static void config_load_defaults(Config *config, EFI_FILE *root_dir) {
.auto_firmware = true,
.reboot_for_bitlocker = false,
.secure_boot_enroll = ENROLL_MANUAL,
- .random_seed_mode = RANDOM_SEED_WITH_SYSTEM_TOKEN,
.idx_default_efivar = IDX_INVALID,
.console_mode = CONSOLE_MODE_KEEP,
.console_mode_efivar = CONSOLE_MODE_KEEP,
@@ -2735,7 +2711,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
save_selected_entry(&config, entry);
/* Optionally, read a random seed off the ESP and pass it to the OS */
- (void) process_random_seed(root_dir, config.random_seed_mode);
+ (void) process_random_seed(root_dir);
err = image_start(image, entry);
if (err != EFI_SUCCESS)
diff --git a/src/boot/efi/random-seed.c b/src/boot/efi/random-seed.c
index 471398fbf1..4fc56d9356 100644
--- a/src/boot/efi/random-seed.c
+++ b/src/boot/efi/random-seed.c
@@ -140,9 +140,6 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir) {
validate_sha256();
- if (mode == RANDOM_SEED_OFF)
- return EFI_NOT_FOUND;
-
/* hash = LABEL || sizeof(input1) || input1 || ... || sizeof(inputN) || inputN */
sha256_init_ctx(&hash);
@@ -193,7 +190,7 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir) {
* system, even when disk images are duplicated or swapped out. */
size = 0;
err = acquire_system_token(&system_token, &size);
- if (mode != RANDOM_SEED_ALWAYS && (err != EFI_SUCCESS || size < DESIRED_SEED_SIZE) && !seeded_by_efi)
+ if ((err != EFI_SUCCESS || size < DESIRED_SEED_SIZE) && !seeded_by_efi)
return err;
sha256_process_bytes(&size, sizeof(size), &hash);
if (system_token) {
diff --git a/src/boot/efi/random-seed.h b/src/boot/efi/random-seed.h
index 6aa1cc5288..40aaf85860 100644
--- a/src/boot/efi/random-seed.h
+++ b/src/boot/efi/random-seed.h
@@ -2,21 +2,5 @@
#pragma once
#include <efi.h>
-#include <errno.h>
-#include <uchar.h>
-typedef enum RandomSeedMode {
- RANDOM_SEED_OFF,
- RANDOM_SEED_WITH_SYSTEM_TOKEN,
- RANDOM_SEED_ALWAYS,
- _RANDOM_SEED_MODE_MAX,
- _RANDOM_SEED_MODE_INVALID = -EINVAL,
-} RandomSeedMode;
-
-static const char16_t * const random_seed_modes_table[_RANDOM_SEED_MODE_MAX] = {
- [RANDOM_SEED_OFF] = L"off",
- [RANDOM_SEED_WITH_SYSTEM_TOKEN] = L"with-system-token",
- [RANDOM_SEED_ALWAYS] = L"always",
-};
-
-EFI_STATUS process_random_seed(EFI_FILE *root_dir, RandomSeedMode mode);
+EFI_STATUS process_random_seed(EFI_FILE *root_dir);
diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c
index 9352416af5..61e20c40a8 100644
--- a/src/shared/bootspec.c
+++ b/src/shared/bootspec.c
@@ -418,7 +418,6 @@ void boot_config_free(BootConfig *config) {
free(config->auto_entries);
free(config->auto_firmware);
free(config->console_mode);
- free(config->random_seed_mode);
free(config->beep);
free(config->entry_oneshot);
@@ -485,7 +484,7 @@ int boot_loader_read_conf(BootConfig *config, FILE *file, const char *path) {
else if (streq(field, "console-mode"))
r = free_and_strdup(&config->console_mode, p);
else if (streq(field, "random-seed-mode"))
- r = free_and_strdup(&config->random_seed_mode, p);
+ log_syntax(NULL, LOG_WARNING, path, line, 0, "'random-seed-mode' has been deprecated, ignoring.");
else if (streq(field, "beep"))
r = free_and_strdup(&config->beep, p);
else {
diff --git a/src/shared/bootspec.h b/src/shared/bootspec.h
index 7f5d496b95..ac4d1890b0 100644
--- a/src/shared/bootspec.h
+++ b/src/shared/bootspec.h
@@ -57,7 +57,6 @@ typedef struct BootConfig {
char *auto_entries;
char *auto_firmware;
char *console_mode;
- char *random_seed_mode;
char *beep;
char *entry_oneshot;

View File

@ -0,0 +1,302 @@
From 41f56ba9788c24ef66a5ca99ee1a92af697670ec Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Fri, 18 Nov 2022 02:49:16 +0100
Subject: [PATCH] stub: handle random seed like sd-boot does
sd-stub has an opportunity to handle the seed the same way sd-boot does,
which would have benefits for UKIs when sd-boot is not in use. This
commit wires that up.
It refactors the XBOOTLDR partition discovery to also find the ESP
partition, so that it access the random seed there.
(cherry picked from commit 0a1d8ac77a21ae0741bdf4af08f3a71354805ff1)
Related: RHEL-16952
---
src/boot/bootctl.c | 1 +
src/boot/efi/boot.c | 4 ++--
src/boot/efi/meson.build | 8 ++++----
src/boot/efi/{xbootldr.c => part-discovery.c} | 20 ++++++++++---------
src/boot/efi/part-discovery.h | 11 ++++++++++
src/boot/efi/stub.c | 13 ++++++++++++
src/boot/efi/xbootldr.h | 9 ---------
src/fundamental/efivars-fundamental.h | 1 +
units/systemd-boot-system-token.service | 3 ++-
9 files changed, 45 insertions(+), 25 deletions(-)
rename src/boot/efi/{xbootldr.c => part-discovery.c} (94%)
create mode 100644 src/boot/efi/part-discovery.h
delete mode 100644 src/boot/efi/xbootldr.h
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index d495c72bdd..c994be272b 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -1812,6 +1812,7 @@ static int verb_status(int argc, char *argv[], void *userdata) {
{ EFI_STUB_FEATURE_PICK_UP_CREDENTIALS, "Picks up credentials from boot partition" },
{ EFI_STUB_FEATURE_PICK_UP_SYSEXTS, "Picks up system extension images from boot partition" },
{ EFI_STUB_FEATURE_THREE_PCRS, "Measures kernel+command line+sysexts" },
+ { EFI_STUB_FEATURE_RANDOM_SEED, "Support for passing random seed to OS" },
};
_cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL;
sd_id128_t loader_part_uuid = SD_ID128_NULL;
diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
index 4a64c2402d..2e657a8bf9 100644
--- a/src/boot/efi/boot.c
+++ b/src/boot/efi/boot.c
@@ -15,6 +15,7 @@
#include "initrd.h"
#include "linux.h"
#include "measure.h"
+#include "part-discovery.h"
#include "pe.h"
#include "vmm.h"
#include "random-seed.h"
@@ -22,7 +23,6 @@
#include "shim.h"
#include "ticks.h"
#include "util.h"
-#include "xbootldr.h"
#ifndef GNU_EFI_USE_MS_ABI
/* We do not use uefi_call_wrapper() in systemd-boot. As such, we rely on the
@@ -2239,7 +2239,7 @@ static void config_load_xbootldr(
assert(config);
assert(device);
- err = xbootldr_open(device, &new_device, &root_dir);
+ err = partition_open(XBOOTLDR_GUID, device, &new_device, &root_dir);
if (err != EFI_SUCCESS)
return;
diff --git a/src/boot/efi/meson.build b/src/boot/efi/meson.build
index 00f3361d66..8e96a33119 100644
--- a/src/boot/efi/meson.build
+++ b/src/boot/efi/meson.build
@@ -361,6 +361,7 @@ efi_headers = files(
'linux.h',
'measure.h',
'missing_efi.h',
+ 'part-discovery.h',
'pe.h',
'random-seed.h',
'secure-boot.h',
@@ -368,7 +369,6 @@ efi_headers = files(
'splash.h',
'ticks.h',
'util.h',
- 'xbootldr.h',
)
common_sources = files(
@@ -380,7 +380,9 @@ common_sources = files(
'graphics.c',
'initrd.c',
'measure.c',
+ 'part-discovery.c',
'pe.c',
+ 'random-seed.c',
'secure-boot.c',
'ticks.c',
'util.c',
@@ -389,10 +391,8 @@ common_sources = files(
systemd_boot_sources = files(
'boot.c',
'drivers.c',
- 'random-seed.c',
- 'vmm.c',
'shim.c',
- 'xbootldr.c',
+ 'vmm.c',
)
stub_sources = files(
diff --git a/src/boot/efi/xbootldr.c b/src/boot/efi/part-discovery.c
similarity index 94%
rename from src/boot/efi/xbootldr.c
rename to src/boot/efi/part-discovery.c
index 7fef909312..14479c06ea 100644
--- a/src/boot/efi/xbootldr.c
+++ b/src/boot/efi/part-discovery.c
@@ -4,8 +4,8 @@
#include <efigpt.h>
#include <efilib.h>
+#include "part-discovery.h"
#include "util.h"
-#include "xbootldr.h"
union GptHeaderBuffer {
EFI_PARTITION_TABLE_HEADER gpt_header;
@@ -81,6 +81,7 @@ static bool verify_gpt(union GptHeaderBuffer *gpt_header_buffer, EFI_LBA lba_exp
}
static EFI_STATUS try_gpt(
+ const EFI_GUID *type,
EFI_BLOCK_IO_PROTOCOL *block_io,
EFI_LBA lba,
EFI_LBA *ret_backup_lba, /* May be changed even on error! */
@@ -133,7 +134,7 @@ static EFI_STATUS try_gpt(
EFI_PARTITION_ENTRY *entry =
(EFI_PARTITION_ENTRY *) ((uint8_t *) entries + gpt.gpt_header.SizeOfPartitionEntry * i);
- if (memcmp(&entry->PartitionTypeGUID, XBOOTLDR_GUID, sizeof(entry->PartitionTypeGUID)) != 0)
+ if (memcmp(&entry->PartitionTypeGUID, type, sizeof(entry->PartitionTypeGUID)) != 0)
continue;
if (entry->EndingLBA < entry->StartingLBA) /* Bogus? */
@@ -165,7 +166,7 @@ static EFI_STATUS try_gpt(
return EFI_NOT_FOUND;
}
-static EFI_STATUS find_device(EFI_HANDLE *device, EFI_DEVICE_PATH **ret_device_path) {
+static EFI_STATUS find_device(const EFI_GUID *type, EFI_HANDLE *device, EFI_DEVICE_PATH **ret_device_path) {
EFI_STATUS err;
assert(device);
@@ -235,8 +236,7 @@ static EFI_STATUS find_device(EFI_HANDLE *device, EFI_DEVICE_PATH **ret_device_p
continue;
HARDDRIVE_DEVICE_PATH hd;
- err = try_gpt(
- block_io, lba,
+ err = try_gpt(type, block_io, lba,
nr == 0 ? &backup_lba : NULL, /* Only get backup LBA location from first GPT header. */
&hd);
if (err != EFI_SUCCESS) {
@@ -256,17 +256,18 @@ static EFI_STATUS find_device(EFI_HANDLE *device, EFI_DEVICE_PATH **ret_device_p
return EFI_NOT_FOUND;
}
-EFI_STATUS xbootldr_open(EFI_HANDLE *device, EFI_HANDLE *ret_device, EFI_FILE **ret_root_dir) {
+EFI_STATUS partition_open(const EFI_GUID *type, EFI_HANDLE *device, EFI_HANDLE *ret_device,
+ EFI_FILE **ret_root_dir) {
_cleanup_free_ EFI_DEVICE_PATH *partition_path = NULL;
EFI_HANDLE new_device;
EFI_FILE *root_dir;
EFI_STATUS err;
+ assert(type);
assert(device);
- assert(ret_device);
assert(ret_root_dir);
- err = find_device(device, &partition_path);
+ err = find_device(type, device, &partition_path);
if (err != EFI_SUCCESS)
return err;
@@ -279,7 +280,8 @@ EFI_STATUS xbootldr_open(EFI_HANDLE *device, EFI_HANDLE *ret_device, EFI_FILE **
if (err != EFI_SUCCESS)
return err;
- *ret_device = new_device;
+ if (ret_device)
+ *ret_device = new_device;
*ret_root_dir = root_dir;
return EFI_SUCCESS;
}
diff --git a/src/boot/efi/part-discovery.h b/src/boot/efi/part-discovery.h
new file mode 100644
index 0000000000..5cc17f6b3b
--- /dev/null
+++ b/src/boot/efi/part-discovery.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <efi.h>
+
+#define XBOOTLDR_GUID \
+ &(const EFI_GUID) { 0xbc13c2ff, 0x59e6, 0x4262, { 0xa3, 0x52, 0xb2, 0x75, 0xfd, 0x6f, 0x71, 0x72 } }
+#define ESP_GUID \
+ &(const EFI_GUID) { 0xc12a7328, 0xf81f, 0x11d2, { 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b } }
+
+EFI_STATUS partition_open(const EFI_GUID *type, EFI_HANDLE *device, EFI_HANDLE *ret_device, EFI_FILE **ret_root_dir);
diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c
index 7c42a16c70..023f8ae255 100644
--- a/src/boot/efi/stub.c
+++ b/src/boot/efi/stub.c
@@ -9,7 +9,9 @@
#include "graphics.h"
#include "linux.h"
#include "measure.h"
+#include "part-discovery.h"
#include "pe.h"
+#include "random-seed.h"
#include "secure-boot.h"
#include "splash.h"
#include "tpm-pcr.h"
@@ -84,6 +86,7 @@ static void export_variables(EFI_LOADED_IMAGE_PROTOCOL *loaded_image) {
EFI_STUB_FEATURE_PICK_UP_CREDENTIALS | /* We pick up credentials from the boot partition */
EFI_STUB_FEATURE_PICK_UP_SYSEXTS | /* We pick up system extensions from the boot partition */
EFI_STUB_FEATURE_THREE_PCRS | /* We can measure kernel image, parameters and sysext */
+ EFI_STUB_FEATURE_RANDOM_SEED | /* We pass a random seed to the kernel */
0;
char16_t uuid[37];
@@ -188,6 +191,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
_cleanup_free_ char16_t *cmdline = NULL;
int sections_measured = -1, parameters_measured = -1;
bool sysext_measured = false, m;
+ uint64_t loader_features = 0;
EFI_STATUS err;
InitializeLib(image, sys_table);
@@ -205,6 +209,15 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
if (err != EFI_SUCCESS)
return log_error_status_stall(err, L"Error getting a LoadedImageProtocol handle: %r", err);
+ if (efivar_get_uint64_le(LOADER_GUID, L"LoaderFeatures", &loader_features) != EFI_SUCCESS ||
+ !FLAGS_SET(loader_features, EFI_LOADER_FEATURE_RANDOM_SEED)) {
+ _cleanup_(file_closep) EFI_FILE *esp_dir = NULL;
+
+ err = partition_open(ESP_GUID, loaded_image->DeviceHandle, NULL, &esp_dir);
+ if (err == EFI_SUCCESS) /* Non-fatal on failure, so that we still boot without it. */
+ (void) process_random_seed(esp_dir);
+ }
+
err = pe_memory_locate_sections(loaded_image->ImageBase, unified_sections, addrs, szs);
if (err != EFI_SUCCESS || szs[UNIFIED_SECTION_LINUX] == 0) {
if (err == EFI_SUCCESS)
diff --git a/src/boot/efi/xbootldr.h b/src/boot/efi/xbootldr.h
deleted file mode 100644
index 205ce71edf..0000000000
--- a/src/boot/efi/xbootldr.h
+++ /dev/null
@@ -1,9 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <efi.h>
-
-#define XBOOTLDR_GUID \
- &(const EFI_GUID) { 0xbc13c2ff, 0x59e6, 0x4262, { 0xa3, 0x52, 0xb2, 0x75, 0xfd, 0x6f, 0x71, 0x72 } }
-
-EFI_STATUS xbootldr_open(EFI_HANDLE *device, EFI_HANDLE *ret_device, EFI_FILE **ret_root_dir);
diff --git a/src/fundamental/efivars-fundamental.h b/src/fundamental/efivars-fundamental.h
index fe34e6c714..cf785f8b7d 100644
--- a/src/fundamental/efivars-fundamental.h
+++ b/src/fundamental/efivars-fundamental.h
@@ -22,6 +22,7 @@
#define EFI_STUB_FEATURE_PICK_UP_CREDENTIALS (UINT64_C(1) << 1)
#define EFI_STUB_FEATURE_PICK_UP_SYSEXTS (UINT64_C(1) << 2)
#define EFI_STUB_FEATURE_THREE_PCRS (UINT64_C(1) << 3)
+#define EFI_STUB_FEATURE_RANDOM_SEED (UINT64_C(1) << 4)
typedef enum SecureBootMode {
SECURE_BOOT_UNSUPPORTED,
diff --git a/units/systemd-boot-system-token.service b/units/systemd-boot-system-token.service
index 689b902000..63e523bb3e 100644
--- a/units/systemd-boot-system-token.service
+++ b/units/systemd-boot-system-token.service
@@ -17,7 +17,8 @@ Conflicts=shutdown.target initrd-switch-root.target
Before=shutdown.target initrd-switch-root.target
# Only run this if the boot loader can support random seed initialization.
-ConditionPathExists=/sys/firmware/efi/efivars/LoaderFeatures-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
+ConditionPathExists|=/sys/firmware/efi/efivars/LoaderFeatures-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
+ConditionPathExists|=/sys/firmware/efi/efivars/StubFeatures-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
# Only run this if there is no system token defined yet
ConditionPathExists=!/sys/firmware/efi/efivars/LoaderSystemToken-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f

View File

@ -0,0 +1,90 @@
From a30f647ef87e352502dde5ca67ad99927611108a Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Fri, 11 Nov 2022 16:05:03 +0100
Subject: [PATCH] efi: add efi_guid_equal() helper
(cherry picked from commit 50b0b0d351e892d57a562a28dd8362b1e8cd76a9)
Related: RHEL-16952
---
src/boot/efi/devicetree.c | 2 +-
src/boot/efi/part-discovery.c | 2 +-
src/boot/efi/random-seed.c | 3 +--
src/boot/efi/util.h | 4 ++++
src/boot/efi/vmm.c | 4 ++--
5 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/src/boot/efi/devicetree.c b/src/boot/efi/devicetree.c
index 0312670613..daba5582aa 100644
--- a/src/boot/efi/devicetree.c
+++ b/src/boot/efi/devicetree.c
@@ -10,7 +10,7 @@
static void *get_dtb_table(void) {
for (UINTN i = 0; i < ST->NumberOfTableEntries; i++)
- if (memcmp(&EfiDtbTableGuid, &ST->ConfigurationTable[i].VendorGuid, sizeof(EfiDtbTableGuid)) == 0)
+ if (efi_guid_equal(&ST->ConfigurationTable[i].VendorGuid, &EfiDtbTableGuid))
return ST->ConfigurationTable[i].VendorTable;
return NULL;
}
diff --git a/src/boot/efi/part-discovery.c b/src/boot/efi/part-discovery.c
index 14479c06ea..2659a5b6b4 100644
--- a/src/boot/efi/part-discovery.c
+++ b/src/boot/efi/part-discovery.c
@@ -134,7 +134,7 @@ static EFI_STATUS try_gpt(
EFI_PARTITION_ENTRY *entry =
(EFI_PARTITION_ENTRY *) ((uint8_t *) entries + gpt.gpt_header.SizeOfPartitionEntry * i);
- if (memcmp(&entry->PartitionTypeGUID, type, sizeof(entry->PartitionTypeGUID)) != 0)
+ if (!efi_guid_equal(&entry->PartitionTypeGUID, type))
continue;
if (entry->EndingLBA < entry->StartingLBA) /* Bogus? */
diff --git a/src/boot/efi/random-seed.c b/src/boot/efi/random-seed.c
index 4fc56d9356..6070145778 100644
--- a/src/boot/efi/random-seed.c
+++ b/src/boot/efi/random-seed.c
@@ -147,8 +147,7 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir) {
sha256_process_bytes(HASH_LABEL, sizeof(HASH_LABEL) - 1, &hash);
for (size_t i = 0; i < ST->NumberOfTableEntries; ++i)
- if (memcmp(&(const EFI_GUID)LINUX_EFI_RANDOM_SEED_TABLE_GUID,
- &ST->ConfigurationTable[i].VendorGuid, sizeof(EFI_GUID)) == 0) {
+ if (efi_guid_equal(&ST->ConfigurationTable[i].VendorGuid, &(const EFI_GUID) LINUX_EFI_RANDOM_SEED_TABLE_GUID)) {
previous_seed_table = ST->ConfigurationTable[i].VendorTable;
break;
}
diff --git a/src/boot/efi/util.h b/src/boot/efi/util.h
index f58d24fce1..a076f48dba 100644
--- a/src/boot/efi/util.h
+++ b/src/boot/efi/util.h
@@ -217,3 +217,7 @@ static inline bool in_hypervisor(void) {
return false;
}
#endif
+
+static inline bool efi_guid_equal(const EFI_GUID *a, const EFI_GUID *b) {
+ return memcmp(a, b, sizeof(EFI_GUID)) == 0;
+}
diff --git a/src/boot/efi/vmm.c b/src/boot/efi/vmm.c
index 2260b217b7..10d4a75ab2 100644
--- a/src/boot/efi/vmm.c
+++ b/src/boot/efi/vmm.c
@@ -18,7 +18,7 @@
/* detect direct boot */
bool is_direct_boot(EFI_HANDLE device) {
EFI_STATUS err;
- VENDOR_DEVICE_PATH *dp;
+ VENDOR_DEVICE_PATH *dp; /* NB: Alignment of this structure might be quirky! */
err = BS->HandleProtocol(device, &DevicePathProtocol, (void **) &dp);
if (err != EFI_SUCCESS)
@@ -27,7 +27,7 @@ bool is_direct_boot(EFI_HANDLE device) {
/* 'qemu -kernel systemd-bootx64.efi' */
if (dp->Header.Type == MEDIA_DEVICE_PATH &&
dp->Header.SubType == MEDIA_VENDOR_DP &&
- memcmp(&dp->Guid, &(EFI_GUID)QEMU_KERNEL_LOADER_FS_MEDIA_GUID, sizeof(EFI_GUID)) == 0)
+ memcmp(&dp->Guid, &(EFI_GUID)QEMU_KERNEL_LOADER_FS_MEDIA_GUID, sizeof(EFI_GUID)) == 0) /* Don't change to efi_guid_equal() because EFI device path objects are not necessarily aligned! */
return true;
/* loaded from firmware volume (sd-boot added to ovmf) */

View File

@ -0,0 +1,95 @@
From bbf8235eb297047521ac83b594389d70ecfb38df Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 14 Dec 2022 18:48:52 +0100
Subject: [PATCH] efi: add common implementation for loop finding EFI
configuration tables
(cherry picked from commit a04709c1ac81b28b1a4144166991ac56be94cfcd)
Related: RHEL-16952
---
src/boot/efi/devicetree.c | 11 ++---------
src/boot/efi/random-seed.c | 6 +-----
src/boot/efi/util.c | 8 ++++++++
src/boot/efi/util.h | 2 ++
4 files changed, 13 insertions(+), 14 deletions(-)
diff --git a/src/boot/efi/devicetree.c b/src/boot/efi/devicetree.c
index daba5582aa..12015fce6b 100644
--- a/src/boot/efi/devicetree.c
+++ b/src/boot/efi/devicetree.c
@@ -8,13 +8,6 @@
#define FDT_V1_SIZE (7*4)
-static void *get_dtb_table(void) {
- for (UINTN i = 0; i < ST->NumberOfTableEntries; i++)
- if (efi_guid_equal(&ST->ConfigurationTable[i].VendorGuid, &EfiDtbTableGuid))
- return ST->ConfigurationTable[i].VendorTable;
- return NULL;
-}
-
static EFI_STATUS devicetree_allocate(struct devicetree_state *state, UINTN size) {
UINTN pages = DIV_ROUND_UP(size, EFI_PAGE_SIZE);
EFI_STATUS err;
@@ -81,7 +74,7 @@ EFI_STATUS devicetree_install(struct devicetree_state *state, EFI_FILE *root_dir
assert(root_dir);
assert(name);
- state->orig = get_dtb_table();
+ state->orig = find_configuration_table(&EfiDtbTableGuid);
if (!state->orig)
return EFI_UNSUPPORTED;
@@ -121,7 +114,7 @@ EFI_STATUS devicetree_install_from_memory(struct devicetree_state *state,
assert(state);
assert(dtb_buffer && dtb_length > 0);
- state->orig = get_dtb_table();
+ state->orig = find_configuration_table(&EfiDtbTableGuid);
if (!state->orig)
return EFI_UNSUPPORTED;
diff --git a/src/boot/efi/random-seed.c b/src/boot/efi/random-seed.c
index 6070145778..332f537d91 100644
--- a/src/boot/efi/random-seed.c
+++ b/src/boot/efi/random-seed.c
@@ -146,11 +146,7 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir) {
/* Some basic domain separation in case somebody uses this data elsewhere */
sha256_process_bytes(HASH_LABEL, sizeof(HASH_LABEL) - 1, &hash);
- for (size_t i = 0; i < ST->NumberOfTableEntries; ++i)
- if (efi_guid_equal(&ST->ConfigurationTable[i].VendorGuid, &(const EFI_GUID) LINUX_EFI_RANDOM_SEED_TABLE_GUID)) {
- previous_seed_table = ST->ConfigurationTable[i].VendorTable;
- break;
- }
+ previous_seed_table = find_configuration_table(&(const EFI_GUID) LINUX_EFI_RANDOM_SEED_TABLE_GUID);
if (!previous_seed_table) {
size = 0;
sha256_process_bytes(&size, sizeof(size), &hash);
diff --git a/src/boot/efi/util.c b/src/boot/efi/util.c
index 1f07fbc38c..0a6bb59dce 100644
--- a/src/boot/efi/util.c
+++ b/src/boot/efi/util.c
@@ -747,3 +747,11 @@ bool in_hypervisor(void) {
return !!(ecx & 0x80000000U);
}
#endif
+
+void *find_configuration_table(const EFI_GUID *guid) {
+ for (UINTN i = 0; i < ST->NumberOfTableEntries; i++)
+ if (efi_guid_equal(&ST->ConfigurationTable[i].VendorGuid, guid))
+ return ST->ConfigurationTable[i].VendorTable;
+
+ return NULL;
+}
diff --git a/src/boot/efi/util.h b/src/boot/efi/util.h
index a076f48dba..88fc60c17e 100644
--- a/src/boot/efi/util.h
+++ b/src/boot/efi/util.h
@@ -221,3 +221,5 @@ static inline bool in_hypervisor(void) {
static inline bool efi_guid_equal(const EFI_GUID *a, const EFI_GUID *b) {
return memcmp(a, b, sizeof(EFI_GUID)) == 0;
}
+
+void *find_configuration_table(const EFI_GUID *guid);

View File

@ -0,0 +1,310 @@
From 4fad2ae3115ee9cedc61fffaf920fbd08fabc267 Mon Sep 17 00:00:00 2001
From: Jan Janssen <medhefgo@web.de>
Date: Tue, 10 Jan 2023 14:44:29 +0100
Subject: [PATCH] boot: Detect hypervisors using SMBIOS info
This allows skipping secure boot enrollment wait time on other arches.
(cherry picked from commit ba2793927461b82216f56aa8a800cf53fac28d37)
Related: RHEL-16952
---
src/boot/efi/meson.build | 4 +-
src/boot/efi/secure-boot.c | 3 +-
src/boot/efi/ticks.c | 1 +
src/boot/efi/util.c | 17 ----
src/boot/efi/util.h | 8 --
src/boot/efi/vmm.c | 156 +++++++++++++++++++++++++++++++++++++
src/boot/efi/vmm.h | 2 +
7 files changed, 163 insertions(+), 28 deletions(-)
diff --git a/src/boot/efi/meson.build b/src/boot/efi/meson.build
index 8e96a33119..ab2d7595f3 100644
--- a/src/boot/efi/meson.build
+++ b/src/boot/efi/meson.build
@@ -375,6 +375,7 @@ common_sources = files(
'assert.c',
'console.c',
'devicetree.c',
+ 'drivers.c',
'disk.c',
'efi-string.c',
'graphics.c',
@@ -386,13 +387,12 @@ common_sources = files(
'secure-boot.c',
'ticks.c',
'util.c',
+ 'vmm.c',
)
systemd_boot_sources = files(
'boot.c',
- 'drivers.c',
'shim.c',
- 'vmm.c',
)
stub_sources = files(
diff --git a/src/boot/efi/secure-boot.c b/src/boot/efi/secure-boot.c
index 6212868134..55c9ba5d4c 100644
--- a/src/boot/efi/secure-boot.c
+++ b/src/boot/efi/secure-boot.c
@@ -1,9 +1,10 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#include "console.h"
#include "sbat.h"
#include "secure-boot.h"
-#include "console.h"
#include "util.h"
+#include "vmm.h"
bool secure_boot_enabled(void) {
bool secure = false; /* avoid false maybe-uninitialized warning */
diff --git a/src/boot/efi/ticks.c b/src/boot/efi/ticks.c
index 1b74ba15d0..2f6ff878ca 100644
--- a/src/boot/efi/ticks.c
+++ b/src/boot/efi/ticks.c
@@ -5,6 +5,7 @@
#include "ticks.h"
#include "util.h"
+#include "vmm.h"
#ifdef __x86_64__
static uint64_t ticks_read(void) {
diff --git a/src/boot/efi/util.c b/src/boot/efi/util.c
index 0a6bb59dce..dfe2fe791d 100644
--- a/src/boot/efi/util.c
+++ b/src/boot/efi/util.c
@@ -2,9 +2,6 @@
#include <efi.h>
#include <efilib.h>
-#if defined(__i386__) || defined(__x86_64__)
-# include <cpuid.h>
-#endif
#include "ticks.h"
#include "util.h"
@@ -734,20 +731,6 @@ EFI_STATUS device_path_to_str(const EFI_DEVICE_PATH *dp, char16_t **ret) {
return EFI_SUCCESS;
}
-#if defined(__i386__) || defined(__x86_64__)
-bool in_hypervisor(void) {
- uint32_t eax, ebx, ecx, edx;
-
- /* This is a dumbed down version of src/basic/virt.c's detect_vm() that safely works in the UEFI
- * environment. */
-
- if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) == 0)
- return false;
-
- return !!(ecx & 0x80000000U);
-}
-#endif
-
void *find_configuration_table(const EFI_GUID *guid) {
for (UINTN i = 0; i < ST->NumberOfTableEntries; i++)
if (efi_guid_equal(&ST->ConfigurationTable[i].VendorGuid, guid))
diff --git a/src/boot/efi/util.h b/src/boot/efi/util.h
index 88fc60c17e..d688f392fc 100644
--- a/src/boot/efi/util.h
+++ b/src/boot/efi/util.h
@@ -210,14 +210,6 @@ EFI_STATUS open_volume(EFI_HANDLE device, EFI_FILE **ret_file);
EFI_STATUS make_file_device_path(EFI_HANDLE device, const char16_t *file, EFI_DEVICE_PATH **ret_dp);
EFI_STATUS device_path_to_str(const EFI_DEVICE_PATH *dp, char16_t **ret);
-#if defined(__i386__) || defined(__x86_64__)
-bool in_hypervisor(void);
-#else
-static inline bool in_hypervisor(void) {
- return false;
-}
-#endif
-
static inline bool efi_guid_equal(const EFI_GUID *a, const EFI_GUID *b) {
return memcmp(a, b, sizeof(EFI_GUID)) == 0;
}
diff --git a/src/boot/efi/vmm.c b/src/boot/efi/vmm.c
index 10d4a75ab2..3dfa92b58d 100644
--- a/src/boot/efi/vmm.c
+++ b/src/boot/efi/vmm.c
@@ -3,6 +3,9 @@
#include <efi.h>
#include <efilib.h>
#include <stdbool.h>
+#if defined(__i386__) || defined(__x86_64__)
+# include <cpuid.h>
+#endif
#include "drivers.h"
#include "efi-string.h"
@@ -132,3 +135,156 @@ EFI_STATUS vmm_open(EFI_HANDLE *ret_vmm_dev, EFI_FILE **ret_vmm_dir) {
}
assert_not_reached();
}
+
+static bool cpuid_in_hypervisor(void) {
+#if defined(__i386__) || defined(__x86_64__)
+ unsigned eax, ebx, ecx, edx;
+
+ /* This is a dumbed down version of src/basic/virt.c's detect_vm() that safely works in the UEFI
+ * environment. */
+
+ if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) == 0)
+ return false;
+
+ if (FLAGS_SET(ecx, 0x80000000U))
+ return true;
+#endif
+
+ return false;
+}
+
+typedef struct {
+ uint8_t anchor_string[4];
+ uint8_t entry_point_structure_checksum;
+ uint8_t entry_point_length;
+ uint8_t major_version;
+ uint8_t minor_version;
+ uint16_t max_structure_size;
+ uint8_t entry_point_revision;
+ uint8_t formatted_area[5];
+ uint8_t intermediate_anchor_string[5];
+ uint8_t intermediate_checksum;
+ uint16_t table_length;
+ uint32_t table_address;
+ uint16_t number_of_smbios_structures;
+ uint8_t smbios_bcd_revision;
+} _packed_ SmbiosEntryPoint;
+
+typedef struct {
+ uint8_t anchor_string[5];
+ uint8_t entry_point_structure_checksum;
+ uint8_t entry_point_length;
+ uint8_t major_version;
+ uint8_t minor_version;
+ uint8_t docrev;
+ uint8_t entry_point_revision;
+ uint8_t reserved;
+ uint32_t table_maximum_size;
+ uint64_t table_address;
+} _packed_ Smbios3EntryPoint;
+
+typedef struct {
+ uint8_t type;
+ uint8_t length;
+ uint8_t handle[2];
+} _packed_ SmbiosHeader;
+
+typedef struct {
+ SmbiosHeader header;
+ uint8_t vendor;
+ uint8_t bios_version;
+ uint16_t bios_segment;
+ uint8_t bios_release_date;
+ uint8_t bios_size;
+ uint64_t bios_characteristics;
+ uint8_t bios_characteristics_ext[2];
+} _packed_ SmbiosTableType0;
+
+static void *find_smbios_configuration_table(uint64_t *ret_size) {
+ assert(ret_size);
+
+ Smbios3EntryPoint *entry3 = find_configuration_table(&(EFI_GUID) SMBIOS3_TABLE_GUID);
+ if (entry3 && memcmp(entry3->anchor_string, "_SM3_", 5) == 0 &&
+ entry3->entry_point_length <= sizeof(*entry3)) {
+ *ret_size = entry3->table_maximum_size;
+ return PHYSICAL_ADDRESS_TO_POINTER(entry3->table_address);
+ }
+
+ SmbiosEntryPoint *entry = find_configuration_table(&(EFI_GUID) SMBIOS_TABLE_GUID);
+ if (entry && memcmp(entry->anchor_string, "_SM_", 4) == 0 &&
+ entry->entry_point_length <= sizeof(*entry)) {
+ *ret_size = entry->table_length;
+ return PHYSICAL_ADDRESS_TO_POINTER(entry->table_address);
+ }
+
+ return NULL;
+}
+
+static SmbiosHeader *get_smbios_table(uint8_t type) {
+ uint64_t size = 0;
+ uint8_t *p = find_smbios_configuration_table(&size);
+ if (!p)
+ return false;
+
+ for (;;) {
+ if (size < sizeof(SmbiosHeader))
+ return NULL;
+
+ SmbiosHeader *header = (SmbiosHeader *) p;
+
+ /* End of table. */
+ if (header->type == 127)
+ return NULL;
+
+ if (size < header->length)
+ return NULL;
+
+ if (header->type == type)
+ return header; /* Yay! */
+
+ /* Skip over formatted area. */
+ size -= header->length;
+ p += header->length;
+
+ /* Skip over string table. */
+ for (;;) {
+ while (size > 0 && *p != '\0') {
+ p++;
+ size--;
+ }
+ if (size == 0)
+ return NULL;
+ p++;
+ size--;
+
+ /* Double NUL terminates string table. */
+ if (*p == '\0') {
+ if (size == 0)
+ return NULL;
+ p++;
+ break;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static bool smbios_in_hypervisor(void) {
+ /* Look up BIOS Information (Type 0). */
+ SmbiosTableType0 *type0 = (SmbiosTableType0 *) get_smbios_table(0);
+ if (!type0 || type0->header.length < sizeof(SmbiosTableType0))
+ return false;
+
+ /* Bit 4 of 2nd BIOS characteristics extension bytes indicates virtualization. */
+ return FLAGS_SET(type0->bios_characteristics_ext[1], 1 << 4);
+}
+
+bool in_hypervisor(void) {
+ static int cache = -1;
+ if (cache >= 0)
+ return cache;
+
+ cache = cpuid_in_hypervisor() || smbios_in_hypervisor();
+ return cache;
+}
diff --git a/src/boot/efi/vmm.h b/src/boot/efi/vmm.h
index 7bac1a324a..e98ec74af1 100644
--- a/src/boot/efi/vmm.h
+++ b/src/boot/efi/vmm.h
@@ -6,3 +6,5 @@
bool is_direct_boot(EFI_HANDLE device);
EFI_STATUS vmm_open(EFI_HANDLE *ret_qemu_dev, EFI_FILE **ret_qemu_dir);
+
+bool in_hypervisor(void);

View File

@ -0,0 +1,83 @@
From 72089d78ba9e0c0d4c4b83c8f447adbfb32809ed Mon Sep 17 00:00:00 2001
From: Jan Janssen <medhefgo@web.de>
Date: Mon, 16 Jan 2023 16:22:17 +0100
Subject: [PATCH] boot: Skip soft-brick warning when in a VM
This part of the warning is annoying to look at not really true when
running inside of a VM.
(cherry picked from commit 3e87a057a796b57bf9540b948823fbefef6693d7)
Related: RHEL-16952
---
src/boot/efi/secure-boot.c | 56 ++++++++++++++++++++------------------
1 file changed, 29 insertions(+), 27 deletions(-)
diff --git a/src/boot/efi/secure-boot.c b/src/boot/efi/secure-boot.c
index 55c9ba5d4c..3f3a222b5e 100644
--- a/src/boot/efi/secure-boot.c
+++ b/src/boot/efi/secure-boot.c
@@ -44,34 +44,36 @@ EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path) {
clear_screen(COLOR_NORMAL);
- Print(L"Enrolling secure boot keys from directory: %s\n"
- L"Warning: Enrolling custom Secure Boot keys might soft-brick your machine!\n",
- path);
-
- unsigned timeout_sec = 15;
- for(;;) {
- /* Enrolling secure boot keys is safe to do in virtualized environments as there is nothing
- * we can brick there. */
- if (in_hypervisor())
- break;
-
- PrintAt(0, ST->ConOut->Mode->CursorRow, L"Enrolling in %2u s, press any key to abort.", timeout_sec);
-
- uint64_t key;
- err = console_key_read(&key, 1000 * 1000);
- if (err == EFI_NOT_READY)
- continue;
- if (err == EFI_TIMEOUT) {
- if (timeout_sec == 0) /* continue enrolling keys */
- break;
- timeout_sec--;
- continue;
+ Print(u"Enrolling secure boot keys from directory: %s\n");
+
+ /* Enrolling secure boot keys is safe to do in virtualized environments as there is nothing
+ * we can brick there. */
+ if (!in_hypervisor()) {
+ Print(u"Warning: Enrolling custom Secure Boot keys might soft-brick your machine!\n", path);
+
+ unsigned timeout_sec = 15;
+ for (;;) {
+ Print(u"\rEnrolling in %2u s, press any key to abort.", timeout_sec);
+
+ uint64_t key;
+ err = console_key_read(&key, 1000 * 1000);
+ if (err == EFI_NOT_READY)
+ continue;
+ if (err == EFI_TIMEOUT) {
+ if (timeout_sec == 0) /* continue enrolling keys */
+ break;
+ timeout_sec--;
+ continue;
+ }
+ if (err != EFI_SUCCESS)
+ return log_error_status_stall(
+ err,
+ L"Error waiting for user input to enroll Secure Boot keys: %r",
+ err);
+
+ /* user aborted, returning EFI_SUCCESS here allows the user to go back to the menu */
+ return EFI_SUCCESS;
}
- if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Error waiting for user input to enroll Secure Boot keys: %r", err);
-
- /* user aborted, returning EFI_SUCCESS here allows the user to go back to the menu */
- return EFI_SUCCESS;
}
_cleanup_(file_closep) EFI_FILE *dir = NULL;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,42 @@
From a8a487d886f701b1a1e8991074d84ddacf41fcd0 Mon Sep 17 00:00:00 2001
From: Jan Janssen <medhefgo@web.de>
Date: Wed, 25 Jan 2023 15:23:49 +0100
Subject: [PATCH] boot: Use unsigned for beep counting
(cherry picked from commit 54d9ecc380360e925ef5ca7886c8546424ddf4fe)
Related: RHEL-16952
---
src/boot/efi/util.c | 2 +-
src/boot/efi/util.h | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/boot/efi/util.c b/src/boot/efi/util.c
index 2be18936b0..7596bc3edc 100644
--- a/src/boot/efi/util.c
+++ b/src/boot/efi/util.c
@@ -587,7 +587,7 @@ static inline void outb(uint16_t port, uint8_t value) {
asm volatile("outb %0, %1" : : "a"(value), "Nd"(port));
}
-void beep(UINTN beep_count) {
+void beep(unsigned beep_count) {
enum {
PITCH = 500,
BEEP_DURATION_USEC = 100 * 1000,
diff --git a/src/boot/efi/util.h b/src/boot/efi/util.h
index 33472a5b6a..b97dc9768c 100644
--- a/src/boot/efi/util.h
+++ b/src/boot/efi/util.h
@@ -201,9 +201,9 @@ void hexdump(const char16_t *prefix, const void *data, UINTN size);
#endif
#if defined(__i386__) || defined(__x86_64__)
-void beep(UINTN beep_count);
+void beep(unsigned beep_count);
#else
-static inline void beep(UINTN beep_count) {}
+static inline void beep(unsigned beep_count) {}
#endif
EFI_STATUS open_volume(EFI_HANDLE device, EFI_FILE **ret_file);

View File

@ -0,0 +1,316 @@
From 4280dc5179071758294e661600b37e3d5c7658c9 Mon Sep 17 00:00:00 2001
From: Jan Janssen <medhefgo@web.de>
Date: Fri, 9 Dec 2022 11:15:41 +0100
Subject: [PATCH] boot: Use unicode literals
No changes in behavior.
(cherry picked from commit a083aed03fc4a2bf64b2c41df508a47e3ceba91c)
Related: RHEL-16952
---
src/boot/efi/boot.c | 54 +++++++++++++++++++-------------------
src/boot/efi/drivers.c | 4 +--
src/boot/efi/random-seed.c | 2 +-
src/boot/efi/stub.c | 18 ++++++-------
4 files changed, 39 insertions(+), 39 deletions(-)
diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
index 385cfd563a..a39c356158 100644
--- a/src/boot/efi/boot.c
+++ b/src/boot/efi/boot.c
@@ -427,7 +427,7 @@ static bool unicode_supported(void) {
if (cache < 0)
/* Basic unicode box drawing support is mandated by the spec, but it does
* not hurt to make sure it works. */
- cache = ST->ConOut->TestString(ST->ConOut, (char16_t *) L"─") == EFI_SUCCESS;
+ cache = ST->ConOut->TestString(ST->ConOut, (char16_t *) u"─") == EFI_SUCCESS;
return cache;
}
@@ -728,7 +728,7 @@ static bool menu_run(
print_at(x_start,
y_start + i - idx_first,
i == idx_highlight ? COLOR_HIGHLIGHT : COLOR_ENTRY,
- unicode_supported() ? L" ►" : L"=>");
+ unicode_supported() ? u" ►" : u"=>");
}
refresh = false;
} else if (highlight) {
@@ -738,12 +738,12 @@ static bool menu_run(
print_at(x_start,
y_start + idx_highlight_prev - idx_first,
COLOR_ENTRY,
- unicode_supported() ? L" ►" : L"=>");
+ unicode_supported() ? u" ►" : u"=>");
if (idx_highlight == config->idx_default_efivar)
print_at(x_start,
y_start + idx_highlight - idx_first,
COLOR_HIGHLIGHT,
- unicode_supported() ? L" ►" : L"=>");
+ unicode_supported() ? u" ►" : u"=>");
highlight = false;
}
@@ -1504,7 +1504,7 @@ static void config_entry_add_type1(
config_add_entry(config, entry);
- config_entry_parse_tries(entry, path, file, L".conf");
+ config_entry_parse_tries(entry, path, file, u".conf");
TAKE_PTR(entry);
}
@@ -1556,7 +1556,7 @@ static void config_load_defaults(Config *config, EFI_FILE *root_dir) {
.timeout_sec_efivar = TIMEOUT_UNSET,
};
- err = file_read(root_dir, L"\\loader\\loader.conf", 0, 0, &content, NULL);
+ err = file_read(root_dir, u"\\loader\\loader.conf", 0, 0, &content, NULL);
if (err == EFI_SUCCESS)
config_defaults_load_from_file(config, content);
@@ -1591,8 +1591,8 @@ static void config_load_defaults(Config *config, EFI_FILE *root_dir) {
strtolower16(config->entry_oneshot);
strtolower16(config->entry_saved);
- config->use_saved_entry = streq16(config->entry_default_config, L"@saved");
- config->use_saved_entry_efivar = streq16(config->entry_default_efivar, L"@saved");
+ config->use_saved_entry = streq16(config->entry_default_config, u"@saved");
+ config->use_saved_entry_efivar = streq16(config->entry_default_efivar, u"@saved");
if (config->use_saved_entry || config->use_saved_entry_efivar)
(void) efivar_get(LOADER_GUID, L"LoaderEntryLastBooted", &config->entry_saved);
}
@@ -1614,7 +1614,7 @@ static void config_load_entries(
/* Adds Boot Loader Type #1 entries (i.e. /loader/entries/….conf) */
- err = open_directory(root_dir, L"\\loader\\entries", &entries_dir);
+ err = open_directory(root_dir, u"\\loader\\entries", &entries_dir);
if (err != EFI_SUCCESS)
return;
@@ -1630,14 +1630,14 @@ static void config_load_entries(
if (FLAGS_SET(f->Attribute, EFI_FILE_DIRECTORY))
continue;
- if (!endswith_no_case(f->FileName, L".conf"))
+ if (!endswith_no_case(f->FileName, u".conf"))
continue;
- if (startswith(f->FileName, L"auto-"))
+ if (startswith(f->FileName, u"auto-"))
continue;
err = file_read(entries_dir, f->FileName, 0, 0, &content, NULL);
if (err == EFI_SUCCESS)
- config_entry_add_type1(config, device, root_dir, L"\\loader\\entries", f->FileName, content, loaded_image_path);
+ config_entry_add_type1(config, device, root_dir, u"\\loader\\entries", f->FileName, content, loaded_image_path);
}
}
@@ -1876,7 +1876,7 @@ static ConfigEntry *config_entry_add_loader_auto(
return NULL;
if (!loader) {
- loader = L"\\EFI\\BOOT\\BOOT" EFI_MACHINE_TYPE_NAME ".efi";
+ loader = u"\\EFI\\BOOT\\BOOT" EFI_MACHINE_TYPE_NAME ".efi";
/* We are trying to add the default EFI loader here,
* but we do not want to do that if that would be us.
@@ -1885,7 +1885,7 @@ static ConfigEntry *config_entry_add_loader_auto(
* chainload GRUBX64.EFI in that case, which might be us.*/
if (strcaseeq16(loader, loaded_image_path) ||
is_sd_boot(root_dir, loader) ||
- is_sd_boot(root_dir, L"\\EFI\\BOOT\\GRUB" EFI_MACHINE_TYPE_NAME L".EFI"))
+ is_sd_boot(root_dir, u"\\EFI\\BOOT\\GRUB" EFI_MACHINE_TYPE_NAME u".EFI"))
return NULL;
}
@@ -1936,10 +1936,10 @@ static void config_entry_add_osx(Config *config) {
handles[i],
root,
NULL,
- L"auto-osx",
+ u"auto-osx",
'a',
- L"macOS",
- L"\\System\\Library\\CoreServices\\boot.efi"))
+ u"macOS",
+ u"\\System\\Library\\CoreServices\\boot.efi"))
break;
}
}
@@ -2008,7 +2008,7 @@ static EFI_STATUS boot_windows_bitlocker(void) {
if (buf_size < offset + sizeof(char16_t))
continue;
- if (streq16((char16_t *) (buf + offset), L"Windows Boot Manager")) {
+ if (streq16((char16_t *) (buf + offset), u"Windows Boot Manager")) {
err = efivar_set_raw(
EFI_GLOBAL_GUID,
L"BootNext",
@@ -2040,13 +2040,13 @@ static void config_entry_add_windows(Config *config, EFI_HANDLE *device, EFI_FIL
return;
/* Try to find a better title. */
- err = file_read(root_dir, L"\\EFI\\Microsoft\\Boot\\BCD", 0, 100*1024, &bcd, &len);
+ err = file_read(root_dir, u"\\EFI\\Microsoft\\Boot\\BCD", 0, 100*1024, &bcd, &len);
if (err == EFI_SUCCESS)
title = get_bcd_title((uint8_t *) bcd, len);
ConfigEntry *e = config_entry_add_loader_auto(config, device, root_dir, NULL,
- L"auto-windows", 'w', title ?: L"Windows Boot Manager",
- L"\\EFI\\Microsoft\\Boot\\bootmgfw.efi");
+ u"auto-windows", 'w', title ?: u"Windows Boot Manager",
+ u"\\EFI\\Microsoft\\Boot\\bootmgfw.efi");
if (config->reboot_for_bitlocker)
e->call = boot_windows_bitlocker;
@@ -2069,7 +2069,7 @@ static void config_entry_add_unified(
assert(device);
assert(root_dir);
- err = open_directory(root_dir, L"\\EFI\\Linux", &linux_dir);
+ err = open_directory(root_dir, u"\\EFI\\Linux", &linux_dir);
if (err != EFI_SUCCESS)
return;
@@ -2101,9 +2101,9 @@ static void config_entry_add_unified(
continue;
if (FLAGS_SET(f->Attribute, EFI_FILE_DIRECTORY))
continue;
- if (!endswith_no_case(f->FileName, L".efi"))
+ if (!endswith_no_case(f->FileName, u".efi"))
continue;
- if (startswith(f->FileName, L"auto-"))
+ if (startswith(f->FileName, u"auto-"))
continue;
/* look for .osrel and .cmdline sections in the .efi binary */
@@ -2196,7 +2196,7 @@ static void config_entry_add_unified(
strtolower16(entry->id);
config_add_entry(config, entry);
- config_entry_parse_tries(entry, L"\\EFI\\Linux", f->FileName, L".efi");
+ config_entry_parse_tries(entry, u"\\EFI\\Linux", f->FileName, u".efi");
if (szs[SECTION_CMDLINE] == 0)
continue;
@@ -2571,9 +2571,9 @@ static void config_load_all_entries(
config_entry_add_osx(config);
config_entry_add_windows(config, loaded_image->DeviceHandle, root_dir);
config_entry_add_loader_auto(config, loaded_image->DeviceHandle, root_dir, NULL,
- L"auto-efi-shell", 's', L"EFI Shell", L"\\shell" EFI_MACHINE_TYPE_NAME ".efi");
+ u"auto-efi-shell", 's', u"EFI Shell", u"\\shell" EFI_MACHINE_TYPE_NAME ".efi");
config_entry_add_loader_auto(config, loaded_image->DeviceHandle, root_dir, loaded_image_path,
- L"auto-efi-default", '\0', L"EFI Default Loader", NULL);
+ u"auto-efi-default", '\0', u"EFI Default Loader", NULL);
if (config->auto_firmware && FLAGS_SET(get_os_indications_supported(), EFI_OS_INDICATIONS_BOOT_TO_FW_UI)) {
ConfigEntry *entry = xnew(ConfigEntry, 1);
diff --git a/src/boot/efi/drivers.c b/src/boot/efi/drivers.c
index c073e1a4f2..41a7d8fe15 100644
--- a/src/boot/efi/drivers.c
+++ b/src/boot/efi/drivers.c
@@ -82,7 +82,7 @@ EFI_STATUS load_drivers(
err = open_directory(
root_dir,
- L"\\EFI\\systemd\\drivers",
+ u"\\EFI\\systemd\\drivers",
&drivers_dir);
if (err == EFI_NOT_FOUND)
return EFI_SUCCESS;
@@ -100,7 +100,7 @@ EFI_STATUS load_drivers(
continue;
if (FLAGS_SET(dirent->Attribute, EFI_FILE_DIRECTORY))
continue;
- if (!endswith_no_case(dirent->FileName, EFI_MACHINE_TYPE_NAME L".efi"))
+ if (!endswith_no_case(dirent->FileName, EFI_MACHINE_TYPE_NAME u".efi"))
continue;
err = load_one_driver(parent_image, loaded_image, dirent->FileName);
diff --git a/src/boot/efi/random-seed.c b/src/boot/efi/random-seed.c
index 5d7459d87e..a52934a901 100644
--- a/src/boot/efi/random-seed.c
+++ b/src/boot/efi/random-seed.c
@@ -196,7 +196,7 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir) {
err = root_dir->Open(
root_dir,
&handle,
- (char16_t *) L"\\loader\\random-seed",
+ (char16_t *) u"\\loader\\random-seed",
EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,
0);
if (err != EFI_SUCCESS) {
diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c
index e3b97164a8..433fef548c 100644
--- a/src/boot/efi/stub.c
+++ b/src/boot/efi/stub.c
@@ -286,27 +286,27 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
if (pack_cpio(loaded_image,
NULL,
- L".cred",
+ u".cred",
".extra/credentials",
/* dir_mode= */ 0500,
/* access_mode= */ 0400,
/* tpm_pcr= */ (uint32_t[]) { TPM_PCR_INDEX_KERNEL_PARAMETERS, TPM_PCR_INDEX_KERNEL_PARAMETERS_COMPAT },
/* n_tpm_pcr= */ 2,
- L"Credentials initrd",
+ u"Credentials initrd",
&credential_initrd,
&credential_initrd_size,
&m) == EFI_SUCCESS)
parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m);
if (pack_cpio(loaded_image,
- L"\\loader\\credentials",
- L".cred",
+ u"\\loader\\credentials",
+ u".cred",
".extra/global_credentials",
/* dir_mode= */ 0500,
/* access_mode= */ 0400,
/* tpm_pcr= */ (uint32_t[]) { TPM_PCR_INDEX_KERNEL_PARAMETERS, TPM_PCR_INDEX_KERNEL_PARAMETERS_COMPAT },
/* n_tpm_pcr= */ 2,
- L"Global credentials initrd",
+ u"Global credentials initrd",
&global_credential_initrd,
&global_credential_initrd_size,
&m) == EFI_SUCCESS)
@@ -314,13 +314,13 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
if (pack_cpio(loaded_image,
NULL,
- L".raw",
+ u".raw",
".extra/sysext",
/* dir_mode= */ 0555,
/* access_mode= */ 0444,
/* tpm_pcr= */ (uint32_t[]) { TPM_PCR_INDEX_INITRD_SYSEXTS },
/* n_tpm_pcr= */ 1,
- L"System extension initrd",
+ u"System extension initrd",
&sysext_initrd,
&sysext_initrd_size,
&m) == EFI_SUCCESS)
@@ -341,7 +341,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
(uint8_t*) loaded_image->ImageBase + addrs[UNIFIED_SECTION_PCRSIG],
szs[UNIFIED_SECTION_PCRSIG],
".extra",
- L"tpm2-pcr-signature.json",
+ u"tpm2-pcr-signature.json",
/* dir_mode= */ 0555,
/* access_mode= */ 0444,
/* tpm_pcr= */ NULL,
@@ -360,7 +360,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
(uint8_t*) loaded_image->ImageBase + addrs[UNIFIED_SECTION_PCRPKEY],
szs[UNIFIED_SECTION_PCRPKEY],
".extra",
- L"tpm2-pcr-public-key.pem",
+ u"tpm2-pcr-public-key.pem",
/* dir_mode= */ 0555,
/* access_mode= */ 0444,
/* tpm_pcr= */ NULL,

View File

@ -0,0 +1,106 @@
From 925a5adafed2d17c4f2c50460d4e571ca509f54e Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 7 Dec 2022 18:31:27 +0100
Subject: [PATCH] macro: add generic IS_ALIGNED32() anf friends
Let's generalize (and invert) the UNALIGNED32_P() macro from the sha256
code, and let's add a test for it.
(cherry picked from commit 4f07388360a3513b9fc8d2773568b8def941f4a4)
Related: RHEL-16952
---
src/fundamental/macro-fundamental.h | 9 +++++
src/test/test-macro.c | 53 +++++++++++++++++++++++++++++
2 files changed, 62 insertions(+)
diff --git a/src/fundamental/macro-fundamental.h b/src/fundamental/macro-fundamental.h
index e0665d9dcb..dd0de328cb 100644
--- a/src/fundamental/macro-fundamental.h
+++ b/src/fundamental/macro-fundamental.h
@@ -334,14 +334,23 @@ static inline size_t ALIGN_TO(size_t l, size_t ali) {
return ((l + ali - 1) & ~(ali - 1));
}
+#define ALIGN2(l) ALIGN_TO(l, 2)
#define ALIGN4(l) ALIGN_TO(l, 4)
#define ALIGN8(l) ALIGN_TO(l, 8)
+#define ALIGN2_PTR(p) ((void*) ALIGN2((uintptr_t) p))
+#define ALIGN4_PTR(p) ((void*) ALIGN4((uintptr_t) p))
+#define ALIGN8_PTR(p) ((void*) ALIGN8((uintptr_t) p))
#ifndef SD_BOOT
/* libefi also provides ALIGN, and we do not use them in sd-boot explicitly. */
#define ALIGN(l) ALIGN_TO(l, sizeof(void*))
#define ALIGN_PTR(p) ((void*) ALIGN((uintptr_t) (p)))
#endif
+/* Checks if the specified pointer is aligned as appropriate for the specific type */
+#define IS_ALIGNED16(p) (((uintptr_t) p) % __alignof__(uint16_t) == 0)
+#define IS_ALIGNED32(p) (((uintptr_t) p) % __alignof__(uint32_t) == 0)
+#define IS_ALIGNED64(p) (((uintptr_t) p) % __alignof__(uint64_t) == 0)
+
/* Same as ALIGN_TO but callable in constant contexts. */
#define CONST_ALIGN_TO(l, ali) \
__builtin_choose_expr( \
diff --git a/src/test/test-macro.c b/src/test/test-macro.c
index bb79ea0dbe..a1618c3105 100644
--- a/src/test/test-macro.c
+++ b/src/test/test-macro.c
@@ -755,4 +755,57 @@ TEST(FOREACH_ARRAY) {
assert_se(n == 0);
}
+TEST(ALIGNED) {
+ assert_se(IS_ALIGNED16(NULL));
+ assert_se(IS_ALIGNED32(NULL));
+ assert_se(IS_ALIGNED64(NULL));
+
+ uint64_t u64;
+ uint32_t u32;
+ uint16_t u16;
+
+ assert_se(IS_ALIGNED16(&u16));
+ assert_se(IS_ALIGNED16(&u32));
+ assert_se(IS_ALIGNED16(&u64));
+ assert_se(IS_ALIGNED32(&u32));
+ assert_se(IS_ALIGNED32(&u64));
+ assert_se(IS_ALIGNED64(&u64));
+
+ _align_(32) uint8_t ua256;
+ _align_(8) uint8_t ua64;
+ _align_(4) uint8_t ua32;
+ _align_(2) uint8_t ua16;
+
+ assert_se(IS_ALIGNED16(&ua256));
+ assert_se(IS_ALIGNED32(&ua256));
+ assert_se(IS_ALIGNED64(&ua256));
+
+ assert_se(IS_ALIGNED16(&ua64));
+ assert_se(IS_ALIGNED32(&ua64));
+ assert_se(IS_ALIGNED64(&ua64));
+
+ assert_se(IS_ALIGNED16(&ua32));
+ assert_se(IS_ALIGNED32(&ua32));
+
+ assert_se(IS_ALIGNED16(&ua16));
+
+#ifdef __x86_64__
+ /* Conditionalized on x86-64, since there we know for sure that all three types are aligned to
+ * their size. Too lazy to figure it out for other archs */
+ void *p = UINT_TO_PTR(1); /* definitely not aligned */
+ assert_se(!IS_ALIGNED16(p));
+ assert_se(!IS_ALIGNED32(p));
+ assert_se(!IS_ALIGNED64(p));
+
+ assert_se(IS_ALIGNED16(ALIGN2_PTR(p)));
+ assert_se(IS_ALIGNED32(ALIGN4_PTR(p)));
+ assert_se(IS_ALIGNED64(ALIGN8_PTR(p)));
+
+ p = UINT_TO_PTR(-1); /* also definitely not aligned */
+ assert_se(!IS_ALIGNED16(p));
+ assert_se(!IS_ALIGNED32(p));
+ assert_se(!IS_ALIGNED64(p));
+#endif
+}
+
DEFINE_TEST_MAIN(LOG_INFO);

View File

@ -0,0 +1,214 @@
From 1b03cc4e54f74c075e177b57e04cd6f9338540fd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 10 Jan 2023 14:25:57 +0100
Subject: [PATCH] meson: use 0|1 for SD_BOOT
We converted to not using #ifdef for most of our defines because the syntax is
nicer and we are protected against typos and can set -Werror=undef. Let's do
the same for SD_BOOT. The define is nicely hidden in build.h for normal builds,
and for EFI builds we were already setting SD_BOOT on the commandline.
(cherry picked from commit 493cd5034c3eb091e7163ea1e744a4e07b410710)
Related: RHEL-16952
---
meson.build | 3 +++
src/boot/efi/efi-string.c | 8 ++++----
src/boot/efi/efi-string.h | 2 +-
src/boot/efi/meson.build | 2 +-
src/fundamental/macro-fundamental.h | 6 +++---
src/fundamental/memory-util-fundamental.h | 2 +-
src/fundamental/sha256.c | 2 +-
src/fundamental/string-util-fundamental.c | 4 ++--
src/fundamental/string-util-fundamental.h | 6 +++---
9 files changed, 19 insertions(+), 16 deletions(-)
diff --git a/meson.build b/meson.build
index 54155eee1f..843d823e3e 100644
--- a/meson.build
+++ b/meson.build
@@ -55,6 +55,9 @@ fuzzer_build = want_ossfuzz or want_libfuzzer
# limits).
conf.set10('FUZZ_USE_SIZE_LIMIT', fuzzer_build)
+# We'll set this to '1' for EFI builds in a different place.
+conf.set10('SD_BOOT', false)
+
# Create a title-less summary section early, so it ends up first in the output.
# More items are added later after they have been detected.
summary({'build mode' : get_option('mode')})
diff --git a/src/boot/efi/efi-string.c b/src/boot/efi/efi-string.c
index 2ba15673c9..79c296eda3 100644
--- a/src/boot/efi/efi-string.c
+++ b/src/boot/efi/efi-string.c
@@ -5,7 +5,7 @@
#include "efi-string.h"
-#ifdef SD_BOOT
+#if SD_BOOT
# include "util.h"
#else
# include <stdlib.h>
@@ -378,7 +378,7 @@ bool efi_fnmatch(const char16_t *pattern, const char16_t *haystack) {
DEFINE_PARSE_NUMBER(char, parse_number8);
DEFINE_PARSE_NUMBER(char16_t, parse_number16);
-#ifdef SD_BOOT
+#if SD_BOOT
/* To provide the actual implementation for these we need to remove the redirection to the builtins. */
# undef memcmp
# undef memcpy
@@ -414,7 +414,7 @@ _used_ _weak_ void *memcpy(void * restrict dest, const void * restrict src, size
if (!dest || !src || n == 0)
return dest;
-#ifdef SD_BOOT
+#if SD_BOOT
/* The firmware-provided memcpy is likely optimized, so use that. The function is guaranteed to be
* available by the UEFI spec. We still make it depend on the boot services pointer being set just in
* case the compiler emits a call before it is available. */
@@ -441,7 +441,7 @@ _used_ _weak_ void *memset(void *p, int c, size_t n) {
if (!p || n == 0)
return p;
-#ifdef SD_BOOT
+#if SD_BOOT
/* See comment in efi_memcpy. Note that the signature has c and n swapped! */
if (_likely_(BS)) {
BS->SetMem(p, n, c);
diff --git a/src/boot/efi/efi-string.h b/src/boot/efi/efi-string.h
index 25931a7d6e..aaa9b399c8 100644
--- a/src/boot/efi/efi-string.h
+++ b/src/boot/efi/efi-string.h
@@ -109,7 +109,7 @@ bool efi_fnmatch(const char16_t *pattern, const char16_t *haystack);
bool parse_number8(const char *s, uint64_t *ret_u, const char **ret_tail);
bool parse_number16(const char16_t *s, uint64_t *ret_u, const char16_t **ret_tail);
-#ifdef SD_BOOT
+#if SD_BOOT
/* The compiler normally has knowledge about standard functions such as memcmp, but this is not the case when
* compiling with -ffreestanding. By referring to builtins, the compiler can check arguments and do
* optimizations again. Note that we still need to provide implementations as the compiler is free to not
diff --git a/src/boot/efi/meson.build b/src/boot/efi/meson.build
index ab2d7595f3..bba3b62d3c 100644
--- a/src/boot/efi/meson.build
+++ b/src/boot/efi/meson.build
@@ -176,7 +176,7 @@ efi_config_h = configure_file(
efi_cflags = [
'-DGNU_EFI_USE_MS_ABI',
- '-DSD_BOOT',
+ '-DSD_BOOT=1',
'-ffreestanding',
'-fshort-wchar',
'-fvisibility=hidden',
diff --git a/src/fundamental/macro-fundamental.h b/src/fundamental/macro-fundamental.h
index dd0de328cb..1c4c445e4e 100644
--- a/src/fundamental/macro-fundamental.h
+++ b/src/fundamental/macro-fundamental.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
-#ifndef SD_BOOT
+#if !SD_BOOT
# include <assert.h>
#endif
@@ -66,7 +66,7 @@
#define XCONCATENATE(x, y) x ## y
#define CONCATENATE(x, y) XCONCATENATE(x, y)
-#ifdef SD_BOOT
+#if SD_BOOT
_noreturn_ void efi_assert(const char *expr, const char *file, unsigned line, const char *function);
#ifdef NDEBUG
@@ -340,7 +340,7 @@ static inline size_t ALIGN_TO(size_t l, size_t ali) {
#define ALIGN2_PTR(p) ((void*) ALIGN2((uintptr_t) p))
#define ALIGN4_PTR(p) ((void*) ALIGN4((uintptr_t) p))
#define ALIGN8_PTR(p) ((void*) ALIGN8((uintptr_t) p))
-#ifndef SD_BOOT
+#if !SD_BOOT
/* libefi also provides ALIGN, and we do not use them in sd-boot explicitly. */
#define ALIGN(l) ALIGN_TO(l, sizeof(void*))
#define ALIGN_PTR(p) ((void*) ALIGN((uintptr_t) (p)))
diff --git a/src/fundamental/memory-util-fundamental.h b/src/fundamental/memory-util-fundamental.h
index 9015300ae8..8f50d8b8e1 100644
--- a/src/fundamental/memory-util-fundamental.h
+++ b/src/fundamental/memory-util-fundamental.h
@@ -3,7 +3,7 @@
#include <stddef.h>
-#ifdef SD_BOOT
+#if SD_BOOT
# include "efi-string.h"
#else
# include <string.h>
diff --git a/src/fundamental/sha256.c b/src/fundamental/sha256.c
index 9b717645b3..39029de93c 100644
--- a/src/fundamental/sha256.c
+++ b/src/fundamental/sha256.c
@@ -22,7 +22,7 @@
<https://www.gnu.org/licenses/>. */
#include <stdbool.h>
-#ifdef SD_BOOT
+#if SD_BOOT
# include "efi-string.h"
#else
# include <string.h>
diff --git a/src/fundamental/string-util-fundamental.c b/src/fundamental/string-util-fundamental.c
index 11701ebe52..484131d72a 100644
--- a/src/fundamental/string-util-fundamental.c
+++ b/src/fundamental/string-util-fundamental.c
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#ifndef SD_BOOT
+#if !SD_BOOT
# include <ctype.h>
#endif
@@ -20,7 +20,7 @@ sd_char *startswith(const sd_char *s, const sd_char *prefix) {
return (sd_char*) s + l;
}
-#ifndef SD_BOOT
+#if !SD_BOOT
sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) {
size_t l;
diff --git a/src/fundamental/string-util-fundamental.h b/src/fundamental/string-util-fundamental.h
index ecf32e519f..523c612a17 100644
--- a/src/fundamental/string-util-fundamental.h
+++ b/src/fundamental/string-util-fundamental.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
-#ifdef SD_BOOT
+#if SD_BOOT
# include <efi.h>
# include <efilib.h>
# include "efi-string.h"
@@ -11,7 +11,7 @@
#include "macro-fundamental.h"
-#ifdef SD_BOOT
+#if SD_BOOT
# define strlen strlen16
# define strcmp strcmp16
# define strncmp strncmp16
@@ -59,7 +59,7 @@ static inline size_t strlen_ptr(const sd_char *s) {
}
sd_char *startswith(const sd_char *s, const sd_char *prefix) _pure_;
-#ifndef SD_BOOT
+#if !SD_BOOT
sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) _pure_;
#endif
sd_char *endswith(const sd_char *s, const sd_char *postfix) _pure_;

View File

@ -0,0 +1,843 @@
From 6f7f7bb71af6047458a41c0f7135a8d31df840c4 Mon Sep 17 00:00:00 2001
From: Jan Janssen <medhefgo@web.de>
Date: Fri, 10 Jun 2022 18:55:24 +0200
Subject: [PATCH] boot: Add printf functions
(cherry picked from commit 7c4536a9af986332eaac8db292b22d59b4977f04)
Related: RHEL-16952
---
src/boot/efi/efi-string.c | 491 +++++++++++++++++++++++++++++++++
src/boot/efi/efi-string.h | 26 ++
src/boot/efi/fuzz-efi-printf.c | 76 +++++
src/boot/efi/meson.build | 1 +
src/boot/efi/missing_efi.h | 12 +
src/boot/efi/test-efi-string.c | 142 ++++++++++
6 files changed, 748 insertions(+)
create mode 100644 src/boot/efi/fuzz-efi-printf.c
diff --git a/src/boot/efi/efi-string.c b/src/boot/efi/efi-string.c
index 79c296eda3..860dfc00b2 100644
--- a/src/boot/efi/efi-string.c
+++ b/src/boot/efi/efi-string.c
@@ -2,10 +2,12 @@
#include <stdbool.h>
#include <stdint.h>
+#include <wchar.h>
#include "efi-string.h"
#if SD_BOOT
+# include "missing_efi.h"
# include "util.h"
#else
# include <stdlib.h>
@@ -378,6 +380,495 @@ bool efi_fnmatch(const char16_t *pattern, const char16_t *haystack) {
DEFINE_PARSE_NUMBER(char, parse_number8);
DEFINE_PARSE_NUMBER(char16_t, parse_number16);
+static const char * const warn_table[] = {
+ [EFI_SUCCESS] = "Success",
+#if SD_BOOT
+ [EFI_WARN_UNKNOWN_GLYPH] = "Unknown glyph",
+ [EFI_WARN_DELETE_FAILURE] = "Delete failure",
+ [EFI_WARN_WRITE_FAILURE] = "Write failure",
+ [EFI_WARN_BUFFER_TOO_SMALL] = "Buffer too small",
+ [EFI_WARN_STALE_DATA] = "Stale data",
+ [EFI_WARN_FILE_SYSTEM] = "File system",
+ [EFI_WARN_RESET_REQUIRED] = "Reset required",
+#endif
+};
+
+/* Errors have MSB set, remove it to keep the table compact. */
+#define NOERR(err) ((err) & ~EFI_ERROR_MASK)
+
+static const char * const err_table[] = {
+ [NOERR(EFI_ERROR_MASK)] = "Error",
+ [NOERR(EFI_LOAD_ERROR)] = "Load error",
+#if SD_BOOT
+ [NOERR(EFI_INVALID_PARAMETER)] = "Invalid parameter",
+ [NOERR(EFI_UNSUPPORTED)] = "Unsupported",
+ [NOERR(EFI_BAD_BUFFER_SIZE)] = "Bad buffer size",
+ [NOERR(EFI_BUFFER_TOO_SMALL)] = "Buffer too small",
+ [NOERR(EFI_NOT_READY)] = "Not ready",
+ [NOERR(EFI_DEVICE_ERROR)] = "Device error",
+ [NOERR(EFI_WRITE_PROTECTED)] = "Write protected",
+ [NOERR(EFI_OUT_OF_RESOURCES)] = "Out of resources",
+ [NOERR(EFI_VOLUME_CORRUPTED)] = "Volume corrupt",
+ [NOERR(EFI_VOLUME_FULL)] = "Volume full",
+ [NOERR(EFI_NO_MEDIA)] = "No media",
+ [NOERR(EFI_MEDIA_CHANGED)] = "Media changed",
+ [NOERR(EFI_NOT_FOUND)] = "Not found",
+ [NOERR(EFI_ACCESS_DENIED)] = "Access denied",
+ [NOERR(EFI_NO_RESPONSE)] = "No response",
+ [NOERR(EFI_NO_MAPPING)] = "No mapping",
+ [NOERR(EFI_TIMEOUT)] = "Time out",
+ [NOERR(EFI_NOT_STARTED)] = "Not started",
+ [NOERR(EFI_ALREADY_STARTED)] = "Already started",
+ [NOERR(EFI_ABORTED)] = "Aborted",
+ [NOERR(EFI_ICMP_ERROR)] = "ICMP error",
+ [NOERR(EFI_TFTP_ERROR)] = "TFTP error",
+ [NOERR(EFI_PROTOCOL_ERROR)] = "Protocol error",
+ [NOERR(EFI_INCOMPATIBLE_VERSION)] = "Incompatible version",
+ [NOERR(EFI_SECURITY_VIOLATION)] = "Security violation",
+ [NOERR(EFI_CRC_ERROR)] = "CRC error",
+ [NOERR(EFI_END_OF_MEDIA)] = "End of media",
+ [29] = "Reserved (29)",
+ [30] = "Reserved (30)",
+ [NOERR(EFI_END_OF_FILE)] = "End of file",
+ [NOERR(EFI_INVALID_LANGUAGE)] = "Invalid language",
+ [NOERR(EFI_COMPROMISED_DATA)] = "Compromised data",
+ [NOERR(EFI_IP_ADDRESS_CONFLICT)] = "IP address conflict",
+ [NOERR(EFI_HTTP_ERROR)] = "HTTP error",
+#endif
+};
+
+static const char *status_to_string(EFI_STATUS status) {
+ if (status <= ELEMENTSOF(warn_table) - 1)
+ return warn_table[status];
+ if (status >= EFI_ERROR_MASK && status <= ((ELEMENTSOF(err_table) - 1) | EFI_ERROR_MASK))
+ return err_table[NOERR(status)];
+ return NULL;
+}
+
+typedef struct {
+ size_t padded_len; /* Field width in printf. */
+ size_t len; /* Precision in printf. */
+ bool pad_zero;
+ bool align_left;
+ bool alternative_form;
+ bool long_arg;
+ bool longlong_arg;
+ bool have_field_width;
+
+ const char *str;
+ const wchar_t *wstr;
+
+ /* For numbers. */
+ bool is_signed;
+ bool lowercase;
+ int8_t base;
+ char sign_pad; /* For + and (space) flags. */
+} SpecifierContext;
+
+typedef struct {
+ char16_t stack_buf[128]; /* We use stack_buf first to avoid allocations in most cases. */
+ char16_t *dyn_buf; /* Allocated buf or NULL if stack_buf is used. */
+ char16_t *buf; /* Points to the current active buf. */
+ size_t n_buf; /* Len of buf (in char16_t's, not bytes!). */
+ size_t n; /* Used len of buf (in char16_t's). This is always <n_buf. */
+
+ EFI_STATUS status;
+ const char *format;
+ va_list ap;
+} FormatContext;
+
+static void grow_buf(FormatContext *ctx, size_t need) {
+ assert(ctx);
+
+ assert_se(!__builtin_add_overflow(ctx->n, need, &need));
+
+ if (need < ctx->n_buf)
+ return;
+
+ /* Greedily allocate if we can. */
+ if (__builtin_mul_overflow(need, 2, &ctx->n_buf))
+ ctx->n_buf = need;
+
+ /* We cannot use realloc here as ctx->buf may be ctx->stack_buf, which we cannot free. */
+ char16_t *new_buf = xnew(char16_t, ctx->n_buf);
+ memcpy(new_buf, ctx->buf, ctx->n * sizeof(*ctx->buf));
+
+ free(ctx->dyn_buf);
+ ctx->buf = ctx->dyn_buf = new_buf;
+}
+
+static void push_padding(FormatContext *ctx, char pad, size_t len) {
+ assert(ctx);
+ while (len > 0) {
+ len--;
+ ctx->buf[ctx->n++] = pad;
+ }
+}
+
+static bool push_str(FormatContext *ctx, SpecifierContext *sp) {
+ assert(ctx);
+ assert(sp);
+
+ sp->padded_len = LESS_BY(sp->padded_len, sp->len);
+
+ grow_buf(ctx, sp->padded_len + sp->len);
+
+ if (!sp->align_left)
+ push_padding(ctx, ' ', sp->padded_len);
+
+ /* In userspace unit tests we cannot just memcpy() the wide string. */
+ if (sp->wstr && sizeof(wchar_t) == sizeof(char16_t)) {
+ memcpy(ctx->buf + ctx->n, sp->wstr, sp->len * sizeof(*sp->wstr));
+ ctx->n += sp->len;
+ } else
+ for (size_t i = 0; i < sp->len; i++)
+ ctx->buf[ctx->n++] = sp->str ? sp->str[i] : sp->wstr[i];
+
+ if (sp->align_left)
+ push_padding(ctx, ' ', sp->padded_len);
+
+ assert(ctx->n < ctx->n_buf);
+ return true;
+}
+
+static bool push_num(FormatContext *ctx, SpecifierContext *sp, uint64_t u) {
+ const char *digits = sp->lowercase ? "0123456789abcdef" : "0123456789ABCDEF";
+ char16_t tmp[32];
+ size_t n = 0;
+
+ assert(ctx);
+ assert(sp);
+ assert(IN_SET(sp->base, 10, 16));
+
+ /* "%.0u" prints nothing if value is 0. */
+ if (u == 0 && sp->len == 0)
+ return true;
+
+ if (sp->is_signed && (int64_t) u < 0) {
+ /* We cannot just do "u = -(int64_t)u" here because -INT64_MIN overflows. */
+
+ uint64_t rem = -((int64_t) u % sp->base);
+ u = (int64_t) u / -sp->base;
+ tmp[n++] = digits[rem];
+ sp->sign_pad = '-';
+ }
+
+ while (u > 0 || n == 0) {
+ uint64_t rem = u % sp->base;
+ u /= sp->base;
+ tmp[n++] = digits[rem];
+ }
+
+ /* Note that numbers never get truncated! */
+ size_t prefix = (sp->sign_pad != 0 ? 1 : 0) + (sp->alternative_form ? 2 : 0);
+ size_t number_len = prefix + MAX(n, sp->len);
+ grow_buf(ctx, MAX(sp->padded_len, number_len));
+
+ size_t padding = 0;
+ if (sp->pad_zero)
+ /* Leading zeroes go after the sign or 0x prefix. */
+ number_len = MAX(number_len, sp->padded_len);
+ else
+ padding = LESS_BY(sp->padded_len, number_len);
+
+ if (!sp->align_left)
+ push_padding(ctx, ' ', padding);
+
+ if (sp->sign_pad != 0)
+ ctx->buf[ctx->n++] = sp->sign_pad;
+ if (sp->alternative_form) {
+ ctx->buf[ctx->n++] = '0';
+ ctx->buf[ctx->n++] = sp->lowercase ? 'x' : 'X';
+ }
+
+ push_padding(ctx, '0', LESS_BY(number_len, n + prefix));
+
+ while (n > 0)
+ ctx->buf[ctx->n++] = tmp[--n];
+
+ if (sp->align_left)
+ push_padding(ctx, ' ', padding);
+
+ assert(ctx->n < ctx->n_buf);
+ return true;
+}
+
+/* This helps unit testing. */
+#if SD_BOOT
+# define NULLSTR "(null)"
+# define wcsnlen strnlen16
+#else
+# define NULLSTR "(nil)"
+#endif
+
+static bool handle_format_specifier(FormatContext *ctx, SpecifierContext *sp) {
+ /* Parses one item from the format specifier in ctx and put the info into sp. If we are done with
+ * this specifier returns true, otherwise this function should be called again. */
+
+ /* This implementation assumes 32bit ints. Also note that all types smaller than int are promoted to
+ * int in vararg functions, which is why we fetch only ints for any such types. The compiler would
+ * otherwise warn about fetching smaller types. */
+ assert_cc(sizeof(int) == 4);
+ assert_cc(sizeof(wchar_t) <= sizeof(int));
+ assert_cc(sizeof(intmax_t) <= sizeof(long long));
+
+ assert(ctx);
+ assert(sp);
+
+ switch (*ctx->format) {
+ case '#':
+ sp->alternative_form = true;
+ return false;
+ case '.':
+ sp->have_field_width = true;
+ return false;
+ case '-':
+ sp->align_left = true;
+ return false;
+ case '+':
+ case ' ':
+ sp->sign_pad = *ctx->format;
+ return false;
+
+ case '0':
+ if (!sp->have_field_width) {
+ sp->pad_zero = true;
+ return false;
+ }
+
+ /* If field width has already been provided then 0 is part of precision (%.0s). */
+ _fallthrough_;
+
+ case '*':
+ case '1' ... '9': {
+ int64_t i;
+
+ if (*ctx->format == '*')
+ i = va_arg(ctx->ap, int);
+ else {
+ uint64_t u;
+ if (!parse_number8(ctx->format, &u, &ctx->format) || u > INT_MAX)
+ assert_not_reached();
+ ctx->format--; /* Point it back to the last digit. */
+ i = u;
+ }
+
+ if (sp->have_field_width) {
+ /* Negative precision is ignored. */
+ if (i >= 0)
+ sp->len = (size_t) i;
+ } else {
+ /* Negative field width is treated as positive field width with '-' flag. */
+ if (i < 0) {
+ i *= -1;
+ sp->align_left = true;
+ }
+ sp->padded_len = i;
+ }
+
+ return false;
+ }
+
+ case 'h':
+ if (*(ctx->format + 1) == 'h')
+ ctx->format++;
+ /* char/short gets promoted to int, nothing to do here. */
+ return false;
+
+ case 'l':
+ if (*(ctx->format + 1) == 'l') {
+ ctx->format++;
+ sp->longlong_arg = true;
+ } else
+ sp->long_arg = true;
+ return false;
+
+ case 'z':
+ sp->long_arg = sizeof(size_t) == sizeof(long);
+ sp->longlong_arg = !sp->long_arg && sizeof(size_t) == sizeof(long long);
+ return false;
+
+ case 'j':
+ sp->long_arg = sizeof(intmax_t) == sizeof(long);
+ sp->longlong_arg = !sp->long_arg && sizeof(intmax_t) == sizeof(long long);
+ return false;
+
+ case 't':
+ sp->long_arg = sizeof(ptrdiff_t) == sizeof(long);
+ sp->longlong_arg = !sp->long_arg && sizeof(ptrdiff_t) == sizeof(long long);
+ return false;
+
+ case '%':
+ sp->str = "%";
+ sp->len = 1;
+ return push_str(ctx, sp);
+
+ case 'c':
+ sp->wstr = &(wchar_t){ va_arg(ctx->ap, int) };
+ sp->len = 1;
+ return push_str(ctx, sp);
+
+ case 's':
+ if (sp->long_arg) {
+ sp->wstr = va_arg(ctx->ap, const wchar_t *) ?: L"(null)";
+ sp->len = wcsnlen(sp->wstr, sp->len);
+ } else {
+ sp->str = va_arg(ctx->ap, const char *) ?: "(null)";
+ sp->len = strnlen8(sp->str, sp->len);
+ }
+ return push_str(ctx, sp);
+
+ case 'd':
+ case 'i':
+ case 'u':
+ case 'x':
+ case 'X':
+ sp->lowercase = *ctx->format == 'x';
+ sp->is_signed = IN_SET(*ctx->format, 'd', 'i');
+ sp->base = IN_SET(*ctx->format, 'x', 'X') ? 16 : 10;
+ if (sp->len == SIZE_MAX)
+ sp->len = 1;
+
+ uint64_t v;
+ if (sp->longlong_arg)
+ v = sp->is_signed ? (uint64_t) va_arg(ctx->ap, long long) :
+ va_arg(ctx->ap, unsigned long long);
+ else if (sp->long_arg)
+ v = sp->is_signed ? (uint64_t) va_arg(ctx->ap, long) : va_arg(ctx->ap, unsigned long);
+ else
+ v = sp->is_signed ? (uint64_t) va_arg(ctx->ap, int) : va_arg(ctx->ap, unsigned);
+
+ return push_num(ctx, sp, v);
+
+ case 'p': {
+ const void *ptr = va_arg(ctx->ap, const void *);
+ if (!ptr) {
+ sp->str = NULLSTR;
+ sp->len = STRLEN(NULLSTR);
+ return push_str(ctx, sp);
+ }
+
+ sp->base = 16;
+ sp->lowercase = true;
+ sp->alternative_form = true;
+ sp->len = 0; /* Precision is ignored for %p. */
+ return push_num(ctx, sp, (uintptr_t) ptr);
+ }
+
+ case 'm': {
+ sp->str = status_to_string(ctx->status);
+ if (sp->str) {
+ sp->len = strlen8(sp->str);
+ return push_str(ctx, sp);
+ }
+
+ sp->base = 16;
+ sp->lowercase = true;
+ sp->alternative_form = true;
+ sp->len = 0;
+ return push_num(ctx, sp, ctx->status);
+ }
+
+ default:
+ assert_not_reached();
+ }
+}
+
+/* printf_internal is largely compatible to userspace vasprintf. Any features omitted should trigger asserts.
+ *
+ * Supported:
+ * - Flags: #, 0, +, -, space
+ * - Lengths: h, hh, l, ll, z, j, t
+ * - Specifiers: %, c, s, u, i, d, x, X, p, m
+ * - Precision and width (inline or as int arg using *)
+ *
+ * Notable differences:
+ * - Passing NULL to %s is permitted and will print "(null)"
+ * - %p will also use "(null)"
+ * - The provided EFI_STATUS is used for %m instead of errno
+ * - "\n" is translated to "\r\n" */
+_printf_(2, 0) static char16_t *printf_internal(EFI_STATUS status, const char *format, va_list ap, bool ret) {
+ assert(format);
+
+ FormatContext ctx = {
+ .buf = ctx.stack_buf,
+ .n_buf = ELEMENTSOF(ctx.stack_buf),
+ .format = format,
+ .status = status,
+ };
+
+ /* We cannot put this into the struct without making a copy. */
+ va_copy(ctx.ap, ap);
+
+ while (*ctx.format != '\0') {
+ SpecifierContext sp = { .len = SIZE_MAX };
+
+ switch (*ctx.format) {
+ case '%':
+ ctx.format++;
+ while (!handle_format_specifier(&ctx, &sp))
+ ctx.format++;
+ ctx.format++;
+ break;
+ case '\n':
+ ctx.format++;
+ sp.str = "\r\n";
+ sp.len = 2;
+ push_str(&ctx, &sp);
+ break;
+ default:
+ sp.str = ctx.format++;
+ while (!IN_SET(*ctx.format, '%', '\n', '\0'))
+ ctx.format++;
+ sp.len = ctx.format - sp.str;
+ push_str(&ctx, &sp);
+ }
+ }
+
+ va_end(ctx.ap);
+
+ assert(ctx.n < ctx.n_buf);
+ ctx.buf[ctx.n++] = '\0';
+
+ if (ret) {
+ if (ctx.dyn_buf)
+ return TAKE_PTR(ctx.dyn_buf);
+
+ char16_t *ret_buf = xnew(char16_t, ctx.n);
+ memcpy(ret_buf, ctx.buf, ctx.n * sizeof(*ctx.buf));
+ return ret_buf;
+ }
+
+#if SD_BOOT
+ ST->ConOut->OutputString(ST->ConOut, ctx.buf);
+#endif
+
+ return mfree(ctx.dyn_buf);
+}
+
+void printf_status(EFI_STATUS status, const char *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ printf_internal(status, format, ap, false);
+ va_end(ap);
+}
+
+void vprintf_status(EFI_STATUS status, const char *format, va_list ap) {
+ printf_internal(status, format, ap, false);
+}
+
+char16_t *xasprintf_status(EFI_STATUS status, const char *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ char16_t *ret = printf_internal(status, format, ap, true);
+ va_end(ap);
+ return ret;
+}
+
+char16_t *xvasprintf_status(EFI_STATUS status, const char *format, va_list ap) {
+ return printf_internal(status, format, ap, true);
+}
+
#if SD_BOOT
/* To provide the actual implementation for these we need to remove the redirection to the builtins. */
# undef memcmp
diff --git a/src/boot/efi/efi-string.h b/src/boot/efi/efi-string.h
index aaa9b399c8..2a28db3593 100644
--- a/src/boot/efi/efi-string.h
+++ b/src/boot/efi/efi-string.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
+#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <uchar.h>
@@ -109,7 +110,32 @@ bool efi_fnmatch(const char16_t *pattern, const char16_t *haystack);
bool parse_number8(const char *s, uint64_t *ret_u, const char **ret_tail);
bool parse_number16(const char16_t *s, uint64_t *ret_u, const char16_t **ret_tail);
+typedef size_t EFI_STATUS;
+
+#if !SD_BOOT
+/* Provide these for unit testing. */
+enum {
+ EFI_ERROR_MASK = ((EFI_STATUS) 1 << (sizeof(EFI_STATUS) * CHAR_BIT - 1)),
+ EFI_SUCCESS = 0,
+ EFI_LOAD_ERROR = 1 | EFI_ERROR_MASK,
+};
+#endif
+
+#ifdef __clang__
+# define _gnu_printf_(a, b) _printf_(a, b)
+#else
+# define _gnu_printf_(a, b) __attribute__((format(gnu_printf, a, b)))
+#endif
+
+_gnu_printf_(2, 3) void printf_status(EFI_STATUS status, const char *format, ...);
+_gnu_printf_(2, 0) void vprintf_status(EFI_STATUS status, const char *format, va_list ap);
+_gnu_printf_(2, 3) _warn_unused_result_ char16_t *xasprintf_status(EFI_STATUS status, const char *format, ...);
+_gnu_printf_(2, 0) _warn_unused_result_ char16_t *xvasprintf_status(EFI_STATUS status, const char *format, va_list ap);
+
#if SD_BOOT
+# define printf(...) printf_status(EFI_SUCCESS, __VA_ARGS__)
+# define xasprintf(...) xasprintf_status(EFI_SUCCESS, __VA_ARGS__)
+
/* The compiler normally has knowledge about standard functions such as memcmp, but this is not the case when
* compiling with -ffreestanding. By referring to builtins, the compiler can check arguments and do
* optimizations again. Note that we still need to provide implementations as the compiler is free to not
diff --git a/src/boot/efi/fuzz-efi-printf.c b/src/boot/efi/fuzz-efi-printf.c
new file mode 100644
index 0000000000..218a427cef
--- /dev/null
+++ b/src/boot/efi/fuzz-efi-printf.c
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "alloc-util.h"
+#include "efi-string.h"
+#include "fuzz.h"
+#include "utf8.h"
+
+typedef struct {
+ EFI_STATUS status;
+ int16_t field_width;
+ int16_t precision;
+ const void *ptr;
+ char c;
+ unsigned char uchar;
+ signed char schar;
+ unsigned short ushort;
+ signed short sshort;
+ unsigned int uint;
+ signed int sint;
+ unsigned long ulong;
+ signed long slong;
+ unsigned long long ulonglong;
+ signed long long slonglong;
+ size_t size;
+ ssize_t ssize;
+ intmax_t intmax;
+ uintmax_t uintmax;
+ ptrdiff_t ptrdiff;
+ char str[];
+} Input;
+
+#define PRINTF_ONE(...) \
+ ({ \
+ _cleanup_free_ char16_t *_ret = xasprintf_status(__VA_ARGS__); \
+ DO_NOT_OPTIMIZE(_ret); \
+ })
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ if (outside_size_range(size, sizeof(Input), 1024 * 1024))
+ return 0;
+
+ const Input *i = (const Input *) data;
+ size_t len = size - offsetof(Input, str);
+
+ PRINTF_ONE(i->status, "%*.*s", i->field_width, (int) len, i->str);
+ PRINTF_ONE(i->status, "%*.*ls", i->field_width, (int) (len / sizeof(wchar_t)), (const wchar_t *) i->str);
+
+ PRINTF_ONE(i->status, "%% %*.*m", i->field_width, i->precision);
+ PRINTF_ONE(i->status, "%*p", i->field_width, i->ptr);
+ PRINTF_ONE(i->status, "%*c %12340c %56789c", i->field_width, i->c, i->c, i->c);
+
+ PRINTF_ONE(i->status, "%*.*hhu", i->field_width, i->precision, i->uchar);
+ PRINTF_ONE(i->status, "%*.*hhi", i->field_width, i->precision, i->schar);
+ PRINTF_ONE(i->status, "%*.*hu", i->field_width, i->precision, i->ushort);
+ PRINTF_ONE(i->status, "%*.*hi", i->field_width, i->precision, i->sshort);
+ PRINTF_ONE(i->status, "%*.*u", i->field_width, i->precision, i->uint);
+ PRINTF_ONE(i->status, "%*.*i", i->field_width, i->precision, i->sint);
+ PRINTF_ONE(i->status, "%*.*lu", i->field_width, i->precision, i->ulong);
+ PRINTF_ONE(i->status, "%*.*li", i->field_width, i->precision, i->slong);
+ PRINTF_ONE(i->status, "%*.*llu", i->field_width, i->precision, i->ulonglong);
+ PRINTF_ONE(i->status, "%*.*lli", i->field_width, i->precision, i->slonglong);
+
+ PRINTF_ONE(i->status, "%+*.*hhi", i->field_width, i->precision, i->schar);
+ PRINTF_ONE(i->status, "%-*.*hi", i->field_width, i->precision, i->sshort);
+ PRINTF_ONE(i->status, "% *.*i", i->field_width, i->precision, i->sint);
+ PRINTF_ONE(i->status, "%0*li", i->field_width, i->slong);
+ PRINTF_ONE(i->status, "%#*.*llx", i->field_width, i->precision, i->ulonglong);
+
+ PRINTF_ONE(i->status, "%-*.*zx", i->field_width, i->precision, i->size);
+ PRINTF_ONE(i->status, "% *.*zi", i->field_width, i->precision, i->ssize);
+ PRINTF_ONE(i->status, "%0*ji", i->field_width, i->intmax);
+ PRINTF_ONE(i->status, "%#0*jX", i->field_width, i->uintmax);
+ PRINTF_ONE(i->status, "%*.*ti", i->field_width, i->precision, i->ptrdiff);
+
+ return 0;
+}
diff --git a/src/boot/efi/meson.build b/src/boot/efi/meson.build
index bba3b62d3c..ed332262e8 100644
--- a/src/boot/efi/meson.build
+++ b/src/boot/efi/meson.build
@@ -423,6 +423,7 @@ if efi_arch[1] in ['ia32', 'x86_64', 'arm', 'aarch64']
fuzzers += [
[files('fuzz-bcd.c', 'bcd.c', 'efi-string.c')],
[files('fuzz-efi-string.c', 'efi-string.c')],
+ [files('fuzz-efi-printf.c', 'efi-string.c')],
]
endif
diff --git a/src/boot/efi/missing_efi.h b/src/boot/efi/missing_efi.h
index b446e0399f..a71c8fa7e2 100644
--- a/src/boot/efi/missing_efi.h
+++ b/src/boot/efi/missing_efi.h
@@ -417,3 +417,15 @@ struct EFI_BOOT_MANAGER_POLICY_PROTOCOL {
EFI_GUID *Class);
};
#endif
+
+#ifndef EFI_WARN_UNKNOWN_GLYPH
+# define EFI_WARN_UNKNOWN_GLYPH 1
+#endif
+
+#ifndef EFI_WARN_RESET_REQUIRED
+# define EFI_WARN_STALE_DATA 5
+# define EFI_WARN_FILE_SYSTEM 6
+# define EFI_WARN_RESET_REQUIRED 7
+# define EFI_IP_ADDRESS_CONFLICT EFIERR(34)
+# define EFI_HTTP_ERROR EFIERR(35)
+#endif
diff --git a/src/boot/efi/test-efi-string.c b/src/boot/efi/test-efi-string.c
index 7b43e1d629..c26973d8bd 100644
--- a/src/boot/efi/test-efi-string.c
+++ b/src/boot/efi/test-efi-string.c
@@ -468,6 +468,148 @@ TEST(parse_number16) {
assert_se(streq16(tail, u"rest"));
}
+_printf_(1, 2) static void test_printf_one(const char *format, ...) {
+ va_list ap, ap_efi;
+ va_start(ap, format);
+ va_copy(ap_efi, ap);
+
+ _cleanup_free_ char *buf = NULL;
+ int r = vasprintf(&buf, format, ap);
+ assert_se(r >= 0);
+ log_info("/* %s(%s) -> \"%.100s\" */", __func__, format, buf);
+
+ _cleanup_free_ char16_t *buf_efi = xvasprintf_status(0, format, ap_efi);
+
+ bool eq = true;
+ for (size_t i = 0; i <= (size_t) r; i++) {
+ if (buf[i] != buf_efi[i])
+ eq = false;
+ buf[i] = buf_efi[i];
+ }
+
+ log_info("%.100s", buf);
+ assert_se(eq);
+
+ va_end(ap);
+ va_end(ap_efi);
+}
+
+TEST(xvasprintf_status) {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-zero-length"
+ test_printf_one("");
+#pragma GCC diagnostic pop
+ test_printf_one("string");
+ test_printf_one("%%-%%%%");
+
+ test_printf_one("%p %p %32p %*p %*p", NULL, (void *) 0xF, &errno, 0, &saved_argc, 20, &saved_argv);
+ test_printf_one("%-10p %-32p %-*p %-*p", NULL, &errno, 0, &saved_argc, 20, &saved_argv);
+
+ test_printf_one("%c %3c %*c %*c %-8c", '1', '!', 0, 'a', 9, '_', '>');
+
+ test_printf_one("%s %s %s", "012345", "6789", "ab");
+ test_printf_one("%.4s %.4s %.4s %.0s", "cdefgh", "ijkl", "mn", "@");
+ test_printf_one("%8s %8s %8s", "opqrst", "uvwx", "yz");
+ test_printf_one("%8.4s %8.4s %8.4s %8.0s", "ABCDEF", "GHIJ", "KL", "$");
+ test_printf_one("%4.8s %4.8s %4.8s", "ABCDEFGHIJ", "ABCDEFGH", "ABCD");
+
+ test_printf_one("%.*s %.*s %.*s %.*s", 4, "012345", 4, "6789", 4, "ab", 0, "&");
+ test_printf_one("%*s %*s %*s", 8, "cdefgh", 8, "ijkl", 8, "mn");
+ test_printf_one("%*.*s %*.*s %*.*s %*.*s", 8, 4, "opqrst", 8, 4, "uvwx", 8, 4, "yz", 8, 0, "#");
+ test_printf_one("%*.*s %*.*s %*.*s", 3, 8, "OPQRST", 3, 8, "UVWX", 3, 8, "YZ");
+
+ test_printf_one("%ls %ls %ls", L"012345", L"6789", L"ab");
+ test_printf_one("%.4ls %.4ls %.4ls %.0ls", L"cdefgh", L"ijkl", L"mn", L"@");
+ test_printf_one("%8ls %8ls %8ls", L"opqrst", L"uvwx", L"yz");
+ test_printf_one("%8.4ls %8.4ls %8.4ls %8.0ls", L"ABCDEF", L"GHIJ", L"KL", L"$");
+ test_printf_one("%4.8ls %4.8ls %4.8ls", L"ABCDEFGHIJ", L"ABCDEFGH", L"ABCD");
+
+ test_printf_one("%.*ls %.*ls %.*ls %.*ls", 4, L"012345", 4, L"6789", 4, L"ab", 0, L"&");
+ test_printf_one("%*ls %*ls %*ls", 8, L"cdefgh", 8, L"ijkl", 8, L"mn");
+ test_printf_one("%*.*ls %*.*ls %*.*ls %*.*ls", 8, 4, L"opqrst", 8, 4, L"uvwx", 8, 4, L"yz", 8, 0, L"#");
+ test_printf_one("%*.*ls %*.*ls %*.*ls", 3, 8, L"OPQRST", 3, 8, L"UVWX", 3, 8, L"YZ");
+
+ test_printf_one("%-14s %-10.0s %-10.3s", "left", "", "chopped");
+ test_printf_one("%-14ls %-10.0ls %-10.3ls", L"left", L"", L"chopped");
+
+ test_printf_one("%.6s", (char[]){ 'n', 'o', ' ', 'n', 'u', 'l' });
+ test_printf_one("%.6ls", (wchar_t[]){ 'n', 'o', ' ', 'n', 'u', 'l' });
+
+ test_printf_one("%u %u %u", 0U, 42U, 1234567890U);
+ test_printf_one("%i %i %i", 0, -42, -1234567890);
+ test_printf_one("%x %x %x", 0x0U, 0x42U, 0x123ABCU);
+ test_printf_one("%X %X %X", 0x1U, 0x43U, 0x234BCDU);
+ test_printf_one("%#x %#x %#x", 0x2U, 0x44U, 0x345CDEU);
+ test_printf_one("%#X %#X %#X", 0x3U, 0x45U, 0x456FEDU);
+
+ test_printf_one("%u %lu %llu %zu", UINT_MAX, ULONG_MAX, ULLONG_MAX, SIZE_MAX);
+ test_printf_one("%i %i %zi", INT_MIN, INT_MAX, SSIZE_MAX);
+ test_printf_one("%li %li %lli %lli", LONG_MIN, LONG_MAX, LLONG_MIN, LLONG_MAX);
+ test_printf_one("%x %#lx %llx %#zx", UINT_MAX, ULONG_MAX, ULLONG_MAX, SIZE_MAX);
+ test_printf_one("%X %#lX %llX %#zX", UINT_MAX, ULONG_MAX, ULLONG_MAX, SIZE_MAX);
+ test_printf_one("%ju %ji %ji", UINTMAX_MAX, INTMAX_MIN, INTMAX_MAX);
+ test_printf_one("%ti %ti", PTRDIFF_MIN, PTRDIFF_MAX);
+
+ test_printf_one("%" PRIu32 " %" PRIi32 " %" PRIi32, UINT32_MAX, INT32_MIN, INT32_MAX);
+ test_printf_one("%" PRIx32 " %" PRIX32, UINT32_MAX, UINT32_MAX);
+ test_printf_one("%#" PRIx32 " %#" PRIX32, UINT32_MAX, UINT32_MAX);
+
+ test_printf_one("%" PRIu64 " %" PRIi64 " %" PRIi64, UINT64_MAX, INT64_MIN, INT64_MAX);
+ test_printf_one("%" PRIx64 " %" PRIX64, UINT64_MAX, UINT64_MAX);
+ test_printf_one("%#" PRIx64 " %#" PRIX64, UINT64_MAX, UINT64_MAX);
+
+ test_printf_one("%.11u %.11i %.11x %.11X %#.11x %#.11X", 1U, -2, 3U, 0xA1U, 0xB2U, 0xC3U);
+ test_printf_one("%13u %13i %13x %13X %#13x %#13X", 4U, -5, 6U, 0xD4U, 0xE5U, 0xF6U);
+ test_printf_one("%9.5u %9.5i %9.5x %9.5X %#9.5x %#9.5X", 7U, -8, 9U, 0xA9U, 0xB8U, 0xC7U);
+ test_printf_one("%09u %09i %09x %09X %#09x %#09X", 4U, -5, 6U, 0xD6U, 0xE5U, 0xF4U);
+
+ test_printf_one("%*u %.*u %*i %.*i", 15, 42U, 15, 43U, 15, -42, 15, -43);
+ test_printf_one("%*.*u %*.*i", 14, 10, 13U, 14, 10, -14);
+ test_printf_one("%*x %*X %.*x %.*X", 15, 0x1AU, 15, 0x2BU, 15, 0x3CU, 15, 0x4DU);
+ test_printf_one("%#*x %#*X %#.*x %#.*X", 15, 0xA1U, 15, 0xB2U, 15, 0xC3U, 15, 0xD4U);
+ test_printf_one("%*.*x %*.*X", 14, 10, 0x1AU, 14, 10, 0x2BU);
+ test_printf_one("%#*.*x %#*.*X", 14, 10, 0x3CU, 14, 10, 0x4DU);
+
+ test_printf_one("%+.5i %+.5i % .7i % .7i", -15, 51, -15, 51);
+ test_printf_one("%+5.i %+5.i % 7.i % 7.i", -15, 51, -15, 51);
+
+ test_printf_one("%-10u %-10i %-10x %#-10X %- 10i", 1u, -2, 0xA2D2u, 0XB3F4u, -512);
+ test_printf_one("%-10.6u %-10.6i %-10.6x %#-10.6X %- 10.6i", 1u, -2, 0xA2D2u, 0XB3F4u, -512);
+ test_printf_one("%-6.10u %-6.10i %-6.10x %#-6.10X %- 6.10i", 3u, -4, 0x2A2Du, 0X3B4Fu, -215);
+ test_printf_one("%*.u %.*i %.*i", -4, 9u, -4, 8, -4, -6);
+
+ test_printf_one("%.0u %.0i %.0x %.0X", 0u, 0, 0u, 0u);
+ test_printf_one("%.*u %.*i %.*x %.*X", 0, 0u, 0, 0, 0, 0u, 0, 0u);
+ test_printf_one("%*u %*i %*x %*X", -1, 0u, -1, 0, -1, 0u, -1, 0u);
+
+ test_printf_one("%*s%*s%*s", 256, "", 256, "", 4096, ""); /* Test buf growing. */
+ test_printf_one("%0*i%0*i%0*i", 256, 0, 256, 0, 4096, 0); /* Test buf growing. */
+ test_printf_one("%0*i", INT16_MAX, 0); /* Poor programmer's memzero. */
+
+ /* Non printf-compatible behavior tests below. */
+ char16_t *s;
+
+ assert_se(s = xasprintf_status(0, "\n \r \r\n"));
+ assert_se(streq16(s, u"\r\n \r \r\r\n"));
+ s = mfree(s);
+
+ assert_se(s = xasprintf_status(EFI_SUCCESS, "%m"));
+ assert_se(streq16(s, u"Success"));
+ s = mfree(s);
+
+ assert_se(s = xasprintf_status(EFI_SUCCESS, "%15m"));
+ assert_se(streq16(s, u" Success"));
+ s = mfree(s);
+
+ assert_se(s = xasprintf_status(EFI_LOAD_ERROR, "%m"));
+ assert_se(streq16(s, u"Load error"));
+ s = mfree(s);
+
+ assert_se(s = xasprintf_status(0x42, "%m"));
+ assert_se(streq16(s, u"0x42"));
+ s = mfree(s);
+}
+
TEST(efi_memcmp) {
assert_se(efi_memcmp(NULL, NULL, 0) == 0);
assert_se(efi_memcmp(NULL, NULL, 1) == 0);

View File

@ -0,0 +1,965 @@
From e5dea043b9c20f648bffffd581a0e624f5622a16 Mon Sep 17 00:00:00 2001
From: Jan Janssen <medhefgo@web.de>
Date: Fri, 10 Jun 2022 19:06:57 +0200
Subject: [PATCH] boot: Use printf for error logging
This also drops the _stall suffix in anticipation of the next commit.
(cherry picked from commit c2c6203556f842820ca09e0653c123305f2ba6d2)
Related: RHEL-16952
---
src/boot/efi/assert.c | 12 ---------
src/boot/efi/boot.c | 54 +++++++++++++++++++-------------------
src/boot/efi/console.c | 6 ++---
src/boot/efi/cpio.c | 23 ++++++++--------
src/boot/efi/devicetree.c | 3 +--
src/boot/efi/drivers.c | 16 +++++------
src/boot/efi/linux.c | 10 +++----
src/boot/efi/linux_x86.c | 15 +++++------
src/boot/efi/log.c | 34 ++++++++++++++++++++++++
src/boot/efi/log.h | 9 +++++++
src/boot/efi/measure.c | 2 +-
src/boot/efi/meson.build | 3 ++-
src/boot/efi/pe.c | 2 +-
src/boot/efi/random-seed.c | 44 +++++++++++++++----------------
src/boot/efi/secure-boot.c | 11 ++++----
src/boot/efi/stub.c | 6 ++---
src/boot/efi/util.c | 30 +--------------------
src/boot/efi/util.h | 12 +--------
18 files changed, 141 insertions(+), 151 deletions(-)
delete mode 100644 src/boot/efi/assert.c
create mode 100644 src/boot/efi/log.c
create mode 100644 src/boot/efi/log.h
diff --git a/src/boot/efi/assert.c b/src/boot/efi/assert.c
deleted file mode 100644
index bb16d2bf93..0000000000
--- a/src/boot/efi/assert.c
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include <efi.h>
-#include <efilib.h>
-
-#include "util.h"
-
-void efi_assert(const char *expr, const char *file, unsigned line, const char *function) {
- log_error_stall(L"systemd-boot assertion '%a' failed at %a:%u, function %a(). Halting.", expr, file, line, function);
- for (;;)
- BS->Stall(60 * 1000 * 1000);
-}
diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
index a39c356158..1e7b7a0fa7 100644
--- a/src/boot/efi/boot.c
+++ b/src/boot/efi/boot.c
@@ -587,14 +587,14 @@ static EFI_STATUS reboot_into_firmware(void) {
EFI_STATUS err;
if (!FLAGS_SET(get_os_indications_supported(), EFI_OS_INDICATIONS_BOOT_TO_FW_UI))
- return log_error_status_stall(EFI_UNSUPPORTED, L"Reboot to firmware interface not supported.");
+ return log_error_status(EFI_UNSUPPORTED, "Reboot to firmware interface not supported.");
(void) efivar_get_uint64_le(EFI_GLOBAL_GUID, L"OsIndications", &osind);
osind |= EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
err = efivar_set_uint64_le(EFI_GLOBAL_GUID, L"OsIndications", osind, EFI_VARIABLE_NON_VOLATILE);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Error setting OsIndications: %r", err);
+ return log_error_status(err, "Error setting OsIndications: %m");
RT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
assert_not_reached();
@@ -634,7 +634,7 @@ static bool menu_run(
config->console_mode_efivar : config->console_mode);
if (err != EFI_SUCCESS) {
clear_screen(COLOR_NORMAL);
- log_error_stall(L"Error switching console mode: %r", err);
+ log_error_status(err, "Error switching console mode: %m");
}
size_t line_width = 0, entry_padding = 3;
@@ -1177,7 +1177,7 @@ static void config_defaults_load_from_file(Config *config, char *content) {
else {
uint64_t u;
if (!parse_number8(value, &u, NULL) || u > TIMEOUT_TYPE_MAX) {
- log_error_stall(L"Error parsing 'timeout' config option: %a", value);
+ log_error("Error parsing 'timeout' config option: %s", value);
continue;
}
config->timeout_sec_config = u;
@@ -1188,7 +1188,7 @@ static void config_defaults_load_from_file(Config *config, char *content) {
if (streq8(key, "default")) {
if (value[0] == '@' && !strcaseeq8(value, "@saved")) {
- log_error_stall(L"Unsupported special entry identifier: %a", value);
+ log_error("Unsupported special entry identifier: %s", value);
continue;
}
free(config->entry_default_config);
@@ -1199,35 +1199,35 @@ static void config_defaults_load_from_file(Config *config, char *content) {
if (streq8(key, "editor")) {
err = parse_boolean(value, &config->editor);
if (err != EFI_SUCCESS)
- log_error_stall(L"Error parsing 'editor' config option: %a", value);
+ log_error("Error parsing 'editor' config option: %s", value);
continue;
}
if (streq8(key, "auto-entries")) {
err = parse_boolean(value, &config->auto_entries);
if (err != EFI_SUCCESS)
- log_error_stall(L"Error parsing 'auto-entries' config option: %a", value);
+ log_error("Error parsing 'auto-entries' config option: %s", value);
continue;
}
if (streq8(key, "auto-firmware")) {
err = parse_boolean(value, &config->auto_firmware);
if (err != EFI_SUCCESS)
- log_error_stall(L"Error parsing 'auto-firmware' config option: %a", value);
+ log_error("Error parsing 'auto-firmware' config option: %s", value);
continue;
}
if (streq8(key, "beep")) {
err = parse_boolean(value, &config->beep);
if (err != EFI_SUCCESS)
- log_error_stall(L"Error parsing 'beep' config option: %a", value);
+ log_error("Error parsing 'beep' config option: %s", value);
continue;
}
if (streq8(key, "reboot-for-bitlocker")) {
err = parse_boolean(value, &config->reboot_for_bitlocker);
if (err != EFI_SUCCESS)
- log_error_stall(L"Error parsing 'reboot-for-bitlocker' config option: %a", value);
+ log_error("Error parsing 'reboot-for-bitlocker' config option: %s", value);
}
if (streq8(key, "secure-boot-enroll")) {
@@ -1238,7 +1238,7 @@ static void config_defaults_load_from_file(Config *config, char *content) {
else if (streq8(value, "off"))
config->secure_boot_enroll = ENROLL_OFF;
else
- log_error_stall(L"Error parsing 'secure-boot-enroll' config option: %a", value);
+ log_error("Error parsing 'secure-boot-enroll' config option: %s", value);
continue;
}
@@ -1252,7 +1252,7 @@ static void config_defaults_load_from_file(Config *config, char *content) {
else {
uint64_t u;
if (!parse_number8(value, &u, NULL) || u > CONSOLE_MODE_RANGE_MAX) {
- log_error_stall(L"Error parsing 'console-mode' config option: %a", value);
+ log_error("Error parsing 'console-mode' config option: %s", value);
continue;
}
config->console_mode = u;
@@ -1356,7 +1356,7 @@ static void config_entry_bump_counters(ConfigEntry *entry, EFI_FILE *root_dir) {
strcpy16(file_info->FileName, entry->next_name);
err = handle->SetInfo(handle, &GenericFileInfo, file_info_size, file_info);
if (err != EFI_SUCCESS) {
- log_error_stall(L"Failed to rename '%s' to '%s', ignoring: %r", old_path, entry->next_name, err);
+ log_error_status(err, "Failed to rename '%ls' to '%ls', ignoring: %m", old_path, entry->next_name);
return;
}
@@ -1564,7 +1564,7 @@ static void config_load_defaults(Config *config, EFI_FILE *root_dir) {
if (err == EFI_SUCCESS)
config->timeout_sec = config->timeout_sec_efivar;
else if (err != EFI_NOT_FOUND)
- log_error_stall(u"Error reading LoaderConfigTimeout EFI variable: %r", err);
+ log_error_status(err, "Error reading LoaderConfigTimeout EFI variable: %m");
err = efivar_get_timeout(u"LoaderConfigTimeoutOneShot", &config->timeout_sec);
if (err == EFI_SUCCESS) {
@@ -1573,7 +1573,7 @@ static void config_load_defaults(Config *config, EFI_FILE *root_dir) {
config->force_menu = true; /* force the menu when this is set */
} else if (err != EFI_NOT_FOUND)
- log_error_stall(u"Error reading LoaderConfigTimeoutOneShot EFI variable: %r", err);
+ log_error_status(err, "Error reading LoaderConfigTimeoutOneShot EFI variable: %m");
err = efivar_get_uint_string(LOADER_GUID, L"LoaderConfigConsoleMode", &value);
if (err == EFI_SUCCESS)
@@ -2327,38 +2327,38 @@ static EFI_STATUS image_start(
_cleanup_(file_closep) EFI_FILE *image_root = NULL;
err = open_volume(entry->device, &image_root);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Error opening root path: %r", err);
+ return log_error_status(err, "Error opening root path: %m");
err = make_file_device_path(entry->device, entry->loader, &path);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Error making file device path: %r", err);
+ return log_error_status(err, "Error making file device path: %m");
size_t initrd_size = 0;
_cleanup_free_ void *initrd = NULL;
_cleanup_free_ char16_t *options_initrd = NULL;
err = initrd_prepare(image_root, entry, &options_initrd, &initrd, &initrd_size);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Error preparing initrd: %r", err);
+ return log_error_status(err, "Error preparing initrd: %m");
err = shim_load_image(parent_image, path, &image);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Error loading %s: %r", entry->loader, err);
+ return log_error_status(err, "Error loading %ls: %m", entry->loader);
if (entry->devicetree) {
err = devicetree_install(&dtstate, image_root, entry->devicetree);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Error loading %s: %r", entry->devicetree, err);
+ return log_error_status(err, "Error loading %ls: %m", entry->devicetree);
}
_cleanup_(cleanup_initrd) EFI_HANDLE initrd_handle = NULL;
err = initrd_register(initrd, initrd_size, &initrd_handle);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Error registering initrd: %r", err);
+ return log_error_status(err, "Error registering initrd: %m");
EFI_LOADED_IMAGE_PROTOCOL *loaded_image;
err = BS->HandleProtocol(image, &LoadedImageProtocol, (void **) &loaded_image);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Error getting LoadedImageProtocol handle: %r", err);
+ return log_error_status(err, "Error getting LoadedImageProtocol handle: %m");
char16_t *options = options_initrd ?: entry->options;
if (options) {
@@ -2382,7 +2382,7 @@ static EFI_STATUS image_start(
err = pe_kernel_info(loaded_image->ImageBase, &compat_address);
if (err != EFI_SUCCESS) {
if (err != EFI_UNSUPPORTED)
- return log_error_status_stall(err, L"Error finding kernel compat entry address: %r", err);
+ return log_error_status(err, "Error finding kernel compat entry address: %m");
} else if (compat_address > 0) {
EFI_IMAGE_ENTRY_POINT kernel_entry =
(EFI_IMAGE_ENTRY_POINT) ((uint8_t *) loaded_image->ImageBase + compat_address);
@@ -2395,7 +2395,7 @@ static EFI_STATUS image_start(
err = EFI_UNSUPPORTED;
}
- return log_error_status_stall(err, L"Failed to execute %s (%s): %r", entry->title_show, entry->loader, err);
+ return log_error_status(err, "Failed to execute %ls (%ls): %m", entry->title_show, entry->loader);
}
static void config_free(Config *config) {
@@ -2634,7 +2634,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Error getting a LoadedImageProtocol handle: %r", err);
+ return log_error_status(err, "Error getting a LoadedImageProtocol handle: %m");
(void) device_path_to_str(loaded_image->FilePath, &loaded_image_path);
@@ -2642,14 +2642,14 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
err = discover_root_dir(loaded_image, &root_dir);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Unable to open root directory: %r", err);
+ return log_error_status(err, "Unable to open root directory: %m");
(void) load_drivers(image, loaded_image, root_dir);
config_load_all_entries(&config, loaded_image, loaded_image_path, root_dir);
if (config.entry_count == 0) {
- log_error_stall(L"No loader found. Configuration files in \\loader\\entries\\*.conf are needed.");
+ log_error("No loader found. Configuration files in \\loader\\entries\\*.conf are needed.");
goto out;
}
diff --git a/src/boot/efi/console.c b/src/boot/efi/console.c
index c3d9ff0e82..b876ff2bd7 100644
--- a/src/boot/efi/console.c
+++ b/src/boot/efi/console.c
@@ -83,7 +83,7 @@ EFI_STATUS console_key_read(uint64_t *key, uint64_t timeout_usec) {
err = BS->CreateEvent(EVT_TIMER, 0, NULL, NULL, &timer);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Error creating timer event: %r", err);
+ return log_error_status(err, "Error creating timer event: %m");
EFI_EVENT events[] = {
timer,
@@ -104,14 +104,14 @@ EFI_STATUS console_key_read(uint64_t *key, uint64_t timeout_usec) {
TimerRelative,
MIN(timeout_usec, watchdog_ping_usec) * 10);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Error arming timer event: %r", err);
+ return log_error_status(err, "Error arming timer event: %m");
(void) BS->SetWatchdogTimer(watchdog_timeout_sec, 0x10000, 0, NULL);
err = BS->WaitForEvent(n_events, events, &index);
(void) BS->SetWatchdogTimer(watchdog_timeout_sec, 0x10000, 0, NULL);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Error waiting for events: %r", err);
+ return log_error_status(err, "Error waiting for events: %m");
/* We have keyboard input, process it after this loop. */
if (timer != events[index])
diff --git a/src/boot/efi/cpio.c b/src/boot/efi/cpio.c
index bb424a44d5..62773ded9a 100644
--- a/src/boot/efi/cpio.c
+++ b/src/boot/efi/cpio.c
@@ -326,7 +326,7 @@ static EFI_STATUS measure_cpio(
tpm_description,
&m);
if (err != EFI_SUCCESS) {
- log_error_stall(L"Unable to add initrd TPM measurement for PCR %u (%s), ignoring: %r", tpm_pcr[i], tpm_description, err);
+ log_error_status(err, "Unable to add initrd TPM measurement for PCR %u (%ls), ignoring: %m", tpm_pcr[i], tpm_description);
measured = false;
continue;
}
@@ -401,8 +401,7 @@ EFI_STATUS pack_cpio(
* its file handles. */
goto nothing;
if (err != EFI_SUCCESS)
- return log_error_status_stall(
- err, L"Unable to open root directory: %r", err);
+ return log_error_status(err, "Unable to open root directory: %m");
if (!dropin_dir)
dropin_dir = rel_dropin_dir = get_dropin_dir(loaded_image->FilePath);
@@ -412,14 +411,14 @@ EFI_STATUS pack_cpio(
/* No extra subdir, that's totally OK */
goto nothing;
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed to open extra directory of loaded image: %r", err);
+ return log_error_status(err, "Failed to open extra directory of loaded image: %m");
for (;;) {
_cleanup_free_ char16_t *d = NULL;
err = readdir_harder(extra_dir, &dirent, &dirent_size);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed to read extra directory of loaded image: %r", err);
+ return log_error_status(err, "Failed to read extra directory of loaded image: %m");
if (!dirent) /* End of directory */
break;
@@ -462,7 +461,7 @@ EFI_STATUS pack_cpio(
* 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);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed to pack cpio prefix: %r", err);
+ return log_error_status(err, "Failed to pack cpio prefix: %m");
for (size_t i = 0; i < n_items; i++) {
_cleanup_free_ char *content = NULL;
@@ -470,7 +469,7 @@ EFI_STATUS pack_cpio(
err = file_read(extra_dir, items[i], 0, 0, &content, &contentsize);
if (err != EFI_SUCCESS) {
- log_error_status_stall(err, L"Failed to read %s, ignoring: %r", items[i], err);
+ log_error_status(err, "Failed to read %ls, ignoring: %m", items[i]);
continue;
}
@@ -482,12 +481,12 @@ EFI_STATUS pack_cpio(
&inode,
&buffer, &buffer_size);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed to pack cpio file %s: %r", dirent->FileName, err);
+ return log_error_status(err, "Failed to pack cpio file %ls: %m", dirent->FileName);
}
err = pack_cpio_trailer(&buffer, &buffer_size);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed to pack cpio trailer: %r");
+ return log_error_status(err, "Failed to pack cpio trailer: %m");
err = measure_cpio(buffer, buffer_size, tpm_pcr, n_tpm_pcr, tpm_description, ret_measured);
if (err != EFI_SUCCESS)
@@ -539,7 +538,7 @@ EFI_STATUS pack_cpio_literal(
err = pack_cpio_prefix(target_dir_prefix, dir_mode, &inode, &buffer, &buffer_size);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed to pack cpio prefix: %r", err);
+ return log_error_status(err, "Failed to pack cpio prefix: %m");
err = pack_cpio_one(
target_filename,
@@ -549,11 +548,11 @@ EFI_STATUS pack_cpio_literal(
&inode,
&buffer, &buffer_size);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed to pack cpio file %s: %r", target_filename, err);
+ return log_error_status(err, "Failed to pack cpio file %ls: %m", target_filename);
err = pack_cpio_trailer(&buffer, &buffer_size);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed to pack cpio trailer: %r");
+ return log_error_status(err, "Failed to pack cpio trailer: %m");
err = measure_cpio(buffer, buffer_size, tpm_pcr, n_tpm_pcr, tpm_description, ret_measured);
if (err != EFI_SUCCESS)
diff --git a/src/boot/efi/devicetree.c b/src/boot/efi/devicetree.c
index f3c2e47e58..52f64a6e2f 100644
--- a/src/boot/efi/devicetree.c
+++ b/src/boot/efi/devicetree.c
@@ -36,8 +36,7 @@ static EFI_STATUS devicetree_fixup(struct devicetree_state *state, size_t len) {
err = BS->LocateProtocol(&EfiDtFixupProtocol, NULL, (void **) &fixup);
if (err != EFI_SUCCESS)
- return log_error_status_stall(EFI_SUCCESS,
- L"Could not locate device tree fixup protocol, skipping.");
+ return log_error_status(EFI_SUCCESS, "Could not locate device tree fixup protocol, skipping.");
size = devicetree_allocated(state);
err = fixup->Fixup(fixup, PHYSICAL_ADDRESS_TO_POINTER(state->addr), &size,
diff --git a/src/boot/efi/drivers.c b/src/boot/efi/drivers.c
index 41a7d8fe15..c76f8e0903 100644
--- a/src/boot/efi/drivers.c
+++ b/src/boot/efi/drivers.c
@@ -23,26 +23,26 @@ static EFI_STATUS load_one_driver(
spath = xpool_print(L"\\EFI\\systemd\\drivers\\%s", fname);
err = make_file_device_path(loaded_image->DeviceHandle, spath, &path);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Error making file device path: %r", err);
+ return log_error_status(err, "Error making file device path: %m");
err = BS->LoadImage(false, parent_image, path, NULL, 0, &image);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed to load image %s: %r", fname, err);
+ return log_error_status(err, "Failed to load image %ls: %m", fname);
err = BS->HandleProtocol(image, &LoadedImageProtocol, (void **)&loaded_image);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed to find protocol in driver image %s: %r", fname, err);
+ return log_error_status(err, "Failed to find protocol in driver image %ls: %m", fname);
if (loaded_image->ImageCodeType != EfiBootServicesCode &&
loaded_image->ImageCodeType != EfiRuntimeServicesCode)
- return log_error_status_stall(EFI_INVALID_PARAMETER, L"Image %s is not a driver, refusing.", fname);
+ return log_error("Image %ls is not a driver, refusing.", fname);
err = BS->StartImage(image, NULL, NULL);
if (err != EFI_SUCCESS) {
/* EFI_ABORTED signals an initializing driver. It uses this error code on success
* so that it is unloaded after. */
if (err != EFI_ABORTED)
- log_error_stall(L"Failed to start image %s: %r", fname, err);
+ log_error_status(err, "Failed to start image %ls: %m", fname);
return err;
}
@@ -59,7 +59,7 @@ EFI_STATUS reconnect_all_drivers(void) {
err = BS->LocateHandleBuffer(AllHandles, NULL, NULL, &n_handles, &handles);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed to get list of handles: %r", err);
+ return log_error_status(err, "Failed to get list of handles: %m");
for (size_t i = 0; i < n_handles; i++)
/* Some firmware gives us some bogus handles (or they might become bad due to
@@ -87,12 +87,12 @@ EFI_STATUS load_drivers(
if (err == EFI_NOT_FOUND)
return EFI_SUCCESS;
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed to open \\EFI\\systemd\\drivers: %r", err);
+ return log_error_status(err, "Failed to open \\EFI\\systemd\\drivers: %m");
for (;;) {
err = readdir_harder(drivers_dir, &dirent, &dirent_size);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed to read extra directory of loaded image: %r", err);
+ return log_error_status(err, "Failed to read extra directory of loaded image: %m");
if (!dirent) /* End of directory */
break;
diff --git a/src/boot/efi/linux.c b/src/boot/efi/linux.c
index 48801f9dd8..2ae68ec295 100644
--- a/src/boot/efi/linux.c
+++ b/src/boot/efi/linux.c
@@ -120,17 +120,17 @@ EFI_STATUS linux_exec(
initrd_length);
#endif
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, u"Bad kernel image: %r", err);
+ return log_error_status(err, "Bad kernel image: %m");
_cleanup_(unload_imagep) EFI_HANDLE kernel_image = NULL;
err = load_image(parent, linux_buffer, linux_length, &kernel_image);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, u"Error loading kernel image: %r", err);
+ return log_error_status(err, "Error loading kernel image: %m");
EFI_LOADED_IMAGE_PROTOCOL *loaded_image;
err = BS->HandleProtocol(kernel_image, &LoadedImageProtocol, (void **) &loaded_image);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, u"Error getting kernel loaded image protocol: %r", err);
+ return log_error_status(err, "Error getting kernel loaded image protocol: %m");
if (cmdline) {
loaded_image->LoadOptions = (void *) cmdline;
@@ -140,7 +140,7 @@ EFI_STATUS linux_exec(
_cleanup_(cleanup_initrd) EFI_HANDLE initrd_handle = NULL;
err = initrd_register(initrd_buffer, initrd_length, &initrd_handle);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, u"Error registering initrd: %r", err);
+ return log_error_status(err, "Error registering initrd: %m");
err = BS->StartImage(kernel_image, NULL, NULL);
@@ -151,5 +151,5 @@ EFI_STATUS linux_exec(
err = compat_entry(kernel_image, ST);
}
- return log_error_status_stall(err, u"Error starting kernel image: %r", err);
+ return log_error_status(err, "Error starting kernel image: %m");
}
diff --git a/src/boot/efi/linux_x86.c b/src/boot/efi/linux_x86.c
index 6a5e431107..cbd92201b6 100644
--- a/src/boot/efi/linux_x86.c
+++ b/src/boot/efi/linux_x86.c
@@ -141,28 +141,27 @@ EFI_STATUS linux_exec_efi_handover(
const BootParams *image_params = (const BootParams *) linux_buffer;
if (image_params->hdr.header != SETUP_MAGIC || image_params->hdr.boot_flag != BOOT_FLAG_MAGIC)
- return log_error_status_stall(EFI_UNSUPPORTED, u"Unsupported kernel image.");
+ return log_error_status(EFI_UNSUPPORTED, "Unsupported kernel image.");
if (image_params->hdr.version < SETUP_VERSION_2_11)
- return log_error_status_stall(EFI_UNSUPPORTED, u"Kernel too old.");
+ return log_error_status(EFI_UNSUPPORTED, "Kernel too old.");
if (!image_params->hdr.relocatable_kernel)
- return log_error_status_stall(EFI_UNSUPPORTED, u"Kernel is not relocatable.");
+ return log_error_status(EFI_UNSUPPORTED, "Kernel is not relocatable.");
/* The xloadflags were added in version 2.12+ of the boot protocol but the handover support predates
* that, so we cannot safety-check this for 2.11. */
if (image_params->hdr.version >= SETUP_VERSION_2_12 &&
!FLAGS_SET(image_params->hdr.xloadflags, XLF_EFI_HANDOVER))
- return log_error_status_stall(EFI_UNSUPPORTED, u"Kernel does not support EFI handover protocol.");
+ return log_error_status(EFI_UNSUPPORTED, "Kernel does not support EFI handover protocol.");
bool can_4g = image_params->hdr.version >= SETUP_VERSION_2_12 &&
FLAGS_SET(image_params->hdr.xloadflags, XLF_CAN_BE_LOADED_ABOVE_4G);
if (!can_4g && POINTER_TO_PHYSICAL_ADDRESS(linux_buffer) + linux_length > UINT32_MAX)
- return log_error_status_stall(
+ return log_error_status(
EFI_UNSUPPORTED,
- u"Unified kernel image was loaded above 4G, but kernel lacks support.");
+ "Unified kernel image was loaded above 4G, but kernel lacks support.");
if (!can_4g && POINTER_TO_PHYSICAL_ADDRESS(initrd_buffer) + initrd_length > UINT32_MAX)
- return log_error_status_stall(
- EFI_UNSUPPORTED, u"Initrd is above 4G, but kernel lacks support.");
+ return log_error_status(EFI_UNSUPPORTED, "Initrd is above 4G, but kernel lacks support.");
_cleanup_pages_ Pages boot_params_page = xmalloc_pages(
can_4g ? AllocateAnyPages : AllocateMaxAddress,
diff --git a/src/boot/efi/log.c b/src/boot/efi/log.c
new file mode 100644
index 0000000000..38e7c5a8a8
--- /dev/null
+++ b/src/boot/efi/log.c
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <efi.h>
+#include <efilib.h>
+
+#include "log.h"
+
+void efi_assert(const char *expr, const char *file, unsigned line, const char *function) {
+ log_error("systemd-boot assertion '%s' failed at %s:%u@%s. Halting.", expr, file, line, function);
+ for (;;)
+ BS->Stall(60 * 1000 * 1000);
+}
+
+EFI_STATUS log_internal(EFI_STATUS status, const char *format, ...) {
+ assert(format);
+
+ int32_t attr = ST->ConOut->Mode->Attribute;
+
+ if (ST->ConOut->Mode->CursorColumn > 0)
+ ST->ConOut->OutputString(ST->ConOut, (char16_t *) u"\r\n");
+ ST->ConOut->SetAttribute(ST->ConOut, EFI_LIGHTRED | EFI_BACKGROUND_BLACK);
+
+ va_list ap;
+ va_start(ap, format);
+ vprintf_status(status, format, ap);
+ va_end(ap);
+
+ ST->ConOut->OutputString(ST->ConOut, (char16_t *) u"\r\n");
+ ST->ConOut->SetAttribute(ST->ConOut, attr);
+
+ /* Give the user a chance to see the message. */
+ BS->Stall(3 * 1000 * 1000);
+ return status;
+}
diff --git a/src/boot/efi/log.h b/src/boot/efi/log.h
new file mode 100644
index 0000000000..c6e8d626ce
--- /dev/null
+++ b/src/boot/efi/log.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include "efi-string.h"
+
+_gnu_printf_(2, 3) EFI_STATUS log_internal(EFI_STATUS status, const char *format, ...);
+#define log_error_status(status, ...) log_internal(status, __VA_ARGS__)
+#define log_error(...) log_internal(EFI_INVALID_PARAMETER, __VA_ARGS__)
+#define log_oom() log_internal(EFI_OUT_OF_RESOURCES, "Out of memory.")
diff --git a/src/boot/efi/measure.c b/src/boot/efi/measure.c
index 27a0f06475..52c5cd7ae8 100644
--- a/src/boot/efi/measure.c
+++ b/src/boot/efi/measure.c
@@ -207,7 +207,7 @@ EFI_STATUS tpm_log_load_options(const char16_t *load_options, bool *ret_measured
err = tpm_log_event(pcr, POINTER_TO_PHYSICAL_ADDRESS(load_options), strsize16(load_options), load_options, &m);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Unable to add load options (i.e. kernel command) line measurement to PCR %u: %r", pcr, err);
+ return log_error_status(err, "Unable to add load options (i.e. kernel command) line measurement to PCR %u: %m", pcr);
measured = measured < 0 ? m : (measured && m);
}
diff --git a/src/boot/efi/meson.build b/src/boot/efi/meson.build
index ed332262e8..09c40a280b 100644
--- a/src/boot/efi/meson.build
+++ b/src/boot/efi/meson.build
@@ -359,6 +359,7 @@ efi_headers = files(
'graphics.h',
'initrd.h',
'linux.h',
+ 'log.h',
'measure.h',
'missing_efi.h',
'part-discovery.h',
@@ -372,7 +373,6 @@ efi_headers = files(
)
common_sources = files(
- 'assert.c',
'console.c',
'devicetree.c',
'drivers.c',
@@ -380,6 +380,7 @@ common_sources = files(
'efi-string.c',
'graphics.c',
'initrd.c',
+ 'log.c',
'measure.c',
'part-discovery.c',
'pe.c',
diff --git a/src/boot/efi/pe.c b/src/boot/efi/pe.c
index 65308639f6..c946ce2b0a 100644
--- a/src/boot/efi/pe.c
+++ b/src/boot/efi/pe.c
@@ -158,7 +158,7 @@ static void locate_sections(
if (in_memory) {
if (prev_section_addr > sect->VirtualAddress)
- log_error_stall(u"Overlapping PE sections detected. Boot may fail due to image memory corruption!");
+ log_error("Overlapping PE sections detected. Boot may fail due to image memory corruption!");
prev_section_addr = sect->VirtualAddress + sect->VirtualSize;
}
diff --git a/src/boot/efi/random-seed.c b/src/boot/efi/random-seed.c
index a52934a901..e971f48097 100644
--- a/src/boot/efi/random-seed.c
+++ b/src/boot/efi/random-seed.c
@@ -48,7 +48,7 @@ static EFI_STATUS acquire_rng(void *ret, size_t size) {
err = rng->GetRNG(rng, NULL, size, ret);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed to acquire RNG data: %r", err);
+ return log_error_status(err, "Failed to acquire RNG data: %m");
return EFI_SUCCESS;
}
@@ -63,12 +63,12 @@ static EFI_STATUS acquire_system_token(void **ret, size_t *ret_size) {
err = efivar_get_raw(LOADER_GUID, L"LoaderSystemToken", &data, &size);
if (err != EFI_SUCCESS) {
if (err != EFI_NOT_FOUND)
- log_error_stall(L"Failed to read LoaderSystemToken EFI variable: %r", err);
+ log_error_status(err, "Failed to read LoaderSystemToken EFI variable: %m");
return err;
}
if (size <= 0)
- return log_error_status_stall(EFI_NOT_FOUND, L"System token too short, ignoring.");
+ return log_error_status(EFI_NOT_FOUND, "System token too short, ignoring.");
*ret = TAKE_PTR(data);
*ret_size = size;
@@ -201,29 +201,29 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir) {
0);
if (err != EFI_SUCCESS) {
if (err != EFI_NOT_FOUND && err != EFI_WRITE_PROTECTED)
- log_error_stall(L"Failed to open random seed file: %r", err);
+ log_error_status(err, "Failed to open random seed file: %m");
return err;
}
err = get_file_info_harder(handle, &info, NULL);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed to get file info for random seed: %r", err);
+ return log_error_status(err, "Failed to get file info for random seed: %m");
size = info->FileSize;
if (size < RANDOM_MAX_SIZE_MIN)
- return log_error_status_stall(EFI_INVALID_PARAMETER, L"Random seed file is too short.");
+ return log_error("Random seed file is too short.");
if (size > RANDOM_MAX_SIZE_MAX)
- return log_error_status_stall(EFI_INVALID_PARAMETER, L"Random seed file is too large.");
+ return log_error("Random seed file is too large.");
seed = xmalloc(size);
rsize = size;
err = handle->Read(handle, &rsize, seed);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed to read random seed file: %r", err);
+ return log_error_status(err, "Failed to read random seed file: %m");
if (rsize != size) {
explicit_bzero_safe(seed, rsize);
- return log_error_status_stall(EFI_PROTOCOL_ERROR, L"Short read on random seed file.");
+ return log_error_status(EFI_PROTOCOL_ERROR, "Short read on random seed file.");
}
sha256_process_bytes(&size, sizeof(size), &hash);
@@ -232,14 +232,14 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir) {
err = handle->SetPosition(handle, 0);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed to seek to beginning of random seed file: %r", err);
+ return log_error_status(err, "Failed to seek to beginning of random seed file: %m");
/* Let's also include the UEFI monotonic counter (which is supposedly increasing on every single
* boot) in the hash, so that even if the changes to the ESP for some reason should not be
* persistent, the random seed we generate will still be different on every single boot. */
err = BS->GetNextMonotonicCount(&uefi_monotonic_counter);
if (err != EFI_SUCCESS && !seeded_by_efi)
- return log_error_status_stall(err, L"Failed to acquire UEFI monotonic counter: %r", err);
+ return log_error_status(err, "Failed to acquire UEFI monotonic counter: %m");
size = sizeof(uefi_monotonic_counter);
sha256_process_bytes(&size, sizeof(size), &hash);
sha256_process_bytes(&uefi_monotonic_counter, size, &hash);
@@ -264,26 +264,26 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir) {
if (size < info->FileSize) {
err = handle->SetPosition(handle, size);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed to seek to offset of random seed file: %r", err);
+ return log_error_status(err, "Failed to seek to offset of random seed file: %m");
wsize = info->FileSize - size;
err = handle->Write(handle, &wsize, seed /* All zeros now */);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed to write random seed file: %r", err);
+ return log_error_status(err, "Failed to write random seed file: %m");
if (wsize != info->FileSize - size)
- return log_error_status_stall(EFI_PROTOCOL_ERROR, L"Short write on random seed file.");
+ return log_error_status(EFI_PROTOCOL_ERROR, "Short write on random seed file.");
err = handle->Flush(handle);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed to flush random seed file: %r", err);
+ return log_error_status(err, "Failed to flush random seed file: %m");
err = handle->SetPosition(handle, 0);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed to seek to beginning of random seed file: %r", err);
+ return log_error_status(err, "Failed to seek to beginning of random seed file: %m");
/* We could truncate the file here with something like:
*
* info->FileSize = size;
* err = handle->SetInfo(handle, &GenericFileInfo, info->Size, info);
* if (err != EFI_SUCCESS)
- * return log_error_status_stall(err, L"Failed to truncate random seed file: %r", err);
+ * return log_error_status(err, "Failed to truncate random seed file: %u");
*
* But this is considered slightly risky, because EFI filesystem drivers are a little bit
* flimsy. So instead we rely on userspace eventually truncating this when it writes a new
@@ -293,18 +293,18 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir) {
wsize = size;
err = handle->Write(handle, &wsize, random_bytes);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed to write random seed file: %r", err);
+ return log_error_status(err, "Failed to write random seed file: %m");
if (wsize != size)
- return log_error_status_stall(EFI_PROTOCOL_ERROR, L"Short write on random seed file.");
+ return log_error_status(EFI_PROTOCOL_ERROR, "Short write on random seed file.");
err = handle->Flush(handle);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed to flush random seed file: %r", err);
+ return log_error_status(err, "Failed to flush random seed file: %m");
err = BS->AllocatePool(EfiACPIReclaimMemory,
offsetof(struct linux_efi_random_seed, seed) + DESIRED_SEED_SIZE,
(void **) &new_seed_table);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed to allocate EFI table for random seed: %r", err);
+ return log_error_status(err, "Failed to allocate EFI table for random seed: %m");
new_seed_table->size = DESIRED_SEED_SIZE;
/* hash = hash_key || 1 */
@@ -316,7 +316,7 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir) {
err = BS->InstallConfigurationTable(&(EFI_GUID)LINUX_EFI_RANDOM_SEED_TABLE_GUID, new_seed_table);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed to install EFI table for random seed: %r", err);
+ return log_error_status(err, "Failed to install EFI table for random seed: %m");
TAKE_PTR(new_seed_table);
if (previous_seed_table) {
diff --git a/src/boot/efi/secure-boot.c b/src/boot/efi/secure-boot.c
index 3f3a222b5e..6b6d48277e 100644
--- a/src/boot/efi/secure-boot.c
+++ b/src/boot/efi/secure-boot.c
@@ -66,10 +66,9 @@ EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path) {
continue;
}
if (err != EFI_SUCCESS)
- return log_error_status_stall(
+ return log_error_status(
err,
- L"Error waiting for user input to enroll Secure Boot keys: %r",
- err);
+ "Error waiting for user input to enroll Secure Boot keys: %m");
/* user aborted, returning EFI_SUCCESS here allows the user to go back to the menu */
return EFI_SUCCESS;
@@ -80,7 +79,7 @@ EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path) {
err = open_directory(root_dir, path, &dir);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Failed opening keys directory %s: %r", path, err);
+ return log_error_status(err, "Failed opening keys directory %ls: %m", path);
struct {
const char16_t *name;
@@ -98,7 +97,7 @@ EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path) {
for (size_t i = 0; i < ELEMENTSOF(sb_vars); i++) {
err = file_read(dir, sb_vars[i].filename, 0, 0, &sb_vars[i].buffer, &sb_vars[i].size);
if (err != EFI_SUCCESS) {
- log_error_stall(L"Failed reading file %s\\%s: %r", path, sb_vars[i].filename, err);
+ log_error_status(err, "Failed reading file %ls\\%ls: %m", path, sb_vars[i].filename);
goto out_deallocate;
}
}
@@ -112,7 +111,7 @@ EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path) {
err = efivar_set_raw(&sb_vars[i].vendor, sb_vars[i].name, sb_vars[i].buffer, sb_vars[i].size, sb_vars_opts);
if (err != EFI_SUCCESS) {
- log_error_stall(L"Failed to write %s secure boot variable: %r", sb_vars[i].name, err);
+ log_error_status(err, "Failed to write %ls secure boot variable: %m", sb_vars[i].name);
goto out_deallocate;
}
}
diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c
index 433fef548c..f9c023e11c 100644
--- a/src/boot/efi/stub.c
+++ b/src/boot/efi/stub.c
@@ -207,7 +207,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (err != EFI_SUCCESS)
- return log_error_status_stall(err, L"Error getting a LoadedImageProtocol handle: %r", err);
+ return log_error_status(err, "Error getting a LoadedImageProtocol handle: %m");
if (efivar_get_uint64_le(LOADER_GUID, L"LoaderFeatures", &loader_features) != EFI_SUCCESS ||
!FLAGS_SET(loader_features, EFI_LOADER_FEATURE_RANDOM_SEED)) {
@@ -222,7 +222,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
if (err != EFI_SUCCESS || szs[UNIFIED_SECTION_LINUX] == 0) {
if (err == EFI_SUCCESS)
err = EFI_NOT_FOUND;
- return log_error_status_stall(err, L"Unable to locate embedded .linux section: %r", err);
+ return log_error_status(err, "Unable to locate embedded .linux section: %m");
}
/* Measure all "payload" of this PE image into a separate PCR (i.e. where nothing else is written
@@ -417,7 +417,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
err = devicetree_install_from_memory(
&dt_state, PHYSICAL_ADDRESS_TO_POINTER(dt_base), dt_size);
if (err != EFI_SUCCESS)
- log_error_stall(L"Error loading embedded devicetree: %r", err);
+ log_error_status(err, "Error loading embedded devicetree: %m");
}
err = linux_exec(image, cmdline,
diff --git a/src/boot/efi/util.c b/src/boot/efi/util.c
index 7596bc3edc..320bddec1b 100644
--- a/src/boot/efi/util.c
+++ b/src/boot/efi/util.c
@@ -325,34 +325,6 @@ EFI_STATUS file_read(EFI_FILE *dir, const char16_t *name, size_t off, size_t siz
return err;
}
-void log_error_stall(const char16_t *fmt, ...) {
- va_list args;
-
- assert(fmt);
-
- int32_t attr = ST->ConOut->Mode->Attribute;
- ST->ConOut->SetAttribute(ST->ConOut, EFI_LIGHTRED|EFI_BACKGROUND_BLACK);
-
- if (ST->ConOut->Mode->CursorColumn > 0)
- Print(L"\n");
-
- va_start(args, fmt);
- VPrint(fmt, args);
- va_end(args);
-
- Print(L"\n");
-
- ST->ConOut->SetAttribute(ST->ConOut, attr);
-
- /* Give the user a chance to see the message. */
- BS->Stall(3 * 1000 * 1000);
-}
-
-EFI_STATUS log_oom(void) {
- log_error_stall(L"Out of memory.");
- return EFI_OUT_OF_RESOURCES;
-}
-
void print_at(size_t x, size_t y, size_t attr, const char16_t *str) {
assert(str);
ST->ConOut->SetCursorPosition(ST->ConOut, x, y);
@@ -572,7 +544,7 @@ void hexdump(const char16_t *prefix, const void *data, size_t size) {
buf[size*2] = 0;
- log_error_stall(L"%s[%" PRIuN "]: %s", prefix, size, buf);
+ log_error("%ls[%zu]: %ls", prefix, size, buf);
}
#endif
diff --git a/src/boot/efi/util.h b/src/boot/efi/util.h
index b97dc9768c..771f11c8bd 100644
--- a/src/boot/efi/util.h
+++ b/src/boot/efi/util.h
@@ -5,6 +5,7 @@
#include <efilib.h>
#include <stddef.h>
+#include "log.h"
#include "string-util-fundamental.h"
#define UINTN_MAX (~(UINTN)0)
@@ -139,17 +140,6 @@ static inline void unload_imagep(EFI_HANDLE *image) {
&(const EFI_GUID) { 0x4a67b082, 0x0a4c, 0x41cf, { 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f } }
#define EFI_GLOBAL_GUID &(const EFI_GUID) EFI_GLOBAL_VARIABLE
-void log_error_stall(const char16_t *fmt, ...);
-EFI_STATUS log_oom(void);
-
-/* This works just like log_error_errno() from userspace, but requires you
- * to provide err a second time if you want to use %r in the message! */
-#define log_error_status_stall(err, fmt, ...) \
- ({ \
- log_error_stall(fmt, ##__VA_ARGS__); \
- err; \
- })
-
void print_at(size_t x, size_t y, size_t attr, const char16_t *str);
void clear_screen(size_t attr);

View File

@ -0,0 +1,220 @@
From e2493416cd85725a1198a391f9b1f93e1e9db88e Mon Sep 17 00:00:00 2001
From: Jan Janssen <medhefgo@web.de>
Date: Sun, 5 Jun 2022 13:19:21 +0200
Subject: [PATCH] boot: Introduce log_wait
Instead of stalling for every log message as it appears we now wait for
several messages at strategic locations.
(cherry picked from commit 6ac54809deefddccc7861b5a2cfa4d766cf1aa3b)
Related: RHEL-16952
---
src/boot/efi/boot.c | 18 +++++++++++++-----
src/boot/efi/console.c | 1 +
src/boot/efi/graphics.c | 7 ++++---
src/boot/efi/linux.c | 1 +
src/boot/efi/linux_x86.c | 1 +
src/boot/efi/log.c | 13 +++++++++++--
src/boot/efi/log.h | 1 +
src/boot/efi/stub.c | 19 +++++++++++++------
src/boot/efi/util.c | 1 +
9 files changed, 46 insertions(+), 16 deletions(-)
diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
index 1e7b7a0fa7..1e94aa57b1 100644
--- a/src/boot/efi/boot.c
+++ b/src/boot/efi/boot.c
@@ -2612,7 +2612,7 @@ static EFI_STATUS discover_root_dir(EFI_LOADED_IMAGE_PROTOCOL *loaded_image, EFI
return open_volume(loaded_image->DeviceHandle, ret_dir);
}
-EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
+static EFI_STATUS real_main(EFI_HANDLE image) {
EFI_LOADED_IMAGE_PROTOCOL *loaded_image;
_cleanup_(file_closep) EFI_FILE *root_dir = NULL;
_cleanup_(config_free) Config config = {};
@@ -2621,11 +2621,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
uint64_t init_usec;
bool menu = false;
- InitializeLib(image, sys_table);
init_usec = time_usec();
- debug_hook(L"systemd-boot");
- /* Uncomment the next line if you need to wait for debugger. */
- // debug_break();
err = BS->OpenProtocol(image,
&LoadedImageProtocol,
@@ -2714,3 +2710,15 @@ out:
BS->CloseProtocol(image, &LoadedImageProtocol, image, NULL);
return err;
}
+
+EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
+ InitializeLib(image, sys_table);
+
+ debug_hook(L"systemd-boot");
+ /* Uncomment the next line if you need to wait for debugger. */
+ // debug_break();
+
+ EFI_STATUS err = real_main(image);
+ log_wait();
+ return err;
+}
diff --git a/src/boot/efi/console.c b/src/boot/efi/console.c
index b876ff2bd7..001b82854b 100644
--- a/src/boot/efi/console.c
+++ b/src/boot/efi/console.c
@@ -188,6 +188,7 @@ static EFI_STATUS change_mode(int64_t mode) {
mode = CLAMP(mode, CONSOLE_MODE_RANGE_MIN, CONSOLE_MODE_RANGE_MAX);
old_mode = MAX(CONSOLE_MODE_RANGE_MIN, ST->ConOut->Mode->Mode);
+ log_wait();
err = ST->ConOut->SetMode(ST->ConOut, mode);
if (err == EFI_SUCCESS)
return EFI_SUCCESS;
diff --git a/src/boot/efi/graphics.c b/src/boot/efi/graphics.c
index dc646bce1f..350d1bc434 100644
--- a/src/boot/efi/graphics.c
+++ b/src/boot/efi/graphics.c
@@ -25,16 +25,17 @@ EFI_STATUS graphics_mode(bool on) {
return err == EFI_NOT_FOUND ? EFI_SUCCESS : err;
/* check current mode */
- err =ConsoleControl->GetMode(ConsoleControl, &current, &uga_exists, &stdin_locked);
+ err = ConsoleControl->GetMode(ConsoleControl, &current, &uga_exists, &stdin_locked);
if (err != EFI_SUCCESS)
return err;
/* do not touch the mode */
- new = on ? EfiConsoleControlScreenGraphics : EfiConsoleControlScreenText;
+ new = on ? EfiConsoleControlScreenGraphics : EfiConsoleControlScreenText;
if (new == current)
return EFI_SUCCESS;
- err =ConsoleControl->SetMode(ConsoleControl, new);
+ log_wait();
+ err = ConsoleControl->SetMode(ConsoleControl, new);
/* some firmware enables the cursor when switching modes */
ST->ConOut->EnableCursor(ST->ConOut, false);
diff --git a/src/boot/efi/linux.c b/src/boot/efi/linux.c
index 2ae68ec295..727e507101 100644
--- a/src/boot/efi/linux.c
+++ b/src/boot/efi/linux.c
@@ -142,6 +142,7 @@ EFI_STATUS linux_exec(
if (err != EFI_SUCCESS)
return log_error_status(err, "Error registering initrd: %m");
+ log_wait();
err = BS->StartImage(kernel_image, NULL, NULL);
/* Try calling the kernel compat entry point if one exists. */
diff --git a/src/boot/efi/linux_x86.c b/src/boot/efi/linux_x86.c
index cbd92201b6..eaae988d97 100644
--- a/src/boot/efi/linux_x86.c
+++ b/src/boot/efi/linux_x86.c
@@ -209,6 +209,7 @@ EFI_STATUS linux_exec_efi_handover(
boot_params->hdr.ramdisk_size = initrd_length;
boot_params->ext_ramdisk_size = ((uint64_t) initrd_length) >> 32;
+ log_wait();
linux_efi_handover(parent, (uintptr_t) linux_buffer, boot_params);
return EFI_LOAD_ERROR;
}
diff --git a/src/boot/efi/log.c b/src/boot/efi/log.c
index 38e7c5a8a8..b1a613e4e5 100644
--- a/src/boot/efi/log.c
+++ b/src/boot/efi/log.c
@@ -5,6 +5,8 @@
#include "log.h"
+static unsigned log_count = 0;
+
void efi_assert(const char *expr, const char *file, unsigned line, const char *function) {
log_error("systemd-boot assertion '%s' failed at %s:%u@%s. Halting.", expr, file, line, function);
for (;;)
@@ -28,7 +30,14 @@ EFI_STATUS log_internal(EFI_STATUS status, const char *format, ...) {
ST->ConOut->OutputString(ST->ConOut, (char16_t *) u"\r\n");
ST->ConOut->SetAttribute(ST->ConOut, attr);
- /* Give the user a chance to see the message. */
- BS->Stall(3 * 1000 * 1000);
+ log_count++;
return status;
}
+
+void log_wait(void) {
+ if (log_count == 0)
+ return;
+
+ BS->Stall(MIN(4u, log_count) * 2500 * 1000);
+ log_count = 0;
+}
diff --git a/src/boot/efi/log.h b/src/boot/efi/log.h
index c6e8d626ce..f24034fd78 100644
--- a/src/boot/efi/log.h
+++ b/src/boot/efi/log.h
@@ -3,6 +3,7 @@
#include "efi-string.h"
+void log_wait(void);
_gnu_printf_(2, 3) EFI_STATUS log_internal(EFI_STATUS status, const char *format, ...);
#define log_error_status(status, ...) log_internal(status, __VA_ARGS__)
#define log_error(...) log_internal(EFI_INVALID_PARAMETER, __VA_ARGS__)
diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c
index f9c023e11c..f71f041a2f 100644
--- a/src/boot/efi/stub.c
+++ b/src/boot/efi/stub.c
@@ -180,7 +180,7 @@ static bool use_load_options(
return true;
}
-EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
+static EFI_STATUS real_main(EFI_HANDLE image) {
_cleanup_free_ void *credential_initrd = NULL, *global_credential_initrd = NULL, *sysext_initrd = NULL, *pcrsig_initrd = NULL, *pcrpkey_initrd = NULL;
size_t credential_initrd_size = 0, global_credential_initrd_size = 0, sysext_initrd_size = 0, pcrsig_initrd_size = 0, pcrpkey_initrd_size = 0;
size_t linux_size, initrd_size, dt_size;
@@ -194,11 +194,6 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
uint64_t loader_features = 0;
EFI_STATUS err;
- InitializeLib(image, sys_table);
- debug_hook(L"systemd-stub");
- /* Uncomment the next line if you need to wait for debugger. */
- // debug_break();
-
err = BS->OpenProtocol(
image,
&LoadedImageProtocol,
@@ -426,3 +421,15 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
graphics_mode(false);
return err;
}
+
+EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
+ InitializeLib(image, sys_table);
+
+ debug_hook(L"systemd-stub");
+ /* Uncomment the next line if you need to wait for debugger. */
+ // debug_break();
+
+ EFI_STATUS err = real_main(image);
+ log_wait();
+ return err;
+}
diff --git a/src/boot/efi/util.c b/src/boot/efi/util.c
index 320bddec1b..aa7b1fa1a2 100644
--- a/src/boot/efi/util.c
+++ b/src/boot/efi/util.c
@@ -333,6 +333,7 @@ void print_at(size_t x, size_t y, size_t attr, const char16_t *str) {
}
void clear_screen(size_t attr) {
+ log_wait();
ST->ConOut->SetAttribute(ST->ConOut, attr);
ST->ConOut->ClearScreen(ST->ConOut);
}

View File

@ -0,0 +1,21 @@
From ee1dfadec7be7c64a2bc2b34a1e4195b9048c46f Mon Sep 17 00:00:00 2001
From: Jan Janssen <medhefgo@web.de>
Date: Thu, 18 Aug 2022 13:41:49 +0200
Subject: [PATCH] boot: Add log_trace debugging helper
(cherry picked from commit 5966c54df4668abc17ae12c40fb0c30d31e80998)
Related: RHEL-16952
---
src/boot/efi/log.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/boot/efi/log.h b/src/boot/efi/log.h
index f24034fd78..9bdcfad923 100644
--- a/src/boot/efi/log.h
+++ b/src/boot/efi/log.h
@@ -8,3 +8,4 @@ _gnu_printf_(2, 3) EFI_STATUS log_internal(EFI_STATUS status, const char *format
#define log_error_status(status, ...) log_internal(status, __VA_ARGS__)
#define log_error(...) log_internal(EFI_INVALID_PARAMETER, __VA_ARGS__)
#define log_oom() log_internal(EFI_OUT_OF_RESOURCES, "Out of memory.")
+#define log_trace() log_internal(EFI_SUCCESS, "%s:%i@%s", __FILE__, __LINE__, __func__)

View File

@ -0,0 +1,78 @@
From b3fb286a49f0a4254f49ff88d1ed520e878c5cca Mon Sep 17 00:00:00 2001
From: Jan Janssen <medhefgo@web.de>
Date: Thu, 18 Aug 2022 13:43:19 +0200
Subject: [PATCH] tree-wide: Use __func__ in asserts
clang puts the whole function signature in __PRETTY_FUNCTION__, which is
a bit excessive for something that can already be figured out by using
the line number.
(cherry picked from commit 5a9b91576630f82ca72a932b5195654dbb04d67e)
Related: RHEL-16952
---
src/basic/macro.h | 6 +++---
src/fundamental/macro-fundamental.h | 6 +++---
src/journal/test-journal-interleaving.c | 2 +-
3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/src/basic/macro.h b/src/basic/macro.h
index 9cb7ae5077..2d378454a2 100644
--- a/src/basic/macro.h
+++ b/src/basic/macro.h
@@ -194,12 +194,12 @@ static inline int __coverity_check_and_return__(int condition) {
#define assert_message_se(expr, message) \
do { \
if (_unlikely_(!(expr))) \
- log_assert_failed(message, PROJECT_FILE, __LINE__, __PRETTY_FUNCTION__); \
+ log_assert_failed(message, PROJECT_FILE, __LINE__, __func__); \
} while (false)
#define assert_log(expr, message) ((_likely_(expr)) \
? (true) \
- : (log_assert_failed_return(message, PROJECT_FILE, __LINE__, __PRETTY_FUNCTION__), false))
+ : (log_assert_failed_return(message, PROJECT_FILE, __LINE__, __func__), false))
#endif /* __COVERITY__ */
@@ -214,7 +214,7 @@ static inline int __coverity_check_and_return__(int condition) {
#endif
#define assert_not_reached() \
- log_assert_failed_unreachable(PROJECT_FILE, __LINE__, __PRETTY_FUNCTION__)
+ log_assert_failed_unreachable(PROJECT_FILE, __LINE__, __func__)
#define assert_return(expr, r) \
do { \
diff --git a/src/fundamental/macro-fundamental.h b/src/fundamental/macro-fundamental.h
index 1c4c445e4e..e226d8d411 100644
--- a/src/fundamental/macro-fundamental.h
+++ b/src/fundamental/macro-fundamental.h
@@ -73,11 +73,11 @@
#define assert(expr)
#define assert_not_reached() __builtin_unreachable()
#else
- #define assert(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); })
- #define assert_not_reached() efi_assert("Code should not be reached", __FILE__, __LINE__, __PRETTY_FUNCTION__)
+ #define assert(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __func__); })
+ #define assert_not_reached() efi_assert("Code should not be reached", __FILE__, __LINE__, __func__)
#endif
#define static_assert _Static_assert
- #define assert_se(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); })
+ #define assert_se(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __func__); })
#endif
/* This passes the argument through after (if asserts are enabled) checking that it is not null. */
diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c
index b3ae4b8143..fb38cc7e82 100644
--- a/src/journal/test-journal-interleaving.c
+++ b/src/journal/test-journal-interleaving.c
@@ -30,7 +30,7 @@ _noreturn_ static void log_assert_errno(const char *text, int error, const char
do { \
int _r_ = (expr); \
if (_unlikely_(_r_ < 0)) \
- log_assert_errno(#expr, -_r_, PROJECT_FILE, __LINE__, __PRETTY_FUNCTION__); \
+ log_assert_errno(#expr, -_r_, PROJECT_FILE, __LINE__, __func__); \
} while (false)
static ManagedJournalFile *test_open(const char *name) {

View File

@ -0,0 +1,326 @@
From a15ea7473b6e54c3019daf2a894d681c0928a132 Mon Sep 17 00:00:00 2001
From: Jan Janssen <medhefgo@web.de>
Date: Sun, 5 Jun 2022 15:08:07 +0200
Subject: [PATCH] boot: Drop use of xpool_print/SPrint
(cherry picked from commit 2f3c3b0bee5534f2338439f04b0aa517479f8b76)
Related: RHEL-16952
---
src/boot/efi/boot.c | 73 +++++++++++++++++++++---------------------
src/boot/efi/cpio.c | 2 +-
src/boot/efi/drivers.c | 2 +-
src/boot/efi/stub.c | 6 ++--
src/boot/efi/util.h | 1 -
src/boot/efi/vmm.c | 3 +-
6 files changed, 43 insertions(+), 44 deletions(-)
diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
index 1e94aa57b1..64a9eda24e 100644
--- a/src/boot/efi/boot.c
+++ b/src/boot/efi/boot.c
@@ -3,6 +3,7 @@
#include <efi.h>
#include <efigpt.h>
#include <efilib.h>
+#include <inttypes.h>
#include "bcd.h"
#include "bootspec-fundamental.h"
@@ -417,7 +418,7 @@ static char16_t *update_timeout_efivar(uint32_t *t, bool inc) {
case TIMEOUT_MENU_HIDDEN:
return xstrdup16(u"Menu disabled. Hold down key at bootup to show menu.");
default:
- return xpool_print(L"Menu timeout set to %u s.", *t);
+ return xasprintf("Menu timeout set to %u s.", *t);
}
}
@@ -749,7 +750,7 @@ static bool menu_run(
if (timeout_remain > 0) {
free(status);
- status = xpool_print(L"Boot in %u s.", timeout_remain);
+ status = xasprintf("Boot in %u s.", timeout_remain);
}
if (status) {
@@ -928,9 +929,9 @@ static bool menu_run(
break;
case KEYPRESS(0, 0, 'v'):
- status = xpool_print(
- L"systemd-boot " GIT_VERSION L" (" EFI_MACHINE_TYPE_NAME L"), "
- L"UEFI Specification %u.%02u, Vendor %s %u.%02u",
+ status = xasprintf(
+ "systemd-boot " GIT_VERSION " (" EFI_MACHINE_TYPE_NAME "), "
+ "UEFI Specification %u.%02u, Vendor %ls %u.%02u",
ST->Hdr.Revision >> 16,
ST->Hdr.Revision & 0xffff,
ST->FirmwareVendor,
@@ -952,10 +953,12 @@ static bool menu_run(
case KEYPRESS(0, 0, 'r'):
err = console_set_mode(CONSOLE_MODE_NEXT);
if (err != EFI_SUCCESS)
- status = xpool_print(L"Error changing console mode: %r", err);
+ status = xasprintf_status(err, "Error changing console mode: %m");
else {
config->console_mode_efivar = ST->ConOut->Mode->Mode;
- status = xpool_print(L"Console mode changed to %ld.", config->console_mode_efivar);
+ status = xasprintf(
+ "Console mode changed to %" PRIi64 ".",
+ config->console_mode_efivar);
}
new_mode = true;
break;
@@ -965,10 +968,13 @@ static bool menu_run(
err = console_set_mode(config->console_mode == CONSOLE_MODE_KEEP ?
console_mode_initial : config->console_mode);
if (err != EFI_SUCCESS)
- status = xpool_print(L"Error resetting console mode: %r", err);
+ status = xasprintf_status(err, "Error resetting console mode: %m");
else
- status = xpool_print(L"Console mode reset to %s default.",
- config->console_mode == CONSOLE_MODE_KEEP ? L"firmware" : L"configuration file");
+ status = xasprintf(
+ "Console mode reset to %s default.",
+ config->console_mode == CONSOLE_MODE_KEEP ?
+ "firmware" :
+ "configuration file");
new_mode = true;
break;
@@ -981,9 +987,9 @@ static bool menu_run(
if (FLAGS_SET(get_os_indications_supported(), EFI_OS_INDICATIONS_BOOT_TO_FW_UI)) {
firmware_setup = true;
/* Let's make sure the user really wants to do this. */
- status = xpool_print(L"Press Enter to reboot into firmware interface.");
+ status = xstrdup16(u"Press Enter to reboot into firmware interface.");
} else
- status = xpool_print(L"Reboot into firmware interface not supported.");
+ status = xstrdup16(u"Reboot into firmware interface not supported.");
break;
default:
@@ -1317,9 +1323,9 @@ static void config_entry_parse_tries(
entry->tries_done = tries_done;
entry->path = xstrdup16(path);
entry->current_name = xstrdup16(file);
- entry->next_name = xpool_print(
- L"%.*s%u-%u%s",
- prefix_len,
+ entry->next_name = xasprintf(
+ "%.*ls%" PRIu64 "-%" PRIu64 "%ls",
+ (int) prefix_len,
file,
LESS_BY(tries_left, 1u),
MIN(tries_done + 1, (uint64_t) INT_MAX),
@@ -1342,7 +1348,7 @@ static void config_entry_bump_counters(ConfigEntry *entry, EFI_FILE *root_dir) {
if (!entry->path || !entry->current_name || !entry->next_name)
return;
- old_path = xpool_print(L"%s\\%s", entry->path, entry->current_name);
+ old_path = xasprintf("%ls\\%ls", entry->path, entry->current_name);
err = root_dir->Open(root_dir, &handle, old_path, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0ULL);
if (err != EFI_SUCCESS)
@@ -1365,7 +1371,7 @@ static void config_entry_bump_counters(ConfigEntry *entry, EFI_FILE *root_dir) {
/* Let's tell the OS that we renamed this file, so that it knows what to rename to the counter-less name on
* success */
- new_path = xpool_print(L"%s\\%s", entry->path, entry->next_name);
+ new_path = xasprintf("%ls\\%ls", entry->path, entry->next_name);
efivar_set(LOADER_GUID, L"LoaderBootCountPath", new_path, 0);
/* If the file we just renamed is the loader path, then let's update that. */
@@ -1479,7 +1485,7 @@ static void config_entry_add_type1(
new = xstr8_to_16(value);
if (entry->options) {
- char16_t *s = xpool_print(L"%s %s", entry->options, new);
+ char16_t *s = xasprintf("%ls %ls", entry->options, new);
free(entry->options);
entry->options = s;
} else
@@ -1796,7 +1802,7 @@ static void config_title_generate(Config *config) {
continue;
_cleanup_free_ char16_t *t = config->entries[i]->title_show;
- config->entries[i]->title_show = xpool_print(L"%s (%s)", t, config->entries[i]->version);
+ config->entries[i]->title_show = xasprintf("%ls (%ls)", t, config->entries[i]->version);
}
if (entries_unique(config->entries, unique, config->entry_count))
@@ -1813,11 +1819,7 @@ static void config_title_generate(Config *config) {
continue;
_cleanup_free_ char16_t *t = config->entries[i]->title_show;
- config->entries[i]->title_show = xpool_print(
- L"%s (%.*s)",
- t,
- strnlen16(config->entries[i]->machine_id, 8),
- config->entries[i]->machine_id);
+ config->entries[i]->title_show = xasprintf("%ls (%.8ls)", t, config->entries[i]->machine_id);
}
if (entries_unique(config->entries, unique, config->entry_count))
@@ -1829,7 +1831,7 @@ static void config_title_generate(Config *config) {
continue;
_cleanup_free_ char16_t *t = config->entries[i]->title_show;
- config->entries[i]->title_show = xpool_print(L"%s (%s)", t, config->entries[i]->id);
+ config->entries[i]->title_show = xasprintf("%ls (%ls)", t, config->entries[i]->id);
}
}
@@ -1994,10 +1996,9 @@ static EFI_STATUS boot_windows_bitlocker(void) {
for (size_t i = 0; i < boot_order_size / sizeof(uint16_t); i++) {
_cleanup_free_ char *buf = NULL;
- char16_t name[sizeof(L"Boot0000")];
size_t buf_size;
- SPrint(name, sizeof(name), L"Boot%04x", (uint32_t) boot_order[i]);
+ _cleanup_free_ char16_t *name = xasprintf("Boot%04x", boot_order[i]);
err = efivar_get_raw(EFI_GLOBAL_GUID, name, &buf, &buf_size);
if (err != EFI_SUCCESS)
continue;
@@ -2187,7 +2188,7 @@ static void config_entry_add_unified(
.title = xstrdup16(good_name),
.version = xstrdup16(good_version),
.device = device,
- .loader = xpool_print(L"\\EFI\\Linux\\%s", f->FileName),
+ .loader = xasprintf("\\EFI\\Linux\\%ls", f->FileName),
.sort_key = xstrdup16(good_sort_key),
.key = 'l',
.tries_done = -1,
@@ -2266,9 +2267,9 @@ static EFI_STATUS initrd_prepare(
STRV_FOREACH(i, entry->initrd) {
_cleanup_free_ char16_t *o = options;
if (o)
- options = xpool_print(L"%s initrd=%s", o, *i);
+ options = xasprintf("%ls initrd=%ls", o, *i);
else
- options = xpool_print(L"initrd=%s", *i);
+ options = xasprintf("initrd=%ls", *i);
_cleanup_(file_closep) EFI_FILE *handle = NULL;
err = root->Open(root, &handle, *i, EFI_FILE_MODE_READ, 0);
@@ -2300,7 +2301,7 @@ static EFI_STATUS initrd_prepare(
if (entry->options) {
_cleanup_free_ char16_t *o = options;
- options = xpool_print(L"%s %s", o, entry->options);
+ options = xasprintf("%ls %ls", o, entry->options);
}
*ret_options = TAKE_PTR(options);
@@ -2482,9 +2483,9 @@ static EFI_STATUS secure_boot_discover_keys(Config *config, EFI_FILE *root_dir)
entry = xnew(ConfigEntry, 1);
*entry = (ConfigEntry) {
- .id = xpool_print(L"secure-boot-keys-%s", dirent->FileName),
- .title = xpool_print(L"Enroll Secure Boot keys: %s", dirent->FileName),
- .path = xpool_print(L"\\loader\\keys\\%s", dirent->FileName),
+ .id = xasprintf("secure-boot-keys-%ls", dirent->FileName),
+ .title = xasprintf("Enroll Secure Boot keys: %ls", dirent->FileName),
+ .path = xasprintf("\\loader\\keys\\%ls", dirent->FileName),
.type = LOADER_SECURE_BOOT_KEYS,
.tries_done = -1,
.tries_left = -1,
@@ -2527,10 +2528,10 @@ static void export_variables(
efivar_set_time_usec(LOADER_GUID, L"LoaderTimeInitUSec", init_usec);
efivar_set(LOADER_GUID, L"LoaderInfo", L"systemd-boot " GIT_VERSION, 0);
- infostr = xpool_print(L"%s %u.%02u", ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
+ infostr = xasprintf("%ls %u.%02u", ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
efivar_set(LOADER_GUID, L"LoaderFirmwareInfo", infostr, 0);
- typestr = xpool_print(L"UEFI %u.%02u", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
+ typestr = xasprintf("UEFI %u.%02u", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
efivar_set(LOADER_GUID, L"LoaderFirmwareType", typestr, 0);
(void) efivar_set_uint64_le(LOADER_GUID, L"LoaderFeatures", loader_features, 0);
diff --git a/src/boot/efi/cpio.c b/src/boot/efi/cpio.c
index 62773ded9a..0d95d40183 100644
--- a/src/boot/efi/cpio.c
+++ b/src/boot/efi/cpio.c
@@ -360,7 +360,7 @@ static char16_t *get_dropin_dir(const EFI_DEVICE_PATH *file_path) {
return NULL;
convert_efi_path(file_path_str);
- return xpool_print(u"%s.extra.d", file_path_str);
+ return xasprintf("%ls.extra.d", file_path_str);
}
EFI_STATUS pack_cpio(
diff --git a/src/boot/efi/drivers.c b/src/boot/efi/drivers.c
index c76f8e0903..4abb3fbd82 100644
--- a/src/boot/efi/drivers.c
+++ b/src/boot/efi/drivers.c
@@ -20,7 +20,7 @@ static EFI_STATUS load_one_driver(
assert(loaded_image);
assert(fname);
- spath = xpool_print(L"\\EFI\\systemd\\drivers\\%s", fname);
+ spath = xasprintf("\\EFI\\systemd\\drivers\\%ls", fname);
err = make_file_device_path(loaded_image->DeviceHandle, spath, &path);
if (err != EFI_SUCCESS)
return log_error_status(err, "Error making file device path: %m");
diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c
index f71f041a2f..552660eb07 100644
--- a/src/boot/efi/stub.c
+++ b/src/boot/efi/stub.c
@@ -114,14 +114,14 @@ static void export_variables(EFI_LOADED_IMAGE_PROTOCOL *loaded_image) {
/* if LoaderFirmwareInfo is not set, let's set it */
if (efivar_get_raw(LOADER_GUID, L"LoaderFirmwareInfo", NULL, NULL) != EFI_SUCCESS) {
_cleanup_free_ char16_t *s = NULL;
- s = xpool_print(L"%s %u.%02u", ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
+ s = xasprintf("%ls %u.%02u", ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
efivar_set(LOADER_GUID, L"LoaderFirmwareInfo", s, 0);
}
/* ditto for LoaderFirmwareType */
if (efivar_get_raw(LOADER_GUID, L"LoaderFirmwareType", NULL, NULL) != EFI_SUCCESS) {
_cleanup_free_ char16_t *s = NULL;
- s = xpool_print(L"UEFI %u.%02u", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
+ s = xasprintf("UEFI %u.%02u", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
efivar_set(LOADER_GUID, L"LoaderFirmwareType", s, 0);
}
@@ -173,7 +173,7 @@ static bool use_load_options(
*ret = xstrdup16(shell->Argv[1]);
for (size_t i = 2; i < shell->Argc; i++) {
_cleanup_free_ char16_t *old = *ret;
- *ret = xpool_print(u"%s %s", old, shell->Argv[i]);
+ *ret = xasprintf("%ls %ls", old, shell->Argv[i]);
}
mangle_stub_cmdline(*ret);
diff --git a/src/boot/efi/util.h b/src/boot/efi/util.h
index 771f11c8bd..e0c3b408f2 100644
--- a/src/boot/efi/util.h
+++ b/src/boot/efi/util.h
@@ -68,7 +68,6 @@ static inline void *xrealloc(void *p, size_t old_size, size_t new_size) {
return r;
}
-#define xpool_print(fmt, ...) ((char16_t *) ASSERT_SE_PTR(PoolPrint((fmt), ##__VA_ARGS__)))
#define xnew(type, n) ((type *) xmalloc_multiply(sizeof(type), (n)))
typedef struct {
diff --git a/src/boot/efi/vmm.c b/src/boot/efi/vmm.c
index 3dfa92b58d..b24d556700 100644
--- a/src/boot/efi/vmm.c
+++ b/src/boot/efi/vmm.c
@@ -97,9 +97,8 @@ EFI_STATUS vmm_open(EFI_HANDLE *ret_vmm_dev, EFI_FILE **ret_vmm_dir) {
for (size_t order = 0;; order++) {
_cleanup_free_ EFI_DEVICE_PATH *dp = NULL;
- char16_t order_str[STRLEN("VMMBootOrder") + 4 + 1];
- SPrint(order_str, sizeof(order_str), u"VMMBootOrder%04x", order);
+ _cleanup_free_ char16_t *order_str = xasprintf("VMMBootOrder%04zx", order);
dp_err = efivar_get_raw(&(EFI_GUID)VMM_BOOT_ORDER_GUID, order_str, (char**)&dp, NULL);
for (size_t i = 0; i < n_handles; i++) {

View File

@ -0,0 +1,323 @@
From 013b84264db5b2062840f0ff04df776fa144c586 Mon Sep 17 00:00:00 2001
From: Jan Janssen <medhefgo@web.de>
Date: Tue, 23 Aug 2022 10:51:36 +0200
Subject: [PATCH] boot: Drop use of Print
The custom print helpers have been replaced with explicit checks at the
call site to keep this in line with the way it is done in userspace. Any
calls where the check has been ommited should not need them as the value
is expected to alawys be around.
(cherry picked from commit 9220b2c46bfbdf759b5a777a8bb3109a4d873039)
Related: RHEL-16952
---
src/boot/efi/boot.c | 176 ++++++++++++++++++++-----------------
src/boot/efi/secure-boot.c | 6 +-
src/boot/efi/stub.c | 2 +-
src/boot/efi/util.h | 2 +-
4 files changed, 102 insertions(+), 84 deletions(-)
diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
index 64a9eda24e..cb237675ec 100644
--- a/src/boot/efi/boot.c
+++ b/src/boot/efi/boot.c
@@ -433,22 +433,9 @@ static bool unicode_supported(void) {
return cache;
}
-static void ps_string(const char16_t *fmt, const void *value) {
- assert(fmt);
- if (value)
- Print(fmt, value);
-}
-
-static void ps_bool(const char16_t *fmt, bool value) {
- assert(fmt);
- Print(fmt, yes_no(value));
-}
-
static bool ps_continue(void) {
- if (unicode_supported())
- Print(L"\n─── Press any key to continue, ESC or q to quit. ───\n\n");
- else
- Print(L"\n--- Press any key to continue, ESC or q to quit. ---\n\n");
+ const char16_t *sep = unicode_supported() ? u"───" : u"---";
+ printf("\n%ls Press any key to continue, ESC or q to quit. %ls\n\n", sep, sep);
uint64_t key;
return console_key_read(&key, UINT64_MAX) == EFI_SUCCESS &&
@@ -470,112 +457,143 @@ static void print_status(Config *config, char16_t *loaded_image_path) {
secure = secure_boot_mode();
(void) efivar_get(LOADER_GUID, L"LoaderDevicePartUUID", &device_part_uuid);
- /* We employ some unusual indentation here for readability. */
-
- ps_string(L" systemd-boot version: %a\n", GIT_VERSION);
- ps_string(L" loaded image: %s\n", loaded_image_path);
- ps_string(L" loader partition UUID: %s\n", device_part_uuid);
- ps_string(L" architecture: %a\n", EFI_MACHINE_TYPE_NAME);
- Print(L" UEFI specification: %u.%02u\n", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
- ps_string(L" firmware vendor: %s\n", ST->FirmwareVendor);
- Print(L" firmware version: %u.%02u\n", ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
- Print(L" OS indications: %lu\n", get_os_indications_supported());
- Print(L" secure boot: %s (%s)\n", yes_no(IN_SET(secure, SECURE_BOOT_USER, SECURE_BOOT_DEPLOYED)), secure_boot_mode_to_string(secure));
- ps_bool(L" shim: %s\n", shim_loaded());
- ps_bool(L" TPM: %s\n", tpm_present());
- Print(L" console mode: %d/%ld (%" PRIuN L"x%" PRIuN L" @%ux%u)\n", ST->ConOut->Mode->Mode, ST->ConOut->Mode->MaxMode - INT64_C(1), x_max, y_max, screen_width, screen_height);
+ printf(" systemd-boot version: " GIT_VERSION "\n");
+ if (loaded_image_path)
+ printf(" loaded image: %ls\n", loaded_image_path);
+ if (device_part_uuid)
+ printf(" loader partition UUID: %ls\n", device_part_uuid);
+ printf(" architecture: " EFI_MACHINE_TYPE_NAME "\n");
+ printf(" UEFI specification: %u.%02u\n", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
+ printf(" firmware vendor: %ls\n", ST->FirmwareVendor);
+ printf(" firmware version: %u.%02u\n", ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
+ printf(" OS indications: %#" PRIx64 "\n", get_os_indications_supported());
+ printf(" secure boot: %ls (%ls)\n",
+ yes_no(IN_SET(secure, SECURE_BOOT_USER, SECURE_BOOT_DEPLOYED)),
+ secure_boot_mode_to_string(secure));
+ printf(" shim: %ls\n", yes_no(shim_loaded()));
+ printf(" TPM: %ls\n", yes_no(tpm_present()));
+ printf(" console mode: %i/%" PRIi64 " (%zux%zu @%ux%u)\n",
+ ST->ConOut->Mode->Mode, ST->ConOut->Mode->MaxMode - INT64_C(1),
+ x_max, y_max, screen_width, screen_height);
if (!ps_continue())
return;
switch (config->timeout_sec_config) {
case TIMEOUT_UNSET:
- break;
+ break;
case TIMEOUT_MENU_FORCE:
- Print(L" timeout (config): menu-force\n"); break;
+ printf(" timeout (config): menu-force\n");
+ break;
case TIMEOUT_MENU_HIDDEN:
- Print(L" timeout (config): menu-hidden\n"); break;
+ printf(" timeout (config): menu-hidden\n");
+ break;
default:
- Print(L" timeout (config): %u s\n", config->timeout_sec_config);
+ printf(" timeout (config): %u s\n", config->timeout_sec_config);
}
switch (config->timeout_sec_efivar) {
case TIMEOUT_UNSET:
- break;
+ break;
case TIMEOUT_MENU_FORCE:
- Print(L" timeout (EFI var): menu-force\n"); break;
+ printf(" timeout (EFI var): menu-force\n");
+ break;
case TIMEOUT_MENU_HIDDEN:
- Print(L" timeout (EFI var): menu-hidden\n"); break;
+ printf(" timeout (EFI var): menu-hidden\n");
+ break;
default:
- Print(L" timeout (EFI var): %u s\n", config->timeout_sec_efivar);
+ printf(" timeout (EFI var): %u s\n", config->timeout_sec_efivar);
}
- ps_string(L" default (config): %s\n", config->entry_default_config);
- ps_string(L" default (EFI var): %s\n", config->entry_default_efivar);
- ps_string(L" default (one-shot): %s\n", config->entry_oneshot);
- ps_string(L" saved entry: %s\n", config->entry_saved);
- ps_bool(L" editor: %s\n", config->editor);
- ps_bool(L" auto-entries: %s\n", config->auto_entries);
- ps_bool(L" auto-firmware: %s\n", config->auto_firmware);
- ps_bool(L" beep: %s\n", config->beep);
- ps_bool(L" reboot-for-bitlocker: %s\n", config->reboot_for_bitlocker);
+ if (config->entry_default_config)
+ printf(" default (config): %ls\n", config->entry_default_config);
+ if (config->entry_default_efivar)
+ printf(" default (EFI var): %ls\n", config->entry_default_efivar);
+ if (config->entry_oneshot)
+ printf(" default (one-shot): %ls\n", config->entry_oneshot);
+ if (config->entry_saved)
+ printf(" saved entry: %ls\n", config->entry_saved);
+ printf(" editor: %ls\n", yes_no(config->editor));
+ printf(" auto-entries: %ls\n", yes_no(config->auto_entries));
+ printf(" auto-firmware: %ls\n", yes_no(config->auto_firmware));
+ printf(" beep: %ls\n", yes_no(config->beep));
+ printf(" reboot-for-bitlocker: %ls\n", yes_no(config->reboot_for_bitlocker));
switch (config->secure_boot_enroll) {
case ENROLL_OFF:
- Print(L" secure-boot-enroll: off\n"); break;
+ printf(" secure-boot-enroll: off\n");
+ break;
case ENROLL_MANUAL:
- Print(L" secure-boot-enroll: manual\n"); break;
+ printf(" secure-boot-enroll: manual\n");
+ break;
case ENROLL_FORCE:
- Print(L" secure-boot-enroll: force\n"); break;
+ printf(" secure-boot-enroll: force\n");
+ break;
default:
assert_not_reached();
}
switch (config->console_mode) {
case CONSOLE_MODE_AUTO:
- Print(L" console-mode (config): %s\n", L"auto"); break;
+ printf(" console-mode (config): auto\n");
+ break;
case CONSOLE_MODE_KEEP:
- Print(L" console-mode (config): %s\n", L"keep"); break;
+ printf(" console-mode (config): keep\n");
+ break;
case CONSOLE_MODE_FIRMWARE_MAX:
- Print(L" console-mode (config): %s\n", L"max"); break;
+ printf(" console-mode (config): max\n");
+ break;
default:
- Print(L" console-mode (config): %ld\n", config->console_mode); break;
+ printf(" console-mode (config): %" PRIi64 "\n", config->console_mode);
+ break;
}
/* EFI var console mode is always a concrete value or unset. */
if (config->console_mode_efivar != CONSOLE_MODE_KEEP)
- Print(L"console-mode (EFI var): %ld\n", config->console_mode_efivar);
+ printf("console-mode (EFI var): %" PRIi64 "\n", config->console_mode_efivar);
if (!ps_continue())
return;
for (size_t i = 0; i < config->entry_count; i++) {
ConfigEntry *entry = config->entries[i];
-
- _cleanup_free_ char16_t *dp = NULL;
- if (entry->device)
- (void) device_path_to_str(DevicePathFromHandle(entry->device), &dp);
-
- Print(L" config entry: %" PRIuN L"/%" PRIuN L"\n", i + 1, config->entry_count);
- ps_string(L" id: %s\n", entry->id);
- ps_string(L" title: %s\n", entry->title);
- ps_string(L" title show: %s\n", streq16(entry->title, entry->title_show) ? NULL : entry->title_show);
- ps_string(L" sort key: %s\n", entry->sort_key);
- ps_string(L" version: %s\n", entry->version);
- ps_string(L" machine-id: %s\n", entry->machine_id);
- ps_string(L" device: %s\n", dp);
- ps_string(L" loader: %s\n", entry->loader);
+ EFI_DEVICE_PATH *dp = NULL;
+ _cleanup_free_ char16_t *dp_str = NULL;
+
+ if (entry->device &&
+ BS->HandleProtocol(entry->device, &(EFI_GUID) EFI_DEVICE_PATH_PROTOCOL_GUID, (void **) &dp) ==
+ EFI_SUCCESS)
+ (void) device_path_to_str(dp, &dp_str);
+
+ printf(" config entry: %zu/%zu\n", i + 1, config->entry_count);
+ printf(" id: %ls\n", entry->id);
+ if (entry->title)
+ printf(" title: %ls\n", entry->title);
+ if (entry->title_show && !streq16(entry->title, entry->title_show))
+ printf(" title show: %ls\n", entry->title_show);
+ if (entry->sort_key)
+ printf(" sort key: %ls\n", entry->sort_key);
+ if (entry->version)
+ printf(" version: %ls\n", entry->version);
+ if (entry->machine_id)
+ printf(" machine-id: %ls\n", entry->machine_id);
+ if (dp_str)
+ printf(" device: %ls\n", dp_str);
+ if (entry->loader)
+ printf(" loader: %ls\n", entry->loader);
STRV_FOREACH(initrd, entry->initrd)
- Print(L" initrd: %s\n", *initrd);
- ps_string(L" devicetree: %s\n", entry->devicetree);
- ps_string(L" options: %s\n", entry->options);
- ps_bool(L" internal call: %s\n", !!entry->call);
-
- ps_bool(L"counting boots: %s\n", entry->tries_left >= 0);
+ printf(" initrd: %ls\n", *initrd);
+ if (entry->devicetree)
+ printf(" devicetree: %ls\n", entry->devicetree);
+ if (entry->options)
+ printf(" options: %ls\n", entry->options);
+ printf(" internal call: %ls\n", yes_no(!!entry->call));
+
+ printf("counting boots: %ls\n", yes_no(entry->tries_left >= 0));
if (entry->tries_left >= 0) {
- Print(L" tries: %u left, %u done\n", entry->tries_left, entry->tries_done);
- Print(L" current path: %s\\%s\n", entry->path, entry->current_name);
- Print(L" next path: %s\\%s\n", entry->path, entry->next_name);
+ printf(" tries: %i left, %i done\n", entry->tries_left, entry->tries_done);
+ printf(" current path: %ls\\%ls\n", entry->path, entry->current_name);
+ printf(" next path: %ls\\%ls\n", entry->path, entry->next_name);
}
if (!ps_continue())
@@ -629,7 +647,7 @@ static bool menu_run(
ST->ConOut->EnableCursor(ST->ConOut, false);
/* draw a single character to make ClearScreen work on some firmware */
- Print(L" ");
+ ST->ConOut->OutputString(ST->ConOut, (char16_t *) u" ");
err = console_set_mode(config->console_mode_efivar != CONSOLE_MODE_KEEP ?
config->console_mode_efivar : config->console_mode);
@@ -2715,7 +2733,7 @@ out:
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
InitializeLib(image, sys_table);
- debug_hook(L"systemd-boot");
+ debug_hook("systemd-boot");
/* Uncomment the next line if you need to wait for debugger. */
// debug_break();
diff --git a/src/boot/efi/secure-boot.c b/src/boot/efi/secure-boot.c
index 6b6d48277e..2594c8798f 100644
--- a/src/boot/efi/secure-boot.c
+++ b/src/boot/efi/secure-boot.c
@@ -44,16 +44,16 @@ EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path) {
clear_screen(COLOR_NORMAL);
- Print(u"Enrolling secure boot keys from directory: %s\n");
+ printf("Enrolling secure boot keys from directory: %ls\n", path);
/* Enrolling secure boot keys is safe to do in virtualized environments as there is nothing
* we can brick there. */
if (!in_hypervisor()) {
- Print(u"Warning: Enrolling custom Secure Boot keys might soft-brick your machine!\n", path);
+ printf("Warning: Enrolling custom Secure Boot keys might soft-brick your machine!\n");
unsigned timeout_sec = 15;
for (;;) {
- Print(u"\rEnrolling in %2u s, press any key to abort.", timeout_sec);
+ printf("\rEnrolling in %2u s, press any key to abort.", timeout_sec);
uint64_t key;
err = console_key_read(&key, 1000 * 1000);
diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c
index 552660eb07..69e6a0b07f 100644
--- a/src/boot/efi/stub.c
+++ b/src/boot/efi/stub.c
@@ -425,7 +425,7 @@ static EFI_STATUS real_main(EFI_HANDLE image) {
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
InitializeLib(image, sys_table);
- debug_hook(L"systemd-stub");
+ debug_hook("systemd-stub");
/* Uncomment the next line if you need to wait for debugger. */
// debug_break();
diff --git a/src/boot/efi/util.h b/src/boot/efi/util.h
index e0c3b408f2..3247694014 100644
--- a/src/boot/efi/util.h
+++ b/src/boot/efi/util.h
@@ -180,7 +180,7 @@ void debug_break(void);
extern uint8_t _text, _data;
/* Report the relocated position of text and data sections so that a debugger
* can attach to us. See debug-sd-boot.sh for how this can be done. */
-# define debug_hook(identity) Print(identity L"@0x%lx,0x%lx\n", POINTER_TO_PHYSICAL_ADDRESS(&_text), POINTER_TO_PHYSICAL_ADDRESS(&_data))
+# define debug_hook(identity) printf(identity "@%p,%p\n", &_text, &_data)
#else
# define debug_hook(identity)
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,51 @@
From 50a254def1c98a34ee5fdb52dcfbb1ed59b1250a Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Mon, 30 Jan 2023 16:22:10 +0100
Subject: [PATCH] efi-string: Fix strchr() null byte handling
strchr() should be able to search for the terminating null byte,
our implementation doesn't, let's fix that.
(cherry picked from commit bbef5a9617e91b4b1bc30266eb9dcbda395a8c61)
Related: RHEL-16952
---
src/boot/efi/efi-string.c | 2 +-
src/boot/efi/test-efi-string.c | 4 ++++
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/boot/efi/efi-string.c b/src/boot/efi/efi-string.c
index 860dfc00b2..cf0d71e986 100644
--- a/src/boot/efi/efi-string.c
+++ b/src/boot/efi/efi-string.c
@@ -116,7 +116,7 @@ DEFINE_STRCPY(char16_t, strcpy16);
s++; \
} \
\
- return NULL; \
+ return c ? NULL : (type *) s; \
}
DEFINE_STRCHR(char, strchr8);
diff --git a/src/boot/efi/test-efi-string.c b/src/boot/efi/test-efi-string.c
index c26973d8bd..c7e42c7b94 100644
--- a/src/boot/efi/test-efi-string.c
+++ b/src/boot/efi/test-efi-string.c
@@ -229,6 +229,8 @@ TEST(strchr8) {
assert_se(strchr8(str, 'a') == &str[0]);
assert_se(strchr8(str, 'c') == &str[2]);
assert_se(strchr8(str, 'B') == &str[4]);
+
+ assert_se(strchr8(str, 0) == str + strlen8(str));
}
TEST(strchr16) {
@@ -240,6 +242,8 @@ TEST(strchr16) {
assert_se(strchr16(str, 'a') == &str[0]);
assert_se(strchr16(str, 'c') == &str[2]);
assert_se(strchr16(str, 'B') == &str[4]);
+
+ assert_se(strchr16(str, 0) == str + strlen16(str));
}
TEST(xstrndup8) {

View File

@ -0,0 +1,79 @@
From 3684d9be497c5cb5164435238b970931c93b41e6 Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Mon, 30 Jan 2023 16:25:23 +0100
Subject: [PATCH] efi-string: Add startswith8()
startswith() from string-util-fundamental.h is defined for sd_char
which is char16_t, so let's add an implementation for char as well.
(cherry picked from commit ad36d31ea578622883c3b5297c971374096a504a)
Related: RHEL-16952
---
src/boot/efi/efi-string.c | 15 +++++++++++++++
src/boot/efi/efi-string.h | 2 ++
src/boot/efi/test-efi-string.c | 12 ++++++++++++
3 files changed, 29 insertions(+)
diff --git a/src/boot/efi/efi-string.c b/src/boot/efi/efi-string.c
index cf0d71e986..6b84af69e6 100644
--- a/src/boot/efi/efi-string.c
+++ b/src/boot/efi/efi-string.c
@@ -216,6 +216,21 @@ char16_t *xstrn8_to_16(const char *str8, size_t n) {
return str16;
}
+char *startswith8(const char *s, const char *prefix) {
+ size_t l;
+
+ assert(prefix);
+
+ if (!s)
+ return NULL;
+
+ l = strlen8(prefix);
+ if (!strneq8(s, prefix, l))
+ return NULL;
+
+ return (char*) s + l;
+}
+
static bool efi_fnmatch_prefix(const char16_t *p, const char16_t *h, const char16_t **ret_p, const char16_t **ret_h) {
assert(p);
assert(h);
diff --git a/src/boot/efi/efi-string.h b/src/boot/efi/efi-string.h
index 2a28db3593..477229bf60 100644
--- a/src/boot/efi/efi-string.h
+++ b/src/boot/efi/efi-string.h
@@ -105,6 +105,8 @@ static inline char16_t *xstr8_to_16(const char *str8) {
return xstrn8_to_16(str8, strlen8(str8));
}
+char *startswith8(const char *s, const char *prefix);
+
bool efi_fnmatch(const char16_t *pattern, const char16_t *haystack);
bool parse_number8(const char *s, uint64_t *ret_u, const char **ret_tail);
diff --git a/src/boot/efi/test-efi-string.c b/src/boot/efi/test-efi-string.c
index c7e42c7b94..be7f8f9b1c 100644
--- a/src/boot/efi/test-efi-string.c
+++ b/src/boot/efi/test-efi-string.c
@@ -355,6 +355,18 @@ TEST(xstrn8_to_16) {
free(s);
}
+TEST(startswith8) {
+ assert_se(streq8(startswith8("", ""), ""));
+ assert_se(streq8(startswith8("x", ""), "x"));
+ assert_se(!startswith8("", "x"));
+ assert_se(!startswith8("", "xxxxxxxx"));
+ assert_se(streq8(startswith8("xxx", "x"), "xx"));
+ assert_se(streq8(startswith8("xxx", "xx"), "x"));
+ assert_se(streq8(startswith8("xxx", "xxx"), ""));
+ assert_se(!startswith8("xxx", "xxxx"));
+ assert_se(!startswith8(NULL, ""));
+}
+
#define TEST_FNMATCH_ONE(pattern, haystack, expect) \
({ \
assert_se(fnmatch(pattern, haystack, 0) == (expect ? 0 : FNM_NOMATCH)); \

View File

@ -0,0 +1,93 @@
From 9461c9b524c2f3bf19b86dbcda24f57acde67852 Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Tue, 31 Jan 2023 15:39:40 +0100
Subject: [PATCH] efi-string: Add efi_memchr()
(cherry picked from commit e71f0f63da87fb8043f665a142261bc393fe0216)
Related: RHEL-16952
---
src/boot/efi/efi-string.c | 14 ++++++++++++++
src/boot/efi/efi-string.h | 2 ++
src/boot/efi/test-efi-string.c | 13 +++++++++++++
3 files changed, 29 insertions(+)
diff --git a/src/boot/efi/efi-string.c b/src/boot/efi/efi-string.c
index 6b84af69e6..60b5d0f712 100644
--- a/src/boot/efi/efi-string.c
+++ b/src/boot/efi/efi-string.c
@@ -886,16 +886,30 @@ char16_t *xvasprintf_status(EFI_STATUS status, const char *format, va_list ap) {
#if SD_BOOT
/* To provide the actual implementation for these we need to remove the redirection to the builtins. */
+# undef memchr
# undef memcmp
# undef memcpy
# undef memset
#else
/* And for userspace unit testing we need to give them an efi_ prefix. */
+# define memchr efi_memchr
# define memcmp efi_memcmp
# define memcpy efi_memcpy
# define memset efi_memset
#endif
+_used_ void *memchr(const void *p, int c, size_t n) {
+ if (!p || n == 0)
+ return NULL;
+
+ const uint8_t *q = p;
+ for (size_t i = 0; i < n; i++)
+ if (q[i] == (unsigned char) c)
+ return (void *) (q + i);
+
+ return NULL;
+}
+
_used_ int memcmp(const void *p1, const void *p2, size_t n) {
const uint8_t *up1 = p1, *up2 = p2;
int r;
diff --git a/src/boot/efi/efi-string.h b/src/boot/efi/efi-string.h
index 477229bf60..3d035d7ead 100644
--- a/src/boot/efi/efi-string.h
+++ b/src/boot/efi/efi-string.h
@@ -142,6 +142,7 @@ _gnu_printf_(2, 0) _warn_unused_result_ char16_t *xvasprintf_status(EFI_STATUS s
* compiling with -ffreestanding. By referring to builtins, the compiler can check arguments and do
* optimizations again. Note that we still need to provide implementations as the compiler is free to not
* inline its own implementation and instead issue a library call. */
+# define memchr __builtin_memchr
# define memcmp __builtin_memcmp
# define memcpy __builtin_memcpy
# define memset __builtin_memset
@@ -155,6 +156,7 @@ static inline void *mempcpy(void * restrict dest, const void * restrict src, siz
#else
/* For unit testing. */
+void *efi_memchr(const void *p, int c, size_t n);
int efi_memcmp(const void *p1, const void *p2, size_t n);
void *efi_memcpy(void * restrict dest, const void * restrict src, size_t n);
void *efi_memset(void *p, int c, size_t n);
diff --git a/src/boot/efi/test-efi-string.c b/src/boot/efi/test-efi-string.c
index be7f8f9b1c..d214b1536e 100644
--- a/src/boot/efi/test-efi-string.c
+++ b/src/boot/efi/test-efi-string.c
@@ -626,6 +626,19 @@ TEST(xvasprintf_status) {
s = mfree(s);
}
+TEST(efi_memchr) {
+ assert_se(streq8(efi_memchr("abcde", 'c', 5), "cde"));
+ assert_se(streq8(efi_memchr("abcde", 'c', 3), "cde"));
+ assert_se(streq8(efi_memchr("abcde", 'c', 2), NULL));
+ assert_se(streq8(efi_memchr("abcde", 'c', 7), "cde"));
+ assert_se(streq8(efi_memchr("abcde", 'q', 5), NULL));
+ assert_se(streq8(efi_memchr("abcde", 'q', 0), NULL));
+ /* Test that the character is interpreted as unsigned char. */
+ assert_se(streq8(efi_memchr("abcde", 'a', 6), efi_memchr("abcde", 'a' + 0x100, 6)));
+ assert_se(streq8(efi_memchr("abcde", 0, 6), ""));
+ assert_se(efi_memchr(NULL, 0, 0) == NULL);
+}
+
TEST(efi_memcmp) {
assert_se(efi_memcmp(NULL, NULL, 0) == 0);
assert_se(efi_memcmp(NULL, NULL, 1) == 0);

View File

@ -0,0 +1,70 @@
From 139d725cb2b293443e7b0db263401b588373a7cb Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Mon, 30 Jan 2023 21:15:12 +0100
Subject: [PATCH] vmm: Add more const
SMBIOS tables are immutable, so let's access it via const pointers
where possible.
(cherry picked from commit 761f62fe98cab82a3742bdae49f79626ede2ceaf)
Related: RHEL-16952
---
src/boot/efi/vmm.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/src/boot/efi/vmm.c b/src/boot/efi/vmm.c
index 6bd440f032..6b684e1bf4 100644
--- a/src/boot/efi/vmm.c
+++ b/src/boot/efi/vmm.c
@@ -201,17 +201,17 @@ typedef struct {
uint8_t bios_characteristics_ext[2];
} _packed_ SmbiosTableType0;
-static void *find_smbios_configuration_table(uint64_t *ret_size) {
+static const void *find_smbios_configuration_table(uint64_t *ret_size) {
assert(ret_size);
- Smbios3EntryPoint *entry3 = find_configuration_table(MAKE_GUID_PTR(SMBIOS3_TABLE));
+ const Smbios3EntryPoint *entry3 = find_configuration_table(MAKE_GUID_PTR(SMBIOS3_TABLE));
if (entry3 && memcmp(entry3->anchor_string, "_SM3_", 5) == 0 &&
entry3->entry_point_length <= sizeof(*entry3)) {
*ret_size = entry3->table_maximum_size;
return PHYSICAL_ADDRESS_TO_POINTER(entry3->table_address);
}
- SmbiosEntryPoint *entry = find_configuration_table(MAKE_GUID_PTR(SMBIOS_TABLE));
+ const SmbiosEntryPoint *entry = find_configuration_table(MAKE_GUID_PTR(SMBIOS_TABLE));
if (entry && memcmp(entry->anchor_string, "_SM_", 4) == 0 &&
entry->entry_point_length <= sizeof(*entry)) {
*ret_size = entry->table_length;
@@ -221,9 +221,9 @@ static void *find_smbios_configuration_table(uint64_t *ret_size) {
return NULL;
}
-static SmbiosHeader *get_smbios_table(uint8_t type) {
+static const SmbiosHeader *get_smbios_table(uint8_t type) {
uint64_t size = 0;
- uint8_t *p = find_smbios_configuration_table(&size);
+ const uint8_t *p = find_smbios_configuration_table(&size);
if (!p)
return false;
@@ -231,7 +231,7 @@ static SmbiosHeader *get_smbios_table(uint8_t type) {
if (size < sizeof(SmbiosHeader))
return NULL;
- SmbiosHeader *header = (SmbiosHeader *) p;
+ const SmbiosHeader *header = (const SmbiosHeader *) p;
/* End of table. */
if (header->type == 127)
@@ -273,7 +273,7 @@ static SmbiosHeader *get_smbios_table(uint8_t type) {
static bool smbios_in_hypervisor(void) {
/* Look up BIOS Information (Type 0). */
- SmbiosTableType0 *type0 = (SmbiosTableType0 *) get_smbios_table(0);
+ const SmbiosTableType0 *type0 = (const SmbiosTableType0 *) get_smbios_table(0);
if (!type0 || type0->header.length < sizeof(SmbiosTableType0))
return false;

View File

@ -0,0 +1,107 @@
From c7c166f2dd636418bfa25ea9c69ebfc45c618d8f Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Mon, 30 Jan 2023 16:26:14 +0100
Subject: [PATCH] vmm: Add smbios_find_oem_string()
This function can be used to find SMBIOS strings in the SMBIOS Type 11
table.
(cherry picked from commit a885188b3ab71c222cbcc42b083ba671884aa651)
Related: RHEL-16952
---
src/boot/efi/vmm.c | 44 +++++++++++++++++++++++++++++++++++++++++---
src/boot/efi/vmm.h | 2 ++
2 files changed, 43 insertions(+), 3 deletions(-)
diff --git a/src/boot/efi/vmm.c b/src/boot/efi/vmm.c
index 6b684e1bf4..19b66a3974 100644
--- a/src/boot/efi/vmm.c
+++ b/src/boot/efi/vmm.c
@@ -201,6 +201,12 @@ typedef struct {
uint8_t bios_characteristics_ext[2];
} _packed_ SmbiosTableType0;
+typedef struct {
+ SmbiosHeader header;
+ uint8_t count;
+ char contents[];
+} _packed_ SmbiosTableType11;
+
static const void *find_smbios_configuration_table(uint64_t *ret_size) {
assert(ret_size);
@@ -221,7 +227,7 @@ static const void *find_smbios_configuration_table(uint64_t *ret_size) {
return NULL;
}
-static const SmbiosHeader *get_smbios_table(uint8_t type) {
+static const SmbiosHeader *get_smbios_table(uint8_t type, uint64_t *ret_size_left) {
uint64_t size = 0;
const uint8_t *p = find_smbios_configuration_table(&size);
if (!p)
@@ -240,8 +246,11 @@ static const SmbiosHeader *get_smbios_table(uint8_t type) {
if (size < header->length)
return NULL;
- if (header->type == type)
+ if (header->type == type) {
+ if (ret_size_left)
+ *ret_size_left = size;
return header; /* Yay! */
+ }
/* Skip over formatted area. */
size -= header->length;
@@ -273,7 +282,7 @@ static const SmbiosHeader *get_smbios_table(uint8_t type) {
static bool smbios_in_hypervisor(void) {
/* Look up BIOS Information (Type 0). */
- const SmbiosTableType0 *type0 = (const SmbiosTableType0 *) get_smbios_table(0);
+ const SmbiosTableType0 *type0 = (const SmbiosTableType0 *) get_smbios_table(0, NULL);
if (!type0 || type0->header.length < sizeof(SmbiosTableType0))
return false;
@@ -289,3 +298,32 @@ bool in_hypervisor(void) {
cache = cpuid_in_hypervisor() || smbios_in_hypervisor();
return cache;
}
+
+const char* smbios_find_oem_string(const char *name) {
+ uint64_t left;
+
+ assert(name);
+
+ const SmbiosTableType11 *type11 = (const SmbiosTableType11 *) get_smbios_table(11, &left);
+ if (!type11 || type11->header.length < sizeof(SmbiosTableType11))
+ return NULL;
+
+ assert(left >= type11->header.length);
+
+ const char *s = type11->contents;
+ left -= type11->header.length;
+
+ for (const char *p = s; p < s + left; ) {
+ const char *e = memchr(p, 0, s + left - p);
+ if (!e || e == p) /* Double NUL byte means we've reached the end of the OEM strings. */
+ break;
+
+ const char *eq = startswith8(p, name);
+ if (eq && *eq == '=')
+ return eq + 1;
+
+ p = e + 1;
+ }
+
+ return NULL;
+}
diff --git a/src/boot/efi/vmm.h b/src/boot/efi/vmm.h
index e98ec74af1..2002f32bec 100644
--- a/src/boot/efi/vmm.h
+++ b/src/boot/efi/vmm.h
@@ -8,3 +8,5 @@ bool is_direct_boot(EFI_HANDLE device);
EFI_STATUS vmm_open(EFI_HANDLE *ret_qemu_dev, EFI_FILE **ret_qemu_dir);
bool in_hypervisor(void);
+
+const char* smbios_find_oem_string(const char *name);

View File

@ -0,0 +1,71 @@
From dc742ee6411f4f7bd5d447cd29dc17a0025843e0 Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Mon, 30 Jan 2023 16:26:50 +0100
Subject: [PATCH] stub: Read extra kernel command line items from SMBIOS
Let's read more kernel command line arguments from SMBIOS OEM string
io.systemd.stub.kernel-cmdline-extra. This allows adding debug kernel
command line arguments when booting in qemy without having to modify
the UKI.
(cherry picked from commit 717af0de4648ccc223f06683a6baf73d64271e02)
Related: RHEL-16952
---
man/systemd-stub.xml | 17 +++++++++++++++++
src/boot/efi/stub.c | 7 +++++++
2 files changed, 24 insertions(+)
diff --git a/man/systemd-stub.xml b/man/systemd-stub.xml
index 85d30129d6..66c158c44d 100644
--- a/man/systemd-stub.xml
+++ b/man/systemd-stub.xml
@@ -382,6 +382,23 @@
default, this is done for the TPM2 PCR signature and public key files.</para>
</refsect1>
+ <refsect1>
+ <title>SMBIOS Type 11 Strings</title>
+
+ <para><command>systemd-stub</command> can be configured using SMBIOS Type 11 strings. Applicable strings
+ consist of a name, followed by <literal>=</literal>, followed by the value.
+ <command>systemd-stub</command> will search the table for a string with a specific name, and if found,
+ use its value. The following strings are read:</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><varname>io.systemd.stub.kernel-cmdline-extra</varname></term>
+ <listitem><para>If set, the value of this string is added to the list of kernel command line
+ arguments that are passed to the kernel.</para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
<refsect1>
<title>Assembling Kernel Images</title>
diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c
index dac1bb0606..86eae2e350 100644
--- a/src/boot/efi/stub.c
+++ b/src/boot/efi/stub.c
@@ -16,6 +16,7 @@
#include "splash.h"
#include "tpm-pcr.h"
#include "util.h"
+#include "vmm.h"
/* magic string to find in the binary image */
_used_ _section_(".sdmagic") static const char magic[] = "#### LoaderInfo: systemd-stub " GIT_VERSION " ####";
@@ -277,6 +278,12 @@ static EFI_STATUS real_main(EFI_HANDLE image) {
mangle_stub_cmdline(cmdline);
}
+ const char *extra = smbios_find_oem_string("io.systemd.stub.kernel-cmdline-extra");
+ if (extra) {
+ _cleanup_free_ char16_t *tmp = TAKE_PTR(cmdline), *extra16 = xstr8_to_16(extra);
+ cmdline = xasprintf("%ls %ls", tmp, extra16);
+ }
+
export_variables(loaded_image);
if (pack_cpio(loaded_image,

View File

@ -0,0 +1,46 @@
From 47fd30b95f506beaef5640ad61b40b180c7ac47b Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Wed, 22 Feb 2023 17:04:58 +0100
Subject: [PATCH] vmm: Modernize get_smbios_table()
(cherry picked from commit c8e5d82c97a1478b15d2f97ffebd9591e81663ba)
Related: RHEL-16952
---
src/boot/efi/vmm.c | 18 +++++++-----------
1 file changed, 7 insertions(+), 11 deletions(-)
diff --git a/src/boot/efi/vmm.c b/src/boot/efi/vmm.c
index 19b66a3974..f9a59dca0a 100644
--- a/src/boot/efi/vmm.c
+++ b/src/boot/efi/vmm.c
@@ -258,22 +258,18 @@ static const SmbiosHeader *get_smbios_table(uint8_t type, uint64_t *ret_size_lef
/* Skip over string table. */
for (;;) {
- while (size > 0 && *p != '\0') {
- p++;
- size--;
- }
- if (size == 0)
+ const uint8_t *e = memchr(p, 0, size);
+ if (!e)
return NULL;
- p++;
- size--;
- /* Double NUL terminates string table. */
- if (*p == '\0') {
- if (size == 0)
- return NULL;
+ if (e == p) {/* Double NUL byte means we've reached the end of the string table. */
p++;
+ size--;
break;
}
+
+ size -= e + 1 - p;
+ p = e + 1;
}
}

View File

@ -0,0 +1,59 @@
From ee8090db1c2fe4df29fd0b134d80791eced6434d Mon Sep 17 00:00:00 2001
From: Luca Boccassi <bluca@debian.org>
Date: Sun, 21 May 2023 15:18:21 +0100
Subject: [PATCH] stub: measure SMBIOS kernel-cmdline-extra in PCR12
PCR1, where SMBIOS strings are measured, is filled with data that is not
under the control of the machine owner. Measure cmdline extensions in
PCR12 too, where we measure other optional addons that are loaded by
sd-stub.
(cherry picked from commit 2c90b5ec63ab420d074ebe4f5c6881737c9bc155)
Related: RHEL-16952
---
man/systemd-stub.xml | 5 ++++-
src/boot/efi/stub.c | 7 +++++++
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/man/systemd-stub.xml b/man/systemd-stub.xml
index 66c158c44d..edfc299bc2 100644
--- a/man/systemd-stub.xml
+++ b/man/systemd-stub.xml
@@ -66,6 +66,9 @@
<listitem><para>A compiled binary DeviceTree will be looked for in the <literal>.dtb</literal> PE
section.</para></listitem>
+ <listitem><para>Kernel version information, i.e. the output of <command>uname -r</command> for the
+ kernel included in the UKI, in the <literal>.uname</literal> PE section.</para></listitem>
+
<listitem><para>The kernel command line to pass to the invoked kernel will be looked for in the
<literal>.cmdline</literal> PE section.</para></listitem>
@@ -394,7 +397,7 @@
<varlistentry>
<term><varname>io.systemd.stub.kernel-cmdline-extra</varname></term>
<listitem><para>If set, the value of this string is added to the list of kernel command line
- arguments that are passed to the kernel.</para></listitem>
+ arguments that are measured in PCR12 and passed to the kernel.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c
index 86eae2e350..a195612f0e 100644
--- a/src/boot/efi/stub.c
+++ b/src/boot/efi/stub.c
@@ -282,6 +282,13 @@ static EFI_STATUS real_main(EFI_HANDLE image) {
if (extra) {
_cleanup_free_ char16_t *tmp = TAKE_PTR(cmdline), *extra16 = xstr8_to_16(extra);
cmdline = xasprintf("%ls %ls", tmp, extra16);
+
+ /* SMBIOS strings are measured in PCR1, but we also want to measure them in our specific
+ * PCR12, as firmware-owned PCRs are very difficult to use as they'll contain unpredictable
+ * measurements that are not under control of the machine owner. */
+ m = false;
+ (void) tpm_log_load_options(extra16, &m);
+ parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m);
}
export_variables(loaded_image);

View File

@ -0,0 +1,28 @@
From 3a31a48e1bda8d8799695a878a872fd30d5c3e45 Mon Sep 17 00:00:00 2001
From: Luca Boccassi <bluca@debian.org>
Date: Fri, 12 May 2023 00:49:57 +0100
Subject: [PATCH] efi: support passing empty cmdline to mangle_stub_cmdline()
Just return instead of crashing
(cherry picked from commit e715d82de6694d82a17921b5ccbcf47398604068)
Related: RHEL-16952
---
src/boot/efi/util.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/boot/efi/util.c b/src/boot/efi/util.c
index bd821a5afb..b8befb4b0c 100644
--- a/src/boot/efi/util.c
+++ b/src/boot/efi/util.c
@@ -272,6 +272,9 @@ char16_t *xstr8_to_path(const char *str8) {
}
void mangle_stub_cmdline(char16_t *cmdline) {
+ if (!cmdline)
+ return;
+
for (; *cmdline != '\0'; cmdline++)
/* Convert ASCII control characters to spaces. */
if (*cmdline <= 0x1F)

View File

@ -0,0 +1,61 @@
From d0e7305306407992bebbf6785a03cf2062d8359b Mon Sep 17 00:00:00 2001
From: Luca Boccassi <bluca@debian.org>
Date: Fri, 12 May 2023 00:51:19 +0100
Subject: [PATCH] efi: set EFIVAR to stop Shim from uninstalling its protocol
We'll use it from the stub to validate files. Requires Shim 5.18.
By default, Shim uninstalls its protocol when calling StartImage(),
so when loading systemd-boot via shim and then loading an UKI, the
UKI's sd-stub will no longer be able to use the shim verification
protocol by default.
(cherry picked from commit e1f1b5fc62f721a3a4c14d97ad01447b2ac07d6d)
Related: RHEL-16952
---
src/boot/efi/boot.c | 4 ++++
src/boot/efi/shim.c | 9 +++++++++
src/boot/efi/shim.h | 1 +
3 files changed, 14 insertions(+)
diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
index d859ffe0b8..5a9bfc9646 100644
--- a/src/boot/efi/boot.c
+++ b/src/boot/efi/boot.c
@@ -2644,6 +2644,10 @@ static EFI_STATUS real_main(EFI_HANDLE image) {
init_usec = time_usec();
+ /* Ask Shim to leave its protocol around, so that the stub can use it to validate PEs.
+ * By default, Shim uninstalls its protocol when calling StartImage(). */
+ shim_retain_protocol();
+
err = BS->OpenProtocol(
image,
MAKE_GUID_PTR(EFI_LOADED_IMAGE_PROTOCOL),
diff --git a/src/boot/efi/shim.c b/src/boot/efi/shim.c
index 5da298c10a..d2fd680bbc 100644
--- a/src/boot/efi/shim.c
+++ b/src/boot/efi/shim.c
@@ -100,3 +100,12 @@ EFI_STATUS shim_load_image(EFI_HANDLE parent, const EFI_DEVICE_PATH *device_path
return ret;
}
+
+void shim_retain_protocol(void) {
+ uint8_t value = 1;
+
+ /* Ask Shim to avoid uninstalling its security protocol, so that we can use it from sd-stub to
+ * validate PE addons. By default, Shim uninstalls its protocol when calling StartImage().
+ * Requires Shim 15.8. */
+ (void) efivar_set_raw(MAKE_GUID_PTR(SHIM_LOCK), u"ShimRetainProtocol", &value, sizeof(value), 0);
+}
diff --git a/src/boot/efi/shim.h b/src/boot/efi/shim.h
index 6d213f5efa..23fdc0923f 100644
--- a/src/boot/efi/shim.h
+++ b/src/boot/efi/shim.h
@@ -14,3 +14,4 @@
bool shim_loaded(void);
EFI_STATUS shim_load_image(EFI_HANDLE parent, const EFI_DEVICE_PATH *device_path, EFI_HANDLE *ret_image);
+void shim_retain_protocol(void);

View File

@ -0,0 +1,78 @@
From 7307ab86351846cb750f3fcd35db7d9de9aefdf0 Mon Sep 17 00:00:00 2001
From: Luca Boccassi <bluca@debian.org>
Date: Tue, 23 May 2023 01:45:40 +0100
Subject: [PATCH] ukify: use empty stub for addons
Instead of picking up sd-stub, which is runnable, add an empty
addon stub that just returns an error if executed
(cherry picked from commit f644ea3ed7ec22c28814b194e4e5bbbf2fa98560)
Related: RHEL-16952
---
src/boot/efi/addon.c | 15 +++++++++++++++
src/boot/efi/meson.build | 13 ++++++++++---
2 files changed, 25 insertions(+), 3 deletions(-)
create mode 100644 src/boot/efi/addon.c
diff --git a/src/boot/efi/addon.c b/src/boot/efi/addon.c
new file mode 100644
index 0000000000..959e54b5cc
--- /dev/null
+++ b/src/boot/efi/addon.c
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "efi.h"
+#include "macro-fundamental.h"
+
+/* Magic string for recognizing our own binaries */
+_used_ _section_(".sdmagic") static const char magic[] =
+ "#### LoaderInfo: systemd-addon " GIT_VERSION " ####";
+
+/* This is intended to carry data, not to be executed */
+
+EFIAPI EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *system_table);
+EFIAPI EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *system_table) {
+ return EFI_UNSUPPORTED;
+}
diff --git a/src/boot/efi/meson.build b/src/boot/efi/meson.build
index 09c40a280b..9e5d535b5b 100644
--- a/src/boot/efi/meson.build
+++ b/src/boot/efi/meson.build
@@ -403,6 +403,8 @@ stub_sources = files(
'stub.c',
)
+addon_sources = files('addon.c')
+
if efi_arch[1] in ['ia32', 'x86_64']
stub_sources += files('linux_x86.c')
endif
@@ -430,7 +432,8 @@ endif
systemd_boot_objects = []
stub_objects = []
-foreach file : fundamental_source_paths + common_sources + systemd_boot_sources + stub_sources
+addon_objects = []
+foreach file : fundamental_source_paths + common_sources + systemd_boot_sources + stub_sources + addon_sources
# FIXME: replace ''.format(file) with fs.name(file) when meson_version requirement is >= 0.59.0
o_file = custom_target('@0@.o'.format(file).split('/')[-1],
input : file,
@@ -443,10 +446,14 @@ foreach file : fundamental_source_paths + common_sources + systemd_boot_sources
if (fundamental_source_paths + common_sources + stub_sources).contains(file)
stub_objects += o_file
endif
+ if (fundamental_source_paths + common_sources + addon_sources).contains(file)
+ addon_objects += o_file
+ endif
endforeach
-foreach tuple : [['systemd-boot@0@.@1@', systemd_boot_objects, false, 'systemd-boot'],
- ['linux@0@.@1@.stub', stub_objects, true, 'systemd-stub']]
+foreach tuple : [['systemd-boot@0@.@1@', systemd_boot_objects, false, 'systemd-boot',],
+ ['linux@0@.@1@.stub', stub_objects, true, 'systemd-stub'],
+ ['addon@0@.@1@.stub', addon_objects, true, 'addon']]
elf = custom_target(
tuple[0].format(efi_arch[0], 'elf'),
input : tuple[1],

View File

@ -0,0 +1,389 @@
From 2f2729382327bde136559a0d0ac15740d76108f9 Mon Sep 17 00:00:00 2001
From: Luca Boccassi <bluca@debian.org>
Date: Fri, 12 May 2023 00:55:58 +0100
Subject: [PATCH] stub: allow loading and verifying cmdline addons
Files placed in /EFI/Linux/UKI.efi.extra.d/ and /loader/addons/ are
opened and verified using the LoadImage protocol, and will thus get
verified via shim/firmware.
If they are valid signed PE files, the .cmdline section will be
extracted and appended. If there are multiple addons in each directory,
they will be parsed in alphanumerical order.
Optionally the .uname sections are also matched if present, so
that they can be used to filter out addons as well if needed, and only
addons that correspond exactly to the UKI being loaded are used.
It is recommended to also always add a .sbat section to addons, so
that they can be mass-revoked with just a policy update.
The files must have a .addon.efi suffix.
Files in the per-UKI directory are parsed, sorted, measured and
appended first. Then, files in the generic directory are processed.
(cherry picked from commit 05c9f9c2517c54b98d55f08f8afa67c79be861e8)
Related: RHEL-16952
---
man/systemd-stub.xml | 32 ++++++
src/boot/efi/cpio.c | 2 +-
src/boot/efi/cpio.h | 2 +
src/boot/efi/meson.build | 2 +-
src/boot/efi/stub.c | 216 +++++++++++++++++++++++++++++++++++++++
5 files changed, 252 insertions(+), 2 deletions(-)
diff --git a/man/systemd-stub.xml b/man/systemd-stub.xml
index edfc299bc2..21035cc944 100644
--- a/man/systemd-stub.xml
+++ b/man/systemd-stub.xml
@@ -28,8 +28,10 @@
<para><filename>/usr/lib/systemd/boot/efi/linuxx64.efi.stub</filename></para>
<para><filename>/usr/lib/systemd/boot/efi/linuxia32.efi.stub</filename></para>
<para><filename>/usr/lib/systemd/boot/efi/linuxaa64.efi.stub</filename></para>
+ <para><filename><replaceable>ESP</replaceable>/.../<replaceable>foo</replaceable>.efi.extra.d/*.addon.efi</filename></para>
<para><filename><replaceable>ESP</replaceable>/.../<replaceable>foo</replaceable>.efi.extra.d/*.cred</filename></para>
<para><filename><replaceable>ESP</replaceable>/.../<replaceable>foo</replaceable>.efi.extra.d/*.raw</filename></para>
+ <para><filename><replaceable>ESP</replaceable>/loader/addons/*.addon.efi</filename></para>
<para><filename><replaceable>ESP</replaceable>/loader/credentials/*.cred</filename></para>
</refsynopsisdiv>
@@ -148,11 +150,41 @@
details on system extension images. The generated <command>cpio</command> archive containing these
system extension images is measured into TPM PCR 13 (if a TPM is present).</para></listitem>
+ <listitem><para>Similarly, files
+ <filename><replaceable>foo</replaceable>.efi.extra.d/*.addon.efi</filename>
+ are loaded and verified as PE binaries, and a <literal>.cmdline</literal> section is parsed from them.
+ In case Secure Boot is enabled, these files will be validated using keys in UEFI DB, Shim's DB or
+ Shim's MOK, and will be rejected otherwise. Additionally, if the both the addon and the UKI contain a
+ a <literal>.uname</literal> section, the addon will be rejected if they do not exactly match. It is
+ recommended to always add a <literal>.sbat</literal> section to all signed addons, so that they may be
+ revoked with a SBAT policy update, without requiring blocklisting via DBX/MOKX. The
+ <citerefentry><refentrytitle>ukify</refentrytitle><manvolnum>1</manvolnum></citerefentry> tool will
+ add a SBAT policy by default if none is passed when building addons. For more information on SBAT see
+ <ulink url="https://github.com/rhboot/shim/blob/main/SBAT.md">Shim's documentation.</ulink>
+ Addons are supposed to be used to pass additional kernel command line parameters, regardless of the
+ kernel image being booted, for example to allow platform vendors to ship platform-specific
+ configuration. The loaded command line addon files are sorted, loaded, measured into TPM PCR 12 (if a
+ TPM is present) and appended to the kernel command line. UKI command line options are listed first,
+ then options from addons in <filename>/loader/addons/*.addon.efi</filename> are appended next, and
+ finally UKI-specific addons are appended last. Addons are always loaded in the same order based on the
+ filename, so that, given the same set of addons, the same set of measurements can be expected in
+ PCR12, however note that the filename is not protected by the PE signature, and as such an attacker
+ with write access to the ESP could potentially rename these files to change the order in which they
+ are loaded, in a way that could alter the functionality of the kernel, as some options might be order
+ dependent. If you sign such addons, you should pay attention to the PCR12 values and make use of an
+ attestation service so that improper use of your signed addons can be detected and dealt with using
+ one of the aforementioned revocation mechanisms.</para></listitem>
+
<listitem><para>Files <filename>/loader/credentials/*.cred</filename> are packed up in a
<command>cpio</command> archive and placed in the <filename>/.extra/global_credentials/</filename>
directory of the initrd file hierarchy. This is supposed to be used to pass additional credentials to
the initrd, regardless of the kernel being booted. The generated <command>cpio</command> archive is
measured into TPM PCR 12 (if a TPM is present)</para></listitem>
+
+ <listitem><para>Additionally, files <filename>/loader/addons/*.addon.efi</filename> are loaded and
+ verified as PE binaries, and a <literal>.cmdline</literal> section is parsed from them. This is
+ supposed to be used to pass additional command line parameters to the kernel, regardless of the kernel
+ being booted.</para></listitem>
</itemizedlist>
<para>These mechanisms may be used to parameterize and extend trusted (i.e. signed), immutable initrd
diff --git a/src/boot/efi/cpio.c b/src/boot/efi/cpio.c
index 0d95d40183..741c11f7ae 100644
--- a/src/boot/efi/cpio.c
+++ b/src/boot/efi/cpio.c
@@ -341,7 +341,7 @@ static EFI_STATUS measure_cpio(
return EFI_SUCCESS;
}
-static char16_t *get_dropin_dir(const EFI_DEVICE_PATH *file_path) {
+char16_t *get_dropin_dir(const EFI_DEVICE_PATH *file_path) {
if (!file_path)
return NULL;
diff --git a/src/boot/efi/cpio.h b/src/boot/efi/cpio.h
index e80e06723c..0f14edbf5f 100644
--- a/src/boot/efi/cpio.h
+++ b/src/boot/efi/cpio.h
@@ -32,3 +32,5 @@ EFI_STATUS pack_cpio_literal(
void **ret_buffer,
size_t *ret_buffer_size,
bool *ret_measured);
+
+char16_t *get_dropin_dir(const EFI_DEVICE_PATH *file_path);
diff --git a/src/boot/efi/meson.build b/src/boot/efi/meson.build
index 9e5d535b5b..b84ceb8c9f 100644
--- a/src/boot/efi/meson.build
+++ b/src/boot/efi/meson.build
@@ -386,6 +386,7 @@ common_sources = files(
'pe.c',
'random-seed.c',
'secure-boot.c',
+ 'shim.c',
'ticks.c',
'util.c',
'vmm.c',
@@ -393,7 +394,6 @@ common_sources = files(
systemd_boot_sources = files(
'boot.c',
- 'shim.c',
)
stub_sources = files(
diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c
index a195612f0e..2c7c56de3e 100644
--- a/src/boot/efi/stub.c
+++ b/src/boot/efi/stub.c
@@ -13,6 +13,7 @@
#include "pe.h"
#include "random-seed.h"
#include "secure-boot.h"
+#include "shim.h"
#include "splash.h"
#include "tpm-pcr.h"
#include "util.h"
@@ -181,6 +182,189 @@ static bool use_load_options(
return true;
}
+static EFI_STATUS load_addons_from_dir(
+ EFI_FILE *root,
+ const char16_t *prefix,
+ char16_t ***items,
+ size_t *n_items,
+ size_t *n_allocated) {
+
+ _cleanup_(file_closep) EFI_FILE *extra_dir = NULL;
+ _cleanup_free_ EFI_FILE_INFO *dirent = NULL;
+ size_t dirent_size = 0;
+ EFI_STATUS err;
+
+ assert(root);
+ assert(prefix);
+ assert(items);
+ assert(n_items);
+ assert(n_allocated);
+
+ err = open_directory(root, prefix, &extra_dir);
+ if (err == EFI_NOT_FOUND)
+ /* No extra subdir, that's totally OK */
+ return EFI_SUCCESS;
+ if (err != EFI_SUCCESS)
+ return log_error_status(err, "Failed to open addons directory '%ls': %m", prefix);
+
+ for (;;) {
+ _cleanup_free_ char16_t *d = NULL;
+
+ err = readdir_harder(extra_dir, &dirent, &dirent_size);
+ if (err != EFI_SUCCESS)
+ return log_error_status(err, "Failed to read addons directory of loaded image: %m");
+ if (!dirent) /* End of directory */
+ break;
+
+ if (dirent->FileName[0] == '.')
+ continue;
+ if (FLAGS_SET(dirent->Attribute, EFI_FILE_DIRECTORY))
+ continue;
+ if (!is_ascii(dirent->FileName))
+ continue;
+ if (strlen16(dirent->FileName) > 255) /* Max filename size on Linux */
+ continue;
+ if (!endswith_no_case(dirent->FileName, u".addon.efi"))
+ continue;
+
+ d = xstrdup16(dirent->FileName);
+
+ if (*n_items + 2 > *n_allocated) {
+ /* We allocate 16 entries at a time, as a matter of optimization */
+ if (*n_items > (SIZE_MAX / sizeof(uint16_t)) - 16) /* Overflow check, just in case */
+ return log_oom();
+
+ size_t m = *n_items + 16;
+ *items = xrealloc(*items, *n_allocated * sizeof(uint16_t *), m * sizeof(uint16_t *));
+ *n_allocated = m;
+ }
+
+ (*items)[(*n_items)++] = TAKE_PTR(d);
+ (*items)[*n_items] = NULL; /* Let's always NUL terminate, to make freeing via strv_free() easy */
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+static EFI_STATUS cmdline_append_and_measure_addons(
+ EFI_HANDLE stub_image,
+ EFI_LOADED_IMAGE_PROTOCOL *loaded_image,
+ const char16_t *prefix,
+ const char *uname,
+ bool *ret_parameters_measured,
+ char16_t **cmdline_append) {
+
+ _cleanup_(strv_freep) char16_t **items = NULL;
+ _cleanup_(file_closep) EFI_FILE *root = NULL;
+ _cleanup_free_ char16_t *buffer = NULL;
+ size_t n_items = 0, n_allocated = 0;
+ EFI_STATUS err;
+
+ assert(stub_image);
+ assert(loaded_image);
+ assert(prefix);
+ assert(ret_parameters_measured);
+ assert(cmdline_append);
+
+ if (!loaded_image->DeviceHandle)
+ return EFI_SUCCESS;
+
+ err = open_volume(loaded_image->DeviceHandle, &root);
+ if (err == EFI_UNSUPPORTED)
+ /* Error will be unsupported if the bootloader doesn't implement the file system protocol on
+ * its file handles. */
+ return EFI_SUCCESS;
+ if (err != EFI_SUCCESS)
+ return log_error_status(err, "Unable to open root directory: %m");
+
+ err = load_addons_from_dir(root, prefix, &items, &n_items, &n_allocated);
+ if (err != EFI_SUCCESS)
+ return err;
+
+ if (n_items == 0)
+ return EFI_SUCCESS; /* Empty directory */
+
+ /* Now, sort the files we found, to make this uniform and stable (and to ensure the TPM measurements
+ * are not dependent on read order) */
+ sort_pointer_array((void**) items, n_items, (compare_pointer_func_t) strcmp16);
+
+ for (size_t i = 0; i < n_items; i++) {
+ size_t addrs[_UNIFIED_SECTION_MAX] = {}, szs[_UNIFIED_SECTION_MAX] = {};
+ _cleanup_free_ EFI_DEVICE_PATH *addon_path = NULL;
+ _cleanup_(unload_imagep) EFI_HANDLE addon = NULL;
+ EFI_LOADED_IMAGE_PROTOCOL *loaded_addon = NULL;
+ _cleanup_free_ char16_t *addon_spath = NULL;
+
+ addon_spath = xasprintf("%ls\\%ls", prefix, items[i]);
+ err = make_file_device_path(loaded_image->DeviceHandle, addon_spath, &addon_path);
+ if (err != EFI_SUCCESS)
+ return log_error_status(err, "Error making device path for %ls: %m", addon_spath);
+
+ /* By using shim_load_image, we cover both the case where the PE files are signed with MoK
+ * and with DB, and running with or without shim. */
+ err = shim_load_image(stub_image, addon_path, &addon);
+ if (err != EFI_SUCCESS) {
+ log_error_status(err,
+ "Failed to read '%ls' from '%ls', ignoring: %m",
+ items[i],
+ addon_spath);
+ continue;
+ }
+
+ err = BS->HandleProtocol(addon,
+ MAKE_GUID_PTR(EFI_LOADED_IMAGE_PROTOCOL),
+ (void **) &loaded_addon);
+ if (err != EFI_SUCCESS)
+ return log_error_status(err, "Failed to find protocol in %ls: %m", items[i]);
+
+ err = pe_memory_locate_sections(loaded_addon->ImageBase, unified_sections, addrs, szs);
+ if (err != EFI_SUCCESS || szs[UNIFIED_SECTION_CMDLINE] == 0) {
+ if (err == EFI_SUCCESS)
+ err = EFI_NOT_FOUND;
+ log_error_status(err,
+ "Unable to locate embedded .cmdline section in %ls, ignoring: %m",
+ items[i]);
+ continue;
+ }
+
+ /* We want to enforce that addons are not UKIs, i.e.: they must not embed a kernel. */
+ if (szs[UNIFIED_SECTION_LINUX] > 0) {
+ log_error_status(EFI_INVALID_PARAMETER, "%ls is a UKI, not an addon, ignoring: %m", items[i]);
+ continue;
+ }
+
+ /* Also enforce that, in case it is specified, .uname matches as a quick way to allow
+ * enforcing compatibility with a specific UKI only */
+ if (uname && szs[UNIFIED_SECTION_UNAME] > 0 &&
+ !strneq8(uname,
+ (char *)loaded_addon->ImageBase + addrs[UNIFIED_SECTION_UNAME],
+ szs[UNIFIED_SECTION_UNAME])) {
+ log_error(".uname mismatch between %ls and UKI, ignoring", items[i]);
+ continue;
+ }
+
+ _cleanup_free_ char16_t *tmp = TAKE_PTR(buffer),
+ *extra16 = xstrn8_to_16((char *)loaded_addon->ImageBase + addrs[UNIFIED_SECTION_CMDLINE],
+ szs[UNIFIED_SECTION_CMDLINE]);
+ buffer = xasprintf("%ls%ls%ls", strempty(tmp), isempty(tmp) ? u"" : u" ", extra16);
+ }
+
+ mangle_stub_cmdline(buffer);
+
+ if (!isempty(buffer)) {
+ _cleanup_free_ char16_t *tmp = TAKE_PTR(*cmdline_append);
+ bool m = false;
+
+ (void) tpm_log_load_options(buffer, &m);
+ *ret_parameters_measured = m;
+
+ *cmdline_append = xasprintf("%ls%ls%ls", strempty(tmp), isempty(tmp) ? u"" : u" ", buffer);
+ }
+
+ return EFI_SUCCESS;
+}
+
static EFI_STATUS real_main(EFI_HANDLE image) {
_cleanup_free_ void *credential_initrd = NULL, *global_credential_initrd = NULL, *sysext_initrd = NULL, *pcrsig_initrd = NULL, *pcrpkey_initrd = NULL;
size_t credential_initrd_size = 0, global_credential_initrd_size = 0, sysext_initrd_size = 0, pcrsig_initrd_size = 0, pcrpkey_initrd_size = 0;
@@ -191,6 +375,7 @@ static EFI_STATUS real_main(EFI_HANDLE image) {
size_t addrs[_UNIFIED_SECTION_MAX] = {}, szs[_UNIFIED_SECTION_MAX] = {};
_cleanup_free_ char16_t *cmdline = NULL;
int sections_measured = -1, parameters_measured = -1;
+ _cleanup_free_ char *uname = NULL;
bool sysext_measured = false, m;
uint64_t loader_features = 0;
EFI_STATUS err;
@@ -263,6 +448,10 @@ static EFI_STATUS real_main(EFI_HANDLE image) {
/* Show splash screen as early as possible */
graphics_splash((const uint8_t*) loaded_image->ImageBase + addrs[UNIFIED_SECTION_SPLASH], szs[UNIFIED_SECTION_SPLASH]);
+ if (szs[UNIFIED_SECTION_UNAME] > 0)
+ uname = xstrndup8((char *)loaded_image->ImageBase + addrs[UNIFIED_SECTION_UNAME],
+ szs[UNIFIED_SECTION_UNAME]);
+
if (use_load_options(image, loaded_image, szs[UNIFIED_SECTION_CMDLINE] > 0, &cmdline)) {
/* Let's measure the passed kernel command line into the TPM. Note that this possibly
* duplicates what we already did in the boot menu, if that was already used. However, since
@@ -278,6 +467,33 @@ static EFI_STATUS real_main(EFI_HANDLE image) {
mangle_stub_cmdline(cmdline);
}
+ /* If we have any extra command line to add via PE addons, load them now and append, and
+ * measure the additions separately, after the embedded options, but before the smbios ones,
+ * so that the order is reversed from "most hardcoded" to "most dynamic". The global addons are
+ * loaded first, and the image-specific ones later, for the same reason. */
+ err = cmdline_append_and_measure_addons(
+ image,
+ loaded_image,
+ u"\\loader\\addons",
+ uname,
+ &m,
+ &cmdline);
+ if (err != EFI_SUCCESS)
+ log_error_status(err, "Error loading global addons, ignoring: %m");
+ parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m);
+
+ _cleanup_free_ char16_t *dropin_dir = get_dropin_dir(loaded_image->FilePath);
+ err = cmdline_append_and_measure_addons(
+ image,
+ loaded_image,
+ dropin_dir,
+ uname,
+ &m,
+ &cmdline);
+ if (err != EFI_SUCCESS)
+ log_error_status(err, "Error loading UKI-specific addons, ignoring: %m");
+ parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m);
+
const char *extra = smbios_find_oem_string("io.systemd.stub.kernel-cmdline-extra");
if (extra) {
_cleanup_free_ char16_t *tmp = TAKE_PTR(cmdline), *extra16 = xstr8_to_16(extra);

View File

@ -0,0 +1,29 @@
From a84abc0caba660444d8210107da4c03c03150cd4 Mon Sep 17 00:00:00 2001
From: Luca Boccassi <bluca@debian.org>
Date: Wed, 24 May 2023 11:18:18 +0100
Subject: [PATCH] TODO: remove fixed item
(cherry picked from commit f19b62756071cd6fc28b800062f591a3af88fe6a)
Related: RHEL-16952
---
TODO | 6 ------
1 file changed, 6 deletions(-)
diff --git a/TODO b/TODO
index c512bedb92..abe8faf5e8 100644
--- a/TODO
+++ b/TODO
@@ -249,12 +249,6 @@ Features:
parametrization, if needed. This matches our usual rule that admin config
should win over vendor defaults.
-* sd-stub: optionally allow users to configure manual kernel command line even
- in SecureBoot by authenticating it via shim's APIs, integrating with MOK and
- similar: instead of authenticating just PE code shim should be capable of
- authenticating any kind of data for us, including files containing kernel
- command lines.
-
* write a "search path" spec, that documents the prefixes to search in
(i.e. the usual /etc/, /run/, /usr/lib/ dance, potentially /usr/etc/), how to
sort found entries, how masking works and overriding.

View File

@ -0,0 +1,78 @@
From 529df7ab684596d7dae85da8360138647fa0c46b Mon Sep 17 00:00:00 2001
From: Maanya Goenka <maanyagoenka@microsoft.com>
Date: Wed, 27 Sep 2023 15:44:04 +0000
Subject: [PATCH] fix: do not check/verify slice units if recursive errors are
to be ignored
Before this fix, when recursive-errors was set to 'no' during a systemd-analyze
verification, the parent slice was checked regardless. The 'no' setting means that,
only the specified unit should be looked at and verified and errors in the slices should be
ignored. This commit fixes that issue.
Example:
Say we have a sample.service file:
[Unit]
Description=Sample Service
[Service]
ExecStart=/bin/echo "a"
Slice=support.slice
Before Change:
systemd-analyze verify --recursive-errors=no maanya/sample.service
Assertion 'u' failed at src/core/unit.c:153, function unit_has_name(). Aborting.
Aborted (core dumped)
After Change:
systemd-analyze verify --recursive-errors=no maanya/sample.service
{No errors}
(cherry picked from commit f660c7fa56b247c278fdb2ebcfea37912f249524)
Related: RHEL-1086
---
src/core/slice.c | 4 ++++
test/units/testsuite-65.sh | 12 ++++++++++++
2 files changed, 16 insertions(+)
diff --git a/src/core/slice.c b/src/core/slice.c
index c453aa033e..8f913a8d45 100644
--- a/src/core/slice.c
+++ b/src/core/slice.c
@@ -96,6 +96,10 @@ static int slice_verify(Slice *s) {
if (r < 0)
return log_unit_error_errno(UNIT(s), r, "Failed to determine parent slice: %m");
+ /* If recursive errors are to be ignored, the parent slice should not be verified */
+ if (UNIT(s)->manager && FLAGS_SET(UNIT(s)->manager->test_run_flags, MANAGER_TEST_RUN_IGNORE_DEPENDENCIES))
+ return 0;
+
if (parent ? !unit_has_name(UNIT_GET_SLICE(UNIT(s)), parent) : !!UNIT_GET_SLICE(UNIT(s)))
return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOEXEC), "Located outside of parent slice. Refusing.");
diff --git a/test/units/testsuite-65.sh b/test/units/testsuite-65.sh
index 4093c5a2a7..7c34948f82 100755
--- a/test/units/testsuite-65.sh
+++ b/test/units/testsuite-65.sh
@@ -217,6 +217,18 @@ set -e
rm /tmp/testfile.service
rm /tmp/testfile2.service
+cat <<EOF >/tmp/sample.service
+[Unit]
+Description = A Sample Service
+
+[Service]
+ExecStart = echo hello
+Slice=support.slice
+EOF
+
+# Zero exit status since no additional dependencies are recursively loaded when the unit file is loaded
+systemd-analyze verify --recursive-errors=no /tmp/sample.service
+
cat <<EOF >/tmp/testfile.service
[Service]
ExecStart = echo hello

View File

@ -21,7 +21,7 @@
Name: systemd
Url: https://systemd.io
Version: 252
Release: 27%{?dist}
Release: 28%{?dist}
# For a breakdown of the licensing, see README
License: LGPLv2+ and MIT and GPLv2+
Summary: System and Service Manager
@ -735,6 +735,56 @@ Patch0649: 0649-test-modernize-test-journal-flush.patch
Patch0650: 0650-journal-file-util-do-not-fail-when-journal_file_set_.patch
Patch0651: 0651-journal-file-util-Prefer-punching-holes-instead-of-t.patch
Patch0652: 0652-test-add-reproducer-for-SIGBUS-issue-caused-by-journ.patch
Patch0653: 0653-random-seed-shorten-a-bit-may_credit.patch
Patch0654: 0654-random-seed-make-one-more-use-of-random_write_entrop.patch
Patch0655: 0655-random-seed-use-getopt.patch
Patch0656: 0656-random-seed-make-the-logic-to-calculate-the-number-o.patch
Patch0657: 0657-random-seed-no-need-to-pass-mode-argument-when-openi.patch
Patch0658: 0658-random-seed-split-out-run.patch
Patch0659: 0659-random_seed-minor-improvement-in-run.patch
Patch0660: 0660-random-seed-downgrade-some-messages.patch
Patch0661: 0661-random-seed-clarify-one-comment.patch
Patch0662: 0662-random-seed-make-sure-to-load-machine-id-even-if-the.patch
Patch0663: 0663-chase-symlinks-add-new-flag-for-prohibiting-any-foll.patch
Patch0664: 0664-bootctl-bootspec-make-use-of-CHASE_PROHIBIT_SYMLINKS.patch
Patch0665: 0665-boot-implement-kernel-EFI-RNG-seed-protocol-with-pro.patch
Patch0666: 0666-random-seed-refresh-EFI-boot-seed-when-writing-a-new.patch
Patch0667: 0667-random-seed-handle-post-merge-review-nits.patch
Patch0668: 0668-boot-do-not-truncate-random-seed-file.patch
Patch0669: 0669-bootctl-install-system-token-on-virtualized-systems.patch
Patch0670: 0670-boot-remove-random-seed-mode.patch
Patch0671: 0671-stub-handle-random-seed-like-sd-boot-does.patch
Patch0672: 0672-efi-add-efi_guid_equal-helper.patch
Patch0673: 0673-efi-add-common-implementation-for-loop-finding-EFI-c.patch
Patch0674: 0674-boot-Detect-hypervisors-using-SMBIOS-info.patch
Patch0675: 0675-boot-Skip-soft-brick-warning-when-in-a-VM.patch
Patch0676: 0676-boot-Replace-UINTN-with-size_t.patch
Patch0677: 0677-boot-Use-unsigned-for-beep-counting.patch
Patch0678: 0678-boot-Use-unicode-literals.patch
Patch0679: 0679-macro-add-generic-IS_ALIGNED32-anf-friends.patch
Patch0680: 0680-meson-use-0-1-for-SD_BOOT.patch
Patch0681: 0681-boot-Add-printf-functions.patch
Patch0682: 0682-boot-Use-printf-for-error-logging.patch
Patch0683: 0683-boot-Introduce-log_wait.patch
Patch0684: 0684-boot-Add-log_trace-debugging-helper.patch
Patch0685: 0685-tree-wide-Use-__func__-in-asserts.patch
Patch0686: 0686-boot-Drop-use-of-xpool_print-SPrint.patch
Patch0687: 0687-boot-Drop-use-of-Print.patch
Patch0688: 0688-boot-Rework-GUID-handling.patch
Patch0689: 0689-efi-string-Fix-strchr-null-byte-handling.patch
Patch0690: 0690-efi-string-Add-startswith8.patch
Patch0691: 0691-efi-string-Add-efi_memchr.patch
Patch0692: 0692-vmm-Add-more-const.patch
Patch0693: 0693-vmm-Add-smbios_find_oem_string.patch
Patch0694: 0694-stub-Read-extra-kernel-command-line-items-from-SMBIO.patch
Patch0695: 0695-vmm-Modernize-get_smbios_table.patch
Patch0696: 0696-stub-measure-SMBIOS-kernel-cmdline-extra-in-PCR12.patch
Patch0697: 0697-efi-support-passing-empty-cmdline-to-mangle_stub_cmd.patch
Patch0698: 0698-efi-set-EFIVAR-to-stop-Shim-from-uninstalling-its-pr.patch
Patch0699: 0699-ukify-use-empty-stub-for-addons.patch
Patch0700: 0700-stub-allow-loading-and-verifying-cmdline-addons.patch
Patch0701: 0701-TODO-remove-fixed-item.patch
Patch0702: 0702-fix-do-not-check-verify-slice-units-if-recursive-err.patch
# Downstream-only patches (90009999)
@ -1600,6 +1650,58 @@ systemd-hwdb update &>/dev/null || :
%{_prefix}/lib/dracut/modules.d/70rhel-net-naming-sysattrs/*
%changelog
* Tue Feb 20 2024 systemd maintenance team <systemd-maint@redhat.com> - 252-28
- random-seed: shorten a bit may_credit() (RHEL-16952)
- random-seed: make one more use of random_write_entropy() (RHEL-16952)
- random-seed: use getopt() (RHEL-16952)
- random-seed: make the logic to calculate the number of bytes read from the random seed file clearer (RHEL-16952)
- random-seed: no need to pass 'mode' argument when opening /dev/urandom (RHEL-16952)
- random-seed: split out run() (RHEL-16952)
- random_seed: minor improvement in run() (RHEL-16952)
- random-seed: downgrade some messages (RHEL-16952)
- random-seed: clarify one comment (RHEL-16952)
- random-seed: make sure to load machine id even if the seed file is missing (RHEL-16952)
- chase-symlinks: add new flag for prohibiting any following of symlinks (RHEL-16952)
- bootctl,bootspec: make use of CHASE_PROHIBIT_SYMLINKS whenever we access the ESP/XBOOTLDR (RHEL-16952)
- boot: implement kernel EFI RNG seed protocol with proper hashing (RHEL-16952)
- random-seed: refresh EFI boot seed when writing a new seed (RHEL-16952)
- random-seed: handle post-merge review nits (RHEL-16952)
- boot: do not truncate random seed file (RHEL-16952)
- bootctl: install system token on virtualized systems (RHEL-16952)
- boot: remove random-seed-mode (RHEL-16952)
- stub: handle random seed like sd-boot does (RHEL-16952)
- efi: add efi_guid_equal() helper (RHEL-16952)
- efi: add common implementation for loop finding EFI configuration tables (RHEL-16952)
- boot: Detect hypervisors using SMBIOS info (RHEL-16952)
- boot: Skip soft-brick warning when in a VM (RHEL-16952)
- boot: Replace UINTN with size_t (RHEL-16952)
- boot: Use unsigned for beep counting (RHEL-16952)
- boot: Use unicode literals (RHEL-16952)
- macro: add generic IS_ALIGNED32() anf friends (RHEL-16952)
- meson: use 0|1 for SD_BOOT (RHEL-16952)
- boot: Add printf functions (RHEL-16952)
- boot: Use printf for error logging (RHEL-16952)
- boot: Introduce log_wait (RHEL-16952)
- boot: Add log_trace debugging helper (RHEL-16952)
- tree-wide: Use __func__ in asserts (RHEL-16952)
- boot: Drop use of xpool_print/SPrint (RHEL-16952)
- boot: Drop use of Print (RHEL-16952)
- boot: Rework GUID handling (RHEL-16952)
- efi-string: Fix strchr() null byte handling (RHEL-16952)
- efi-string: Add startswith8() (RHEL-16952)
- efi-string: Add efi_memchr() (RHEL-16952)
- vmm: Add more const (RHEL-16952)
- vmm: Add smbios_find_oem_string() (RHEL-16952)
- stub: Read extra kernel command line items from SMBIOS (RHEL-16952)
- vmm: Modernize get_smbios_table() (RHEL-16952)
- stub: measure SMBIOS kernel-cmdline-extra in PCR12 (RHEL-16952)
- efi: support passing empty cmdline to mangle_stub_cmdline() (RHEL-16952)
- efi: set EFIVAR to stop Shim from uninstalling its protocol (RHEL-16952)
- ukify: use empty stub for addons (RHEL-16952)
- stub: allow loading and verifying cmdline addons (RHEL-16952)
- TODO: remove fixed item (RHEL-16952)
- fix: do not check/verify slice units if recursive errors are to be ignored (RHEL-1086)
* Thu Feb 15 2024 systemd maintenance team <systemd-maint@redhat.com> - 252-27
- test: merge TEST-20-MAINPIDGAMES into TEST-07-PID1 (fixup) (RHEL-1086)
- test: use the default nsec3-iterations value (RHEL-1086)