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 "mountns_helper.h" 48 #include "test.h" 49 #include "safe_macros.h" 50 51 char *TCID = "mountns03"; 52 int TST_TOTAL = 2; 53 54 #if defined(MS_SHARED) && defined(MS_PRIVATE) \ 55 && defined(MS_REC) && defined(MS_SLAVE) 56 57 int child_func(void *arg LTP_ATTRIBUTE_UNUSED) 58 { 59 int ret = 0; 60 61 /* makes mount DIRA a slave of DIRA (all slave mounts have 62 * a master mount which is a shared mount) */ 63 if (mount("none", DIRA, "none", MS_SLAVE, NULL) == -1) { 64 perror("mount"); 65 return 1; 66 } 67 68 TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0); 69 70 /* checks that shared mounts propagates to slave mount */ 71 if (access(DIRA"/B", F_OK) == -1) 72 ret = 2; 73 74 TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0); 75 76 /* bind mounts DIRB to DIRA making contents of DIRB visible 77 * in DIRA */ 78 if (mount(DIRB, DIRA, "none", MS_BIND, NULL) == -1) { 79 perror("mount"); 80 return 1; 81 } 82 83 TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0); 84 85 umount(DIRA); 86 return ret; 87 } 88 89 static void test(void) 90 { 91 int status; 92 93 /* unshares the mount ns */ 94 if (unshare(CLONE_NEWNS) == -1) 95 tst_brkm(TBROK | TERRNO, cleanup, "unshare failed"); 96 /* makes sure parent mounts/umounts have no effect on a real system */ 97 SAFE_MOUNT(cleanup, "none", "/", "none", MS_REC|MS_PRIVATE, NULL); 98 99 /* bind mounts DIRA to itself */ 100 SAFE_MOUNT(cleanup, DIRA, DIRA, "none", MS_BIND, NULL); 101 102 /* makes mount DIRA shared */ 103 SAFE_MOUNT(cleanup, "none", DIRA, "none", MS_SHARED, NULL); 104 105 if (do_clone_tests(CLONE_NEWNS, child_func, NULL, NULL, NULL) == -1) 106 tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); 107 108 /* waits for child to make a slave mount */ 109 TST_SAFE_CHECKPOINT_WAIT(cleanup, 0); 110 111 /* bind mounts DIRB to DIRA making contents of DIRB visible 112 * in DIRA */ 113 SAFE_MOUNT(cleanup, DIRB, DIRA, "none", MS_BIND, NULL); 114 115 TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(cleanup, 0); 116 117 SAFE_UMOUNT(cleanup, DIRA); 118 119 TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(cleanup, 0); 120 121 /* checks that slave mount doesn't propagate to shared mount */ 122 if ((access(DIRA"/A", F_OK) == 0) && (access(DIRA"/B", F_OK) == -1)) 123 tst_resm(TPASS, "propagation from slave mount passed"); 124 else 125 tst_resm(TFAIL, "propagation form slave mount failed"); 126 127 TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); 128 129 130 SAFE_WAIT(cleanup, &status); 131 if (WIFEXITED(status)) { 132 if (WEXITSTATUS(status) == 0) 133 tst_resm(TPASS, "propagation to slave mount passed"); 134 else 135 tst_resm(TFAIL, "propagation to slave mount failed"); 136 } 137 if (WIFSIGNALED(status)) { 138 tst_resm(TBROK, "child was killed with signal %s", 139 tst_strsig(WTERMSIG(status))); 140 return; 141 } 142 143 SAFE_UMOUNT(cleanup, DIRA); 144 } 145 146 int main(int argc, char *argv[]) 147 { 148 int lc; 149 150 tst_parse_opts(argc, argv, NULL, NULL); 151 152 setup(); 153 154 for (lc = 0; TEST_LOOPING(lc); lc++) 155 test(); 156 157 cleanup(); 158 tst_exit(); 159 } 160 161 #else 162 int main(void) 163 { 164 tst_brkm(TCONF, NULL, "needed mountflags are not defined"); 165 } 166 #endif 167