From 7857840b125a2bf2e9374ed9d3eadb307e72d4ae Mon Sep 17 00:00:00 2001 From: Chris Gellermann Date: Mon, 3 Aug 2026 14:48:59 +0200 Subject: selftests/membarrier: introduce helper to get membarrier command registrations Patch series "selftests/membarrier: Skip an unregistered memory barrier test on Musl". The membarrier test "membarrier MEMBARRIER_CMD_PRIVATE_EXPEDITED not registered failure" fails in the multithreaded test scenario when using Musl libc as the command gets preregistered implicitly during thread creation. Skip the test if command registration is detected. This patch (of 2): Add a new membarrier_get_registrations() for reusage. Link: https://lore.kernel.org/20260803124900.3328789-1-christian.gellermann@codasip.com Link: https://lore.kernel.org/20260803124900.3328789-2-christian.gellermann@codasip.com Signed-off-by: Chris Gellermann Signed-off-by: Andrew Morton Tested-by: Michael Jeanson Cc: Ben Segall Cc: Dietmar Eggemann Cc: Ingo Molnar Cc: Juri Lelli Cc: K Prateek Nayak Cc: Mathieu Desnoyers Cc: Mel Gorman Cc: "Paul E . McKenney" Cc: Peter Zijlstra Cc: Shuah Khan Cc: Steven Rostedt Cc: Valentin Schneider Cc: Vincent Guittot Cc: Wei Yang --- tools/testing/selftests/membarrier/membarrier_test_impl.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/testing/selftests/membarrier/membarrier_test_impl.h b/tools/testing/selftests/membarrier/membarrier_test_impl.h index f6d7c44b2288..29aac3bc4988 100644 --- a/tools/testing/selftests/membarrier/membarrier_test_impl.h +++ b/tools/testing/selftests/membarrier/membarrier_test_impl.h @@ -16,6 +16,11 @@ static int sys_membarrier(int cmd, int flags) return syscall(__NR_membarrier, cmd, flags); } +static int membarrier_get_registrations(void) +{ + return sys_membarrier(MEMBARRIER_CMD_GET_REGISTRATIONS, 0); +} + static int test_membarrier_get_registrations(int cmd) { int ret, flags = 0; @@ -24,7 +29,7 @@ static int test_membarrier_get_registrations(int cmd) registrations |= cmd; - ret = sys_membarrier(MEMBARRIER_CMD_GET_REGISTRATIONS, 0); + ret = membarrier_get_registrations(); if (ret < 0) { ksft_exit_fail_msg( "%s test: flags = %d, errno = %d\n", -- cgit v1.2.3 From 276abb3ee627e01fef3eb1782dbb20765019f0e4 Mon Sep 17 00:00:00 2001 From: Chris Gellermann Date: Mon, 3 Aug 2026 14:49:00 +0200 Subject: selftests/membarrier: skip unpermitted membarrier command test if preregistered by libc On thread creation, Musl registers the private expedited memory barrier, see pthread_create [1]. Thus, invoking the barrier command will no longer be rejected by the kernel with EPERM. The test checking this will fail. Check if the memory barrier command has been registered and skip the test in this case. Link: https://git.musl-libc.org/cgit/musl/tree/src/thread/pthread_create.c#n260 [1] Link: https://lore.kernel.org/20260803124900.3328789-3-christian.gellermann@codasip.com Signed-off-by: Chris Gellermann Signed-off-by: Andrew Morton Tested-by: Michael Jeanson Cc: Ben Segall Cc: Dietmar Eggemann Cc: Ingo Molnar Cc: Juri Lelli Cc: K Prateek Nayak Cc: Mathieu Desnoyers Cc: Mel Gorman Cc: "Paul E . McKenney" Cc: Peter Zijlstra Cc: Shuah Khan Cc: Steven Rostedt Cc: Valentin Schneider Cc: Vincent Guittot Cc: Wei Yang --- tools/testing/selftests/membarrier/membarrier_test_impl.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'tools') diff --git a/tools/testing/selftests/membarrier/membarrier_test_impl.h b/tools/testing/selftests/membarrier/membarrier_test_impl.h index 29aac3bc4988..b4dcbb32538d 100644 --- a/tools/testing/selftests/membarrier/membarrier_test_impl.h +++ b/tools/testing/selftests/membarrier/membarrier_test_impl.h @@ -113,6 +113,16 @@ static int test_membarrier_private_expedited_fail(void) int cmd = MEMBARRIER_CMD_PRIVATE_EXPEDITED, flags = 0; const char *test_name = "sys membarrier MEMBARRIER_CMD_PRIVATE_EXPEDITED not registered failure"; + /* + * Some C libraries, like Musl, register the private expedited barrier + * command when creating a thread. Expecting an EPERM on an unregistered + * command will therefore no longer work. Skip the test in this case. + */ + if (MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED & membarrier_get_registrations()) { + ksft_test_result_skip("%s test: Command already registered\n", test_name); + return 0; + } + if (sys_membarrier(cmd, flags) != -1) { ksft_exit_fail_msg( "%s test: flags = %d. Should fail, but passed\n", -- cgit v1.2.3 From 4238e66c82b6ee888a768cb298c85083b4566726 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Fri, 28 Aug 2026 17:54:07 +0200 Subject: selftests/epoll: fix race condition in multi-waiter wakeup tests In tests with multiple concurrent waiters on edge-triggered epoll instances where an emitter writes to multiple sockets (epoll16, epoll56, epoll58): When the emitter performs its first write(), ep_poll_callback() fires and wakes up both waiters because one waiter uses epoll_wait() and the other one uses poll(). This translates to different wait queues, ep->wq for epoll and ep->poll_wait for poll/select, which are both awoken by the kernel because of that single write. Next, both waiter threads invoke epoll_wait(), but since there is only one event, only one epoll_wait() will return non-zero because of the edge-triggered mode being used (in level-triggered mode, the kernel would re-queue the event because of remaining unread data). Since the second waiter sees an empty ready list, it does not increment ctx.count and the test fails spuriously with ctx.count == 1 instead of 2. Emitter (CPU 0) Thread 0 (CPU 1) Thread 1 (CPU 2) =============== ================ ================ epoll_wait(e0, -1) poll(e0, -1) [on e0->wq] [on e0->poll_wait] write(sfd[1]) | +--(Kernel wakes BOTH e0->wq and e0->poll_wait via callback)--+ | | | wakes up wakes up | | epoll_wait() reaps e1 poll() returns 1 | | (e1 removed via ET) (wants event) | | e0->rdllist is EMPTY | | | count++ (count = 1) v | | epoll_wait(e0, 0) | | sees EMPTY list! | | returns 0! | | thread exits | v | write(sfd[3]) | (event arrives too late!) v EXPECT_EQ(count, 2) <-- SPURIOUS FAILURE! Introduce waiter_entry1ap_loop() to retry poll() if the initial epoll_wait(..., 0) yielded no events. This ensures the thread waits for the subsequent write rather than failing immediately. Apply this helper in epoll16, epoll56, and for both waiter threads in epoll58. Link: https://lore.kernel.org/20260828-selftest-epoll-fix-race-v2-1-953ab57fd60a@codasip.com Fixes: f2728fe80cef ("selftests: add epoll selftests") Signed-off-by: Florian Schmaus Signed-off-by: Andrew Morton Cc: Heiher Cc: Roman Penyaev Cc: Shuah Khan Cc: Christian Brauner --- .../filesystems/epoll/epoll_wakeup_test.c | 32 +++++++++++++++------- 1 file changed, 22 insertions(+), 10 deletions(-) (limited to 'tools') diff --git a/tools/testing/selftests/filesystems/epoll/epoll_wakeup_test.c b/tools/testing/selftests/filesystems/epoll/epoll_wakeup_test.c index 81a994943e12..b4dcbcd79773 100644 --- a/tools/testing/selftests/filesystems/epoll/epoll_wakeup_test.c +++ b/tools/testing/selftests/filesystems/epoll/epoll_wakeup_test.c @@ -74,6 +74,24 @@ static void *waiter_entry1ap(void *data) return NULL; } +static void *waiter_entry1ap_loop(void *data) +{ + struct pollfd pfd; + struct epoll_event e; + struct epoll_mtcontext *ctx = data; + + pfd.fd = ctx->efd[0]; + pfd.events = POLLIN; + while (poll(&pfd, 1, 2000) > 0) { + if (epoll_wait(ctx->efd[0], &e, 1, 0) > 0) { + __sync_fetch_and_add(&ctx->count, 1); + break; + } + } + + return NULL; +} + static void *waiter_entry1o(void *data) { struct epoll_event e; @@ -809,7 +827,7 @@ TEST(epoll16) ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.sfd[2], events), 0); ctx.main = pthread_self(); - ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0); + ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap_loop, &ctx), 0); ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry2, &ctx), 0); if (epoll_wait(ctx.efd[0], events, 1, -1) > 0) @@ -2925,7 +2943,7 @@ TEST(epoll56) ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[2], &e), 0); ctx.main = pthread_self(); - ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0); + ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap_loop, &ctx), 0); ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry2, &ctx), 0); if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0) @@ -3030,7 +3048,6 @@ TEST(epoll57) TEST(epoll58) { pthread_t emitter; - struct pollfd pfd; struct epoll_event e; struct epoll_mtcontext ctx = { 0 }; @@ -3061,15 +3078,10 @@ TEST(epoll58) ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[2], &e), 0); ctx.main = pthread_self(); - ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0); + ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap_loop, &ctx), 0); ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry2, &ctx), 0); - pfd.fd = ctx.efd[0]; - pfd.events = POLLIN; - if (poll(&pfd, 1, -1) > 0) { - if (epoll_wait(ctx.efd[0], &e, 1, 0) > 0) - __sync_fetch_and_add(&ctx.count, 1); - } + waiter_entry1ap_loop(&ctx); ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0); EXPECT_EQ(ctx.count, 2); -- cgit v1.2.3 From df0b7e0ea59c43708cff8c7e34da5e2f8d430e5e Mon Sep 17 00:00:00 2001 From: Konstantin Khorenko Date: Fri, 14 Aug 2026 18:57:09 +0200 Subject: selftests/core: fix unshare_test with large fs.nr_open The test assumes fs.nr_open is close to the default 1048576, but some systems set it much higher (e.g. 1073741816). This is systemd's doing: since systemd v240 (2018), PID 1 bumps fs.nr_open and fs.file-max to their largest possible values on boot, as file descriptors are already accounted for by memcg [1]. In that case, dup2() to nr_open + 64 requires the kernel to allocate a file descriptor table with ~1 billion entries, which fails with ENOMEM. On a kernel that already carries 04a2c4b4511d1, dup2() no longer fails with ENOMEM. The allocation is now rejected up front and the caller gets EMFILE instead, without the WARNING, but the test still fails. Cap the nr_open value used for the test's own arithmetic to a known reasonable base value (1048576) and restore the true original value once the test has completed. Link: https://lore.kernel.org/20260814165709.513263-1-khorenko@virtuozzo.com Link: https://github.com/systemd/systemd/commit/a8b627aaed409a15260c25988970c795bf963812 [1] Signed-off-by: Konstantin Khorenko Signed-off-by: Eva Kurchatova Signed-off-by: Andrew Morton Cc: Shuah Khan Cc: Wei Yang Cc: --- tools/testing/selftests/core/unshare_test.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/testing/selftests/core/unshare_test.c b/tools/testing/selftests/core/unshare_test.c index ffce75a6c228..d40e963dd520 100644 --- a/tools/testing/selftests/core/unshare_test.c +++ b/tools/testing/selftests/core/unshare_test.c @@ -40,6 +40,14 @@ TEST(unshare_EMFILE) ASSERT_EQ(sscanf(buf, "%d", &nr_open), 1); + /* + * Cap nr_open for the duration of the test to avoid ENOMEM from a + * huge fd table allocation; buf/n keep the real original value so + * fs.nr_open can be restored to it once the test is done. + */ + if (nr_open > 1024 * 1024) + nr_open = 1024 * 1024; + ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlimit)); /* bump fs.nr_open */ @@ -73,10 +81,13 @@ TEST(unshare_EMFILE) if (pid == 0) { int err; + char buf3[32]; + ssize_t n3; - /* restore fs.nr_open */ + /* restore fs.nr_open to the (possibly capped) test baseline */ + n3 = sprintf(buf3, "%d\n", nr_open); lseek(fd, 0, SEEK_SET); - write(fd, buf, n); + write(fd, buf3, n3); /* ... and now unshare(CLONE_FILES) must fail with EMFILE */ err = unshare(CLONE_FILES); EXPECT_EQ(err, -1) @@ -89,6 +100,10 @@ TEST(unshare_EMFILE) EXPECT_EQ(waitpid(pid, &status, 0), pid); EXPECT_EQ(true, WIFEXITED(status)); EXPECT_EQ(0, WEXITSTATUS(status)); + + /* restore the real fs.nr_open value */ + lseek(fd, 0, SEEK_SET); + write(fd, buf, n); } TEST_HARNESS_MAIN -- cgit v1.2.3 From d6f97fcebd0e9544d41a0a662890a59520a6ee0e Mon Sep 17 00:00:00 2001 From: "Masami Hiramatsu (Google)" Date: Fri, 11 Sep 2026 23:13:06 +0900 Subject: bootconfig: reject unexpected data after null character Patch series "bootconfig: Reject unexpected data after null character and cleanups", v2. Make bootconfig reject unexpected config data after null character and implement other cleanups including tools/bootconfig to consolidate bootconfig initialization with errors, and to skip internal tree sanity checks in kernel. This patch (of 4): If a bootconfig buffer contains an intermediate null character in the middle of the configuration, xbc_parse_tree() stops at the null character because string delimiter searches (e.g. strpbrk()) stop at '\0', and cleanly breaks out of the loop without error. As a result, any configuration data following the intermediate null character is silently ignored, allowing unparsed or potentially malicious data to be hidden after an early termination. Fix this in xbc_parse_tree() by checking that no non-null data remains between the parser termination point and the end of the input buffer. Trailing null characters (such as alignment padding in initrd) continue to be accepted as valid. Also update apply_xbc() in tools/bootconfig/main.c to calculate the buffer size based on the loaded file size rather than strlen(), so that files with intermediate null characters are not truncated before validation. Link: https://lore.kernel.org/178913597653.248794.1237187523153227751.stgit@devnote2 Link: https://lore.kernel.org/178913598628.248794.1048773774471250986.stgit@devnote2 Signed-off-by: Masami Hiramatsu (Google) Signed-off-by: Andrew Morton Reviewed-by: Sang-Heon Jeon Assisted-by: Antigravity:gemini-3.8-flash --- tools/bootconfig/main.c | 4 +++- tools/bootconfig/test-bootconfig.sh | 12 ++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/bootconfig/main.c b/tools/bootconfig/main.c index 17d971d47f87..aff169ba75b8 100644 --- a/tools/bootconfig/main.c +++ b/tools/bootconfig/main.c @@ -433,7 +433,9 @@ static int apply_xbc(const char *path, const char *xbc_path) pr_err("Failed to load %s : %d\n", xbc_path, ret); return ret; } - size = strlen(buf) + 1; + size = ret; + if (size == 0 || buf[size - 1] != '\0') + size++; csum = xbc_calc_checksum(buf, size); /* Backup the bootconfig data */ diff --git a/tools/bootconfig/test-bootconfig.sh b/tools/bootconfig/test-bootconfig.sh index fc69f815ce4a..530ce7e28d63 100755 --- a/tools/bootconfig/test-bootconfig.sh +++ b/tools/bootconfig/test-bootconfig.sh @@ -180,6 +180,18 @@ EOF $BOOTCONF -a $TEMPCONF $INITRD 2> $OUTFILE xpass grep -q "1:1" $OUTFILE +echo "Intermediate null character test" +printf "key = value\n\0extra = data\n" > $TEMPCONF +xfail $BOOTCONF -a $TEMPCONF $INITRD +$BOOTCONF -a $TEMPCONF $INITRD 2> $OUTFILE +xpass grep -q "Unexpected" $OUTFILE + +echo "Trailing null character test" +printf "key = value\n\0" > $TEMPCONF +xpass $BOOTCONF -a $TEMPCONF $INITRD +$BOOTCONF $INITRD > $OUTFILE +xpass grep -q "value" $OUTFILE + echo "=== expected failure cases ===" for i in samples/bad-* ; do xfail $BOOTCONF -a $i $INITRD -- cgit v1.2.3 From d05de2360a3e25aa3ec24f460802755a95e8e6e9 Mon Sep 17 00:00:00 2001 From: Danish Khateeb Date: Fri, 25 Sep 2026 15:55:02 -0500 Subject: kselftest/filelock: plan for the five ofdlocks tests ofdlocks reports five results but plans for four, so even when they all pass it ends with # Planned tests != run tests (4 != 5) and exits with KSFT_FAIL, which run_kselftest.sh reports as a failure. Link: https://lore.kernel.org/20260925205502.115327-1-danishkhateeb03@gmail.com Fixes: 33d5b13098fb ("kselftest/filelock: report each test in oftlocks separately") Signed-off-by: Danish Khateeb Signed-off-by: Andrew Morton Assisted-by: LLM Cc: Shuah Khan Cc: Mark Brown Cc: Jeff Layton --- tools/testing/selftests/filelock/ofdlocks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/testing/selftests/filelock/ofdlocks.c b/tools/testing/selftests/filelock/ofdlocks.c index 68bac28b234b..0ab484cb075b 100644 --- a/tools/testing/selftests/filelock/ofdlocks.c +++ b/tools/testing/selftests/filelock/ofdlocks.c @@ -40,7 +40,7 @@ int main(void) int fd2 = open("/tmp/aa", O_RDONLY); ksft_print_header(); - ksft_set_plan(4); + ksft_set_plan(5); unlink("/tmp/aa"); assert(fd != -1); -- cgit v1.2.3 From c4d9005e7e1ee6ce277f47cf53d44fc5b90b287b Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Mon, 12 Oct 2026 07:53:29 -0400 Subject: selftests/proc: proc-pid-vm: fix unused variable warning on non-x86 g_vsyscall is only used by the x86_64 test, so clang builds for other architectures get: proc-pid-vm.c:224:21: warning: unused variable 'g_vsyscall' [-Wunused-variable] The vsyscall strings next to it had the same problem and were marked __maybe_unused for it. Move all of the vsyscall variables into the __x86_64__ block that uses them instead, and drop those annotations along with the local __maybe_unused fallback that was added for them. Link: https://lore.kernel.org/20261012115330.3777115-1-sashal@kernel.org Fixes: 17415606f9d8 ("tools/testing/selftests/proc/proc-pid-vm.c: test with vsyscall in mind") Signed-off-by: Sasha Levin Signed-off-by: Andrew Morton Suggested-by: Andrew Morton Assisted-by: LLM Cc: Shuah Khan Cc: Alexey Dobriyan --- tools/testing/selftests/proc/proc-pid-vm.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'tools') diff --git a/tools/testing/selftests/proc/proc-pid-vm.c b/tools/testing/selftests/proc/proc-pid-vm.c index 4e6a3e53f975..98e882e56815 100644 --- a/tools/testing/selftests/proc/proc-pid-vm.c +++ b/tools/testing/selftests/proc/proc-pid-vm.c @@ -47,10 +47,6 @@ #include #include -#ifndef __maybe_unused -#define __maybe_unused __attribute__((__unused__)) -#endif - #include "kselftest.h" static inline long sys_execveat(int dirfd, const char *pathname, char **argv, char **envp, int flags) @@ -214,7 +210,6 @@ static int make_exe(const uint8_t *payload, size_t len) return fd1; } -#endif /* * 0: vsyscall VMA doesn't exist vsyscall=none @@ -222,15 +217,14 @@ static int make_exe(const uint8_t *payload, size_t len) * 2: vsyscall VMA is r-xp vsyscall=emulate */ static volatile int g_vsyscall; -static const char *str_vsyscall __maybe_unused; +static const char *str_vsyscall; -static const char str_vsyscall_0[] __maybe_unused = ""; -static const char str_vsyscall_1[] __maybe_unused = +static const char str_vsyscall_0[] = ""; +static const char str_vsyscall_1[] = "ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]\n"; -static const char str_vsyscall_2[] __maybe_unused = +static const char str_vsyscall_2[] = "ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]\n"; -#ifdef __x86_64__ static void sigaction_SIGSEGV(int _, siginfo_t *__, void *___) { _exit(g_vsyscall); -- cgit v1.2.3