6#include <sys/syscall.h>
8enum { OWNER_REAL = 51001, OWNER_EFFECTIVE = 51002, OWNER_SAVED = 51003, FOREIGN = 51004 };
18static void* target_entry(
void* argument) {
20 if (sc_pin(0, sc_cpus[0]))
22 state->tid = (pid_t)syscall(SYS_gettid);
23 atomic_store_explicit(&state->ready, 1, memory_order_release);
26 if (sc_read(state->command, &command, 1))
32 unsigned node = UINT32_MAX;
35 result.failed = syscall(SYS_getcpu, &result.cpu, &node, NULL) || node ||
36 sched_getaffinity(0,
sizeof(mask), &mask);
37 result.count = result.failed ? -1 : CPU_COUNT(&mask);
38 if (sc_write(state->report, &result,
sizeof(result)))
42static int target_child(
int command,
int report,
void* argument) {
44 if (setresuid(OWNER_REAL, OWNER_EFFECTIVE, OWNER_SAVED))
49 struct target_state state = {.command = gate[0], .report = report};
51 if (pthread_create(&thread, NULL, target_entry, &state))
53 if (sc_wait(&state.ready, 1) || sc_write(report, &state.tid,
sizeof(state.tid)))
57 if (sc_read(command, &
byte, 1) || (
byte !=
'S' &&
byte !=
'Q') || sc_send(gate[1],
byte))
63 int failed = pthread_join(thread, &result) || result;
70 uid_t real, effective, filesystem;
71 int allowed, destination;
73static int permission_child(
int command,
int report,
void* argument) {
78 CHECK(setresuid(test->real, test->effective, 0) == 0);
79 setfsuid(test->filesystem);
80 CHECK((uid_t)setfsuid((uid_t)-1) == test->filesystem);
81 CHECK(geteuid() == test->effective);
82 cpu_set_t before, after;
83 struct sched_param param = {.sched_priority = 0};
84 CHECK(sched_getaffinity(test->target,
sizeof(before), &before) == 0);
85 CHECK(syscall(SYS_sched_getscheduler, test->target) == SCHED_OTHER);
86 CHECK(syscall(SYS_sched_getparam, test->target, ¶m) == 0 && !param.sched_priority);
88 int result = sc_pin(test->target, test->destination);
89 CHECK(test->allowed ? result == 0 : result == -1 && errno == EPERM);
90 CHECK(sched_getaffinity(test->target,
sizeof(after), &after) == 0);
91 CHECK(test->allowed ? sc_mask(test->target, test->destination) == 0 : CPU_EQUAL(&before, &after));
93 long policy = syscall(SYS_sched_setparam, test->target, ¶m);
94 CHECK(test->allowed ? policy == 0 : policy == -1 && errno == EPERM);
96 policy = syscall(SYS_sched_setscheduler, test->target, SCHED_OTHER, ¶m);
97 CHECK(test->allowed ? policy == 0 : policy == -1 && errno == EPERM);
98 CHECK(syscall(SYS_sched_getscheduler, test->target) == SCHED_OTHER);
102int sc_permissions(
void) {
104 struct sc_peer target = SC_PEER_INITIALIZER, caller = SC_PEER_INITIALIZER;
105 CHECK(geteuid() == 0);
106 CHECK(sc_spawn(&target, target_child, NULL) == 0);
108 CHECK(sc_read(target.report, &tid,
sizeof(tid)) == 0 && tid > 0 && tid != target.pid);
110 {.real = FOREIGN, .effective = OWNER_REAL, .filesystem = FOREIGN, .allowed = 1},
111 {.real = FOREIGN, .effective = OWNER_EFFECTIVE, .filesystem = FOREIGN, .allowed = 1},
112 {.real = OWNER_REAL, .effective = FOREIGN, .filesystem = OWNER_REAL, .allowed = 0},
113 {.real = FOREIGN, .effective = OWNER_SAVED, .filesystem = FOREIGN, .allowed = 0},
114 {.real = FOREIGN, .effective = FOREIGN, .filesystem = 0, .allowed = 0},
115 {.real = FOREIGN, .effective = 0, .filesystem = FOREIGN, .allowed = 1}};
116 for (
size_t i = 0; i <
sizeof(cases) /
sizeof(cases[0]); ++i) {
117 cases[i].target = tid;
118 cases[i].destination = sc_cpus[sc_count - 1];
119 CHECK(sc_pin(tid, sc_cpus[0]) == 0);
120 CHECK(sc_spawn(&caller, permission_child, &cases[i]) == 0);
121 CHECK(sc_join(&caller) == 0);
122 CHECK(sc_send(target.command,
'S') == 0);
124 CHECK(sc_read(target.report, &result,
sizeof(result)) == 0);
125 int expected = cases[i].allowed ? cases[i].destination : sc_cpus[0];
126 CHECK(!result.failed && result.count == 1 && result.cpu == (
unsigned)expected);
129 CHECK(sched_getaffinity(target.pid,
sizeof(leader), &leader) == 0 &&
130 CPU_EQUAL(&leader, &sc_allowed));
132 CHECK(sc_send(target.command,
'Q') == 0 && sc_join(&target) == 0);