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

Configure Feed

Select the types of activity you want to include in your feed.

selftests: vDSO: ensure vgetrandom works in a time namespace

After verifying that vDSO getrandom does work, which ensures that the
RNG is initialized, test to see if it also works inside of a time
namespace. This is important to test, because the vvar pages get
swizzled around there. If the arch code isn't careful, the RNG will
appear uninitialized inside of a time namespace.

Because broken code makes the RNG appear uninitialized, test that
everything works by issuing a call to vgetrandom from a fork in a time
namespace, and use ptrace to ensure that the actual syscall getrandom
doesn't get called. If it doesn't get called, then the test succeeds.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>

+42 -1
+42 -1
tools/testing/selftests/vDSO/vdso_test_getrandom.c
··· 16 16 #include <sys/mman.h> 17 17 #include <sys/random.h> 18 18 #include <sys/syscall.h> 19 + #include <sys/ptrace.h> 20 + #include <sys/wait.h> 19 21 #include <sys/types.h> 20 22 #include <linux/random.h> 23 + #include <linux/compiler.h> 24 + #include <linux/ptrace.h> 21 25 22 26 #include "../kselftest.h" 23 27 #include "parse_vdso.h" ··· 243 239 static void kselftest(void) 244 240 { 245 241 uint8_t weird_size[1263]; 242 + pid_t child; 246 243 247 244 ksft_print_header(); 248 - ksft_set_plan(1); 245 + ksft_set_plan(2); 249 246 250 247 for (size_t i = 0; i < 1000; ++i) { 251 248 ssize_t ret = vgetrandom(weird_size, sizeof(weird_size), 0); ··· 255 250 } 256 251 257 252 ksft_test_result_pass("getrandom: PASS\n"); 253 + 254 + unshare(CLONE_NEWUSER); 255 + assert(unshare(CLONE_NEWTIME) == 0); 256 + child = fork(); 257 + assert(child >= 0); 258 + if (!child) { 259 + vgetrandom_init(); 260 + child = getpid(); 261 + assert(ptrace(PTRACE_TRACEME, 0, NULL, NULL) == 0); 262 + assert(kill(child, SIGSTOP) == 0); 263 + assert(vgetrandom(weird_size, sizeof(weird_size), 0) == sizeof(weird_size)); 264 + _exit(0); 265 + } 266 + for (;;) { 267 + struct ptrace_syscall_info info = { 0 }; 268 + int status, ret; 269 + assert(waitpid(child, &status, 0) >= 0); 270 + if (WIFEXITED(status)) { 271 + if (WEXITSTATUS(status) != 0) 272 + exit(KSFT_FAIL); 273 + break; 274 + } 275 + assert(WIFSTOPPED(status)); 276 + if (WSTOPSIG(status) == SIGSTOP) 277 + assert(ptrace(PTRACE_SETOPTIONS, child, 0, PTRACE_O_TRACESYSGOOD) == 0); 278 + else if (WSTOPSIG(status) == (SIGTRAP | 0x80)) { 279 + assert(ptrace(PTRACE_GET_SYSCALL_INFO, child, sizeof(info), &info) > 0); 280 + if (info.op == PTRACE_SYSCALL_INFO_ENTRY && info.entry.nr == __NR_getrandom && 281 + info.entry.args[0] == (uintptr_t)weird_size && info.entry.args[1] == sizeof(weird_size)) 282 + exit(KSFT_FAIL); 283 + } 284 + assert(ptrace(PTRACE_SYSCALL, child, 0, 0) == 0); 285 + } 286 + 287 + ksft_test_result_pass("getrandom timens: PASS\n"); 288 + 258 289 exit(KSFT_PASS); 259 290 } 260 291