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
cleanup(void)46 static void cleanup(void)
47 {
48 tst_rmdir();
49 }
50
setup(void)51 static void setup(void)
52 {
53 tst_require_root();
54 check_newipc();
55 tst_tmpdir();
56 TST_CHECKPOINT_INIT(tst_rmdir);
57 }
58
chld1_shm(void * arg)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
chld2_shm(void * arg)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
test(void)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
main(int argc,char * argv[])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