1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) Huawei Technologies Co., Ltd., 2015
4f08c3bdfSopenharmony_ci * Copyright (C) 2022 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
5f08c3bdfSopenharmony_ci */
6f08c3bdfSopenharmony_ci
7f08c3bdfSopenharmony_ci/*\
8f08c3bdfSopenharmony_ci * [Description]
9f08c3bdfSopenharmony_ci *
10f08c3bdfSopenharmony_ci * Verify that if a process created via fork(2) or clone(2) without the
11f08c3bdfSopenharmony_ci * CLONE_NEWUSER flag is a member of the same user namespace as its parent.
12f08c3bdfSopenharmony_ci *
13f08c3bdfSopenharmony_ci * When unshare an user namespace, the calling process is moved into a new user
14f08c3bdfSopenharmony_ci * namespace which is not shared with any previously existing process.
15f08c3bdfSopenharmony_ci */
16f08c3bdfSopenharmony_ci
17f08c3bdfSopenharmony_ci#define _GNU_SOURCE
18f08c3bdfSopenharmony_ci
19f08c3bdfSopenharmony_ci#include <stdio.h>
20f08c3bdfSopenharmony_ci#include "tst_test.h"
21f08c3bdfSopenharmony_ci#include "lapi/sched.h"
22f08c3bdfSopenharmony_ci#include "common.h"
23f08c3bdfSopenharmony_ci
24f08c3bdfSopenharmony_cistatic void child_fn1(void)
25f08c3bdfSopenharmony_ci{
26f08c3bdfSopenharmony_ci	TST_CHECKPOINT_WAIT(0);
27f08c3bdfSopenharmony_ci}
28f08c3bdfSopenharmony_ci
29f08c3bdfSopenharmony_cistatic unsigned int getusernsidbypid(int pid)
30f08c3bdfSopenharmony_ci{
31f08c3bdfSopenharmony_ci	char path[BUFSIZ];
32f08c3bdfSopenharmony_ci	char userid[BUFSIZ];
33f08c3bdfSopenharmony_ci	unsigned int id = 0;
34f08c3bdfSopenharmony_ci
35f08c3bdfSopenharmony_ci	sprintf(path, "/proc/%d/ns/user", pid);
36f08c3bdfSopenharmony_ci
37f08c3bdfSopenharmony_ci	SAFE_READLINK(path, userid, BUFSIZ);
38f08c3bdfSopenharmony_ci
39f08c3bdfSopenharmony_ci	if (sscanf(userid, "user:[%u]", &id) < 0)
40f08c3bdfSopenharmony_ci		tst_brk(TBROK | TERRNO, "sscanf failure");
41f08c3bdfSopenharmony_ci
42f08c3bdfSopenharmony_ci	return id;
43f08c3bdfSopenharmony_ci}
44f08c3bdfSopenharmony_ci
45f08c3bdfSopenharmony_cistatic void run(void)
46f08c3bdfSopenharmony_ci{
47f08c3bdfSopenharmony_ci	const struct tst_clone_args args1 = { .exit_signal = SIGCHLD };
48f08c3bdfSopenharmony_ci	const struct tst_clone_args args2 = {
49f08c3bdfSopenharmony_ci		.flags = CLONE_NEWUSER,
50f08c3bdfSopenharmony_ci		.exit_signal = SIGCHLD,
51f08c3bdfSopenharmony_ci	};
52f08c3bdfSopenharmony_ci	int cpid1, cpid2, cpid3;
53f08c3bdfSopenharmony_ci	unsigned int parentuserns, cpid1userns, cpid2userns, newparentuserns;
54f08c3bdfSopenharmony_ci
55f08c3bdfSopenharmony_ci	parentuserns = getusernsidbypid(getpid());
56f08c3bdfSopenharmony_ci
57f08c3bdfSopenharmony_ci	cpid1 = SAFE_CLONE(&args1);
58f08c3bdfSopenharmony_ci	if (!cpid1) {
59f08c3bdfSopenharmony_ci		child_fn1();
60f08c3bdfSopenharmony_ci		return;
61f08c3bdfSopenharmony_ci	}
62f08c3bdfSopenharmony_ci
63f08c3bdfSopenharmony_ci	cpid1userns = getusernsidbypid(cpid1);
64f08c3bdfSopenharmony_ci
65f08c3bdfSopenharmony_ci	TST_CHECKPOINT_WAKE(0);
66f08c3bdfSopenharmony_ci
67f08c3bdfSopenharmony_ci	/* A process created via fork(2) or clone(2) without the
68f08c3bdfSopenharmony_ci	 * CLONE_NEWUSER flag is a member of the same user namespace as its
69f08c3bdfSopenharmony_ci	 * parent
70f08c3bdfSopenharmony_ci	 */
71f08c3bdfSopenharmony_ci	TST_EXP_EQ_LI(parentuserns, cpid1userns);
72f08c3bdfSopenharmony_ci
73f08c3bdfSopenharmony_ci	cpid2 = SAFE_CLONE(&args2);
74f08c3bdfSopenharmony_ci	if (!cpid2) {
75f08c3bdfSopenharmony_ci		child_fn1();
76f08c3bdfSopenharmony_ci		return;
77f08c3bdfSopenharmony_ci	}
78f08c3bdfSopenharmony_ci
79f08c3bdfSopenharmony_ci	cpid2userns = getusernsidbypid(cpid2);
80f08c3bdfSopenharmony_ci
81f08c3bdfSopenharmony_ci	TST_CHECKPOINT_WAKE(0);
82f08c3bdfSopenharmony_ci
83f08c3bdfSopenharmony_ci	TST_EXP_EXPR(parentuserns != cpid2userns,
84f08c3bdfSopenharmony_ci		"parent namespace != child namespace");
85f08c3bdfSopenharmony_ci
86f08c3bdfSopenharmony_ci	cpid3 = SAFE_FORK();
87f08c3bdfSopenharmony_ci	if (!cpid3) {
88f08c3bdfSopenharmony_ci		SAFE_UNSHARE(CLONE_NEWUSER);
89f08c3bdfSopenharmony_ci		newparentuserns = getusernsidbypid(getpid());
90f08c3bdfSopenharmony_ci
91f08c3bdfSopenharmony_ci		/* When unshare an user namespace, the calling process
92f08c3bdfSopenharmony_ci		 * is moved into a new user namespace which is not shared
93f08c3bdfSopenharmony_ci		 * with any previously existing process
94f08c3bdfSopenharmony_ci		 */
95f08c3bdfSopenharmony_ci		TST_EXP_EXPR(parentuserns != newparentuserns,
96f08c3bdfSopenharmony_ci			"parent namespace != unshared child namespace");
97f08c3bdfSopenharmony_ci	}
98f08c3bdfSopenharmony_ci}
99f08c3bdfSopenharmony_ci
100f08c3bdfSopenharmony_cistatic struct tst_test test = {
101f08c3bdfSopenharmony_ci	.test_all = run,
102f08c3bdfSopenharmony_ci	.needs_root = 1,
103f08c3bdfSopenharmony_ci	.forks_child = 1,
104f08c3bdfSopenharmony_ci	.needs_checkpoints = 1,
105f08c3bdfSopenharmony_ci	.needs_kconfigs = (const char *[]) {
106f08c3bdfSopenharmony_ci		"CONFIG_USER_NS",
107f08c3bdfSopenharmony_ci		NULL,
108f08c3bdfSopenharmony_ci	},
109f08c3bdfSopenharmony_ci};
110