Import CS systemd-252-46.el9
This commit is contained in:
parent
83748cd7ed
commit
a34de4e57d
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +1,2 @@
|
||||
SOURCES/rhel-net-naming-sysattrs-v0.4.tar.gz
|
||||
SOURCES/rhel-net-naming-sysattrs-v0.5.tar.gz
|
||||
SOURCES/systemd-252.tar.gz
|
||||
|
@ -1,2 +1,2 @@
|
||||
89b6d8ec519fd7d8b64f8d96b6cd0a65af97822b SOURCES/rhel-net-naming-sysattrs-v0.4.tar.gz
|
||||
9ce6834429dbb9cb049de1bdf77bc8c84763709c SOURCES/rhel-net-naming-sysattrs-v0.5.tar.gz
|
||||
7c961dc6e8bb950825b85129f59dc80f4536cabb SOURCES/systemd-252.tar.gz
|
||||
|
47
SOURCES/0653-random-seed-shorten-a-bit-may_credit.patch
Normal file
47
SOURCES/0653-random-seed-shorten-a-bit-may_credit.patch
Normal 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[]) {
|
@ -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");
|
||||
}
|
207
SOURCES/0655-random-seed-use-getopt.patch
Normal file
207
SOURCES/0655-random-seed-use-getopt.patch
Normal 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);
|
||||
|
@ -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)
|
@ -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");
|
||||
|
372
SOURCES/0658-random-seed-split-out-run.patch
Normal file
372
SOURCES/0658-random-seed-split-out-run.patch
Normal 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);
|
34
SOURCES/0659-random_seed-minor-improvement-in-run.patch
Normal file
34
SOURCES/0659-random_seed-minor-improvement-in-run.patch
Normal 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;
|
37
SOURCES/0660-random-seed-downgrade-some-messages.patch
Normal file
37
SOURCES/0660-random-seed-downgrade-some-messages.patch
Normal 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;
|
||||
}
|
33
SOURCES/0661-random-seed-clarify-one-comment.patch
Normal file
33
SOURCES/0661-random-seed-clarify-one-comment.patch
Normal 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");
|
@ -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;
|
@ -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);
|
||||
}
|
@ -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) {
|
@ -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
|
@ -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);
|
181
SOURCES/0667-random-seed-handle-post-merge-review-nits.patch
Normal file
181
SOURCES/0667-random-seed-handle-post-merge-review-nits.patch
Normal 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;
|
50
SOURCES/0668-boot-do-not-truncate-random-seed-file.patch
Normal file
50
SOURCES/0668-boot-do-not-truncate-random-seed-file.patch
Normal 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;
|
@ -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
|
221
SOURCES/0670-boot-remove-random-seed-mode.patch
Normal file
221
SOURCES/0670-boot-remove-random-seed-mode.patch
Normal 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;
|
302
SOURCES/0671-stub-handle-random-seed-like-sd-boot-does.patch
Normal file
302
SOURCES/0671-stub-handle-random-seed-like-sd-boot-does.patch
Normal 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
|
90
SOURCES/0672-efi-add-efi_guid_equal-helper.patch
Normal file
90
SOURCES/0672-efi-add-efi_guid_equal-helper.patch
Normal 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) */
|
@ -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);
|
310
SOURCES/0674-boot-Detect-hypervisors-using-SMBIOS-info.patch
Normal file
310
SOURCES/0674-boot-Detect-hypervisors-using-SMBIOS-info.patch
Normal 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);
|
83
SOURCES/0675-boot-Skip-soft-brick-warning-when-in-a-VM.patch
Normal file
83
SOURCES/0675-boot-Skip-soft-brick-warning-when-in-a-VM.patch
Normal 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;
|
1577
SOURCES/0676-boot-Replace-UINTN-with-size_t.patch
Normal file
1577
SOURCES/0676-boot-Replace-UINTN-with-size_t.patch
Normal file
File diff suppressed because it is too large
Load Diff
42
SOURCES/0677-boot-Use-unsigned-for-beep-counting.patch
Normal file
42
SOURCES/0677-boot-Use-unsigned-for-beep-counting.patch
Normal 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);
|
316
SOURCES/0678-boot-Use-unicode-literals.patch
Normal file
316
SOURCES/0678-boot-Use-unicode-literals.patch
Normal 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,
|
106
SOURCES/0679-macro-add-generic-IS_ALIGNED32-anf-friends.patch
Normal file
106
SOURCES/0679-macro-add-generic-IS_ALIGNED32-anf-friends.patch
Normal 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);
|
214
SOURCES/0680-meson-use-0-1-for-SD_BOOT.patch
Normal file
214
SOURCES/0680-meson-use-0-1-for-SD_BOOT.patch
Normal 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_;
|
843
SOURCES/0681-boot-Add-printf-functions.patch
Normal file
843
SOURCES/0681-boot-Add-printf-functions.patch
Normal 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);
|
965
SOURCES/0682-boot-Use-printf-for-error-logging.patch
Normal file
965
SOURCES/0682-boot-Use-printf-for-error-logging.patch
Normal 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);
|
||||
|
220
SOURCES/0683-boot-Introduce-log_wait.patch
Normal file
220
SOURCES/0683-boot-Introduce-log_wait.patch
Normal 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, ¤t, &uga_exists, &stdin_locked);
|
||||
+ err = ConsoleControl->GetMode(ConsoleControl, ¤t, &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);
|
||||
}
|
21
SOURCES/0684-boot-Add-log_trace-debugging-helper.patch
Normal file
21
SOURCES/0684-boot-Add-log_trace-debugging-helper.patch
Normal 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__)
|
78
SOURCES/0685-tree-wide-Use-__func__-in-asserts.patch
Normal file
78
SOURCES/0685-tree-wide-Use-__func__-in-asserts.patch
Normal 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) {
|
326
SOURCES/0686-boot-Drop-use-of-xpool_print-SPrint.patch
Normal file
326
SOURCES/0686-boot-Drop-use-of-xpool_print-SPrint.patch
Normal 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++) {
|
323
SOURCES/0687-boot-Drop-use-of-Print.patch
Normal file
323
SOURCES/0687-boot-Drop-use-of-Print.patch
Normal 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
|
1107
SOURCES/0688-boot-Rework-GUID-handling.patch
Normal file
1107
SOURCES/0688-boot-Rework-GUID-handling.patch
Normal file
File diff suppressed because it is too large
Load Diff
51
SOURCES/0689-efi-string-Fix-strchr-null-byte-handling.patch
Normal file
51
SOURCES/0689-efi-string-Fix-strchr-null-byte-handling.patch
Normal 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) {
|
79
SOURCES/0690-efi-string-Add-startswith8.patch
Normal file
79
SOURCES/0690-efi-string-Add-startswith8.patch
Normal 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)); \
|
93
SOURCES/0691-efi-string-Add-efi_memchr.patch
Normal file
93
SOURCES/0691-efi-string-Add-efi_memchr.patch
Normal 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);
|
70
SOURCES/0692-vmm-Add-more-const.patch
Normal file
70
SOURCES/0692-vmm-Add-more-const.patch
Normal 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;
|
||||
|
107
SOURCES/0693-vmm-Add-smbios_find_oem_string.patch
Normal file
107
SOURCES/0693-vmm-Add-smbios_find_oem_string.patch
Normal 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);
|
@ -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,
|
46
SOURCES/0695-vmm-Modernize-get_smbios_table.patch
Normal file
46
SOURCES/0695-vmm-Modernize-get_smbios_table.patch
Normal 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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
@ -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)
|
@ -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);
|
78
SOURCES/0699-ukify-use-empty-stub-for-addons.patch
Normal file
78
SOURCES/0699-ukify-use-empty-stub-for-addons.patch
Normal 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],
|
@ -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);
|
29
SOURCES/0701-TODO-remove-fixed-item.patch
Normal file
29
SOURCES/0701-TODO-remove-fixed-item.patch
Normal 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.
|
@ -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
|
@ -0,0 +1,31 @@
|
||||
From 1db73293a8a69372a0cc020855f2402ab49600dd Mon Sep 17 00:00:00 2001
|
||||
From: Luca Boccassi <bluca@debian.org>
|
||||
Date: Thu, 24 Nov 2022 10:01:59 +0000
|
||||
Subject: [PATCH] units: fix typo in Condition in systemd-boot-system-token
|
||||
|
||||
/lib/systemd/system/systemd-boot-system-token.service:20: Unknown key name 'ConditionPathExists|' in section 'Unit', ignoring
|
||||
|
||||
Follow-up for 0a1d8ac77a21ae0741bdf4af08f3a71354805ff1
|
||||
|
||||
(cherry picked from commit 0f6d54ca47662f1386ada65ed179a1afd6e727e4)
|
||||
|
||||
Related: RHEL-16952
|
||||
---
|
||||
units/systemd-boot-system-token.service | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/units/systemd-boot-system-token.service b/units/systemd-boot-system-token.service
|
||||
index 63e523bb3e..ef5577549e 100644
|
||||
--- a/units/systemd-boot-system-token.service
|
||||
+++ b/units/systemd-boot-system-token.service
|
||||
@@ -17,8 +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/StubFeatures-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
|
@ -0,0 +1,184 @@
|
||||
From bcb4e65f7ab49fd94b002ff9e1bba24237082726 Mon Sep 17 00:00:00 2001
|
||||
From: Jacek Migacz <jmigacz@redhat.com>
|
||||
Date: Mon, 26 Feb 2024 14:05:37 +0100
|
||||
Subject: [PATCH] resolved: limit the number of signature validations in a
|
||||
transaction
|
||||
|
||||
It has been demonstrated that tolerating an unbounded number of dnssec
|
||||
signature validations is a bad idea. It is easy for a maliciously
|
||||
crafted DNS reply to contain as many keytag collisions as desired,
|
||||
causing us to iterate every dnskey and signature combination in vain.
|
||||
|
||||
The solution is to impose a maximum number of validations we will
|
||||
tolerate. While collisions are not hard to craft, I still expect they
|
||||
are unlikely in the wild so it should be safe to pick fairly small
|
||||
values.
|
||||
|
||||
Here two limits are imposed: one on the maximum number of invalid
|
||||
signatures encountered per rrset, and another on the total number of
|
||||
validations performed per transaction.
|
||||
|
||||
(cherry picked from commit 67d0ce8843d612a2245d0966197d4f528b911b66)
|
||||
|
||||
Resolves: RHEL-26643
|
||||
---
|
||||
src/resolve/resolved-dns-dnssec.c | 16 ++++++++++++++--
|
||||
src/resolve/resolved-dns-dnssec.h | 9 ++++++++-
|
||||
src/resolve/resolved-dns-transaction.c | 19 ++++++++++++++++---
|
||||
3 files changed, 38 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c
|
||||
index 426ea945ca..de2660e317 100644
|
||||
--- a/src/resolve/resolved-dns-dnssec.c
|
||||
+++ b/src/resolve/resolved-dns-dnssec.c
|
||||
@@ -1176,6 +1176,7 @@ int dnssec_verify_rrset_search(
|
||||
DnsResourceRecord **ret_rrsig) {
|
||||
|
||||
bool found_rrsig = false, found_invalid = false, found_expired_rrsig = false, found_unsupported_algorithm = false;
|
||||
+ unsigned nvalidations = 0;
|
||||
DnsResourceRecord *rrsig;
|
||||
int r;
|
||||
|
||||
@@ -1221,6 +1222,14 @@ int dnssec_verify_rrset_search(
|
||||
if (realtime == USEC_INFINITY)
|
||||
realtime = now(CLOCK_REALTIME);
|
||||
|
||||
+ /* Have we seen an unreasonable number of invalid signaures? */
|
||||
+ if (nvalidations > DNSSEC_INVALID_MAX) {
|
||||
+ if (ret_rrsig)
|
||||
+ *ret_rrsig = NULL;
|
||||
+ *result = DNSSEC_TOO_MANY_VALIDATIONS;
|
||||
+ return (int) nvalidations;
|
||||
+ }
|
||||
+
|
||||
/* Yay, we found a matching RRSIG with a matching
|
||||
* DNSKEY, awesome. Now let's verify all entries of
|
||||
* the RRSet against the RRSIG and DNSKEY
|
||||
@@ -1230,6 +1239,8 @@ int dnssec_verify_rrset_search(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
+ nvalidations++;
|
||||
+
|
||||
switch (one_result) {
|
||||
|
||||
case DNSSEC_VALIDATED:
|
||||
@@ -1240,7 +1251,7 @@ int dnssec_verify_rrset_search(
|
||||
*ret_rrsig = rrsig;
|
||||
|
||||
*result = one_result;
|
||||
- return 0;
|
||||
+ return (int) nvalidations;
|
||||
|
||||
case DNSSEC_INVALID:
|
||||
/* If the signature is invalid, let's try another
|
||||
@@ -1287,7 +1298,7 @@ int dnssec_verify_rrset_search(
|
||||
if (ret_rrsig)
|
||||
*ret_rrsig = NULL;
|
||||
|
||||
- return 0;
|
||||
+ return (int) nvalidations;
|
||||
}
|
||||
|
||||
int dnssec_has_rrsig(DnsAnswer *a, const DnsResourceKey *key) {
|
||||
@@ -2571,6 +2582,7 @@ static const char* const dnssec_result_table[_DNSSEC_RESULT_MAX] = {
|
||||
[DNSSEC_FAILED_AUXILIARY] = "failed-auxiliary",
|
||||
[DNSSEC_NSEC_MISMATCH] = "nsec-mismatch",
|
||||
[DNSSEC_INCOMPATIBLE_SERVER] = "incompatible-server",
|
||||
+ [DNSSEC_TOO_MANY_VALIDATIONS] = "too-many-validations",
|
||||
};
|
||||
DEFINE_STRING_TABLE_LOOKUP(dnssec_result, DnssecResult);
|
||||
|
||||
diff --git a/src/resolve/resolved-dns-dnssec.h b/src/resolve/resolved-dns-dnssec.h
|
||||
index 954bb3ef9d..29b90130a3 100644
|
||||
--- a/src/resolve/resolved-dns-dnssec.h
|
||||
+++ b/src/resolve/resolved-dns-dnssec.h
|
||||
@@ -9,12 +9,13 @@ typedef enum DnssecVerdict DnssecVerdict;
|
||||
#include "resolved-dns-rr.h"
|
||||
|
||||
enum DnssecResult {
|
||||
- /* These five are returned by dnssec_verify_rrset() */
|
||||
+ /* These six are returned by dnssec_verify_rrset() */
|
||||
DNSSEC_VALIDATED,
|
||||
DNSSEC_VALIDATED_WILDCARD, /* Validated via a wildcard RRSIG, further NSEC/NSEC3 checks necessary */
|
||||
DNSSEC_INVALID,
|
||||
DNSSEC_SIGNATURE_EXPIRED,
|
||||
DNSSEC_UNSUPPORTED_ALGORITHM,
|
||||
+ DNSSEC_TOO_MANY_VALIDATIONS,
|
||||
|
||||
/* These two are added by dnssec_verify_rrset_search() */
|
||||
DNSSEC_NO_SIGNATURE,
|
||||
@@ -45,6 +46,12 @@ enum DnssecVerdict {
|
||||
/* The longest digest we'll ever generate, of all digest algorithms we support */
|
||||
#define DNSSEC_HASH_SIZE_MAX (MAX(20, 32))
|
||||
|
||||
+/* The most invalid signatures we will tolerate for a single rrset */
|
||||
+#define DNSSEC_INVALID_MAX 5
|
||||
+
|
||||
+/* The total number of signature validations we will tolerate for a single transaction */
|
||||
+#define DNSSEC_VALIDATION_MAX 64
|
||||
+
|
||||
int dnssec_rrsig_match_dnskey(DnsResourceRecord *rrsig, DnsResourceRecord *dnskey, bool revoked_ok);
|
||||
int dnssec_key_match_rrsig(const DnsResourceKey *key, DnsResourceRecord *rrsig);
|
||||
|
||||
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
|
||||
index 0306af84a2..ccca49d399 100644
|
||||
--- a/src/resolve/resolved-dns-transaction.c
|
||||
+++ b/src/resolve/resolved-dns-transaction.c
|
||||
@@ -3140,11 +3140,14 @@ static int dnssec_validate_records(
|
||||
DnsTransaction *t,
|
||||
Phase phase,
|
||||
bool *have_nsec,
|
||||
+ unsigned *nvalidations,
|
||||
DnsAnswer **validated) {
|
||||
|
||||
DnsResourceRecord *rr;
|
||||
int r;
|
||||
|
||||
+ assert(nvalidations);
|
||||
+
|
||||
/* Returns negative on error, 0 if validation failed, 1 to restart validation, 2 when finished. */
|
||||
|
||||
DNS_ANSWER_FOREACH(rr, t->answer) {
|
||||
@@ -3186,6 +3189,7 @@ static int dnssec_validate_records(
|
||||
&rrsig);
|
||||
if (r < 0)
|
||||
return r;
|
||||
+ *nvalidations += r;
|
||||
|
||||
log_debug("Looking at %s: %s", strna(dns_resource_record_to_string(rr)), dnssec_result_to_string(result));
|
||||
|
||||
@@ -3383,7 +3387,8 @@ static int dnssec_validate_records(
|
||||
DNSSEC_SIGNATURE_EXPIRED,
|
||||
DNSSEC_NO_SIGNATURE))
|
||||
manager_dnssec_verdict(t->scope->manager, DNSSEC_BOGUS, rr->key);
|
||||
- else /* DNSSEC_MISSING_KEY or DNSSEC_UNSUPPORTED_ALGORITHM */
|
||||
+ else /* DNSSEC_MISSING_KEY, DNSSEC_UNSUPPORTED_ALGORITHM,
|
||||
+ or DNSSEC_TOO_MANY_VALIDATIONS */
|
||||
manager_dnssec_verdict(t->scope->manager, DNSSEC_INDETERMINATE, rr->key);
|
||||
|
||||
/* This is a primary response to our question, and it failed validation.
|
||||
@@ -3476,13 +3481,21 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) {
|
||||
return r;
|
||||
|
||||
phase = DNSSEC_PHASE_DNSKEY;
|
||||
- for (;;) {
|
||||
+ for (unsigned nvalidations = 0;;) {
|
||||
bool have_nsec = false;
|
||||
|
||||
- r = dnssec_validate_records(t, phase, &have_nsec, &validated);
|
||||
+ r = dnssec_validate_records(t, phase, &have_nsec, &nvalidations, &validated);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
+ if (nvalidations > DNSSEC_VALIDATION_MAX) {
|
||||
+ /* This reply requires an onerous number of signature validations to verify. Let's
|
||||
+ * not waste our time trying, as this shouldn't happen for well-behaved domains
|
||||
+ * anyway. */
|
||||
+ t->answer_dnssec_result = DNSSEC_TOO_MANY_VALIDATIONS;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
/* Try again as long as we managed to achieve something */
|
||||
if (r == 1)
|
||||
continue;
|
@ -0,0 +1,34 @@
|
||||
From f7b027e1a0dcdd2c92a5f3b1bcd488912389dca4 Mon Sep 17 00:00:00 2001
|
||||
From: Jacek Migacz <jmigacz@redhat.com>
|
||||
Date: Mon, 26 Feb 2024 14:07:37 +0100
|
||||
Subject: [PATCH] resolved: reduce the maximum nsec3 iterations to 100
|
||||
|
||||
According to RFC9267, the 2500 value is not helpful, and in fact it can
|
||||
be harmful to permit a large number of iterations. Combined with limits
|
||||
on the number of signature validations, I expect this will mitigate the
|
||||
impact of maliciously crafted domains designed to cause excessive
|
||||
cryptographic work.
|
||||
|
||||
(cherry picked from commit eba291124bc11f03732d1fc468db3bfac069f9cb)
|
||||
|
||||
Related: RHEL-26643
|
||||
---
|
||||
src/resolve/resolved-dns-dnssec.c | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c
|
||||
index de2660e317..df25b7f619 100644
|
||||
--- a/src/resolve/resolved-dns-dnssec.c
|
||||
+++ b/src/resolve/resolved-dns-dnssec.c
|
||||
@@ -27,8 +27,9 @@ DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EC_KEY*, EC_KEY_free, NULL);
|
||||
/* Permit a maximum clock skew of 1h 10min. This should be enough to deal with DST confusion */
|
||||
#define SKEW_MAX (1*USEC_PER_HOUR + 10*USEC_PER_MINUTE)
|
||||
|
||||
-/* Maximum number of NSEC3 iterations we'll do. RFC5155 says 2500 shall be the maximum useful value */
|
||||
-#define NSEC3_ITERATIONS_MAX 2500
|
||||
+/* Maximum number of NSEC3 iterations we'll do. RFC5155 says 2500 shall be the maximum useful value, but
|
||||
+ * RFC9276 § 3.2 says that we should reduce the acceptable iteration count */
|
||||
+#define NSEC3_ITERATIONS_MAX 100
|
||||
|
||||
/*
|
||||
* The DNSSEC Chain of trust:
|
@ -0,0 +1,28 @@
|
||||
From 4d3b9819a24f233f66f46a8d153f56e7d73cc809 Mon Sep 17 00:00:00 2001
|
||||
From: Michal Sekletar <msekleta@redhat.com>
|
||||
Date: Thu, 29 Feb 2024 17:51:33 +0100
|
||||
Subject: [PATCH] efi: alignment of the PE file has to be at least 512 bytes
|
||||
|
||||
https://learn.microsoft.com/en-us/windows/win32/debug/pe-format?redirectedfrom=MSDN#optional-header-windows-specific-fields-image-only
|
||||
|
||||
Resolves: RHEL-26133
|
||||
|
||||
RHEL-only
|
||||
|
||||
[msekleta: this is RHEL-only because upstream no longer uses objcopy to create PE files]
|
||||
---
|
||||
src/boot/efi/meson.build | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/src/boot/efi/meson.build b/src/boot/efi/meson.build
|
||||
index b84ceb8c9f..c4eb471451 100644
|
||||
--- a/src/boot/efi/meson.build
|
||||
+++ b/src/boot/efi/meson.build
|
||||
@@ -485,6 +485,7 @@ foreach tuple : [['systemd-boot@0@.@1@', systemd_boot_objects, false, 'systemd-b
|
||||
'-j', '.sdata',
|
||||
'-j', '.sdmagic',
|
||||
'-j', '.text',
|
||||
+ '--file-alignment=512',
|
||||
'--section-alignment=512',
|
||||
efi_format,
|
||||
'@INPUT@', '@OUTPUT@'],
|
@ -0,0 +1,101 @@
|
||||
From 1c4cb49d13264fe1e3de51d64b293b964439fee5 Mon Sep 17 00:00:00 2001
|
||||
From: Luca Boccassi <bluca@debian.org>
|
||||
Date: Wed, 8 Feb 2023 23:06:27 +0000
|
||||
Subject: [PATCH] units: change assert to condition to skip running in
|
||||
initrd/os
|
||||
|
||||
These units are also present in the initrd, so instead of an assert,
|
||||
just use a condition so they are skipped where they need to be skipped.
|
||||
|
||||
Fixes https://github.com/systemd/systemd/issues/26358
|
||||
|
||||
(cherry picked from commit 7ef09e2099a4f97ad40748d6b7c735b45aa4c990)
|
||||
|
||||
Related: RHEL-16182
|
||||
---
|
||||
units/systemd-pcrfs-root.service.in | 2 +-
|
||||
units/systemd-pcrfs@.service.in | 2 +-
|
||||
units/systemd-pcrmachine.service.in | 2 +-
|
||||
units/systemd-pcrphase-initrd.service.in | 2 +-
|
||||
units/systemd-pcrphase-sysinit.service.in | 2 +-
|
||||
units/systemd-pcrphase.service.in | 2 +-
|
||||
6 files changed, 6 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/units/systemd-pcrfs-root.service.in b/units/systemd-pcrfs-root.service.in
|
||||
index b0da413bb4..432eb9fd8c 100644
|
||||
--- a/units/systemd-pcrfs-root.service.in
|
||||
+++ b/units/systemd-pcrfs-root.service.in
|
||||
@@ -14,7 +14,7 @@ DefaultDependencies=no
|
||||
Conflicts=shutdown.target
|
||||
After=systemd-pcrmachine.service
|
||||
Before=shutdown.target
|
||||
-AssertPathExists=!/etc/initrd-release
|
||||
+ConditionPathExists=!/etc/initrd-release
|
||||
ConditionSecurity=tpm2
|
||||
ConditionPathExists=/sys/firmware/efi/efivars/StubPcrKernelImage-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
|
||||
|
||||
diff --git a/units/systemd-pcrfs@.service.in b/units/systemd-pcrfs@.service.in
|
||||
index ec1ff118c3..6bbd4b72a5 100644
|
||||
--- a/units/systemd-pcrfs@.service.in
|
||||
+++ b/units/systemd-pcrfs@.service.in
|
||||
@@ -15,7 +15,7 @@ BindsTo=%i.mount
|
||||
Conflicts=shutdown.target
|
||||
After=%i.mount systemd-pcrfs-root.service
|
||||
Before=shutdown.target
|
||||
-AssertPathExists=!/etc/initrd-release
|
||||
+ConditionPathExists=!/etc/initrd-release
|
||||
ConditionSecurity=tpm2
|
||||
ConditionPathExists=/sys/firmware/efi/efivars/StubPcrKernelImage-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
|
||||
|
||||
diff --git a/units/systemd-pcrmachine.service.in b/units/systemd-pcrmachine.service.in
|
||||
index e154a7eec1..f1c6ce9f26 100644
|
||||
--- a/units/systemd-pcrmachine.service.in
|
||||
+++ b/units/systemd-pcrmachine.service.in
|
||||
@@ -13,7 +13,7 @@ Documentation=man:systemd-pcrmachine.service(8)
|
||||
DefaultDependencies=no
|
||||
Conflicts=shutdown.target
|
||||
Before=sysinit.target shutdown.target
|
||||
-AssertPathExists=!/etc/initrd-release
|
||||
+ConditionPathExists=!/etc/initrd-release
|
||||
ConditionSecurity=tpm2
|
||||
ConditionPathExists=/sys/firmware/efi/efivars/StubPcrKernelImage-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
|
||||
|
||||
diff --git a/units/systemd-pcrphase-initrd.service.in b/units/systemd-pcrphase-initrd.service.in
|
||||
index e437c7e1ce..6320dccf27 100644
|
||||
--- a/units/systemd-pcrphase-initrd.service.in
|
||||
+++ b/units/systemd-pcrphase-initrd.service.in
|
||||
@@ -13,7 +13,7 @@ Documentation=man:systemd-pcrphase-initrd.service(8)
|
||||
DefaultDependencies=no
|
||||
Conflicts=shutdown.target initrd-switch-root.target
|
||||
Before=sysinit.target cryptsetup-pre.target cryptsetup.target shutdown.target initrd-switch-root.target systemd-sysext.service
|
||||
-AssertPathExists=/etc/initrd-release
|
||||
+ConditionPathExists=/etc/initrd-release
|
||||
ConditionSecurity=tpm2
|
||||
ConditionPathExists=/sys/firmware/efi/efivars/StubPcrKernelImage-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
|
||||
|
||||
diff --git a/units/systemd-pcrphase-sysinit.service.in b/units/systemd-pcrphase-sysinit.service.in
|
||||
index a22fbbe935..f00ad61257 100644
|
||||
--- a/units/systemd-pcrphase-sysinit.service.in
|
||||
+++ b/units/systemd-pcrphase-sysinit.service.in
|
||||
@@ -14,7 +14,7 @@ DefaultDependencies=no
|
||||
Conflicts=shutdown.target
|
||||
After=sysinit.target
|
||||
Before=basic.target shutdown.target
|
||||
-AssertPathExists=!/etc/initrd-release
|
||||
+ConditionPathExists=!/etc/initrd-release
|
||||
ConditionSecurity=tpm2
|
||||
ConditionPathExists=/sys/firmware/efi/efivars/StubPcrKernelImage-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
|
||||
|
||||
diff --git a/units/systemd-pcrphase.service.in b/units/systemd-pcrphase.service.in
|
||||
index 5ba437e5b1..558f268857 100644
|
||||
--- a/units/systemd-pcrphase.service.in
|
||||
+++ b/units/systemd-pcrphase.service.in
|
||||
@@ -12,7 +12,7 @@ Description=TPM2 PCR Barrier (User)
|
||||
Documentation=man:systemd-pcrphase.service(8)
|
||||
After=remote-fs.target remote-cryptsetup.target
|
||||
Before=systemd-user-sessions.service
|
||||
-AssertPathExists=!/etc/initrd-release
|
||||
+ConditionPathExists=!/etc/initrd-release
|
||||
ConditionSecurity=tpm2
|
||||
ConditionPathExists=/sys/firmware/efi/efivars/StubPcrKernelImage-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
|
||||
|
@ -0,0 +1,20 @@
|
||||
From afb45c747f66526ec015372155c08baf74f4b988 Mon Sep 17 00:00:00 2001
|
||||
From: Jan Macku <jamacku@redhat.com>
|
||||
Date: Mon, 4 Mar 2024 13:37:41 +0100
|
||||
Subject: [PATCH] ci: add configuration for regression sniffer GA
|
||||
|
||||
rhel-only
|
||||
|
||||
Related: RHEL-1086
|
||||
---
|
||||
.github/regression-sniffer.yml | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
create mode 100644 .github/regression-sniffer.yml
|
||||
|
||||
diff --git a/.github/regression-sniffer.yml b/.github/regression-sniffer.yml
|
||||
new file mode 100644
|
||||
index 0000000000..3824028e92
|
||||
--- /dev/null
|
||||
+++ b/.github/regression-sniffer.yml
|
||||
@@ -0,0 +1 @@
|
||||
+upstream: systemd/systemd
|
@ -0,0 +1,120 @@
|
||||
From e12d41f584e33c0183a47d6c7211ccbf23f3e6a4 Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Mon, 19 Dec 2022 22:26:30 +0100
|
||||
Subject: [PATCH] bootctl: rework random seed logic to use open_mkdir_at() and
|
||||
openat()
|
||||
|
||||
This doesn't really fix anything, but in general we should put stronger
|
||||
emphasis on operating via dir fds rather than paths more (in particular
|
||||
when writing files as opposed to consuming them).
|
||||
|
||||
No real change in behaviour.
|
||||
|
||||
(cherry picked from commit 6b97b267bf990b2ec553efae229b7996dc262996)
|
||||
|
||||
Related: RHEL-16952
|
||||
---
|
||||
src/boot/bootctl.c | 57 +++++++++++++++++++++++-----------------------
|
||||
1 file changed, 29 insertions(+), 28 deletions(-)
|
||||
|
||||
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
|
||||
index c994be272b..9bb99eeec1 100644
|
||||
--- a/src/boot/bootctl.c
|
||||
+++ b/src/boot/bootctl.c
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "fileio.h"
|
||||
#include "find-esp.h"
|
||||
#include "fs-util.h"
|
||||
+#include "io-util.h"
|
||||
#include "glyph-util.h"
|
||||
#include "main-func.h"
|
||||
#include "mkdir.h"
|
||||
@@ -1983,53 +1984,47 @@ 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_close_ int esp_fd = -EBADF, loader_dir_fd = -EBADF, fd = -EBADF;
|
||||
+ _cleanup_free_ char *tmp = NULL;
|
||||
uint8_t buffer[RANDOM_EFI_SEED_SIZE];
|
||||
- _cleanup_free_ char *path = NULL;
|
||||
- _cleanup_close_ int fd = -1;
|
||||
size_t token_size;
|
||||
- ssize_t n;
|
||||
int r;
|
||||
|
||||
assert(esp);
|
||||
|
||||
- path = path_join(esp, "/loader/random-seed");
|
||||
- if (!path)
|
||||
- return log_oom();
|
||||
+ esp_fd = open(esp, O_DIRECTORY|O_RDONLY|O_CLOEXEC);
|
||||
+ if (esp_fd < 0)
|
||||
+ return log_error_errno(errno, "Failed to open ESP directory '%s': %m", esp);
|
||||
+
|
||||
+ loader_dir_fd = open_mkdir_at(esp_fd, "loader", O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOFOLLOW, 0775);
|
||||
+ if (loader_dir_fd < 0)
|
||||
+ return log_error_errno(loader_dir_fd, "Failed to open loader directory '%s/loader': %m", esp);
|
||||
|
||||
r = crypto_random_bytes(buffer, sizeof(buffer));
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to acquire random seed: %m");
|
||||
|
||||
- /* Normally create_subdirs() should already have created everything we need, but in case "bootctl
|
||||
- * random-seed" is called we want to just create the minimum we need for it, and not the full
|
||||
- * list. */
|
||||
- r = mkdir_parents(path, 0755);
|
||||
- if (r < 0)
|
||||
- return log_error_errno(r, "Failed to create parent directory for %s: %m", path);
|
||||
-
|
||||
- r = tempfn_random(path, "bootctl", &tmp);
|
||||
- if (r < 0)
|
||||
+ if (tempfn_random("random-seed", "bootctl", &tmp) < 0)
|
||||
return log_oom();
|
||||
|
||||
- fd = open(tmp, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|O_WRONLY|O_CLOEXEC, 0600);
|
||||
- if (fd < 0) {
|
||||
- tmp = mfree(tmp);
|
||||
+ fd = openat(loader_dir_fd, tmp, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|O_WRONLY|O_CLOEXEC, 0600);
|
||||
+ if (fd < 0)
|
||||
return log_error_errno(fd, "Failed to open random seed file for writing: %m");
|
||||
- }
|
||||
|
||||
- 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 != sizeof(buffer))
|
||||
- return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short write while writing random seed file.");
|
||||
+ r = loop_write(fd, buffer, sizeof(buffer), /* do_poll= */ false);
|
||||
+ if (r < 0) {
|
||||
+ log_error_errno(r, "Failed to write random seed file: %m");
|
||||
+ goto fail;
|
||||
+ }
|
||||
|
||||
- if (rename(tmp, path) < 0)
|
||||
- return log_error_errno(errno, "Failed to move random seed file into place: %m");
|
||||
+ if (renameat(loader_dir_fd, tmp, loader_dir_fd, "random-seed") < 0) {
|
||||
+ r = log_error_errno(errno, "Failed to move random seed file into place: %m");
|
||||
+ goto fail;
|
||||
+ }
|
||||
|
||||
tmp = mfree(tmp);
|
||||
|
||||
- log_info("Random seed file %s successfully written (%zu bytes).", path, sizeof(buffer));
|
||||
+ log_info("Random seed file %s/loader/random-seed successfully written (%zu bytes).", esp, sizeof(buffer));
|
||||
|
||||
if (!arg_touch_variables)
|
||||
return 0;
|
||||
@@ -2092,6 +2087,12 @@ static int install_random_seed(const char *esp) {
|
||||
}
|
||||
|
||||
return 0;
|
||||
+
|
||||
+fail:
|
||||
+ if (tmp)
|
||||
+ (void) unlinkat(loader_dir_fd, tmp, 0);
|
||||
+
|
||||
+ return r;
|
||||
}
|
||||
|
||||
static int sync_everything(void) {
|
@ -0,0 +1,51 @@
|
||||
From 30aa0b51b3edba2cda99abf32e7965afb4ea311c Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Tue, 20 Dec 2022 11:15:51 +0100
|
||||
Subject: [PATCH] bootctl: properly sync fs before/after moving random seed
|
||||
file into place
|
||||
|
||||
Let's do a careful, focussed sync at the right places instead of a
|
||||
blanket sync at the end. After all we want to run this on every boot
|
||||
soon.
|
||||
|
||||
(cherry picked from commit 60315d59534fe59aacae26e2c497359a409af0b6)
|
||||
|
||||
Related: RHEL-16952
|
||||
---
|
||||
src/boot/bootctl.c | 9 ++++++++-
|
||||
1 file changed, 8 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
|
||||
index 9bb99eeec1..5edcf0fc32 100644
|
||||
--- a/src/boot/bootctl.c
|
||||
+++ b/src/boot/bootctl.c
|
||||
@@ -2017,6 +2017,11 @@ static int install_random_seed(const char *esp) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
+ if (fsync(fd) < 0 || fsync(loader_dir_fd) < 0) {
|
||||
+ r = log_error_errno(errno, "Failed to sync random seed file: %m");
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
if (renameat(loader_dir_fd, tmp, loader_dir_fd, "random-seed") < 0) {
|
||||
r = log_error_errno(errno, "Failed to move random seed file into place: %m");
|
||||
goto fail;
|
||||
@@ -2024,6 +2029,9 @@ static int install_random_seed(const char *esp) {
|
||||
|
||||
tmp = mfree(tmp);
|
||||
|
||||
+ if (syncfs(fd) < 0)
|
||||
+ return log_error_errno(errno, "Failed to sync ESP file system: %m");
|
||||
+
|
||||
log_info("Random seed file %s/loader/random-seed successfully written (%zu bytes).", esp, sizeof(buffer));
|
||||
|
||||
if (!arg_touch_variables)
|
||||
@@ -2468,7 +2476,6 @@ static int verb_random_seed(int argc, char *argv[], void *userdata) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
- (void) sync_everything();
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,90 @@
|
||||
From a698bb3a2dd4fec2302e0aebef4d8359d8d4cf40 Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Tue, 20 Dec 2022 11:48:21 +0100
|
||||
Subject: [PATCH] bootctl: when updating EFI random seed file, hash old seed
|
||||
with new one
|
||||
|
||||
Let's not regress in entropy in any case.
|
||||
|
||||
This does what f913c784ad4c93894fd6cb2590738113dff5a694 also does.
|
||||
|
||||
(cherry picked from commit 114172fbe75b247883dd873cafb9209e4a2bd778)
|
||||
|
||||
Related: RHEL-16952
|
||||
---
|
||||
src/boot/bootctl.c | 36 +++++++++++++++++++++++++++++++++++-
|
||||
1 file changed, 35 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
|
||||
index 5edcf0fc32..fe8d7e83a1 100644
|
||||
--- a/src/boot/bootctl.c
|
||||
+++ b/src/boot/bootctl.c
|
||||
@@ -43,6 +43,7 @@
|
||||
#include "pretty-print.h"
|
||||
#include "random-util.h"
|
||||
#include "rm-rf.h"
|
||||
+#include "sha256.h"
|
||||
#include "stat-util.h"
|
||||
#include "stdio-util.h"
|
||||
#include "string-table.h"
|
||||
@@ -1987,11 +1988,15 @@ static int install_random_seed(const char *esp) {
|
||||
_cleanup_close_ int esp_fd = -EBADF, loader_dir_fd = -EBADF, fd = -EBADF;
|
||||
_cleanup_free_ char *tmp = NULL;
|
||||
uint8_t buffer[RANDOM_EFI_SEED_SIZE];
|
||||
+ struct sha256_ctx hash_state;
|
||||
size_t token_size;
|
||||
+ bool refreshed;
|
||||
int r;
|
||||
|
||||
assert(esp);
|
||||
|
||||
+ assert_cc(RANDOM_EFI_SEED_SIZE == SHA256_DIGEST_SIZE);
|
||||
+
|
||||
esp_fd = open(esp, O_DIRECTORY|O_RDONLY|O_CLOEXEC);
|
||||
if (esp_fd < 0)
|
||||
return log_error_errno(errno, "Failed to open ESP directory '%s': %m", esp);
|
||||
@@ -2004,6 +2009,35 @@ static int install_random_seed(const char *esp) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to acquire random seed: %m");
|
||||
|
||||
+ sha256_init_ctx(&hash_state);
|
||||
+ sha256_process_bytes(&(const size_t) { sizeof(buffer) }, sizeof(size_t), &hash_state);
|
||||
+ sha256_process_bytes(buffer, sizeof(buffer), &hash_state);
|
||||
+
|
||||
+ fd = openat(loader_dir_fd, "random-seed", O_NOFOLLOW|O_CLOEXEC|O_RDONLY|O_NOCTTY);
|
||||
+ if (fd < 0) {
|
||||
+ if (errno != ENOENT)
|
||||
+ return log_error_errno(errno, "Failed to open old random seed file: %m");
|
||||
+
|
||||
+ sha256_process_bytes(&(const ssize_t) { 0 }, sizeof(ssize_t), &hash_state);
|
||||
+ refreshed = false;
|
||||
+ } else {
|
||||
+ ssize_t n;
|
||||
+
|
||||
+ /* Hash the old seed in so that we never regress in entropy. */
|
||||
+
|
||||
+ n = read(fd, buffer, sizeof(buffer));
|
||||
+ if (n < 0)
|
||||
+ return log_error_errno(errno, "Failed to read old random seed file: %m");
|
||||
+
|
||||
+ sha256_process_bytes(&n, sizeof(n), &hash_state);
|
||||
+ sha256_process_bytes(buffer, n, &hash_state);
|
||||
+
|
||||
+ fd = safe_close(fd);
|
||||
+ refreshed = n > 0;
|
||||
+ }
|
||||
+
|
||||
+ sha256_finish_ctx(&hash_state, buffer);
|
||||
+
|
||||
if (tempfn_random("random-seed", "bootctl", &tmp) < 0)
|
||||
return log_oom();
|
||||
|
||||
@@ -2032,7 +2066,7 @@ static int install_random_seed(const char *esp) {
|
||||
if (syncfs(fd) < 0)
|
||||
return log_error_errno(errno, "Failed to sync ESP file system: %m");
|
||||
|
||||
- log_info("Random seed file %s/loader/random-seed successfully written (%zu bytes).", esp, sizeof(buffer));
|
||||
+ log_info("Random seed file %s/loader/random-seed successfully %s (%zu bytes).", esp, refreshed ? "refreshed" : "written", sizeof(buffer));
|
||||
|
||||
if (!arg_touch_variables)
|
||||
return 0;
|
@ -0,0 +1,101 @@
|
||||
From 7b9e71d4f8d01557da700f2da11870f6246abdf2 Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Tue, 20 Dec 2022 11:53:37 +0100
|
||||
Subject: [PATCH] sha256: add helper than hashes a buffer *and* its size
|
||||
|
||||
We use this pattern all the time in order to thward extension attacks,
|
||||
add a helper to make it shorter.
|
||||
|
||||
(cherry picked from commit a16c65f3c4c93e24eda9cf7f14d5da4062c6ca10)
|
||||
|
||||
Related: RHEL-16952
|
||||
---
|
||||
src/boot/bootctl.c | 6 ++----
|
||||
src/fundamental/sha256.h | 5 +++++
|
||||
src/random-seed/random-seed.c | 12 ++++--------
|
||||
3 files changed, 11 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
|
||||
index fe8d7e83a1..3e9a89a759 100644
|
||||
--- a/src/boot/bootctl.c
|
||||
+++ b/src/boot/bootctl.c
|
||||
@@ -2010,8 +2010,7 @@ static int install_random_seed(const char *esp) {
|
||||
return log_error_errno(r, "Failed to acquire random seed: %m");
|
||||
|
||||
sha256_init_ctx(&hash_state);
|
||||
- sha256_process_bytes(&(const size_t) { sizeof(buffer) }, sizeof(size_t), &hash_state);
|
||||
- sha256_process_bytes(buffer, sizeof(buffer), &hash_state);
|
||||
+ sha256_process_bytes_and_size(buffer, sizeof(buffer), &hash_state);
|
||||
|
||||
fd = openat(loader_dir_fd, "random-seed", O_NOFOLLOW|O_CLOEXEC|O_RDONLY|O_NOCTTY);
|
||||
if (fd < 0) {
|
||||
@@ -2029,8 +2028,7 @@ static int install_random_seed(const char *esp) {
|
||||
if (n < 0)
|
||||
return log_error_errno(errno, "Failed to read old random seed file: %m");
|
||||
|
||||
- sha256_process_bytes(&n, sizeof(n), &hash_state);
|
||||
- sha256_process_bytes(buffer, n, &hash_state);
|
||||
+ sha256_process_bytes_and_size(buffer, n, &hash_state);
|
||||
|
||||
fd = safe_close(fd);
|
||||
refreshed = n > 0;
|
||||
diff --git a/src/fundamental/sha256.h b/src/fundamental/sha256.h
|
||||
index 31790c2ebd..2857900c80 100644
|
||||
--- a/src/fundamental/sha256.h
|
||||
+++ b/src/fundamental/sha256.h
|
||||
@@ -28,6 +28,11 @@ void sha256_init_ctx(struct sha256_ctx *ctx);
|
||||
uint8_t *sha256_finish_ctx(struct sha256_ctx *ctx, uint8_t resbuf[static SHA256_DIGEST_SIZE]);
|
||||
void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx);
|
||||
|
||||
+static inline void sha256_process_bytes_and_size(const void *buffer, size_t len, struct sha256_ctx *ctx) {
|
||||
+ sha256_process_bytes(&len, sizeof(len), ctx);
|
||||
+ sha256_process_bytes(buffer, len, ctx);
|
||||
+}
|
||||
+
|
||||
uint8_t* sha256_direct(const void *buffer, size_t sz, uint8_t result[static SHA256_DIGEST_SIZE]);
|
||||
|
||||
#define SHA256_DIRECT(buffer, sz) sha256_direct(buffer, sz, (uint8_t[SHA256_DIGEST_SIZE]) {})
|
||||
diff --git a/src/random-seed/random-seed.c b/src/random-seed/random-seed.c
|
||||
index ab1f942289..3bb78200c9 100644
|
||||
--- a/src/random-seed/random-seed.c
|
||||
+++ b/src/random-seed/random-seed.c
|
||||
@@ -195,8 +195,7 @@ static int load_seed_file(
|
||||
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);
|
||||
+ sha256_process_bytes_and_size(buf, k, hash_state); /* Hash with length to distinguish from new seed. */
|
||||
|
||||
*ret_hash_state = hash_state;
|
||||
}
|
||||
@@ -289,8 +288,7 @@ static int save_seed_file(
|
||||
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_process_bytes_and_size(buf, k, hash_state); /* Hash with length to distinguish from old seed. */
|
||||
sha256_finish_ctx(hash_state, hash);
|
||||
l = MIN((size_t)k, sizeof(hash));
|
||||
memcpy((uint8_t *)buf + k - l, hash, l);
|
||||
@@ -371,8 +369,7 @@ static int refresh_boot_seed(void) {
|
||||
|
||||
/* Hash the old seed in so that we never regress in entropy. */
|
||||
sha256_init_ctx(&hash_state);
|
||||
- sha256_process_bytes(&n, sizeof(n), &hash_state);
|
||||
- sha256_process_bytes(seed_file_bytes, n, &hash_state);
|
||||
+ sha256_process_bytes_and_size(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
|
||||
@@ -393,8 +390,7 @@ static int refresh_boot_seed(void) {
|
||||
assert(n == sizeof(buffer));
|
||||
|
||||
/* Hash the new seed into the state containing the old one to generate our final seed. */
|
||||
- sha256_process_bytes(&n, sizeof(n), &hash_state);
|
||||
- sha256_process_bytes(buffer, n, &hash_state);
|
||||
+ sha256_process_bytes_and_size(buffer, n, &hash_state);
|
||||
sha256_finish_ctx(&hash_state, buffer);
|
||||
|
||||
if (lseek(seed_fd, 0, SEEK_SET) < 0)
|
@ -0,0 +1,191 @@
|
||||
From 5c3c932aeef27dcc0b4cb91aeb7e52974add6998 Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Tue, 20 Dec 2022 16:18:11 +0100
|
||||
Subject: [PATCH] random-seed: don't refresh EFI random seed from random-seed.c
|
||||
anymore
|
||||
|
||||
The ESP is simply not mounted early enough for this. We want that the
|
||||
regular random seed handling runs as early as we possibly could, but we
|
||||
don't want to delay this until the ESP is actually mounted.
|
||||
|
||||
Hence, let's remove this from random-seed.c here. A follow-up commit
|
||||
will then add this back in, in a separate service which just calls
|
||||
"bootctl random-seed".
|
||||
|
||||
Effectively reverts: f913c784ad4c93894fd6cb2590738113dff5a694
|
||||
|
||||
Fixes: #25769
|
||||
(cherry picked from commit 29d487adb4ce70cc87a09ce2003d29789b2b4c3f)
|
||||
|
||||
Related: RHEL-16952
|
||||
---
|
||||
src/random-seed/random-seed.c | 111 +---------------------------------
|
||||
1 file changed, 2 insertions(+), 109 deletions(-)
|
||||
|
||||
diff --git a/src/random-seed/random-seed.c b/src/random-seed/random-seed.c
|
||||
index 3bb78200c9..79544c1027 100644
|
||||
--- a/src/random-seed/random-seed.c
|
||||
+++ b/src/random-seed/random-seed.c
|
||||
@@ -16,10 +16,7 @@
|
||||
|
||||
#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"
|
||||
@@ -27,17 +24,13 @@
|
||||
#include "missing_random.h"
|
||||
#include "missing_syscall.h"
|
||||
#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"
|
||||
#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"
|
||||
|
||||
@@ -314,100 +307,6 @@ 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, dir_fd = -1;
|
||||
- size_t len;
|
||||
- ssize_t n;
|
||||
- int 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 */
|
||||
- }
|
||||
-
|
||||
- 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))
|
||||
- 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)
|
||||
- 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();
|
||||
- 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_and_size(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. */
|
||||
- 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;
|
||||
- }
|
||||
- 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(n == sizeof(buffer));
|
||||
-
|
||||
- /* Hash the new seed into the state containing the old one to generate our final seed. */
|
||||
- sha256_process_bytes_and_size(buffer, n, &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(r, "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;
|
||||
@@ -525,10 +424,7 @@ 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;
|
||||
-
|
||||
- (void) refresh_boot_seed();
|
||||
- return missing ? 0 : r;
|
||||
+ return missing ? 0 : -errno;
|
||||
}
|
||||
} else
|
||||
write_seed_file = true;
|
||||
@@ -538,7 +434,6 @@ static int run(int argc, char *argv[]) {
|
||||
break;
|
||||
|
||||
case ACTION_SAVE:
|
||||
- (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");
|
||||
@@ -556,11 +451,9 @@ 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);
|
@ -0,0 +1,34 @@
|
||||
From 825d1d4535a7aafd7549bc7a5de7d72b5ec2cdbd Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Tue, 20 Dec 2022 16:34:36 +0100
|
||||
Subject: [PATCH] bootctl: downgrade graceful messages to LOG_NOTICE
|
||||
|
||||
(cherry picked from commit 5019b0cb15d788e5e1f3c15eb7cdca6ee18a847c)
|
||||
|
||||
Related: RHEL-16952
|
||||
---
|
||||
src/boot/bootctl.c | 4 ++--
|
||||
...-system-token.service => systemd-boot-random-seed.service} | 0
|
||||
2 files changed, 2 insertions(+), 2 deletions(-)
|
||||
rename units/{systemd-boot-system-token.service => systemd-boot-random-seed.service} (100%)
|
||||
|
||||
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
|
||||
index 3e9a89a759..3833e755b1 100644
|
||||
--- a/src/boot/bootctl.c
|
||||
+++ b/src/boot/bootctl.c
|
||||
@@ -2119,9 +2119,9 @@ static int install_random_seed(const char *esp) {
|
||||
return log_error_errno(r, "Failed to write 'LoaderSystemToken' EFI variable: %m");
|
||||
|
||||
if (r == -EINVAL)
|
||||
- log_warning_errno(r, "Unable to write 'LoaderSystemToken' EFI variable (firmware problem?), ignoring: %m");
|
||||
+ log_notice_errno(r, "Unable to write 'LoaderSystemToken' EFI variable (firmware problem?), ignoring: %m");
|
||||
else
|
||||
- log_warning_errno(r, "Unable to write 'LoaderSystemToken' EFI variable, ignoring: %m");
|
||||
+ log_notice_errno(r, "Unable to write 'LoaderSystemToken' EFI variable, ignoring: %m");
|
||||
} else
|
||||
log_info("Successfully initialized system token in EFI variable with %zu bytes.", sizeof(buffer));
|
||||
}
|
||||
diff --git a/units/systemd-boot-system-token.service b/units/systemd-boot-random-seed.service
|
||||
similarity index 100%
|
||||
rename from units/systemd-boot-system-token.service
|
||||
rename to units/systemd-boot-random-seed.service
|
@ -0,0 +1,392 @@
|
||||
From b7f74506b4a479edf2d7c5b9c08fb105e3fd7b29 Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Tue, 20 Dec 2022 17:16:47 +0100
|
||||
Subject: [PATCH] =?UTF-8?q?units:=20rename/rework=20systemd-boot-system-to?=
|
||||
=?UTF-8?q?ken.service=20=E2=86=92=20systemd-boot-random-seed.service?=
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This renames systemd-boot-system-token.service to
|
||||
systemd-boot-random-seed.service and conditions it less strictly.
|
||||
|
||||
Previously, the job of the service was to write a "system token" EFI
|
||||
variable if it was missing. It called "bootctl --graceful random-seed"
|
||||
for that. With this change we condition it more liberally: instead of
|
||||
calling it only when the "system token" EFI variable isn't set, we call
|
||||
it whenever a boot loader interface compatible boot loader is used. This
|
||||
means, previously it was invoked on the first boot only: now it is
|
||||
invoked at every boot.
|
||||
|
||||
This doesn#t change the command that is invoked. That's because
|
||||
previously already the "bootctl --graceful random-seed" did two things:
|
||||
set the system token if not set yet *and* refresh the random seed in the
|
||||
ESP. Previousy we put the focus on the former, now we shift the focus to
|
||||
the latter.
|
||||
|
||||
With this simple change we can replace the logic
|
||||
f913c784ad4c93894fd6cb2590738113dff5a694 added, but from a service that
|
||||
can run much later and doesn't keep the ESP pinned.
|
||||
|
||||
(cherry picked from commit 921fc451cb7ce29467c5d87346db2b8bb72fdf18)
|
||||
|
||||
Related: RHEL-16952
|
||||
---
|
||||
man/bootctl.xml | 4 +-
|
||||
man/rules/meson.build | 2 +-
|
||||
man/systemd-boot-random-seed.service.xml | 99 +++++++++++++++++++++++
|
||||
man/systemd-boot-system-token.service.xml | 76 -----------------
|
||||
man/systemd-boot.xml | 2 +-
|
||||
man/systemd-random-seed.service.xml | 6 +-
|
||||
units/meson.build | 2 +-
|
||||
units/systemd-boot-random-seed.service | 15 ++--
|
||||
units/systemd-boot-update.service | 3 +-
|
||||
units/systemd-random-seed.service.in | 4 +-
|
||||
10 files changed, 120 insertions(+), 93 deletions(-)
|
||||
create mode 100644 man/systemd-boot-random-seed.service.xml
|
||||
delete mode 100644 man/systemd-boot-system-token.service.xml
|
||||
|
||||
diff --git a/man/bootctl.xml b/man/bootctl.xml
|
||||
index d82f12d5bb..27b45c06d3 100644
|
||||
--- a/man/bootctl.xml
|
||||
+++ b/man/bootctl.xml
|
||||
@@ -208,7 +208,7 @@
|
||||
OS and a new seed to store in the ESP from the combination of both. The random seed passed to the OS
|
||||
is credited to the kernel's entropy pool by the system manager during early boot, and permits
|
||||
userspace to boot up with an entropy pool fully initialized very early on. Also see
|
||||
- <citerefentry><refentrytitle>systemd-boot-system-token.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
|
||||
+ <citerefentry><refentrytitle>systemd-boot-random-seed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
|
||||
|
||||
<para>See <ulink url="https://systemd.io/RANDOM_SEEDS">Random Seeds</ulink> for further
|
||||
information.</para></listitem>
|
||||
@@ -550,7 +550,7 @@ Boot Loader Entries:
|
||||
<citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
|
||||
<ulink url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink>,
|
||||
<ulink url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader Interface</ulink>,
|
||||
- <citerefentry><refentrytitle>systemd-boot-system-token.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
+ <citerefentry><refentrytitle>systemd-boot-random-seed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
diff --git a/man/rules/meson.build b/man/rules/meson.build
|
||||
index 9c0d773e51..beecc893fd 100644
|
||||
--- a/man/rules/meson.build
|
||||
+++ b/man/rules/meson.build
|
||||
@@ -863,7 +863,7 @@ manpages = [
|
||||
'8',
|
||||
['systemd-boot-check-no-failures'],
|
||||
''],
|
||||
- ['systemd-boot-system-token.service', '8', [], 'HAVE_GNU_EFI'],
|
||||
+ ['systemd-boot-random-seed.service', '8', [], 'HAVE_GNU_EFI'],
|
||||
['systemd-boot', '7', ['sd-boot'], 'HAVE_GNU_EFI'],
|
||||
['systemd-cat', '1', [], ''],
|
||||
['systemd-cgls', '1', [], ''],
|
||||
diff --git a/man/systemd-boot-random-seed.service.xml b/man/systemd-boot-random-seed.service.xml
|
||||
new file mode 100644
|
||||
index 0000000000..86ce639828
|
||||
--- /dev/null
|
||||
+++ b/man/systemd-boot-random-seed.service.xml
|
||||
@@ -0,0 +1,99 @@
|
||||
+<?xml version='1.0'?> <!--*-nxml-*-->
|
||||
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
+<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
|
||||
+
|
||||
+<refentry id="systemd-boot-random-seed.service" conditional='HAVE_GNU_EFI'
|
||||
+ xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
+
|
||||
+ <refentryinfo>
|
||||
+ <title>systemd-boot-random-seed.service</title>
|
||||
+ <productname>systemd</productname>
|
||||
+ </refentryinfo>
|
||||
+
|
||||
+ <refmeta>
|
||||
+ <refentrytitle>systemd-boot-random-seed.service</refentrytitle>
|
||||
+ <manvolnum>8</manvolnum>
|
||||
+ </refmeta>
|
||||
+
|
||||
+ <refnamediv>
|
||||
+ <refname>systemd-boot-random-seed.service</refname>
|
||||
+ <refpurpose>Refresh boot loader random seed at boot</refpurpose>
|
||||
+ </refnamediv>
|
||||
+
|
||||
+ <refsynopsisdiv>
|
||||
+ <para><filename>systemd-boot-random-seed.service</filename></para>
|
||||
+ </refsynopsisdiv>
|
||||
+
|
||||
+ <refsect1>
|
||||
+ <title>Description</title>
|
||||
+
|
||||
+ <para><filename>systemd-boot-random-seed.service</filename> is a system service that automatically
|
||||
+ refreshes the boot loader random seed stored in the EFI System Partition (ESP), from the Linux kernel
|
||||
+ entropy pool. The boot loader random seed is primarily consumed and updated by
|
||||
+ <citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry> from the
|
||||
+ UEFI environemnt (or
|
||||
+ <citerefentry><refentrytitle>systemd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry> if the
|
||||
+ former is not used, but the latter is), and passed as initial RNG seed to the OS. It is an effective way
|
||||
+ to ensure the OS comes up with a random pool that is fully initialized.</para>
|
||||
+
|
||||
+ <para>The service also automatically generates a 'system token' to store in an EFI variable in the
|
||||
+ system's NVRAM. The boot loader may then combine the on-disk random seed and the system token by
|
||||
+ cryptographic hashing, and pass it to the OS it boots as initialization seed for its entropy pool. Note:
|
||||
+ the random seed stored in the ESP is refreshed on <emphasis>every</emphasis> reboot ensuring that
|
||||
+ multiple subsequent boots will boot with different seeds. On the other hand, the system token is
|
||||
+ generated randomly <emphasis>once</emphasis>, and then persistently stored in the system's EFI variable
|
||||
+ storage, ensuring the same disk image won't result in the same series of boot loader seed values if used
|
||||
+ on multiple systems in parallel.</para>
|
||||
+
|
||||
+ <para>The <filename>systemd-boot-random-seed.service</filename> unit invokes the <command>bootctl
|
||||
+ random-seed</command> command, which updates the random seed in the ESP, and initializes the system
|
||||
+ token if it's not initialized yet. The service is conditionalized so that it is run only when a boot
|
||||
+ loader is used that implements the <ulink url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader
|
||||
+ Interface</ulink>.</para> <para>For further details see
|
||||
+ <citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>, regarding
|
||||
+ the command this service invokes.</para>
|
||||
+
|
||||
+ <para>Note the relationship between <filename>systemd-boot-random-seed.service</filename> and
|
||||
+ <citerefentry><refentrytitle>systemd-random-seed</refentrytitle><manvolnum>8</manvolnum></citerefentry>. The
|
||||
+ former maintains the random seed consumed and updated by the boot environment (i.e. by
|
||||
+ <citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry> or
|
||||
+ <citerefentry><refentrytitle>systemd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry>), the
|
||||
+ latter maintains a random seed consumed and updated by the OS itself. The former ensures that the OS has
|
||||
+ a filled entropy pool already during earliest boot when regular disk access is not available yet
|
||||
+ (i.e. when the OS random seed cannot be loaded yet). The latter is processed much later, once writable
|
||||
+ disk access is available. Thus it cannot be used to seed the initial boot phase, but typically has much
|
||||
+ higher quality of entropy. Both files are consumed and updated at boot, but at different
|
||||
+ times. Specifically:</para>
|
||||
+
|
||||
+ <orderedlist>
|
||||
+ <listitem><para>In UEFI mode, the <filename>systemd-boot</filename> or
|
||||
+ <filename>systemd-stub</filename> components load the boot loader random seed off the ESP, hash it with
|
||||
+ available entropy and the system token, and then update it on disk. A derived seed is passed to the
|
||||
+ kernel which writes it to its entropy pool.</para></listitem>
|
||||
+
|
||||
+ <listitem><para>In userspace the <filename>systemd-random-seed.service</filename> service loads the OS
|
||||
+ random seed, writes it to the kernel entropy pool, and then updates it on disk with a new value derived
|
||||
+ from the kernel entropy pool.</para></listitem>
|
||||
+
|
||||
+ <listitem><para>In userspace the <filename>systemd-boot-random-seed.service</filename> service updates
|
||||
+ the boot loader random seed with a new value derived from the kernel kernel entropy pool.</para></listitem>
|
||||
+ </orderedlist>
|
||||
+
|
||||
+ <para>This logic should ensure that the kernel's entropy pool is seeded during earliest bool already, if
|
||||
+ possible, but the highest quality entropy is propagated back to both on-disk seeds.</para>
|
||||
+ </refsect1>
|
||||
+
|
||||
+ <refsect1>
|
||||
+ <title>See Also</title>
|
||||
+ <para>
|
||||
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
+ <citerefentry><refentrytitle>random</refentrytitle><manvolnum>4</manvolnum></citerefentry>,
|
||||
+ <citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
+ <citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
|
||||
+ <citerefentry><refentrytitle>systemd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
|
||||
+ <citerefentry><refentrytitle>systemd-random-seed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
+ </para>
|
||||
+ </refsect1>
|
||||
+
|
||||
+</refentry>
|
||||
diff --git a/man/systemd-boot-system-token.service.xml b/man/systemd-boot-system-token.service.xml
|
||||
deleted file mode 100644
|
||||
index f2e30a9b13..0000000000
|
||||
--- a/man/systemd-boot-system-token.service.xml
|
||||
+++ /dev/null
|
||||
@@ -1,76 +0,0 @@
|
||||
-<?xml version='1.0'?> <!--*-nxml-*-->
|
||||
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
-<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
|
||||
-
|
||||
-<refentry id="systemd-boot-system-token.service" conditional='HAVE_GNU_EFI'
|
||||
- xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
-
|
||||
- <refentryinfo>
|
||||
- <title>systemd-boot-system-token.service</title>
|
||||
- <productname>systemd</productname>
|
||||
- </refentryinfo>
|
||||
-
|
||||
- <refmeta>
|
||||
- <refentrytitle>systemd-boot-system-token.service</refentrytitle>
|
||||
- <manvolnum>8</manvolnum>
|
||||
- </refmeta>
|
||||
-
|
||||
- <refnamediv>
|
||||
- <refname>systemd-boot-system-token.service</refname>
|
||||
- <refpurpose>Generate an initial boot loader system token and random seed</refpurpose>
|
||||
- </refnamediv>
|
||||
-
|
||||
- <refsynopsisdiv>
|
||||
- <para><filename>systemd-boot-system-token.service</filename></para>
|
||||
- </refsynopsisdiv>
|
||||
-
|
||||
- <refsect1>
|
||||
- <title>Description</title>
|
||||
-
|
||||
- <para><filename>systemd-boot-system-token.service</filename> is a system service that automatically
|
||||
- generates a 'system token' to store in an EFI variable in the system's NVRAM and a random seed to store
|
||||
- on the EFI System Partition ESP on disk. The boot loader may then combine these two randomized data
|
||||
- fields by cryptographic hashing, and pass it to the OS it boots as initialization seed for its entropy
|
||||
- pool. The random seed stored in the ESP is refreshed on each reboot ensuring that multiple subsequent
|
||||
- boots will boot with different seeds. The 'system token' is generated randomly once, and then
|
||||
- persistently stored in the system's EFI variable storage.</para>
|
||||
-
|
||||
- <para>The <filename>systemd-boot-system-token.service</filename> unit invokes the <command>bootctl
|
||||
- random-seed</command> command, which updates the random seed in the ESP, and initializes the 'system
|
||||
- token' if it's not initialized yet. The service is conditionalized so that it is run only when all of the
|
||||
- below apply:</para>
|
||||
-
|
||||
- <itemizedlist>
|
||||
- <listitem><para>A boot loader is used that implements the <ulink
|
||||
- url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader Interface</ulink> (which defines the 'system
|
||||
- token' concept).</para></listitem>
|
||||
-
|
||||
- <listitem><para>Either a 'system token' was not set yet, or the boot loader has not passed the OS a
|
||||
- random seed yet (and thus most likely has been missing the random seed file in the
|
||||
- ESP).</para></listitem>
|
||||
-
|
||||
- <listitem><para>The system is not running in a VM environment. This case is explicitly excluded since
|
||||
- on VM environments the ESP backing storage and EFI variable storage is typically not physically
|
||||
- separated and hence booting the same OS image in multiple instances would replicate both, thus reusing
|
||||
- the same random seed and 'system token' among all instances, which defeats its purpose. Note that it's
|
||||
- still possible to use boot loader random seed provisioning in this mode, but the automatic logic
|
||||
- implemented by this service has no effect then, and the user instead has to manually invoke the
|
||||
- <command>bootctl random-seed</command> acknowledging these restrictions.</para></listitem>
|
||||
- </itemizedlist>
|
||||
-
|
||||
- <para>For further details see
|
||||
- <citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>, regarding
|
||||
- the command this service invokes.</para>
|
||||
- </refsect1>
|
||||
-
|
||||
- <refsect1>
|
||||
- <title>See Also</title>
|
||||
- <para>
|
||||
- <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
- <citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
- <citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||
- </para>
|
||||
- </refsect1>
|
||||
-
|
||||
-</refentry>
|
||||
diff --git a/man/systemd-boot.xml b/man/systemd-boot.xml
|
||||
index f96c4c6512..773d6988e3 100644
|
||||
--- a/man/systemd-boot.xml
|
||||
+++ b/man/systemd-boot.xml
|
||||
@@ -526,7 +526,7 @@
|
||||
<citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>loader.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-bless-boot.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
- <citerefentry><refentrytitle>systemd-boot-system-token.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
+ <citerefentry><refentrytitle>systemd-boot-random-seed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>kernel-install</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
|
||||
<ulink url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink>,
|
||||
diff --git a/man/systemd-random-seed.service.xml b/man/systemd-random-seed.service.xml
|
||||
index a1e31cd460..bc8cf50a39 100644
|
||||
--- a/man/systemd-random-seed.service.xml
|
||||
+++ b/man/systemd-random-seed.service.xml
|
||||
@@ -18,7 +18,7 @@
|
||||
<refnamediv>
|
||||
<refname>systemd-random-seed.service</refname>
|
||||
<refname>systemd-random-seed</refname>
|
||||
- <refpurpose>Load and save the system random seed at boot and shutdown</refpurpose>
|
||||
+ <refpurpose>Load and save the OS system random seed at boot and shutdown</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
@@ -86,7 +86,9 @@
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>random</refentrytitle><manvolnum>4</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
|
||||
- <citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>4</manvolnum></citerefentry>
|
||||
+ <citerefentry><refentrytitle>systemd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
|
||||
+ <citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>4</manvolnum></citerefentry>,
|
||||
+ <citerefentry><refentrytitle>systemd-boot-random-seed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
diff --git a/units/meson.build b/units/meson.build
|
||||
index 3a1f5229a0..cfc96a9111 100644
|
||||
--- a/units/meson.build
|
||||
+++ b/units/meson.build
|
||||
@@ -105,7 +105,7 @@ units = [
|
||||
['systemd-ask-password-wall.path', '',
|
||||
'multi-user.target.wants/'],
|
||||
['systemd-ask-password-wall.service', ''],
|
||||
- ['systemd-boot-system-token.service', 'HAVE_GNU_EFI',
|
||||
+ ['systemd-boot-random-seed.service', 'HAVE_GNU_EFI',
|
||||
'sysinit.target.wants/'],
|
||||
['systemd-boot-update.service', 'HAVE_GNU_EFI'],
|
||||
['systemd-coredump.socket', 'ENABLE_COREDUMP',
|
||||
diff --git a/units/systemd-boot-random-seed.service b/units/systemd-boot-random-seed.service
|
||||
index ef5577549e..4fa286071d 100644
|
||||
--- a/units/systemd-boot-random-seed.service
|
||||
+++ b/units/systemd-boot-random-seed.service
|
||||
@@ -8,22 +8,21 @@
|
||||
# (at your option) any later version.
|
||||
|
||||
[Unit]
|
||||
-Description=Store a System Token in an EFI Variable
|
||||
-Documentation=man:systemd-boot-system-token.service(8)
|
||||
+Description=Update Boot Loader Random Seed
|
||||
+Documentation=man:systemd-boot-random-seed.service(8) man:random(4)
|
||||
|
||||
DefaultDependencies=no
|
||||
After=local-fs.target systemd-random-seed.service
|
||||
-Conflicts=shutdown.target initrd-switch-root.target
|
||||
-Before=shutdown.target initrd-switch-root.target
|
||||
+Conflicts=shutdown.target
|
||||
+Before=sysinit.target shutdown.target
|
||||
|
||||
+ConditionVirtualization=!container
|
||||
+ConditionPathExists=!/etc/initrd-release
|
||||
# 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/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
|
||||
-
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
-ExecStart=bootctl random-seed --graceful
|
||||
+ExecStart=bootctl --graceful random-seed
|
||||
diff --git a/units/systemd-boot-update.service b/units/systemd-boot-update.service
|
||||
index 61ff12762a..fe63fde35a 100644
|
||||
--- a/units/systemd-boot-update.service
|
||||
+++ b/units/systemd-boot-update.service
|
||||
@@ -10,9 +10,10 @@
|
||||
[Unit]
|
||||
Description=Automatic Boot Loader Update
|
||||
Documentation=man:bootctl(1)
|
||||
+
|
||||
DefaultDependencies=no
|
||||
-Conflicts=shutdown.target
|
||||
After=local-fs.target
|
||||
+Conflicts=shutdown.target
|
||||
Before=sysinit.target shutdown.target systemd-update-done.service
|
||||
|
||||
[Service]
|
||||
diff --git a/units/systemd-random-seed.service.in b/units/systemd-random-seed.service.in
|
||||
index 1aa9af9710..d57b2d1269 100644
|
||||
--- a/units/systemd-random-seed.service.in
|
||||
+++ b/units/systemd-random-seed.service.in
|
||||
@@ -8,14 +8,16 @@
|
||||
# (at your option) any later version.
|
||||
|
||||
[Unit]
|
||||
-Description=Load/Save Random Seed
|
||||
+Description=Load/Save OS Random Seed
|
||||
Documentation=man:systemd-random-seed.service(8) man:random(4)
|
||||
+
|
||||
DefaultDependencies=no
|
||||
RequiresMountsFor={{RANDOM_SEED}}
|
||||
Conflicts=shutdown.target
|
||||
After=systemd-remount-fs.service
|
||||
Before=first-boot-complete.target shutdown.target
|
||||
Wants=first-boot-complete.target
|
||||
+
|
||||
ConditionVirtualization=!container
|
||||
ConditionPathExists=!/etc/initrd-release
|
||||
|
@ -0,0 +1,171 @@
|
||||
From 6fb21c25c859d950c1d9ab3b954573e87e87e64a Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Tue, 20 Dec 2022 18:03:06 +0100
|
||||
Subject: [PATCH] bootctl: split out setting of system token into function of
|
||||
its own
|
||||
|
||||
Let's break a huge function in two. No code change, just some
|
||||
refactoring.
|
||||
|
||||
(cherry picked from commit 54978e3f3b5394d26f53f4753bb1c9e3e5811408)
|
||||
|
||||
Related: RHEL-16952
|
||||
---
|
||||
src/boot/bootctl.c | 132 +++++++++++++++++++++++----------------------
|
||||
1 file changed, 69 insertions(+), 63 deletions(-)
|
||||
|
||||
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
|
||||
index 3833e755b1..00e8eda992 100644
|
||||
--- a/src/boot/bootctl.c
|
||||
+++ b/src/boot/bootctl.c
|
||||
@@ -1984,12 +1984,79 @@ static int verb_list(int argc, char *argv[], void *userdata) {
|
||||
return show_boot_entries(&config, arg_json_format_flags);
|
||||
}
|
||||
|
||||
+static int set_system_token(void) {
|
||||
+ uint8_t buffer[RANDOM_EFI_SEED_SIZE];
|
||||
+ size_t token_size;
|
||||
+ int r;
|
||||
+
|
||||
+ if (!arg_touch_variables)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (arg_root) {
|
||||
+ log_warning("Acting on %s, skipping EFI variable setup.",
|
||||
+ arg_image ? "image" : "root directory");
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ if (!is_efi_boot()) {
|
||||
+ log_notice("Not booted with EFI, skipping EFI variable setup.");
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ r = getenv_bool("SYSTEMD_WRITE_SYSTEM_TOKEN");
|
||||
+ if (r < 0) {
|
||||
+ if (r != -ENXIO)
|
||||
+ log_warning_errno(r, "Failed to parse $SYSTEMD_WRITE_SYSTEM_TOKEN, ignoring.");
|
||||
+ } else if (r == 0) {
|
||||
+ log_notice("Not writing system token, because $SYSTEMD_WRITE_SYSTEM_TOKEN is set to false.");
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ r = efi_get_variable(EFI_LOADER_VARIABLE(LoaderSystemToken), NULL, NULL, &token_size);
|
||||
+ if (r == -ENODATA)
|
||||
+ log_debug_errno(r, "LoaderSystemToken EFI variable is invalid (too short?), replacing.");
|
||||
+ else if (r < 0) {
|
||||
+ if (r != -ENOENT)
|
||||
+ return log_error_errno(r, "Failed to test system token validity: %m");
|
||||
+ } else {
|
||||
+ 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, sizeof(buffer));
|
||||
+ }
|
||||
+
|
||||
+ r = crypto_random_bytes(buffer, sizeof(buffer));
|
||||
+ if (r < 0)
|
||||
+ return log_error_errno(r, "Failed to acquire random seed: %m");
|
||||
+
|
||||
+ /* Let's write this variable with an umask in effect, so that unprivileged users can't see the token
|
||||
+ * 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, sizeof(buffer));
|
||||
+ if (r < 0) {
|
||||
+ if (!arg_graceful)
|
||||
+ return log_error_errno(r, "Failed to write 'LoaderSystemToken' EFI variable: %m");
|
||||
+
|
||||
+ if (r == -EINVAL)
|
||||
+ log_notice_errno(r, "Unable to write 'LoaderSystemToken' EFI variable (firmware problem?), ignoring: %m");
|
||||
+ else
|
||||
+ log_notice_errno(r, "Unable to write 'LoaderSystemToken' EFI variable, ignoring: %m");
|
||||
+ } else
|
||||
+ log_info("Successfully initialized system token in EFI variable with %zu bytes.", sizeof(buffer));
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int install_random_seed(const char *esp) {
|
||||
_cleanup_close_ int esp_fd = -EBADF, loader_dir_fd = -EBADF, fd = -EBADF;
|
||||
_cleanup_free_ char *tmp = NULL;
|
||||
uint8_t buffer[RANDOM_EFI_SEED_SIZE];
|
||||
struct sha256_ctx hash_state;
|
||||
- size_t token_size;
|
||||
bool refreshed;
|
||||
int r;
|
||||
|
||||
@@ -2066,68 +2133,7 @@ static int install_random_seed(const char *esp) {
|
||||
|
||||
log_info("Random seed file %s/loader/random-seed successfully %s (%zu bytes).", esp, refreshed ? "refreshed" : "written", sizeof(buffer));
|
||||
|
||||
- if (!arg_touch_variables)
|
||||
- return 0;
|
||||
-
|
||||
- if (!is_efi_boot()) {
|
||||
- log_notice("Not booted with EFI, skipping EFI variable setup.");
|
||||
- return 0;
|
||||
- }
|
||||
-
|
||||
- if (arg_root) {
|
||||
- log_warning("Acting on %s, skipping EFI variable setup.",
|
||||
- arg_image ? "image" : "root directory");
|
||||
- return 0;
|
||||
- }
|
||||
-
|
||||
- r = getenv_bool("SYSTEMD_WRITE_SYSTEM_TOKEN");
|
||||
- if (r < 0) {
|
||||
- if (r != -ENXIO)
|
||||
- log_warning_errno(r, "Failed to parse $SYSTEMD_WRITE_SYSTEM_TOKEN, ignoring.");
|
||||
- } else if (r == 0) {
|
||||
- log_notice("Not writing system token, because $SYSTEMD_WRITE_SYSTEM_TOKEN is set to false.");
|
||||
- return 0;
|
||||
- }
|
||||
-
|
||||
- r = efi_get_variable(EFI_LOADER_VARIABLE(LoaderSystemToken), NULL, NULL, &token_size);
|
||||
- if (r == -ENODATA)
|
||||
- log_debug_errno(r, "LoaderSystemToken EFI variable is invalid (too short?), replacing.");
|
||||
- else if (r < 0) {
|
||||
- if (r != -ENOENT)
|
||||
- return log_error_errno(r, "Failed to test system token validity: %m");
|
||||
- } else {
|
||||
- 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, sizeof(buffer));
|
||||
- }
|
||||
-
|
||||
- r = crypto_random_bytes(buffer, sizeof(buffer));
|
||||
- if (r < 0)
|
||||
- return log_error_errno(r, "Failed to acquire random seed: %m");
|
||||
-
|
||||
- /* Let's write this variable with an umask in effect, so that unprivileged users can't see the token
|
||||
- * 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, sizeof(buffer));
|
||||
- if (r < 0) {
|
||||
- if (!arg_graceful)
|
||||
- return log_error_errno(r, "Failed to write 'LoaderSystemToken' EFI variable: %m");
|
||||
-
|
||||
- if (r == -EINVAL)
|
||||
- log_notice_errno(r, "Unable to write 'LoaderSystemToken' EFI variable (firmware problem?), ignoring: %m");
|
||||
- else
|
||||
- log_notice_errno(r, "Unable to write 'LoaderSystemToken' EFI variable, ignoring: %m");
|
||||
- } else
|
||||
- log_info("Successfully initialized system token in EFI variable with %zu bytes.", sizeof(buffer));
|
||||
- }
|
||||
-
|
||||
- return 0;
|
||||
-
|
||||
+ return set_system_token();
|
||||
fail:
|
||||
if (tmp)
|
||||
(void) unlinkat(loader_dir_fd, tmp, 0);
|
36
SOURCES/0717-execute-Pass-AT_FDCWD-instead-of-1.patch
Normal file
36
SOURCES/0717-execute-Pass-AT_FDCWD-instead-of-1.patch
Normal file
@ -0,0 +1,36 @@
|
||||
From 7d3b9e98e22f92561c98f6bf838cc830324834e3 Mon Sep 17 00:00:00 2001
|
||||
From: Daan De Meyer <daan.j.demeyer@gmail.com>
|
||||
Date: Tue, 13 Dec 2022 10:50:01 +0000
|
||||
Subject: [PATCH] execute: Pass AT_FDCWD instead of -1
|
||||
|
||||
Let's enforce that callers pass AT_FDCWD as read_dfd to load_credential()
|
||||
to avoid an assert() in read_full_file_full() if read_dfd is -1.
|
||||
|
||||
(cherry picked from commit 661e4251a5b157d1aee1df98fbd2f0c95285ebba)
|
||||
|
||||
Resolves: RHEL-31783
|
||||
---
|
||||
src/core/execute.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/core/execute.c b/src/core/execute.c
|
||||
index ea36254241..13222ddea3 100644
|
||||
--- a/src/core/execute.c
|
||||
+++ b/src/core/execute.c
|
||||
@@ -2662,6 +2662,7 @@ static int load_credential(
|
||||
assert(id);
|
||||
assert(path);
|
||||
assert(unit);
|
||||
+ assert(read_dfd >= 0 || read_dfd == AT_FDCWD);
|
||||
assert(write_dfd >= 0);
|
||||
assert(left);
|
||||
|
||||
@@ -2888,7 +2889,7 @@ static int acquire_credentials(
|
||||
lc->path,
|
||||
lc->encrypted,
|
||||
unit,
|
||||
- -1,
|
||||
+ AT_FDCWD,
|
||||
dfd,
|
||||
uid,
|
||||
ownership_ok,
|
@ -0,0 +1,48 @@
|
||||
From 06a6d5c5d5c6f3a9eb7ae55a7635d69158593181 Mon Sep 17 00:00:00 2001
|
||||
From: Jan Macku <jamacku@redhat.com>
|
||||
Date: Thu, 11 Apr 2024 10:01:04 +0200
|
||||
Subject: [PATCH] ci(src-git): update list of supported products
|
||||
|
||||
rhel-only
|
||||
|
||||
Related: RHEL-30372
|
||||
---
|
||||
.github/tracker-validator.yml | 28 ++++++++++++++--------------
|
||||
1 file changed, 14 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/.github/tracker-validator.yml b/.github/tracker-validator.yml
|
||||
index f88cc0a572..31ef28f6ea 100644
|
||||
--- a/.github/tracker-validator.yml
|
||||
+++ b/.github/tracker-validator.yml
|
||||
@@ -12,17 +12,17 @@ products:
|
||||
- rhel-9.2.0.z
|
||||
- rhel-9.3.0
|
||||
- rhel-9.3.0.z
|
||||
- - rhel-9.4.0
|
||||
- - rhel-9.4.0.z
|
||||
- - rhel-9.5.0
|
||||
- - rhel-9.5.0.z
|
||||
- - rhel-9.6.0
|
||||
- - rhel-9.6.0.z
|
||||
- - rhel-9.7.0
|
||||
- - rhel-9.7.0.z
|
||||
- - rhel-9.8.0
|
||||
- - rhel-9.8.0.z
|
||||
- - rhel-9.9.0
|
||||
- - rhel-9.9.0.z
|
||||
- - rhel-9.10.0
|
||||
- - rhel-9.10.0.z
|
||||
+ - rhel-9.4
|
||||
+ - rhel-9.4.z
|
||||
+ - rhel-9.5
|
||||
+ - rhel-9.5.z
|
||||
+ - rhel-9.6
|
||||
+ - rhel-9.6.z
|
||||
+ - rhel-9.7
|
||||
+ - rhel-9.7.z
|
||||
+ - rhel-9.8
|
||||
+ - rhel-9.8.z
|
||||
+ - rhel-9.9
|
||||
+ - rhel-9.9.z
|
||||
+ - rhel-9.10
|
||||
+ - rhel-9.10.z
|
@ -0,0 +1,46 @@
|
||||
From f387005b548bee7695c663167f9bd54e45636f6b Mon Sep 17 00:00:00 2001
|
||||
From: Michal Sekletar <msekleta@redhat.com>
|
||||
Date: Fri, 5 Apr 2024 15:56:58 +0200
|
||||
Subject: [PATCH] coredump: by default process and store core files up to 1GiB
|
||||
|
||||
This is a major departure from our previous policy of soft core file
|
||||
limit set to 0, i.e. core file processing and storage by
|
||||
systemd-coredump was disabled. However, that policy made very difficult
|
||||
for people to debug sporadic crashes with no known reproducer.
|
||||
|
||||
RHEL-only
|
||||
|
||||
Resolves: RHEL-15501
|
||||
---
|
||||
src/core/system.conf.in | 2 +-
|
||||
src/coredump/coredump.conf | 4 ++--
|
||||
2 files changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/src/core/system.conf.in b/src/core/system.conf.in
|
||||
index 624746e512..5d1f6d24f0 100644
|
||||
--- a/src/core/system.conf.in
|
||||
+++ b/src/core/system.conf.in
|
||||
@@ -61,7 +61,7 @@
|
||||
#DefaultLimitFSIZE=
|
||||
#DefaultLimitDATA=
|
||||
#DefaultLimitSTACK=
|
||||
-DefaultLimitCORE=0:infinity
|
||||
+#DefaultLimitCORE=
|
||||
#DefaultLimitRSS=
|
||||
#DefaultLimitNOFILE=1024:{{HIGH_RLIMIT_NOFILE}}
|
||||
#DefaultLimitAS=
|
||||
diff --git a/src/coredump/coredump.conf b/src/coredump/coredump.conf
|
||||
index 1f75d48d33..b934c2afb7 100644
|
||||
--- a/src/coredump/coredump.conf
|
||||
+++ b/src/coredump/coredump.conf
|
||||
@@ -17,8 +17,8 @@
|
||||
[Coredump]
|
||||
#Storage=external
|
||||
#Compress=yes
|
||||
-#ProcessSizeMax=2G
|
||||
-#ExternalSizeMax=2G
|
||||
+ProcessSizeMax=1G
|
||||
+ExternalSizeMax=1G
|
||||
#JournalSizeMax=767M
|
||||
#MaxUse=
|
||||
#KeepFree=
|
35
SOURCES/0720-coredump-keep-core-files-for-two-weeks.patch
Normal file
35
SOURCES/0720-coredump-keep-core-files-for-two-weeks.patch
Normal file
@ -0,0 +1,35 @@
|
||||
From e100e3855305a86367c690689833a460fa166428 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
|
||||
Date: Tue, 5 Dec 2023 15:56:54 +0100
|
||||
Subject: [PATCH] coredump: keep core files for two weeks
|
||||
|
||||
We have two mechanisms that remove old coredumps: systemd-coredump has
|
||||
parameters based on disk use / remaining disk free, and systemd-tmpfiles does
|
||||
cleanup based on time. The first mechanism should prevent us from using too much
|
||||
disk space in case something is crashing continuously or there are very large
|
||||
core files.
|
||||
|
||||
The limit of 3 days makes it likely that the core file will be gone by the time
|
||||
the admin looks at the issue. E.g. if something crashes on Friday, the coredump
|
||||
would likely be gone before people are back on Monday to look at it.
|
||||
|
||||
(cherry picked from commit f8d67130b8b492a1f2eedd07a3189051f98db648)
|
||||
|
||||
Related: RHEL-15501
|
||||
---
|
||||
tmpfiles.d/systemd.conf.in | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tmpfiles.d/systemd.conf.in b/tmpfiles.d/systemd.conf.in
|
||||
index fa838d8d06..958935a04f 100644
|
||||
--- a/tmpfiles.d/systemd.conf.in
|
||||
+++ b/tmpfiles.d/systemd.conf.in
|
||||
@@ -59,7 +59,7 @@ a+ /var/log/journal/%m/system.journal - - - - group:wheel:r--
|
||||
{% endif %}
|
||||
|
||||
d /var/lib/systemd 0755 root root -
|
||||
-d /var/lib/systemd/coredump 0755 root root 3d
|
||||
+d /var/lib/systemd/coredump 0755 root root 2w
|
||||
|
||||
d /var/lib/private 0700 root root -
|
||||
d /var/log/private 0700 root root -
|
@ -0,0 +1,42 @@
|
||||
From af01ea4040e2d6fdd15641793db688d01f2da046 Mon Sep 17 00:00:00 2001
|
||||
From: Frantisek Sumsal <frantisek@sumsal.cz>
|
||||
Date: Sat, 23 Dec 2023 12:20:03 +0100
|
||||
Subject: [PATCH] ukify: make the test happy with the latest OpenSSL
|
||||
|
||||
Which dropped some whitespaces in the output:
|
||||
|
||||
$ openssl version
|
||||
OpenSSL 3.2.0 23 Nov 2023 (Library: OpenSSL 3.2.0 23 Nov 2023)
|
||||
$ openssl x509 -in cert.pem -text -noout | grep Issuer
|
||||
Issuer: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd
|
||||
|
||||
$ openssl version
|
||||
OpenSSL 3.0.9 30 May 2023 (Library: OpenSSL 3.0.9 30 May 2023)
|
||||
$ openssl x509 -in cert.pem -text -noout | grep Issuer
|
||||
Issuer: C = XX, L = Default City, O = Default Company Ltd
|
||||
|
||||
Making test-ukify unhappy:
|
||||
|
||||
> assert 'Issuer: CN = SecureBoot signing key on host' in out
|
||||
E AssertionError: assert 'Issuer: CN = SecureBoot signing key on host' in '<...snip...>Issuer: CN=SecureBoot signing key on host archlinux2\n...'
|
||||
|
||||
(cherry picked from commit 338ed5bea4fcd0b5b1cdcfb96a789edf6251bbdd)
|
||||
|
||||
Related: RHEL-30372
|
||||
---
|
||||
src/ukify/test/test_ukify.py | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/ukify/test/test_ukify.py b/src/ukify/test/test_ukify.py
|
||||
index 5a42a94799..31054eabea 100755
|
||||
--- a/src/ukify/test/test_ukify.py
|
||||
+++ b/src/ukify/test/test_ukify.py
|
||||
@@ -850,7 +850,7 @@ def test_key_cert_generation(tmpdir):
|
||||
'-noout',
|
||||
], text = True)
|
||||
assert 'Certificate' in out
|
||||
- assert 'Issuer: CN = SecureBoot signing key on host' in out
|
||||
+ assert re.search('Issuer: CN\s?=\s?SecureBoot signing key on host', out)
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(pytest.main(sys.argv))
|
32
SOURCES/0722-test_ukify-use-raw-string-for-the-regex.patch
Normal file
32
SOURCES/0722-test_ukify-use-raw-string-for-the-regex.patch
Normal file
@ -0,0 +1,32 @@
|
||||
From 1c4640a859937b84d3f31dd2fa054f7d744d65f4 Mon Sep 17 00:00:00 2001
|
||||
From: Frantisek Sumsal <frantisek@sumsal.cz>
|
||||
Date: Sat, 3 Feb 2024 15:46:26 +0100
|
||||
Subject: [PATCH] test_ukify: use raw string for the regex
|
||||
|
||||
To get rid of the "invalid escape sequence" warning:
|
||||
|
||||
=============================== warnings summary ===============================
|
||||
../src/ukify/test/test_ukify.py:876
|
||||
../src/ukify/test/test_ukify.py:876: SyntaxWarning: invalid escape sequence '\s'
|
||||
assert re.search('Issuer: CN\s?=\s?SecureBoot signing key on host', out)
|
||||
|
||||
(cherry picked from commit a0485e07b38b3b1195a92ba86a173742f2bb867a)
|
||||
|
||||
Related: RHEL-30372
|
||||
---
|
||||
src/ukify/test/test_ukify.py | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/ukify/test/test_ukify.py b/src/ukify/test/test_ukify.py
|
||||
index 31054eabea..f233e25cf7 100755
|
||||
--- a/src/ukify/test/test_ukify.py
|
||||
+++ b/src/ukify/test/test_ukify.py
|
||||
@@ -850,7 +850,7 @@ def test_key_cert_generation(tmpdir):
|
||||
'-noout',
|
||||
], text = True)
|
||||
assert 'Certificate' in out
|
||||
- assert re.search('Issuer: CN\s?=\s?SecureBoot signing key on host', out)
|
||||
+ assert re.search(r'Issuer: CN\s?=\s?SecureBoot signing key on host', out)
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(pytest.main(sys.argv))
|
@ -0,0 +1,530 @@
|
||||
From d0427b44ecb56cdbc40ca156af8e013b64cce74d Mon Sep 17 00:00:00 2001
|
||||
From: Michal Sekletar <msekleta@redhat.com>
|
||||
Date: Mon, 18 Mar 2024 13:01:40 +0100
|
||||
Subject: [PATCH] coredump: generate stacktraces also for processes running in
|
||||
containers w/o coredump forwarding
|
||||
|
||||
Note that entering container namespace has to be explicitly enabled by
|
||||
setting SYSTEMD_COREDUMP_ALLOW_NAMESPACE_CHANGE environment variable.
|
||||
|
||||
RHEL-only
|
||||
|
||||
Resolves: RHEL-29430
|
||||
---
|
||||
src/analyze/analyze-inspect-elf.c | 2 +-
|
||||
src/basic/socket-util.c | 52 +++++++++++
|
||||
src/basic/socket-util.h | 15 ++++
|
||||
src/coredump/coredump.c | 143 +++++++++++++++++++-----------
|
||||
src/shared/elf-util.c | 46 +++++++++-
|
||||
src/shared/elf-util.h | 4 +-
|
||||
6 files changed, 202 insertions(+), 60 deletions(-)
|
||||
|
||||
diff --git a/src/analyze/analyze-inspect-elf.c b/src/analyze/analyze-inspect-elf.c
|
||||
index 155c611c71..b8074100a5 100644
|
||||
--- a/src/analyze/analyze-inspect-elf.c
|
||||
+++ b/src/analyze/analyze-inspect-elf.c
|
||||
@@ -30,7 +30,7 @@ static int analyze_elf(char **filenames, JsonFormatFlags json_flags) {
|
||||
if (fd < 0)
|
||||
return log_error_errno(fd, "Could not open \"%s\": %m", abspath);
|
||||
|
||||
- r = parse_elf_object(fd, abspath, /* fork_disable_dump= */false, NULL, &package_metadata);
|
||||
+ r = parse_elf_object(fd, -EBADF, UID_NOBODY, GID_NOBODY, abspath, /* fork_disable_dump= */false, NULL, &package_metadata);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Parsing \"%s\" as ELF object failed: %m", abspath);
|
||||
|
||||
diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c
|
||||
index f39be19a59..1d86ca3f55 100644
|
||||
--- a/src/basic/socket-util.c
|
||||
+++ b/src/basic/socket-util.c
|
||||
@@ -41,6 +41,11 @@
|
||||
# define IDN_FLAGS 0
|
||||
#endif
|
||||
|
||||
+/* From the kernel's include/net/scm.h */
|
||||
+#ifndef SCM_MAX_FD
|
||||
+# define SCM_MAX_FD 253
|
||||
+#endif
|
||||
+
|
||||
static const char* const socket_address_type_table[] = {
|
||||
[SOCK_STREAM] = "Stream",
|
||||
[SOCK_DGRAM] = "Datagram",
|
||||
@@ -951,6 +956,53 @@ int getpeergroups(int fd, gid_t **ret) {
|
||||
return (int) n;
|
||||
}
|
||||
|
||||
+ssize_t send_many_fds_iov_sa(
|
||||
+ int transport_fd,
|
||||
+ int *fds_array, size_t n_fds_array,
|
||||
+ const struct iovec *iov, size_t iovlen,
|
||||
+ const struct sockaddr *sa, socklen_t len,
|
||||
+ int flags) {
|
||||
+
|
||||
+ _cleanup_free_ struct cmsghdr *cmsg = NULL;
|
||||
+ struct msghdr mh = {
|
||||
+ .msg_name = (struct sockaddr*) sa,
|
||||
+ .msg_namelen = len,
|
||||
+ .msg_iov = (struct iovec *)iov,
|
||||
+ .msg_iovlen = iovlen,
|
||||
+ };
|
||||
+ ssize_t k;
|
||||
+
|
||||
+ assert(transport_fd >= 0);
|
||||
+ assert(fds_array || n_fds_array == 0);
|
||||
+
|
||||
+ /* The kernel will reject sending more than SCM_MAX_FD FDs at once */
|
||||
+ if (n_fds_array > SCM_MAX_FD)
|
||||
+ return -E2BIG;
|
||||
+
|
||||
+ /* We need either an FD array or data to send. If there's nothing, return an error. */
|
||||
+ if (n_fds_array == 0 && !iov)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (n_fds_array > 0) {
|
||||
+ mh.msg_controllen = CMSG_SPACE(sizeof(int) * n_fds_array);
|
||||
+ mh.msg_control = cmsg = malloc(mh.msg_controllen);
|
||||
+ if (!cmsg)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ *cmsg = (struct cmsghdr) {
|
||||
+ .cmsg_len = CMSG_LEN(sizeof(int) * n_fds_array),
|
||||
+ .cmsg_level = SOL_SOCKET,
|
||||
+ .cmsg_type = SCM_RIGHTS,
|
||||
+ };
|
||||
+ memcpy(CMSG_DATA(cmsg), fds_array, sizeof(int) * n_fds_array);
|
||||
+ }
|
||||
+ k = sendmsg(transport_fd, &mh, MSG_NOSIGNAL | flags);
|
||||
+ if (k < 0)
|
||||
+ return (ssize_t) -errno;
|
||||
+
|
||||
+ return k;
|
||||
+}
|
||||
+
|
||||
ssize_t send_one_fd_iov_sa(
|
||||
int transport_fd,
|
||||
int fd,
|
||||
diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h
|
||||
index 2e36e1a56b..61bf8ff32b 100644
|
||||
--- a/src/basic/socket-util.h
|
||||
+++ b/src/basic/socket-util.h
|
||||
@@ -153,6 +153,13 @@ int getpeercred(int fd, struct ucred *ucred);
|
||||
int getpeersec(int fd, char **ret);
|
||||
int getpeergroups(int fd, gid_t **ret);
|
||||
|
||||
+ssize_t send_many_fds_iov_sa(
|
||||
+ int transport_fd,
|
||||
+ int *fds_array, size_t n_fds_array,
|
||||
+ const struct iovec *iov, size_t iovlen,
|
||||
+ const struct sockaddr *sa, socklen_t len,
|
||||
+ int flags);
|
||||
+
|
||||
ssize_t send_one_fd_iov_sa(
|
||||
int transport_fd,
|
||||
int fd,
|
||||
@@ -163,6 +170,14 @@ int send_one_fd_sa(int transport_fd,
|
||||
int fd,
|
||||
const struct sockaddr *sa, socklen_t len,
|
||||
int flags);
|
||||
+static inline int send_many_fds(
|
||||
+ int transport_fd,
|
||||
+ int *fds_array,
|
||||
+ size_t n_fds_array,
|
||||
+ int flags) {
|
||||
+
|
||||
+ return send_many_fds_iov_sa(transport_fd, fds_array, n_fds_array, NULL, 0, NULL, 0, flags);
|
||||
+}
|
||||
#define send_one_fd_iov(transport_fd, fd, iov, iovlen, flags) send_one_fd_iov_sa(transport_fd, fd, iov, iovlen, NULL, 0, flags)
|
||||
#define send_one_fd(transport_fd, fd, flags) send_one_fd_iov_sa(transport_fd, fd, NULL, 0, NULL, 0, flags)
|
||||
ssize_t receive_one_fd_iov(int transport_fd, struct iovec *iov, size_t iovlen, int flags, int *ret_fd);
|
||||
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
|
||||
index b9c5f3ad04..dca78fa72c 100644
|
||||
--- a/src/coredump/coredump.c
|
||||
+++ b/src/coredump/coredump.c
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "coredump-vacuum.h"
|
||||
#include "dirent-util.h"
|
||||
#include "elf-util.h"
|
||||
+#include "env-util.h"
|
||||
#include "escape.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
@@ -36,6 +37,7 @@
|
||||
#include "main-func.h"
|
||||
#include "memory-util.h"
|
||||
#include "mkdir-label.h"
|
||||
+#include "namespace-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "process-util.h"
|
||||
#include "signal-util.h"
|
||||
@@ -130,6 +132,8 @@ typedef struct Context {
|
||||
const char *meta[_META_MAX];
|
||||
size_t meta_size[_META_MAX];
|
||||
pid_t pid;
|
||||
+ uid_t uid;
|
||||
+ gid_t gid;
|
||||
bool is_pid1;
|
||||
bool is_journald;
|
||||
} Context;
|
||||
@@ -866,36 +870,11 @@ static int get_process_container_parent_cmdline(pid_t pid, char** cmdline) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
-static int change_uid_gid(const Context *context) {
|
||||
- uid_t uid;
|
||||
- gid_t gid;
|
||||
- int r;
|
||||
-
|
||||
- r = parse_uid(context->meta[META_ARGV_UID], &uid);
|
||||
- if (r < 0)
|
||||
- return r;
|
||||
-
|
||||
- if (uid_is_system(uid)) {
|
||||
- const char *user = "systemd-coredump";
|
||||
-
|
||||
- r = get_user_creds(&user, &uid, &gid, NULL, NULL, 0);
|
||||
- if (r < 0) {
|
||||
- log_warning_errno(r, "Cannot resolve %s user. Proceeding to dump core as root: %m", user);
|
||||
- uid = gid = 0;
|
||||
- }
|
||||
- } else {
|
||||
- r = parse_gid(context->meta[META_ARGV_GID], &gid);
|
||||
- if (r < 0)
|
||||
- return r;
|
||||
- }
|
||||
-
|
||||
- return drop_privileges(uid, gid, 0);
|
||||
-}
|
||||
-
|
||||
static int submit_coredump(
|
||||
const Context *context,
|
||||
struct iovec_wrapper *iovw,
|
||||
- int input_fd) {
|
||||
+ int input_fd,
|
||||
+ int mntns_fd) {
|
||||
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *json_metadata = NULL;
|
||||
_cleanup_close_ int coredump_fd = -1, coredump_node_fd = -1;
|
||||
@@ -938,15 +917,6 @@ static int submit_coredump(
|
||||
/* Vacuum again, but exclude the coredump we just created */
|
||||
(void) coredump_vacuum(coredump_node_fd >= 0 ? coredump_node_fd : coredump_fd, arg_keep_free, arg_max_use);
|
||||
|
||||
- /* Now, let's drop privileges to become the user who owns the segfaulted process
|
||||
- * and allocate the coredump memory under the user's uid. This also ensures that
|
||||
- * the credentials journald will see are the ones of the coredumping user, thus
|
||||
- * making sure the user gets access to the core dump. Let's also get rid of all
|
||||
- * capabilities, if we run as root, we won't need them anymore. */
|
||||
- r = change_uid_gid(context);
|
||||
- if (r < 0)
|
||||
- return log_error_errno(r, "Failed to drop privileges: %m");
|
||||
-
|
||||
/* Try to get a stack trace if we can */
|
||||
if (coredump_size > arg_process_size_max)
|
||||
log_debug("Not generating stack trace: core size %"PRIu64" is greater "
|
||||
@@ -956,12 +926,23 @@ static int submit_coredump(
|
||||
bool skip = startswith(context->meta[META_COMM], "systemd-coredum"); /* COMM is 16 bytes usually */
|
||||
|
||||
(void) parse_elf_object(coredump_fd,
|
||||
+ mntns_fd,
|
||||
+ context->uid,
|
||||
+ context->gid,
|
||||
context->meta[META_EXE],
|
||||
/* fork_disable_dump= */ skip, /* avoid loops */
|
||||
&stacktrace,
|
||||
&json_metadata);
|
||||
}
|
||||
|
||||
+ /* Now, let's drop privileges to become the user who owns the segfaulted process. This also ensures
|
||||
+ * that the credentials journald will see are the ones of the coredumping user, thus making sure
|
||||
+ * the user gets access to the core dump. Let's also get rid of all capabilities, if we run as root,
|
||||
+ * we won't need them anymore. */
|
||||
+ r = drop_privileges(context->uid, context->gid, 0);
|
||||
+ if (r < 0)
|
||||
+ return log_error_errno(r, "Failed to drop privileges: %m");
|
||||
+
|
||||
log:
|
||||
core_message = strjoina("Process ", context->meta[META_ARGV_PID],
|
||||
" (", context->meta[META_COMM], ") of user ",
|
||||
@@ -1094,6 +1075,15 @@ static int save_context(Context *context, const struct iovec_wrapper *iovw) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse PID \"%s\": %m", context->meta[META_ARGV_PID]);
|
||||
|
||||
+ r = parse_uid(context->meta[META_ARGV_UID], &context->uid);
|
||||
+ if (r < 0)
|
||||
+ return log_error_errno(r, "Failed to parse UID \"%s\": %m", context->meta[META_ARGV_UID]);
|
||||
+
|
||||
+ r = parse_gid(context->meta[META_ARGV_GID], &context->gid);
|
||||
+ if (r < 0)
|
||||
+ return log_error_errno(r, "Failed to parse GID \"%s\": %m", context->meta[META_ARGV_GID]);
|
||||
+
|
||||
+
|
||||
unit = context->meta[META_UNIT];
|
||||
context->is_pid1 = streq(context->meta[META_ARGV_PID], "1") || streq_ptr(unit, SPECIAL_INIT_SCOPE);
|
||||
context->is_journald = streq_ptr(unit, SPECIAL_JOURNALD_SERVICE);
|
||||
@@ -1102,11 +1092,11 @@ static int save_context(Context *context, const struct iovec_wrapper *iovw) {
|
||||
}
|
||||
|
||||
static int process_socket(int fd) {
|
||||
- _cleanup_close_ int input_fd = -1;
|
||||
+ _cleanup_close_ int input_fd = -EBADF, mntns_fd = -EBADF;
|
||||
Context context = {};
|
||||
struct iovec_wrapper iovw = {};
|
||||
struct iovec iovec;
|
||||
- int r;
|
||||
+ int iterations = 0, r;
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
@@ -1146,23 +1136,39 @@ static int process_socket(int fd) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
- /* The final zero-length datagram carries the file descriptor and tells us
|
||||
+ /* The final zero-length datagram carries the file descriptors and tells us
|
||||
* that we're done. */
|
||||
if (n == 0) {
|
||||
struct cmsghdr *found;
|
||||
|
||||
free(iovec.iov_base);
|
||||
|
||||
- found = cmsg_find(&mh, SOL_SOCKET, SCM_RIGHTS, CMSG_LEN(sizeof(int)));
|
||||
- if (!found) {
|
||||
- cmsg_close_all(&mh);
|
||||
- r = log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
|
||||
- "Coredump file descriptor missing.");
|
||||
- goto finish;
|
||||
+ found = cmsg_find(&mh, SOL_SOCKET, SCM_RIGHTS, CMSG_LEN(sizeof(int) * 2));
|
||||
+ if (found) {
|
||||
+ int fds[2] = { -EBADF, -EBADF };
|
||||
+
|
||||
+ memcpy(fds, CMSG_DATA(found), sizeof(int) * 2);
|
||||
+
|
||||
+ assert(mntns_fd < 0);
|
||||
+
|
||||
+ /* Maybe we already got coredump FD in previous iteration? */
|
||||
+ safe_close(input_fd);
|
||||
+
|
||||
+ input_fd = fds[0];
|
||||
+ mntns_fd = fds[1];
|
||||
+
|
||||
+ /* We have all FDs we need let's take a shortcut here. */
|
||||
+ break;
|
||||
+ } else {
|
||||
+ found = cmsg_find(&mh, SOL_SOCKET, SCM_RIGHTS, CMSG_LEN(sizeof(int)));
|
||||
+ if (found)
|
||||
+ input_fd = *CMSG_DATA(found);
|
||||
}
|
||||
|
||||
- assert(input_fd < 0);
|
||||
- input_fd = *(int*) CMSG_DATA(found);
|
||||
+ /* This is the first message that carries file descriptors, maybe there will be one more that actually contains array of descriptors. */
|
||||
+ if (iterations++ == 0)
|
||||
+ continue;
|
||||
+
|
||||
break;
|
||||
} else
|
||||
cmsg_close_all(&mh);
|
||||
@@ -1177,7 +1183,11 @@ static int process_socket(int fd) {
|
||||
}
|
||||
|
||||
/* Make sure we got all data we really need */
|
||||
- assert(input_fd >= 0);
|
||||
+ if (input_fd < 0) {
|
||||
+ r = log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
|
||||
+ "Coredump file descriptor missing.");
|
||||
+ goto finish;
|
||||
+ }
|
||||
|
||||
r = save_context(&context, &iovw);
|
||||
if (r < 0)
|
||||
@@ -1192,15 +1202,15 @@ static int process_socket(int fd) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
- r = submit_coredump(&context, &iovw, input_fd);
|
||||
+ r = submit_coredump(&context, &iovw, input_fd, mntns_fd);
|
||||
|
||||
finish:
|
||||
iovw_free_contents(&iovw, true);
|
||||
return r;
|
||||
}
|
||||
|
||||
-static int send_iovec(const struct iovec_wrapper *iovw, int input_fd) {
|
||||
- _cleanup_close_ int fd = -1;
|
||||
+static int send_iovec(const struct iovec_wrapper *iovw, int input_fd, int mntns_fd) {
|
||||
+ _cleanup_close_ int fd = -EBADF;
|
||||
int r;
|
||||
|
||||
assert(iovw);
|
||||
@@ -1256,6 +1266,12 @@ static int send_iovec(const struct iovec_wrapper *iovw, int input_fd) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to send coredump fd: %m");
|
||||
|
||||
+ if (mntns_fd >= 0) {
|
||||
+ r = send_many_fds(fd, (int[]) { input_fd, mntns_fd }, 2, 0);
|
||||
+ if (r < 0)
|
||||
+ return log_error_errno(r, "Failed to send coredump fds: %m");
|
||||
+ }
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1428,7 +1444,7 @@ static int gather_pid_metadata(struct iovec_wrapper *iovw, Context *context) {
|
||||
static int process_kernel(int argc, char* argv[]) {
|
||||
Context context = {};
|
||||
struct iovec_wrapper *iovw;
|
||||
- int r;
|
||||
+ int r, mntns_fd = -EBADF;
|
||||
|
||||
/* When we're invoked by the kernel, stdout/stderr are closed which is dangerous because the fds
|
||||
* could get reallocated. To avoid hard to debug issues, let's instead bind stdout/stderr to
|
||||
@@ -1462,6 +1478,25 @@ static int process_kernel(int argc, char* argv[]) {
|
||||
log_open();
|
||||
}
|
||||
|
||||
+ r = in_same_namespace(getpid_cached(), context.pid, NAMESPACE_PID);
|
||||
+ if (r < 0)
|
||||
+ log_debug_errno(r, "Failed to check pidns of crashing process, ignoring: %m");
|
||||
+
|
||||
+ if (r == 0 && getenv_bool("SYSTEMD_COREDUMP_ALLOW_NAMESPACE_CHANGE") > 0) {
|
||||
+ r = namespace_open(context.pid, NULL, &mntns_fd, NULL, NULL, NULL);
|
||||
+ if (r < 0)
|
||||
+ return log_error_errno(r, "Failed to open mntns of crashing process: %m");
|
||||
+ } else {
|
||||
+ /* Crashing process is not running in the container or changing namespace is disabled, but we
|
||||
+ still need to send mount namespace fd along side coredump fd so let's just open our own
|
||||
+ mount namespace. Entering it will be NOP but that is OK. */
|
||||
+ r = namespace_open(getpid_cached(), NULL, &mntns_fd, NULL, NULL, NULL);
|
||||
+ if (r < 0)
|
||||
+ return log_error_errno(r, "Failed to open our mntns: %m");
|
||||
+ }
|
||||
+
|
||||
+ assert(mntns_fd >= 0 && fd_is_ns(mntns_fd, CLONE_NEWNS) > 0);
|
||||
+
|
||||
/* If this is PID 1 disable coredump collection, we'll unlikely be able to process
|
||||
* it later on.
|
||||
*
|
||||
@@ -1474,9 +1509,9 @@ static int process_kernel(int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
if (context.is_journald || context.is_pid1)
|
||||
- r = submit_coredump(&context, iovw, STDIN_FILENO);
|
||||
+ r = submit_coredump(&context, iovw, STDIN_FILENO, mntns_fd);
|
||||
else
|
||||
- r = send_iovec(iovw, STDIN_FILENO);
|
||||
+ r = send_iovec(iovw, STDIN_FILENO, mntns_fd);
|
||||
|
||||
finish:
|
||||
iovw = iovw_free_free(iovw);
|
||||
diff --git a/src/shared/elf-util.c b/src/shared/elf-util.c
|
||||
index bde5013b92..6a2969732d 100644
|
||||
--- a/src/shared/elf-util.c
|
||||
+++ b/src/shared/elf-util.c
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
+#include "capability-util.h"
|
||||
#include "dlfcn-util.h"
|
||||
#include "elf-util.h"
|
||||
#include "errno-util.h"
|
||||
@@ -21,9 +22,12 @@
|
||||
#include "hexdecoct.h"
|
||||
#include "io-util.h"
|
||||
#include "macro.h"
|
||||
+#include "namespace-util.h"
|
||||
#include "process-util.h"
|
||||
#include "rlimit-util.h"
|
||||
#include "string-util.h"
|
||||
+#include "uid-alloc-range.h"
|
||||
+#include "user-util.h"
|
||||
#include "util.h"
|
||||
|
||||
#define FRAMES_MAX 64
|
||||
@@ -752,11 +756,27 @@ static int parse_elf(int fd, const char *executable, char **ret, JsonVariant **r
|
||||
return 0;
|
||||
}
|
||||
|
||||
-int parse_elf_object(int fd, const char *executable, bool fork_disable_dump, char **ret, JsonVariant **ret_package_metadata) {
|
||||
+static int core_change_uid_gid(uid_t uid, gid_t gid) {
|
||||
+ uid_t u = uid;
|
||||
+ gid_t g = gid;
|
||||
+ int r;
|
||||
+
|
||||
+ if (uid_is_system(u)) {
|
||||
+ const char *user = "systemd-coredump";
|
||||
+
|
||||
+ r = get_user_creds(&user, &u, &g, NULL, NULL, 0);
|
||||
+ if (r < 0)
|
||||
+ log_warning_errno(r, "Cannot resolve %s user, ignoring: %m", user);
|
||||
+ }
|
||||
+
|
||||
+ return drop_privileges(u, g, 0);
|
||||
+}
|
||||
+
|
||||
+int parse_elf_object(int fd, int mntns_fd, uid_t uid, gid_t gid, const char *executable, bool fork_disable_dump, char **ret, JsonVariant **ret_package_metadata) {
|
||||
_cleanup_close_pair_ int error_pipe[2] = { -1, -1 }, return_pipe[2] = { -1, -1 }, json_pipe[2] = { -1, -1 };
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *package_metadata = NULL;
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
- int r;
|
||||
+ int flags, r;
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
@@ -784,6 +804,10 @@ int parse_elf_object(int fd, const char *executable, bool fork_disable_dump, cha
|
||||
return r;
|
||||
}
|
||||
|
||||
+ flags = FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE|FORK_NEW_USERNS|FORK_WAIT|FORK_REOPEN_LOG;
|
||||
+ if (mntns_fd >= 0)
|
||||
+ flags &= ~(FORK_CLOSE_ALL_FDS|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE|FORK_NEW_USERNS);
|
||||
+
|
||||
/* Parsing possibly malformed data is crash-happy, so fork. In case we crash,
|
||||
* the core file will not be lost, and the messages will still be attached to
|
||||
* the journal. Reading the elf object might be slow, but it still has an upper
|
||||
@@ -793,7 +817,7 @@ int parse_elf_object(int fd, const char *executable, bool fork_disable_dump, cha
|
||||
r = safe_fork_full("(sd-parse-elf)",
|
||||
(int[]){ fd, error_pipe[1], return_pipe[1], json_pipe[1] },
|
||||
4,
|
||||
- FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE|FORK_NEW_USERNS|FORK_WAIT|FORK_REOPEN_LOG,
|
||||
+ flags,
|
||||
NULL);
|
||||
if (r < 0) {
|
||||
if (r == -EPROTO) { /* We should have the errno from the child, but don't clobber original error */
|
||||
@@ -811,6 +835,22 @@ int parse_elf_object(int fd, const char *executable, bool fork_disable_dump, cha
|
||||
return r;
|
||||
}
|
||||
if (r == 0) {
|
||||
+ if (mntns_fd >= 0) {
|
||||
+ r = namespace_enter(/* pidns_fd = */ -EBADF,
|
||||
+ mntns_fd,
|
||||
+ /* netns_fd = */ -EBADF,
|
||||
+ /* userns_fd = */ -EBADF,
|
||||
+ /* root_fd = */ -EBADF);
|
||||
+ if (r < 0)
|
||||
+ log_notice_errno(r, "Failed to enter mount namespace of crashing process, ignoring: %m");
|
||||
+ }
|
||||
+
|
||||
+ if (uid != UID_NOBODY && gid != GID_NOBODY) {
|
||||
+ r = core_change_uid_gid(uid, gid);
|
||||
+ if (r < 0)
|
||||
+ log_notice_errno(r, "Failed to drop privileges, ignoring: %m");
|
||||
+ }
|
||||
+
|
||||
/* We want to avoid loops, given this can be called from systemd-coredump */
|
||||
if (fork_disable_dump) {
|
||||
r = RET_NERRNO(prctl(PR_SET_DUMPABLE, 0));
|
||||
diff --git a/src/shared/elf-util.h b/src/shared/elf-util.h
|
||||
index b28e64cea6..350464941f 100644
|
||||
--- a/src/shared/elf-util.h
|
||||
+++ b/src/shared/elf-util.h
|
||||
@@ -10,9 +10,9 @@ int dlopen_elf(void);
|
||||
/* Parse an ELF object in a forked process, so that errors while iterating over
|
||||
* untrusted and potentially malicious data do not propagate to the main caller's process.
|
||||
* If fork_disable_dump, the child process will not dump core if it crashes. */
|
||||
-int parse_elf_object(int fd, const char *executable, bool fork_disable_dump, char **ret, JsonVariant **ret_package_metadata);
|
||||
+int parse_elf_object(int fd, int mntns_fd, uid_t uid, gid_t gid, const char *executable, bool fork_disable_dump, char **ret, JsonVariant **ret_package_metadata);
|
||||
#else
|
||||
-static inline int parse_elf_object(int fd, const char *executable, bool fork_disable_dump, char **ret, JsonVariant **ret_package_metadata) {
|
||||
+static inline int parse_elf_object(int fd, int mntns_fd, uid_t uid, gid_t gid, const char *executable, bool fork_disable_dump, char **ret, JsonVariant **ret_package_metadata) {
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "elfutils disabled, parsing ELF objects not supported");
|
||||
}
|
||||
#endif
|
@ -0,0 +1,194 @@
|
||||
From 6307dbb9cb25fd5a2131c043b89a52f032817178 Mon Sep 17 00:00:00 2001
|
||||
From: Frantisek Sumsal <frantisek@sumsal.cz>
|
||||
Date: Tue, 21 Mar 2023 23:19:41 +0100
|
||||
Subject: [PATCH] test: add a couple of tests for systemd-coredump
|
||||
|
||||
(cherry picked from commit aadbd81f7ffbc313d0541c15455211dddeedbfde)
|
||||
|
||||
Related: RHEL-29430
|
||||
---
|
||||
test/units/testsuite-74.coredump.sh | 175 ++++++++++++++++++++++++++++
|
||||
1 file changed, 175 insertions(+)
|
||||
create mode 100755 test/units/testsuite-74.coredump.sh
|
||||
|
||||
diff --git a/test/units/testsuite-74.coredump.sh b/test/units/testsuite-74.coredump.sh
|
||||
new file mode 100755
|
||||
index 0000000000..6a299ecbfb
|
||||
--- /dev/null
|
||||
+++ b/test/units/testsuite-74.coredump.sh
|
||||
@@ -0,0 +1,175 @@
|
||||
+#!/usr/bin/env bash
|
||||
+# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
+set -eux
|
||||
+set -o pipefail
|
||||
+
|
||||
+# Make sure the binary name fits into 15 characters
|
||||
+CORE_TEST_BIN="/tmp/test-dump"
|
||||
+CORE_TEST_UNPRIV_BIN="/tmp/test-usr-dump"
|
||||
+MAKE_DUMP_SCRIPT="/tmp/make-dump"
|
||||
+# Unset $PAGER so we don't have to use --no-pager everywhere
|
||||
+export PAGER=
|
||||
+
|
||||
+at_exit() {
|
||||
+ rm -fv -- "$CORE_TEST_BIN" "$CORE_TEST_UNPRIV_BIN" "$MAKE_DUMP_SCRIPT"
|
||||
+}
|
||||
+
|
||||
+trap at_exit EXIT
|
||||
+
|
||||
+if systemd-detect-virt -cq; then
|
||||
+ echo "Running in a container, skipping the systemd-coredump test..."
|
||||
+ exit 0
|
||||
+fi
|
||||
+
|
||||
+# Check that we're the ones to receive coredumps
|
||||
+sysctl kernel.core_pattern | grep systemd-coredump
|
||||
+
|
||||
+# Prepare "fake" binaries for coredumps, so we can properly exercise
|
||||
+# the matching stuff too
|
||||
+cp -vf /bin/sleep "${CORE_TEST_BIN:?}"
|
||||
+cp -vf /bin/sleep "${CORE_TEST_UNPRIV_BIN:?}"
|
||||
+# Simple script that spawns given "fake" binary and then kills it with
|
||||
+# given signal
|
||||
+cat >"${MAKE_DUMP_SCRIPT:?}" <<\EOF
|
||||
+#!/bin/bash -ex
|
||||
+
|
||||
+bin="${1:?}"
|
||||
+sig="${2:?}"
|
||||
+
|
||||
+ulimit -c unlimited
|
||||
+"$bin" infinity &
|
||||
+pid=$!
|
||||
+sleep 1
|
||||
+kill -s "$sig" "$pid"
|
||||
+# This should always fail
|
||||
+! wait "$pid"
|
||||
+EOF
|
||||
+chmod +x "$MAKE_DUMP_SCRIPT"
|
||||
+
|
||||
+# Privileged stuff
|
||||
+[[ "$(id -u)" -eq 0 ]]
|
||||
+# Trigger a couple of coredumps
|
||||
+"$MAKE_DUMP_SCRIPT" "$CORE_TEST_BIN" "SIGTRAP"
|
||||
+"$MAKE_DUMP_SCRIPT" "$CORE_TEST_BIN" "SIGABRT"
|
||||
+# In the tests we store the coredumps in journals, so let's generate a couple
|
||||
+# with Storage=external as well
|
||||
+mkdir -p /run/systemd/coredump.conf.d/
|
||||
+printf '[Coredump]\nStorage=external' >/run/systemd/coredump.conf.d/99-external.conf
|
||||
+"$MAKE_DUMP_SCRIPT" "$CORE_TEST_BIN" "SIGTRAP"
|
||||
+"$MAKE_DUMP_SCRIPT" "$CORE_TEST_BIN" "SIGABRT"
|
||||
+rm -fv /run/systemd/coredump.conf.d/99-external.conf
|
||||
+# Wait a bit for the coredumps to get processed
|
||||
+timeout 30 bash -c "while [[ $(coredumpctl list -q --no-legend $CORE_TEST_BIN | wc -l) -lt 4 ]]; do sleep 1; done"
|
||||
+
|
||||
+coredumpctl
|
||||
+SYSTEMD_LOG_LEVEL=debug coredumpctl
|
||||
+coredumpctl --help
|
||||
+coredumpctl --version
|
||||
+coredumpctl --no-pager --no-legend
|
||||
+coredumpctl --all
|
||||
+coredumpctl -1
|
||||
+coredumpctl -n 1
|
||||
+coredumpctl --reverse
|
||||
+coredumpctl -F COREDUMP_EXE
|
||||
+coredumpctl --json=short | jq
|
||||
+coredumpctl --json=pretty | jq
|
||||
+coredumpctl --json=off
|
||||
+coredumpctl --root=/
|
||||
+coredumpctl --directory=/var/log/journal
|
||||
+coredumpctl --file="/var/log/journal/$(</etc/machine-id)/system.journal"
|
||||
+coredumpctl --since=@0
|
||||
+coredumpctl --since=yesterday --until=tomorrow
|
||||
+# We should have a couple of externally stored coredumps
|
||||
+coredumpctl --field=COREDUMP_FILENAME | tee /tmp/coredumpctl.out
|
||||
+grep "/var/lib/systemd/coredump/core" /tmp/coredumpctl.out
|
||||
+rm -f /tmp/coredumpctl.out
|
||||
+
|
||||
+coredumpctl info
|
||||
+coredumpctl info "$CORE_TEST_BIN"
|
||||
+coredumpctl info /foo /bar/ /baz "$CORE_TEST_BIN"
|
||||
+coredumpctl info "${CORE_TEST_BIN##*/}"
|
||||
+coredumpctl info foo bar baz "${CORE_TEST_BIN##*/}"
|
||||
+coredumpctl info COREDUMP_EXE="$CORE_TEST_BIN"
|
||||
+coredumpctl info COREDUMP_EXE=aaaaa COREDUMP_EXE= COREDUMP_EXE="$CORE_TEST_BIN"
|
||||
+
|
||||
+coredumpctl debug --debugger=/bin/true "$CORE_TEST_BIN"
|
||||
+SYSTEMD_DEBUGGER=/bin/true coredumpctl debug "$CORE_TEST_BIN"
|
||||
+coredumpctl debug --debugger=/bin/true --debugger-arguments="-this --does --not 'do anything' -a -t --all" "${CORE_TEST_BIN##*/}"
|
||||
+
|
||||
+coredumpctl dump "$CORE_TEST_BIN" >/tmp/core.redirected
|
||||
+test -s /tmp/core.redirected
|
||||
+coredumpctl dump -o /tmp/core.output "${CORE_TEST_BIN##*/}"
|
||||
+test -s /tmp/core.output
|
||||
+rm -f /tmp/core.{output,redirected}
|
||||
+
|
||||
+# Unprivileged stuff
|
||||
+# Related issue: https://github.com/systemd/systemd/issues/26912
|
||||
+UNPRIV_CMD=(systemd-run --user --wait --pipe -M "testuser@.host" --)
|
||||
+# Trigger a couple of coredumps as an unprivileged user
|
||||
+"${UNPRIV_CMD[@]}" "$MAKE_DUMP_SCRIPT" "$CORE_TEST_UNPRIV_BIN" "SIGTRAP"
|
||||
+"${UNPRIV_CMD[@]}" "$MAKE_DUMP_SCRIPT" "$CORE_TEST_UNPRIV_BIN" "SIGABRT"
|
||||
+# In the tests we store the coredumps in journals, so let's generate a couple
|
||||
+# with Storage=external as well
|
||||
+mkdir -p /run/systemd/coredump.conf.d/
|
||||
+printf '[Coredump]\nStorage=external' >/run/systemd/coredump.conf.d/99-external.conf
|
||||
+"${UNPRIV_CMD[@]}" "$MAKE_DUMP_SCRIPT" "$CORE_TEST_UNPRIV_BIN" "SIGTRAP"
|
||||
+"${UNPRIV_CMD[@]}" "$MAKE_DUMP_SCRIPT" "$CORE_TEST_UNPRIV_BIN" "SIGABRT"
|
||||
+rm -fv /run/systemd/coredump.conf.d/99-external.conf
|
||||
+# Wait a bit for the coredumps to get processed
|
||||
+timeout 30 bash -c "while [[ $(coredumpctl list -q --no-legend $CORE_TEST_UNPRIV_BIN | wc -l) -lt 4 ]]; do sleep 1; done"
|
||||
+
|
||||
+# root should see coredumps from both binaries
|
||||
+coredumpctl info "$CORE_TEST_UNPRIV_BIN"
|
||||
+coredumpctl info "${CORE_TEST_UNPRIV_BIN##*/}"
|
||||
+# The test user should see only their own coredumps
|
||||
+"${UNPRIV_CMD[@]}" coredumpctl
|
||||
+"${UNPRIV_CMD[@]}" coredumpctl info "$CORE_TEST_UNPRIV_BIN"
|
||||
+"${UNPRIV_CMD[@]}" coredumpctl info "${CORE_TEST_UNPRIV_BIN##*/}"
|
||||
+(! "${UNPRIV_CMD[@]}" coredumpctl info --all "$CORE_TEST_BIN")
|
||||
+(! "${UNPRIV_CMD[@]}" coredumpctl info --all "${CORE_TEST_BIN##*/}")
|
||||
+# We should have a couple of externally stored coredumps
|
||||
+"${UNPRIV_CMD[@]}" coredumpctl --field=COREDUMP_FILENAME | tee /tmp/coredumpctl.out
|
||||
+grep "/var/lib/systemd/coredump/core" /tmp/coredumpctl.out
|
||||
+rm -f /tmp/coredumpctl.out
|
||||
+
|
||||
+"${UNPRIV_CMD[@]}" coredumpctl debug --debugger=/bin/true "$CORE_TEST_UNPRIV_BIN"
|
||||
+"${UNPRIV_CMD[@]}" coredumpctl debug --debugger=/bin/true --debugger-arguments="-this --does --not 'do anything' -a -t --all" "${CORE_TEST_UNPRIV_BIN##*/}"
|
||||
+
|
||||
+"${UNPRIV_CMD[@]}" coredumpctl dump "$CORE_TEST_UNPRIV_BIN" >/tmp/core.redirected
|
||||
+test -s /tmp/core.redirected
|
||||
+"${UNPRIV_CMD[@]}" coredumpctl dump -o /tmp/core.output "${CORE_TEST_UNPRIV_BIN##*/}"
|
||||
+test -s /tmp/core.output
|
||||
+rm -f /tmp/core.{output,redirected}
|
||||
+(! "${UNPRIV_CMD[@]}" coredumpctl dump "$CORE_TEST_BIN" >/dev/null)
|
||||
+
|
||||
+# --backtrace mode
|
||||
+# Pass one of the existing journal coredump records to systemd-coredump and
|
||||
+# use our PID as the source to make matching the coredump later easier
|
||||
+# systemd-coredump args: PID UID GID SIGNUM TIMESTAMP CORE_SOFT_RLIMIT HOSTNAME
|
||||
+journalctl -b -n 1 --output=export --output-fields=MESSAGE,COREDUMP COREDUMP_EXE="/usr/bin/test-dump" |
|
||||
+ /usr/lib/systemd/systemd-coredump --backtrace $$ 0 0 6 1679509994 12345 mymachine
|
||||
+# Wait a bit for the coredump to get processed
|
||||
+timeout 30 bash -c "while [[ $(coredumpctl list -q --no-legend $$ | wc -l) -eq 0 ]]; do sleep 1; done"
|
||||
+coredumpctl info "$$"
|
||||
+coredumpctl info COREDUMP_HOSTNAME="mymachine"
|
||||
+
|
||||
+
|
||||
+(! coredumpctl --hello-world)
|
||||
+(! coredumpctl -n 0)
|
||||
+(! coredumpctl -n -1)
|
||||
+(! coredumpctl --file=/dev/null)
|
||||
+(! coredumpctl --since=0)
|
||||
+(! coredumpctl --until='')
|
||||
+(! coredumpctl --since=today --until=yesterday)
|
||||
+(! coredumpctl --directory=/ --root=/)
|
||||
+(! coredumpctl --json=foo)
|
||||
+(! coredumpctl -F foo -F bar)
|
||||
+(! coredumpctl list 0)
|
||||
+(! coredumpctl list -- -1)
|
||||
+(! coredumpctl list '')
|
||||
+(! coredumpctl info /../.~=)
|
||||
+(! coredumpctl info '')
|
||||
+(! coredumpctl dump --output=/dev/full "$CORE_TEST_BIN")
|
||||
+(! coredumpctl dump --output=/dev/null --output=/dev/null "$CORE_TEST_BIN")
|
||||
+(! coredumpctl debug --debugger=/bin/false)
|
||||
+(! coredumpctl debug --debugger=/bin/true --debugger-arguments='"')
|
@ -0,0 +1,54 @@
|
||||
From 687c8da38e766fe35a2710b0539576710c345f34 Mon Sep 17 00:00:00 2001
|
||||
From: Frantisek Sumsal <frantisek@sumsal.cz>
|
||||
Date: Sat, 25 Mar 2023 12:02:15 +0100
|
||||
Subject: [PATCH] test: don't expand the subshell expression prematurely
|
||||
|
||||
We need to expand the subshell expression during the `bash -c`
|
||||
invocation, not before, to take the desired effect, as now it expands to:
|
||||
|
||||
timeout 30 bash -c 'while [[ 0 -eq 0 ]]; do sleep 1; done'
|
||||
|
||||
instead of the expected:
|
||||
|
||||
timeout 30 bash -c 'while [[ $(coredumpctl list -q --no-legend 770 | wc -l) -eq 0 ]]; do sleep 1; done'
|
||||
|
||||
Follow-up to aadbd81f7f.
|
||||
|
||||
(cherry picked from commit 0b189ac84c432a085a1f10139260cec6b5032523)
|
||||
|
||||
Related: RHEL-29430
|
||||
---
|
||||
test/units/testsuite-74.coredump.sh | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/test/units/testsuite-74.coredump.sh b/test/units/testsuite-74.coredump.sh
|
||||
index 6a299ecbfb..3910abe0ec 100755
|
||||
--- a/test/units/testsuite-74.coredump.sh
|
||||
+++ b/test/units/testsuite-74.coredump.sh
|
||||
@@ -59,7 +59,7 @@ printf '[Coredump]\nStorage=external' >/run/systemd/coredump.conf.d/99-external.
|
||||
"$MAKE_DUMP_SCRIPT" "$CORE_TEST_BIN" "SIGABRT"
|
||||
rm -fv /run/systemd/coredump.conf.d/99-external.conf
|
||||
# Wait a bit for the coredumps to get processed
|
||||
-timeout 30 bash -c "while [[ $(coredumpctl list -q --no-legend $CORE_TEST_BIN | wc -l) -lt 4 ]]; do sleep 1; done"
|
||||
+timeout 30 bash -c "while [[ \$(coredumpctl list -q --no-legend $CORE_TEST_BIN | wc -l) -lt 4 ]]; do sleep 1; done"
|
||||
|
||||
coredumpctl
|
||||
SYSTEMD_LOG_LEVEL=debug coredumpctl
|
||||
@@ -116,7 +116,7 @@ printf '[Coredump]\nStorage=external' >/run/systemd/coredump.conf.d/99-external.
|
||||
"${UNPRIV_CMD[@]}" "$MAKE_DUMP_SCRIPT" "$CORE_TEST_UNPRIV_BIN" "SIGABRT"
|
||||
rm -fv /run/systemd/coredump.conf.d/99-external.conf
|
||||
# Wait a bit for the coredumps to get processed
|
||||
-timeout 30 bash -c "while [[ $(coredumpctl list -q --no-legend $CORE_TEST_UNPRIV_BIN | wc -l) -lt 4 ]]; do sleep 1; done"
|
||||
+timeout 30 bash -c "while [[ \$(coredumpctl list -q --no-legend $CORE_TEST_UNPRIV_BIN | wc -l) -lt 4 ]]; do sleep 1; done"
|
||||
|
||||
# root should see coredumps from both binaries
|
||||
coredumpctl info "$CORE_TEST_UNPRIV_BIN"
|
||||
@@ -149,7 +149,7 @@ rm -f /tmp/core.{output,redirected}
|
||||
journalctl -b -n 1 --output=export --output-fields=MESSAGE,COREDUMP COREDUMP_EXE="/usr/bin/test-dump" |
|
||||
/usr/lib/systemd/systemd-coredump --backtrace $$ 0 0 6 1679509994 12345 mymachine
|
||||
# Wait a bit for the coredump to get processed
|
||||
-timeout 30 bash -c "while [[ $(coredumpctl list -q --no-legend $$ | wc -l) -eq 0 ]]; do sleep 1; done"
|
||||
+timeout 30 bash -c "while [[ \$(coredumpctl list -q --no-legend $$ | wc -l) -eq 0 ]]; do sleep 1; done"
|
||||
coredumpctl info "$$"
|
||||
coredumpctl info COREDUMP_HOSTNAME="mymachine"
|
||||
|
@ -0,0 +1,63 @@
|
||||
From f46d65bba43c519d8d2ed8fab86ea765166c0e72 Mon Sep 17 00:00:00 2001
|
||||
From: Luca Boccassi <bluca@debian.org>
|
||||
Date: Wed, 26 Apr 2023 14:18:04 +0100
|
||||
Subject: [PATCH] coredump filter: fix stack overflow with =all
|
||||
|
||||
We translate 'all' to UNIT64_MAX, which has a lot more 'f's. Use the
|
||||
helper macro, since a decimal uint64_t will always be >> than a hex
|
||||
representation.
|
||||
|
||||
root@image:~# systemd-run -t --property CoredumpFilter=all ls /tmp
|
||||
Running as unit: run-u13.service
|
||||
Press ^] three times within 1s to disconnect TTY.
|
||||
*** stack smashing detected ***: terminated
|
||||
[137256.320511] systemd[1]: run-u13.service: Main process exited, code=dumped, status=6/ABRT
|
||||
[137256.320850] systemd[1]: run-u13.service: Failed with result 'core-dump'.
|
||||
|
||||
(cherry picked from commit 37232d55a7bcace37280e28b207c85f5ca9b3f6b)
|
||||
|
||||
Related: RHEL-29430
|
||||
---
|
||||
src/basic/macro.h | 4 ++++
|
||||
src/shared/coredump-util.c | 5 +++--
|
||||
2 files changed, 7 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/basic/macro.h b/src/basic/macro.h
|
||||
index 2d378454a2..6893a1ff32 100644
|
||||
--- a/src/basic/macro.h
|
||||
+++ b/src/basic/macro.h
|
||||
@@ -268,6 +268,10 @@ static inline int __coverity_check_and_return__(int condition) {
|
||||
|
||||
#define sizeof_field(struct_type, member) sizeof(((struct_type *) 0)->member)
|
||||
|
||||
+/* Maximum buffer size needed for formatting an unsigned integer type as hex, including space for '0x'
|
||||
+ * prefix and trailing NUL suffix. */
|
||||
+#define HEXADECIMAL_STR_MAX(type) (2 + sizeof(type) * 2 + 1)
|
||||
+
|
||||
/* Returns the number of chars needed to format variables of the specified type as a decimal string. Adds in
|
||||
* extra space for a negative '-' prefix for signed types. Includes space for the trailing NUL. */
|
||||
#define DECIMAL_STR_MAX(type) \
|
||||
diff --git a/src/shared/coredump-util.c b/src/shared/coredump-util.c
|
||||
index a0b648bf79..aaf3e16eff 100644
|
||||
--- a/src/shared/coredump-util.c
|
||||
+++ b/src/shared/coredump-util.c
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "coredump-util.h"
|
||||
#include "extract-word.h"
|
||||
#include "fileio.h"
|
||||
+#include "stdio-util.h"
|
||||
#include "string-table.h"
|
||||
|
||||
static const char *const coredump_filter_table[_COREDUMP_FILTER_MAX] = {
|
||||
@@ -65,9 +66,9 @@ int coredump_filter_mask_from_string(const char *s, uint64_t *ret) {
|
||||
}
|
||||
|
||||
int set_coredump_filter(uint64_t value) {
|
||||
- char t[STRLEN("0xFFFFFFFF")];
|
||||
+ char t[HEXADECIMAL_STR_MAX(uint64_t)];
|
||||
|
||||
- sprintf(t, "0x%"PRIx64, value);
|
||||
+ xsprintf(t, "0x%"PRIx64, value);
|
||||
|
||||
return write_string_file("/proc/self/coredump_filter", t,
|
||||
WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_DISABLE_BUFFER);
|
@ -0,0 +1,59 @@
|
||||
From 8db17468f2c0dd07d5e9618e3b49fddda26724c6 Mon Sep 17 00:00:00 2001
|
||||
From: Luca Boccassi <bluca@debian.org>
|
||||
Date: Wed, 26 Apr 2023 14:19:33 +0100
|
||||
Subject: [PATCH] coredump filter: add mask for 'all' using UINT32_MAX, not
|
||||
UINT64_MAX
|
||||
|
||||
The kernel returns ERANGE when UINT64_MAX is passed. Create a mask
|
||||
and use UINT32_max, which is accepted, so that future bits will also
|
||||
be set.
|
||||
|
||||
(cherry picked from commit 7f3bb8f20dcccaceea8b1ee05f0560b81162037b)
|
||||
|
||||
Related: RHEL-29430
|
||||
---
|
||||
src/shared/coredump-util.c | 2 +-
|
||||
src/shared/coredump-util.h | 3 +++
|
||||
src/test/test-coredump-util.c | 2 ++
|
||||
3 files changed, 6 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/shared/coredump-util.c b/src/shared/coredump-util.c
|
||||
index aaf3e16eff..7a44816834 100644
|
||||
--- a/src/shared/coredump-util.c
|
||||
+++ b/src/shared/coredump-util.c
|
||||
@@ -43,7 +43,7 @@ int coredump_filter_mask_from_string(const char *s, uint64_t *ret) {
|
||||
}
|
||||
|
||||
if (streq(n, "all")) {
|
||||
- m = UINT64_MAX;
|
||||
+ m = COREDUMP_FILTER_MASK_ALL;
|
||||
continue;
|
||||
}
|
||||
|
||||
diff --git a/src/shared/coredump-util.h b/src/shared/coredump-util.h
|
||||
index 09e7ed443f..f4d4098136 100644
|
||||
--- a/src/shared/coredump-util.h
|
||||
+++ b/src/shared/coredump-util.h
|
||||
@@ -22,6 +22,9 @@ typedef enum CoredumpFilter {
|
||||
1u << COREDUMP_FILTER_ELF_HEADERS | \
|
||||
1u << COREDUMP_FILTER_PRIVATE_HUGE)
|
||||
|
||||
+/* The kernel doesn't like UINT64_MAX and returns ERANGE, use UINT32_MAX to support future new flags */
|
||||
+#define COREDUMP_FILTER_MASK_ALL UINT32_MAX
|
||||
+
|
||||
const char* coredump_filter_to_string(CoredumpFilter i) _const_;
|
||||
CoredumpFilter coredump_filter_from_string(const char *s) _pure_;
|
||||
int coredump_filter_mask_from_string(const char *s, uint64_t *ret);
|
||||
diff --git a/src/test/test-coredump-util.c b/src/test/test-coredump-util.c
|
||||
index 40b68df9f4..87dc371a88 100644
|
||||
--- a/src/test/test-coredump-util.c
|
||||
+++ b/src/test/test-coredump-util.c
|
||||
@@ -23,6 +23,8 @@ TEST(coredump_filter_mask_from_string) {
|
||||
uint64_t f;
|
||||
assert_se(coredump_filter_mask_from_string("default", &f) == 0);
|
||||
assert_se(f == COREDUMP_FILTER_MASK_DEFAULT);
|
||||
+ assert_se(coredump_filter_mask_from_string("all", &f) == 0);
|
||||
+ assert_se(f == COREDUMP_FILTER_MASK_ALL);
|
||||
|
||||
assert_se(coredump_filter_mask_from_string(" default\tdefault\tdefault ", &f) == 0);
|
||||
assert_se(f == COREDUMP_FILTER_MASK_DEFAULT);
|
26
SOURCES/0728-test-add-coverage-for-CoredumpFilter-all.patch
Normal file
26
SOURCES/0728-test-add-coverage-for-CoredumpFilter-all.patch
Normal file
@ -0,0 +1,26 @@
|
||||
From 27538bb6224cdcd2ee04284b496449e0d2755e7b Mon Sep 17 00:00:00 2001
|
||||
From: Luca Boccassi <bluca@debian.org>
|
||||
Date: Wed, 26 Apr 2023 14:32:04 +0100
|
||||
Subject: [PATCH] test: add coverage for CoredumpFilter=all
|
||||
|
||||
(cherry picked from commit cf636aa59eb8c848ed04d5b08aac0acf3f6683d9)
|
||||
|
||||
Related: RHEL-29430
|
||||
---
|
||||
test/units/testsuite-74.coredump.sh | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/test/units/testsuite-74.coredump.sh b/test/units/testsuite-74.coredump.sh
|
||||
index 3910abe0ec..0e5d050f45 100755
|
||||
--- a/test/units/testsuite-74.coredump.sh
|
||||
+++ b/test/units/testsuite-74.coredump.sh
|
||||
@@ -153,6 +153,9 @@ timeout 30 bash -c "while [[ \$(coredumpctl list -q --no-legend $$ | wc -l) -eq
|
||||
coredumpctl info "$$"
|
||||
coredumpctl info COREDUMP_HOSTNAME="mymachine"
|
||||
|
||||
+# This used to cause a stack overflow
|
||||
+systemd-run -t --property CoredumpFilter=all ls /tmp
|
||||
+systemd-run -t --property CoredumpFilter=default ls /tmp
|
||||
|
||||
(! coredumpctl --hello-world)
|
||||
(! coredumpctl -n 0)
|
@ -0,0 +1,52 @@
|
||||
From cada47a50ea898f092c430508656ed717ab78dba Mon Sep 17 00:00:00 2001
|
||||
From: Yu Watanabe <watanabe.yu+github@gmail.com>
|
||||
Date: Wed, 24 May 2023 10:31:41 +0900
|
||||
Subject: [PATCH] test: rotate journal before storing coredumps
|
||||
|
||||
Hopefully fixes the failure like
|
||||
https://jenkins-systemd.apps.ocp.cloud.ci.centos.org/job/upstream-vagrant-archlinux-sanitizers/2558/
|
||||
---
|
||||
[ 66.708894] testsuite-74.sh[728]: + coredumpctl --json=off
|
||||
[ 66.709344] testsuite-74.sh[826]: TIME PID UID GID SIG COREFILE EXE SIZE
|
||||
[ 66.709773] testsuite-74.sh[826]: Tue 2023-05-23 22:10:17 UTC 739 0 0 SIGTRAP journal /tmp/test-dump -
|
||||
[ 66.711134] testsuite-74.sh[826]: Tue 2023-05-23 22:10:18 UTC 747 0 0 SIGABRT journal /tmp/test-dump -
|
||||
[ 66.711789] testsuite-74.sh[826]: Tue 2023-05-23 22:10:19 UTC 763 0 0 SIGTRAP present /tmp/test-dump 53.5K
|
||||
[ 66.712460] testsuite-74.sh[826]: Tue 2023-05-23 22:10:20 UTC 776 0 0 SIGABRT present /tmp/test-dump 53.3K
|
||||
[ 66.713505] testsuite-74.sh[728]: + coredumpctl --root=/
|
||||
[ 66.714144] testsuite-74.sh[828]: TIME PID UID GID SIG COREFILE EXE SIZE
|
||||
[ 66.714535] testsuite-74.sh[828]: Tue 2023-05-23 22:10:17 UTC 739 0 0 SIGTRAP journal /tmp/test-dump -
|
||||
[ 66.715208] testsuite-74.sh[828]: Tue 2023-05-23 22:10:18 UTC 747 0 0 SIGABRT journal /tmp/test-dump -
|
||||
[ 66.715907] testsuite-74.sh[828]: Tue 2023-05-23 22:10:19 UTC 763 0 0 SIGTRAP present /tmp/test-dump 53.5K
|
||||
[ 66.716565] testsuite-74.sh[828]: Tue 2023-05-23 22:10:20 UTC 776 0 0 SIGABRT present /tmp/test-dump 53.3K
|
||||
[ 66.717494] testsuite-74.sh[728]: + coredumpctl --directory=/var/log/journal
|
||||
[ 66.718188] testsuite-74.sh[830]: TIME PID UID GID SIG COREFILE EXE SIZE
|
||||
[ 66.882072] testsuite-74.sh[830]: Tue 2023-05-23 22:10:17 UTC 739 0 0 SIGTRAP journal /tmp/test-dump -
|
||||
[ 66.882642] testsuite-74.sh[830]: Tue 2023-05-23 22:10:18 UTC 747 0 0 SIGABRT journal /tmp/test-dump -
|
||||
[ 66.883450] testsuite-74.sh[830]: Tue 2023-05-23 22:10:19 UTC 763 0 0 SIGTRAP present /tmp/test-dump 53.5K
|
||||
[ 66.883944] testsuite-74.sh[830]: Tue 2023-05-23 22:10:20 UTC 776 0 0 SIGABRT present /tmp/test-dump 53.3K
|
||||
[ 66.885448] testsuite-74.sh[728]: + coredumpctl --file=/var/log/journal/2e1ed84be19a4e22adfc99ad849be1f6/system.journal
|
||||
[ 66.885989] testsuite-74.sh[728]: + at_exit
|
||||
[ 66.894162] coredumpctl[833]: No coredumps found.
|
||||
---
|
||||
|
||||
(cherry picked from commit 5c4e96c28c4a2193ba0dd459ea3366614f9b262f)
|
||||
|
||||
Related: RHEL-29430
|
||||
---
|
||||
test/units/testsuite-74.coredump.sh | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/test/units/testsuite-74.coredump.sh b/test/units/testsuite-74.coredump.sh
|
||||
index 0e5d050f45..d5039b70f4 100755
|
||||
--- a/test/units/testsuite-74.coredump.sh
|
||||
+++ b/test/units/testsuite-74.coredump.sh
|
||||
@@ -21,6 +21,9 @@ if systemd-detect-virt -cq; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
+# To make all coredump entries stored in system.journal.
|
||||
+journalctl --rotate
|
||||
+
|
||||
# Check that we're the ones to receive coredumps
|
||||
sysctl kernel.core_pattern | grep systemd-coredump
|
||||
|
@ -0,0 +1,77 @@
|
||||
From 803900bb830163c13539a70ea56d82d27b06f52b Mon Sep 17 00:00:00 2001
|
||||
From: Frantisek Sumsal <frantisek@sumsal.cz>
|
||||
Date: Fri, 2 Jun 2023 13:24:32 +0200
|
||||
Subject: [PATCH] test: sync with the fake binary before killing it
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
On faster machines we might be too fast and kill the fake binary during
|
||||
fork() which then makes kernel report a "wrong" binary in the coredump,
|
||||
e.g.:
|
||||
|
||||
[ 31.408078] testsuite-74.sh[548]: + /tmp/make-dump /tmp/test-dump SIGTRAP
|
||||
[ 31.409720] testsuite-74.sh[560]: + bin=/tmp/test-dump
|
||||
[ 31.409720] testsuite-74.sh[560]: + sig=SIGTRAP
|
||||
[ 31.409720] testsuite-74.sh[560]: + ulimit -c unlimited
|
||||
[ 31.409720] testsuite-74.sh[560]: + pid=561
|
||||
[ 31.409720] testsuite-74.sh[560]: + sleep 1
|
||||
[ 31.409720] testsuite-74.sh[560]: + kill -s SIGTRAP 561
|
||||
[ 31.409720] testsuite-74.sh[560]: + wait 561
|
||||
[ 31.491757] systemd[1]: Created slice system-systemd\x2dcoredump.slice.
|
||||
[ 31.524488] systemd[1]: Started systemd-coredump@0-563-0.service.
|
||||
[ 31.616372] systemd-coredump[564]: [🡕] Process 561 (make-dump) of user 0 dumped core.
|
||||
|
||||
Stack trace of thread 561:
|
||||
#0 0x00007ff86bb49af7 _Fork (libc.so.6 + 0xd4af7)
|
||||
#1 0x00007ff86bb4965f __libc_fork (libc.so.6 + 0xd465f)
|
||||
#2 0x000055e88011b0ad make_child (bash + 0x550ad)
|
||||
#3 0x000055e8800fd05f n/a (bash + 0x3705f)
|
||||
#4 0x000055e880100116 execute_command_internal (bash + 0x3a116)
|
||||
#5 0x000055e8801011f2 execute_command_internal (bash + 0x3b1f2)
|
||||
#6 0x000055e8801025b6 execute_command (bash + 0x3c5b6)
|
||||
#7 0x000055e8800f134b reader_loop (bash + 0x2b34b)
|
||||
#8 0x000055e8800e757d main (bash + 0x2157d)
|
||||
#9 0x00007ff86ba98850 n/a (libc.so.6 + 0x23850)
|
||||
#10 0x00007ff86ba9890a __libc_start_main (libc.so.6 + 0x2390a)
|
||||
#11 0x000055e8800e83b5 _start (bash + 0x223b5)
|
||||
ELF object binary architecture: AMD x86-64
|
||||
[ 31.666617] testsuite-74.sh[560]: /tmp/make-dump: line 12: 561 Trace/breakpoint trap (core dumped) "$bin" infinity
|
||||
...
|
||||
$ coredumpctl list --file system.journal
|
||||
TIME PID UID GID SIG COREFILE EXE SIZE
|
||||
Fri 2023-06-02 10:42:10 CEST 561 0 0 SIGTRAP journal /usr/bin/bash -
|
||||
Fri 2023-06-02 10:42:11 CEST 570 0 0 SIGABRT journal /tmp/test-dump -
|
||||
Fri 2023-06-02 10:42:12 CEST 582 0 0 SIGTRAP missing /tmp/test-dump -
|
||||
Fri 2023-06-02 10:42:13 CEST 593 0 0 SIGABRT missing /tmp/test-dump -
|
||||
|
||||
(cherry picked from commit 1326d2dd059132760b40acb7a715ecc9ff08bd35)
|
||||
|
||||
Related: RHEL-29430
|
||||
---
|
||||
test/units/testsuite-74.coredump.sh | 12 +++++++++++-
|
||||
1 file changed, 11 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/test/units/testsuite-74.coredump.sh b/test/units/testsuite-74.coredump.sh
|
||||
index d5039b70f4..d30fd73717 100755
|
||||
--- a/test/units/testsuite-74.coredump.sh
|
||||
+++ b/test/units/testsuite-74.coredump.sh
|
||||
@@ -42,7 +42,17 @@ sig="${2:?}"
|
||||
ulimit -c unlimited
|
||||
"$bin" infinity &
|
||||
pid=$!
|
||||
-sleep 1
|
||||
+# Sync with the "fake" binary, so we kill it once it's fully forked off,
|
||||
+# otherwise we might kill it during fork and kernel would then report
|
||||
+# "wrong" binary name (i.e. $MAKE_DUMP_SCRIPT instead of $CORE_TEST_BIN).
|
||||
+# In this case, wait until the "fake" binary (sleep in this case) enters
|
||||
+# the "interruptible sleep" state, at which point it should be ready
|
||||
+# to be sacrificed.
|
||||
+for _ in {0..9}; do
|
||||
+ read -ra self_stat <"/proc/$pid/stat"
|
||||
+ [[ "${self_stat[2]}" == S ]] && break
|
||||
+ sleep .5
|
||||
+done
|
||||
kill -s "$sig" "$pid"
|
||||
# This should always fail
|
||||
! wait "$pid"
|
@ -0,0 +1,112 @@
|
||||
From 623e09d910fffd6824d77203b8d9b016c0dd6208 Mon Sep 17 00:00:00 2001
|
||||
From: Frantisek Sumsal <frantisek@sumsal.cz>
|
||||
Date: Thu, 25 Apr 2024 19:50:10 +0200
|
||||
Subject: [PATCH] test: check coredump handling in containers & namespaces
|
||||
|
||||
This is partially based on upstream's 097e28736a, which tests coredump
|
||||
forwarding (that we don't have in RHEL 9). It also provides basic
|
||||
coverage for RHEL-29430 (generating stack traces for processes in
|
||||
containers without coredump fowarding).
|
||||
|
||||
rhel-only
|
||||
Related: RHEL-29430
|
||||
---
|
||||
test/test-functions | 2 +-
|
||||
test/units/testsuite-74.coredump.sh | 64 ++++++++++++++++++++++++++++-
|
||||
2 files changed, 64 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/test/test-functions b/test/test-functions
|
||||
index 1608644cbb..947f8589c5 100644
|
||||
--- a/test/test-functions
|
||||
+++ b/test/test-functions
|
||||
@@ -2619,7 +2619,7 @@ inst_binary() {
|
||||
# ls, stat - pulls in nss_systemd with certain options (like ls -l) when
|
||||
# nsswitch.conf uses [SUCCESS=merge] (like on Arch Linux)
|
||||
# tar - called by machinectl in TEST-25
|
||||
- if get_bool "$IS_BUILT_WITH_ASAN" && [[ "$bin" =~ /(chown|getent|login|ls|stat|su|tar|useradd|userdel)$ ]]; then
|
||||
+ if get_bool "$IS_BUILT_WITH_ASAN" && [[ "$bin" =~ /(chown|getent|login|id|ls|stat|su|tar|useradd|userdel)$ ]]; then
|
||||
wrap_binary=1
|
||||
fi
|
||||
|
||||
diff --git a/test/units/testsuite-74.coredump.sh b/test/units/testsuite-74.coredump.sh
|
||||
index d30fd73717..1093cad8a9 100755
|
||||
--- a/test/units/testsuite-74.coredump.sh
|
||||
+++ b/test/units/testsuite-74.coredump.sh
|
||||
@@ -74,6 +74,68 @@ rm -fv /run/systemd/coredump.conf.d/99-external.conf
|
||||
# Wait a bit for the coredumps to get processed
|
||||
timeout 30 bash -c "while [[ \$(coredumpctl list -q --no-legend $CORE_TEST_BIN | wc -l) -lt 4 ]]; do sleep 1; done"
|
||||
|
||||
+# RHEL9: following part is taken out of 097e28736aed9280dfac0f8e8096deca71bac813 but slightly tweaked, since
|
||||
+# in RHEL9 we don't have the support for coredump forwarding
|
||||
+CONTAINER="testsuite-74-container"
|
||||
+TESTUSER_UID="$(id -u testuser)"
|
||||
+TESTUSER_GID="$(id -g testuser)"
|
||||
+
|
||||
+mkdir -p "/var/lib/machines/$CONTAINER"
|
||||
+mkdir -p "/run/systemd/system/systemd-nspawn@$CONTAINER.service.d"
|
||||
+# Bind-mounting /etc into the container kinda defeats the purpose of --volatile=,
|
||||
+# but we need the ASan-related overrides scattered across /etc
|
||||
+cat > "/run/systemd/system/systemd-nspawn@$CONTAINER.service.d/override.conf" << EOF
|
||||
+[Service]
|
||||
+ExecStart=
|
||||
+ExecStart=systemd-nspawn --quiet --link-journal=try-guest --keep-unit --machine=%i --boot \
|
||||
+ --volatile=yes --directory=/ --bind-ro=/etc --inaccessible=/etc/machine-id
|
||||
+EOF
|
||||
+systemctl daemon-reload
|
||||
+
|
||||
+machinectl start "$CONTAINER"
|
||||
+timeout 60 bash -xec "until systemd-run -M '$CONTAINER' -q --wait --pipe true; do sleep .5; done"
|
||||
+machinectl copy-to "$CONTAINER" "$MAKE_DUMP_SCRIPT"
|
||||
+
|
||||
+run_namespaced_coredump_tests() {
|
||||
+ local TS
|
||||
+
|
||||
+ # Make a couple of coredumps in a full-fleged container
|
||||
+ TS="$(date +"%s.%N")"
|
||||
+ [[ "$(coredumpctl list --since="@$TS" -q --no-legend /usr/bin/sleep | wc -l)" -eq 0 ]]
|
||||
+ [[ "$(coredumpctl list --since="@$TS" -q --no-legend /usr/bin/sleep _UID="$TESTUSER_UID" | wc -l)" -eq 0 ]]
|
||||
+ systemd-run -M "testuser@$CONTAINER" --user -q --wait --pipe "$MAKE_DUMP_SCRIPT" "/usr/bin/sleep" "SIGABRT"
|
||||
+ systemd-run -M "$CONTAINER" -q --wait --pipe "$MAKE_DUMP_SCRIPT" "/usr/bin/sleep" "SIGTRAP"
|
||||
+ # Wait a bit for the coredumps to get processed
|
||||
+ timeout 30 bash -c "while [[ \$(coredumpctl list --since=@$TS -q --no-legend /usr/bin/sleep | wc -l) -ne 2 ]]; do sleep 1; done"
|
||||
+ coredumpctl list
|
||||
+ [[ "$(coredumpctl list --since="@$TS" -q --no-legend /usr/bin/sleep _UID="$TESTUSER_UID" _GID="$TESTUSER_GID" | wc -l)" -eq 1 ]]
|
||||
+
|
||||
+ # Simplified version of the above - not a full container, just a mount & pid namespace
|
||||
+ TS="$(date +"%s.%N")"
|
||||
+ unshare --mount --pid --fork --mount-proc /bin/bash -xec "$MAKE_DUMP_SCRIPT /usr/bin/sleep SIGABRT"
|
||||
+ timeout 30 bash -c "while [[ \$(coredumpctl list --since=@$TS -q --no-legend /usr/bin/sleep | wc -l) -ne 1 ]]; do sleep 1; done"
|
||||
+ TS="$(date +"%s.%N")"
|
||||
+ unshare --setuid="$TESTUSER_UID" --setgid="$TESTUSER_GID" --mount --pid --fork --mount-proc /bin/bash -xec "$MAKE_DUMP_SCRIPT /usr/bin/sleep SIGABRT"
|
||||
+ timeout 30 bash -c "while [[ \$(coredumpctl list --since=@$TS -q --no-legend /usr/bin/sleep _UID=$TESTUSER_UID _GID=$TESTUSER_GID | wc -l) -ne 1 ]]; do sleep 1; done"
|
||||
+}
|
||||
+
|
||||
+# First, run the tests with default systemd-coredumpd settings
|
||||
+run_namespaced_coredump_tests
|
||||
+
|
||||
+# And now with SYSTEMD_COREDUMP_ALLOW_NAMESPACE_CHANGE=1 (RHEL-only)
|
||||
+cat >/tmp/coredump-handler.sh <<EOF
|
||||
+#!/bin/bash
|
||||
+export SYSTEMD_COREDUMP_ALLOW_NAMESPACE_CHANGE=1
|
||||
+exec /usr/lib/systemd/systemd-coredump "\$@"
|
||||
+EOF
|
||||
+chmod +x /tmp/coredump-handler.sh
|
||||
+sysctl -w kernel.core_pattern="|/tmp/coredump-handler.sh %P %u %g %s %t %c %h"
|
||||
+run_namespaced_coredump_tests
|
||||
+
|
||||
+# Restore the original coredump handler
|
||||
+sysctl -p /usr/lib/sysctl.d/50-coredump.conf
|
||||
+sysctl kernel.core_pattern
|
||||
+
|
||||
coredumpctl
|
||||
SYSTEMD_LOG_LEVEL=debug coredumpctl
|
||||
coredumpctl --help
|
||||
@@ -89,7 +151,7 @@ coredumpctl --json=pretty | jq
|
||||
coredumpctl --json=off
|
||||
coredumpctl --root=/
|
||||
coredumpctl --directory=/var/log/journal
|
||||
-coredumpctl --file="/var/log/journal/$(</etc/machine-id)/system.journal"
|
||||
+coredumpctl --file="/var/log/journal/$(</etc/machine-id)"/*.journal
|
||||
coredumpctl --since=@0
|
||||
coredumpctl --since=yesterday --until=tomorrow
|
||||
# We should have a couple of externally stored coredumps
|
29
SOURCES/0732-ci-update-actions-upload-artifact-to-v4.patch
Normal file
29
SOURCES/0732-ci-update-actions-upload-artifact-to-v4.patch
Normal file
@ -0,0 +1,29 @@
|
||||
From ddf2ccf36bb804d666da37ce12d00123550d85f1 Mon Sep 17 00:00:00 2001
|
||||
From: Jan Macku <jamacku@redhat.com>
|
||||
Date: Thu, 25 Apr 2024 15:06:03 +0200
|
||||
Subject: [PATCH] ci: update actions/upload-artifact to v4
|
||||
|
||||
`v3` will be deprecated soon, so update to `v4`.
|
||||
|
||||
https://github.blog/changelog/2024-04-16-deprecation-notice-v3-of-the-artifact-actions/
|
||||
|
||||
rhel-only
|
||||
|
||||
Related: RHEL-30372
|
||||
---
|
||||
.github/workflows/gather-metadata.yml | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/.github/workflows/gather-metadata.yml b/.github/workflows/gather-metadata.yml
|
||||
index 635708a71f..59659d9bc5 100644
|
||||
--- a/.github/workflows/gather-metadata.yml
|
||||
+++ b/.github/workflows/gather-metadata.yml
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
uses: redhat-plumbers-in-action/gather-pull-request-metadata@v1
|
||||
|
||||
- name: Upload artifact with gathered metadata
|
||||
- uses: actions/upload-artifact@v3
|
||||
+ uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pr-metadata
|
||||
path: ${{ steps.Metadata.outputs.metadata-file }}
|
@ -0,0 +1,33 @@
|
||||
From da0298596af24d1da92eb748b0a56065a9c041d9 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Cristian=20Rodr=C3=ADguez?= <crodriguez@owncloud.com>
|
||||
Date: Fri, 11 Nov 2022 15:28:51 +0000
|
||||
Subject: [PATCH] journal-remote: code is of type enum
|
||||
MHD_RequestTerminationCode
|
||||
|
||||
Fixes gcc 13 -Wenum-int-mismatch which are enabled by default.
|
||||
|
||||
(cherry picked from commit aa70dd624bff6280ab6f2871f62d313bdb1e1bcc)
|
||||
|
||||
Related: RHEL-30372
|
||||
---
|
||||
src/journal-remote/microhttpd-util.h | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/journal-remote/microhttpd-util.h b/src/journal-remote/microhttpd-util.h
|
||||
index 7e7d1b56b1..df18335469 100644
|
||||
--- a/src/journal-remote/microhttpd-util.h
|
||||
+++ b/src/journal-remote/microhttpd-util.h
|
||||
@@ -64,11 +64,11 @@ void microhttpd_logger(void *arg, const char *fmt, va_list ap) _printf_(2, 0);
|
||||
|
||||
int mhd_respondf(struct MHD_Connection *connection,
|
||||
int error,
|
||||
- unsigned code,
|
||||
+ enum MHD_RequestTerminationCode code,
|
||||
const char *format, ...) _printf_(4,5);
|
||||
|
||||
int mhd_respond(struct MHD_Connection *connection,
|
||||
- unsigned code,
|
||||
+ enum MHD_RequestTerminationCode code,
|
||||
const char *message);
|
||||
|
||||
int mhd_respond_oom(struct MHD_Connection *connection);
|
@ -0,0 +1,30 @@
|
||||
From cc1a9f1a9a74dd8f5491a3a0fd9734fbca731378 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Cristian=20Rodr=C3=ADguez?= <crodriguez@owncloud.com>
|
||||
Date: Fri, 11 Nov 2022 15:31:18 +0000
|
||||
Subject: [PATCH] resolve: dns_server_feature_level_*_string type is
|
||||
DnsServerFeatureLevel
|
||||
|
||||
gcc 13 -Wenum-int-mismatch reminds us that enum != int
|
||||
|
||||
(cherry picked from commit e14afe31c3e8380496dc85b57103b2f648bc7d43)
|
||||
|
||||
Related: RHEL-30372
|
||||
---
|
||||
src/resolve/resolved-dns-server.h | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h
|
||||
index be9efb0a79..f939b534c3 100644
|
||||
--- a/src/resolve/resolved-dns-server.h
|
||||
+++ b/src/resolve/resolved-dns-server.h
|
||||
@@ -44,8 +44,8 @@ typedef enum DnsServerFeatureLevel {
|
||||
#define DNS_SERVER_FEATURE_LEVEL_IS_DNSSEC(x) ((x) >= DNS_SERVER_FEATURE_LEVEL_DO)
|
||||
#define DNS_SERVER_FEATURE_LEVEL_IS_UDP(x) IN_SET(x, DNS_SERVER_FEATURE_LEVEL_UDP, DNS_SERVER_FEATURE_LEVEL_EDNS0, DNS_SERVER_FEATURE_LEVEL_DO)
|
||||
|
||||
-const char* dns_server_feature_level_to_string(int i) _const_;
|
||||
-int dns_server_feature_level_from_string(const char *s) _pure_;
|
||||
+const char* dns_server_feature_level_to_string(DnsServerFeatureLevel i) _const_;
|
||||
+DnsServerFeatureLevel dns_server_feature_level_from_string(const char *s) _pure_;
|
||||
|
||||
struct DnsServer {
|
||||
Manager *manager;
|
@ -0,0 +1,36 @@
|
||||
From 9f0967eb61b1889c97da705abaf0b0e905d117f3 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Cristian=20Rodr=C3=ADguez?= <crodriguez@owncloud.com>
|
||||
Date: Fri, 11 Nov 2022 15:34:32 +0000
|
||||
Subject: [PATCH] shared|install: Use InstallChangeType consistently
|
||||
|
||||
gcc 13 -Wenum-int-mismatch, enabled by default, reminds us enum ! = int
|
||||
|
||||
(cherry picked from commit 9264db1a0ac6034ab5b40ef3f5914d8dc7d77aba)
|
||||
|
||||
Related: RHEL-30372
|
||||
---
|
||||
src/shared/install.h | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/shared/install.h b/src/shared/install.h
|
||||
index 9bb412ba06..0abc73897e 100644
|
||||
--- a/src/shared/install.h
|
||||
+++ b/src/shared/install.h
|
||||
@@ -197,7 +197,7 @@ int unit_file_exists(LookupScope scope, const LookupPaths *paths, const char *na
|
||||
int unit_file_get_list(LookupScope scope, const char *root_dir, Hashmap *h, char **states, char **patterns);
|
||||
Hashmap* unit_file_list_free(Hashmap *h);
|
||||
|
||||
-InstallChangeType install_changes_add(InstallChange **changes, size_t *n_changes, int type, const char *path, const char *source);
|
||||
+InstallChangeType install_changes_add(InstallChange **changes, size_t *n_changes, InstallChangeType type, const char *path, const char *source);
|
||||
void install_changes_free(InstallChange *changes, size_t n_changes);
|
||||
void install_changes_dump(int r, const char *verb, const InstallChange *changes, size_t n_changes, bool quiet);
|
||||
|
||||
@@ -224,7 +224,7 @@ UnitFileState unit_file_state_from_string(const char *s) _pure_;
|
||||
/* from_string conversion is unreliable because of the overlap between -EPERM and -1 for error. */
|
||||
|
||||
const char *install_change_type_to_string(InstallChangeType t) _const_;
|
||||
-int install_change_type_from_string(const char *s) _pure_;
|
||||
+InstallChangeType install_change_type_from_string(const char *s) _pure_;
|
||||
|
||||
const char *unit_file_preset_mode_to_string(UnitFilePresetMode m) _const_;
|
||||
UnitFilePresetMode unit_file_preset_mode_from_string(const char *s) _pure_;
|
@ -0,0 +1,78 @@
|
||||
From 54c44b19c1018400c38da8f8be597536d14e7afa Mon Sep 17 00:00:00 2001
|
||||
From: Frantisek Sumsal <frantisek@sumsal.cz>
|
||||
Date: Thu, 18 Apr 2024 22:39:31 +0200
|
||||
Subject: [PATCH] test: temporarily disable coredumps in testsuite-17.03.sh
|
||||
|
||||
Since f387005b54 we started generating coredumps by default (up to
|
||||
certain size). This change has one unintentional effect on our test
|
||||
suite - if a sanitized binary (udevd worker here) crashes and ASan is
|
||||
instructed to allow core dumping (via disable_coredump=0 and
|
||||
use_madv_dontdump=1), we try to dump a relatively big core file (~80
|
||||
MiB), and since the test suite configures systemd-coredumpd to dump the
|
||||
cores into the journal, we try to append it to the journal message about
|
||||
the crash. However, journal complains that the message with the coredump
|
||||
is too big so the crash report is not written, and we end up with
|
||||
coredumpctl not showing the crash, which the test in this case uses to
|
||||
monitor if the udevd worker's job timed out:
|
||||
|
||||
[ 17.873463] systemd-udevd[1617]: null: Worker [1625] processing SEQNUM=3588 is taking a long time
|
||||
[ 17.876823] systemd-udevd[1625]: null: Spawned process '/bin/sleep 60' [1626] is taking longer than 3s to complete
|
||||
...
|
||||
[ 24.223459] systemd-udevd[1617]: null: Worker [1625] processing SEQNUM=3588 killed
|
||||
[ 24.265141] systemd[1]: Created slice system-systemd\x2dcoredump.slice.
|
||||
[ 24.284960] systemd[1]: Started systemd-coredump@0-1707-0.service.
|
||||
[ 27.545120] systemd-journald[1225]: Failed to write entry to /var/log/journal/6da99a97048e4f08abd4ddabcf92bbdd/system.journal (51 items, 89252196 bytes) despite vacuuming, ignoring: Argument list too long
|
||||
[ 27.551759] systemd-coredump[1709]: ==1709==LeakSanitizer has encountered a fatal error.
|
||||
[ 27.551759] systemd-coredump[1709]: ==1709==HINT: For debugging, try setting environment variable LSAN_OPTIONS=verbosity=1:log_threads=1
|
||||
[ 27.551759] systemd-coredump[1709]: ==1709==HINT: LeakSanitizer does not work under ptrace (strace, gdb, etc)
|
||||
|
||||
The upstream version of this test doesn't suffer from this because it
|
||||
was recently-ish rewritten to not check for the crash event
|
||||
(5592608bdcb, but we're missing some udevd prerequisites for that to
|
||||
work in RHEL9), and we also started instructing ASan to allow coredumps
|
||||
after that change, so the issue was never encountered there in the first
|
||||
place.
|
||||
|
||||
Since we don't really care about the actual coredump in this case, let's
|
||||
just temporarily override the core rlimit to 0 for the udevd process.
|
||||
|
||||
Related: RHEL-30372
|
||||
rhel-only
|
||||
---
|
||||
test/units/testsuite-17.03.sh | 10 +++++++++-
|
||||
1 file changed, 9 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/test/units/testsuite-17.03.sh b/test/units/testsuite-17.03.sh
|
||||
index 318afdcb5a..8fa58e2f08 100755
|
||||
--- a/test/units/testsuite-17.03.sh
|
||||
+++ b/test/units/testsuite-17.03.sh
|
||||
@@ -17,9 +17,16 @@ event_timeout=10
|
||||
timeout_signal=SIGABRT
|
||||
EOF
|
||||
|
||||
+ mkdir -p /run/systemd/system/systemd-udevd.service.d/
|
||||
+ cat >/run/systemd/system/systemd-udevd.service.d/99-disable-coredumps.conf <<EOF
|
||||
+[Service]
|
||||
+LimitCORE=0
|
||||
+EOF
|
||||
+ systemctl daemon-reload
|
||||
systemctl restart systemd-udevd.service
|
||||
}
|
||||
|
||||
+# shellcheck disable=SC2317
|
||||
teardown() {
|
||||
set +e
|
||||
|
||||
@@ -27,10 +34,11 @@ teardown() {
|
||||
kill "$KILL_PID"
|
||||
fi
|
||||
|
||||
- rm -rf "$TMPDIR"
|
||||
+ rm -rf "$TMPDIR" /run/systemd/system/systemd-udevd.service.d
|
||||
|
||||
mv -f /etc/udev/udev.conf.bckp /etc/udev/udev.conf
|
||||
rm -f "$test_rule"
|
||||
+ systemctl daemon-reload
|
||||
systemctl restart systemd-udevd.service
|
||||
}
|
||||
|
80
SOURCES/0737-ci-update-manpage-deployment-workflow.patch
Normal file
80
SOURCES/0737-ci-update-manpage-deployment-workflow.patch
Normal file
@ -0,0 +1,80 @@
|
||||
From 365a74eef2463a011fbe7413ab5479b4fbd60650 Mon Sep 17 00:00:00 2001
|
||||
From: Jan Macku <jamacku@redhat.com>
|
||||
Date: Thu, 25 Apr 2024 15:46:35 +0200
|
||||
Subject: [PATCH] ci: update manpage deployment workflow
|
||||
|
||||
rhel-only
|
||||
|
||||
Related: RHEL-30372
|
||||
---
|
||||
.github/workflows/deploy-man-pages.yml | 52 +-------------------------
|
||||
1 file changed, 2 insertions(+), 50 deletions(-)
|
||||
|
||||
diff --git a/.github/workflows/deploy-man-pages.yml b/.github/workflows/deploy-man-pages.yml
|
||||
index 08c3d6e322..9739228a87 100644
|
||||
--- a/.github/workflows/deploy-man-pages.yml
|
||||
+++ b/.github/workflows/deploy-man-pages.yml
|
||||
@@ -37,61 +37,13 @@ jobs:
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
- RELEASE="$(lsb_release -cs)"
|
||||
- sudo bash -c "echo 'deb-src http://archive.ubuntu.com/ubuntu/ $RELEASE main restricted universe multiverse' >>/etc/apt/sources.list"
|
||||
- sudo add-apt-repository -y ppa:upstream-systemd-ci/systemd-ci
|
||||
+ sudo add-apt-repository -y --no-update --enable-source
|
||||
sudo apt-get -y update
|
||||
sudo apt-get -y build-dep systemd
|
||||
- sudo apt-get install -y \
|
||||
- cryptsetup-bin \
|
||||
- expect \
|
||||
- fdisk \
|
||||
- gettext \
|
||||
- iputils-ping \
|
||||
- isc-dhcp-client \
|
||||
- itstool \
|
||||
- kbd \
|
||||
- libblkid-dev \
|
||||
- libbpf-dev \
|
||||
- libc6-dev-i386 \
|
||||
- libcap-dev \
|
||||
- libcurl4-gnutls-dev \
|
||||
- libfdisk-dev \
|
||||
- libfido2-dev \
|
||||
- libgpg-error-dev \
|
||||
- liblz4-dev \
|
||||
- liblzma-dev \
|
||||
- libmicrohttpd-dev \
|
||||
- libmount-dev \
|
||||
- libp11-kit-dev \
|
||||
- libpwquality-dev \
|
||||
- libqrencode-dev \
|
||||
- libssl-dev \
|
||||
- libtss2-dev \
|
||||
- libxkbcommon-dev \
|
||||
- libxtables-dev \
|
||||
- libzstd-dev \
|
||||
- meson \
|
||||
- mold \
|
||||
- mount \
|
||||
- net-tools \
|
||||
- ninja-build \
|
||||
- perl \
|
||||
- python3-evdev \
|
||||
- python3-jinja2 \
|
||||
- python3-lxml \
|
||||
- python3-pip \
|
||||
- python3-pyparsing \
|
||||
- python3-setuptools \
|
||||
- quota \
|
||||
- strace \
|
||||
- unifont \
|
||||
- util-linux \
|
||||
- zstd \
|
||||
|
||||
- name: Build HTML man pages
|
||||
run: |
|
||||
- meson build
|
||||
+ meson setup build
|
||||
ninja -C build man/html
|
||||
|
||||
- name: Setup Pages
|
38
SOURCES/0738-bootspec-fix-null-dereference-read.patch
Normal file
38
SOURCES/0738-bootspec-fix-null-dereference-read.patch
Normal file
@ -0,0 +1,38 @@
|
||||
From 41d2e7fbb87a99e80e9be1873775c79879f8b821 Mon Sep 17 00:00:00 2001
|
||||
From: Yu Watanabe <watanabe.yu+github@gmail.com>
|
||||
Date: Fri, 2 Dec 2022 14:30:22 +0900
|
||||
Subject: [PATCH] bootspec: fix null-dereference-read
|
||||
|
||||
Fixes [oss-fuzz#53578](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=53578).
|
||||
Fixes #25450.
|
||||
|
||||
(cherry picked from commit 46dc071985ff487f5ccf20808531168a6add73d3)
|
||||
|
||||
Resolves: RHEL-36284
|
||||
---
|
||||
src/shared/bootspec.c | 2 ++
|
||||
...lusterfuzz-testcase-minimized-fuzz-bootspec-5731869371269120 | 1 +
|
||||
2 files changed, 3 insertions(+)
|
||||
create mode 100644 test/fuzz/fuzz-bootspec/clusterfuzz-testcase-minimized-fuzz-bootspec-5731869371269120
|
||||
|
||||
diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c
|
||||
index 61e20c40a8..7fe8845429 100644
|
||||
--- a/src/shared/bootspec.c
|
||||
+++ b/src/shared/bootspec.c
|
||||
@@ -996,6 +996,8 @@ static int boot_config_find(const BootConfig *config, const char *id) {
|
||||
if (id[0] == '@') {
|
||||
if (!strcaseeq(id, "@saved"))
|
||||
return -1;
|
||||
+ if (!config->entry_selected)
|
||||
+ return -1;
|
||||
id = config->entry_selected;
|
||||
}
|
||||
|
||||
diff --git a/test/fuzz/fuzz-bootspec/clusterfuzz-testcase-minimized-fuzz-bootspec-5731869371269120 b/test/fuzz/fuzz-bootspec/clusterfuzz-testcase-minimized-fuzz-bootspec-5731869371269120
|
||||
new file mode 100644
|
||||
index 0000000000..8804abd094
|
||||
--- /dev/null
|
||||
+++ b/test/fuzz/fuzz-bootspec/clusterfuzz-testcase-minimized-fuzz-bootspec-5731869371269120
|
||||
@@ -0,0 +1 @@
|
||||
+{"config":"default @saved","loader":[""]}
|
||||
\ No newline at end of file
|
@ -0,0 +1,40 @@
|
||||
From 0947147008c9b2cb56b40616fccccf64a6534f07 Mon Sep 17 00:00:00 2001
|
||||
From: Frantisek Sumsal <frantisek@sumsal.cz>
|
||||
Date: Tue, 17 Jan 2023 12:14:13 +0100
|
||||
Subject: [PATCH] units: don't install pcrphase-related units without gnu-efi
|
||||
|
||||
since we don't have systemd-pcrphase built anyway, which breaks the tests:
|
||||
|
||||
...
|
||||
I: Attempting to install /usr/lib/systemd/systemd-networkd-wait-online (based on unit file reference)
|
||||
I: Attempting to install /usr/lib/systemd/systemd-network-generator (based on unit file reference)
|
||||
I: Attempting to install /usr/lib/systemd/systemd-oomd (based on unit file reference)
|
||||
I: Attempting to install /usr/lib/systemd/systemd-pcrphase (based on unit file reference)
|
||||
W: Failed to install '/usr/lib/systemd/systemd-pcrphase'
|
||||
make: *** [Makefile:4: setup] Error 1
|
||||
make: Leaving directory '/root/systemd/test/TEST-01-BASIC'
|
||||
|
||||
Follow-up to 04959faa632272a8fc9cdac3121b2e4af721c1b6.
|
||||
|
||||
(cherry picked from commit 0eb635ef4bc11792cd4ef384ae252a2c7fd4122a)
|
||||
|
||||
Related: RHEL-33384
|
||||
---
|
||||
units/meson.build | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/units/meson.build b/units/meson.build
|
||||
index cfc96a9111..39e6a9bb65 100644
|
||||
--- a/units/meson.build
|
||||
+++ b/units/meson.build
|
||||
@@ -264,8 +264,8 @@ in_units = [
|
||||
'sysinit.target.wants/'],
|
||||
['systemd-pcrphase.service', 'HAVE_GNU_EFI HAVE_OPENSSL HAVE_TPM2',
|
||||
'sysinit.target.wants/'],
|
||||
- ['systemd-pcrfs-root.service', ''],
|
||||
- ['systemd-pcrfs@.service', ''],
|
||||
+ ['systemd-pcrfs-root.service', 'HAVE_GNU_EFI HAVE_OPENSSL HAVE_TPM2'],
|
||||
+ ['systemd-pcrfs@.service', 'HAVE_GNU_EFI HAVE_OPENSSL HAVE_TPM2'],
|
||||
['systemd-growfs-root.service', ''],
|
||||
['systemd-growfs@.service', ''],
|
||||
['systemd-pcrmachine.service', 'HAVE_GNU_EFI HAVE_OPENSSL HAVE_TPM2',
|
44
SOURCES/0740-kernel-install-fix-uki-copy-deinstall.patch
Normal file
44
SOURCES/0740-kernel-install-fix-uki-copy-deinstall.patch
Normal file
@ -0,0 +1,44 @@
|
||||
From 4ab2df57c79a923fba74b2cf48fd56c6a0756413 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Mon, 18 Mar 2024 17:04:22 +0100
|
||||
Subject: [PATCH] kernel-install: fix uki-copy deinstall
|
||||
|
||||
For "kernel-install remove ..." only the kernel version is passed, not
|
||||
the kernel image. So auto-detecting KERNEL_INSTALL_IMAGE_TYPE and
|
||||
setting KERNEL_INSTALL_LAYOUT does not work for uninstall.
|
||||
|
||||
The 90-uki-copy.install plugin must consider this and *not* exit early
|
||||
for the "remove" command, otherwise $BOOT_ROOT will be filled with stale
|
||||
kernel images.
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
|
||||
(cherry picked from commit 3037616d8ed68f3263746e3c6399d4a05242068b)
|
||||
|
||||
Resolves: RHEL-36505
|
||||
---
|
||||
src/kernel-install/90-uki-copy.install | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/kernel-install/90-uki-copy.install b/src/kernel-install/90-uki-copy.install
|
||||
index c66c09719c..d443c4b401 100755
|
||||
--- a/src/kernel-install/90-uki-copy.install
|
||||
+++ b/src/kernel-install/90-uki-copy.install
|
||||
@@ -26,8 +26,6 @@ KERNEL_VERSION="${2:?}"
|
||||
ENTRY_DIR_ABS="$3"
|
||||
KERNEL_IMAGE="$4"
|
||||
|
||||
-[ "$KERNEL_INSTALL_LAYOUT" = "uki" ] || exit 0
|
||||
-
|
||||
ENTRY_TOKEN="$KERNEL_INSTALL_ENTRY_TOKEN"
|
||||
BOOT_ROOT="$KERNEL_INSTALL_BOOT_ROOT"
|
||||
|
||||
@@ -48,6 +46,8 @@ case "$COMMAND" in
|
||||
;;
|
||||
esac
|
||||
|
||||
+[ "$KERNEL_INSTALL_LAYOUT" = "uki" ] || exit 0
|
||||
+
|
||||
if ! [ -d "$UKI_DIR" ]; then
|
||||
[ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "creating $UKI_DIR"
|
||||
mkdir -p "$UKI_DIR"
|
27
SOURCES/0741-ci-packit-explicitly-clone-c9s-branch.patch
Normal file
27
SOURCES/0741-ci-packit-explicitly-clone-c9s-branch.patch
Normal file
@ -0,0 +1,27 @@
|
||||
From 16eace42619860cbcfedca8c93e4ea20bfb0f98b Mon Sep 17 00:00:00 2001
|
||||
From: Jan Macku <jamacku@redhat.com>
|
||||
Date: Fri, 17 May 2024 14:02:07 +0200
|
||||
Subject: [PATCH] ci(packit): explicitly clone `c9s` branch
|
||||
|
||||
Once default branch is changed to `c10s` the current configuration could stop working.
|
||||
|
||||
rhel-only
|
||||
|
||||
Related: RHEL-30372
|
||||
---
|
||||
.packit.yml | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/.packit.yml b/.packit.yml
|
||||
index 35938f3586..9697a0df84 100644
|
||||
--- a/.packit.yml
|
||||
+++ b/.packit.yml
|
||||
@@ -18,7 +18,7 @@ srpm_build_deps: []
|
||||
actions:
|
||||
post-upstream-clone:
|
||||
# Use the CentOS Stream specfile
|
||||
- - "git clone https://gitlab.com/redhat/centos-stream/rpms/systemd.git .packit_rpm --depth=1"
|
||||
+ - "git clone -b c9s https://gitlab.com/redhat/centos-stream/rpms/systemd.git .packit_rpm --depth=1"
|
||||
# Drop the "sources" file so rebase-helper doesn't think we're a dist-git
|
||||
- "rm -fv .packit_rpm/sources"
|
||||
# Drop all patches, since they're already included in the tarball
|
@ -0,0 +1,25 @@
|
||||
From 43373d851c9f6222f4523b9db7006fbfe14c3d70 Mon Sep 17 00:00:00 2001
|
||||
From: Michal Sekletar <msekleta@redhat.com>
|
||||
Date: Thu, 23 May 2024 18:07:45 +0200
|
||||
Subject: [PATCH] ci(src-git): add RHEL-9.1 and RHEL-9.1.z to allowed versions
|
||||
|
||||
rhel-only
|
||||
|
||||
Related: RHEL-30372
|
||||
---
|
||||
.github/tracker-validator.yml | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/.github/tracker-validator.yml b/.github/tracker-validator.yml
|
||||
index 31ef28f6ea..21cbedd8b0 100644
|
||||
--- a/.github/tracker-validator.yml
|
||||
+++ b/.github/tracker-validator.yml
|
||||
@@ -8,6 +8,8 @@ products:
|
||||
- CentOS Stream 9
|
||||
- rhel-9.0.0
|
||||
- rhel-9.0.0.z
|
||||
+ - rhel-9.1.0
|
||||
+ - rhel-9.1.0.z
|
||||
- rhel-9.2.0
|
||||
- rhel-9.2.0.z
|
||||
- rhel-9.3.0
|
30
SOURCES/0743-libsystemd-link-with-z-nodelete.patch
Normal file
30
SOURCES/0743-libsystemd-link-with-z-nodelete.patch
Normal file
@ -0,0 +1,30 @@
|
||||
From aa18f6b2b2cad6977f39e1e323705e2b11a7829c Mon Sep 17 00:00:00 2001
|
||||
From: Michal Sekletar <msekleta@redhat.com>
|
||||
Date: Thu, 23 May 2024 17:35:51 +0200
|
||||
Subject: [PATCH] libsystemd: link with '-z nodelete'
|
||||
|
||||
We want to avoid reinitialization of our global variables with static
|
||||
storage duration in case we get dlopened multiple times by the same
|
||||
application. This will avoid potential resource leaks that could have
|
||||
happened otherwise (e.g. leaking journal socket fd).
|
||||
|
||||
(cherry picked from commit 9d8533b7152daf792356c601516b57c6412d3e52)
|
||||
|
||||
Resolves: RHEL-6589
|
||||
---
|
||||
meson.build | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/meson.build b/meson.build
|
||||
index 843d823e3e..274e43ba9e 100644
|
||||
--- a/meson.build
|
||||
+++ b/meson.build
|
||||
@@ -2004,6 +2004,8 @@ libsystemd = shared_library(
|
||||
version : libsystemd_version,
|
||||
include_directories : libsystemd_includes,
|
||||
link_args : ['-shared',
|
||||
+ # Make sure our library is never deleted from memory, so that our open logging fds don't leak on dlopen/dlclose cycles.
|
||||
+ '-z', 'nodelete',
|
||||
'-Wl,--version-script=' + libsystemd_sym_path],
|
||||
link_with : [libbasic,
|
||||
libbasic_gcrypt,
|
@ -0,0 +1,54 @@
|
||||
From d26e1ba4539a3a33224ca1019b9e6cf5590744f5 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
|
||||
Date: Fri, 23 Jun 2023 11:10:42 -0600
|
||||
Subject: [PATCH] basic/utf8: make utf8_encoded_to_unichar() return length of
|
||||
the codepoint
|
||||
|
||||
(cherry picked from commit 9579e9a5308573c3c9c82f1978456cc71f68760c)
|
||||
|
||||
Related: RHEL-31219
|
||||
---
|
||||
src/basic/utf8.c | 10 ++++------
|
||||
1 file changed, 4 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/src/basic/utf8.c b/src/basic/utf8.c
|
||||
index 2532fcf81a..9d9e76904e 100644
|
||||
--- a/src/basic/utf8.c
|
||||
+++ b/src/basic/utf8.c
|
||||
@@ -90,7 +90,7 @@ int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar) {
|
||||
switch (len) {
|
||||
case 1:
|
||||
*ret_unichar = (char32_t)str[0];
|
||||
- return 0;
|
||||
+ return 1;
|
||||
case 2:
|
||||
unichar = str[0] & 0x1f;
|
||||
break;
|
||||
@@ -119,15 +119,14 @@ int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar) {
|
||||
}
|
||||
|
||||
*ret_unichar = unichar;
|
||||
-
|
||||
- return 0;
|
||||
+ return len;
|
||||
}
|
||||
|
||||
bool utf8_is_printable_newline(const char* str, size_t length, bool allow_newline) {
|
||||
assert(str);
|
||||
|
||||
for (const char *p = str; length > 0;) {
|
||||
- int encoded_len, r;
|
||||
+ int encoded_len;
|
||||
char32_t val;
|
||||
|
||||
encoded_len = utf8_encoded_valid_unichar(p, length);
|
||||
@@ -135,8 +134,7 @@ bool utf8_is_printable_newline(const char* str, size_t length, bool allow_newlin
|
||||
return false;
|
||||
assert(encoded_len > 0 && (size_t) encoded_len <= length);
|
||||
|
||||
- r = utf8_encoded_to_unichar(p, &val);
|
||||
- if (r < 0 ||
|
||||
+ if (utf8_encoded_to_unichar(p, &val) < 0 ||
|
||||
unichar_is_control(val) ||
|
||||
(!allow_newline && val == '\n'))
|
||||
return false;
|
@ -0,0 +1,67 @@
|
||||
From 0fc377b76f10eb283d4de76b8fe7c083b95f70b7 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
|
||||
Date: Fri, 23 Jun 2023 17:24:11 -0600
|
||||
Subject: [PATCH] test-gunicode: add new test to show that unichar_iswide() is
|
||||
borked
|
||||
|
||||
I discovered this while looking at the tests with wide characters in the next
|
||||
patch. It's something to fix, but not directly relevant to the issue of
|
||||
skipping ANSI in ellipsization. We will generate output that is wider than
|
||||
expected in some cases, but wide characters are used very rarely so this isn't
|
||||
such a big problem.
|
||||
|
||||
(cherry picked from commit d9c72e54190db2a0845d1558b5beb734e9f629ff)
|
||||
|
||||
Related: RHEL-31219
|
||||
---
|
||||
src/test/meson.build | 2 ++
|
||||
src/test/test-gunicode.c | 27 +++++++++++++++++++++++++++
|
||||
2 files changed, 29 insertions(+)
|
||||
create mode 100644 src/test/test-gunicode.c
|
||||
|
||||
diff --git a/src/test/meson.build b/src/test/meson.build
|
||||
index 5430e72ab5..1d61dc343f 100644
|
||||
--- a/src/test/meson.build
|
||||
+++ b/src/test/meson.build
|
||||
@@ -469,6 +469,8 @@ tests += [
|
||||
|
||||
[files('test-gpt.c')],
|
||||
|
||||
+ [files('test-gunicode.c')],
|
||||
+
|
||||
[files('test-log.c')],
|
||||
|
||||
[files('test-ipcrm.c'),
|
||||
diff --git a/src/test/test-gunicode.c b/src/test/test-gunicode.c
|
||||
new file mode 100644
|
||||
index 0000000000..1836cdc04a
|
||||
--- /dev/null
|
||||
+++ b/src/test/test-gunicode.c
|
||||
@@ -0,0 +1,27 @@
|
||||
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
+
|
||||
+#include "gunicode.h"
|
||||
+#include "tests.h"
|
||||
+#include "utf8.h"
|
||||
+
|
||||
+TEST(unichar_iswide) {
|
||||
+ char32_t c;
|
||||
+ int r;
|
||||
+
|
||||
+ /* FIXME: the cats are wide, but we get this wrong */
|
||||
+ for (const char *narrow = "abX_…ąęµ!" "😼😿🙀😸😻"; *narrow; narrow += r) {
|
||||
+ r = utf8_encoded_to_unichar(narrow, &c);
|
||||
+ bool w = unichar_iswide(c);
|
||||
+ assert_se(r > 0);
|
||||
+ assert_se(!w);
|
||||
+ }
|
||||
+
|
||||
+ for (const char *wide = "🐱/¥"; *wide; wide += r) {
|
||||
+ r = utf8_encoded_to_unichar(wide, &c);
|
||||
+ bool w = unichar_iswide(c);
|
||||
+ assert_se(r > 0);
|
||||
+ assert_se(w);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+DEFINE_TEST_MAIN(LOG_INFO);
|
@ -0,0 +1,320 @@
|
||||
From cec4cc86486d3e212b5e919595feb39c6cee4c2c Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
|
||||
Date: Fri, 23 Jun 2023 18:40:14 -0600
|
||||
Subject: [PATCH] string-util: pass ANSI sequences through unchanged
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Cutting off in the middle may leave the terminal in a bad state, breaking
|
||||
further output. But we don't know what a given ANSI sequence does, e.g.
|
||||
ANSI_NORMAL should not be skipped. But it is also nice to keep various
|
||||
sequences intact, so that if we had part of the string in blue, and we cut out
|
||||
the beginning of the blue part, we still want to keep the remainder in color.
|
||||
So let's just pass them through, stripping out the characters that take up
|
||||
actual space.
|
||||
|
||||
Also, use memcpy_safe as we may end up copying zero bytes when ellipsizing at
|
||||
the start/end of a string.
|
||||
|
||||
Fixes: #24502
|
||||
|
||||
This also fixes an ugliness where we would ellipsize string with ANSI
|
||||
sequences too much, leading to output that was narrower on screen than the
|
||||
requested length:
|
||||
|
||||
Starting AAAAAAAAAAAAAAAAAAAAA.service
|
||||
Starting BBBBBBBBBBBBBBBBBBBBB.service
|
||||
Starting LONG…ER.service
|
||||
|
||||
Co-authored-by: Jan Janssen <medhefgo@web.de>
|
||||
|
||||
(cherry picked from commit cb558ab222f0dbda3afd985c2190f35693963ffa)
|
||||
|
||||
Resolves: RHEL-31219
|
||||
---
|
||||
src/basic/string-util.c | 163 ++++++++++++++++++++++++++++++--------
|
||||
src/test/test-ellipsize.c | 41 ++++++++++
|
||||
2 files changed, 172 insertions(+), 32 deletions(-)
|
||||
|
||||
diff --git a/src/basic/string-util.c b/src/basic/string-util.c
|
||||
index 17d35fe1a4..fe6e9e94ad 100644
|
||||
--- a/src/basic/string-util.c
|
||||
+++ b/src/basic/string-util.c
|
||||
@@ -288,6 +288,62 @@ static int write_ellipsis(char *buf, bool unicode) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
+static size_t ansi_sequence_length(const char *s, size_t len) {
|
||||
+ assert(s);
|
||||
+
|
||||
+ if (len < 2)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (s[0] != 0x1B) /* ASCII 27, aka ESC, aka Ctrl-[ */
|
||||
+ return 0; /* Not the start of a sequence */
|
||||
+
|
||||
+ if (s[1] == 0x5B) { /* [, start of CSI sequence */
|
||||
+ size_t i = 2;
|
||||
+
|
||||
+ if (i == len)
|
||||
+ return 0;
|
||||
+
|
||||
+ while (s[i] >= 0x30 && s[i] <= 0x3F) /* Parameter bytes */
|
||||
+ if (++i == len)
|
||||
+ return 0;
|
||||
+ while (s[i] >= 0x20 && s[i] <= 0x2F) /* Intermediate bytes */
|
||||
+ if (++i == len)
|
||||
+ return 0;
|
||||
+ if (s[i] >= 0x40 && s[i] <= 0x7E) /* Final byte */
|
||||
+ return i + 1;
|
||||
+ return 0; /* Bad sequence */
|
||||
+
|
||||
+ } else if (s[1] >= 0x40 && s[1] <= 0x5F) /* other non-CSI Fe sequence */
|
||||
+ return 2;
|
||||
+
|
||||
+ return 0; /* Bad escape? */
|
||||
+}
|
||||
+
|
||||
+static bool string_has_ansi_sequence(const char *s, size_t len) {
|
||||
+ const char *t = s;
|
||||
+
|
||||
+ while ((t = memchr(s, 0x1B, len - (t - s))))
|
||||
+ if (ansi_sequence_length(t, len - (t - s)) > 0)
|
||||
+ return true;
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
+static size_t previous_ansi_sequence(const char *s, size_t length, const char **ret_where) {
|
||||
+ /* Locate the previous ANSI sequence and save its start in *ret_where and return length. */
|
||||
+
|
||||
+ for (size_t i = length - 2; i > 0; i--) { /* -2 because at least two bytes are needed */
|
||||
+ size_t slen = ansi_sequence_length(s + (i - 1), length - (i - 1));
|
||||
+ if (slen == 0)
|
||||
+ continue;
|
||||
+
|
||||
+ *ret_where = s + (i - 1);
|
||||
+ return slen;
|
||||
+ }
|
||||
+
|
||||
+ *ret_where = NULL;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
|
||||
size_t x, need_space, suffix_len;
|
||||
char *t;
|
||||
@@ -347,7 +403,6 @@ static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_le
|
||||
char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
|
||||
size_t x, k, len, len2;
|
||||
const char *i, *j;
|
||||
- char *e;
|
||||
int r;
|
||||
|
||||
/* Note that 'old_length' refers to bytes in the string, while 'new_length' refers to character cells taken up
|
||||
@@ -371,73 +426,117 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne
|
||||
if (new_length == 0)
|
||||
return strdup("");
|
||||
|
||||
- /* If no multibyte characters use ascii_ellipsize_mem for speed */
|
||||
- if (ascii_is_valid_n(s, old_length))
|
||||
+ bool has_ansi_seq = string_has_ansi_sequence(s, old_length);
|
||||
+
|
||||
+ /* If no multibyte characters or ANSI sequences, use ascii_ellipsize_mem for speed */
|
||||
+ if (!has_ansi_seq && ascii_is_valid_n(s, old_length))
|
||||
return ascii_ellipsize_mem(s, old_length, new_length, percent);
|
||||
|
||||
- x = ((new_length - 1) * percent) / 100;
|
||||
+ x = (new_length - 1) * percent / 100;
|
||||
assert(x <= new_length - 1);
|
||||
|
||||
k = 0;
|
||||
- for (i = s; i < s + old_length; i = utf8_next_char(i)) {
|
||||
- char32_t c;
|
||||
- int w;
|
||||
+ for (i = s; i < s + old_length; ) {
|
||||
+ size_t slen = has_ansi_seq ? ansi_sequence_length(i, old_length - (i - s)) : 0;
|
||||
+ if (slen > 0) {
|
||||
+ i += slen;
|
||||
+ continue; /* ANSI sequences don't take up any space in output */
|
||||
+ }
|
||||
|
||||
+ char32_t c;
|
||||
r = utf8_encoded_to_unichar(i, &c);
|
||||
if (r < 0)
|
||||
return NULL;
|
||||
|
||||
- w = unichar_iswide(c) ? 2 : 1;
|
||||
- if (k + w <= x)
|
||||
- k += w;
|
||||
- else
|
||||
+ int w = unichar_iswide(c) ? 2 : 1;
|
||||
+ if (k + w > x)
|
||||
break;
|
||||
+
|
||||
+ k += w;
|
||||
+ i += r;
|
||||
}
|
||||
|
||||
- for (j = s + old_length; j > i; ) {
|
||||
+ const char *ansi_start = s + old_length;
|
||||
+ size_t ansi_len = 0;
|
||||
+
|
||||
+ for (const char *t = j = s + old_length; t > i && k < new_length; ) {
|
||||
char32_t c;
|
||||
int w;
|
||||
- const char *jj;
|
||||
+ const char *tt;
|
||||
+
|
||||
+ if (has_ansi_seq && ansi_start >= t)
|
||||
+ /* Figure out the previous ANSI sequence, if any */
|
||||
+ ansi_len = previous_ansi_sequence(s, t - s, &ansi_start);
|
||||
|
||||
- jj = utf8_prev_char(j);
|
||||
- r = utf8_encoded_to_unichar(jj, &c);
|
||||
+ /* If the sequence extends all the way to the current position, skip it. */
|
||||
+ if (has_ansi_seq && ansi_len > 0 && ansi_start + ansi_len == t) {
|
||||
+ t = ansi_start;
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ tt = utf8_prev_char(t);
|
||||
+ r = utf8_encoded_to_unichar(tt, &c);
|
||||
if (r < 0)
|
||||
return NULL;
|
||||
|
||||
w = unichar_iswide(c) ? 2 : 1;
|
||||
- if (k + w <= new_length) {
|
||||
- k += w;
|
||||
- j = jj;
|
||||
- } else
|
||||
+ if (k + w > new_length)
|
||||
break;
|
||||
+
|
||||
+ k += w;
|
||||
+ j = t = tt; /* j should always point to the first "real" character */
|
||||
}
|
||||
- assert(i <= j);
|
||||
|
||||
- /* we don't actually need to ellipsize */
|
||||
- if (i == j)
|
||||
+ /* We don't actually need to ellipsize */
|
||||
+ if (i >= j)
|
||||
return memdup_suffix0(s, old_length);
|
||||
|
||||
- /* make space for ellipsis, if possible */
|
||||
- if (j < s + old_length)
|
||||
- j = utf8_next_char(j);
|
||||
- else if (i > s)
|
||||
- i = utf8_prev_char(i);
|
||||
+ if (k >= new_length) {
|
||||
+ /* Make space for ellipsis, if required and possible. We know that the edge character is not
|
||||
+ * part of an ANSI sequence (because then we'd skip it). If the last character we looked at
|
||||
+ * was wide, we don't need to make space. */
|
||||
+ if (j < s + old_length)
|
||||
+ j = utf8_next_char(j);
|
||||
+ else if (i > s)
|
||||
+ i = utf8_prev_char(i);
|
||||
+ }
|
||||
|
||||
len = i - s;
|
||||
len2 = s + old_length - j;
|
||||
- e = new(char, len + 3 + len2 + 1);
|
||||
+
|
||||
+ /* If we have ANSI, allow the same length as the source string + ellipsis. It'd be too involved to
|
||||
+ * figure out what exact space is needed. Strings with ANSI sequences are most likely to be fairly
|
||||
+ * short anyway. */
|
||||
+ size_t alloc_len = has_ansi_seq ? old_length + 3 + 1 : len + 3 + len2 + 1;
|
||||
+
|
||||
+ char *e = new(char, alloc_len);
|
||||
if (!e)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
- printf("old_length=%zu new_length=%zu x=%zu len=%u len2=%u k=%u\n",
|
||||
+ printf("old_length=%zu new_length=%zu x=%zu len=%zu len2=%zu k=%zu\n",
|
||||
old_length, new_length, x, len, len2, k);
|
||||
*/
|
||||
|
||||
- memcpy(e, s, len);
|
||||
+ memcpy_safe(e, s, len);
|
||||
write_ellipsis(e + len, true);
|
||||
- memcpy(e + len + 3, j, len2);
|
||||
- *(e + len + 3 + len2) = '\0';
|
||||
+
|
||||
+ char *dst = e + len + 3;
|
||||
+
|
||||
+ if (has_ansi_seq)
|
||||
+ /* Copy over any ANSI sequences in full */
|
||||
+ for (const char *p = s + len; p < j; ) {
|
||||
+ size_t slen = ansi_sequence_length(p, j - p);
|
||||
+ if (slen > 0) {
|
||||
+ memcpy(dst, p, slen);
|
||||
+ dst += slen;
|
||||
+ p += slen;
|
||||
+ } else
|
||||
+ p = utf8_next_char(p);
|
||||
+ }
|
||||
+
|
||||
+ memcpy_safe(dst, j, len2);
|
||||
+ dst[len2] = '\0';
|
||||
|
||||
return e;
|
||||
}
|
||||
diff --git a/src/test/test-ellipsize.c b/src/test/test-ellipsize.c
|
||||
index 7317193363..8f7e17bfe9 100644
|
||||
--- a/src/test/test-ellipsize.c
|
||||
+++ b/src/test/test-ellipsize.c
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "def.h"
|
||||
+#include "escape.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "terminal-util.h"
|
||||
@@ -116,4 +117,44 @@ TEST(ellipsize) {
|
||||
test_ellipsize_one("shórt");
|
||||
}
|
||||
|
||||
+TEST(ellipsize_ansi) {
|
||||
+ const char *s = ANSI_HIGHLIGHT_YELLOW_UNDERLINE "yęllow"
|
||||
+ ANSI_HIGHLIGHT_GREY_UNDERLINE "grěy"
|
||||
+ ANSI_HIGHLIGHT_BLUE_UNDERLINE "blue"
|
||||
+ ANSI_NORMAL "nórmął";
|
||||
+ size_t len = strlen(s);
|
||||
+
|
||||
+ for (unsigned percent = 0; percent <= 100; percent += 15)
|
||||
+ for (ssize_t x = 21; x >= 0; x--) {
|
||||
+ _cleanup_free_ char *t = ellipsize_mem(s, len, x, percent);
|
||||
+ printf("%02zd: \"%s\"\n", x, t);
|
||||
+ assert_se(utf8_is_valid(t));
|
||||
+
|
||||
+ if (DEBUG_LOGGING) {
|
||||
+ _cleanup_free_ char *e = cescape(t);
|
||||
+ printf(" : \"%s\"\n", e);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+TEST(ellipsize_ansi_cats) {
|
||||
+ _cleanup_free_ char *e, *f, *g, *h;
|
||||
+
|
||||
+ /* Make sure we don't cut off in the middle of an ANSI escape sequence. */
|
||||
+
|
||||
+ e = ellipsize("01" ANSI_NORMAL "23", 4, 0);
|
||||
+ puts(e);
|
||||
+ assert_se(streq(e, "01" ANSI_NORMAL "23"));
|
||||
+ f = ellipsize("ab" ANSI_NORMAL "cd", 4, 90);
|
||||
+ puts(f);
|
||||
+ assert_se(streq(f, "ab" ANSI_NORMAL "cd"));
|
||||
+
|
||||
+ g = ellipsize("🐱🐱" ANSI_NORMAL "🐱🐱" ANSI_NORMAL, 5, 0);
|
||||
+ puts(g);
|
||||
+ assert_se(streq(g, "…" ANSI_NORMAL "🐱🐱" ANSI_NORMAL));
|
||||
+ h = ellipsize("🐱🐱" ANSI_NORMAL "🐱🐱" ANSI_NORMAL, 5, 90);
|
||||
+ puts(h);
|
||||
+ assert_se(streq(h, "🐱…" ANSI_NORMAL "🐱" ANSI_NORMAL));
|
||||
+}
|
||||
+
|
||||
DEFINE_TEST_MAIN(LOG_INFO);
|
@ -0,0 +1,75 @@
|
||||
From eac6ff660b32656d2a39bdc13d729e7eb0288596 Mon Sep 17 00:00:00 2001
|
||||
From: Luca Boccassi <bluca@debian.org>
|
||||
Date: Wed, 15 Feb 2023 00:44:01 +0000
|
||||
Subject: [PATCH] cryptsetup: do not assert when unsealing token without salt
|
||||
|
||||
Salt was added in v253. We are not checking whether it was actually found
|
||||
(non-zero size), so when an old tpm+pin enrollment is opened things go boom.
|
||||
For good measure, check both the buffer and the size in both places.
|
||||
|
||||
Assertion 'saltlen > 0' failed at src/shared/tpm2-util.c:2490, function tpm2_util_pbkdf2_hmac_sha256(). Aborting.
|
||||
|
||||
(cherry picked from commit 504d0acf61c8472bc93c2a927e858074873b2eaf)
|
||||
|
||||
Resolves: RHEL-38864
|
||||
---
|
||||
src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c | 3 ++-
|
||||
src/cryptsetup/cryptsetup-tpm2.c | 4 +++-
|
||||
src/shared/tpm2-util.c | 1 +
|
||||
3 files changed, 6 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c
|
||||
index 630a2d8d3e..e353e947aa 100644
|
||||
--- a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c
|
||||
+++ b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c
|
||||
@@ -40,6 +40,7 @@ int acquire_luks2_key(
|
||||
_cleanup_(erase_and_freep) char *b64_salted_pin = NULL;
|
||||
int r;
|
||||
|
||||
+ assert(salt || salt_size == 0);
|
||||
assert(ret_decrypted_key);
|
||||
assert(ret_decrypted_key_size);
|
||||
|
||||
@@ -60,7 +61,7 @@ int acquire_luks2_key(
|
||||
if ((flags & TPM2_FLAGS_USE_PIN) && salt && !pin)
|
||||
return -ENOANO;
|
||||
|
||||
- if (pin) {
|
||||
+ if (pin && salt_size > 0) {
|
||||
uint8_t salted_pin[SHA256_DIGEST_SIZE] = {};
|
||||
CLEANUP_ERASE(salted_pin);
|
||||
r = tpm2_util_pbkdf2_hmac_sha256(pin, strlen(pin), salt, salt_size, salted_pin);
|
||||
diff --git a/src/cryptsetup/cryptsetup-tpm2.c b/src/cryptsetup/cryptsetup-tpm2.c
|
||||
index c049b8a313..036f3d3a00 100644
|
||||
--- a/src/cryptsetup/cryptsetup-tpm2.c
|
||||
+++ b/src/cryptsetup/cryptsetup-tpm2.c
|
||||
@@ -88,6 +88,8 @@ int acquire_tpm2_key(
|
||||
const void *blob;
|
||||
int r;
|
||||
|
||||
+ assert(salt || salt_size == 0);
|
||||
+
|
||||
if (!device) {
|
||||
r = tpm2_find_device_auto(&auto_device);
|
||||
if (r == -ENODEV)
|
||||
@@ -165,7 +167,7 @@ int acquire_tpm2_key(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
- if (salt) {
|
||||
+ if (salt_size > 0) {
|
||||
uint8_t salted_pin[SHA256_DIGEST_SIZE] = {};
|
||||
CLEANUP_ERASE(salted_pin);
|
||||
|
||||
diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c
|
||||
index 4e382f691e..1d2d4ddda4 100644
|
||||
--- a/src/shared/tpm2-util.c
|
||||
+++ b/src/shared/tpm2-util.c
|
||||
@@ -6041,6 +6041,7 @@ int tpm2_util_pbkdf2_hmac_sha256(const void *pass,
|
||||
*/
|
||||
static const uint8_t block_cnt[] = { 0, 0, 0, 1 };
|
||||
|
||||
+ assert (salt);
|
||||
assert (saltlen > 0);
|
||||
assert (saltlen <= (SIZE_MAX - sizeof(block_cnt)));
|
||||
assert (passlen > 0);
|
@ -0,0 +1,29 @@
|
||||
From 661e3758451dc504eeb176194293c87f238d55dd Mon Sep 17 00:00:00 2001
|
||||
From: Yu Watanabe <watanabe.yu+github@gmail.com>
|
||||
Date: Fri, 17 Feb 2023 08:24:54 +0900
|
||||
Subject: [PATCH] cryptsetup: check the existence of salt by salt_size > 0
|
||||
|
||||
Follow-up for 504d0acf61c8472bc93c2a927e858074873b2eaf.
|
||||
|
||||
The function may be called with non-NULL salt and salt_size == 0.
|
||||
|
||||
(cherry picked from commit 8c2264abb9c16bc2933f95be299f15ee66c21181)
|
||||
|
||||
Related: RHEL-38864
|
||||
---
|
||||
src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c
|
||||
index e353e947aa..5230a84025 100644
|
||||
--- a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c
|
||||
+++ b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c
|
||||
@@ -58,7 +58,7 @@ int acquire_luks2_key(
|
||||
return -ENOANO;
|
||||
|
||||
/* If we're using a PIN, and the luks header has a salt, it better have a pin too */
|
||||
- if ((flags & TPM2_FLAGS_USE_PIN) && salt && !pin)
|
||||
+ if ((flags & TPM2_FLAGS_USE_PIN) && salt_size > 0 && !pin)
|
||||
return -ENOANO;
|
||||
|
||||
if (pin && salt_size > 0) {
|
@ -0,0 +1,83 @@
|
||||
From 3e65e8111f7cc30ac38901dced3ed0defbd90206 Mon Sep 17 00:00:00 2001
|
||||
From: Mike Yuan <me@yhndnzj.com>
|
||||
Date: Sat, 17 Feb 2024 03:03:50 +0800
|
||||
Subject: [PATCH] core/mount: if umount(8) fails but mount disappeared, assume
|
||||
success
|
||||
|
||||
Fixes #31337
|
||||
|
||||
(cherry picked from commit 8e94bb62a5c1309c56c57e0a505aae13a2ac5f4f)
|
||||
|
||||
Resolves: RHEL-13159
|
||||
---
|
||||
src/core/mount.c | 20 ++++++++++++--------
|
||||
1 file changed, 12 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/src/core/mount.c b/src/core/mount.c
|
||||
index a46ac804d8..cfe3f40302 100644
|
||||
--- a/src/core/mount.c
|
||||
+++ b/src/core/mount.c
|
||||
@@ -1439,7 +1439,8 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
||||
|
||||
if (IN_SET(m->state, MOUNT_REMOUNTING, MOUNT_REMOUNTING_SIGKILL, MOUNT_REMOUNTING_SIGTERM))
|
||||
mount_set_reload_result(m, f);
|
||||
- else if (m->result == MOUNT_SUCCESS)
|
||||
+ else if (m->result == MOUNT_SUCCESS && !IN_SET(m->state, MOUNT_MOUNTING, MOUNT_UNMOUNTING))
|
||||
+ /* MOUNT_MOUNTING and MOUNT_UNMOUNTING states need to be patched, see below. */
|
||||
m->result = f;
|
||||
|
||||
if (m->control_command) {
|
||||
@@ -1462,11 +1463,11 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
||||
switch (m->state) {
|
||||
|
||||
case MOUNT_MOUNTING:
|
||||
- /* Our mount point has not appeared in mountinfo. Something went wrong. */
|
||||
+ /* Our mount point has not appeared in mountinfo. Something went wrong. */
|
||||
|
||||
if (f == MOUNT_SUCCESS) {
|
||||
- /* Either /bin/mount has an unexpected definition of success,
|
||||
- * or someone raced us and we lost. */
|
||||
+ /* Either /bin/mount has an unexpected definition of success, or someone raced us
|
||||
+ * and we lost. */
|
||||
log_unit_warning(UNIT(m), "Mount process finished, but there is no mount.");
|
||||
f = MOUNT_FAILURE_PROTOCOL;
|
||||
}
|
||||
@@ -1484,9 +1485,7 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
||||
break;
|
||||
|
||||
case MOUNT_UNMOUNTING:
|
||||
-
|
||||
if (f == MOUNT_SUCCESS && m->from_proc_self_mountinfo) {
|
||||
-
|
||||
/* Still a mount point? If so, let's try again. Most likely there were multiple mount points
|
||||
* stacked on top of each other. We might exceed the timeout specified by the user overall,
|
||||
* but we will stop as soon as any one umount times out. */
|
||||
@@ -1499,13 +1498,18 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
||||
log_unit_warning(u, "Mount still present after %u attempts to unmount, giving up.", m->n_retry_umount);
|
||||
mount_enter_mounted(m, f);
|
||||
}
|
||||
+ } else if (f == MOUNT_FAILURE_EXIT_CODE && !m->from_proc_self_mountinfo) {
|
||||
+ /* Hmm, umount process spawned by us failed, but the mount disappeared anyway?
|
||||
+ * Maybe someone else is trying to unmount at the same time. */
|
||||
+ log_unit_notice(u, "Mount disappeared even though umount process failed, continuing.");
|
||||
+ mount_enter_dead(m, MOUNT_SUCCESS);
|
||||
} else
|
||||
mount_enter_dead_or_mounted(m, f);
|
||||
|
||||
break;
|
||||
|
||||
- case MOUNT_UNMOUNTING_SIGKILL:
|
||||
case MOUNT_UNMOUNTING_SIGTERM:
|
||||
+ case MOUNT_UNMOUNTING_SIGKILL:
|
||||
mount_enter_dead_or_mounted(m, f);
|
||||
break;
|
||||
|
||||
@@ -2040,7 +2044,7 @@ static int mount_process_proc_self_mountinfo(Manager *m) {
|
||||
* then remove it because of an internal error. E.g., fuse.sshfs seems
|
||||
* to do that when the connection fails. See #17617. To handle such the
|
||||
* case, let's once set the state back to mounting. Then, the unit can
|
||||
- * correctly enter the failed state later in mount_sigchld(). */
|
||||
+ * correctly enter the failed state later in mount_sigchld_event(). */
|
||||
mount_set_state(mount, MOUNT_MOUNTING);
|
||||
break;
|
||||
|
@ -0,0 +1,31 @@
|
||||
From 82231e1834a5936216c666e3488bccb8b82de258 Mon Sep 17 00:00:00 2001
|
||||
From: Daan De Meyer <daan.j.demeyer@gmail.com>
|
||||
Date: Mon, 24 Apr 2023 20:55:15 +0200
|
||||
Subject: [PATCH] Drop log level of header limits log message
|
||||
|
||||
Especially when using in-memory logging, these are too noisy so
|
||||
let's drop them back to debug level.
|
||||
|
||||
(cherry picked from commit afc47ee2af456d12670df862457dcc7f6b864d79)
|
||||
|
||||
Related: RHEL-33890
|
||||
---
|
||||
src/journal/journald-server.c | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
|
||||
index cbcf1e9d9e..56f2ea8583 100644
|
||||
--- a/src/journal/journald-server.c
|
||||
+++ b/src/journal/journald-server.c
|
||||
@@ -848,8 +848,9 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, size_t n
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
- if (journal_file_rotate_suggested(f->file, s->max_file_usec, LOG_INFO)) {
|
||||
- log_info("%s: Journal header limits reached or header out-of-date, rotating.", f->file->path);
|
||||
+ if (journal_file_rotate_suggested(f->file, s->max_file_usec, LOG_DEBUG)) {
|
||||
+ log_debug("%s: Journal header limits reached or header out-of-date, rotating.",
|
||||
+ f->file->path);
|
||||
rotate = true;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user