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