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: sem_comm.c 16 * 17 * Description: 18 * 1. Clones two child processes with CLONE_NEWIPC flag, each child 19 * creates System V semaphore (sem) with the _identical_ key. 20 * 2. Child1 locks the semaphore. 21 * 3. Child2 locks the semaphore. 22 * 4. Locking the semaphore with the identical key but from two different 23 * IPC namespaces should not interfere with each other, so if child2 24 * is able to lock the semaphore (after child1 locked it), test passes, 25 * otherwise test fails. 26 */ 27 28 #define _GNU_SOURCE 29 #include <sys/ipc.h> 30 #include <sys/sem.h> 31 #include <sys/types.h> 32 #include <sys/wait.h> 33 #include <stdio.h> 34 #include <errno.h> 35 #include "test.h" 36 #include "safe_macros.h" 37 #include "libclone.h" 38 #include "ipcns_helper.h" 39 #include "lapi/semun.h" 40 41 #define TESTKEY 124426L 42 char *TCID = "sem_comm"; 43 int TST_TOTAL = 1; 44 45 static void cleanup(void) 46 { 47 tst_rmdir(); 48 } 49 50 static void setup(void) 51 { 52 tst_require_root(); 53 check_newipc(); 54 tst_tmpdir(); 55 TST_CHECKPOINT_INIT(tst_rmdir); 56 } 57 58 int chld1_sem(void *arg) 59 { 60 int id; 61 union semun su; 62 struct sembuf sm; 63 64 id = semget(TESTKEY, 1, IPC_CREAT); 65 if (id == -1) { 66 perror("semget"); 67 return 2; 68 } 69 70 su.val = 1; 71 if (semctl(id, 0, SETVAL, su) == -1) { 72 perror("semctl"); 73 semctl(id, 0, IPC_RMID); 74 return 2; 75 } 76 77 /* tell child2 to continue and wait for it to create the semaphore */ 78 TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0); 79 80 sm.sem_num = 0; 81 sm.sem_op = -1; 82 sm.sem_flg = IPC_NOWAIT; 83 if (semop(id, &sm, 1) == -1) { 84 perror("semop"); 85 semctl(id, 0, IPC_RMID); 86 return 2; 87 } 88 89 /* tell child2 to continue and wait for it to lock the semaphore */ 90 TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0); 91 92 sm.sem_op = 1; 93 semop(id, &sm, 1); 94 95 semctl(id, 0, IPC_RMID); 96 return 0; 97 } 98 99 int chld2_sem(void *arg) 100 { 101 int id, rval = 0; 102 struct sembuf sm; 103 union semun su; 104 105 /* wait for child1 to create the semaphore */ 106 TST_SAFE_CHECKPOINT_WAIT(NULL, 0); 107 108 id = semget(TESTKEY, 1, IPC_CREAT); 109 if (id == -1) { 110 perror("semget"); 111 return 2; 112 } 113 114 su.val = 1; 115 if (semctl(id, 0, SETVAL, su) == -1) { 116 perror("semctl"); 117 semctl(id, 0, IPC_RMID); 118 return 2; 119 } 120 121 /* tell child1 to continue and wait for it to lock the semaphore */ 122 TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0); 123 124 sm.sem_num = 0; 125 sm.sem_op = -1; 126 sm.sem_flg = IPC_NOWAIT; 127 if (semop(id, &sm, 1) == -1) { 128 if (errno == EAGAIN) { 129 rval = 1; 130 } else { 131 perror("semop"); 132 semctl(id, 0, IPC_RMID); 133 return 2; 134 } 135 } 136 137 /* tell child1 to continue */ 138 TST_SAFE_CHECKPOINT_WAKE(NULL, 0); 139 140 sm.sem_op = 1; 141 semop(id, &sm, 1); 142 143 semctl(id, 0, IPC_RMID); 144 return rval; 145 } 146 147 static void test(void) 148 { 149 int status, ret = 0; 150 151 ret = do_clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld1_sem, NULL); 152 if (ret == -1) 153 tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); 154 155 ret = do_clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld2_sem, NULL); 156 if (ret == -1) 157 tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); 158 159 160 while (wait(&status) > 0) { 161 if (WIFEXITED(status) && WEXITSTATUS(status) == 1) 162 ret = 1; 163 if (WIFEXITED(status) && WEXITSTATUS(status) == 2) 164 tst_brkm(TBROK | TERRNO, cleanup, "error in child"); 165 if (WIFSIGNALED(status)) { 166 tst_resm(TFAIL, "child was killed with signal %s", 167 tst_strsig(WTERMSIG(status))); 168 return; 169 } 170 } 171 172 if (ret) 173 tst_resm(TFAIL, "SysV sem: communication with identical keys" 174 " between namespaces"); 175 else 176 tst_resm(TPASS, "SysV sem: communication with identical keys" 177 " between namespaces"); 178 } 179 180 int main(int argc, char *argv[]) 181 { 182 int lc; 183 184 tst_parse_opts(argc, argv, NULL, NULL); 185 186 setup(); 187 188 for (lc = 0; TEST_LOOPING(lc); lc++) 189 test(); 190 191 cleanup(); 192 tst_exit(); 193 } 194