]> git.saurik.com Git - apple/xnu.git/blobdiff - tools/tests/personas/persona_spawn.c
xnu-7195.50.7.100.1.tar.gz
[apple/xnu.git] / tools / tests / personas / persona_spawn.c
index b6e7782ceffc118b69faeb87bf8f7e677270c5da..618fa76a9d085435c1cc387d8768e76cc1018772 100644 (file)
@@ -19,6 +19,7 @@
 #include <mach/mach.h>
 #include <mach/task.h>
 #include <mach/vm_param.h>
+#include <sys/kauth.h>
 #include <sys/queue.h>
 #include <sys/sysctl.h>
 #include <sys/types.h>
@@ -57,7 +58,8 @@ static pthread_mutex_t g_child_mtx;
 static TAILQ_HEAD(, child) g_children = TAILQ_HEAD_INITIALIZER(g_children);
 static int g_nchildren = 0;
 
-static pid_t spawn_child(int argc, char **argv, struct persona_args *pa)
+static pid_t
+spawn_child(int argc, char **argv, struct persona_args *pa)
 {
        int ret;
        uint32_t persona_flags = 0;
@@ -72,7 +74,7 @@ static pid_t spawn_child(int argc, char **argv, struct persona_args *pa)
                return -ERR_SYSTEM;
        }
 
-       if (!pa->flags & PA_HAS_ID) {
+       if (!(pa->flags & PA_HAS_ID)) {
                err_print("No persona ID specified!");
                return -ERR_SYSTEM;
        }
@@ -98,11 +100,13 @@ static pid_t spawn_child(int argc, char **argv, struct persona_args *pa)
                goto out_err;
        }
 
-       if (pa->flags & PA_SHOULD_VERIFY)
+       if (pa->flags & PA_SHOULD_VERIFY) {
                persona_flags |= POSIX_SPAWN_PERSONA_FLAGS_VERIFY;
+       }
 
-       if (pa->flags & PA_OVERRIDE)
+       if (pa->flags & PA_OVERRIDE) {
                persona_flags |= POSIX_SPAWN_PERSONA_FLAGS_OVERRIDE;
+       }
 
        ret = posix_spawnattr_set_persona_np(&attr, pa->kinfo.persona_id, persona_flags);
        if (ret != 0) {
@@ -129,6 +133,15 @@ static pid_t spawn_child(int argc, char **argv, struct persona_args *pa)
                }
        }
 
