this repo has no description
1
fork

Configure Feed

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

Merge pull request #217 from bugaevc/new-darling

Implement the new 'darling' executable

authored by

Luboš Doležel and committed by
GitHub
726567c1 4922fc90

+564 -160
+10 -1
README.md
··· 61 61 make install 62 62 ```` 63 63 64 + To build the new, experimental `darling` executable: 65 + 66 + ```` 67 + cmake ../.. -DCMAKE_TOOLCHAIN_FILE=../../Toolchain-x86_64.cmake -DNEW_DARLING=TRUE 68 + make 69 + make install 70 + chmod +s $(which darling) 71 + ```` 72 + 64 73 #### For running i386 OS X binaries 65 74 66 75 <a href="http://teamcity.dolezel.info/viewType.html?buildTypeId=Darling_DebianStableX8664&guest=1"> ··· 164 173 165 174 ### AppKit 166 175 167 - AppKit is still highly expiramental and incomplete, but to work on it you need to configure CMake with `-DFRAMEWORK_APPKIT=1` and install some additional packages. 176 + AppKit is still highly experimental and incomplete, but to work on it you need to configure CMake with `-DFRAMEWORK_APPKIT=1` and install some additional packages. 168 177 169 178 Ubuntu 16.04: 170 179 ```
+514 -138
src/dyld/darling.c
··· 37 37 #include "darling.h" 38 38 #include "darling-config.h" 39 39 40 + // Path where the system root gets "mounted" inside the prefix 41 + #define SYSTEM_ROOT "/system-root" 42 + 40 43 const char* DARLING_INIT_COMM = "darling-init"; 41 - uid_t g_originalUid; 44 + char *prefix; 45 + uid_t g_originalUid, g_originalGid; 42 46 43 47 int main(int argc, const char** argv) 44 48 { 45 - const char* dprefix; 46 - int pidInit; 47 - 49 + pid_t pidInit, pidChild; 50 + char path[4096]; 51 + int wstatus; 52 + 48 53 if (argc <= 1) 49 54 { 50 55 showHelp(argv[0]); 51 56 return 1; 52 57 } 53 - 54 - /*if (geteuid() != 0) 58 + 59 + if (geteuid() != 0) 55 60 { 56 61 missingSetuidRoot(); 57 62 return 1; 58 - }*/ 59 - 63 + } 64 + 60 65 if (loadKernelModule()) 61 66 return 1; 62 67 63 - // Temporarily drop root privileges 64 68 g_originalUid = getuid(); 65 - seteuid(getuid()); 66 - setegid(getgid()); 67 - 68 - dprefix = getenv("DPREFIX"); 69 - if (!dprefix) 70 - dprefix = defaultPrefixPath(); 71 - if (!dprefix) 69 + g_originalGid = getgid(); 70 + 71 + prefix = getenv("DPREFIX"); 72 + if (!prefix) 73 + prefix = defaultPrefixPath(); 74 + if (!prefix) 72 75 return 1; 73 - checkPrefixOwner(dprefix); 74 - 75 - pidInit = getInitProcess(dprefix); 76 - 76 + setenv("DPREFIX", prefix, 0); 77 + 78 + if (!checkPrefixDir()) 79 + setupPrefix(); 80 + checkPrefixOwner(); 81 + 82 + pidInit = getInitProcess(); 83 + 77 84 // If prefix's init is not running, start it up 78 85 if (pidInit == 0) 79 86 { 80 - char* opts; 81 - 82 - createDir(dprefix); 83 - setupWorkdir(dprefix); 84 - 85 - // Since overlay cannot be mounted inside user namespaces, we have to setup a new mount namespace 86 - // and do the mount while we can be root 87 - //seteuid(0); 88 - if (unshare(CLONE_NEWNS) != 0) 87 + setupWorkdir(); 88 + pidInit = spawnInitProcess(); 89 + putInitPid(pidInit); 90 + } 91 + 92 + if (strcmp(argv[1], "shell") != 0) 93 + { 94 + const char *argv_child[argc + 1]; 95 + 96 + argv_child[0] = "dyld"; 97 + for (int i = 1; i < argc; i++) 98 + argv_child[i] = argv[i]; 99 + argv_child[argc] = NULL; 100 + 101 + pidChild = spawnChild(pidInit, DYLD_PATH, argv_child); 102 + } 103 + else 104 + { 105 + // Spawn the shell 106 + snprintf(path, sizeof(path), "%s/bin/bash", prefix); 107 + if (argc > 2) 89 108 { 90 - fprintf(stderr, "Cannot unshare(CLONE_NEWNS): %s\n", strerror(errno)); 91 - return 1; 109 + size_t total_len = 0; 110 + for (int i = 2; i < argc; i++) 111 + total_len += strlen(argv[i]); 112 + 113 + char buffer[total_len + argc]; 114 + 115 + char *to = buffer; 116 + for (int i = 2; i < argc; i++) 117 + to = stpcpy(stpcpy(to, argv[i]), " "); 118 + // Overwrite the last whitespace 119 + *(to - 1) = '\0'; 120 + 121 + pidChild = spawnChild(pidInit, DYLD_PATH, 122 + (const char *[5]) {"dyld", path, "-c", buffer, NULL}); 92 123 } 93 - 94 - // Because IDIOTIC systemd marks / as MS_SHARED and we would inherit this into the overlay mount, 95 - // causing it not to be unmounted once the init process dies. 96 - if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL) != 0) 124 + else 125 + pidChild = spawnChild(pidInit, DYLD_PATH, 126 + (const char *[3]) {"dyld", path, NULL}); 127 + } 128 + 129 + // Drop the privileges so that we can be killed, etc by the user 130 + seteuid(g_originalUid); 131 + 132 + waitpid(pidChild, &wstatus, 0); 133 + 134 + // Should we unloadKernelModule() here? Others may be still using it 135 + if (WIFEXITED(wstatus)) 136 + return WEXITSTATUS(wstatus); 137 + if (WIFSIGNALED(wstatus)) 138 + return WTERMSIG(wstatus); 139 + return 0; 140 + } 141 + 142 + pid_t spawnChild(int pidInit, const char *path, const char *const argv[]) 143 + { 144 + int fdNS; 145 + pid_t pidChild; 146 + char pathNS[4096], curPath[4096]; 147 + 148 + if (getcwd(curPath, sizeof(curPath)) == NULL) 149 + { 150 + fprintf(stderr, "Cannot get current directory: %s\n", strerror(errno)); 151 + exit(1); 152 + } 153 + 154 + snprintf(pathNS, sizeof(pathNS), "/proc/%d/ns/pid", pidInit); 155 + 156 + fdNS = open(pathNS, O_RDONLY); 157 + 158 + if (fdNS < 0) 159 + { 160 + fprintf(stderr, "Cannot open PID namespace file: %s\n", strerror(errno)); 161 + exit(1); 162 + } 163 + 164 + // Calling setns() with a PID namespace doesn't move our process into it, 165 + // but our child process will be spawned inside the namespace 166 + if (setns(fdNS, CLONE_NEWPID) != 0) 167 + { 168 + fprintf(stderr, "Cannot join PID namespace: %s\n", strerror(errno)); 169 + exit(1); 170 + } 171 + close(fdNS); 172 + 173 + pidChild = fork(); 174 + if (pidChild < 0) 175 + { 176 + fprintf(stderr, "Cannot spawn a child process: %s\n", strerror(errno)); 177 + exit(1); 178 + } 179 + 180 + if (pidChild == 0) 181 + { 182 + // This is the child process 183 + 184 + // We still have the outside PIDs in /proc 185 + snprintf(pathNS, sizeof(pathNS), "/proc/%d/ns/mnt", pidInit); 186 + fdNS = open(pathNS, O_RDONLY); 187 + if (fdNS < 0) 97 188 { 98 - fprintf(stderr, "Cannot remount / as private: %s\n", strerror(errno)); 99 - return 1; 189 + fprintf(stderr, "Cannot open mount namespace file: %s\n", strerror(errno)); 190 + exit(1); 100 191 } 101 - 102 - opts = (char*) malloc(strlen(dprefix)*2 + sizeof(LIBEXEC_PATH) + 50); 103 - sprintf(opts, "lowerdir=%s,upperdir=%s,workdir=%s.workdir", LIBEXEC_PATH, dprefix, dprefix); 104 - 105 - // Mount overlay onto our prefix 106 - if (mount("overlay", dprefix, "overlay", 0, opts) != 0) 192 + 193 + if (setns(fdNS, CLONE_NEWNS) != 0) 194 + { 195 + fprintf(stderr, "Cannot join mount namespace: %s\n", strerror(errno)); 196 + exit(1); 197 + } 198 + close(fdNS); 199 + 200 + snprintf(pathNS, sizeof(pathNS), "/proc/%d/ns/user", pidInit); 201 + fdNS = open(pathNS, O_RDONLY); 202 + if (fdNS < 0) 203 + { 204 + fprintf(stderr, "Cannot open user namespace file: %s\n", strerror(errno)); 205 + exit(1); 206 + } 207 + 208 + setresuid(g_originalUid, g_originalUid, g_originalUid); 209 + setresgid(g_originalGid, g_originalGid, g_originalGid); 210 + 211 + if (setns(fdNS, CLONE_NEWUSER) != 0) 107 212 { 108 - fprintf(stderr, "Cannot mount overlay: %s\n", strerror(errno)); 109 - return 1; 213 + fprintf(stderr, "Cannot join user namespace: %s\n", strerror(errno)); 214 + exit(1); 110 215 } 111 - 112 - free(opts); 113 - //seteuid(getuid()); 114 - 115 - pidInit = spawnInitProcess(dprefix); 216 + close(fdNS); 217 + 218 + setupChild(curPath); 219 + 220 + execv(path, (char * const *) argv); 221 + 222 + fprintf(stderr, "Cannot exec the target program: %s\n", strerror(errno)); 223 + exit(1); 116 224 } 117 - 118 - // TODO: Spawn the executable in the namespace, wait for it and return its exit code 119 - unloadKernelModule(); 120 - return 0; 225 + 226 + return pidChild; 227 + } 228 + 229 + void setupChild(const char *curPath) 230 + { 231 + char buffer1[4096]; 232 + char buffer2[4096]; 233 + 234 + setenv("PATH", "/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin", 1); 235 + 236 + sscanf(getenv("HOME"), "/home/%4096s", buffer1); 237 + snprintf(buffer2, sizeof(buffer2), "/Users/%s", buffer1); 238 + setenv("HOME", buffer2, 1); 239 + 240 + if (sscanf(curPath, "/home/%4096s", buffer1) == 1) 241 + { 242 + // We're currently inside our home directory 243 + snprintf(buffer2, sizeof(buffer2), "/Users/%s", buffer1); 244 + setenv("PWD", buffer2, 1); 245 + 246 + snprintf(buffer2, sizeof(buffer2), "%s/Users/%s", prefix, buffer1); 247 + chdir(buffer2); 248 + } 249 + else 250 + { 251 + snprintf(buffer2, sizeof(buffer2), SYSTEM_ROOT "%s", curPath); 252 + setenv("PWD", buffer2, 1); 253 + 254 + snprintf(buffer2, sizeof(buffer2), "%s" SYSTEM_ROOT "%s", prefix, curPath); 255 + chdir(buffer2); 256 + } 121 257 } 122 258 123 259 void showHelp(const char* argv0) ··· 125 261 fprintf(stderr, "This is Darling, translation layer for macOS software.\n\n"); 126 262 fprintf(stderr, "Copyright (C) 2012-2016 Lubos Dolezel\n\n"); 127 263 128 - fprintf(stderr, "Usage: %s program-path [arguments...]\n\n", argv0); 264 + fprintf(stderr, "Usage:\n"); 265 + fprintf(stderr, "\t%s program-path [arguments...]\n", argv0); 266 + fprintf(stderr, "\t%s shell [arguments...]\n", argv0); 267 + fprintf(stderr, "\n"); 129 268 fprintf(stderr, "Environment variables:\n" 130 269 "DPREFIX - specifies the location of Darling prefix, defaults to ~/.darling\n"); 131 270 } ··· 134 273 { 135 274 char path[4096]; 136 275 int len; 137 - 276 + 138 277 len = readlink("/proc/self/exe", path, sizeof(path)-1); 139 278 if (len < 0) 140 279 strcpy(path, "darling"); 141 280 else 142 281 path[len] = '\0'; 143 - 282 + 144 283 fprintf(stderr, "Sorry, the `%s' binary is not setuid root, which is mandatory.\n", path); 145 284 fprintf(stderr, "Darling needs this in order to create mount and PID namespaces and to perform mounts.\n"); 146 285 } 147 286 148 - int spawnInitProcess(const char* prefix) 287 + pid_t spawnInitProcess(void) 149 288 { 150 - char* childStack; 151 - int pid; 152 - char uidmap[100]; 153 - 154 - childStack = (char*) malloc(16*1024); 155 - childStack += 16*1024; 156 - 157 - //setuid(0); 158 - pid = clone(darlingPreInit, childStack, /*CLONE_NEWPID |*/ CLONE_NEWUSER, (void*) prefix); 159 - 160 - if (pid <= 0) 289 + pid_t pid; 290 + int pipefd[2]; 291 + char idmap[100]; 292 + char buffer[1]; 293 + FILE *file; 294 + 295 + if (pipe(pipefd) == -1) 296 + { 297 + fprintf(stderr, "Cannot create a pipe for synchronization: %s\n", strerror(errno)); 298 + exit(1); 299 + } 300 + 301 + if (unshare(CLONE_NEWPID) != 0) 302 + { 303 + fprintf(stderr, "Cannot unshare pid namespace to create darling-init: %s\n", strerror(errno)); 304 + exit(1); 305 + } 306 + 307 + pid = fork(); 308 + 309 + if (pid < 0) 161 310 { 162 - fprintf(stderr, "Cannot clone() to create darling-init: %s\n", strerror(errno)); 311 + fprintf(stderr, "Cannot fork() to create darling-init: %s\n", strerror(errno)); 163 312 exit(1); 164 313 } 165 - 166 - sprintf(uidmap, "/proc/%d/uid_map", pid); 167 - 168 - FILE* file = fopen(uidmap, "w"); 314 + 315 + if (pid == 0) 316 + { 317 + // The child 318 + 319 + char *opts; 320 + 321 + // Since overlay cannot be mounted inside user namespaces, we have to setup a new mount namespace 322 + // and do the mount while we can be root 323 + if (unshare(CLONE_NEWNS) != 0) 324 + { 325 + fprintf(stderr, "Cannot unshare mount namespace: %s\n", strerror(errno)); 326 + exit(1); 327 + } 328 + 329 + // Because systemd marks / as MS_SHARED and we would inherit this into the overlay mount, 330 + // causing it not to be unmounted once the init process dies. 331 + if (mount(NULL, "/", NULL, MS_REC | MS_SLAVE, NULL) != 0) 332 + { 333 + fprintf(stderr, "Cannot remount / as slave: %s\n", strerror(errno)); 334 + exit(1); 335 + } 336 + 337 + opts = (char*) malloc(strlen(prefix)*2 + sizeof(LIBEXEC_PATH) + 50); 338 + sprintf(opts, "lowerdir=%s,upperdir=%s,workdir=%s.workdir", LIBEXEC_PATH, prefix, prefix); 339 + 340 + // Mount overlay onto our prefix 341 + if (mount("overlay", prefix, "overlay", 0, opts) != 0) 342 + { 343 + fprintf(stderr, "Cannot mount overlay: %s\n", strerror(errno)); 344 + exit(1); 345 + } 346 + 347 + free(opts); 348 + 349 + // Drop the privileges 350 + setresuid(g_originalUid, g_originalUid, g_originalUid); 351 + setresgid(g_originalGid, g_originalGid, g_originalGid); 352 + prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); 353 + 354 + prctl(PR_SET_NAME, DARLING_INIT_COMM, 0, 0); 355 + 356 + if (unshare(CLONE_NEWUSER) != 0) 357 + { 358 + fprintf(stderr, "Cannot unshare user namespace: %s\n", strerror(errno)); 359 + exit(1); 360 + } 361 + 362 + // Tell the parent we're ready for it to set up UID/GID mappings 363 + write(pipefd[1], buffer, 1); 364 + close(pipefd[1]); 365 + // And wait for it to do it 366 + read(pipefd[0], buffer, 1); 367 + close(pipefd[0]); 368 + 369 + darlingPreInit(); 370 + // Never returns 371 + } 372 + 373 + // Wait for the child to drop UID/GIDs and unshare stuff 374 + read(pipefd[0], buffer, 1); 375 + close(pipefd[0]); 376 + 377 + snprintf(idmap, sizeof(idmap), "/proc/%d/uid_map", pid); 378 + 379 + file = fopen(idmap, "w"); 169 380 if (file != NULL) 170 381 { 171 - fprintf(file, "0 %d 1\n", getuid()); // all users map to our user on the outside 382 + fprintf(file, "0 %d 1\n", g_originalUid); // all users map to our user on the outside 172 383 fclose(file); 173 384 } 174 385 else 175 386 { 176 - fprintf(stderr, "Failure setting uid_map in init process\n"); 387 + fprintf(stderr, "Cannot set uid_map for the init process: %s\n", strerror(errno)); 177 388 } 178 - 389 + 390 + snprintf(idmap, sizeof(idmap), "/proc/%d/gid_map", pid); 391 + 392 + file = fopen(idmap, "w"); 393 + if (file != NULL) 394 + { 395 + fprintf(file, "0 %d 1\n", g_originalGid); // all groups map to our group on the outside 396 + fclose(file); 397 + } 398 + else 399 + { 400 + fprintf(stderr, "Cannot set gid_map for the init process: %s\n", strerror(errno)); 401 + } 402 + 403 + // Resume the child 404 + write(pipefd[1], buffer, 1); 405 + close(pipefd[1]); 406 + 407 + return pid; 408 + } 409 + 410 + void putInitPid(pid_t pidInit) 411 + { 412 + const char pidFile[] = "/.init.pid"; 413 + char* pidPath; 414 + FILE *fp; 415 + 416 + pidPath = (char*) alloca(strlen(prefix) + sizeof(pidFile)); 417 + strcpy(pidPath, prefix); 418 + strcat(pidPath, pidFile); 419 + 179 420 seteuid(g_originalUid); 180 - setuid(g_originalUid); 181 - 182 - return pid; 421 + setegid(g_originalGid); 422 + 423 + fp = fopen(pidPath, "w"); 424 + 425 + seteuid(0); 426 + setegid(0); 427 + 428 + if (fp == NULL) 429 + { 430 + fprintf(stderr, "Cannot write out PID of the init process: %s\n", strerror(errno)); 431 + return; 432 + } 433 + fprintf(fp, "%d", (int) pidInit); 434 + fclose(fp); 183 435 } 184 436 185 - int darlingPreInit(void* arg) 437 + void darlingPreInit(void) 186 438 { 187 - const char* prefix = (const char*) arg; 188 - 189 - prctl(PR_SET_NAME, DARLING_INIT_COMM, 0, 0); 190 - 191 - // Wait until the parent sets our uid_map 192 - while (getuid() == 65534); 193 - 194 439 // TODO: Run /usr/libexec/makewhatis 195 - 440 + 196 441 // TODO: this is where we will exec() launchd in future. 197 442 // Instead, we just reap zombies. 198 443 while (1) 199 444 { 200 445 int status, sig; 201 446 sigset_t chld; 202 - 447 + 203 448 sigemptyset(&chld); 204 449 sigaddset(&chld, SIGCHLD); 205 450 sigwait(&chld, &sig); 206 - 451 + 207 452 while (waitpid(-1, &status, 0) != -1); 208 453 } 209 - 210 - return 0; 211 454 } 212 455 213 456 char* defaultPrefixPath(void) ··· 215 458 const char defaultPath[] = "/.darling"; 216 459 const char* home = getenv("HOME"); 217 460 char* buf; 218 - 461 + 219 462 if (!home) 220 463 { 221 464 fprintf(stderr, "Cannot detect your home directory!\n"); 222 465 return NULL; 223 466 } 224 - 467 + 225 468 buf = (char*) malloc(strlen(home) + sizeof(defaultPath)); 226 469 strcpy(buf, home); 227 470 strcat(buf, defaultPath); 228 - 471 + 229 472 return buf; 230 473 } 231 474 232 475 void createDir(const char* path) 233 476 { 234 477 struct stat st; 235 - 478 + 236 479 if (stat(path, &st) == 0) 237 480 { 238 481 if (!S_ISDIR(st.st_mode)) ··· 253 496 } 254 497 else 255 498 { 256 - fprintf(stderr, "Problem accessing %s: %s\n", path, strerror(errno)); 499 + fprintf(stderr, "Cannot access %s: %s\n", path, strerror(errno)); 257 500 exit(1); 258 501 } 259 502 } 260 503 } 261 504 262 - void setupWorkdir(const char* prefix) 505 + void setupWorkdir() 263 506 { 264 507 char* workdir; 265 508 const char suffix[] = ".workdir"; 266 509 size_t len; 267 - 510 + 268 511 len = strlen(prefix); 269 512 workdir = (char*) alloca(len + sizeof(suffix)); 270 513 strcpy(workdir, prefix); 271 - 514 + 272 515 // Remove trailing / 273 516 while (workdir[len-1] == '/') 274 517 len--; 275 518 workdir[len] = '\0'; 276 - 519 + 277 520 strcat(workdir, suffix); 278 - 521 + 279 522 createDir(workdir); 280 523 } 281 524 282 - int getInitProcess(const char* prefix) 525 + int checkPrefixDir() 526 + { 527 + struct stat st; 528 + 529 + if (stat(prefix, &st) == 0) 530 + { 531 + if (!S_ISDIR(st.st_mode)) 532 + { 533 + fprintf(stderr, "%s is a file. Remove the file.\n", prefix); 534 + exit(1); 535 + } 536 + return 1; // OK 537 + } 538 + if (errno == ENOENT) 539 + return 0; // not found 540 + fprintf(stderr, "Cannot access %s: %s\n", prefix, strerror(errno)); 541 + exit(1); 542 + } 543 + 544 + void setupPrefix() 545 + { 546 + char path[4096]; 547 + 548 + fprintf(stderr, "Setting up a new Darling prefix at %s\n", prefix); 549 + 550 + seteuid(g_originalUid); 551 + setegid(g_originalGid); 552 + 553 + createDir(prefix); 554 + 555 + snprintf(path, sizeof(path), "%s" SYSTEM_ROOT, prefix); 556 + if (symlink("/", path) != 0) 557 + { 558 + fprintf(stderr, "Cannot symlink %s: %s\n", path, strerror(errno)); 559 + exit(1); 560 + } 561 + 562 + snprintf(path, sizeof(path), "%s/dev", prefix); 563 + if (symlink(SYSTEM_ROOT "/dev" + 1, path) != 0) 564 + { 565 + fprintf(stderr, "Cannot symlink %s: %s\n", path, strerror(errno)); 566 + exit(1); 567 + } 568 + 569 + snprintf(path, sizeof(path), "%s/tmp", prefix); 570 + if (symlink(SYSTEM_ROOT "/tmp" + 1, path) != 0) 571 + { 572 + fprintf(stderr, "Cannot symlink %s: %s\n", path, strerror(errno)); 573 + exit(1); 574 + } 575 + 576 + snprintf(path, sizeof(path), "%s/Users", prefix); 577 + if (symlink(SYSTEM_ROOT "/home" + 1, path) != 0) 578 + { 579 + fprintf(stderr, "Cannot symlink %s: %s\n", path, strerror(errno)); 580 + exit(1); 581 + } 582 + 583 + snprintf(path, sizeof(path), "%s/Volumes", prefix); 584 + createDir(path); 585 + snprintf(path, sizeof(path), "%s/Applications", prefix); 586 + createDir(path); 587 + 588 + snprintf(path, sizeof(path), "%s/var", prefix); 589 + createDir(path); 590 + snprintf(path, sizeof(path), "%s/var/root", prefix); 591 + createDir(path); 592 + snprintf(path, sizeof(path), "%s/var/run", prefix); 593 + createDir(path); 594 + 595 + snprintf(path, sizeof(path), "%s/var/run/syslog", prefix); 596 + if (symlink("../.." SYSTEM_ROOT "/dev/log", path) != 0) 597 + { 598 + fprintf(stderr, "Cannot symlink %s: %s\n", path, strerror(errno)); 599 + exit(1); 600 + } 601 + 602 + seteuid(0); 603 + setegid(0); 604 + } 605 + 606 + pid_t getInitProcess() 283 607 { 284 608 const char pidFile[] = "/.init.pid"; 285 609 char* pidPath; 286 - int fd, rd, pid; 287 - char pidBuf[10]; 288 - char exeBuf[17], procBuf[100]; 289 - 610 + pid_t pid; 611 + int pid_i; 612 + FILE *fp; 613 + char procBuf[100]; 614 + char *exeBuf, *statusBuf; 615 + int uidMatch = 0, gidMatch = 0; 616 + 290 617 pidPath = (char*) alloca(strlen(prefix) + sizeof(pidFile)); 291 618 strcpy(pidPath, prefix); 292 619 strcat(pidPath, pidFile); 293 - 294 - fd = open(pidPath, O_RDONLY); 295 - if (fd == -1) 620 + 621 + fp = fopen(pidPath, "r"); 622 + if (fp == NULL) 296 623 return 0; 297 - 298 - rd = read(fd, pidBuf, sizeof(pidBuf)-1); 299 - close(fd); 300 - 301 - if (rd <= 0) 624 + 625 + if (fscanf(fp, "%d", &pid_i) != 1) 626 + { 627 + fclose(fp); 628 + unlink(pidPath); 302 629 return 0; 303 - 304 - pidBuf[rd-1] = '\0'; 305 - pid = atoi(pidBuf); 630 + } 631 + fclose(fp); 632 + pid = (pid_t) pid_i; 306 633 307 634 // Does the process exist? 308 635 if (kill(pid, 0) == -1) ··· 310 637 unlink(pidPath); 311 638 return 0; 312 639 } 313 - 640 + 314 641 // Is it actually an init process? 315 - sprintf(procBuf, "/proc/%d/comm", pid); 316 - fd = open(procBuf, O_RDONLY); 317 - if (fd == -1) 642 + snprintf(procBuf, sizeof(procBuf), "/proc/%d/comm", pid); 643 + fp = fopen(procBuf, "r"); 644 + if (fp == NULL) 318 645 { 319 646 unlink(pidPath); 320 647 return 0; 321 648 } 322 - 323 - rd = read(fd, exeBuf, sizeof(exeBuf)-1); 324 - close(fd); 325 - 326 - if (rd <= 0) 649 + 650 + if (fscanf(fp, "%ms", &exeBuf) != 1) 327 651 { 652 + fclose(fp); 328 653 unlink(pidPath); 329 654 return 0; 330 655 } 331 - 332 - exeBuf[rd] = '\0'; 656 + fclose(fp); 657 + 333 658 if (strcmp(exeBuf, DARLING_INIT_COMM) != 0) 334 659 { 335 660 unlink(pidPath); 336 661 return 0; 337 662 } 338 - 663 + free(exeBuf); 664 + 665 + // Is it owned by the current user? 666 + if (g_originalUid != 0) 667 + { 668 + snprintf(procBuf, sizeof(procBuf), "/proc/%d/status", pid); 669 + fp = fopen(procBuf, "r"); 670 + if (fp == NULL) 671 + { 672 + unlink(pidPath); 673 + return 0; 674 + } 675 + 676 + while (1) 677 + { 678 + statusBuf = NULL; 679 + size_t len; 680 + if (getline(&statusBuf, &len, fp) == -1) 681 + break; 682 + int rid, eid, sid, fid; 683 + if (sscanf(statusBuf, "Uid: %d %d %d %d", &rid, &eid, &sid, &fid) == 4) 684 + { 685 + uidMatch = 1; 686 + uidMatch &= rid == g_originalUid; 687 + uidMatch &= eid == g_originalUid; 688 + uidMatch &= sid == g_originalUid; 689 + uidMatch &= fid == g_originalUid; 690 + } 691 + if (sscanf(statusBuf, "Gid: %d %d %d %d", &rid, &eid, &sid, &fid) == 4) 692 + { 693 + gidMatch = 1; 694 + gidMatch &= rid == g_originalGid; 695 + gidMatch &= eid == g_originalGid; 696 + gidMatch &= sid == g_originalGid; 697 + gidMatch &= fid == g_originalGid; 698 + } 699 + free(statusBuf); 700 + } 701 + fclose(fp); 702 + 703 + if (!uidMatch || !gidMatch) 704 + { 705 + unlink(pidPath); 706 + return 0; 707 + } 708 + } 709 + 339 710 return pid; 340 711 } 341 712 342 - void checkPrefixOwner(const char* prefix) 713 + void checkPrefixOwner() 343 714 { 344 715 struct stat st; 345 - 716 + 346 717 if (stat(prefix, &st) == 0) 347 718 { 348 - if (st.st_uid != getuid()) 719 + if (g_originalUid != 0 && st.st_uid != g_originalUid) 349 720 { 350 721 fprintf(stderr, "You do not own the prefix directory.\n"); 351 722 exit(1); ··· 360 731 361 732 int isModuleLoaded() 362 733 { 363 - size_t len = 0; 734 + size_t len = 0; 364 735 ssize_t read = 0; 365 - char * line = NULL; 366 - FILE *fp = NULL; 736 + char * line = NULL; 737 + FILE *fp = NULL; 367 738 368 739 if ((fp = fopen("/proc/modules", "r")) == NULL) 369 740 { 370 741 fprintf(stderr, "Failure opening /proc/modules: %s\n", strerror(errno)); 742 + fclose(fp); 371 743 return 0; 372 744 } 373 745 ··· 375 747 { 376 748 read = getline(&line, &len, fp); 377 749 if (read > 0 && strstr(line, "darling_mach") != NULL) 750 + { 751 + fclose(fp); 378 752 return 1; 753 + } 379 754 } 380 755 756 + fclose(fp); 381 757 return 0; 382 758 } 383 759 ··· 391 767 return 0; 392 768 393 769 uname(&name); 394 - sprintf(path, "/lib/modules/%s/kernel/misc/darling-mach.ko", name.release); 770 + snprintf(path, sizeof(path), "/lib/modules/%s/kernel/misc/darling-mach.ko", name.release); 395 771 if (access(path, F_OK)) 396 772 { 397 773 fprintf(stderr, "Cannot find kernel module at %s: %s\n", path, strerror(errno));
+25 -6
src/dyld/darling.h
··· 17 17 along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 18 */ 19 19 20 + #include <sys/types.h> 21 + 20 22 #ifndef _DARLING_H_ 21 23 #define _DARLING_H_ 22 24 ··· 27 29 28 30 // Returns ~/.darling with ~ expanded 29 31 char* defaultPrefixPath(void); 30 - void setupWorkdir(const char* prefix); 32 + 33 + void setupWorkdir(void); 34 + 35 + void setupPrefix(void); 36 + 37 + int checkPrefixDir(void); 31 38 32 39 // Creates the given directory, exit()ing if not possible 33 40 void createDir(const char* path); 34 41 35 - // Return the PID of the init process in prefix (in our namespace) 42 + // Spawn the specified proceess inside the namespaces that PID 1 is in 43 + // Returns the PID of the child 44 + // exit()s on error 45 + pid_t spawnChild(int pidInit, const char *path, const char *const argv[]); 46 + 47 + // Set up some environment variables 48 + // As well as the working directory 49 + // Called in the child process 50 + void setupChild(const char *curPath); 51 + 52 + // Returns the PID of the init process in prefix (in our namespace) 36 53 // Returns 0 if no init is running 37 - int getInitProcess(const char* prefix); 54 + pid_t getInitProcess(void); 55 + 56 + pid_t spawnInitProcess(void); 38 57 39 - int spawnInitProcess(const char* prefix); 58 + void putInitPid(pid_t pidInit); 40 59 41 - int darlingPreInit(void* arg); 60 + void darlingPreInit(void); 42 61 43 - void checkPrefixOwner(const char* prefix); 62 + void checkPrefixOwner(void); 44 63 45 64 int isModuleLoaded(void); 46 65
+15 -15
src/dyld/dirstructure.cpp
··· 29 29 30 30 static std::string GetUserLibrary() 31 31 { 32 - const char* home; 32 + const char *home, *prefix; 33 33 std::stringstream ss; 34 34 std::string path; 35 - 35 + 36 + prefix = getenv("DPREFIX"); 36 37 home = getenv("HOME"); 37 - if (!home) 38 + if (!prefix || !home) 38 39 return std::string(); // give up on this user 39 - 40 - ss << home << '/' << "Library" << '/'; 40 + 41 + ss << prefix << home << '/' << "Library" << '/'; 41 42 return ss.str(); 42 43 } 43 44 44 45 bool HasUserDirectoryStructure() 45 46 { 46 47 std::string path = GetUserLibrary(); 47 - 48 + 48 49 if (path.empty()) 49 50 return true; // give up on this user 50 - 51 + 51 52 if (::access(path.c_str(), F_OK) == -1) 52 53 return false; 53 54 else ··· 90 91 "Spelling", 91 92 "Voices", 92 93 }; 93 - 94 + 94 95 std::string path = GetUserLibrary(); 95 - 96 + 96 97 if (path.empty()) 97 98 return; 98 - 99 + 99 100 std::cerr << "Darling: Creating Library structure at " << path << std::endl; 100 - 101 + 101 102 if (::mkdir(path.c_str(), 0777) == -1) 102 103 std::cerr << "Darling: Cannot mkdir(" << path << "): " << strerror(errno) << std::endl; 103 - 104 + 104 105 for (const char* dir : dirs) 105 106 { 106 107 std::string s = path; 107 - 108 + 108 109 s += dir; 109 - 110 + 110 111 if (::mkdir(s.c_str(), 0777) == -1) 111 112 std::cerr << "Darling: Cannot mkdir(" << s << "): " << strerror(errno) << std::endl; 112 113 } 113 114 } 114 -