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