1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) Linux Test Project, 2014-2020
4f08c3bdfSopenharmony_ci *
5f08c3bdfSopenharmony_ci * functional test for setns(2) - reassociate thread with a namespace
6f08c3bdfSopenharmony_ci * 1. create child with CLONE_NEWUTS, set different hostname in child,
7f08c3bdfSopenharmony_ci *    set namespace back to parent ns and check that hostname has changed
8f08c3bdfSopenharmony_ci * 2. create child with CLONE_NEWIPC, set up shared memory in parent
9f08c3bdfSopenharmony_ci *    and verify that child can't shmat it, then set namespace
10f08c3bdfSopenharmony_ci *    back to parent one and verify that child is able to do shmat
11f08c3bdfSopenharmony_ci */
12f08c3bdfSopenharmony_ci#define _GNU_SOURCE
13f08c3bdfSopenharmony_ci#include <sys/ipc.h>
14f08c3bdfSopenharmony_ci#include <sys/shm.h>
15f08c3bdfSopenharmony_ci#include <sys/stat.h>
16f08c3bdfSopenharmony_ci#include <sys/types.h>
17f08c3bdfSopenharmony_ci#include <sys/utsname.h>
18f08c3bdfSopenharmony_ci#include <sys/wait.h>
19f08c3bdfSopenharmony_ci#include <errno.h>
20f08c3bdfSopenharmony_ci#include <sched.h>
21f08c3bdfSopenharmony_ci#include <stdlib.h>
22f08c3bdfSopenharmony_ci#include <string.h>
23f08c3bdfSopenharmony_ci#include "config.h"
24f08c3bdfSopenharmony_ci#include "tst_test.h"
25f08c3bdfSopenharmony_ci#include "tst_safe_sysv_ipc.h"
26f08c3bdfSopenharmony_ci#include "lapi/syscalls.h"
27f08c3bdfSopenharmony_ci#include "setns.h"
28f08c3bdfSopenharmony_ci
29f08c3bdfSopenharmony_ci#define CHILD_STACK_SIZE (1024*1024)
30f08c3bdfSopenharmony_ci#define CP "(child) "
31f08c3bdfSopenharmony_ci
32f08c3bdfSopenharmony_cistatic char *dummy_hostname = "setns_dummy_uts";
33f08c3bdfSopenharmony_cistatic int ns_ipc_fd;
34f08c3bdfSopenharmony_cistatic int ns_uts_fd;
35f08c3bdfSopenharmony_cistatic key_t ipc_key;
36f08c3bdfSopenharmony_cistatic int shmid;
37f08c3bdfSopenharmony_ci
38f08c3bdfSopenharmony_cistatic void setup(void);
39f08c3bdfSopenharmony_cistatic void cleanup(void);
40f08c3bdfSopenharmony_ci
41f08c3bdfSopenharmony_cistatic int do_child_newuts(void *arg)
42f08c3bdfSopenharmony_ci{
43f08c3bdfSopenharmony_ci	struct utsname uts, uts_parent;
44f08c3bdfSopenharmony_ci	int ns_flag = *(int *)arg;
45f08c3bdfSopenharmony_ci
46f08c3bdfSopenharmony_ci	if (uname(&uts_parent) == -1)
47f08c3bdfSopenharmony_ci		tst_res(TFAIL|TERRNO, CP"uname");
48f08c3bdfSopenharmony_ci	tst_res(TINFO, CP"hostname (inherited from parent): %s",
49f08c3bdfSopenharmony_ci		uts_parent.nodename);
50f08c3bdfSopenharmony_ci
51f08c3bdfSopenharmony_ci	if (sethostname(dummy_hostname, strlen(dummy_hostname)) == -1)
52f08c3bdfSopenharmony_ci		tst_res(TFAIL|TERRNO, CP"sethostname");
53f08c3bdfSopenharmony_ci	if (uname(&uts) == -1)
54f08c3bdfSopenharmony_ci		tst_res(TFAIL|TERRNO, CP"uname");
55f08c3bdfSopenharmony_ci
56f08c3bdfSopenharmony_ci	tst_res(TINFO, CP"hostname changed to: %s", uts.nodename);
57f08c3bdfSopenharmony_ci	if (strcmp(uts_parent.nodename, uts.nodename) == 0) {
58f08c3bdfSopenharmony_ci		tst_res(TFAIL, CP"expected hostname to be different");
59f08c3bdfSopenharmony_ci		return 1;
60f08c3bdfSopenharmony_ci	} else {
61f08c3bdfSopenharmony_ci		tst_res(TPASS, CP"hostname is different in parent/child");
62f08c3bdfSopenharmony_ci	}
63f08c3bdfSopenharmony_ci
64f08c3bdfSopenharmony_ci	tst_res(TINFO, CP"attempting to switch ns back to parent ns");
65f08c3bdfSopenharmony_ci	if (tst_syscall(__NR_setns, ns_uts_fd, ns_flag) == -1) {
66f08c3bdfSopenharmony_ci		tst_res(TFAIL|TERRNO, CP"setns");
67f08c3bdfSopenharmony_ci		return 2;
68f08c3bdfSopenharmony_ci	}
69f08c3bdfSopenharmony_ci	if (uname(&uts) == -1)
70f08c3bdfSopenharmony_ci		tst_res(TFAIL|TERRNO, CP"uname");
71f08c3bdfSopenharmony_ci
72f08c3bdfSopenharmony_ci	tst_res(TINFO, CP"hostname: %s", uts.nodename);
73f08c3bdfSopenharmony_ci	if (strcmp(uts_parent.nodename, uts.nodename) != 0) {
74f08c3bdfSopenharmony_ci		tst_res(TFAIL, CP"expected hostname to match parent");
75f08c3bdfSopenharmony_ci		return 3;
76f08c3bdfSopenharmony_ci	} else {
77f08c3bdfSopenharmony_ci		tst_res(TPASS, CP"hostname now as expected");
78f08c3bdfSopenharmony_ci	}
79f08c3bdfSopenharmony_ci	return 0;
80f08c3bdfSopenharmony_ci}
81f08c3bdfSopenharmony_ci
82f08c3bdfSopenharmony_cistatic int do_child_newipc(void *arg)
83f08c3bdfSopenharmony_ci{
84f08c3bdfSopenharmony_ci	void *p;
85f08c3bdfSopenharmony_ci	int ns_flag = *(int *)arg;
86f08c3bdfSopenharmony_ci
87f08c3bdfSopenharmony_ci	p = shmat(shmid, NULL, 0);
88f08c3bdfSopenharmony_ci	if (p == (void *) -1) {
89f08c3bdfSopenharmony_ci		tst_res(TPASS|TERRNO, CP"shmat failed as expected");
90f08c3bdfSopenharmony_ci	} else {
91f08c3bdfSopenharmony_ci		tst_res(TFAIL, CP"shmat unexpectedly suceeded");
92f08c3bdfSopenharmony_ci		shmdt(p);
93f08c3bdfSopenharmony_ci		return 1;
94f08c3bdfSopenharmony_ci	}
95f08c3bdfSopenharmony_ci
96f08c3bdfSopenharmony_ci	tst_res(TINFO, CP"attempting to switch ns back to parent ns");
97f08c3bdfSopenharmony_ci	if (tst_syscall(__NR_setns, ns_ipc_fd, ns_flag) == -1) {
98f08c3bdfSopenharmony_ci		tst_res(TFAIL|TERRNO, CP"setns");
99f08c3bdfSopenharmony_ci		return 2;
100f08c3bdfSopenharmony_ci	}
101f08c3bdfSopenharmony_ci
102f08c3bdfSopenharmony_ci	p = shmat(shmid, NULL, 0);
103f08c3bdfSopenharmony_ci	if (p == (void *) -1) {
104f08c3bdfSopenharmony_ci		tst_res(TFAIL|TERRNO, CP"shmat failed after setns");
105f08c3bdfSopenharmony_ci		return 3;
106f08c3bdfSopenharmony_ci	} else {
107f08c3bdfSopenharmony_ci		tst_res(TPASS, CP"shmat suceeded");
108f08c3bdfSopenharmony_ci		shmdt(p);
109f08c3bdfSopenharmony_ci	}
110f08c3bdfSopenharmony_ci
111f08c3bdfSopenharmony_ci	return 0;
112f08c3bdfSopenharmony_ci}
113f08c3bdfSopenharmony_ci
114f08c3bdfSopenharmony_cistatic void test_flag(int clone_flag, int ns_flag, int (*fn) (void *arg))
115f08c3bdfSopenharmony_ci{
116f08c3bdfSopenharmony_ci	void *child_stack;
117f08c3bdfSopenharmony_ci	int ret, status;
118f08c3bdfSopenharmony_ci
119f08c3bdfSopenharmony_ci	child_stack = SAFE_MALLOC(CHILD_STACK_SIZE);
120f08c3bdfSopenharmony_ci
121f08c3bdfSopenharmony_ci	tst_res(TINFO, "creating child with clone_flag=0x%x, ns_flag=0x%x",
122f08c3bdfSopenharmony_ci		clone_flag, ns_flag);
123f08c3bdfSopenharmony_ci	ret = ltp_clone(SIGCHLD|clone_flag, fn, &ns_flag,
124f08c3bdfSopenharmony_ci		CHILD_STACK_SIZE, child_stack);
125f08c3bdfSopenharmony_ci	if (ret == -1)
126f08c3bdfSopenharmony_ci		tst_brk(TBROK|TERRNO, "ltp_clone");
127f08c3bdfSopenharmony_ci
128f08c3bdfSopenharmony_ci	SAFE_WAITPID(ret, &status, 0);
129f08c3bdfSopenharmony_ci	free(child_stack);
130f08c3bdfSopenharmony_ci}
131f08c3bdfSopenharmony_ci
132f08c3bdfSopenharmony_civoid test_all(void)
133f08c3bdfSopenharmony_ci{
134f08c3bdfSopenharmony_ci	if (ns_uts_fd != -1) {
135f08c3bdfSopenharmony_ci		tst_res(TINFO, "test_newuts");
136f08c3bdfSopenharmony_ci		test_flag(CLONE_NEWUTS, CLONE_NEWUTS, do_child_newuts);
137f08c3bdfSopenharmony_ci		test_flag(CLONE_NEWUTS, 0, do_child_newuts);
138f08c3bdfSopenharmony_ci	} else
139f08c3bdfSopenharmony_ci		tst_res(TCONF, "CLONE_NEWUTS is not supported");
140f08c3bdfSopenharmony_ci
141f08c3bdfSopenharmony_ci	if (ns_ipc_fd != -1) {
142f08c3bdfSopenharmony_ci		tst_res(TINFO, "test_newipc");
143f08c3bdfSopenharmony_ci		test_flag(CLONE_NEWIPC, CLONE_NEWIPC, do_child_newipc);
144f08c3bdfSopenharmony_ci		test_flag(CLONE_NEWIPC, 0, do_child_newipc);
145f08c3bdfSopenharmony_ci	} else
146f08c3bdfSopenharmony_ci		tst_res(TCONF, "CLONE_NEWIPC is not supported");
147f08c3bdfSopenharmony_ci}
148f08c3bdfSopenharmony_ci
149f08c3bdfSopenharmony_cistatic void setup(void)
150f08c3bdfSopenharmony_ci{
151f08c3bdfSopenharmony_ci	char tmp[PATH_MAX];
152f08c3bdfSopenharmony_ci
153f08c3bdfSopenharmony_ci	/* runtime check if syscall is supported */
154f08c3bdfSopenharmony_ci	tst_syscall(__NR_setns, -1, 0);
155f08c3bdfSopenharmony_ci
156f08c3bdfSopenharmony_ci	/* check if kernel has CONFIG_*_NS set and exports /proc entries */
157f08c3bdfSopenharmony_ci	ns_ipc_fd = get_ns_fd(getpid(), "ipc");
158f08c3bdfSopenharmony_ci	ns_uts_fd = get_ns_fd(getpid(), "uts");
159f08c3bdfSopenharmony_ci	if (ns_ipc_fd == -1 && ns_uts_fd == -1)
160f08c3bdfSopenharmony_ci		tst_brk(TCONF, "your kernel has CONFIG_IPC_NS, "
161f08c3bdfSopenharmony_ci			"CONFIG_UTS_NS or CONFIG_PROC disabled");
162f08c3bdfSopenharmony_ci
163f08c3bdfSopenharmony_ci	SAFE_GETCWD(tmp, PATH_MAX);
164f08c3bdfSopenharmony_ci	ipc_key = ftok(tmp, 65);
165f08c3bdfSopenharmony_ci	shmid = SAFE_SHMGET(ipc_key, getpagesize(), IPC_CREAT | 0666);
166f08c3bdfSopenharmony_ci}
167f08c3bdfSopenharmony_ci
168f08c3bdfSopenharmony_cistatic void cleanup(void)
169f08c3bdfSopenharmony_ci{
170f08c3bdfSopenharmony_ci	if (ns_ipc_fd != -1)
171f08c3bdfSopenharmony_ci		SAFE_CLOSE(ns_ipc_fd);
172f08c3bdfSopenharmony_ci	if (ns_uts_fd != -1)
173f08c3bdfSopenharmony_ci		SAFE_CLOSE(ns_uts_fd);
174f08c3bdfSopenharmony_ci
175f08c3bdfSopenharmony_ci	SAFE_SHMCTL(shmid, IPC_RMID, NULL);
176f08c3bdfSopenharmony_ci}
177f08c3bdfSopenharmony_ci
178f08c3bdfSopenharmony_cistatic struct tst_test test = {
179f08c3bdfSopenharmony_ci	.test_all = test_all,
180f08c3bdfSopenharmony_ci	.setup = setup,
181f08c3bdfSopenharmony_ci	.cleanup = cleanup,
182f08c3bdfSopenharmony_ci	.needs_root = 1,
183f08c3bdfSopenharmony_ci};
184