+       if (pa->flags & PA_HAS_GROUPS) {
+               ret = posix_spawnattr_set_persona_groups_np(&attr, pa->kinfo.persona_ngroups, pa->kinfo.persona_groups, KAUTH_UID_NONE);
+               if (ret != 0) {
+                       err_print("");
+                       ret = -ERR_SPAWN_ATTR;
+                       goto out_err;
+               }
+       }
+
        ret = posix_spawn(&child->pid, argv[0], NULL, &attr, argv, environ);
        if (ret != 0) {
                err_print("posix_spawn (ret=%d)", ret);
@@ -156,14 +169,16 @@ out_err:
 
 static int child_should_exit = 0;
 
-static void child_sighandler(int sig)
+static void
+child_sighandler(int sig)
 {
        (void)sig;
        dbg("PID: %d received sig %d", getpid(), sig);
        child_should_exit = 1;
 }
 
-static int child_main_loop(int argc, char **argv)
+static int
+child_main_loop(int argc, char **argv)
 {
        char ch;
        sigset_t sigset;
@@ -214,17 +229,20 @@ static int child_main_loop(int argc, char **argv)
 
        kinfo.persona_info_version = PERSONA_INFO_V1;
        err = kpersona_info(persona_id, &kinfo);
-       if (err == 0)
+       if (err == 0) {
                dump_kpersona("Child: kpersona_info", &kinfo);
-       else
+       } else {
                info("Child: ERROR grabbing kpersona_info: %d", errno);
+       }
 
-       if (child_should_exit)
+       if (child_should_exit) {
                return rval;
+       }
 
        infov("Child Sleeping!");
-       while (!child_should_exit)
+       while (!child_should_exit) {
                sleep(1);
+       }
 
        infov("Child exiting!");
        return rval;
@@ -237,7 +255,8 @@ static int child_main_loop(int argc, char **argv)
  *
  * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  */
-static void main_sighandler(int sig)
+static void
+main_sighandler(int sig)
 {
        dbg("PID: %d received sig %d", getpid(), sig);
        if (sig == SIGCHLD) {
@@ -245,20 +264,24 @@ static void main_sighandler(int sig)
        }
 }
 
-static void usage_main(const char *progname, int verbose)
+static void
+usage_main(const char *progname, int verbose)
 {
        const char *nm = basename((char *)progname);
 
        printf("%s v%d.%d\n", PERSONA_TEST_NAME, PERSONA_TEST_VMAJOR, PERSONA_TEST_VMINOR);
        printf("usage: %s [-I id] [-V] [-u uid] [-g gid] [-vw] progname [args...]\n", nm);
        printf("       Spawn a new process into a new or existing persona.\n");
-       if (!verbose)
+       if (!verbose) {
                exit(1);
+       }
 
        printf("\t%-10s\tID of the persona\n", "-I id");
        printf("\t%-10s\tVerify persona parameters against existing persona (given by -I)\n", "-V");
        printf("\t%-10s\tOverride/verify the user ID of the new process\n", "-u uid");
        printf("\t%-10s\tOverride/verify the group ID of the new process\n", "-g gid");
+       printf("\t%-15s\tGroups to which the persona will belong\n", "-G {groupspec}");
+       printf("\t%-15s\tgroupspec: G1{,G2,G3...}\n", " ");
        printf("\t%-10s\tBe verbose\n", "-v");
        printf("\t%-10s\tDo not wait for the child process\n", "-w");
        printf("\n");
@@ -266,7 +289,8 @@ static void usage_main(const char *progname, int verbose)
        exit(1);
 }
 
-int main(int argc, char **argv)
+int
+main(int argc, char **argv)
 {
        char ch;
        int ret;
@@ -282,8 +306,14 @@ int main(int argc, char **argv)
        if (argc > 1 && strcmp(argv[1], "child") == 0) {
                optind = 2;
                ret = child_main_loop(argc, argv);
-               if (ret != 1)
+               if (ret != 1) {
+                       exit(ret);
+               }
+               if (strcmp(argv[optind], "spawn") != 0) {
+                       printf("child exiting (%s).\n", argv[optind]);
                        exit(0);
+               }
+               optind++;
 
                /*
                 * If we get here, then the child wants us to continue running
@@ -293,8 +323,9 @@ int main(int argc, char **argv)
                 */
        }
 
-       if (geteuid() != 0)
+       if (geteuid() != 0) {
                err("%s must be run as root", argv[0] ? basename(argv[0]) : PERSONA_TEST_NAME);
+       }
 
        struct persona_args pa;
        memset(&pa, 0, sizeof(pa));
@@ -305,28 +336,33 @@ int main(int argc, char **argv)
        /*
         * Argument parse for default overrides:
         */
-       while ((ch = getopt(argc, argv, "Vg:I:u:vwh")) != -1) {
+       while ((ch = getopt(argc, argv, "Vg:G:I:u:vwh")) != -1) {
                switch (ch) {
                case 'V':
                        pa.flags |= PA_SHOULD_VERIFY;
                        break;
                case 'g':
                        pa.kinfo.persona_gid = atoi(optarg);
-                       if (pa.kinfo.persona_gid <= 500)
-                               err("Invalid GID: %d", pa.kinfo.persona_gid);
                        pa.flags |= PA_HAS_GID;
                        pa.flags |= PA_OVERRIDE;
                        break;
+               case 'G':
+                       ret = parse_groupspec(&pa.kinfo, optarg);
+                       if (ret < 0) {
+                               err("Invalid groupspec: \"%s\"", optarg);
+                       }
+                       pa.flags |= PA_HAS_GROUPS;
+                       pa.flags |= PA_OVERRIDE;
+                       break;
                case 'I':
                        pa.kinfo.persona_id = atoi(optarg);
-                       if (pa.kinfo.persona_id == 0)
+                       if (pa.kinfo.persona_id == 0) {
                                err("Invalid Persona ID: %s", optarg);
+                       }
                        pa.flags |= PA_HAS_ID;
                        break;
                case 'u':
                        pa.override_uid = atoi(optarg);
-                       if (pa.override_uid <= 500)
-                               err("Invalid UID: %d", pa.override_uid);
                        pa.flags |= PA_HAS_UID;
                        pa.flags |= PA_OVERRIDE;
                        break;
@@ -346,8 +382,9 @@ int main(int argc, char **argv)
                }
        }
 
-       if (pa.flags & PA_SHOULD_VERIFY)
+       if (pa.flags & PA_SHOULD_VERIFY) {
                pa.flags = ~PA_OVERRIDE;
+       }
 
        if (optind >= argc) {
                printf("No program given!\n");
@@ -362,8 +399,9 @@ int main(int argc, char **argv)
        argv[argc] = NULL;
 
        ret = spawn_child(argc, argv, &pa);
-       if (ret < 0)
+       if (ret < 0) {
                return ret;
+       }
 
        pid_t child_pid = (pid_t)ret;
        int status = 0;
@@ -378,9 +416,10 @@ int main(int argc, char **argv)
                waitpid(child_pid, &status, 0);
                if (WIFEXITED(status)) {
                        status = WEXITSTATUS(status);
-                       if (status != 0)
+                       if (status != 0) {
                                errc(ERR_CHILD_FAIL,
-                                    "Child exited with status: %d", status);
+                                   "Child exited with status: %d", status);
+                       }
                }
        }