xref: /freebsd/sys/contrib/openzfs/tests/zfs-tests/cmd/user_ns_exec.c (revision dbd5678dca91abcefe8d046aa2f9b66497a95ffb)
1716fd348SMartin Matuska /*
2716fd348SMartin Matuska  * CDDL HEADER START
3716fd348SMartin Matuska  *
4716fd348SMartin Matuska  * The contents of this file are subject to the terms of the
5716fd348SMartin Matuska  * Common Development and Distribution License (the "License").
6716fd348SMartin Matuska  * You may not use this file except in compliance with the License.
7716fd348SMartin Matuska  *
8716fd348SMartin Matuska  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*271171e0SMartin Matuska  * or https://opensource.org/licenses/CDDL-1.0.
10716fd348SMartin Matuska  * See the License for the specific language governing permissions
11716fd348SMartin Matuska  * and limitations under the License.
12716fd348SMartin Matuska  *
13716fd348SMartin Matuska  * When distributing Covered Code, include this CDDL HEADER in each
14716fd348SMartin Matuska  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15716fd348SMartin Matuska  * If applicable, add the following below this CDDL HEADER, with the
16716fd348SMartin Matuska  * fields enclosed by brackets "[]" replaced with your own identifying
17716fd348SMartin Matuska  * information: Portions Copyright [yyyy] [name of copyright owner]
18716fd348SMartin Matuska  *
19716fd348SMartin Matuska  * CDDL HEADER END
20716fd348SMartin Matuska  */
21716fd348SMartin Matuska 
22716fd348SMartin Matuska #include <stdio.h>
23716fd348SMartin Matuska #include <unistd.h>
24716fd348SMartin Matuska #include <string.h>
25716fd348SMartin Matuska #include <limits.h>
26716fd348SMartin Matuska #include <sys/types.h>
27716fd348SMartin Matuska #include <sys/types.h>
28716fd348SMartin Matuska #include <sys/socket.h>
29716fd348SMartin Matuska #include <sys/wait.h>
30716fd348SMartin Matuska #include <fcntl.h>
31716fd348SMartin Matuska #include <errno.h>
32716fd348SMartin Matuska #include <signal.h>
33716fd348SMartin Matuska #include <sched.h>
34716fd348SMartin Matuska 
35716fd348SMartin Matuska #define	EXECSHELL	"/bin/sh"
36716fd348SMartin Matuska #define	UIDMAP		"0 100000 65536"
37716fd348SMartin Matuska 
38716fd348SMartin Matuska static int
child_main(int argc,char * argv[],int sync_pipe)39716fd348SMartin Matuska child_main(int argc, char *argv[], int sync_pipe)
40716fd348SMartin Matuska {
41716fd348SMartin Matuska 	char sync_buf;
42716fd348SMartin Matuska 	char cmds[BUFSIZ] = { 0 };
43716fd348SMartin Matuska 	char sep[] = " ";
44716fd348SMartin Matuska 	int i, len;
45716fd348SMartin Matuska 
46716fd348SMartin Matuska 	if (unshare(CLONE_NEWUSER | CLONE_NEWNS) != 0) {
47716fd348SMartin Matuska 		perror("unshare");
48716fd348SMartin Matuska 		return (1);
49716fd348SMartin Matuska 	}
50716fd348SMartin Matuska 
51716fd348SMartin Matuska 	/* tell parent we entered the new namespace */
52716fd348SMartin Matuska 	if (write(sync_pipe, "1", 1) != 1) {
53716fd348SMartin Matuska 		perror("write");
54716fd348SMartin Matuska 		return (1);
55716fd348SMartin Matuska 	}
56716fd348SMartin Matuska 
57716fd348SMartin Matuska 	/* wait for parent to setup the uid mapping */
58716fd348SMartin Matuska 	if (read(sync_pipe, &sync_buf, 1) != 1) {
59716fd348SMartin Matuska 		(void) fprintf(stderr, "user namespace setup failed\n");
60716fd348SMartin Matuska 		return (1);
61716fd348SMartin Matuska 	}
62716fd348SMartin Matuska 
63716fd348SMartin Matuska 	close(sync_pipe);
64716fd348SMartin Matuska 
65716fd348SMartin Matuska 	if (setuid(0) != 0) {
66716fd348SMartin Matuska 		perror("setuid");
67716fd348SMartin Matuska 		return (1);
68716fd348SMartin Matuska 	}
69716fd348SMartin Matuska 	if (setgid(0) != 0) {
70716fd348SMartin Matuska 		perror("setgid");
71716fd348SMartin Matuska 		return (1);
72716fd348SMartin Matuska 	}
73716fd348SMartin Matuska 
74716fd348SMartin Matuska 	len = 0;
75716fd348SMartin Matuska 	for (i = 1; i < argc; i++) {
76716fd348SMartin Matuska 		(void) snprintf(cmds+len, sizeof (cmds)-len,
77716fd348SMartin Matuska 		    "%s%s", argv[i], sep);
78716fd348SMartin Matuska 		len += strlen(argv[i]) + strlen(sep);
79716fd348SMartin Matuska 	}
80716fd348SMartin Matuska 
81716fd348SMartin Matuska 	if (execl(EXECSHELL, "sh",  "-c", cmds, (char *)NULL) != 0) {
82716fd348SMartin Matuska 		perror("execl: " EXECSHELL);
83716fd348SMartin Matuska 		return (1);
84716fd348SMartin Matuska 	}
85716fd348SMartin Matuska 
86716fd348SMartin Matuska 	return (0);
87716fd348SMartin Matuska }
88716fd348SMartin Matuska 
89716fd348SMartin Matuska static int
set_idmap(pid_t pid,const char * file)90716fd348SMartin Matuska set_idmap(pid_t pid, const char *file)
91716fd348SMartin Matuska {
92716fd348SMartin Matuska 	int result = 0;
93716fd348SMartin Matuska 	int mapfd;
94716fd348SMartin Matuska 	char path[PATH_MAX];
95716fd348SMartin Matuska 
96716fd348SMartin Matuska 	(void) snprintf(path, sizeof (path), "/proc/%d/%s", (int)pid, file);
97716fd348SMartin Matuska 
98716fd348SMartin Matuska 	mapfd = open(path, O_WRONLY);
99716fd348SMartin Matuska 	if (mapfd < 0) {
100716fd348SMartin Matuska 		perror("open");
101716fd348SMartin Matuska 		return (errno);
102716fd348SMartin Matuska 	}
103716fd348SMartin Matuska 
104716fd348SMartin Matuska 	if (write(mapfd, UIDMAP, sizeof (UIDMAP)-1) != sizeof (UIDMAP)-1) {
105716fd348SMartin Matuska 		perror("write");
106716fd348SMartin Matuska 		result = (errno);
107716fd348SMartin Matuska 	}
108716fd348SMartin Matuska 
109716fd348SMartin Matuska 	close(mapfd);
110716fd348SMartin Matuska 
111716fd348SMartin Matuska 	return (result);
112716fd348SMartin Matuska }
113716fd348SMartin Matuska 
114716fd348SMartin Matuska int
main(int argc,char * argv[])115716fd348SMartin Matuska main(int argc, char *argv[])
116716fd348SMartin Matuska {
117716fd348SMartin Matuska 	char sync_buf;
118716fd348SMartin Matuska 	int result, wstatus;
119716fd348SMartin Matuska 	int syncfd[2];
120716fd348SMartin Matuska 	pid_t child;
121716fd348SMartin Matuska 
122716fd348SMartin Matuska 	if (argc < 2 || strlen(argv[1]) == 0) {
123716fd348SMartin Matuska 		(void) printf("\tUsage: %s <commands> ...\n", argv[0]);
124716fd348SMartin Matuska 		return (1);
125716fd348SMartin Matuska 	}
126716fd348SMartin Matuska 
127716fd348SMartin Matuska 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, syncfd) != 0) {
128716fd348SMartin Matuska 		perror("socketpair");
129716fd348SMartin Matuska 		return (1);
130716fd348SMartin Matuska 	}
131716fd348SMartin Matuska 
132716fd348SMartin Matuska 	child = fork();
133716fd348SMartin Matuska 	if (child == (pid_t)-1) {
134716fd348SMartin Matuska 		perror("fork");
135716fd348SMartin Matuska 		return (1);
136716fd348SMartin Matuska 	}
137716fd348SMartin Matuska 
138716fd348SMartin Matuska 	if (child == 0) {
139716fd348SMartin Matuska 		close(syncfd[0]);
140716fd348SMartin Matuska 		return (child_main(argc, argv, syncfd[1]));
141716fd348SMartin Matuska 	}
142716fd348SMartin Matuska 
143716fd348SMartin Matuska 	close(syncfd[1]);
144716fd348SMartin Matuska 
145716fd348SMartin Matuska 	result = 0;
146716fd348SMartin Matuska 	/* wait for the child to have unshared its namespaces */
147716fd348SMartin Matuska 	if (read(syncfd[0], &sync_buf, 1) != 1) {
148716fd348SMartin Matuska 		perror("read");
149716fd348SMartin Matuska 		kill(child, SIGKILL);
150716fd348SMartin Matuska 		result = 1;
151716fd348SMartin Matuska 		goto reap;
152716fd348SMartin Matuska 	}
153716fd348SMartin Matuska 
154716fd348SMartin Matuska 	/* write uid mapping */
155716fd348SMartin Matuska 	if (set_idmap(child, "uid_map") != 0 ||
156716fd348SMartin Matuska 	    set_idmap(child, "gid_map") != 0) {
157716fd348SMartin Matuska 		result = 1;
158716fd348SMartin Matuska 		kill(child, SIGKILL);
159716fd348SMartin Matuska 		goto reap;
160716fd348SMartin Matuska 	}
161716fd348SMartin Matuska 
162716fd348SMartin Matuska 	/* tell the child to proceed */
163716fd348SMartin Matuska 	if (write(syncfd[0], "1", 1) != 1) {
164716fd348SMartin Matuska 		perror("write");
165716fd348SMartin Matuska 		kill(child, SIGKILL);
166716fd348SMartin Matuska 		result = 1;
167716fd348SMartin Matuska 		goto reap;
168716fd348SMartin Matuska 	}
169716fd348SMartin Matuska 	close(syncfd[0]);
170716fd348SMartin Matuska 
171716fd348SMartin Matuska reap:
172716fd348SMartin Matuska 	while (waitpid(child, &wstatus, 0) != child)
173716fd348SMartin Matuska 		kill(child, SIGKILL);
174716fd348SMartin Matuska 	if (result == 0)
175716fd348SMartin Matuska 		result = WEXITSTATUS(wstatus);
176716fd348SMartin Matuska 
177716fd348SMartin Matuska 	return (result);
178716fd348SMartin Matuska }
179