Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tools/nolibc: add namespace functionality

This is used in various selftests and will be handy when integrating
those with nolibc.

Not all configurations support namespaces, so skip the tests where
necessary. Also if the tests are running without privileges.
Enable the namespace configuration for those architectures where it is not
enabled by default.

Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
Acked-by: Willy Tarreau <w@1wt.eu>
Link: https://lore.kernel.org/r/20250428-nolibc-misc-v2-12-3c043eeab06c@linutronix.de
Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>

authored by

Thomas Weißschuh and committed by
Thomas Weißschuh
256dc733 7ff3c71a

+121
+1
tools/include/nolibc/Makefile
··· 38 38 math.h \ 39 39 nolibc.h \ 40 40 poll.h \ 41 + sched.h \ 41 42 signal.h \ 42 43 stackprotector.h \ 43 44 std.h \
+1
tools/include/nolibc/nolibc.h
··· 106 106 #include "sys/wait.h" 107 107 #include "ctype.h" 108 108 #include "elf.h" 109 + #include "sched.h" 109 110 #include "signal.h" 110 111 #include "unistd.h" 111 112 #include "stdio.h"
+50
tools/include/nolibc/sched.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * sched function definitions for NOLIBC 4 + * Copyright (C) 2025 Thomas Weißschuh <linux@weissschuh.net> 5 + */ 6 + 7 + /* make sure to include all global symbols */ 8 + #include "nolibc.h" 9 + 10 + #ifndef _NOLIBC_SCHED_H 11 + #define _NOLIBC_SCHED_H 12 + 13 + #include "sys.h" 14 + 15 + #include <linux/sched.h> 16 + 17 + /* 18 + * int setns(int fd, int nstype); 19 + */ 20 + 21 + static __attribute__((unused)) 22 + int sys_setns(int fd, int nstype) 23 + { 24 + return my_syscall2(__NR_setns, fd, nstype); 25 + } 26 + 27 + static __attribute__((unused)) 28 + int setns(int fd, int nstype) 29 + { 30 + return __sysret(sys_setns(fd, nstype)); 31 + } 32 + 33 + 34 + /* 35 + * int unshare(int flags); 36 + */ 37 + 38 + static __attribute__((unused)) 39 + int sys_unshare(int flags) 40 + { 41 + return my_syscall1(__NR_unshare, flags); 42 + } 43 + 44 + static __attribute__((unused)) 45 + int unshare(int flags) 46 + { 47 + return __sysret(sys_unshare(flags)); 48 + } 49 + 50 + #endif /* _NOLIBC_SCHED_H */
+2
tools/testing/selftests/nolibc/Makefile
··· 109 109 110 110 EXTRACONFIG_m68k = -e CONFIG_BLK_DEV_INITRD 111 111 EXTRACONFIG = $(EXTRACONFIG_$(XARCH)) 112 + EXTRACONFIG_arm = -e CONFIG_NAMESPACES 113 + EXTRACONFIG_armthumb = -e CONFIG_NAMESPACES 112 114 113 115 # optional tests to run (default = all) 114 116 TEST =
+67
tools/testing/selftests/nolibc/nolibc-test.c
··· 1172 1172 return 0; 1173 1173 } 1174 1174 1175 + int test_namespace(void) 1176 + { 1177 + int original_ns, new_ns, ret; 1178 + ino_t original_ns_ino; 1179 + struct stat stat_buf; 1180 + 1181 + original_ns = open("/proc/self/ns/uts", O_RDONLY); 1182 + if (original_ns == -1) 1183 + return -1; 1184 + 1185 + ret = fstat(original_ns, &stat_buf); 1186 + if (ret) 1187 + goto out; 1188 + 1189 + original_ns_ino = stat_buf.st_ino; 1190 + 1191 + ret = unshare(CLONE_NEWUTS); 1192 + if (ret) 1193 + goto out; 1194 + 1195 + new_ns = open("/proc/self/ns/uts", O_RDONLY); 1196 + if (new_ns == -1) { 1197 + ret = new_ns; 1198 + goto out; 1199 + } 1200 + 1201 + ret = fstat(new_ns, &stat_buf); 1202 + close(new_ns); 1203 + if (ret) 1204 + goto out; 1205 + 1206 + if (stat_buf.st_ino == original_ns_ino) { 1207 + errno = EINVAL; 1208 + ret = -1; 1209 + goto out; 1210 + } 1211 + 1212 + ret = setns(original_ns, CLONE_NEWUTS); 1213 + if (ret) 1214 + goto out; 1215 + 1216 + new_ns = open("/proc/self/ns/uts", O_RDONLY); 1217 + if (new_ns == -1) { 1218 + ret = new_ns; 1219 + goto out; 1220 + } 1221 + 1222 + ret = fstat(new_ns, &stat_buf); 1223 + if (ret) 1224 + goto out; 1225 + 1226 + close(new_ns); 1227 + 1228 + if (stat_buf.st_ino != original_ns_ino) { 1229 + errno = EINVAL; 1230 + ret = -1; 1231 + goto out; 1232 + } 1233 + 1234 + ret = 0; 1235 + 1236 + out: 1237 + close(original_ns); 1238 + return ret; 1239 + } 1240 + 1175 1241 /* Run syscall tests between IDs <min> and <max>. 1176 1242 * Return 0 on success, non-zero on failure. 1177 1243 */ ··· 1362 1296 CASE_TEST(write_zero); EXPECT_SYSZR(1, write(1, &tmp, 0)); break; 1363 1297 CASE_TEST(syscall_noargs); EXPECT_SYSEQ(1, syscall(__NR_getpid), getpid()); break; 1364 1298 CASE_TEST(syscall_args); EXPECT_SYSER(1, syscall(__NR_statx, 0, NULL, 0, 0, NULL), -1, EFAULT); break; 1299 + CASE_TEST(namespace); EXPECT_SYSZR(euid0 && proc, test_namespace()); break; 1365 1300 case __LINE__: 1366 1301 return ret; /* must be last */ 1367 1302 /* note: do not set any defaults so as to permit holes above */