11static int dumpable(
void) {
12 return prctl(PR_GET_DUMPABLE, 0UL, 0UL, 0UL, 0UL);
14static int self(
void) {
16 unsigned char source = 0x31, destination = 0;
17 CHECK(!pm_dumpable(0) && dumpable() == 0);
18 CHECK(pm_copy(getpid(), &destination, &source, 1, 0) == 1 && destination == 0x31);
20 CHECK(pm_copy(getpid(), &destination, &source, 1, 1) == 1 && source == 0x42);
22 CHECK(prctl(PR_SET_DUMPABLE, 2UL, 0UL, 0UL, 0UL) == -1 && errno == EINVAL);
23 CHECK(dumpable() == 0 && !pm_dumpable(1) && dumpable() == 1);
27static int policy_target(
int command,
int report,
void* ignored) {
30 volatile unsigned char byte;
31 uintptr_t address = (uintptr_t)&
byte;
32 for (
int step = 0; step < 8; ++step) {
33 CHECK(!setresuid(0, 0, 0) && !setresgid(0, 0, 0));
36 CHECK(!setresuid(70001, -1, -1));
39 CHECK(!setresuid(-1, 70001, -1));
42 CHECK(!setresuid(-1, -1, 70001));
45 CHECK(!setresgid(70002, -1, -1));
48 CHECK(!setresgid(-1, 70002, -1));
51 CHECK(!setresgid(-1, -1, 70002));
54 CHECK(!pm_dumpable(step != 1));
56 CHECK(!pm_write(report, &address,
sizeof(address)) && !pm_receive(command,
'n'));
57 CHECK(
byte == (step == 0 ? 0x5b : 0x4a));
62static int policy(
void) {
64 struct pm_peer peer = PM_PEER_INITIALIZER;
67 CHECK(getuid() == 0 && geteuid() == 0 && getgid() == 0 && getegid() == 0);
68 CHECK(!pm_spawn(&peer, policy_target, NULL));
69 for (
int step = 0; step < 8; ++step) {
70 CHECK(!pm_read(peer.report, &address,
sizeof(address)));
73 CHECK(pm_copy(peer.pid, &
byte, (
void*)address, 1, 0) == 1 &&
byte == 0x4a);
74 CHECK(setfsuid(70001) == 0 && setfsgid(70002) == 0);
75 CHECK(!seteuid(70003) && getuid() == 0 && geteuid() == 70003);
76 CHECK(pm_copy(peer.pid, &
byte, (
void*)address, 1, 0) == 1 &&
byte == 0x4a);
77 CHECK(!seteuid(0) && setfsgid(0) == 70002);
79 CHECK(pm_copy(peer.pid, &
byte, (
void*)address, 1, 1) == 1);
82 CHECK(pm_copy(peer.pid, &
byte, (
void*)address, 1, 0) == -1 && errno == EPERM);
85 CHECK(pm_copy(peer.pid, &
byte, (
void*)address, 1, 1) == -1 && errno == EPERM);
87 CHECK(!pm_send(peer.command,
'n'));
89 CHECK(!pm_join(&peer));
97static int ids(uid_t r, uid_t e, uid_t s, gid_t gr, gid_t ge, gid_t gs) {
98 uid_t actual_r, actual_e, actual_s;
99 gid_t actual_gr, actual_ge, actual_gs;
100 return getresuid(&actual_r, &actual_e, &actual_s) ||
101 getresgid(&actual_gr, &actual_ge, &actual_gs) || actual_r != r || actual_e != e ||
102 actual_s != s || actual_gr != gr || actual_ge != ge || actual_gs != gs;
104static int transitions(
void) {
107 CHECK(!setresgid(70001, 70002, 70003) && !setresuid(71001, 71002, 71003));
108 CHECK(!ids(71001, 71002, 71003, 70001, 70002, 70003) && dumpable() == 0);
109 CHECK(setfsuid(-1) == 71002 && setfsgid(-1) == 70002);
110 CHECK(!pm_dumpable(1) && setfsuid(71003) == 71002 && dumpable() == 0);
112 CHECK(setfsuid(79999) == 71003 && errno == 0 && setfsuid(-1) == 71003);
113 CHECK(!setresuid(-1, -1, -1) && setfsuid(-1) == 71003);
114 CHECK(!setresuid(-1, 71002, -1) && setfsuid(-1) == 71002);
115 CHECK(setfsgid(70003) == 70002);
117 CHECK(setfsgid(79999) == 70003 && errno == 0 && setfsgid(-1) == 70003);
118 CHECK(!setresgid(-1, 70002, -1) && setfsgid(-1) == 70002);
120 CHECK(setresuid(71002, 79999, -1) == -1 && errno == EPERM);
121 CHECK(!ids(71001, 71002, 71003, 70001, 70002, 70003));
123 CHECK(setresgid(70002, 79999, -1) == -1 && errno == EPERM);
124 CHECK(!ids(71001, 71002, 71003, 70001, 70002, 70003));
125 CHECK(!pm_dumpable(1));
126 execl(
"/applications/process-memory-missing",
"missing", (
char*)NULL);
127 CHECK(errno == ENOENT && dumpable() == 1 && !ids(71001, 71002, 71003, 70001, 70002, 70003));
131 if (ids(71001, 71002, 71003, 70001, 70002, 70003) || dumpable() != 1)
133 execl(PM_APP, PM_APP,
"fs-exec",
"71001",
"71002",
"70001",
"70002",
"0", (
char*)NULL);
136 int status = pm_reap(child, 10000);
139 CHECK(!setuid(71001) && !setgid(70001));
140 CHECK(!ids(71001, 71001, 71003, 70001, 70001, 70003));
142 CHECK(setuid(79999) == -1 && errno == EPERM);
144 CHECK(setgid(79999) == -1 && errno == EPERM);
145 CHECK(!ids(71001, 71001, 71003, 70001, 70001, 70003));
151static int groups(
void) {
153 gid_t chosen[] = {70003, 70001, 70003}, actual[3], invalid = (gid_t)-1;
154 void* bad = mmap(NULL, pm_page, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
155 CHECK(bad != MAP_FAILED && !setgroups(3, chosen));
156 CHECK(getgroups(0, NULL) == 3 && getgroups(3, actual) == 3);
157 CHECK(actual[0] == 70001 && actual[1] == 70003 && actual[2] == 70003);
159 CHECK(setgroups(33, NULL) == -1 && errno == EINVAL);
161 CHECK(setgroups(1, bad) == -1 && errno == EFAULT);
163 CHECK(setgroups(1, &invalid) == -1 && errno == EINVAL);
164 CHECK(getgroups(3, actual) == 3 && actual[0] == 70001 && actual[2] == 70003);
165 CHECK(!setuid(71001));
167 CHECK(setgroups(0, NULL) == -1 && errno == EPERM);
168 CHECK(getgroups(0, NULL) == 3);
170 if (bad != MAP_FAILED)
171 munmap(bad, pm_page);
174int pm_credentials(
void) {
175 return self() || policy() || pm_isolate(transitions) || pm_isolate(groups);