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