1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or https://opensource.org/licenses/CDDL-1.0. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 #include <stdio.h> 23 #include <unistd.h> 24 #include <string.h> 25 #include <limits.h> 26 #include <sys/types.h> 27 #include <sys/types.h> 28 #include <sys/socket.h> 29 #include <sys/wait.h> 30 #include <fcntl.h> 31 #include <errno.h> 32 #include <signal.h> 33 #include <sched.h> 34 35 #define EXECSHELL "/bin/sh" 36 #define UIDMAP "0 100000 65536" 37 38 static int 39 child_main(int argc, char *argv[], int sync_pipe) 40 { 41 char sync_buf; 42 char cmds[BUFSIZ] = { 0 }; 43 char sep[] = " "; 44 int i, len; 45 46 if (unshare(CLONE_NEWUSER | CLONE_NEWNS) != 0) { 47 perror("unshare"); 48 return (1); 49 } 50 51 /* tell parent we entered the new namespace */ 52 if (write(sync_pipe, "1", 1) != 1) { 53 perror("write"); 54 return (1); 55 } 56 57 /* wait for parent to setup the uid mapping */ 58 if (read(sync_pipe, &sync_buf, 1) != 1) { 59 (void) fprintf(stderr, "user namespace setup failed\n"); 60 return (1); 61 } 62 63 close(sync_pipe); 64 65 if (setuid(0) != 0) { 66 perror("setuid"); 67 return (1); 68 } 69 if (setgid(0) != 0) { 70 perror("setgid"); 71 return (1); 72 } 73 74 len = 0; 75 for (i = 1; i < argc; i++) { 76 (void) snprintf(cmds+len, sizeof (cmds)-len, 77 "%s%s", argv[i], sep); 78 len += strlen(argv[i]) + strlen(sep); 79 } 80 81 if (execl(EXECSHELL, "sh", "-c", cmds, (char *)NULL) != 0) { 82 perror("execl: " EXECSHELL); 83 return (1); 84 } 85 86 return (0); 87 } 88 89 static int 90 set_idmap(pid_t pid, const char *file) 91 { 92 int result = 0; 93 int mapfd; 94 char path[PATH_MAX]; 95 96 (void) snprintf(path, sizeof (path), "/proc/%d/%s", (int)pid, file); 97 98 mapfd = open(path, O_WRONLY); 99 if (mapfd < 0) { 100 result = errno; 101 perror("open"); 102 return (errno); 103 } 104 105 if (write(mapfd, UIDMAP, sizeof (UIDMAP)-1) != sizeof (UIDMAP)-1) { 106 perror("write"); 107 result = (errno); 108 } 109 110 close(mapfd); 111 112 return (result); 113 } 114 115 int 116 main(int argc, char *argv[]) 117 { 118 char sync_buf; 119 int result, wstatus; 120 int syncfd[2]; 121 pid_t child; 122 123 if (argc < 2 || strlen(argv[1]) == 0) { 124 (void) printf("\tUsage: %s <commands> ...\n", argv[0]); 125 return (1); 126 } 127 128 if (socketpair(AF_UNIX, SOCK_STREAM, 0, syncfd) != 0) { 129 perror("socketpair"); 130 return (1); 131 } 132 133 child = fork(); 134 if (child == (pid_t)-1) { 135 perror("fork"); 136 return (1); 137 } 138 139 if (child == 0) { 140 close(syncfd[0]); 141 return (child_main(argc, argv, syncfd[1])); 142 } 143 144 close(syncfd[1]); 145 146 result = 0; 147 /* wait for the child to have unshared its namespaces */ 148 if (read(syncfd[0], &sync_buf, 1) != 1) { 149 perror("read"); 150 kill(child, SIGKILL); 151 result = 1; 152 goto reap; 153 } 154 155 /* write uid mapping */ 156 if (set_idmap(child, "uid_map") != 0 || 157 set_idmap(child, "gid_map") != 0) { 158 result = 1; 159 kill(child, SIGKILL); 160 goto reap; 161 } 162 163 /* tell the child to proceed */ 164 if (write(syncfd[0], "1", 1) != 1) { 165 perror("write"); 166 kill(child, SIGKILL); 167 result = 1; 168 goto reap; 169 } 170 close(syncfd[0]); 171 172 reap: 173 while (waitpid(child, &wstatus, 0) != child) 174 kill(child, SIGKILL); 175 if (result == 0) 176 result = WEXITSTATUS(wstatus); 177 178 return (result); 179 } 180