1 /* $OpenBSD: t_msgrcv.c,v 1.2 2021/12/13 16:56:48 deraadt Exp $ */
2 /* $NetBSD: t_msgrcv.c,v 1.5 2017/10/08 08:31:05 kre Exp $ */
3
4 /*-
5 * Copyright (c) 2011 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Jukka Ruohonen.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include "macros.h"
34
35 #include <sys/msg.h>
36 #include <sys/stat.h>
37 #include <sys/sysctl.h>
38 #include <sys/wait.h>
39
40 #include "atf-c.h"
41 #include <errno.h>
42 #include <limits.h>
43 #include <pwd.h>
44 #include <signal.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <sysexits.h>
49 #include <time.h>
50 #include <unistd.h>
51
52 #define MSG_KEY 1234
53 #define MSG_MTYPE_1 0x41
54 #define MSG_MTYPE_2 0x42
55 #define MSG_MTYPE_3 0x43
56 #define MSG_LEN 3
57
58 struct msg {
59 long mtype;
60 char buf[MSG_LEN];
61 };
62
63 static void clean(void);
64
65 static void
clean(void)66 clean(void)
67 {
68 int id;
69
70 if ((id = msgget(MSG_KEY, 0)) != -1)
71 (void)msgctl(id, IPC_RMID, 0);
72 }
73
74 ATF_TC_WITH_CLEANUP(msgrcv_basic);
ATF_TC_HEAD(msgrcv_basic,tc)75 ATF_TC_HEAD(msgrcv_basic, tc)
76 {
77 atf_tc_set_md_var(tc, "descr", "A basic test of msgrcv(2)");
78 }
79
ATF_TC_BODY(msgrcv_basic,tc)80 ATF_TC_BODY(msgrcv_basic, tc)
81 {
82 struct msg msg1 = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
83 struct msg msg2 = { MSG_MTYPE_1, { 'x', 'y', 'z' } };
84 int id;
85
86 id = msgget(MSG_KEY, IPC_CREAT | 0600);
87 ATF_REQUIRE(id != -1);
88
89 (void)msgsnd(id, &msg1, MSG_LEN, IPC_NOWAIT);
90 (void)msgrcv(id, &msg2, MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT);
91
92 ATF_CHECK(msg1.buf[0] == msg2.buf[0]);
93 ATF_CHECK(msg1.buf[1] == msg2.buf[1]);
94 ATF_CHECK(msg1.buf[2] == msg2.buf[2]);
95
96 ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
97 }
98
ATF_TC_CLEANUP(msgrcv_basic,tc)99 ATF_TC_CLEANUP(msgrcv_basic, tc)
100 {
101 clean();
102 }
103
104 ATF_TC_WITH_CLEANUP(msgrcv_block);
ATF_TC_HEAD(msgrcv_block,tc)105 ATF_TC_HEAD(msgrcv_block, tc)
106 {
107 atf_tc_set_md_var(tc, "descr", "Test that msgrcv(2) blocks");
108 }
109
ATF_TC_BODY(msgrcv_block,tc)110 ATF_TC_BODY(msgrcv_block, tc)
111 {
112 struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
113 int id, sta;
114 pid_t pid;
115
116 id = msgget(MSG_KEY, IPC_CREAT | 0600);
117 ATF_REQUIRE(id != -1);
118
119 pid = fork();
120 ATF_REQUIRE(pid >= 0);
121
122 if (pid == 0) {
123
124 if (msgrcv(id, &msg, MSG_LEN, MSG_MTYPE_1, 0) < 0)
125 _exit(EXIT_FAILURE);
126
127 _exit(EXIT_SUCCESS);
128 }
129
130 /*
131 * Below msgsnd(2) should unblock the child,
132 * and hence kill(2) should fail with ESRCH.
133 */
134 (void)sleep(1);
135 (void)msgsnd(id, &msg, MSG_LEN, IPC_NOWAIT);
136 (void)sleep(1);
137 (void)kill(pid, SIGKILL);
138 (void)wait(&sta);
139
140 if (WIFEXITED(sta) == 0 || WIFSIGNALED(sta) != 0)
141 atf_tc_fail("msgrcv(2) did not block");
142
143 ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
144 }
145
ATF_TC_CLEANUP(msgrcv_block,tc)146 ATF_TC_CLEANUP(msgrcv_block, tc)
147 {
148 clean();
149 }
150
151 ATF_TC_WITH_CLEANUP(msgrcv_err);
ATF_TC_HEAD(msgrcv_err,tc)152 ATF_TC_HEAD(msgrcv_err, tc)
153 {
154 atf_tc_set_md_var(tc, "descr", "Test errors from msgrcv(2)");
155 }
156
ATF_TC_BODY(msgrcv_err,tc)157 ATF_TC_BODY(msgrcv_err, tc)
158 {
159 struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
160 int id, r = 0;
161
162 id = msgget(MSG_KEY, IPC_CREAT | 0600);
163 ATF_REQUIRE(id != -1);
164
165 errno = 0;
166
167 ATF_REQUIRE_ERRNO(ENOMSG, msgrcv(id, &msg,
168 MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT) == -1);
169
170 ATF_REQUIRE(msgsnd(id, &msg, MSG_LEN, IPC_NOWAIT) == 0);
171
172 errno = 0;
173
174 ATF_REQUIRE_ERRNO(EFAULT, msgrcv(id, (void *)-1,
175 MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT) == -1);
176
177 errno = 0;
178
179 ATF_REQUIRE_ERRNO(EINVAL, msgrcv(-1, &msg,
180 MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT) == -1);
181
182 errno = 0;
183
184 ATF_REQUIRE_ERRNO(EINVAL, msgrcv(-1, &msg,
185 SSIZE_MAX, MSG_MTYPE_1, IPC_NOWAIT) == -1);
186
187 ATF_REQUIRE(msgsnd(id, &msg, MSG_LEN, IPC_NOWAIT) == 0);
188
189 errno = 0;
190
191 ATF_REQUIRE_ERRNO(E2BIG, msgrcv(id, &r,
192 MSG_LEN - 1, MSG_MTYPE_1, IPC_NOWAIT) == -1);
193
194 ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
195 }
196
ATF_TC_CLEANUP(msgrcv_err,tc)197 ATF_TC_CLEANUP(msgrcv_err, tc)
198 {
199 clean();
200 }
201
202
203 ATF_TC_WITH_CLEANUP(msgrcv_mtype);
ATF_TC_HEAD(msgrcv_mtype,tc)204 ATF_TC_HEAD(msgrcv_mtype, tc)
205 {
206 atf_tc_set_md_var(tc, "descr", "Test message types with msgrcv(2)");
207 }
208
ATF_TC_BODY(msgrcv_mtype,tc)209 ATF_TC_BODY(msgrcv_mtype, tc)
210 {
211 struct msg msg1 = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
212 struct msg msg2 = { MSG_MTYPE_3, { 'x', 'y', 'z' } };
213 int id;
214
215 id = msgget(MSG_KEY, IPC_CREAT | 0600);
216 ATF_REQUIRE(id != -1);
217
218 (void)msgsnd(id, &msg1, MSG_LEN, IPC_NOWAIT);
219 (void)msgrcv(id, &msg2, MSG_LEN, MSG_MTYPE_2, IPC_NOWAIT);
220
221 ATF_CHECK(msg1.buf[0] != msg2.buf[0]); /* Different mtype. */
222 ATF_CHECK(msg1.buf[1] != msg2.buf[1]);
223 ATF_CHECK(msg1.buf[2] != msg2.buf[2]);
224
225 (void)msgrcv(id, &msg2, MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT);
226
227 ATF_CHECK(msg1.buf[0] == msg2.buf[0]); /* Same mtype. */
228 ATF_CHECK(msg1.buf[1] == msg2.buf[1]);
229 ATF_CHECK(msg1.buf[2] == msg2.buf[2]);
230
231 ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
232 }
233
ATF_TC_CLEANUP(msgrcv_mtype,tc)234 ATF_TC_CLEANUP(msgrcv_mtype, tc)
235 {
236 clean();
237 }
238
239 ATF_TC_WITH_CLEANUP(msgrcv_nonblock);
ATF_TC_HEAD(msgrcv_nonblock,tc)240 ATF_TC_HEAD(msgrcv_nonblock, tc)
241 {
242 atf_tc_set_md_var(tc, "descr", "Test msgrcv(2) with IPC_NOWAIT");
243 atf_tc_set_md_var(tc, "timeout", "10");
244 }
245
ATF_TC_BODY(msgrcv_nonblock,tc)246 ATF_TC_BODY(msgrcv_nonblock, tc)
247 {
248 struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
249 const ssize_t n = 10;
250 int id, sta;
251 ssize_t i;
252 pid_t pid;
253
254 id = msgget(MSG_KEY, IPC_CREAT | 0600);
255 ATF_REQUIRE(id != -1);
256
257 for (i = 0; i < n; i++) {
258
259 ATF_REQUIRE(msgsnd(id, &msg, MSG_LEN, IPC_NOWAIT) == 0);
260 }
261
262 pid = fork();
263 ATF_REQUIRE(pid >= 0);
264
265 if (pid == 0) {
266
267 while (i != 0) {
268
269 if (msgrcv(id, &msg, MSG_LEN, MSG_MTYPE_1,
270 IPC_NOWAIT) == -1)
271 _exit(EXIT_FAILURE);
272
273 i--;
274 }
275
276 _exit(EXIT_SUCCESS);
277 }
278
279 (void)sleep(2);
280 (void)kill(pid, SIGKILL);
281 (void)wait(&sta);
282
283 if (WIFSIGNALED(sta) != 0 || WTERMSIG(sta) == SIGKILL)
284 atf_tc_fail("msgrcv(2) blocked with IPC_NOWAIT");
285
286 if (WIFEXITED(sta) == 0 && WEXITSTATUS(sta) != EXIT_SUCCESS)
287 atf_tc_fail("msgrcv(2) failed");
288
289 ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
290 }
291
ATF_TC_CLEANUP(msgrcv_nonblock,tc)292 ATF_TC_CLEANUP(msgrcv_nonblock, tc)
293 {
294 clean();
295 }
296
297 ATF_TC_WITH_CLEANUP(msgrcv_truncate);
ATF_TC_HEAD(msgrcv_truncate,tc)298 ATF_TC_HEAD(msgrcv_truncate, tc)
299 {
300 atf_tc_set_md_var(tc, "descr", "Test msgrcv(2) with MSG_NOERROR");
301 }
302
ATF_TC_BODY(msgrcv_truncate,tc)303 ATF_TC_BODY(msgrcv_truncate, tc)
304 {
305 #define MSG_SMALLLEN 2
306 struct msgsmall {
307 long mtype;
308 char buf[MSG_SMALLLEN];
309 };
310
311 struct msg msg1 = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
312 struct msgsmall msg2 = { MSG_MTYPE_1, { 'x', 'y' } };
313 int id;
314
315 id = msgget(MSG_KEY, IPC_CREAT | 0600);
316 ATF_REQUIRE(id != -1);
317
318 (void)msgsnd(id, &msg1, MSG_LEN, IPC_NOWAIT);
319 (void)msgrcv(id, &msg2, MSG_SMALLLEN,
320 MSG_MTYPE_1, IPC_NOWAIT | MSG_NOERROR);
321
322 ATF_CHECK(msg1.buf[0] == msg2.buf[0]);
323 ATF_CHECK(msg1.buf[1] == msg2.buf[1]);
324
325 ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
326 }
327
ATF_TC_CLEANUP(msgrcv_truncate,tc)328 ATF_TC_CLEANUP(msgrcv_truncate, tc)
329 {
330 clean();
331 }
332
333 static volatile int sig_caught;
334
335 static void
sigsys_handler(int signum)336 sigsys_handler(int signum)
337 {
338
339 sig_caught = signum;
340 }
341
342 static int
no_kernel_sysvmsg(void)343 no_kernel_sysvmsg(void)
344 {
345 int id;
346 void (*osig)(int);
347
348 sig_caught = 0;
349 osig = signal(SIGSYS, sigsys_handler);
350 id = msgget(MSG_KEY, IPC_CREAT | 0600);
351 if (sig_caught || id == -1)
352 return 1;
353
354 (void)msgctl(id, IPC_RMID, 0);
355 (void)signal(SIGSYS, osig);
356
357 return 0;
358 }
359
360 ATF_TC(msgrcv_query);
ATF_TC_HEAD(msgrcv_query,tc)361 ATF_TC_HEAD(msgrcv_query, tc)
362 {
363 atf_tc_set_md_var(tc, "descr", "Skip msgrcv_* tests - no SYSVMSG");
364 }
ATF_TC_BODY(msgrcv_query,tc)365 ATF_TC_BODY(msgrcv_query, tc)
366 {
367 atf_tc_skip("No SYSVMSG in kernel");
368 }
369
ATF_TP_ADD_TCS(tp)370 ATF_TP_ADD_TCS(tp)
371 {
372
373 if (no_kernel_sysvmsg()) {
374 ATF_TP_ADD_TC(tp, msgrcv_query);
375 } else {
376 ATF_TP_ADD_TC(tp, msgrcv_basic);
377 ATF_TP_ADD_TC(tp, msgrcv_block);
378 ATF_TP_ADD_TC(tp, msgrcv_err);
379 ATF_TP_ADD_TC(tp, msgrcv_mtype);
380 ATF_TP_ADD_TC(tp, msgrcv_nonblock);
381 ATF_TP_ADD_TC(tp, msgrcv_truncate);
382 }
383
384 return atf_no_error();
385 }
386