]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
tools/nolibc: make __nolibc_enosys() a compile time error
authorThomas Weißschuh <linux@weissschuh.net>
Sat, 4 Apr 2026 15:26:05 +0000 (17:26 +0200)
committerThomas Weißschuh <linux@weissschuh.net>
Mon, 27 Apr 2026 07:00:52 +0000 (09:00 +0200)
Functions which are known at compile-time to result in ENOSYS can be
surprising to the user. For example using old UAPI headers might mean
that stat() will always fail although the kernel would have the system
call available at runtime. Nowadays __nolibc_enosys() should never be
called for normal applications.

Switch the silent ENOSYS return into a compile-time error, so the user
is aware about the issue. Prefer the 'error' attribute as it provides
the best diagnostics. If the users defines NOLIBC_COMPILE_TIME_ENOSYS
the old, silent fallback is kept.

Also add a test which validates that the error can be optimized away.

Reported-by: Willy Tarreau <w@1wt.eu>
Closes: https://lore.kernel.org/lkml/acizRIq2xrFUNHNS@1wt.eu/
Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
Acked-by: Willy Tarreau <w@1wt.eu>
Link: https://patch.msgid.link/20260404-nolibc-enosys-v1-1-e0aba47bdee4@weissschuh.net
tools/include/nolibc/sys.h
tools/testing/selftests/nolibc/nolibc-test.c

index 6335fd51f07f5d0453ad9394f7a976c1b026f2d0..fd7a2ee780e88bd7ea55839589ab5e0dee3a6194 100644 (file)
                : __sysret_arg;                         /* return original value */ \
 })
 
-/* Syscall ENOSYS helper: Avoids unused-parameter warnings and provides a
- * debugging hook.
+/* Syscall ENOSYS helper: Avoids unused-parameter warnings, provides compile
+ * time validation and a debugging hook.
  */
 
+#if defined(NOLIBC_COMPILE_TIME_ENOSYS)
 static __inline__ int __nolibc_enosys(const char *syscall, ...)
 {
        (void)syscall;
        return -ENOSYS;
 }
 
+#elif __nolibc_has_attribute(error)
+__attribute__((error("system call not implemented")))
+extern int __nolibc_enosys(const char *syscall, ...);
+
+#else
+static __inline__ int __nolibc_enosys(const char *syscall, ...)
+{
+       extern int __nolibc_enosys_error;
+       (void)syscall;
+
+       return __nolibc_enosys_error;
+}
+#endif
 
 /* Functions in this file only describe syscalls. They're declared static so
  * that the compiler usually decides to inline them while still being allowed
index cfb797bf416c7802f81401be60f4c1e47837f5e7..eede2887acf6ee6ceb2de1708aa4efd490b98435 100644 (file)
@@ -1299,6 +1299,23 @@ int test_openat(void)
        return 0;
 }
 
+int test_nolibc_enosys(void)
+{
+       if (true)
+               return 0;
+
+#if defined(NOLIBC)
+       /*
+        * __nolibc_enosys() will fail the compilation.
+        * Make sure it can be optimized away if not actually called.
+        */
+       if (__nolibc_enosys("something") != -ENOSYS)
+               return 1;
+#endif
+
+       return 0;
+}
+
 int test_namespace(void)
 {
        int original_ns, new_ns, ret;
@@ -1467,6 +1484,7 @@ int run_syscall(int min, int max)
                CASE_TEST(munmap_bad);        EXPECT_SYSER(1, munmap(NULL, 0), -1, EINVAL); break;
                CASE_TEST(mmap_munmap_good);  EXPECT_SYSZR(1, test_mmap_munmap()); break;
                CASE_TEST(nanosleep);         ts.tv_nsec = -1; EXPECT_SYSER(1, nanosleep(&ts, NULL), -1, EINVAL); break;
+               CASE_TEST(nolibc_enosys);     EXPECT_ZR(is_nolibc, test_nolibc_enosys()); break;
                CASE_TEST(open_tty);          EXPECT_SYSNE(1, tmp = open("/dev/null", O_RDONLY), -1); if (tmp != -1) close(tmp); break;
                CASE_TEST(open_blah);         EXPECT_SYSER(1, tmp = open("/proc/self/blah", O_RDONLY), -1, ENOENT); if (tmp != -1) close(tmp); break;
                CASE_TEST(openat_dir);        EXPECT_SYSZR(1, test_openat()); break;