this repo has no description
1
fork

Configure Feed

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

Add `exec` subcommand to `darling` executable

This subcommand allows you to execute a binary directly, without the
need for a shell.

authored by

Ariel Abreu and committed by
Thomas A
b926434f ad4e30fe

+149 -53
+23 -3
src/shellspawn/shellspawn.c
··· 48 48 49 49 int main(int argc, const char** argv) 50 50 { 51 - setupSigchild(); 51 + // in order to read the exit status of the process, 52 + // we have to allow it to become a zombie, which is prevented 53 + // when we set the SIGCHLD signal to SA_NOCLDWAIT 54 + //setupSigchild(); 52 55 setupSocket(); 53 56 listenForConnections(); 54 57 ··· 133 136 argv = (char**) malloc(sizeof(char*) * 3); 134 137 argv[0] = "/bin/bash"; 135 138 argv[1] = "--login"; 139 + 140 + char* alloc_exec = NULL; 136 141 137 142 // Read commands from client 138 143 while (read_cmds) ··· 238 243 239 244 break; 240 245 } 246 + case SHELLSPAWN_SETEXEC: 247 + { 248 + argc = 0; 249 + argv = realloc(argv, 0); 250 + alloc_exec = param; 251 + if (DBG) printf("setexec: %s\n", param); 252 + break; 253 + } 241 254 } 242 255 } 243 256 ··· 270 283 271 284 // In future, we may support spawning something else than Bash 272 285 // and check the provided shell against /etc/shells 273 - execv("/bin/bash", argv); 286 + execv(alloc_exec ? alloc_exec : "/bin/bash", argv); 274 287 275 288 rv = errno; 276 289 write(pipefd[1], &rv, sizeof(rv)); 277 290 close(pipefd[1]); 278 291 279 292 exit(EXIT_FAILURE); 293 + } 294 + 295 + if (alloc_exec) 296 + { 297 + free(alloc_exec); 298 + alloc_exec = NULL; 280 299 } 281 300 282 301 // Check that exec succeeded ··· 379 398 380 399 // Reap the child 381 400 int wstatus; 382 - waitpid(shell_pid, &wstatus, WEXITED); 401 + if (waitpid(shell_pid, &wstatus, 0) != shell_pid) 402 + perror("waitpid"); 383 403 wstatus = WEXITSTATUS(wstatus); 384 404 385 405 // Report exit code back to the client
+2 -1
src/shellspawn/shellspawn.h
··· 32 32 SHELLSPAWN_ADDARG = 1, // add shell argument 33 33 SHELLSPAWN_SETENV, // add env variable string 34 34 SHELLSPAWN_CHDIR, 35 - SHELLSPAWN_GO, // execute the shell now, must also contain file descriptors 35 + SHELLSPAWN_GO, // execute the shell/executable now, must also contain file descriptors 36 36 SHELLSPAWN_SIGNAL, // pass a signal from client 37 37 SHELLSPAWN_SETUIDGID, // set virtual uid and gid 38 + SHELLSPAWN_SETEXEC, // set the executable to spawn (instead of a shell). must be given before any ADDARG commands. 38 39 }; 39 40 40 41 struct __attribute__((packed)) shellspawn_cmd
+117 -49
src/startup/darling.c
··· 1 1 /* 2 2 This file is part of Darling. 3 3 4 - Copyright (C) 2016-2020 Lubos Dolezel 4 + Copyright (C) 2016-2023 Lubos Dolezel 5 5 6 6 Darling is free software: you can redistribute it and/or modify 7 7 it under the terms of the GNU General Public License as published by ··· 202 202 } 203 203 else 204 204 { 205 + bool doExec = strcmp(argv[1], "exec") == 0; 206 + int argvIndex = doExec ? 2 : 1; 207 + 208 + if (doExec && argc <= 2) 209 + { 210 + printf("'exec' subcommand requires a binary to execute.\n"); 211 + return 1; 212 + } 213 + 205 214 char *fullPath; 206 - char *path = realpath(argv[1], NULL); 215 + char *path = realpath(argv[argvIndex], NULL); 207 216 208 217 if (path == NULL) 209 218 { 210 - printf("'%s' is not a supported command or a file.\n", argv[1]); 219 + printf("'%s' is not a supported command or a file.\n", argv[argvIndex]); 211 220 return 1; 212 221 } 213 222 ··· 216 225 strcat(fullPath, path); 217 226 free(path); 218 227 219 - argv[1] = fullPath; 220 - spawnShell((const char**) &argv[1]); 228 + argv[argvIndex] = fullPath; 229 + 230 + if (doExec) 231 + spawnBinary(argv[argvIndex], (const char**) &argv[argvIndex]); 232 + else 233 + spawnShell((const char**) &argv[argvIndex]); 221 234 } 222 235 223 236 return 0; ··· 532 545 return len; 533 546 } 534 547 535 - void spawnShell(const char** argv) 548 + int connectToShellspawn(void) 536 549 { 537 - size_t total_len = 0; 538 - int count; 539 - char buffer2[4096]; 540 - int sockfd; 541 550 struct sockaddr_un addr; 542 - char* buffer; 543 - 544 - if (argv != NULL) 545 - { 546 - for (count = 0; argv[count] != NULL; count++) 547 - total_len += escapeQuotes(NULL, argv[count]); 548 - 549 - buffer = malloc(total_len + count*3); 550 - 551 - char *to = buffer; 552 - for (int i = 0; argv[i] != NULL; i++) 553 - { 554 - if (to != buffer) 555 - to = stpcpy(to, " "); 556 - to = stpcpy(to, "'"); 557 - to += escapeQuotes(to, argv[i]); 558 - to = stpcpy(to, "'"); 559 - } 560 - } 561 - else 562 - buffer = NULL; 551 + int sockfd; 563 552 564 553 // Connect to the shellspawn daemon in the container 565 554 addr.sun_family = AF_UNIX; ··· 585 574 exit(1); 586 575 } 587 576 577 + return sockfd; 578 + } 579 + 580 + void setupShellspawnEnv(int sockfd) 581 + { 582 + char buffer2[4096]; 583 + 588 584 // Push environment variables 589 585 pushShellspawnCommand(sockfd, SHELLSPAWN_SETENV, 590 586 "PATH=/usr/bin:" ··· 610 606 611 607 snprintf(buffer2, sizeof(buffer2), "HOME=/Users/%s", login); 612 608 pushShellspawnCommand(sockfd, SHELLSPAWN_SETENV, buffer2); 609 + } 613 610 614 - // Push shell arguments 615 - if (buffer != NULL) 616 - { 617 - pushShellspawnCommand(sockfd, SHELLSPAWN_ADDARG, "-c"); 618 - pushShellspawnCommand(sockfd, SHELLSPAWN_ADDARG, buffer); 619 - 620 - free(buffer); 621 - } 622 - 611 + void setupWorkingDir(int sockfd) 612 + { 613 + char buffer2[4096]; 623 614 snprintf(buffer2, sizeof(buffer2), SYSTEM_ROOT "%s", g_workingDirectory); 624 615 pushShellspawnCommand(sockfd, SHELLSPAWN_CHDIR, buffer2); 616 + } 625 617 618 + void setupIDs(int sockfd) 619 + { 626 620 int ids[2] = { g_originalUid, g_originalGid }; 627 621 pushShellspawnCommandData(sockfd, SHELLSPAWN_SETUIDGID, ids, sizeof(ids)); 622 + } 628 623 629 - int fds[3], master = -1; 630 - 624 + void setupFDs(int fds[3], int* master) 625 + { 626 + *master = -1; 627 + 631 628 if (isatty(STDIN_FILENO)) 632 - setupPtys(fds, &master); 629 + setupPtys(fds, master); 633 630 else 634 - fds[0] = dup(STDIN_FILENO); // dup() because we close() a few lines below 631 + fds[0] = dup(STDIN_FILENO); // dup() because we close() after spawning 635 632 636 - if (master == -1 || !isatty(STDOUT_FILENO)) 633 + if (*master == -1 || !isatty(STDOUT_FILENO)) 637 634 fds[1] = STDOUT_FILENO; 638 - if (master == -1 || !isatty(STDERR_FILENO)) 635 + if (*master == -1 || !isatty(STDERR_FILENO)) 639 636 fds[2] = STDERR_FILENO; 637 + } 640 638 639 + void spawnGo(int sockfd, int fds[3], int master) 640 + { 641 641 pushShellspawnCommandFDs(sockfd, SHELLSPAWN_GO, fds); 642 642 close(fds[0]); 643 643 ··· 648 648 close(sockfd); 649 649 } 650 650 651 + void spawnShell(const char** argv) 652 + { 653 + size_t total_len = 0; 654 + int count; 655 + int sockfd; 656 + char* buffer; 657 + int fds[3], master; 658 + 659 + if (argv != NULL) 660 + { 661 + for (count = 0; argv[count] != NULL; count++) 662 + total_len += escapeQuotes(NULL, argv[count]); 663 + 664 + buffer = malloc(total_len + count*3); 665 + 666 + char *to = buffer; 667 + for (int i = 0; argv[i] != NULL; i++) 668 + { 669 + if (to != buffer) 670 + to = stpcpy(to, " "); 671 + to = stpcpy(to, "'"); 672 + to += escapeQuotes(to, argv[i]); 673 + to = stpcpy(to, "'"); 674 + } 675 + } 676 + else 677 + buffer = NULL; 678 + 679 + sockfd = connectToShellspawn(); 680 + 681 + setupShellspawnEnv(sockfd); 682 + 683 + // Push shell arguments 684 + if (buffer != NULL) 685 + { 686 + pushShellspawnCommand(sockfd, SHELLSPAWN_ADDARG, "-c"); 687 + pushShellspawnCommand(sockfd, SHELLSPAWN_ADDARG, buffer); 688 + 689 + free(buffer); 690 + } 691 + 692 + setupWorkingDir(sockfd); 693 + setupIDs(sockfd); 694 + setupFDs(fds, &master); 695 + spawnGo(sockfd, fds, master); 696 + } 697 + 698 + void spawnBinary(const char* binary, const char** argv) 699 + { 700 + int fds[3], master; 701 + int sockfd; 702 + 703 + sockfd = connectToShellspawn(); 704 + setupShellspawnEnv(sockfd); 705 + 706 + pushShellspawnCommand(sockfd, SHELLSPAWN_SETEXEC, binary); 707 + 708 + for (; *argv != NULL; ++argv) 709 + pushShellspawnCommand(sockfd, SHELLSPAWN_ADDARG, *argv); 710 + 711 + setupWorkingDir(sockfd); 712 + setupIDs(sockfd); 713 + setupFDs(fds, &master); 714 + spawnGo(sockfd, fds, master); 715 + } 716 + 651 717 void showHelp(const char* argv0) 652 718 { 653 719 fprintf(stderr, "This is Darling, translation layer for macOS software.\n\n"); 654 - fprintf(stderr, "Copyright (C) 2012-2020 Lubos Dolezel\n\n"); 720 + fprintf(stderr, "Copyright (C) 2012-2023 Lubos Dolezel\n\n"); 655 721 656 722 fprintf(stderr, "Usage:\n"); 657 - fprintf(stderr, "\t%s program-path [arguments...]\n", argv0); 723 + fprintf(stderr, "\t%s <program-path> [arguments...]\n", argv0); 658 724 fprintf(stderr, "\t%s shell [arguments...]\n", argv0); 725 + fprintf(stderr, "\t%s exec <program-path> [arguments...]\n", argv0); 726 + fprintf(stderr, "\t%s shutdown\n", argv0); 659 727 fprintf(stderr, "\n"); 660 728 fprintf(stderr, "Environment variables:\n" 661 729 "DPREFIX - specifies the location of Darling prefix, defaults to ~/.darling\n"); ··· 663 731 664 732 void showVersion(const char* argv0) { 665 733 fprintf(stderr, "%s " GIT_BRANCH " @ " GIT_COMMIT_HASH "\n", argv0); 666 - fprintf(stderr, "Copyright (C) 2012-2020 Lubos Dolezel\n"); 734 + fprintf(stderr, "Copyright (C) 2012-2023 Lubos Dolezel\n"); 667 735 } 668 736 669 737 void missingSetuidRoot(void)
+7
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 + int connectToShellspawn(void); 44 + void setupShellspawnEnv(int shellspawnFD); 45 + void setupWorkingDir(int shellspawnFD); 46 + void setupIDs(int shellspawnFD); 47 + void setupFDs(int fds[3], int* master); 48 + void spawnGo(int shellspawnFD, int fds[3], int master); 43 49 void spawnShell(const char** argv); 50 + void spawnBinary(const char* binary, const char** argv); 44 51 45 52 // Set up some environment variables 46 53 // As well as the working directory