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: shm_comm.c 16 * 17 * Description: 18 * 1. Clones two child processes with CLONE_NEWIPC flag, each child 19 * allocates System V shared memory segment (shm) with the _identical_ 20 * key and attaches that segment into its address space. 21 * 2. Child1 writes into the shared memory segment. 22 * 3. Child2 writes into the shared memory segment. 23 * 4. Writes to the shared memory segment with the identical key but from 24 * two different IPC namespaces should not interfere with each other 25 * and so child1 checks whether its shared segment wasn't changed 26 * by child2, if it wasn't test passes, otherwise test fails. 27 */ 28 29 #define _GNU_SOURCE 30 #include <sys/ipc.h> 31 #include <sys/shm.h> 32 #include <sys/types.h> 33 #include <sys/wait.h> 34 #include <stdio.h> 35 #include <errno.h> 36 #include "test.h" 37 #include "safe_macros.h" 38 #include "libclone.h" 39 #include "ipcns_helper.h" 40 41 42 #define TESTKEY 124426L 43 #define SHMSIZE 50 44 char *TCID = "shm_comm"; 45 int TST_TOTAL = 1; 46 47 static void cleanup(void) 48 { 49 tst_rmdir(); 50 } 51 52 static void setup(void) 53 { 54 tst_require_root(); 55 check_newipc(); 56 tst_tmpdir(); 57 TST_CHECKPOINT_INIT(tst_rmdir); 58 } 59 60 int chld1_shm(void *arg) 61 { 62 int id, rval = 0; 63 char *shmem; 64 65 id = shmget(TESTKEY, SHMSIZE, IPC_CREAT); 66 if (id == -1) { 67 perror("shmget"); 68 return 2; 69 } 70 71 if ((shmem = shmat(id, NULL, 0)) == (char *) -1) { 72 perror("shmat"); 73 shmctl(id, IPC_RMID, NULL); 74 return 2; 75 } 76 77 *shmem = 'A'; 78 79 TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0); 80 81 /* if child1 shared segment has changed (by child2) report fail */ 82 if (*shmem != 'A') 83 rval = 1; 84 85 /* tell child2 to continue */ 86 TST_SAFE_CHECKPOINT_WAKE(NULL, 0); 87 88 shmdt(shmem); 89 shmctl(id, IPC_RMID, NULL); 90 return rval; 91 } 92 93 int chld2_shm(void *arg) 94 { 95 int id; 96 char *shmem; 97 98 id = shmget(TESTKEY, SHMSIZE, IPC_CREAT); 99 if (id == -1) { 100 perror("shmget"); 101 return 2; 102 } 103 104 if ((shmem = shmat(id, NULL, 0)) == (char *) -1) { 105 perror("shmat"); 106 shmctl(id, IPC_RMID, NULL); 107 return 2; 108 } 109 110 /* wait for child1 to write to his segment */ 111 TST_SAFE_CHECKPOINT_WAIT(NULL, 0); 112 113 *shmem = 'B'; 114 115 TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0); 116 117 shmdt(shmem); 118 shmctl(id, IPC_RMID, NULL); 119 return 0; 120 } 121 122 static void test(void) 123 { 124 int status, ret = 0; 125 126 ret = do_clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld1_shm, NULL); 127 if (ret == -1) 128 tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); 129 130 ret = do_clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld2_shm, NULL); 131 if (ret == -1) 132 tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); 133 134 135 while (wait(&status) > 0) { 136 if (WIFEXITED(status) && WEXITSTATUS(status) == 1) 137 ret = 1; 138 if (WIFEXITED(status) && WEXITSTATUS(status) == 2) 139 tst_brkm(TBROK | TERRNO, cleanup, "error in child"); 140 if (WIFSIGNALED(status)) { 141 tst_resm(TFAIL, "child was killed with signal %s", 142 tst_strsig(WTERMSIG(status))); 143 return; 144 } 145 } 146 147 if (ret) 148 tst_resm(TFAIL, "SysV shm: communication with identical keys" 149 " between namespaces"); 150 else 151 tst_resm(TPASS, "SysV shm: communication with identical keys" 152 " between namespaces"); 153 } 154 155 int main(int argc, char *argv[]) 156 { 157 int lc; 158 159 tst_parse_opts(argc, argv, NULL, NULL); 160 161 setup(); 162 163 for (lc = 0; TEST_LOOPING(lc); lc++) 164 test(); 165 166 cleanup(); 167 tst_exit(); 168 } 169