From 4e62d55d77bbdb33d821f5e16306caab38d42267 Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Wed, 28 Oct 2020 10:50:44 +1100 Subject: selftests: openat2: add RESOLVE_ conflict test Now that we reject conflicting RESOLVE_ flags, add a selftest to avoid regressions. Signed-off-by: Aleksa Sarai Link: https://lore.kernel.org/r/20201027235044.5240-3-cyphar@cyphar.com Signed-off-by: Christian Brauner --- tools/testing/selftests/openat2/openat2_test.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/testing/selftests/openat2/openat2_test.c b/tools/testing/selftests/openat2/openat2_test.c index b386367c606b..381d874cce99 100644 --- a/tools/testing/selftests/openat2/openat2_test.c +++ b/tools/testing/selftests/openat2/openat2_test.c @@ -155,7 +155,7 @@ struct flag_test { int err; }; -#define NUM_OPENAT2_FLAG_TESTS 23 +#define NUM_OPENAT2_FLAG_TESTS 24 void test_openat2_flags(void) { @@ -210,6 +210,12 @@ void test_openat2_flags(void) .how.flags = O_TMPFILE | O_RDWR, .how.mode = 0x0000A00000000000ULL, .err = -EINVAL }, + /* ->resolve flags must not conflict. */ + { .name = "incompatible resolve flags (BENEATH | IN_ROOT)", + .how.flags = O_RDONLY, + .how.resolve = RESOLVE_BENEATH | RESOLVE_IN_ROOT, + .err = -EINVAL }, + /* ->resolve must only contain RESOLVE_* flags. */ { .name = "invalid how.resolve and O_RDONLY", .how.flags = O_RDONLY, -- cgit v1.2.3 From 23afeaeff3d985b07abf2c76fd12b8c548da8367 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Wed, 18 Nov 2020 11:47:46 +0100 Subject: selftests: core: add tests for CLOSE_RANGE_CLOEXEC check that close_range(initial_fd, last_fd, CLOSE_RANGE_CLOEXEC) correctly sets the close-on-exec bit for the specified file descriptors. Open 100 file descriptors and set the close-on-exec flag for a subset of them first, then set it for every file descriptor above 2. Make sure RLIMIT_NOFILE doesn't affect the result. Signed-off-by: Giuseppe Scrivano Link: https://lore.kernel.org/r/20201118104746.873084-3-gscrivan@redhat.com Signed-off-by: Christian Brauner --- tools/testing/selftests/core/close_range_test.c | 74 +++++++++++++++++++++++++ 1 file changed, 74 insertions(+) (limited to 'tools') diff --git a/tools/testing/selftests/core/close_range_test.c b/tools/testing/selftests/core/close_range_test.c index 575b391ddc78..87e16d65d9d7 100644 --- a/tools/testing/selftests/core/close_range_test.c +++ b/tools/testing/selftests/core/close_range_test.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "../kselftest_harness.h" #include "../clone3/clone3_selftests.h" @@ -23,6 +24,10 @@ #define CLOSE_RANGE_UNSHARE (1U << 1) #endif +#ifndef CLOSE_RANGE_CLOEXEC +#define CLOSE_RANGE_CLOEXEC (1U << 2) +#endif + static inline int sys_close_range(unsigned int fd, unsigned int max_fd, unsigned int flags) { @@ -224,4 +229,73 @@ TEST(close_range_unshare_capped) EXPECT_EQ(0, WEXITSTATUS(status)); } +TEST(close_range_cloexec) +{ + int i, ret; + int open_fds[101]; + struct rlimit rlimit; + + for (i = 0; i < ARRAY_SIZE(open_fds); i++) { + int fd; + + fd = open("/dev/null", O_RDONLY); + ASSERT_GE(fd, 0) { + if (errno == ENOENT) + XFAIL(return, "Skipping test since /dev/null does not exist"); + } + + open_fds[i] = fd; + } + + ret = sys_close_range(1000, 1000, CLOSE_RANGE_CLOEXEC); + if (ret < 0) { + if (errno == ENOSYS) + XFAIL(return, "close_range() syscall not supported"); + if (errno == EINVAL) + XFAIL(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC"); + } + + /* Ensure the FD_CLOEXEC bit is set also with a resource limit in place. */ + ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlimit)); + rlimit.rlim_cur = 25; + ASSERT_EQ(0, setrlimit(RLIMIT_NOFILE, &rlimit)); + + /* Set close-on-exec for two ranges: [0-50] and [75-100]. */ + ret = sys_close_range(open_fds[0], open_fds[50], CLOSE_RANGE_CLOEXEC); + ASSERT_EQ(0, ret); + ret = sys_close_range(open_fds[75], open_fds[100], CLOSE_RANGE_CLOEXEC); + ASSERT_EQ(0, ret); + + for (i = 0; i <= 50; i++) { + int flags = fcntl(open_fds[i], F_GETFD); + + EXPECT_GT(flags, -1); + EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC); + } + + for (i = 51; i <= 74; i++) { + int flags = fcntl(open_fds[i], F_GETFD); + + EXPECT_GT(flags, -1); + EXPECT_EQ(flags & FD_CLOEXEC, 0); + } + + for (i = 75; i <= 100; i++) { + int flags = fcntl(open_fds[i], F_GETFD); + + EXPECT_GT(flags, -1); + EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC); + } + + /* Test a common pattern. */ + ret = sys_close_range(3, UINT_MAX, CLOSE_RANGE_CLOEXEC); + for (i = 0; i <= 100; i++) { + int flags = fcntl(open_fds[i], F_GETFD); + + EXPECT_GT(flags, -1); + EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC); + } +} + + TEST_HARNESS_MAIN -- cgit v1.2.3