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