1 /*
2 * Check decoding of NS_* commands of ioctl syscall.
3 *
4 * Copyright (c) 2017 Nikolay Marchuk <marchuk.nikolay.a@gmail.com>
5 * Copyright (c) 2017-2021 The strace developers.
6 * All rights reserved.
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include "tests.h"
12
13 #include <fcntl.h>
14 #include <sched.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <sys/ioctl.h>
18 #include <sys/wait.h>
19 #include <unistd.h>
20 #include <linux/nsfs.h>
21
22 #ifndef CLONE_NEWUSER
23 # define CLONE_NEWUSER 0x10000000
24 #endif
25
26 static void
27 test_no_namespace(void)
28 {
29 ioctl(-1, NS_GET_USERNS);
30 printf("ioctl(-1, NS_GET_USERNS) = -1 EBADF (%m)\n");
31 ioctl(-1, NS_GET_PARENT);
32 printf("ioctl(-1, NS_GET_PARENT) = -1 EBADF (%m)\n");
33 ioctl(-1, NS_GET_NSTYPE);
34 printf("ioctl(-1, NS_GET_NSTYPE) = -1 EBADF (%m)\n");
35 ioctl(-1, NS_GET_OWNER_UID, NULL);
36 printf("ioctl(-1, NS_GET_OWNER_UID, NULL) = -1 EBADF (%m)\n");
37 }
38
39 static void
40 test_clone(pid_t pid)
41 {
42 char path[sizeof("/proc/%d/ns/user") + sizeof(int)*3];
43 snprintf(path, sizeof(path), "/proc/%d/ns/user", pid);
44
45 int ns_fd = open(path, O_RDONLY);
46 if (ns_fd == -1)
47 perror_msg_and_skip("open: %s", path);
48
49 int userns_fd = ioctl(ns_fd, NS_GET_USERNS);
50 printf("ioctl(%d, NS_GET_USERNS) = %s\n", ns_fd, sprintrc(userns_fd));
51
52 int parent_ns_fd = ioctl(userns_fd, NS_GET_PARENT);
53 printf("ioctl(%d, NS_GET_PARENT) = %s\n",
54 userns_fd, sprintrc(parent_ns_fd));
55
56 int nstype = ioctl(userns_fd, NS_GET_NSTYPE);
57 if (nstype == -1) {
58 printf("ioctl(%d, NS_GET_NSTYPE) = %s\n",
59 userns_fd, sprintrc(nstype));
60 } else {
61 printf("ioctl(%d, NS_GET_NSTYPE) = %d (CLONE_NEWUSER)\n",
62 userns_fd, nstype);
63 }
64
65 TAIL_ALLOC_OBJECT_CONST_PTR(unsigned int, uid);
66 int rc = ioctl(userns_fd, NS_GET_OWNER_UID, uid);
67 if (rc == -1) {
68 printf("ioctl(%d, NS_GET_OWNER_UID, %p) = %s\n",
69 userns_fd, uid, sprintrc(rc));
70 } else {
71 printf("ioctl(%d, NS_GET_OWNER_UID, [%u]) = %d\n",
72 userns_fd, *uid, rc);
73 }
74 }
75
76 static int
77 child(void *arg)
78 {
79 int *pipefd = (int *) arg;
80 close(pipefd[1]);
81 /* Wait for EOF from pipe. */
82 if (read(pipefd[0], &pipefd[1], 1))
83 perror_msg_and_fail("read");
84 return 0;
85 }
86
87 #ifdef IA64
88 extern int __clone2(int (*)(void *), void *, size_t, int, void *, ...);
89 # define do_clone(fn_, stack_, size_, flags_, arg_, ...) \
90 __clone2((fn_), (stack_), (size_), (flags_), (arg_), ## __VA_ARGS__)
91 #else
92 # define do_clone(fn_, stack_, size_, flags_, arg_, ...) \
93 clone((fn_), (stack_), (flags_), (arg_), ## __VA_ARGS__)
94 #endif
95
96 static void
97 test_user_namespace(void)
98 {
99 int pipefd[2];
100 if (pipe(pipefd))
101 perror_msg_and_fail("pipe");
102
103 const unsigned long child_stack_size = get_page_size();
104 void *const child_stack =
105 tail_alloc(child_stack_size * 2) + child_stack_size;
106
107 const pid_t pid = do_clone(child, child_stack, child_stack_size,
108 CLONE_NEWUSER | CLONE_UNTRACED | SIGCHLD,
109 pipefd);
110 if (pid == -1) {
111 perror("clone");
112 return;
113 }
114 close(pipefd[0]);
115 test_clone(pid);
116 close(pipefd[1]);
117
118 int status;
119 if (wait(&status) != pid) {
120 perror_msg_and_fail("wait");
121 } else if (status != 0) {
122 error_msg_and_fail("unexpected child exit status %d", status);
123 }
124 }
125
126 int
127 main(void)
128 {
129 test_no_namespace();
130 test_user_namespace();
131 puts("+++ exited with 0 +++");
132 return 0;
133 }