this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'launchd'

+1052 -171
+1 -1
CMakeLists.txt
··· 37 37 install(DIRECTORY DESTINATION libexec/darling/private) 38 38 install(DIRECTORY DESTINATION libexec/darling/private/etc) 39 39 install(DIRECTORY DESTINATION libexec/darling/private/var) 40 + install(DIRECTORY DESTINATION libexec/darling/private/tmp) 40 41 InstallSymlink(private/etc ${CMAKE_INSTALL_PREFIX}/libexec/darling/etc) 41 42 InstallSymlink(private/var ${CMAKE_INSTALL_PREFIX}/libexec/darling/var) 42 - InstallSymlink(private/tmp ${CMAKE_INSTALL_PREFIX}/libexec/darling/tmp) 43 43 44 44 install(FILES etc/dylib.conf etc/version.conf 45 45 DESTINATION libexec/darling/etc/darling)
+2 -1
platform-include/xpc/xpc.h
··· 105 105 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0) 106 106 XPC_EXPORT 107 107 XPC_TYPE(_xpc_type_connection); 108 - XPC_DECL(xpc_connection); 108 + //XPC_DECL(xpc_connection); 109 + typedef xpc_object_t xpc_connection_t; 109 110 110 111 /*! 111 112 * @typedef xpc_connection_handler_t
+1
src/CMakeLists.txt
··· 204 204 add_subdirectory(external/python/2.7/Python-2.7.10) 205 205 add_subdirectory(external/ruby) 206 206 add_subdirectory(external/expat) 207 + add_subdirectory(shellspawn) 207 208 #add_subdirectory(external/libauto) 208 209 add_subdirectory(external/libarchive/libarchive) 209 210 add_subdirectory(external/apr)
+1
src/kernel/emulation/linux/CMakeLists.txt
··· 210 210 ioctl/socket.c 211 211 ext/sysinfo.c 212 212 ext/uname.c 213 + ext/nanosleep.c 213 214 ext/epoll_create.c 214 215 ext/epoll_create1.c 215 216 ext/epoll_ctl.c
+5 -7
src/kernel/emulation/linux/bsdthread/workq_kernreturn.c
··· 7 7 #include "../../../../startup/threads.h" 8 8 #include <linux-syscalls/linux.h> 9 9 #include <stddef.h> 10 + #include <pthread/tsd_private.h> 10 11 #include "../ext/futex.h" 11 12 #include "../simple.h" 12 13 ··· 41 42 42 43 struct parked_thread workq_parked_head = { NULL, NULL }; 43 44 44 - extern int thread_self_trap(void); 45 - 46 45 extern void* pthread_get_stackaddr_np(void* pth); 47 - extern void* memmove(void* dest, const void* src, __SIZE_TYPE__ n); 48 46 49 47 static void list_add(struct parked_thread* head, struct parked_thread* item); 50 48 static void list_remove(struct parked_thread* head, struct parked_thread* item); ··· 101 99 102 100 int thread_self; 103 101 struct parked_thread me; 104 - void* stack; 102 + void* pth; 105 103 106 104 sem_down(&workq_parked_lock, -1); 107 105 ··· 141 139 142 140 // reset stack and call entry point again with WQ_FLAG_THREAD_REUSE 143 141 thread_self = thread_self_trap(); 144 - stack = __darling_thread_get_stack(); 142 + pth = _pthread_getspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_SELF); 145 143 146 144 // __simple_printf("Thread %d woken up, prio=%d\n", thread_self, me.flags & WQ_FLAG_THREAD_PRIOMASK); 147 145 ··· 157 155 "xorq %%rcx, %%rcx\n" // 4th argument 158 156 "subq $32, %%rsp\n" 159 157 "jmpq *%2\n" 160 - :: "D" (stack), "S" (thread_self), "a" (wqueue_entry_point), 158 + :: "D" (pth), "S" (thread_self), "a" (wqueue_entry_point), 161 159 "b" (me.flags | WQ_FLAG_THREAD_REUSE), "c" (me.event ? me.event->events : NULL), 162 160 "r" (me.event ? me.event->nevents : 0) 163 161 ); ··· 169 167 "xorl %%edx, %%edx\n" 170 168 "subl $32, %%esp\n" 171 169 "jmpl *%2\n" 172 - :: "a" (stack), "b" (thread_self), "S" (wqueue_entry_point), 170 + :: "a" (pth), "b" (thread_self), "S" (wqueue_entry_point), 173 171 "D" (me.flags | WQ_FLAG_THREAD_REUSE), "d" (me.event ? me.event->events : NULL), 174 172 "S" (me.event ? me.event->nevents : 0) 175 173 );
+21
src/kernel/emulation/linux/ext/nanosleep.c
··· 1 + #include "sys/utsname.h" 2 + #include "../base.h" 3 + #include "../errno.h" 4 + #include <linux-syscalls/linux.h> 5 + 6 + extern void cerror(int e); 7 + 8 + int __linux_nanosleep(struct timespec* ts, struct timespec* rem) 9 + { 10 + int rv; 11 + 12 + rv = LINUX_SYSCALL(__NR_nanosleep, ts, rem); 13 + if (rv < 0) 14 + { 15 + cerror(errno_linux_to_bsd(-rv)); 16 + return -1; 17 + } 18 + 19 + return rv; 20 + } 21 +
+8 -2
src/kernel/emulation/linux/mach/mach_traps.c
··· 506 506 return 0; 507 507 } 508 508 509 + extern int __linux_nanosleep(struct timespec* tv, struct timespec* rem); 509 510 kern_return_t syscall_thread_switch_impl( 510 511 mach_port_name_t thread_name, 511 512 int option, 512 513 mach_msg_timeout_t option_time) 513 514 { 514 - UNIMPLEMENTED_TRAP(); 515 - return KERN_FAILURE; 515 + struct timespec tv = { 516 + .tv_sec = 0, 517 + .tv_nsec = 1000000 518 + }; 519 + // Sleep for 1ms 520 + __linux_nanosleep(&tv, &tv); 521 + return KERN_SUCCESS; 516 522 } 517 523 518 524 mach_port_name_t task_self_trap_impl(void)
+3 -3
src/kernel/emulation/linux/misc/proc_info.c
··· 169 169 info->p_puniqueid |= (ppid & 0xffff); 170 170 171 171 #endif 172 - return 0; 172 + return 1; 173 173 } 174 174 175 175 static long _proc_pidinfo_shortbsdinfo(int32_t pid, void* buffer, int32_t bufsize) ··· 262 262 } 263 263 } 264 264 265 - return 0; 265 + return 1; 266 266 reterr: 267 267 return -EINVAL; 268 268 } ··· 318 318 } 319 319 320 320 memcpy(buffer, &my_rpi, sizeof(my_rpi)); 321 - return foundRegion ? 0 : -ESRCH; 321 + return foundRegion ? 1 : -ESRCH; 322 322 } 323 323 324 324 // Parses line such as:
+11
src/shellspawn/CMakeLists.txt
··· 1 + project(shellspawn) 2 + 3 + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -nostdinc") 4 + 5 + include(darling_exe) 6 + 7 + add_darling_executable(shellspawn shellspawn.c duct_signals.c) 8 + 9 + install(TARGETS shellspawn DESTINATION libexec/darling/usr/libexec) 10 + install(FILES org.darlinghq.shellspawn.plist DESTINATION libexec/darling/System/Library/LaunchDaemons) 11 +
+71
src/shellspawn/duct_signals.c
··· 1 + #include <sys/signal.h> 2 + #include "duct_signals.h" 3 + 4 + int signum_linux_to_bsd(int signum) 5 + { 6 + switch (signum) 7 + { 8 + case LINUX_SIGHUP: 9 + return SIGHUP; 10 + case LINUX_SIGINT: 11 + return SIGINT; 12 + case LINUX_SIGQUIT: 13 + return SIGQUIT; 14 + case LINUX_SIGILL: 15 + return SIGILL; 16 + case LINUX_SIGTRAP: 17 + return SIGTRAP; 18 + case LINUX_SIGABRT: 19 + return SIGABRT; 20 + case LINUX_SIGFPE: 21 + return SIGFPE; 22 + case LINUX_SIGKILL: 23 + return SIGKILL; 24 + case LINUX_SIGBUS: 25 + return SIGBUS; 26 + case LINUX_SIGSEGV: 27 + return SIGSEGV; 28 + case LINUX_SIGSYS: 29 + return SIGSYS; 30 + case LINUX_SIGPIPE: 31 + return SIGPIPE; 32 + case LINUX_SIGALRM: 33 + return SIGALRM; 34 + case LINUX_SIGTERM: 35 + return SIGTERM; 36 + case LINUX_SIGURG: 37 + return SIGURG; 38 + case LINUX_SIGSTOP: 39 + return SIGSTOP; 40 + case LINUX_SIGTSTP: 41 + return SIGTSTP; 42 + case LINUX_SIGCONT: 43 + return SIGCONT; 44 + case LINUX_SIGCHLD: 45 + return SIGCHLD; 46 + case LINUX_SIGTTIN: 47 + return SIGTTIN; 48 + case LINUX_SIGTTOU: 49 + return SIGTTOU; 50 + case LINUX_SIGIO: 51 + return SIGIO; 52 + case LINUX_SIGXCPU: 53 + return SIGXCPU; 54 + case LINUX_SIGXFSZ: 55 + return SIGXFSZ; 56 + case LINUX_SIGVTALRM: 57 + return SIGVTALRM; 58 + case LINUX_SIGPROF: 59 + return SIGPROF; 60 + case LINUX_SIGWINCH: 61 + return SIGWINCH; 62 + case LINUX_SIGUSR1: 63 + return SIGUSR1; 64 + case LINUX_SIGUSR2: 65 + return SIGUSR2; 66 + default: 67 + return 0; 68 + } 69 + } 70 + 71 +
+54
src/shellspawn/duct_signals.h
··· 1 + #ifndef LINUX_DUCT_SIGNALS_H 2 + #define LINUX_DUCT_SIGNALS_H 3 + 4 + #define LINUX_NSIG 32 5 + #define LINUX_SIGHUP 1 6 + #define LINUX_SIGINT 2 7 + #define LINUX_SIGQUIT 3 8 + #define LINUX_SIGILL 4 9 + #define LINUX_SIGTRAP 5 10 + #define LINUX_SIGABRT 6 11 + #define LINUX_SIGIOT 6 12 + #define LINUX_SIGBUS 7 13 + #define LINUX_SIGFPE 8 14 + #define LINUX_SIGKILL 9 15 + #define LINUX_SIGUSR1 10 16 + #define LINUX_SIGSEGV 11 17 + #define LINUX_SIGUSR2 12 18 + #define LINUX_SIGPIPE 13 19 + #define LINUX_SIGALRM 14 20 + #define LINUX_SIGTERM 15 21 + #define LINUX_SIGSTKFLT 16 22 + #define LINUX_SIGCHLD 17 23 + #define LINUX_SIGCONT 18 24 + #define LINUX_SIGSTOP 19 25 + #define LINUX_SIGTSTP 20 26 + #define LINUX_SIGTTIN 21 27 + #define LINUX_SIGTTOU 22 28 + #define LINUX_SIGURG 23 29 + #define LINUX_SIGXCPU 24 30 + #define LINUX_SIGXFSZ 25 31 + #define LINUX_SIGVTALRM 26 32 + #define LINUX_SIGPROF 27 33 + #define LINUX_SIGWINCH 28 34 + #define LINUX_SIGIO 29 35 + #define LINUX_SIGLOST 29 36 + #define LINUX_SIGPWR 30 37 + #define LINUX_SIGSYS 31 38 + #define LINUX_SIGUNUSED 31 39 + #define LINUX_SIGRTMIN 32 40 + #define LINUX_SA_NOCLDSTOP 0x00000001u 41 + #define LINUX_SA_NOCLDWAIT 0x00000002u 42 + #define LINUX_SA_SIGINFO 0x00000004u 43 + #define LINUX_SA_ONSTACK 0x08000000u 44 + #define LINUX_SA_RESTART 0x10000000u 45 + #define LINUX_SA_NODEFER 0x40000000u 46 + #define LINUX_SA_RESETHAND 0x80000000u 47 + #define LINUX_SA_RESTORER 0x04000000 48 + #define LINUX_MINSIGSTKSZ 2048 49 + #define LINUX_SIGSTKSZ 8192 50 + 51 + int signum_linux_to_bsd(int signum); 52 + 53 + #endif 54 +
+17
src/shellspawn/org.darlinghq.shellspawn.plist
··· 1 + <?xml version="1.0" encoding="UTF-8"?> 2 + <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" 3 + "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 4 + <plist version="1.0"> 5 + <dict> 6 + <key>Label</key> 7 + <string>org.darlinghq.shellspawn</string> 8 + <key>ProgramArguments</key> 9 + <array> 10 + <string>/usr/libexec/shellspawn</string> 11 + </array> 12 + <key>RunAtLoad</key> 13 + <true/> 14 + <key>KeepAlive</key> 15 + <true/> 16 + </dict> 17 + </plist>
+402
src/shellspawn/shellspawn.c
··· 1 + /* 2 + This file is part of Darling. 3 + 4 + Copyright (C) 2017 Lubos Dolezel 5 + 6 + Darling is free software: you can redistribute it and/or modify 7 + it under the terms of the GNU General Public License as published by 8 + the Free Software Foundation, either version 3 of the License, or 9 + (at your option) any later version. 10 + 11 + Darling is distributed in the hope that it will be useful, 12 + but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + GNU General Public License for more details. 15 + 16 + You should have received a copy of the GNU General Public License 17 + along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #include <sys/socket.h> 21 + #include <sys/un.h> 22 + #include <sys/stat.h> 23 + #include <stdlib.h> 24 + #include <unistd.h> 25 + #include <fcntl.h> 26 + #include <stdbool.h> 27 + #include <string.h> 28 + #include <stdio.h> 29 + #include <errno.h> 30 + #include <sys/poll.h> 31 + #include <sys/types.h> 32 + #include <sys/wait.h> 33 + #include <sys/event.h> 34 + #include <sys/ioctl.h> 35 + #include <signal.h> 36 + #include "shellspawn.h" 37 + #include "duct_signals.h" 38 + 39 + #define DBG 0 40 + 41 + int g_serverSocket = -1; 42 + 43 + void setupSocket(void); 44 + void listenForConnections(void); 45 + void spawnShell(int fd); 46 + void setupSigchild(void); 47 + void reapAll(void); 48 + 49 + int main(int argc, const char** argv) 50 + { 51 + setupSigchild(); 52 + setupSocket(); 53 + listenForConnections(); 54 + 55 + if (g_serverSocket != -1) 56 + close(g_serverSocket); 57 + return 0; 58 + } 59 + 60 + void setupSocket(void) 61 + { 62 + struct sockaddr_un addr = { 63 + .sun_family = AF_UNIX, 64 + .sun_path = SHELLSPAWN_SOCKPATH 65 + }; 66 + 67 + g_serverSocket = socket(AF_UNIX, SOCK_STREAM, 0); 68 + if (g_serverSocket == -1) 69 + { 70 + perror("Creating unix socket"); 71 + exit(EXIT_FAILURE); 72 + } 73 + 74 + fcntl(g_serverSocket, F_SETFD, FD_CLOEXEC); 75 + unlink(SHELLSPAWN_SOCKPATH); 76 + 77 + if (bind(g_serverSocket, (struct sockaddr*) &addr, sizeof(addr)) == -1) 78 + { 79 + perror("Binding the unix socket"); 80 + exit(EXIT_FAILURE); 81 + } 82 + 83 + chmod(addr.sun_path, 0600); 84 + 85 + if (listen(g_serverSocket, 1) == -1) 86 + { 87 + perror("Listening on unix socket"); 88 + exit(EXIT_FAILURE); 89 + } 90 + } 91 + 92 + void listenForConnections(void) 93 + { 94 + int sock; 95 + struct sockaddr_un addr; 96 + socklen_t len = sizeof(addr); 97 + 98 + while (true) 99 + { 100 + sock = accept(g_serverSocket, (struct sockaddr*) &addr, &len); 101 + if (sock == -1) 102 + break; 103 + 104 + if (fork() == 0) 105 + { 106 + fcntl(sock, F_SETFD, FD_CLOEXEC); 107 + spawnShell(sock); 108 + exit(EXIT_SUCCESS); 109 + } 110 + else 111 + { 112 + close(sock); 113 + } 114 + } 115 + } 116 + 117 + void spawnShell(int fd) 118 + { 119 + pid_t shell_pid = -1; 120 + int shellfd[3] = { -1, -1, -1 }; 121 + int pipefd[2]; 122 + int rv; 123 + struct pollfd pfd[2]; 124 + char** argv = NULL; 125 + int argc = 1; 126 + struct msghdr msg; 127 + struct iovec iov; 128 + char cmsgbuf[CMSG_SPACE(sizeof(int)) * 3]; 129 + int kq; 130 + 131 + bool read_cmds = true; 132 + 133 + argv = (char**) malloc(sizeof(char*) * 2); 134 + argv[0] = "/bin/bash"; 135 + 136 + // Read commands from client 137 + while (read_cmds) 138 + { 139 + struct shellspawn_cmd cmd; 140 + char* param = NULL; 141 + 142 + memset(&msg, 0, sizeof(msg)); 143 + msg.msg_control = cmsgbuf; 144 + msg.msg_controllen = sizeof(cmsgbuf); 145 + 146 + iov.iov_base = &cmd; 147 + iov.iov_len = sizeof(cmd); 148 + msg.msg_iov = &iov; 149 + msg.msg_iovlen = 1; 150 + 151 + if (recvmsg(fd, &msg, 0) != sizeof(cmd)) 152 + { 153 + if (DBG) puts("bad recvmsg"); 154 + goto err; 155 + } 156 + 157 + if (cmd.data_length != 0) 158 + { 159 + param = (char*) malloc(cmd.data_length + 1); 160 + if (read(fd, param, cmd.data_length) != cmd.data_length) 161 + goto err; 162 + param[cmd.data_length] = '\0'; 163 + } 164 + 165 + switch (cmd.cmd) 166 + { 167 + case SHELLSPAWN_ADDARG: 168 + { 169 + if (param != NULL) 170 + { 171 + argv = (char**) realloc(argv, sizeof(char*) * (argc + 1)); 172 + argv[argc] = param; 173 + if (DBG) printf("add arg: %s\n", param); 174 + argc++; 175 + } 176 + break; 177 + } 178 + case SHELLSPAWN_SETENV: 179 + { 180 + if (param != NULL) 181 + { 182 + if (DBG) printf("set env: %s\n", param); 183 + putenv(param); 184 + free(param); 185 + } 186 + break; 187 + } 188 + case SHELLSPAWN_CHDIR: 189 + { 190 + if (param != NULL) 191 + { 192 + if (DBG) printf("chdir: %s\n", param); 193 + chdir(param); 194 + free(param); 195 + } 196 + break; 197 + } 198 + case SHELLSPAWN_GO: 199 + { 200 + struct cmsghdr *cmptr = CMSG_FIRSTHDR(&msg); 201 + 202 + if (cmptr == NULL) 203 + { 204 + if (DBG) puts("bad cmptr"); 205 + goto err; 206 + } 207 + if (cmptr->cmsg_level != SOL_SOCKET 208 + || cmptr->cmsg_type != SCM_RIGHTS) 209 + { 210 + if (DBG) puts("bad cmsg level/type"); 211 + goto err; 212 + } 213 + if (cmptr->cmsg_len != CMSG_LEN(sizeof(int) * 3)) 214 + { 215 + if (DBG) printf("bad cmsg_len: %d\n", cmptr->cmsg_len); 216 + goto err; 217 + } 218 + 219 + memcpy(shellfd, CMSG_DATA(cmptr), sizeof(int) * 3); 220 + 221 + if (DBG) printf("go, fds={ %d, %d, %d }\n", shellfd[0], shellfd[1], shellfd[2]); 222 + free(param); 223 + read_cmds = false; 224 + break; 225 + } 226 + } 227 + } 228 + 229 + // Add terminating NULL 230 + argv = (char**) realloc(argv, sizeof(char*) * (argc + 1)); 231 + argv[argc] = NULL; 232 + 233 + if (pipe(pipefd) == -1) 234 + goto err; 235 + 236 + setsid(); 237 + setpgrp(); 238 + 239 + close(STDIN_FILENO); 240 + close(STDOUT_FILENO); 241 + close(STDERR_FILENO); 242 + 243 + dup2(shellfd[0], STDIN_FILENO); 244 + dup2(shellfd[1], STDOUT_FILENO); 245 + dup2(shellfd[2], STDERR_FILENO); 246 + 247 + ioctl(STDIN_FILENO, TIOCSCTTY, STDIN_FILENO); 248 + 249 + shell_pid = fork(); 250 + if (shell_pid == 0) 251 + { 252 + close(fd); 253 + 254 + fcntl(pipefd[1], F_SETFD, FD_CLOEXEC); 255 + 256 + // In future, we may support spawning something else than Bash 257 + // and check the provided shell against /etc/shells 258 + execv("/bin/bash", argv); 259 + 260 + rv = errno; 261 + write(pipefd[1], &rv, sizeof(rv)); 262 + close(pipefd[1]); 263 + 264 + exit(EXIT_FAILURE); 265 + } 266 + 267 + // Check that exec succeeded 268 + close(pipefd[1]); // close the write end 269 + if (read(pipefd[0], &rv, sizeof(rv)) == sizeof(rv)) 270 + { 271 + errno = rv; 272 + goto err; 273 + } 274 + close(pipefd[0]); 275 + 276 + // Now we start passing signals 277 + // and check for child process exit 278 + 279 + kq = kqueue(); 280 + 281 + { 282 + struct kevent changes[2]; 283 + EV_SET(&changes[0], fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL); 284 + EV_SET(&changes[1], shell_pid, EVFILT_PROC, EV_ADD | EV_ENABLE, NOTE_EXIT, 0, NULL); 285 + 286 + if (kevent(kq, changes, 2, NULL, 0, NULL) == -1) 287 + goto err; 288 + } 289 + 290 + while (true) 291 + { 292 + struct kevent ev; 293 + 294 + if (kevent(kq, NULL, 0, &ev, 1, NULL) <= 0) 295 + { 296 + if (DBG) puts("kevent fail"); 297 + goto err; 298 + } 299 + 300 + if (ev.filter == EVFILT_PROC && (ev.fflags & NOTE_EXIT)) 301 + { 302 + if (DBG) puts("subprocess exit"); 303 + break; 304 + } 305 + else if (ev.filter == EVFILT_READ) 306 + { 307 + struct shellspawn_cmd cmd; 308 + 309 + if (read(fd, &cmd, sizeof(cmd)) != sizeof(cmd)) 310 + { 311 + if (DBG) puts("Cannot read cmd"); 312 + break; 313 + } 314 + 315 + switch (cmd.cmd) 316 + { 317 + case SHELLSPAWN_SIGNAL: 318 + { 319 + int linux_signal, darwin_signal; 320 + 321 + if (cmd.data_length != sizeof(int)) 322 + goto err; 323 + 324 + if (read(fd, &linux_signal, sizeof(int)) != sizeof(int)) 325 + goto err; 326 + 327 + // Convert Linux signal number to Darwin signal number 328 + darwin_signal = signum_linux_to_bsd(linux_signal); 329 + if (DBG) printf("rcvd signal %d -> %d\n", linux_signal, darwin_signal); 330 + 331 + if (darwin_signal != 0) 332 + { 333 + int fg_pid = tcgetpgrp(shellfd[0]); 334 + if (fg_pid != -1) 335 + { 336 + if (DBG) printf("fg_pid = %d\n", fg_pid); 337 + kill(fg_pid, darwin_signal); 338 + } 339 + else 340 + kill(-shell_pid, darwin_signal); 341 + } 342 + 343 + break; 344 + } 345 + default: 346 + goto err; 347 + } 348 + } 349 + } 350 + 351 + // Kill the child process in case it's still running 352 + kill(shell_pid, SIGKILL); 353 + 354 + // Close shell fds 355 + for (int i = 0; i < 3; i++) 356 + { 357 + if (shellfd[i] != -1) 358 + close(shellfd[0]); 359 + } 360 + 361 + // Reap the child 362 + int wstatus; 363 + waitpid(shell_pid, &wstatus, WEXITED); 364 + wstatus = WEXITSTATUS(wstatus); 365 + 366 + // Report exit code back to the client 367 + write(fd, &wstatus, sizeof(int)); 368 + 369 + if (DBG) printf("Shell terminated with exit code %d\n", wstatus); 370 + close(fd); 371 + 372 + reapAll(); 373 + return; 374 + err: 375 + if (DBG) fprintf(stderr, "Error spawning shell: %s\n", strerror(errno)); 376 + 377 + for (int i = 0; i < 3; i++) 378 + { 379 + if (shellfd[i] != -1) 380 + close(shellfd[0]); 381 + } 382 + 383 + if (shell_pid != -1) 384 + kill(shell_pid, SIGKILL); 385 + 386 + close(fd); 387 + reapAll(); 388 + } 389 + 390 + void setupSigchild(void) 391 + { 392 + struct sigaction sigchld_action = { 393 + .sa_handler = SIG_DFL, 394 + .sa_flags = SA_NOCLDWAIT 395 + }; 396 + sigaction(SIGCHLD, &sigchld_action, NULL); 397 + } 398 + 399 + void reapAll(void) 400 + { 401 + while (waitpid((pid_t)(-1), 0, WNOHANG) > 0); 402 + }
+47
src/shellspawn/shellspawn.h
··· 1 + /* 2 + This file is part of Darling. 3 + 4 + Copyright (C) 2017 Lubos Dolezel 5 + 6 + Darling is free software: you can redistribute it and/or modify 7 + it under the terms of the GNU General Public License as published by 8 + the Free Software Foundation, either version 3 of the License, or 9 + (at your option) any later version. 10 + 11 + Darling is distributed in the hope that it will be useful, 12 + but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + GNU General Public License for more details. 15 + 16 + You should have received a copy of the GNU General Public License 17 + along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #ifndef _SHELLSPAWN_H 21 + #define _SHELLSPAWN_H 22 + 23 + #ifdef TESTING 24 + #define SHELLSPAWN_SOCKPATH "/tmp/shellspawn.sock" 25 + #else 26 + #define SHELLSPAWN_SOCKPATH "/var/run/shellspawn.sock" 27 + #endif 28 + 29 + typedef unsigned short shellspawn_cmd_type_t; 30 + 31 + enum { 32 + SHELLSPAWN_ADDARG = 1, // add shell argument 33 + SHELLSPAWN_SETENV, // add env variable string 34 + SHELLSPAWN_CHDIR, 35 + SHELLSPAWN_GO, // execute the shell now, must also contain file descriptors 36 + SHELLSPAWN_SIGNAL, // pass a signal from client 37 + }; 38 + 39 + struct __attribute__((packed)) shellspawn_cmd 40 + { 41 + shellspawn_cmd_type_t cmd; 42 + unsigned short data_length; 43 + char data[]; 44 + }; 45 + 46 + #endif 47 +
+3 -1
src/startup/CMakeLists.txt
··· 9 9 10 10 enable_language(C ASM) 11 11 12 - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11") 12 + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -ggdb -O0") 13 13 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 14 14 #set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-Ttext-segment,0x400000 -Wl,-Tbss,0x410000 -Wl,-Tdata,0x420000") 15 15 add_definitions(-DINSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}" -D_GNU_SOURCE -DMLDR_BUILD) 16 16 17 17 add_executable(darling darling.c) 18 + 19 + target_link_libraries(darling -lutil) 18 20 19 21 include_directories(${CMAKE_CURRENT_SOURCE_DIR}) 20 22
+400 -152
src/startup/darling.c
··· 36 36 #include <sys/utsname.h> 37 37 #include <sys/stat.h> 38 38 #include <sys/syscall.h> 39 + #include <sys/inotify.h> 40 + #include <sys/poll.h> 41 + #include <sys/socket.h> 42 + #include <sys/un.h> 39 43 #include <getopt.h> 44 + #include <termios.h> 45 + #include <pty.h> 46 + #include "../shellspawn/shellspawn.h" 40 47 #include "darling.h" 41 48 #include "darling-config.h" 42 49 43 50 #define MLDR_PATH "/bin/mldr" 44 51 52 + // Between Linux 4.9 and 4.11, a strange bug has been introduced 53 + // which prevents connecting to Unix sockets if the socket was 54 + // created in a different mount namespace or under overlayfs 55 + // (dunno which one is really responsible for this). 56 + #define USE_LINUX_4_11_HACK 1 57 + 45 58 const char* DARLING_INIT_COMM = "darling-init"; 46 59 char *prefix; 47 60 uid_t g_originalUid, g_originalGid; ··· 50 63 51 64 int main(int argc, char ** argv, char ** envp) 52 65 { 53 - pid_t pidInit, pidChild; 66 + pid_t pidInit; 54 67 int wstatus; 55 68 56 69 if (argc <= 1) ··· 156 169 // If prefix's init is not running, start it up 157 170 if (pidInit == 0) 158 171 { 172 + char socketPath[4096]; 173 + 174 + snprintf(socketPath, sizeof(socketPath), "%s" SHELLSPAWN_SOCKPATH, prefix); 175 + 176 + unlink(socketPath); 177 + 159 178 setupWorkdir(); 160 179 pidInit = spawnInitProcess(); 161 180 putInitPid(pidInit); 162 - } 163 - 164 - if (strcmp(argv[1], "shell") != 0) 165 - { 166 - char *path = realpath(argv[1], NULL); 167 - char *fullPath; 168 - 169 - if (path == NULL) 181 + 182 + // Wait until shellspawn starts 183 + for (int i = 0; i < 15; i++) 170 184 { 171 - fprintf(stderr, "Cannot resolve path: %s\n", strerror(errno)); 172 - exit(1); 185 + if (access(socketPath, F_OK) == 0) 186 + break; 187 + sleep(1); 173 188 } 174 - 175 - const char *argv_child[argc + 1]; 176 - 177 - argv_child[0] = MLDR_PATH; 189 + } 178 190 179 - fullPath = malloc(strlen(SYSTEM_ROOT) + strlen(path) + 1); 180 - strcpy(fullPath, SYSTEM_ROOT); 181 - strcat(fullPath, path); 182 - argv_child[1] = fullPath; 191 + #if USE_LINUX_4_11_HACK 192 + joinNamespace(pidInit, CLONE_NEWNS, "mnt"); 193 + #endif 183 194 184 - for (int i = 2; i < argc; i++) 185 - argv_child[i] = argv[i]; 186 - argv_child[argc] = NULL; 195 + seteuid(g_originalUid); 187 196 188 - pidChild = spawnChild(pidInit, MLDR_PATH, argv_child); 189 - free(path); 190 - free(fullPath); 191 - } 192 - else 197 + if (strcmp(argv[1], "shell") == 0) 193 198 { 194 199 // Spawn the shell 195 200 if (argc > 2) 196 - { 197 - size_t total_len = 0; 198 - for (int i = 2; i < argc; i++) 199 - total_len += strlen(argv[i]); 200 - 201 - char buffer[total_len + argc]; 202 - 203 - char *to = buffer; 204 - for (int i = 2; i < argc; i++) 205 - to = stpcpy(stpcpy(to, argv[i]), " "); 206 - // Overwrite the last whitespace 207 - *(to - 1) = '\0'; 208 - 209 - pidChild = spawnChild(pidInit, MLDR_PATH, 210 - (const char *[5]) {MLDR_PATH, "/bin/bash", "-c", buffer, NULL}); 211 - } 201 + spawnShell((const char**) &argv[2]); 212 202 else 213 - pidChild = spawnChild(pidInit, MLDR_PATH, 214 - (const char *[3]) {MLDR_PATH, "/bin/bash", NULL}); 203 + spawnShell(NULL); 215 204 } 216 - if (pidChild == -ENOMEM) 205 + else 217 206 { 218 - pidInit = 0; 219 - goto start_init; 220 - } 207 + char *fullPath; 208 + char** child_argv; 209 + char *path = realpath(argv[1], NULL); 221 210 222 - // Drop the privileges so that we can be killed, etc by the user 223 - seteuid(g_originalUid); 211 + fullPath = malloc(strlen(SYSTEM_ROOT) + strlen(path) + 1); 212 + strcpy(fullPath, SYSTEM_ROOT); 213 + strcat(fullPath, path); 224 214 225 - waitpid(pidChild, &wstatus, 0); 215 + argv[1] = fullPath; 216 + spawnShell((const char**) &argv[1]); 217 + } 226 218 227 - if (WIFEXITED(wstatus)) 228 - return WEXITSTATUS(wstatus); 229 - if (WIFSIGNALED(wstatus)) 230 - return WTERMSIG(wstatus); 231 219 return 0; 232 220 } 233 221 234 - static void joinNamespace(pid_t pid, int type, const char* typeName) 222 + void joinNamespace(pid_t pid, int type, const char* typeName) 235 223 { 236 224 int fdNS; 237 225 char pathNS[4096]; ··· 256 244 close(fdNS); 257 245 } 258 246 259 - pid_t spawnChild(int pidInit, const char *path, const char *const argv[]) 247 + static void pushShellspawnCommandData(int sockfd, shellspawn_cmd_type_t type, const void* data, size_t data_length) 260 248 { 261 - pid_t pidChild; 262 - char curPath[4096]; 249 + struct shellspawn_cmd* cmd; 250 + size_t length; 251 + 252 + length = sizeof(*cmd) + data_length; 253 + 254 + cmd = (struct shellspawn_cmd*) malloc(length); 255 + cmd->cmd = type; 256 + cmd->data_length = data_length; 257 + 258 + if (data != NULL) 259 + memcpy(cmd->data, data, data_length); 263 260 264 - if (getcwd(curPath, sizeof(curPath)) == NULL) 261 + if (write(sockfd, cmd, length) != length) 265 262 { 266 - fprintf(stderr, "Cannot get current directory: %s\n", strerror(errno)); 267 - exit(1); 263 + fprintf(stderr, "Error sending command to shellspawn: %s\n", strerror(errno)); 264 + exit(EXIT_FAILURE); 268 265 } 266 + } 269 267 270 - joinNamespace(pidInit, CLONE_NEWPID, "pid"); 271 - joinNamespace(pidInit, CLONE_NEWUTS, "uts"); 268 + static void pushShellspawnCommand(int sockfd, shellspawn_cmd_type_t type, const char* value) 269 + { 270 + if (!value) 271 + pushShellspawnCommandData(sockfd, type, NULL, 0); 272 + else 273 + pushShellspawnCommandData(sockfd, type, value, strlen(value) + 1); 274 + } 272 275 273 - pidChild = fork(); 274 - if (pidChild < 0) 276 + static void pushShellspawnCommandFDs(int sockfd, shellspawn_cmd_type_t type, const int fds[3]) 277 + { 278 + struct shellspawn_cmd cmd; 279 + char cmsgbuf[CMSG_SPACE(sizeof(int) * 3)]; 280 + struct msghdr msg; 281 + struct iovec iov; 282 + struct cmsghdr *cmptr; 283 + 284 + cmd.cmd = type; 285 + cmd.data_length = 0; 286 + 287 + iov.iov_base = &cmd; 288 + 289 + memset(&msg, 0, sizeof(msg)); 290 + msg.msg_control = cmsgbuf; 291 + msg.msg_controllen = sizeof(cmsgbuf); 292 + 293 + iov.iov_base = &cmd; 294 + iov.iov_len = sizeof(cmd); 295 + msg.msg_iov = &iov; 296 + msg.msg_iovlen = 1; 297 + 298 + cmptr = CMSG_FIRSTHDR(&msg); 299 + 300 + cmptr->cmsg_len = CMSG_LEN(sizeof(int) * 3); 301 + cmptr->cmsg_level = SOL_SOCKET; 302 + cmptr->cmsg_type = SCM_RIGHTS; 303 + memcpy(CMSG_DATA(cmptr), fds, sizeof(fds[0])*3); 304 + 305 + if (sendmsg(sockfd, &msg, 0) < 0) 275 306 { 276 - if (errno == ENOMEM) 277 - { 278 - // This condition happens specifically when the init process is a zombie. 279 - // We should simply start a new init process. 280 - return -ENOMEM; 281 - } 282 - fprintf(stderr, "Cannot spawn a child process: %s\n", strerror(errno)); 283 - exit(1); 307 + fprintf(stderr, "Error sending command to shellspawn: %s\n", strerror(errno)); 308 + exit(EXIT_FAILURE); 284 309 } 310 + } 285 311 286 - if (pidChild == 0) 312 + static int _shSockfd = -1; 313 + static struct termios orig_termios; 314 + static int pty_master; 315 + static void signalHandler(int signo) 316 + { 317 + // printf("Received signal %d\n", signo); 318 + 319 + // Forward window size changes 320 + if (signo == SIGWINCH && pty_master != -1) 287 321 { 288 - // This is the child process 322 + struct winsize win; 289 323 290 - // We still have the outside PIDs in /proc 291 - joinNamespace(pidInit, CLONE_NEWNS, "mnt"); 324 + ioctl(0, TIOCGWINSZ, &win); 325 + ioctl(pty_master, TIOCSWINSZ, &win); 326 + } 327 + 328 + // Foreground process loopkup in shellspawn doesn't work 329 + // if we're not running in TTY mode, so shellspawn falls back 330 + // to forwarding signals to the Bash subprocess. 331 + // 332 + // Hence we translate SIGINT to SIGTERM for user convenience, 333 + // because Bash will not terminate on SIGINT. 334 + if (pty_master == -1 && signo == SIGINT) 335 + signo = SIGTERM; 292 336 293 - /* 294 - snprintf(pathNS, sizeof(pathNS), SYSTEM_ROOT "/proc/%d/ns/user", pidInit); 295 - fdNS = open(pathNS, O_RDONLY); 296 - if (fdNS < 0) 337 + pushShellspawnCommandData(_shSockfd, SHELLSPAWN_SIGNAL, &signo, sizeof(signo)); 338 + } 339 + 340 + static void shellLoop(int sockfd, int master) 341 + { 342 + struct sigaction sa; 343 + struct pollfd pfds[3]; 344 + const int fdcount = (master != -1) ? 3 : 1; // do we do pty proxying? 345 + 346 + // Vars for signal handler 347 + _shSockfd = sockfd; 348 + pty_master = master; 349 + 350 + memset(&sa, 0, sizeof(sa)); 351 + sa.sa_handler = signalHandler; 352 + sigfillset(&sa.sa_mask); 353 + 354 + for (int i = 1; i < 32; i++) 355 + sigaction(i, &sa, NULL); 356 + 357 + pfds[2].fd = master; 358 + pfds[2].events = POLLIN; 359 + pfds[2].revents = 0; 360 + pfds[1].fd = STDIN_FILENO; 361 + pfds[1].events = POLLIN; 362 + pfds[1].revents = 0; 363 + pfds[0].fd = sockfd; 364 + pfds[0].events = POLLIN; 365 + pfds[0].revents = 0; 366 + 367 + if (master != -1) 368 + fcntl(master, F_SETFL, O_NONBLOCK); 369 + fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); 370 + fcntl(sockfd, F_SETFL, O_NONBLOCK); 371 + 372 + while (1) 373 + { 374 + char buf[4096]; 375 + 376 + if (poll(pfds, fdcount, -1) < 0) 297 377 { 298 - fprintf(stderr, "Cannot open user namespace file: %s\n", strerror(errno)); 299 - exit(1); 378 + if (errno != EINTR) 379 + { 380 + perror("poll"); 381 + break; 382 + } 300 383 } 301 - */ 302 - 303 - // Drop the privileges. It's important to drop GID first, because 304 - // non-root users can't change their GID. 305 - setresgid(g_originalGid, g_originalGid, g_originalGid); 306 - setresuid(g_originalUid, g_originalUid, g_originalUid); 307 384 308 - /* 309 - if (setns(fdNS, CLONE_NEWUSER) != 0) 385 + if (pfds[2].revents & POLLIN) 310 386 { 311 - fprintf(stderr, "Cannot join user namespace: %s\n", strerror(errno)); 312 - exit(1); 387 + int rd; 388 + do 389 + { 390 + rd = read(master, buf, sizeof(buf)); 391 + if (rd > 0) 392 + write(STDOUT_FILENO, buf, rd); 393 + } 394 + while (rd == sizeof(buf)); 313 395 } 314 - close(fdNS); 315 - */ 316 396 317 - setupChild(curPath); 397 + if (pfds[1].revents & POLLIN) 398 + { 399 + int rd; 400 + do 401 + { 402 + rd = read(STDIN_FILENO, buf, sizeof(buf)); 403 + if (rd > 0) 404 + write(master, buf, rd); 405 + } 406 + while (rd == sizeof(buf)); 407 + } 318 408 319 - execv(path, (char * const *) argv); 409 + if (pfds[0].revents & (POLLHUP | POLLIN)) 410 + { 411 + int exitStatus; 412 + 413 + if (read(sockfd, &exitStatus, sizeof(int)) == sizeof(int)) 414 + exit(exitStatus); 415 + else 416 + exit(1); 417 + } 418 + } 419 + } 420 + 421 + static void restoreTermios(void) 422 + { 423 + tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios); 424 + } 425 + 426 + // Glibc openpty() fails for me on Debian, because grantpty() fails to chown() the pty node with error code EPERM. 427 + // This is a more lenient version of openpty() that just works. 428 + static int openpty_darling(int* amaster, int* aslave, char* name_unused, const struct termios* tos, const struct winsize* wsz) 429 + { 430 + const char* slave_name; 431 + 432 + *amaster = posix_openpt(O_RDWR); 433 + if (*amaster == -1) 434 + return -1; 435 + 436 + grantpt(*amaster); 437 + if (unlockpt(*amaster) < 0) 438 + return -1; 439 + 440 + slave_name = ptsname(*amaster); 441 + *aslave = open(slave_name, O_RDWR | O_NOCTTY); 442 + if (*aslave == -1) 443 + return -1; 320 444 321 - fprintf(stderr, "Cannot exec the target program: %s\n", strerror(errno)); 445 + if (tos != NULL) 446 + tcsetattr(*amaster, TCSANOW, tos); 447 + if (wsz != NULL) 448 + ioctl(*amaster, TIOCSWINSZ, wsz); 449 + 450 + return 0; 451 + } 452 + 453 + static void setupPtys(int fds[3], int* master) 454 + { 455 + struct winsize win; 456 + struct termios termios; 457 + bool tty = true; 458 + 459 + if (tcgetattr(STDIN_FILENO, &termios) < 0) 460 + tty = false; 461 + 462 + if (openpty_darling(master, &fds[0], NULL, &termios, NULL) < 0) 463 + { 464 + perror("openpty"); 322 465 exit(1); 323 466 } 467 + fds[2] = fds[1] = fds[0]; 324 468 325 - return pidChild; 469 + if (tty) 470 + { 471 + orig_termios = termios; 472 + 473 + ioctl(0, TIOCGWINSZ, &win); 474 + 475 + termios.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO); 476 + termios.c_iflag &= ~(BRKINT | ICRNL | IGNBRK | IGNCR | INLCR | 477 + INPCK | ISTRIP | IXON | PARMRK); 478 + termios.c_oflag &= ~OPOST; 479 + termios.c_cc[VMIN] = 1; 480 + termios.c_cc[VTIME] = 0; 481 + 482 + if (tcsetattr(STDIN_FILENO, TCSANOW, &termios) < 0) 483 + { 484 + perror("tcsetattr"); 485 + exit(1); 486 + } 487 + ioctl(*master, TIOCSWINSZ, &win); 488 + 489 + atexit(restoreTermios); 490 + } 326 491 } 327 492 328 - void setupChild(const char *curPath) 493 + void spawnShell(const char** argv) 329 494 { 495 + size_t total_len = 0; 496 + int count; 330 497 char buffer1[4096]; 331 498 char buffer2[4096]; 499 + int sockfd; 500 + struct sockaddr_un addr; 501 + char* buffer; 332 502 503 + if (argv != NULL) 504 + { 505 + for (count = 0; argv[count] != NULL; count++) 506 + total_len += strlen(argv[count]); 507 + 508 + buffer = malloc(total_len + count*3); 333 509 334 - unsetenv("LESSOPEN"); 335 - unsetenv("LESSCLOSE"); 336 - unsetenv("LESSECHO"); 510 + char *to = buffer; 511 + for (int i = 0; argv[i] != NULL; i++) 512 + { 513 + if (to != buffer) 514 + to = stpcpy(to, " "); 515 + to = stpcpy(to, "'"); 516 + to = stpcpy(to, argv[i]); 517 + to = stpcpy(to, "'"); 518 + } 519 + } 520 + else 521 + buffer = NULL; 337 522 338 - setenv("PATH", 339 - "/usr/bin:" 523 + // Connect to the shellspawn daemon in the container 524 + addr.sun_family = AF_UNIX; 525 + #if USE_LINUX_4_11_HACK 526 + strcpy(addr.sun_path, SHELLSPAWN_SOCKPATH); 527 + #else 528 + snprintf(addr.sun_path, sizeof(addr.sun_path), "%s" SHELLSPAWN_SOCKPATH, prefix); 529 + #endif 530 + 531 + sockfd = socket(AF_UNIX, SOCK_STREAM, 0); 532 + if (sockfd == -1) 533 + { 534 + fprintf(stderr, "Error creating a unix domain socket: %s\n", strerror(errno)); 535 + exit(1); 536 + } 537 + 538 + if (connect(sockfd, (struct sockaddr*) &addr, sizeof(addr)) == -1) 539 + { 540 + fprintf(stderr, "Error connecting to shellspawn in the container (%s): %s\n", addr.sun_path, strerror(errno)); 541 + exit(1); 542 + } 543 + 544 + // Push environment variables 545 + pushShellspawnCommand(sockfd, SHELLSPAWN_SETENV, 546 + "PATH=/usr/bin:" 340 547 "/bin:" 341 548 "/usr/sbin:" 342 549 "/sbin:" 343 - "/usr/local/bin", 344 - 1); 550 + "/usr/local/bin"); 345 551 346 - sscanf(getenv("HOME"), "/home/%4096s", buffer1); 347 - snprintf(buffer2, sizeof(buffer2), "/Users/%s", buffer1); 348 - setenv("HOME", buffer2, 1); 552 + if (sscanf(getenv("HOME"), "/home/%4096s", buffer1) == 1) 553 + { 554 + snprintf(buffer2, sizeof(buffer2), "HOME=/Users/%s", buffer1); 555 + pushShellspawnCommand(sockfd, SHELLSPAWN_SETENV, buffer2); 556 + } 349 557 350 - if (sscanf(curPath, "/home/%4096s", buffer1) == 1) 558 + // Push shell arguments 559 + if (buffer != NULL) 351 560 { 352 - // We're currently inside our home directory 353 - snprintf(buffer2, sizeof(buffer2), "/Users/%s", buffer1); 354 - setenv("PWD", buffer2, 1); 355 - chdir(buffer2); 561 + pushShellspawnCommand(sockfd, SHELLSPAWN_ADDARG, "-c"); 562 + pushShellspawnCommand(sockfd, SHELLSPAWN_ADDARG, buffer); 563 + 564 + free(buffer); 356 565 } 357 - else 566 + 567 + if (getcwd(buffer1, sizeof(buffer1)) != NULL) 358 568 { 359 - snprintf(buffer2, sizeof(buffer2), SYSTEM_ROOT "%s", curPath); 360 - setenv("PWD", buffer2, 1); 361 - chdir(buffer2); 569 + snprintf(buffer2, sizeof(buffer2), SYSTEM_ROOT "%s", buffer1); 570 + pushShellspawnCommand(sockfd, SHELLSPAWN_CHDIR, buffer2); 362 571 } 572 + 573 + int fds[3], master = -1; 574 + 575 + if (isatty(STDIN_FILENO)) 576 + setupPtys(fds, &master); 577 + else 578 + fds[0] = dup(STDIN_FILENO); // dup() because we close() a few lines below 579 + 580 + if (master == -1 || !isatty(STDOUT_FILENO)) 581 + fds[1] = STDOUT_FILENO; 582 + if (master == -1 || !isatty(STDERR_FILENO)) 583 + fds[2] = STDERR_FILENO; 584 + 585 + pushShellspawnCommandFDs(sockfd, SHELLSPAWN_GO, fds); 586 + close(fds[0]); 587 + 588 + shellLoop(sockfd, master); 589 + 590 + if (master != -1) 591 + close(master); 592 + close(sockfd); 363 593 } 364 594 365 595 void showHelp(const char* argv0) ··· 432 662 { 433 663 pid_t pid; 434 664 int pipefd[2]; 435 - // char idmap[100]; 665 + char path[1024]; 436 666 char buffer[1]; 437 667 FILE *file; 438 668 ··· 540 770 // if we enable user namespaces 541 771 542 772 darlingPreInit(); 773 + spawnLaunchd(); 774 + 543 775 // Never returns 544 776 } 545 777 ··· 575 807 fprintf(stderr, "Cannot set gid_map for the init process: %s\n", strerror(errno)); 576 808 } 577 809 */ 578 - 579 - // This is for development only! 580 - if (getenv("TRY_LAUNCHD") != NULL) 581 - { 582 - int status = 0; 583 - waitpid(pid, &status, 0); 584 - } 585 810 586 811 // Here's where we resume the child 587 812 // if we enable user namespaces ··· 616 841 fclose(fp); 617 842 } 618 843 619 - void darlingPreInit(void) 844 + void spawnLaunchd(void) 620 845 { 621 - // TODO: Run /usr/libexec/makewhatis 846 + puts("Bootstrapping the container with launchd..."); 622 847 623 - // This is for development only! 624 - if (getenv("TRY_LAUNCHD") != NULL) 848 + // putenv("KQUEUE_DEBUG=1"); 849 + execl(MLDR_PATH, "mldr!/sbin/launchd", "launchd", NULL); 850 + 851 + fprintf(stderr, "Failed to exec launchd: %s\n", strerror(errno)); 852 + abort(); 853 + } 854 + 855 + static void wipeDir(const char* dirpath) 856 + { 857 + char path[4096]; 858 + struct dirent* ent; 859 + DIR* dir = opendir(dirpath); 860 + 861 + if (!dir) 862 + return; 863 + 864 + while ((ent = readdir(dir)) != NULL) 625 865 { 626 - // putenv("KQUEUE_DEBUG=1"); 627 - execl("/bin/mldr", "mldr!/sbin/launchd", "launchd", NULL); 628 - 629 - fprintf(stderr, "Failed to exec launchd: %s\n", strerror(errno)); 630 - abort(); 866 + if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) 867 + continue; 868 + 869 + snprintf(path, sizeof(path), "%s/%s", dirpath, ent->d_name); 870 + 871 + if (ent->d_type == DT_DIR) 872 + { 873 + wipeDir(path); 874 + rmdir(path); 875 + } 876 + else 877 + unlink(path); 631 878 } 632 - 633 - // TODO: this is where we will exec() launchd in future. 634 - // Instead, we just reap zombies. 635 - while (1) 636 - { 637 - int status, sig; 638 - sigset_t chld; 879 + 880 + closedir(dir); 881 + } 639 882 640 - sigemptyset(&chld); 641 - sigaddset(&chld, SIGCHLD); 642 - sigwait(&chld, &sig); 883 + void darlingPreInit(void) 884 + { 885 + // TODO: Run /usr/libexec/makewhatis 886 + const char* dirs[] = { 887 + "/var/tmp", 888 + "/var/run" 889 + }; 643 890 644 - while (waitpid(-1, &status, 0) != -1); 645 - } 891 + for (size_t i = 0; i < sizeof(dirs)/sizeof(dirs[0]); i++) 892 + wipeDir(dirs[i]); 646 893 } 647 894 648 895 char* defaultPrefixPath(void) ··· 749 996 "/private/var/db", 750 997 "/var", 751 998 "/var/run", 752 - "/var/tmp" 999 + "/var/tmp", 1000 + "/var/log" 753 1001 }; 754 1002 755 1003 fprintf(stderr, "Setting up a new Darling prefix at %s\n", prefix); ··· 825 1073 } 826 1074 fclose(fp); 827 1075 828 - if (strcmp(exeBuf, DARLING_INIT_COMM) != 0) 1076 + if (strcmp(exeBuf, "mldr") != 0) 829 1077 { 830 1078 unlink(pidPath); 831 1079 return 0;
+4 -4
src/startup/darling.h
··· 40 40 // Creates the given directory, exit()ing if not possible 41 41 void createDir(const char* path); 42 42 43 - // Spawn the specified proceess inside the namespaces that PID 1 is in 44 - // Returns the PID of the child 45 - // exit()s on error 46 - pid_t spawnChild(int pidInit, const char *path, const char *const argv[]); 43 + void spawnShell(const char** argv); 47 44 48 45 // Set up some environment variables 49 46 // As well as the working directory ··· 57 54 pid_t spawnInitProcess(void); 58 55 59 56 void putInitPid(pid_t pidInit); 57 + void mapUids(pid_t pid); 60 58 59 + void spawnLaunchd(void); 61 60 void darlingPreInit(void); 62 61 63 62 void checkPrefixOwner(void); ··· 65 64 int isModuleLoaded(void); 66 65 67 66 void loadKernelModule(void); 67 + void joinNamespace(pid_t pid, int type, const char* typeName); 68 68 69 69 #endif
+1
src/tools/sudo
··· 28 28 29 29 export __FAKE_SETUID_ROOT=1 30 30 export __FAKE_SETGID_ROOT=1 31 + export SUDO_COMMAND=1 31 32 32 33 if [ $1 == "-k" ]; then 33 34 shift