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 "ipcns_helper.h" 37 #include "test.h" 38 #include "safe_macros.h" 39 40 41 #define TESTKEY 124426L 42 #define SHMSIZE 50 43 char *TCID = "shm_comm"; 44 int TST_TOTAL = 1; 45 46 static void cleanup(void) 47 { 48 tst_rmdir(); 49 } 50 51 static void setup(void) 52 { 53 tst_require_root(); 54 check_newipc(); 55 tst_tmpdir(); 56 TST_CHECKPOINT_INIT(tst_rmdir); 57 } 58 59 int chld1_shm(void *arg) 60 { 61 int id, rval = 0; 62 char *shmem; 63 64 id = shmget(TESTKEY, SHMSIZE, IPC_CREAT); 65 if (id == -1) { 66 perror("shmget"); 67 return 2; 68 } 69 70 if ((shmem = shmat(id, NULL, 0)) == (char *) -1) { 71 perror("shmat"); 72 shmctl(id, IPC_RMID, NULL); 73 return 2; 74 } 75 76 *shmem = 'A'; 77 78 TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0); 79 80 /* if child1 shared segment has changed (by child2) report fail */ 81 if (*shmem != 'A') 82 rval = 1; 83 84 /* tell child2 to continue */ 85 TST_SAFE_CHECKPOINT_WAKE(NULL, 0); 86 87 shmdt(shmem); 88 shmctl(id, IPC_RMID, NULL); 89 return rval; 90 } 91 92 int chld2_shm(void *arg) 93 { 94 int id; 95 char *shmem; 96 97 id = shmget(TESTKEY, SHMSIZE, IPC_CREAT); 98 if (id == -1) { 99 perror("shmget"); 100 return 2; 101 } 102 103 if ((shmem = shmat(id, NULL, 0)) == (char *) -1) { 104 perror("shmat"); 105 shmctl(id, IPC_RMID, NULL); 106 return 2; 107 } 108 109 /* wait for child1 to write to his segment */ 110 TST_SAFE_CHECKPOINT_WAIT(NULL, 0); 111 112 *shmem = 'B'; 113 114 TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0); 115 116 shmdt(shmem); 117 shmctl(id, IPC_RMID, NULL); 118 return 0; 119 } 120 121 static void test(void) 122 { 123 int status, ret = 0; 124 125 ret = do_clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld1_shm, NULL); 126 if (ret == -1) 127 tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); 128 129 ret = do_clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld2_shm, NULL); 130 if (ret == -1) 131 tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); 132 133 134 while (wait(&status) > 0) { 135 if (WIFEXITED(status) && WEXITSTATUS(status) == 1) 136 ret = 1; 137 if (WIFEXITED(status) && WEXITSTATUS(status) == 2) 138 tst_brkm(TBROK | TERRNO, cleanup, "error in child"); 139 if (WIFSIGNALED(status)) { 140 tst_resm(TFAIL, "child was killed with signal %s", 141 tst_strsig(WTERMSIG(status))); 142 return; 143 } 144 } 145 146 if (ret) 147 tst_resm(TFAIL, "SysV shm: communication with identical keys" 148 " between namespaces"); 149 else 150 tst_resm(TPASS, "SysV shm: communication with identical keys" 151 " between namespaces"); 152 } 153 154 int main(int argc, char *argv[]) 155 { 156 int lc; 157 158 tst_parse_opts(argc, argv, NULL, NULL); 159 160 setup(); 161 162 for (lc = 0; TEST_LOOPING(lc); lc++) 163 test(); 164 165 cleanup(); 166 tst_exit(); 167 } 168