From 2793d6acf063ae8fe506a1684e5a24ce83267e6d Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Wed, 6 Aug 2025 12:40:24 +0100 Subject: [PATCH 1/7] meson: fix compatibility with Python 3.7 [8/2759] Generating src/basic/filesystem-sets.c with a custom command (wrapped by meson to capture output) FAILED: src/basic/filesystem-sets.c /mnt/work/.local/bin/meson --internal exe --capture src/basic/filesystem-sets.c -- /mnt/work/src/systemd/upstream-fork/main/src/basic/filesystem-sets.py fs-type-to-string filesystem-sets fs-in-group --- stderr --- Traceback (most recent call last): File "/mnt/work/src/systemd/upstream-fork/main/src/basic/filesystem-sets.py", line 372, in generate_fs_in_group() File "/mnt/work/src/systemd/upstream-fork/main/src/basic/filesystem-sets.py", line 311, in generate_fs_in_group start=[]))) TypeError: sum() takes no keyword arguments --- src/basic/filesystem-sets.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/basic/filesystem-sets.py b/src/basic/filesystem-sets.py index 6520f45b89..7fc2b7a515 100755 --- a/src/basic/filesystem-sets.py +++ b/src/basic/filesystem-sets.py @@ -307,8 +307,7 @@ def generate_fs_in_group(): print(' switch (fs_group) {') for name, _, *filesystems in FILESYSTEM_SETS: - magics = sorted(set(sum((NAME_TO_MAGIC[fs] for fs in filesystems), - start=[]))) + magics = sorted(set(sum((NAME_TO_MAGIC[fs] for fs in filesystems), []))) enum = 'FILESYSTEM_SET_' + name[1:].upper().replace('-', '_') print(f' case {enum}:') opts = '\n || '.join(f'F_TYPE_EQUAL(st->f_type, {magic})' @@ -355,7 +354,7 @@ def magic_defines(): def check(): kernel_magics = set(magic_defines()) - our_magics = set(sum(NAME_TO_MAGIC.values(), start=[])) + our_magics = set(sum(NAME_TO_MAGIC.values(), [])) extra = kernel_magics - our_magics if extra: sys.exit(f"kernel knows additional filesystem magics: {', '.join(sorted(extra))}") From 3ec74b96b7e82877c03a7d0fb4c81a296b923013 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Wed, 6 Aug 2025 12:41:01 +0100 Subject: [PATCH 2/7] seccomp: fix build with glibc < 2.39 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ../src/shared/seccomp-util.c: In function ‘seccomp_restrict_sxid’: ../src/shared/seccomp-util.c:2228:25: error: ‘__NR_fchmodat2’ undeclared (first use in this function); did you mean ‘fchmodat2’? 2228 | __NR_fchmodat2, | ^~~~~~~~~~~~~~ | fchmodat2 The override/sys/syscalls.h needs to be included before the seccomp headers, otherwise the internal seccomp preprocessor machinery will not see the local definitions, so the local ifdef will be true but the seccomp own definitions will be empty --- src/shared/seccomp-util.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index 53d18dada5..f5bd64f8d3 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -1,5 +1,9 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* This needs to be included before the seccomp headers, otherwise missing syscalls will be defined in this + * file and pass the ifdef, but they won't be defined in the seccomp headers so things like + * SCMP_SYS(fchmodat2) will resolve as empty and fail the build with older glibc/libseccomp. */ +#include #include #include #include From 7108a882b34789be203cc6a9a3f7722f1929f21f Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Wed, 6 Aug 2025 12:58:20 +0100 Subject: [PATCH 3/7] network: fix build with libbpf < 0.7 bpf_loop() and bpf_strncmp(), used by sysctl-monitor, were introduced in libbpf 0.7, so skip the module if using an older version Follow-up for 6d9ef22acdeac4b429efb75164341233955484af --- meson.build | 2 ++ src/network/bpf/sysctl-monitor/meson.build | 2 +- src/network/meson.build | 2 +- src/network/networkd-manager.c | 2 +- src/network/networkd-manager.h | 4 ++-- src/network/networkd-sysctl.c | 2 +- src/network/networkd-sysctl.h | 2 +- 7 files changed, 9 insertions(+), 7 deletions(-) diff --git a/meson.build b/meson.build index c416bb4b60..f3d0a4b515 100644 --- a/meson.build +++ b/meson.build @@ -1958,6 +1958,8 @@ endif conf.set10('HAVE_VMLINUX_H', use_provided_vmlinux_h or use_generated_vmlinux_h) +conf.set10('ENABLE_SYSCTL_BPF', conf.get('HAVE_VMLINUX_H') == 1 and libbpf.version().version_compare('>= 0.7')) + ##################################################################### check_version_history_py = files('tools/check-version-history.py') diff --git a/src/network/bpf/sysctl-monitor/meson.build b/src/network/bpf/sysctl-monitor/meson.build index 2cd385736a..8b0de88674 100644 --- a/src/network/bpf/sysctl-monitor/meson.build +++ b/src/network/bpf/sysctl-monitor/meson.build @@ -1,6 +1,6 @@ # SPDX-License-Identifier: LGPL-2.1-or-later -if conf.get('HAVE_VMLINUX_H') != 1 +if conf.get('ENABLE_SYSCTL_BPF') != 1 subdir_done() endif diff --git a/src/network/meson.build b/src/network/meson.build index c6a323c929..78a0e72b3a 100644 --- a/src/network/meson.build +++ b/src/network/meson.build @@ -140,7 +140,7 @@ networkctl_sources = files( networkd_network_gperf_gperf = files('networkd-network-gperf.gperf') networkd_netdev_gperf_gperf = files('netdev/netdev-gperf.gperf') -if conf.get('HAVE_VMLINUX_H') == 1 +if conf.get('ENABLE_SYSCTL_BPF') == 1 systemd_networkd_extract_sources += sysctl_monitor_skel_h endif diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index e7acf6d126..ef61a90fcb 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -646,7 +646,7 @@ int manager_new(Manager **ret, bool test_mode) { .dhcp_server_persist_leases = DHCP_SERVER_PERSIST_LEASES_YES, .serialization_fd = -EBADF, .ip_forwarding = { -1, -1, }, -#if HAVE_VMLINUX_H +#if ENABLE_SYSCTL_BPF .cgroup_fd = -EBADF, #endif }; diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h index d0897e76ad..ad3d815b0c 100644 --- a/src/network/networkd-manager.h +++ b/src/network/networkd-manager.h @@ -117,7 +117,7 @@ typedef struct Manager { /* sysctl */ int ip_forwarding[2]; -#if HAVE_VMLINUX_H +#if ENABLE_SYSCTL_BPF Hashmap *sysctl_shadow; sd_event_source *sysctl_event_source; struct ring_buffer *sysctl_buffer; @@ -148,7 +148,7 @@ int manager_set_timezone(Manager *m, const char *timezone); int manager_reload(Manager *m, sd_bus_message *message); static inline Hashmap** manager_get_sysctl_shadow(Manager *manager) { -#if HAVE_VMLINUX_H +#if ENABLE_SYSCTL_BPF return &ASSERT_PTR(manager)->sysctl_shadow; #else return NULL; diff --git a/src/network/networkd-sysctl.c b/src/network/networkd-sysctl.c index 4f9b6522d7..6433a77a5e 100644 --- a/src/network/networkd-sysctl.c +++ b/src/network/networkd-sysctl.c @@ -26,7 +26,7 @@ #include "string-util.h" #include "sysctl-util.h" -#if HAVE_VMLINUX_H +#if ENABLE_SYSCTL_BPF #include "bpf-link.h" #include "bpf/sysctl-monitor/sysctl-monitor-skel.h" diff --git a/src/network/networkd-sysctl.h b/src/network/networkd-sysctl.h index dac7a72324..5cf8636312 100644 --- a/src/network/networkd-sysctl.h +++ b/src/network/networkd-sysctl.h @@ -22,7 +22,7 @@ typedef enum IPReversePathFilter { _IP_REVERSE_PATH_FILTER_INVALID = -EINVAL, } IPReversePathFilter; -#if HAVE_VMLINUX_H +#if ENABLE_SYSCTL_BPF int manager_install_sysctl_monitor(Manager *manager); void manager_remove_sysctl_monitor(Manager *manager); int link_clear_sysctl_shadows(Link *link); From 64a4f3110a72351d66f6815bf7b59993a0ed03d7 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Wed, 6 Aug 2025 13:50:56 +0100 Subject: [PATCH 4/7] test-bpf-token: fix build with libbpf < 0.6 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ../s/src/test/test-bpf-token.c: In function ‘intro’: ../s/src/test/test-bpf-token.c:10:5: error: "__LIBBPF_CURRENT_VERSION_GEQ" is not defined, evaluates to 0 [-Werror=undef] 10 | #if __LIBBPF_CURRENT_VERSION_GEQ(1, 5) | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ ../s/src/test/test-bpf-token.c:10:33: error: missing binary operator before token "(" 10 | #if __LIBBPF_CURRENT_VERSION_GEQ(1, 5) Follow-up for ea9826eb946d57aaba7e6bfa2d6b120136c6b20f --- src/test/test-bpf-token.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/test-bpf-token.c b/src/test/test-bpf-token.c index 3d6127182e..ffdf822b8b 100644 --- a/src/test/test-bpf-token.c +++ b/src/test/test-bpf-token.c @@ -7,7 +7,7 @@ #include "tests.h" static int intro(void) { -#if __LIBBPF_CURRENT_VERSION_GEQ(1, 5) +#if defined(LIBBPF_MAJOR_VERSION) && (LIBBPF_MAJOR_VERSION > 1 || (LIBBPF_MAJOR_VERSION == 1 && LIBBPF_MINOR_VERSION >= 5)) _cleanup_close_ int bpffs_fd = open("/sys/fs/bpf", O_RDONLY); if (bpffs_fd < 0) return log_error_errno(errno, "Failed to open '/sys/fs/bpf': %m"); From 14cb1fba9130ccb6b8ed315211fe46e5e3f9cc88 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Wed, 6 Aug 2025 12:48:34 +0100 Subject: [PATCH 5/7] test: fix assert when running test-cgroup in container When running in nspawn and thus from the namespaced root cgroup: Paths for test: //test-a //test-b src/test/test-cgroup.c:77: Assertion failed: Expected "path == test_b", got "/test-b != //test-b" Use path_simplify() in the test like the code does, so that the results always match --- src/test/test-cgroup.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/test/test-cgroup.c b/src/test/test-cgroup.c index d32b119d26..e67887a004 100644 --- a/src/test/test-cgroup.c +++ b/src/test/test-cgroup.c @@ -51,10 +51,12 @@ TEST(cg_create) { _cleanup_free_ char *here = NULL; ASSERT_OK(cg_pid_get_path_shifted(0, NULL, &here)); - _cleanup_free_ char *test_a = ASSERT_NOT_NULL(path_join(here, "/test-a")), - *test_b = ASSERT_NOT_NULL(path_join(here, "/test-b")), - *test_c = ASSERT_NOT_NULL(path_join(here, "/test-b/test-c")), - *test_d = ASSERT_NOT_NULL(path_join(here, "/test-b/test-d")); + /* cg_* will use path_simplify(), so use it here too otherwise when running in a container at the + * root it asserts with "/test-b != //test-b" */ + _cleanup_free_ char *test_a = ASSERT_NOT_NULL(path_simplify(path_join(here, "/test-a"))), + *test_b = ASSERT_NOT_NULL(path_simplify(path_join(here, "/test-b"))), + *test_c = ASSERT_NOT_NULL(path_simplify(path_join(here, "/test-b/test-c"))), + *test_d = ASSERT_NOT_NULL(path_simplify(path_join(here, "/test-b/test-d"))); char *path; log_info("Paths for test:\n%s\n%s", test_a, test_b); From 0d333ed8e302e48efdfc26cb4c8e467a4863f460 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Wed, 6 Aug 2025 14:07:26 +0100 Subject: [PATCH 6/7] test: fix repeated runs of test-oomd-util by clearing test cgroup If the test is ran multiple times in a row, without an ephemeral scope (eg: non-booted nspawn), then subsequent runs will fail as the test cgroup is not cleared so the previous xattrs are still present. Trim the test cgroup before and after the test. Follow-up for 61ff7397d08375ce0950fb7b546c08e4a657f273 --- src/oom/test-oomd-util.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/oom/test-oomd-util.c b/src/oom/test-oomd-util.c index b6f5fe25a5..abb5c2ccd8 100644 --- a/src/oom/test-oomd-util.c +++ b/src/oom/test-oomd-util.c @@ -68,6 +68,8 @@ TEST(oomd_cgroup_kill) { /* Create another cgroup below this one for the pids we forked off. We need this to be managed * by the test so that pid1 doesn't delete it before we can read the xattrs. */ ASSERT_NOT_NULL(subcgroup = path_join(cgroup, "oomdkilltest")); + /* Always start clean, in case of repeated runs and failures */ + ASSERT_OK(cg_trim(subcgroup, /* delete_root */ true)); ASSERT_OK(cg_create(subcgroup)); /* If we don't have permissions to set xattrs we're likely in a userns or missing capabilities */ @@ -106,6 +108,8 @@ TEST(oomd_cgroup_kill) { ASSERT_OK(cg_get_xattr(subcgroup, "user.oomd_kill", &v, /* ret_size= */ NULL)); ASSERT_STREQ(v, i == 0 ? "2" : "4"); } + + ASSERT_OK(cg_trim(subcgroup, /* delete_root */ true)); } TEST(oomd_cgroup_context_acquire_and_insert) { From 4f49a6f572043dbc3a302302464fad5ffbd40e01 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Wed, 6 Aug 2025 12:42:35 +0100 Subject: [PATCH 7/7] ci: add build job on Ubuntu Jammy with Python 3.7 In order to avoid regressions with glibc < 2.39 and Python 3.7 --- .github/workflows/build-test.sh | 18 ++++++++++++++---- .github/workflows/build-test.yml | 16 +++++++++++++++- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-test.sh b/.github/workflows/build-test.sh index 4693382c20..c683ca2de2 100755 --- a/.github/workflows/build-test.sh +++ b/.github/workflows/build-test.sh @@ -124,10 +124,15 @@ fi # This is added by default, and it is often broken, but we don't need anything from it sudo rm -f /etc/apt/sources.list.d/microsoft-prod.{list,sources} -# add-apt-repository --enable-source does not work on deb822 style sources. -for f in /etc/apt/sources.list.d/*.sources; do - sudo sed -i "s/Types: deb/Types: deb deb-src/g" "$f" -done +if grep -q 'VERSION_CODENAME=jammy' /usr/lib/os-release; then + sudo add-apt-repository -y --no-update ppa:upstream-systemd-ci/systemd-ci + sudo add-apt-repository -y --no-update --enable-source +else + # add-apt-repository --enable-source does not work on deb822 style sources. + for f in /etc/apt/sources.list.d/*.sources; do + sudo sed -i "s/Types: deb/Types: deb deb-src/g" "$f" + done +fi sudo apt-get -y update sudo apt-get -y build-dep systemd sudo apt-get -y install "${PACKAGES[@]}" @@ -138,6 +143,11 @@ sudo apt-get -y install "${PACKAGES[@]}" pip3 install --user -r .github/workflows/requirements.txt --require-hashes --break-system-packages export PATH="$HOME/.local/bin:$PATH" +if [[ -n "$CUSTOM_PYTHON" ]]; then + # If CUSTOM_PYTHON is set we need to pull jinja2 from pip, as a local interpreter is used + pip3 install --user --break-system-packages jinja2 +fi + $CC --version meson --version ninja --version diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 1232773e3a..9e76c7920f 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -19,12 +19,13 @@ jobs: build: runs-on: ${{ matrix.runner }} concurrency: - group: ${{ github.workflow }}-${{ toJSON(matrix.env) }}-${{ github.ref }}-${{ matrix.runner }} + group: ${{ github.workflow }}-${{ toJSON(matrix.env) }}-${{ github.ref }}-${{ matrix.runner }}-${{ matrix.python-version }} cancel-in-progress: true strategy: fail-fast: false matrix: runner: [ ubuntu-24.04 ] + python-version: [ '' ] env: - { COMPILER: "gcc", COMPILER_VERSION: "11", LINKER: "bfd" } - { COMPILER: "gcc", COMPILER_VERSION: "13", LINKER: "mold" } @@ -34,13 +35,26 @@ jobs: include: - env: { COMPILER: "gcc", COMPILER_VERSION: "11", LINKER: "bfd" } runner: [ ubuntu-24.04-ppc64le ] + python-version: '' - env: { COMPILER: "gcc", COMPILER_VERSION: "13", LINKER: "mold" } runner: [ ubuntu-24.04-arm ] + python-version: '' - env: { COMPILER: "clang", COMPILER_VERSION: "18", LINKER: "lld" } runner: [ ubuntu-24.04-s390x ] + python-version: '' + # Do one run with the oldest supported python version to ensure there are no regressions + # It is only available on Jammy, which is useful as it will also provide a build check for + # older glibc + - env: { COMPILER: "gcc", COMPILER_VERSION: "12", LINKER: "bfd", CUSTOM_PYTHON: "1" } + runner: [ ubuntu-22.04 ] + python-version: '3.7' env: ${{ matrix.env }} steps: - name: Repository checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - name: Setup python + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 + with: + python-version: ${{ matrix.python-version }} - name: Build check run: .github/workflows/build-test.sh