Linux Audio

Check our new training course

Linux BSP development engineering services

Need help to port Linux and bootloaders to your hardware?
Loading...
Note: File does not exist in v3.15.
  1// SPDX-License-Identifier: GPL-2.0
  2
  3#define _GNU_SOURCE
  4#include <errno.h>
  5#include <fcntl.h>
  6#include <limits.h>
  7#include <linux/types.h>
  8#include <sched.h>
  9#include <signal.h>
 10#include <stdio.h>
 11#include <stdlib.h>
 12#include <string.h>
 13#include <syscall.h>
 14#include <sys/prctl.h>
 15#include <sys/wait.h>
 16#include <unistd.h>
 17#include <sys/socket.h>
 18#include <sys/stat.h>
 19
 20#include "pidfd.h"
 21#include "../clone3/clone3_selftests.h"
 22#include "../kselftest_harness.h"
 23
 24enum {
 25	PIDFD_NS_USER,
 26	PIDFD_NS_MNT,
 27	PIDFD_NS_PID,
 28	PIDFD_NS_UTS,
 29	PIDFD_NS_IPC,
 30	PIDFD_NS_NET,
 31	PIDFD_NS_CGROUP,
 32	PIDFD_NS_PIDCLD,
 33	PIDFD_NS_TIME,
 34	PIDFD_NS_MAX
 35};
 36
 37const struct ns_info {
 38	const char *name;
 39	int flag;
 40} ns_info[] = {
 41	[PIDFD_NS_USER]   = { "user",             CLONE_NEWUSER,   },
 42	[PIDFD_NS_MNT]    = { "mnt",              CLONE_NEWNS,     },
 43	[PIDFD_NS_PID]    = { "pid",              CLONE_NEWPID,    },
 44	[PIDFD_NS_UTS]    = { "uts",              CLONE_NEWUTS,    },
 45	[PIDFD_NS_IPC]    = { "ipc",              CLONE_NEWIPC,    },
 46	[PIDFD_NS_NET]    = { "net",              CLONE_NEWNET,    },
 47	[PIDFD_NS_CGROUP] = { "cgroup",           CLONE_NEWCGROUP, },
 48	[PIDFD_NS_PIDCLD] = { "pid_for_children", 0,               },
 49	[PIDFD_NS_TIME]	  = { "time",             CLONE_NEWTIME,   },
 50};
 51
 52FIXTURE(current_nsset)
 53{
 54	pid_t pid;
 55	int pidfd;
 56	int nsfds[PIDFD_NS_MAX];
 57
 58	pid_t child_pid_exited;
 59	int child_pidfd_exited;
 60
 61	pid_t child_pid1;
 62	int child_pidfd1;
 63	int child_nsfds1[PIDFD_NS_MAX];
 64
 65	pid_t child_pid2;
 66	int child_pidfd2;
 67	int child_nsfds2[PIDFD_NS_MAX];
 68};
 69
 70static int sys_waitid(int which, pid_t pid, int options)
 71{
 72	return syscall(__NR_waitid, which, pid, NULL, options, NULL);
 73}
 74
 75pid_t create_child(int *pidfd, unsigned flags)
 76{
 77	struct __clone_args args = {
 78		.flags		= CLONE_PIDFD | flags,
 79		.exit_signal	= SIGCHLD,
 80		.pidfd		= ptr_to_u64(pidfd),
 81	};
 82
 83	return sys_clone3(&args, sizeof(struct clone_args));
 84}
 85
 86static bool switch_timens(void)
 87{
 88	int fd, ret;
 89
 90	if (unshare(CLONE_NEWTIME))
 91		return false;
 92
 93	fd = open("/proc/self/ns/time_for_children", O_RDONLY | O_CLOEXEC);
 94	if (fd < 0)
 95		return false;
 96
 97	ret = setns(fd, CLONE_NEWTIME);
 98	close(fd);
 99	return ret == 0;
100}
101
102static ssize_t read_nointr(int fd, void *buf, size_t count)
103{
104	ssize_t ret;
105
106	do {
107		ret = read(fd, buf, count);
108	} while (ret < 0 && errno == EINTR);
109
110	return ret;
111}
112
113static ssize_t write_nointr(int fd, const void *buf, size_t count)
114{
115	ssize_t ret;
116
117	do {
118		ret = write(fd, buf, count);
119	} while (ret < 0 && errno == EINTR);
120
121	return ret;
122}
123
124FIXTURE_SETUP(current_nsset)
125{
126	int i, proc_fd, ret;
127	int ipc_sockets[2];
128	char c;
129
130	for (i = 0; i < PIDFD_NS_MAX; i++) {
131		self->nsfds[i]		= -EBADF;
132		self->child_nsfds1[i]	= -EBADF;
133		self->child_nsfds2[i]	= -EBADF;
134	}
135
136	proc_fd = open("/proc/self/ns", O_DIRECTORY | O_CLOEXEC);
137	ASSERT_GE(proc_fd, 0) {
138		TH_LOG("%m - Failed to open /proc/self/ns");
139	}
140
141	self->pid = getpid();
142	for (i = 0; i < PIDFD_NS_MAX; i++) {
143		const struct ns_info *info = &ns_info[i];
144		self->nsfds[i] = openat(proc_fd, info->name, O_RDONLY | O_CLOEXEC);
145		if (self->nsfds[i] < 0) {
146			EXPECT_EQ(errno, ENOENT) {
147				TH_LOG("%m - Failed to open %s namespace for process %d",
148				       info->name, self->pid);
149			}
150		}
151	}
152
153	self->pidfd = sys_pidfd_open(self->pid, 0);
154	EXPECT_GT(self->pidfd, 0) {
155		TH_LOG("%m - Failed to open pidfd for process %d", self->pid);
156	}
157
158	/* Create task that exits right away. */
159	self->child_pid_exited = create_child(&self->child_pidfd_exited,
160					      CLONE_NEWUSER | CLONE_NEWNET);
161	EXPECT_GT(self->child_pid_exited, 0);
162
163	if (self->child_pid_exited == 0)
164		_exit(EXIT_SUCCESS);
165
166	ASSERT_EQ(sys_waitid(P_PID, self->child_pid_exited, WEXITED | WNOWAIT), 0);
167
168	self->pidfd = sys_pidfd_open(self->pid, 0);
169	EXPECT_GE(self->pidfd, 0) {
170		TH_LOG("%m - Failed to open pidfd for process %d", self->pid);
171	}
172
173	ret = socketpair(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
174	EXPECT_EQ(ret, 0);
175
176	/* Create tasks that will be stopped. */
177	self->child_pid1 = create_child(&self->child_pidfd1,
178					CLONE_NEWUSER | CLONE_NEWNS |
179					CLONE_NEWCGROUP | CLONE_NEWIPC |
180					CLONE_NEWUTS | CLONE_NEWPID |
181					CLONE_NEWNET);
182	EXPECT_GE(self->child_pid1, 0);
183
184	if (self->child_pid1 == 0) {
185		close(ipc_sockets[0]);
186
187		if (!switch_timens())
188			_exit(EXIT_FAILURE);
189
190		if (write_nointr(ipc_sockets[1], "1", 1) < 0)
191			_exit(EXIT_FAILURE);
192
193		close(ipc_sockets[1]);
194
195		pause();
196		_exit(EXIT_SUCCESS);
197	}
198
199	close(ipc_sockets[1]);
200	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
201	close(ipc_sockets[0]);
202
203	ret = socketpair(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
204	EXPECT_EQ(ret, 0);
205
206	self->child_pid2 = create_child(&self->child_pidfd2,
207					CLONE_NEWUSER | CLONE_NEWNS |
208					CLONE_NEWCGROUP | CLONE_NEWIPC |
209					CLONE_NEWUTS | CLONE_NEWPID |
210					CLONE_NEWNET);
211	EXPECT_GE(self->child_pid2, 0);
212
213	if (self->child_pid2 == 0) {
214		close(ipc_sockets[0]);
215
216		if (!switch_timens())
217			_exit(EXIT_FAILURE);
218
219		if (write_nointr(ipc_sockets[1], "1", 1) < 0)
220			_exit(EXIT_FAILURE);
221
222		close(ipc_sockets[1]);
223
224		pause();
225		_exit(EXIT_SUCCESS);
226	}
227
228	close(ipc_sockets[1]);
229	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
230	close(ipc_sockets[0]);
231
232	for (i = 0; i < PIDFD_NS_MAX; i++) {
233		char p[100];
234
235		const struct ns_info *info = &ns_info[i];
236
237		self->nsfds[i] = openat(proc_fd, info->name, O_RDONLY | O_CLOEXEC);
238		if (self->nsfds[i] < 0) {
239			EXPECT_EQ(errno, ENOENT) {
240				TH_LOG("%m - Failed to open %s namespace for process %d",
241				       info->name, self->pid);
242			}
243		}
244
245		ret = snprintf(p, sizeof(p), "/proc/%d/ns/%s",
246			       self->child_pid1, info->name);
247		EXPECT_GT(ret, 0);
248		EXPECT_LT(ret, sizeof(p));
249
250		self->child_nsfds1[i] = open(p, O_RDONLY | O_CLOEXEC);
251		if (self->child_nsfds1[i] < 0) {
252			EXPECT_EQ(errno, ENOENT) {
253				TH_LOG("%m - Failed to open %s namespace for process %d",
254				       info->name, self->child_pid1);
255			}
256		}
257
258		ret = snprintf(p, sizeof(p), "/proc/%d/ns/%s",
259			       self->child_pid2, info->name);
260		EXPECT_GT(ret, 0);
261		EXPECT_LT(ret, sizeof(p));
262
263		self->child_nsfds2[i] = open(p, O_RDONLY | O_CLOEXEC);
264		if (self->child_nsfds2[i] < 0) {
265			EXPECT_EQ(errno, ENOENT) {
266				TH_LOG("%m - Failed to open %s namespace for process %d",
267				       info->name, self->child_pid1);
268			}
269		}
270	}
271
272	close(proc_fd);
273}
274
275FIXTURE_TEARDOWN(current_nsset)
276{
277	int i;
278
279	ASSERT_EQ(sys_pidfd_send_signal(self->child_pidfd1,
280					SIGKILL, NULL, 0), 0);
281	ASSERT_EQ(sys_pidfd_send_signal(self->child_pidfd2,
282					SIGKILL, NULL, 0), 0);
283
284	for (i = 0; i < PIDFD_NS_MAX; i++) {
285		if (self->nsfds[i] >= 0)
286			close(self->nsfds[i]);
287		if (self->child_nsfds1[i] >= 0)
288			close(self->child_nsfds1[i]);
289		if (self->child_nsfds2[i] >= 0)
290			close(self->child_nsfds2[i]);
291	}
292
293	if (self->child_pidfd1 >= 0)
294		EXPECT_EQ(0, close(self->child_pidfd1));
295	if (self->child_pidfd2 >= 0)
296		EXPECT_EQ(0, close(self->child_pidfd2));
297	ASSERT_EQ(sys_waitid(P_PID, self->child_pid_exited, WEXITED), 0);
298	ASSERT_EQ(sys_waitid(P_PID, self->child_pid1, WEXITED), 0);
299	ASSERT_EQ(sys_waitid(P_PID, self->child_pid2, WEXITED), 0);
300}
301
302static int preserve_ns(const int pid, const char *ns)
303{
304	int ret;
305	char path[50];
306
307	ret = snprintf(path, sizeof(path), "/proc/%d/ns/%s", pid, ns);
308	if (ret < 0 || (size_t)ret >= sizeof(path))
309		return -EIO;
310
311	return open(path, O_RDONLY | O_CLOEXEC);
312}
313
314static int in_same_namespace(int ns_fd1, pid_t pid2, const char *ns)
315{
316	int ns_fd2 = -EBADF;
317	int ret = -1;
318	struct stat ns_st1, ns_st2;
319
320	ret = fstat(ns_fd1, &ns_st1);
321	if (ret < 0)
322		return -1;
323
324	ns_fd2 = preserve_ns(pid2, ns);
325	if (ns_fd2 < 0)
326		return -1;
327
328	ret = fstat(ns_fd2, &ns_st2);
329	close(ns_fd2);
330	if (ret < 0)
331		return -1;
332
333	/* processes are in the same namespace */
334	if ((ns_st1.st_dev == ns_st2.st_dev) &&
335	    (ns_st1.st_ino == ns_st2.st_ino))
336		return 1;
337
338	/* processes are in different namespaces */
339	return 0;
340}
341
342/* Test that we can't pass garbage to the kernel. */
343TEST_F(current_nsset, invalid_flags)
344{
345	ASSERT_NE(setns(self->pidfd, 0), 0);
346	EXPECT_EQ(errno, EINVAL);
347
348	ASSERT_NE(setns(self->pidfd, -1), 0);
349	EXPECT_EQ(errno, EINVAL);
350
351	ASSERT_NE(setns(self->pidfd, CLONE_VM), 0);
352	EXPECT_EQ(errno, EINVAL);
353
354	ASSERT_NE(setns(self->pidfd, CLONE_NEWUSER | CLONE_VM), 0);
355	EXPECT_EQ(errno, EINVAL);
356}
357
358/* Test that we can't attach to a task that has already exited. */
359TEST_F(current_nsset, pidfd_exited_child)
360{
361	int i;
362	pid_t pid;
363
364	ASSERT_NE(setns(self->child_pidfd_exited, CLONE_NEWUSER | CLONE_NEWNET),
365		  0);
366	EXPECT_EQ(errno, ESRCH);
367
368	pid = getpid();
369	for (i = 0; i < PIDFD_NS_MAX; i++) {
370		const struct ns_info *info = &ns_info[i];
371		/* Verify that we haven't changed any namespaces. */
372		if (self->nsfds[i] >= 0)
373			ASSERT_EQ(in_same_namespace(self->nsfds[i], pid, info->name), 1);
374	}
375}
376
377TEST_F(current_nsset, pidfd_incremental_setns)
378{
379	int i;
380	pid_t pid;
381
382	pid = getpid();
383	for (i = 0; i < PIDFD_NS_MAX; i++) {
384		const struct ns_info *info = &ns_info[i];
385		int nsfd;
386
387		if (self->child_nsfds1[i] < 0)
388			continue;
389
390		if (info->flag) {
391			ASSERT_EQ(setns(self->child_pidfd1, info->flag), 0) {
392				TH_LOG("%m - Failed to setns to %s namespace of %d via pidfd %d",
393				       info->name, self->child_pid1,
394				       self->child_pidfd1);
395			}
396		}
397
398		/* Verify that we have changed to the correct namespaces. */
399		if (info->flag == CLONE_NEWPID)
400			nsfd = self->nsfds[i];
401		else
402			nsfd = self->child_nsfds1[i];
403		ASSERT_EQ(in_same_namespace(nsfd, pid, info->name), 1) {
404			TH_LOG("setns failed to place us correctly into %s namespace of %d via pidfd %d",
405			       info->name, self->child_pid1,
406			       self->child_pidfd1);
407		}
408		TH_LOG("Managed to correctly setns to %s namespace of %d via pidfd %d",
409		       info->name, self->child_pid1, self->child_pidfd1);
410	}
411}
412
413TEST_F(current_nsset, nsfd_incremental_setns)
414{
415	int i;
416	pid_t pid;
417
418	pid = getpid();
419	for (i = 0; i < PIDFD_NS_MAX; i++) {
420		const struct ns_info *info = &ns_info[i];
421		int nsfd;
422
423		if (self->child_nsfds1[i] < 0)
424			continue;
425
426		if (info->flag) {
427			ASSERT_EQ(setns(self->child_nsfds1[i], info->flag), 0) {
428				TH_LOG("%m - Failed to setns to %s namespace of %d via nsfd %d",
429				       info->name, self->child_pid1,
430				       self->child_nsfds1[i]);
431			}
432		}
433
434		/* Verify that we have changed to the correct namespaces. */
435		if (info->flag == CLONE_NEWPID)
436			nsfd = self->nsfds[i];
437		else
438			nsfd = self->child_nsfds1[i];
439		ASSERT_EQ(in_same_namespace(nsfd, pid, info->name), 1) {
440			TH_LOG("setns failed to place us correctly into %s namespace of %d via nsfd %d",
441			       info->name, self->child_pid1,
442			       self->child_nsfds1[i]);
443		}
444		TH_LOG("Managed to correctly setns to %s namespace of %d via nsfd %d",
445		       info->name, self->child_pid1, self->child_nsfds1[i]);
446	}
447}
448
449TEST_F(current_nsset, pidfd_one_shot_setns)
450{
451	unsigned flags = 0;
452	int i;
453	pid_t pid;
454
455	for (i = 0; i < PIDFD_NS_MAX; i++) {
456		const struct ns_info *info = &ns_info[i];
457
458		if (self->child_nsfds1[i] < 0)
459			continue;
460
461		flags |= info->flag;
462		TH_LOG("Adding %s namespace of %d to list of namespaces to attach to",
463		       info->name, self->child_pid1);
464	}
465
466	ASSERT_EQ(setns(self->child_pidfd1, flags), 0) {
467		TH_LOG("%m - Failed to setns to namespaces of %d",
468		       self->child_pid1);
469	}
470
471	pid = getpid();
472	for (i = 0; i < PIDFD_NS_MAX; i++) {
473		const struct ns_info *info = &ns_info[i];
474		int nsfd;
475
476		if (self->child_nsfds1[i] < 0)
477			continue;
478
479		/* Verify that we have changed to the correct namespaces. */
480		if (info->flag == CLONE_NEWPID)
481			nsfd = self->nsfds[i];
482		else
483			nsfd = self->child_nsfds1[i];
484		ASSERT_EQ(in_same_namespace(nsfd, pid, info->name), 1) {
485			TH_LOG("setns failed to place us correctly into %s namespace of %d",
486			       info->name, self->child_pid1);
487		}
488		TH_LOG("Managed to correctly setns to %s namespace of %d",
489		       info->name, self->child_pid1);
490	}
491}
492
493TEST_F(current_nsset, no_foul_play)
494{
495	unsigned flags = 0;
496	int i;
497
498	for (i = 0; i < PIDFD_NS_MAX; i++) {
499		const struct ns_info *info = &ns_info[i];
500
501		if (self->child_nsfds1[i] < 0)
502			continue;
503
504		flags |= info->flag;
505		if (info->flag) /* No use logging pid_for_children. */
506			TH_LOG("Adding %s namespace of %d to list of namespaces to attach to",
507			       info->name, self->child_pid1);
508	}
509
510	ASSERT_EQ(setns(self->child_pidfd1, flags), 0) {
511		TH_LOG("%m - Failed to setns to namespaces of %d vid pidfd %d",
512		       self->child_pid1, self->child_pidfd1);
513	}
514
515	/*
516	 * Can't setns to a user namespace outside of our hierarchy since we
517	 * don't have caps in there and didn't create it. That means that under
518	 * no circumstances should we be able to setns to any of the other
519	 * ones since they aren't owned by our user namespace.
520	 */
521	for (i = 0; i < PIDFD_NS_MAX; i++) {
522		const struct ns_info *info = &ns_info[i];
523
524		if (self->child_nsfds2[i] < 0 || !info->flag)
525			continue;
526
527		ASSERT_NE(setns(self->child_pidfd2, info->flag), 0) {
528			TH_LOG("Managed to setns to %s namespace of %d via pidfd %d",
529			       info->name, self->child_pid2,
530			       self->child_pidfd2);
531		}
532		TH_LOG("%m - Correctly failed to setns to %s namespace of %d via pidfd %d",
533		       info->name, self->child_pid2,
534		       self->child_pidfd2);
535
536		ASSERT_NE(setns(self->child_nsfds2[i], info->flag), 0) {
537			TH_LOG("Managed to setns to %s namespace of %d via nsfd %d",
538			       info->name, self->child_pid2,
539			       self->child_nsfds2[i]);
540		}
541		TH_LOG("%m - Correctly failed to setns to %s namespace of %d via nsfd %d",
542		       info->name, self->child_pid2,
543		       self->child_nsfds2[i]);
544	}
545}
546
547TEST(setns_einval)
548{
549	int fd;
550
551	fd = sys_memfd_create("rostock", 0);
552	EXPECT_GT(fd, 0);
553
554	ASSERT_NE(setns(fd, 0), 0);
555	EXPECT_EQ(errno, EINVAL);
556	close(fd);
557}
558
559TEST_HARNESS_MAIN