1/* Copyright (c) 2014 Red Hat, Inc. 2 * 3 * This program is free software: you can redistribute it and/or modify 4 * it under the terms of version 2 the GNU General Public License as 5 * published by the Free Software Foundation. 6 * 7 * This program is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * GNU General Public License for more details. 11 * 12 * You should have received a copy of the GNU General Public License 13 * along with this program. If not, see <http://www.gnu.org/licenses/>. 14 *********************************************************************** 15 * File: mountns03.c 16 * 17 * Tests a slave mount: slave mount is like a shared mount except that 18 * mount and umount events only propagate towards it. 19 * 20 * Description: 21 * 1. Creates directories "A", "B" and files "A/A", "B/B" 22 * 2. Unshares mount namespace and makes it private (so mounts/umounts 23 * have no effect on a real system) 24 * 3. Bind mounts directory "A" to itself 25 * 4. Makes directory "A" shared 26 * 5. Clones a new child process with CLONE_NEWNS flag and makes "A" 27 * a slave mount 28 * 6. There are two testcases (where X is parent namespace and Y child 29 * namespace): 30 * 1) 31 * X: bind mounts "B" to "A" 32 * Y: must see the file "A/B" 33 * X: umounts "A" 34 * 2) 35 * Y: bind mounts "B" to "A" 36 * X: must see only the "A/A" and must not see "A/B" (as slave 37 * mount does not forward propagation) 38 * Y: umounts "A" 39 ***********************************************************************/ 40 41#define _GNU_SOURCE 42#include <sys/wait.h> 43#include <sys/mount.h> 44#include <stdio.h> 45#include <unistd.h> 46#include <errno.h> 47#include "test.h" 48#include "libclone.h" 49#include "safe_macros.h" 50#include "mountns_helper.h" 51 52 53char *TCID = "mountns03"; 54int TST_TOTAL = 2; 55 56 57#if defined(MS_SHARED) && defined(MS_PRIVATE) \ 58 && defined(MS_REC) && defined(MS_SLAVE) 59 60int child_func(void *arg LTP_ATTRIBUTE_UNUSED) 61{ 62 int ret = 0; 63 64 /* makes mount DIRA a slave of DIRA (all slave mounts have 65 * a master mount which is a shared mount) */ 66 if (mount("none", DIRA, "none", MS_SLAVE, NULL) == -1) { 67 perror("mount"); 68 return 1; 69 } 70 71 TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0); 72 73 /* checks that shared mounts propagates to slave mount */ 74 if (access(DIRA"/B", F_OK) == -1) 75 ret = 2; 76 77 TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0); 78 79 /* bind mounts DIRB to DIRA making contents of DIRB visible 80 * in DIRA */ 81 if (mount(DIRB, DIRA, "none", MS_BIND, NULL) == -1) { 82 perror("mount"); 83 return 1; 84 } 85 86 TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0); 87 88 umount(DIRA); 89 return ret; 90} 91 92static void test(void) 93{ 94 int status; 95 96 /* unshares the mount ns */ 97 if (unshare(CLONE_NEWNS) == -1) 98 tst_brkm(TBROK | TERRNO, cleanup, "unshare failed"); 99 /* makes sure parent mounts/umounts have no effect on a real system */ 100 SAFE_MOUNT(cleanup, "none", "/", "none", MS_REC|MS_PRIVATE, NULL); 101 102 /* bind mounts DIRA to itself */ 103 SAFE_MOUNT(cleanup, DIRA, DIRA, "none", MS_BIND, NULL); 104 105 /* makes mount DIRA shared */ 106 SAFE_MOUNT(cleanup, "none", DIRA, "none", MS_SHARED, NULL); 107 108 if (do_clone_tests(CLONE_NEWNS, child_func, NULL, NULL, NULL) == -1) 109 tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); 110 111 /* waits for child to make a slave mount */ 112 TST_SAFE_CHECKPOINT_WAIT(cleanup, 0); 113 114 /* bind mounts DIRB to DIRA making contents of DIRB visible 115 * in DIRA */ 116 SAFE_MOUNT(cleanup, DIRB, DIRA, "none", MS_BIND, NULL); 117 118 TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(cleanup, 0); 119 120 SAFE_UMOUNT(cleanup, DIRA); 121 122 TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(cleanup, 0); 123 124 /* checks that slave mount doesn't propagate to shared mount */ 125 if ((access(DIRA"/A", F_OK) == 0) && (access(DIRA"/B", F_OK) == -1)) 126 tst_resm(TPASS, "propagation from slave mount passed"); 127 else 128 tst_resm(TFAIL, "propagation form slave mount failed"); 129 130 TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); 131 132 133 SAFE_WAIT(cleanup, &status); 134 if (WIFEXITED(status)) { 135 if (WEXITSTATUS(status) == 0) 136 tst_resm(TPASS, "propagation to slave mount passed"); 137 else 138 tst_resm(TFAIL, "propagation to slave mount failed"); 139 } 140 if (WIFSIGNALED(status)) { 141 tst_resm(TBROK, "child was killed with signal %s", 142 tst_strsig(WTERMSIG(status))); 143 return; 144 } 145 146 SAFE_UMOUNT(cleanup, DIRA); 147} 148 149int main(int argc, char *argv[]) 150{ 151 int lc; 152 153 tst_parse_opts(argc, argv, NULL, NULL); 154 155 setup(); 156 157 for (lc = 0; TEST_LOOPING(lc); lc++) 158 test(); 159 160 cleanup(); 161 tst_exit(); 162} 163 164#else 165int main(void) 166{ 167 tst_brkm(TCONF, NULL, "needed mountflags are not defined"); 168} 169#endif 170