12static int sharing_child(
int command,
int report,
void* argument) {
13 int original = *(
int*)argument;
14 if (ns_expect(
"initial",
"initial-domain") || ns_send(report,
'R') || ns_receive(command,
'M') ||
15 ns_set(
"shared",
"shared-domain") || ns_send(report,
'M') || ns_receive(command,
'U') ||
16 unshare(CLONE_NEWUTS) || ns_expect(
"shared",
"shared-domain") ||
17 ns_set(
"private",
"private-domain") || ns_send(report,
'U') || ns_receive(command,
'J') ||
18 setns(original, 0) || ns_expect(
"shared",
"shared-domain") ||
19 ns_set(
"joined",
"joined-domain") || ns_send(report,
'J'))
24static int fork_membership(
void) {
25 int failed = 0, original = -1;
26 struct ns_peer child = NS_PEER_INITIALIZER;
27 CHECK(ns_set(
"initial",
"initial-domain") == 0);
28 original = open(
"/proc/thread-self/ns/uts", O_RDONLY | O_CLOEXEC);
30 CHECK(ns_spawn(&child, sharing_child, &original) == 0);
31 CHECK(ns_receive(child.report,
'R') == 0);
32 CHECK(ns_send(child.command,
'M') == 0 && ns_receive(child.report,
'M') == 0);
33 CHECK(ns_expect(
"shared",
"shared-domain") == 0);
34 CHECK(ns_send(child.command,
'U') == 0 && ns_receive(child.report,
'U') == 0);
35 CHECK(ns_expect(
"shared",
"shared-domain") == 0);
36 CHECK(ns_send(child.command,
'J') == 0 && ns_receive(child.report,
'J') == 0);
37 CHECK(ns_expect(
"joined",
"joined-domain") == 0);
38 CHECK(ns_join(&child) == 0);
46static void* inherited_thread(
void* argument) {
47 const char* expected = argument;
48 return (
void*)(intptr_t)ns_expect(expected, expected);
50static int inherited_child(
int command,
int report,
void* argument) {
53 return ns_expect(argument, argument);
57 int command[2], report[2];
61static void* separate_thread(
void* argument) {
63 struct ns_peer child = NS_PEER_INITIALIZER;
67 if (ns_expect(
"leader",
"leader") || unshare(CLONE_NEWUTS) || ns_set(
"worker",
"worker") ||
68 ns_send(state->report[1],
'B') || ns_receive(state->command[0],
'I'))
70 if (pthread_create(&descendant, NULL, inherited_thread,
"worker") ||
71 pthread_join(descendant, &result) || result || ns_spawn(&child, inherited_child,
"worker") ||
74 if (ns_send(state->report[1],
'I') || ns_receive(state->command[0],
'J') ||
75 setns(state->original, CLONE_NEWUTS) || ns_expect(
"leader",
"leader") ||
76 ns_set(
"rejoined",
"rejoined") || ns_send(state->report[1],
'J'))
84static int thread_memberships(
void) {
85 int failed = 0, started = 0;
86 struct thread_membership state = {.command = {-1, -1}, .report = {-1, -1}, .original = -1};
87 pthread_t
worker, descendant;
89 CHECK(ns_set(
"leader",
"leader") == 0);
90 state.original = open(
"/proc/thread-self/ns/uts", O_RDONLY | O_CLOEXEC);
91 CHECK(state.original >= 0);
92 CHECK(pipe(state.command) == 0 && pipe(state.report) == 0);
93 CHECK(pthread_create(&
worker, NULL, separate_thread, &state) == 0);
95 CHECK(ns_receive(state.report[0],
'B') == 0);
96 CHECK(ns_expect(
"leader",
"leader") == 0);
97 CHECK(pthread_create(&descendant, NULL, inherited_thread,
"leader") == 0);
98 CHECK(pthread_join(descendant, &result) == 0 && !result);
99 CHECK(ns_send(state.command[1],
'I') == 0 && ns_receive(state.report[0],
'I') == 0);
100 CHECK(ns_expect(
"leader",
"leader") == 0);
101 CHECK(ns_send(state.command[1],
'J') == 0 && ns_receive(state.report[0],
'J') == 0);
102 CHECK(ns_expect(
"rejoined",
"rejoined") == 0);
104 if (failed && state.command[1] >= 0) {
105 close(state.command[1]);
106 state.command[1] = -1;
108 if (started && (pthread_join(
worker, NULL) || state.result))
110 for (
int i = 0; i < 2; ++i) {
111 if (state.command[i] >= 0)
112 close(state.command[i]);
113 if (state.report[i] >= 0)
114 close(state.report[i]);
116 if (state.original >= 0)
117 close(state.original);
125static int new_uts_child(
void* argument) {
128 if (ns_expect(
"clone-parent",
"clone-parent") ||
129 ns_path_identity(
"/proc/thread-self/ns/uts", &own) || ns_same(own, state->original) ||
130 ns_set(
"clone-child",
"clone-child") || ns_send(state->report,
'C'))
134static int clone_membership(
void) {
135 int failed = 0, report[2] = {-1, -1};
137 const size_t length = ns_page * 16;
138 void* stack = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
140 CHECK(stack != MAP_FAILED);
141 CHECK(ns_set(
"clone-parent",
"clone-parent") == 0);
142 CHECK(ns_path_identity(
"/proc/thread-self/ns/uts", &state.original) == 0);
143 CHECK(pipe(report) == 0);
144 state.report = report[1];
145 child = clone(new_uts_child, (
char*)stack + length, CLONE_NEWUTS | SIGCHLD, &state);
147 CHECK(ns_receive(report[0],
'C') == 0);
148 CHECK(ns_expect(
"clone-parent",
"clone-parent") == 0);
149 int status = ns_reap(child, 10000);
154 kill(child, SIGKILL);
155 ns_reap(child, 1000);
157 for (
int i = 0; i < 2; ++i)
160 if (stack != MAP_FAILED)
161 munmap(stack, length);
165int ns_membership(
void) {
166 return fork_membership() || thread_memberships() || clone_membership();