#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>
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;
return -ERR_SYSTEM;
}
- if (!pa->flags & PA_HAS_ID) {
+ if (!(pa->flags & PA_HAS_ID)) {
err_print("No persona ID specified!");
return -ERR_SYSTEM;
}
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) {
}
}
+ 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);
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;
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;
*
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
-static void main_sighandler(int sig)
+static void
+main_sighandler(int sig)
{
dbg("PID: %d received sig %d", getpid(), sig);
if (sig == SIGCHLD) {
}
}
-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");
exit(1);
}
-int main(int argc, char **argv)
+int
+main(int argc, char **argv)
{
char ch;
int ret;
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
*/
}
- 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));
/*
* 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;
}
}
- if (pa.flags & PA_SHOULD_VERIFY)
+ if (pa.flags & PA_SHOULD_VERIFY) {
pa.flags = ~PA_OVERRIDE;
+ }
if (optind >= argc) {
printf("No program given!\n");
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;
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);
+ }
}
}