17static int send_namespace(
int command,
int report,
void* argument) {
20 if (unshare(CLONE_NEWUTS) || ns_set(
"orphan-namespace",
"orphan-domain"))
22 int fd = open(
"/proc/thread-self/ns/uts", O_RDONLY | O_CLOEXEC);
25 ns_send_fd(state->socket, fd)) {
35static int join_inherited(
int command,
int report,
void* argument) {
36 int fd = *(
int*)argument;
37 if (ns_send(report,
'R') || ns_receive(command,
'J') || setns(fd, CLONE_NEWUTS) ||
38 ns_expect(
"orphan-namespace",
"orphan-domain"))
41 return ns_expect(
"orphan-namespace",
"orphan-domain");
44static int retained_descriptors(
void) {
45 int failed = 0, socket[2] = {-1, -1}, fd = -1, alias = -1, regular = -1;
46 struct ns_peer source = NS_PEER_INITIALIZER, child = NS_PEER_INITIALIZER;
47 struct ns_identity expected, actual, original, current;
48 CHECK(ns_set(
"rights-parent",
"rights-parent") == 0);
49 CHECK(ns_path_identity(
"/proc/thread-self/ns/uts", &original) == 0);
50 CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, socket) == 0);
52 CHECK(ns_spawn(&source, send_namespace, &sender) == 0);
55 CHECK(ns_read(source.report, &expected,
sizeof(expected)) == 0);
56 CHECK(ns_join(&source) == 0);
58 fd = ns_receive_fd(socket[0]);
59 CHECK(fd >= 0 && ns_fd_identity(fd, &actual) == 0 && ns_same(actual, expected));
64 CHECK(ns_fd_identity(alias, &actual) == 0 && ns_same(actual, expected));
65 CHECK(ns_spawn(&child, join_inherited, &alias) == 0 && ns_receive(child.report,
'R') == 0);
69 regular = memfd_create(
"namespace-fd-reuse", MFD_CLOEXEC);
71 if (regular != reused) {
72 CHECK(dup2(regular, reused) == reused);
77 CHECK(setns(regular, 0) == -1 && errno == EINVAL);
78 CHECK(ns_path_identity(
"/proc/thread-self/ns/uts", ¤t) == 0 && ns_same(current, original));
79 CHECK(ns_send(child.command,
'J') == 0 && ns_join(&child) == 0);
80 CHECK(ns_expect(
"rights-parent",
"rights-parent") == 0);
90 for (
int i = 0; i < 2; ++i)
96int ns_exec(
int argc,
char** argv) {
100 int retained = atoi(argv[4]), closed = atoi(argv[5]);
102 CHECK(ns_expect(argv[2], argv[3]) == 0);
103 CHECK(ns_fd_identity(retained, &saved) == 0);
104 CHECK(ns_path_identity(
"/proc/thread-self/ns/uts", &own) == 0 && ns_same(saved, own));
105 CHECK(ns_path_identity(
"/proc/self/ns/uts", &leader) == 0 && ns_same(leader, own));
107 CHECK(fcntl(closed, F_GETFD) == -1 && errno == EBADF);
108 CHECK(!(fcntl(retained, F_GETFD) & FD_CLOEXEC));
109 CHECK(unshare(CLONE_NEWUTS) == 0 && ns_set(
"exec-temporary",
"exec-temporary") == 0);
110 CHECK(setns(retained, 0) == 0 && ns_expect(argv[2], argv[3]) == 0);
112 CHECK(ns_expect(argv[2], argv[3]) == 0);
117static int enter_exec(
const char* host) {
118 if (ns_set(host,
"exec-domain"))
120 int original = open(
"/proc/thread-self/ns/uts", O_RDONLY | O_CLOEXEC);
123 int retained = fcntl(original, F_DUPFD, 100);
124 int closed = fcntl(original, F_DUPFD_CLOEXEC, 200);
126 if (retained < 0 || closed < 0)
128 char retained_text[16], closed_text[16];
129 snprintf(retained_text,
sizeof(retained_text),
"%d", retained);
130 snprintf(closed_text,
sizeof(closed_text),
"%d", closed);
131 execl(
"/applications/uts-namespace-no-such-executable",
"absent", (
char*)NULL);
132 if (errno != ENOENT || ns_expect(host,
"exec-domain"))
134 execl(NS_APP, NS_APP,
"uts-exec", host,
"exec-domain", retained_text, closed_text, (
char*)NULL);
137static void* exec_worker(
void* argument) {
139 if (unshare(CLONE_NEWUTS))
141 _exit(enter_exec(
"exec-worker") ? 3 : 0);
143static int exec_child(
int command,
int report,
void* argument) {
146 if (unshare(CLONE_NEWUTS))
148 if (!*(
int*)argument)
149 return enter_exec(
"exec-leader");
151 if (ns_set(
"old-exec-leader",
"old-exec-leader") ||
152 pthread_create(&
worker, NULL, exec_worker, NULL))
157static int exec_membership(
void) {
159 struct ns_peer child = NS_PEER_INITIALIZER;
160 for (
int threaded = 0; threaded < 2; ++threaded) {
161 CHECK(ns_spawn(&child, exec_child, &threaded) == 0);
162 CHECK(ns_join(&child) == 0);
169int ns_lifetime(
void) {
170 return retained_descriptors() || exec_membership();