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