1 #include <darwintest.h>
7 #include <spawn_private.h>
13 #include <sys/kauth.h>
14 #include <sys/proc_info.h>
15 #include <sys/spawn_internal.h>
16 #include <sys/sysctl.h>
20 T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true));
22 T_DECL(posix_spawn_posix_cred
, "Check posix_spawnattr for POSIX creds",
25 posix_spawnattr_t attr
;
28 ret
= posix_spawnattr_init(&attr
);
30 T_ASSERT_POSIX_SUCCESS(ret
, "posix_spawnattr_init");
32 ret
= posix_spawnattr_setflags(&attr
, POSIX_SPAWN_START_SUSPENDED
);
34 T_ASSERT_POSIX_SUCCESS(ret
, "posix_spawnattr_setflags");
36 ret
= posix_spawnattr_setflags(&attr
, POSIX_SPAWN_SETSID
);
37 T_ASSERT_POSIX_SUCCESS(ret
, "posix_spawnattr_setflags(POSIX_SPAWN_SETSID)");
39 ret
= posix_spawnattr_set_uid_np(&attr
, 502);
40 T_ASSERT_POSIX_SUCCESS(ret
, "posix_spawnattr_set_uid_np");
42 ret
= posix_spawnattr_set_gid_np(&attr
, 501);
43 T_ASSERT_POSIX_SUCCESS(ret
, "posix_spawnattr_set_gid_np");
45 gid_t groups
[3] = { 501, 250, 299 };
46 ret
= posix_spawnattr_set_groups_np(&attr
, 3, &groups
, KAUTH_UID_NONE
);
47 T_ASSERT_POSIX_SUCCESS(ret
, "posix_spawnattr_set_groups_np");
49 ret
= posix_spawnattr_set_login_np(&attr
, "fake-name");
50 T_ASSERT_POSIX_SUCCESS(ret
, "posix_spawnattr_set_login_np");
52 char * const prog
= "/bin/sh";
53 char * const argv_child
[] = { prog
,
55 "test $(logname) = \"fake-name\" -a \"$(id -G)\" = \"501 250 299\"",
58 extern char **environ
;
60 ret
= posix_spawn(&child_pid
, prog
, NULL
, &attr
, argv_child
, environ
);
61 T_ASSERT_POSIX_SUCCESS(ret
, "posix_spawn");
63 T_LOG("parent: spawned child with pid %d\n", child_pid
);
65 ret
= posix_spawnattr_destroy(&attr
);
67 T_ASSERT_POSIX_SUCCESS(ret
, "posix_spawnattr_destroy");
69 struct proc_bsdinfo info
;
71 ret
= proc_pidinfo(child_pid
, PROC_PIDTBSDINFO
, 1, &info
, sizeof(info
));
73 T_ASSERT_EQ(ret
, (int)sizeof(info
), "proc_pidinfo(PROC_PIDTBSDINFO)");
75 T_EXPECT_TRUE((bool)(info
.pbi_flags
& PROC_FLAG_SLEADER
),
76 "check setsid happened");
77 T_EXPECT_EQ(info
.pbi_uid
, 502, "UID was set");
78 T_EXPECT_EQ(info
.pbi_gid
, 501, "GID was set");
80 ret
= kill(child_pid
, SIGCONT
);
81 T_ASSERT_POSIX_SUCCESS(ret
, "kill(signal)");
83 T_LOG("parent: waiting for child process\n");
86 int waitpid_result
= waitpid(child_pid
, &status
, 0);
87 T_ASSERT_POSIX_SUCCESS(waitpid_result
, "waitpid");
88 T_ASSERT_EQ(waitpid_result
, child_pid
, "waitpid should return child we spawned");
89 T_ASSERT_EQ(WIFEXITED(status
), 1, "child should have exited normally");
90 T_ASSERT_EQ(WEXITSTATUS(status
), EX_OK
, "child should have exited with success");