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 perror("open"); 101 return (errno); 102 } 103 104 if (write(mapfd, UIDMAP, sizeof (UIDMAP)-1) != sizeof (UIDMAP)-1) { 105 perror("write"); 106 result = (errno); 107 } 108 109 close(mapfd); 110 111 return (result); 112 } 113 114 int 115 main(int argc, char *argv[]) 116 { 117 char sync_buf; 118 int result, wstatus; 119 int syncfd[2]; 120 pid_t child; 121 122 if (argc < 2 || strlen(argv[1]) == 0) { 123 (void) printf("\tUsage: %s <commands> ...\n", argv[0]); 124 return (1); 125 } 126 127 if (socketpair(AF_UNIX, SOCK_STREAM, 0, syncfd) != 0) { 128 perror("socketpair"); 129 return (1); 130 } 131 132 child = fork(); 133 if (child == (pid_t)-1) { 134 perror("fork"); 135 return (1); 136 } 137 138 if (child == 0) { 139 close(syncfd[0]); 140 return (child_main(argc, argv, syncfd[1])); 141 } 142 143 close(syncfd[1]); 144 145 result = 0; 146 /* wait for the child to have unshared its namespaces */ 147 if (read(syncfd[0], &sync_buf, 1) != 1) { 148 perror("read"); 149 kill(child, SIGKILL); 150 result = 1; 151 goto reap; 152 } 153 154 /* write uid mapping */ 155 if (set_idmap(child, "uid_map") != 0 || 156 set_idmap(child, "gid_map") != 0) { 157 result = 1; 158 kill(child, SIGKILL); 159 goto reap; 160 } 161 162 /* tell the child to proceed */ 163 if (write(syncfd[0], "1", 1) != 1) { 164 perror("write"); 165 kill(child, SIGKILL); 166 result = 1; 167 goto reap; 168 } 169 close(syncfd[0]); 170 171 reap: 172 while (waitpid(child, &wstatus, 0) != child) 173 kill(child, SIGKILL); 174 if (result == 0) 175 result = WEXITSTATUS(wstatus); 176 177 return (result); 178 } 179