diff options
author | Andrey Vagin <avagin@openvz.org> | 2016-09-06 03:47:16 -0400 |
---|---|---|
committer | Eric W. Biederman <ebiederm@xmission.com> | 2016-09-22 20:59:41 -0400 |
commit | 6ad92bf63e45f97e306da48cd1cbce6e4fef1e5d (patch) | |
tree | 3a880aea3a869f8ee5261704a7ca5e6f6983db17 | |
parent | a7306ed8d94af729ecef8b6e37506a1c6fc14788 (diff) |
tools/testing: add a test to check nsfs ioctl-s
There are two new ioctl-s:
One ioctl for the user namespace that owns a file descriptor.
One ioctl for the parent namespace of a namespace file descriptor.
The test checks that these ioctl-s works and that they handle a case
when a target namespace is outside of the current process namespace.
Signed-off-by: Andrei Vagin <avagin@openvz.org>
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
-rw-r--r-- | tools/testing/selftests/Makefile | 1 | ||||
-rw-r--r-- | tools/testing/selftests/nsfs/Makefile | 12 | ||||
-rw-r--r-- | tools/testing/selftests/nsfs/owner.c | 91 | ||||
-rw-r--r-- | tools/testing/selftests/nsfs/pidns.c | 78 |
4 files changed, 182 insertions, 0 deletions
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index ff9e5f20a5a7..f770dba2a6f6 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile | |||
@@ -15,6 +15,7 @@ TARGETS += memory-hotplug | |||
15 | TARGETS += mount | 15 | TARGETS += mount |
16 | TARGETS += mqueue | 16 | TARGETS += mqueue |
17 | TARGETS += net | 17 | TARGETS += net |
18 | TARGETS += nsfs | ||
18 | TARGETS += powerpc | 19 | TARGETS += powerpc |
19 | TARGETS += pstore | 20 | TARGETS += pstore |
20 | TARGETS += ptrace | 21 | TARGETS += ptrace |
diff --git a/tools/testing/selftests/nsfs/Makefile b/tools/testing/selftests/nsfs/Makefile new file mode 100644 index 000000000000..2306054a901a --- /dev/null +++ b/tools/testing/selftests/nsfs/Makefile | |||
@@ -0,0 +1,12 @@ | |||
1 | TEST_PROGS := owner pidns | ||
2 | |||
3 | CFLAGS := -Wall -Werror | ||
4 | |||
5 | all: owner pidns | ||
6 | owner: owner.c | ||
7 | pidns: pidns.c | ||
8 | |||
9 | clean: | ||
10 | $(RM) owner pidns | ||
11 | |||
12 | include ../lib.mk | ||
diff --git a/tools/testing/selftests/nsfs/owner.c b/tools/testing/selftests/nsfs/owner.c new file mode 100644 index 000000000000..437205f8b714 --- /dev/null +++ b/tools/testing/selftests/nsfs/owner.c | |||
@@ -0,0 +1,91 @@ | |||
1 | #define _GNU_SOURCE | ||
2 | #include <sched.h> | ||
3 | #include <unistd.h> | ||
4 | #include <stdio.h> | ||
5 | #include <stdlib.h> | ||
6 | #include <signal.h> | ||
7 | #include <errno.h> | ||
8 | #include <sys/types.h> | ||
9 | #include <sys/stat.h> | ||
10 | #include <fcntl.h> | ||
11 | #include <sys/ioctl.h> | ||
12 | #include <sys/prctl.h> | ||
13 | #include <sys/wait.h> | ||
14 | |||
15 | #define NSIO 0xb7 | ||
16 | #define NS_GET_USERNS _IO(NSIO, 0x1) | ||
17 | |||
18 | #define pr_err(fmt, ...) \ | ||
19 | ({ \ | ||
20 | fprintf(stderr, "%s:%d:" fmt ": %m\n", \ | ||
21 | __func__, __LINE__, ##__VA_ARGS__); \ | ||
22 | 1; \ | ||
23 | }) | ||
24 | |||
25 | int main(int argc, char *argvp[]) | ||
26 | { | ||
27 | int pfd[2], ns, uns, init_uns; | ||
28 | struct stat st1, st2; | ||
29 | char path[128]; | ||
30 | pid_t pid; | ||
31 | char c; | ||
32 | |||
33 | if (pipe(pfd)) | ||
34 | return 1; | ||
35 | |||
36 | pid = fork(); | ||
37 | if (pid < 0) | ||
38 | return pr_err("fork"); | ||
39 | if (pid == 0) { | ||
40 | prctl(PR_SET_PDEATHSIG, SIGKILL); | ||
41 | if (unshare(CLONE_NEWUTS | CLONE_NEWUSER)) | ||
42 | return pr_err("unshare"); | ||
43 | close(pfd[0]); | ||
44 | close(pfd[1]); | ||
45 | while (1) | ||
46 | sleep(1); | ||
47 | return 0; | ||
48 | } | ||
49 | close(pfd[1]); | ||
50 | if (read(pfd[0], &c, 1) != 0) | ||
51 | return pr_err("Unable to read from pipe"); | ||
52 | close(pfd[0]); | ||
53 | |||
54 | snprintf(path, sizeof(path), "/proc/%d/ns/uts", pid); | ||
55 | ns = open(path, O_RDONLY); | ||
56 | if (ns < 0) | ||
57 | return pr_err("Unable to open %s", path); | ||
58 | |||
59 | uns = ioctl(ns, NS_GET_USERNS); | ||
60 | if (uns < 0) | ||
61 | return pr_err("Unable to get an owning user namespace"); | ||
62 | |||
63 | if (fstat(uns, &st1)) | ||
64 | return pr_err("fstat"); | ||
65 | |||
66 | snprintf(path, sizeof(path), "/proc/%d/ns/user", pid); | ||
67 | if (stat(path, &st2)) | ||
68 | return pr_err("stat"); | ||
69 | |||
70 | if (st1.st_ino != st2.st_ino) | ||
71 | return pr_err("NS_GET_USERNS returned a wrong namespace"); | ||
72 | |||
73 | init_uns = ioctl(uns, NS_GET_USERNS); | ||
74 | if (uns < 0) | ||
75 | return pr_err("Unable to get an owning user namespace"); | ||
76 | |||
77 | if (ioctl(init_uns, NS_GET_USERNS) >= 0 || errno != EPERM) | ||
78 | return pr_err("Don't get EPERM"); | ||
79 | |||
80 | if (unshare(CLONE_NEWUSER)) | ||
81 | return pr_err("unshare"); | ||
82 | |||
83 | if (ioctl(ns, NS_GET_USERNS) >= 0 || errno != EPERM) | ||
84 | return pr_err("Don't get EPERM"); | ||
85 | if (ioctl(init_uns, NS_GET_USERNS) >= 0 || errno != EPERM) | ||
86 | return pr_err("Don't get EPERM"); | ||
87 | |||
88 | kill(pid, SIGKILL); | ||
89 | wait(NULL); | ||
90 | return 0; | ||
91 | } | ||
diff --git a/tools/testing/selftests/nsfs/pidns.c b/tools/testing/selftests/nsfs/pidns.c new file mode 100644 index 000000000000..ae3a0d68e966 --- /dev/null +++ b/tools/testing/selftests/nsfs/pidns.c | |||
@@ -0,0 +1,78 @@ | |||
1 | #define _GNU_SOURCE | ||
2 | #include <sched.h> | ||
3 | #include <unistd.h> | ||
4 | #include <stdio.h> | ||
5 | #include <stdlib.h> | ||
6 | #include <signal.h> | ||
7 | #include <errno.h> | ||
8 | #include <sys/types.h> | ||
9 | #include <sys/stat.h> | ||
10 | #include <fcntl.h> | ||
11 | #include <sys/ioctl.h> | ||
12 | #include <sys/prctl.h> | ||
13 | #include <sys/wait.h> | ||
14 | |||
15 | #define pr_err(fmt, ...) \ | ||
16 | ({ \ | ||
17 | fprintf(stderr, "%s:%d:" fmt ": %m\n", \ | ||
18 | __func__, __LINE__, ##__VA_ARGS__); \ | ||
19 | 1; \ | ||
20 | }) | ||
21 | |||
22 | #define NSIO 0xb7 | ||
23 | #define NS_GET_USERNS _IO(NSIO, 0x1) | ||
24 | #define NS_GET_PARENT _IO(NSIO, 0x2) | ||
25 | |||
26 | #define __stack_aligned__ __attribute__((aligned(16))) | ||
27 | struct cr_clone_arg { | ||
28 | char stack[128] __stack_aligned__; | ||
29 | char stack_ptr[0]; | ||
30 | }; | ||
31 | |||
32 | static int child(void *args) | ||
33 | { | ||
34 | prctl(PR_SET_PDEATHSIG, SIGKILL); | ||
35 | while (1) | ||
36 | sleep(1); | ||
37 | exit(0); | ||
38 | } | ||
39 | |||
40 | int main(int argc, char *argv[]) | ||
41 | { | ||
42 | char *ns_strs[] = {"pid", "user"}; | ||
43 | char path[] = "/proc/0123456789/ns/pid"; | ||
44 | struct cr_clone_arg ca; | ||
45 | struct stat st1, st2; | ||
46 | int ns, pns, i; | ||
47 | pid_t pid; | ||
48 | |||
49 | pid = clone(child, ca.stack_ptr, CLONE_NEWUSER | CLONE_NEWPID | SIGCHLD, NULL); | ||
50 | if (pid < 0) | ||
51 | return pr_err("clone"); | ||
52 | |||
53 | for (i = 0; i < 2; i++) { | ||
54 | snprintf(path, sizeof(path), "/proc/%d/ns/%s", pid, ns_strs[i]); | ||
55 | ns = open(path, O_RDONLY); | ||
56 | if (ns < 0) | ||
57 | return pr_err("Unable to open %s", path); | ||
58 | |||
59 | pns = ioctl(ns, NS_GET_PARENT); | ||
60 | if (pns < 0) | ||
61 | return pr_err("Unable to get a parent pidns"); | ||
62 | |||
63 | snprintf(path, sizeof(path), "/proc/self/ns/%s", ns_strs[i]); | ||
64 | if (stat(path, &st2)) | ||
65 | return pr_err("Unable to stat %s", path); | ||
66 | if (fstat(pns, &st1)) | ||
67 | return pr_err("Unable to stat the parent pidns"); | ||
68 | if (st1.st_ino != st2.st_ino) | ||
69 | return pr_err("NS_GET_PARENT returned a wrong namespace"); | ||
70 | |||
71 | if (ioctl(pns, NS_GET_PARENT) >= 0 || errno != EPERM) | ||
72 | return pr_err("Don't get EPERM");; | ||
73 | } | ||
74 | |||
75 | kill(pid, SIGKILL); | ||
76 | wait(NULL); | ||
77 | return 0; | ||
78 | } | ||