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:core: test coverage for dup_fd() failure handling in unshare_fd()

At some point there'd been a dumb braino during the dup_fd()
calling conventions change; caught by smatch and immediately fixed.
The trouble is, there had been no test coverage for the dup_fd() failure
handling - neither in kselftests nor in LTP. Fortunately, it can be
triggered on stock kernel - ENOMEM would require fault injection, but
EMFILE can be had with sysctl alone (fs.nr_open).

Add a test for dup_fd() failure.
Fixed up commit log and short log - Shuah Khan

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>

authored by

Al Viro and committed by
Shuah Khan
611fbeb4 c049acee

+95 -1
+1 -1
tools/testing/selftests/core/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 CFLAGS += -g $(KHDR_INCLUDES) 3 3 4 - TEST_GEN_PROGS := close_range_test 4 + TEST_GEN_PROGS := close_range_test unshare_test 5 5 6 6 include ../lib.mk 7 7
+94
tools/testing/selftests/core/unshare_test.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #define _GNU_SOURCE 4 + #include <errno.h> 5 + #include <fcntl.h> 6 + #include <linux/kernel.h> 7 + #include <limits.h> 8 + #include <stdbool.h> 9 + #include <stdio.h> 10 + #include <stdlib.h> 11 + #include <string.h> 12 + #include <syscall.h> 13 + #include <unistd.h> 14 + #include <sys/resource.h> 15 + #include <linux/close_range.h> 16 + 17 + #include "../kselftest_harness.h" 18 + #include "../clone3/clone3_selftests.h" 19 + 20 + TEST(unshare_EMFILE) 21 + { 22 + pid_t pid; 23 + int status; 24 + struct __clone_args args = { 25 + .flags = CLONE_FILES, 26 + .exit_signal = SIGCHLD, 27 + }; 28 + int fd; 29 + ssize_t n, n2; 30 + static char buf[512], buf2[512]; 31 + struct rlimit rlimit; 32 + int nr_open; 33 + 34 + fd = open("/proc/sys/fs/nr_open", O_RDWR); 35 + ASSERT_GE(fd, 0); 36 + 37 + n = read(fd, buf, sizeof(buf)); 38 + ASSERT_GT(n, 0); 39 + ASSERT_EQ(buf[n - 1], '\n'); 40 + 41 + ASSERT_EQ(sscanf(buf, "%d", &nr_open), 1); 42 + 43 + ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlimit)); 44 + 45 + /* bump fs.nr_open */ 46 + n2 = sprintf(buf2, "%d\n", nr_open + 1024); 47 + lseek(fd, 0, SEEK_SET); 48 + write(fd, buf2, n2); 49 + 50 + /* bump ulimit -n */ 51 + rlimit.rlim_cur = nr_open + 1024; 52 + rlimit.rlim_max = nr_open + 1024; 53 + EXPECT_EQ(0, setrlimit(RLIMIT_NOFILE, &rlimit)) { 54 + lseek(fd, 0, SEEK_SET); 55 + write(fd, buf, n); 56 + exit(EXIT_FAILURE); 57 + } 58 + 59 + /* get a descriptor past the old fs.nr_open */ 60 + EXPECT_GE(dup2(2, nr_open + 64), 0) { 61 + lseek(fd, 0, SEEK_SET); 62 + write(fd, buf, n); 63 + exit(EXIT_FAILURE); 64 + } 65 + 66 + /* get descriptor table shared */ 67 + pid = sys_clone3(&args, sizeof(args)); 68 + EXPECT_GE(pid, 0) { 69 + lseek(fd, 0, SEEK_SET); 70 + write(fd, buf, n); 71 + exit(EXIT_FAILURE); 72 + } 73 + 74 + if (pid == 0) { 75 + int err; 76 + 77 + /* restore fs.nr_open */ 78 + lseek(fd, 0, SEEK_SET); 79 + write(fd, buf, n); 80 + /* ... and now unshare(CLONE_FILES) must fail with EMFILE */ 81 + err = unshare(CLONE_FILES); 82 + EXPECT_EQ(err, -1) 83 + exit(EXIT_FAILURE); 84 + EXPECT_EQ(errno, EMFILE) 85 + exit(EXIT_FAILURE); 86 + exit(EXIT_SUCCESS); 87 + } 88 + 89 + EXPECT_EQ(waitpid(pid, &status, 0), pid); 90 + EXPECT_EQ(true, WIFEXITED(status)); 91 + EXPECT_EQ(0, WEXITSTATUS(status)); 92 + } 93 + 94 + TEST_HARNESS_MAIN