tests: add CLOSE_RANGE_UNSHARE tests
authorChristian Brauner <christian.brauner@ubuntu.com>
Wed, 3 Jun 2020 19:51:44 +0000 (21:51 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Tue, 16 Jun 2020 22:07:38 +0000 (00:07 +0200)
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
tools/testing/selftests/core/close_range_test.c

index 9d92f2d..c99b98b 100644 (file)
 #include <unistd.h>
 
 #include "../kselftest_harness.h"
+#include "../clone3/clone3_selftests.h"
 
 #ifndef __NR_close_range
 #define __NR_close_range -1
 #endif
 
+#ifndef CLOSE_RANGE_UNSHARE
+#define CLOSE_RANGE_UNSHARE    (1U << 1)
+#endif
+
 static inline int sys_close_range(unsigned int fd, unsigned int max_fd,
                                  unsigned int flags)
 {
@@ -87,4 +92,136 @@ TEST(close_range)
        EXPECT_EQ(-1, fcntl(open_fds[100], F_GETFL));
 }
 
+TEST(close_range_unshare)
+{
+       int i, ret, status;
+       pid_t pid;
+       int open_fds[101];
+       struct clone_args args = {
+               .flags = CLONE_FILES,
+               .exit_signal = SIGCHLD,
+       };
+
+       for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
+               int fd;
+
+               fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
+               ASSERT_GE(fd, 0) {
+                       if (errno == ENOENT)
+                               XFAIL(return, "Skipping test since /dev/null does not exist");
+               }
+
+               open_fds[i] = fd;
+       }
+
+       pid = sys_clone3(&args, sizeof(args));
+       ASSERT_GE(pid, 0);
+
+       if (pid == 0) {
+               ret = sys_close_range(open_fds[0], open_fds[50],
+                                     CLOSE_RANGE_UNSHARE);
+               if (ret)
+                       exit(EXIT_FAILURE);
+
+               for (i = 0; i <= 50; i++)
+                       if (fcntl(open_fds[i], F_GETFL) != -1)
+                               exit(EXIT_FAILURE);
+
+               for (i = 51; i <= 100; i++)
+                       if (fcntl(open_fds[i], F_GETFL) == -1)
+                               exit(EXIT_FAILURE);
+
+               /* create a couple of gaps */
+               close(57);
+               close(78);
+               close(81);
+               close(82);
+               close(84);
+               close(90);
+
+               ret = sys_close_range(open_fds[51], open_fds[92],
+                                     CLOSE_RANGE_UNSHARE);
+               if (ret)
+                       exit(EXIT_FAILURE);
+
+               for (i = 51; i <= 92; i++)
+                       if (fcntl(open_fds[i], F_GETFL) != -1)
+                               exit(EXIT_FAILURE);
+
+               for (i = 93; i <= 100; i++)
+                       if (fcntl(open_fds[i], F_GETFL) == -1)
+                               exit(EXIT_FAILURE);
+
+               /* test that the kernel caps and still closes all fds */
+               ret = sys_close_range(open_fds[93], open_fds[99],
+                                     CLOSE_RANGE_UNSHARE);
+               if (ret)
+                       exit(EXIT_FAILURE);
+
+               for (i = 93; i <= 99; i++)
+                       if (fcntl(open_fds[i], F_GETFL) != -1)
+                               exit(EXIT_FAILURE);
+
+               if (fcntl(open_fds[100], F_GETFL) == -1)
+                       exit(EXIT_FAILURE);
+
+               ret = sys_close_range(open_fds[100], open_fds[100],
+                                     CLOSE_RANGE_UNSHARE);
+               if (ret)
+                       exit(EXIT_FAILURE);
+
+               if (fcntl(open_fds[100], F_GETFL) != -1)
+                       exit(EXIT_FAILURE);
+
+               exit(EXIT_SUCCESS);
+       }
+
+       EXPECT_EQ(waitpid(pid, &status, 0), pid);
+       EXPECT_EQ(true, WIFEXITED(status));
+       EXPECT_EQ(0, WEXITSTATUS(status));
+}
+
+TEST(close_range_unshare_capped)
+{
+       int i, ret, status;
+       pid_t pid;
+       int open_fds[101];
+       struct clone_args args = {
+               .flags = CLONE_FILES,
+               .exit_signal = SIGCHLD,
+       };
+
+       for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
+               int fd;
+
+               fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
+               ASSERT_GE(fd, 0) {
+                       if (errno == ENOENT)
+                               XFAIL(return, "Skipping test since /dev/null does not exist");
+               }
+
+               open_fds[i] = fd;
+       }
+
+       pid = sys_clone3(&args, sizeof(args));
+       ASSERT_GE(pid, 0);
+
+       if (pid == 0) {
+               ret = sys_close_range(open_fds[0], UINT_MAX,
+                                     CLOSE_RANGE_UNSHARE);
+               if (ret)
+                       exit(EXIT_FAILURE);
+
+               for (i = 0; i <= 100; i++)
+                       if (fcntl(open_fds[i], F_GETFL) != -1)
+                               exit(EXIT_FAILURE);
+
+               exit(EXIT_SUCCESS);
+       }
+
+       EXPECT_EQ(waitpid(pid, &status, 0), pid);
+       EXPECT_EQ(true, WIFEXITED(status));
+       EXPECT_EQ(0, WEXITSTATUS(status));
+}
+
 TEST_HARNESS_MAIN