xref: /aosp_15_r20/external/ltp/testcases/kernel/containers/mountns/mountns03.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2014 Red Hat, Inc.
4  * Copyright (C) 2021 SUSE LLC Andrea Cervesato <[email protected]>
5  */
6 
7 /*\
8  * [Description]
9  *
10  * Tests a slave mount: slave mount is like a shared mount except that
11  * mount and umount events only propagate towards it.
12  *
13  * [Algorithm]
14  *
15  * - Creates directories DIRA, DIRB and files DIRA/"A", DIRB/"B"
16  * - Unshares mount namespace and makes it private (so mounts/umounts have no
17  *   effect on a real system)
18  * - Bind mounts directory DIRA to itself
19  * - Makes directory DIRA shared
20  * - Clones a new child process with CLONE_NEWNS flag and makes "A" a slave
21  *   mount
22  * - There are two testcases (where X is parent namespace and Y child
23  *   namespace):
24  *  1. First test case
25  *   .. X: bind mounts DIRB to DIRA
26  *   .. Y: must see the file DIRA/"B"
27  *   .. X: umounts DIRA
28  *  2. Second test case
29  *   .. Y: bind mounts DIRB to DIRA
30  *   .. X: must see only the DIRA/"A" and must not see DIRA/"B" (as slave mount does
31  *         not forward propagation)
32  *   .. Y: umounts DIRA
33  */
34 
35 #include <sys/wait.h>
36 #include <sys/mount.h>
37 #include "mountns.h"
38 #include "tst_test.h"
39 #include "lapi/sched.h"
40 
child_func(void)41 static void child_func(void)
42 {
43 	/*
44 	 * makes mount DIRA a slave of DIRA (all slave mounts have
45 	 * a master mount which is a shared mount)
46 	 */
47 	SAFE_MOUNT("none", DIRA, "none", MS_SLAVE, NULL);
48 
49 	TST_CHECKPOINT_WAKE_AND_WAIT(0);
50 
51 	if (access(DIRA "/B", F_OK) == 0)
52 		tst_res(TPASS, "propagation to slave mount passed");
53 	else
54 		tst_res(TFAIL, "propagation to slave mount failed");
55 
56 	TST_CHECKPOINT_WAKE_AND_WAIT(0);
57 
58 	SAFE_MOUNT(DIRB, DIRA, "none", MS_BIND, NULL);
59 
60 	TST_CHECKPOINT_WAKE_AND_WAIT(0);
61 
62 	SAFE_UMOUNT(DIRA);
63 }
64 
run(void)65 static void run(void)
66 {
67 	const struct tst_clone_args args = {
68 		.flags = CLONE_NEWNS,
69 		.exit_signal = SIGCHLD,
70 	};
71 
72 	SAFE_UNSHARE(CLONE_NEWNS);
73 
74 	/* makes sure parent mounts/umounts have no effect on a real system */
75 	SAFE_MOUNT("none", "/", "none", MS_REC | MS_PRIVATE, NULL);
76 
77 	SAFE_MOUNT(DIRA, DIRA, "none", MS_BIND, NULL);
78 
79 	SAFE_MOUNT("none", DIRA, "none", MS_SHARED, NULL);
80 
81 	if (!SAFE_CLONE(&args)) {
82 		child_func();
83 		return;
84 	}
85 
86 	TST_CHECKPOINT_WAIT(0);
87 
88 	SAFE_MOUNT(DIRB, DIRA, "none", MS_BIND, NULL);
89 
90 	TST_CHECKPOINT_WAKE_AND_WAIT(0);
91 
92 	SAFE_UMOUNT(DIRA);
93 
94 	TST_CHECKPOINT_WAKE_AND_WAIT(0);
95 
96 	if ((access(DIRA "/A", F_OK) == 0) && (access(DIRA "/B", F_OK) == -1))
97 		tst_res(TPASS, "propagation from slave mount passed");
98 	else
99 		tst_res(TFAIL, "propagation form slave mount failed");
100 
101 	TST_CHECKPOINT_WAKE(0);
102 
103 	SAFE_WAIT(NULL);
104 
105 	SAFE_UMOUNT(DIRA);
106 }
107 
setup(void)108 static void setup(void)
109 {
110 	create_folders();
111 }
112 
cleanup(void)113 static void cleanup(void)
114 {
115 	umount_folders();
116 }
117 
118 static struct tst_test test = {
119 	.setup = setup,
120 	.cleanup = cleanup,
121 	.test_all = run,
122 	.needs_root = 1,
123 	.forks_child = 1,
124 	.needs_checkpoints = 1,
125 	.needs_kconfigs = (const char *[]) {
126 		"CONFIG_USER_NS",
127 		NULL,
128 	},
129 };
130