mirror of
https://github.com/gentoo-mirror/gentoo.git
synced 2026-08-25 07:08:13 -07:00
125 lines
6.6 KiB
Diff
125 lines
6.6 KiB
Diff
https://bugs.gentoo.org/977839
|
|
https://github.com/systemd/systemd/issues/42689
|
|
https://github.com/systemd/systemd/pull/42705
|
|
|
|
From f12879e13f002b9b7a62d9ddba8b258a05b945ef Mon Sep 17 00:00:00 2001
|
|
From: tunaichao <tunaichao@uniontech.com>
|
|
Date: Tue, 23 Jun 2026 15:45:49 +0800
|
|
Subject: [PATCH] core: derive restrict-fsaccess initramfs_s_dev offset from
|
|
skeleton
|
|
|
|
Building with -Dbpf=enabled -Dbpf_compiler=gcc (GCC's BPF backend) fails on
|
|
the static assertions in bpf-restrict-fsaccess.c, introduced in 68fe7fa4d6:
|
|
|
|
error: static assertion failed:
|
|
"offsetof(struct restrict_fsaccess_bss, initramfs_s_dev) ==
|
|
offsetof(typeof_field(struct restrict_fsaccess_bpf, bss[0]), initramfs_s_dev)"
|
|
|
|
The hand-written struct restrict_fsaccess_bss lists the BPF .bss globals in
|
|
source declaration order and asserts that its layout matches the skeleton's
|
|
generated bss struct. bpftool gen skeleton emits that struct from the BTF
|
|
.bss DATASEC, whose member order reflects the physical order the compiler
|
|
placed the variables, not the source order. clang preserves declaration
|
|
order, so the asserts pass; gcc reorders .bss globals, so initramfs_s_dev no
|
|
longer sits at offset 0 and the asserts fail.
|
|
|
|
This is more than a build break: restrict_fsaccess_clear_initramfs_trust()
|
|
clears initramfs_s_dev by mmap()ing the .bss map and storing 0 at a hardcoded
|
|
offset 0. Under the gcc layout that store would clobber the wrong global,
|
|
silently leaving the initramfs trust window open after switch_root instead of
|
|
closing it. The asserts were correctly catching this.
|
|
|
|
Fix it by deriving the offset from the generated skeleton instead of a mirror
|
|
struct: drop struct restrict_fsaccess_bss and the four field-order
|
|
assert_cc()s, take INITRAMFS_S_DEV_OFF from the skeleton's bss struct
|
|
(offsetof(typeof_field(struct restrict_fsaccess_bpf, bss[0]),
|
|
initramfs_s_dev)), and store at p + INITRAMFS_S_DEV_OFF. The offset is a
|
|
compile-time constant, so clang (offset 0) is unchanged while gcc tracks the
|
|
real layout. A retained assert_cc() documents the 4-byte alignment the
|
|
single-store atomicity relies on.
|
|
|
|
Fixes: #42689
|
|
---
|
|
src/core/bpf-restrict-fsaccess.c | 33 +++++++++++++++-----------------
|
|
src/core/bpf-restrict-fsaccess.h | 10 ----------
|
|
2 files changed, 15 insertions(+), 28 deletions(-)
|
|
|
|
diff --git a/src/core/bpf-restrict-fsaccess.c b/src/core/bpf-restrict-fsaccess.c
|
|
index 4e0af5596af29..f0e49199f46df 100644
|
|
--- a/src/core/bpf-restrict-fsaccess.c
|
|
+++ b/src/core/bpf-restrict-fsaccess.c
|
|
@@ -48,19 +48,17 @@ static struct restrict_fsaccess_bpf *restrict_fsaccess_bpf_free(struct restrict_
|
|
|
|
DEFINE_TRIVIAL_CLEANUP_FUNC(struct restrict_fsaccess_bpf *, restrict_fsaccess_bpf_free);
|
|
|
|
-/* Verify that restrict_fsaccess_bss matches the skeleton's .bss layout. The sizeof
|
|
- * check catches field additions/removals; the offsetof checks catch field
|
|
- * reordering. Field order in restrict_fsaccess_bss must match the BPF global
|
|
- * declaration order in restrict-fsaccess.bpf.c — this is what bpftool uses for the
|
|
- * generated struct. The read-modify-write in restrict_fsaccess_clear_initramfs_trust()
|
|
- * depends on this layout. */
|
|
-assert_cc(sizeof(struct restrict_fsaccess_bss) == sizeof_field(struct restrict_fsaccess_bpf, bss[0]));
|
|
-assert_cc(offsetof(struct restrict_fsaccess_bss, initramfs_s_dev) ==
|
|
- offsetof(typeof_field(struct restrict_fsaccess_bpf, bss[0]), initramfs_s_dev));
|
|
-assert_cc(offsetof(struct restrict_fsaccess_bss, protected_map_id_verity) ==
|
|
- offsetof(typeof_field(struct restrict_fsaccess_bpf, bss[0]), protected_map_id_verity));
|
|
-assert_cc(offsetof(struct restrict_fsaccess_bss, protected_map_id_bss) ==
|
|
- offsetof(typeof_field(struct restrict_fsaccess_bpf, bss[0]), protected_map_id_bss));
|
|
+/* Offset of initramfs_s_dev within the BPF program's .bss section, taken from
|
|
+ * the generated skeleton so it matches whichever BPF compiler (clang or gcc)
|
|
+ * emitted the object. clang and gcc do not necessarily place .bss globals in
|
|
+ * source declaration order, so the offset must come from the skeleton rather
|
|
+ * than a hand-maintained mirror struct. restrict_fsaccess_clear_initramfs_trust()
|
|
+ * mmaps the .bss map and clears this field via a single store. */
|
|
+#define INITRAMFS_S_DEV_OFF \
|
|
+ offsetof(typeof_field(struct restrict_fsaccess_bpf, bss[0]), initramfs_s_dev)
|
|
+/* The single aligned 32-bit store in restrict_fsaccess_clear_initramfs_trust()
|
|
+ * is only atomic if the field is 4-byte aligned. */
|
|
+assert_cc(INITRAMFS_S_DEV_OFF % sizeof(uint32_t) == 0);
|
|
|
|
/* Build the skeleton links array indexed by the link enum.
|
|
* For BDEV_SETINTEGRITY, use whichever variant was loaded (full or compat).
|
|
@@ -226,16 +224,15 @@ static int restrict_fsaccess_clear_initramfs_trust(int bss_map_fd) {
|
|
void *p;
|
|
|
|
assert(bss_map_fd >= 0);
|
|
- assert_cc(offsetof(struct restrict_fsaccess_bss, initramfs_s_dev) == 0);
|
|
|
|
p = mmap(NULL, page_size(), PROT_READ | PROT_WRITE, MAP_SHARED, bss_map_fd, 0);
|
|
if (p == MAP_FAILED)
|
|
return log_error_errno(errno, "bpf-restrict-fsaccess: Failed to mmap .bss map: %m");
|
|
|
|
- /* initramfs_s_dev is at offset 0 in the .bss layout. Single aligned
|
|
- * 32-bit store is atomic — BPF programs see either the old or new value,
|
|
- * no torn reads possible. Guard globals are untouched. */
|
|
- *(uint32_t *) p = 0;
|
|
+ /* Single aligned 32-bit store at INITRAMFS_S_DEV_OFF is atomic — BPF
|
|
+ * programs see either the old or new value, no torn reads possible.
|
|
+ * Guard globals are untouched. */
|
|
+ *(uint32_t *) ((uint8_t *) p + INITRAMFS_S_DEV_OFF) = 0;
|
|
|
|
/* munmap failure here is harmless: the clear above already landed in
|
|
* the kernel, and the mapping is discarded by exec anyway. */
|
|
diff --git a/src/core/bpf-restrict-fsaccess.h b/src/core/bpf-restrict-fsaccess.h
|
|
index a39f602539af3..c6b4892695ef9 100644
|
|
--- a/src/core/bpf-restrict-fsaccess.h
|
|
+++ b/src/core/bpf-restrict-fsaccess.h
|
|
@@ -39,16 +39,6 @@ enum {
|
|
#define STAT_DEV_TO_KERNEL(dev) \
|
|
((uint32_t)major(dev) << 20 | (uint32_t)minor(dev))
|
|
|
|
-/* Mirrors the BPF program's .bss section layout for read-modify-write via
|
|
- * bpf_map_lookup_elem/bpf_map_update_elem on the serialized .bss map FD. */
|
|
-struct restrict_fsaccess_bss {
|
|
- uint32_t initramfs_s_dev; /* kernel dev_t encoding: (major << 20) | minor */
|
|
- uint32_t protected_map_id_verity;
|
|
- uint32_t protected_map_id_bss;
|
|
- uint32_t protected_prog_ids[_RESTRICT_FILESYSTEM_ACCESS_LINK_MAX];
|
|
- uint32_t protected_link_ids[_RESTRICT_FILESYSTEM_ACCESS_LINK_MAX];
|
|
-};
|
|
-
|
|
extern const char* const restrict_fsaccess_link_names[_RESTRICT_FILESYSTEM_ACCESS_LINK_MAX];
|
|
|
|
bool dm_verity_require_signatures(void);
|
|
|