summaryrefslogtreecommitdiff
path: root/src/regress/lib/libc/sys/t_msgsnd.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/regress/lib/libc/sys/t_msgsnd.c')
-rw-r--r--src/regress/lib/libc/sys/t_msgsnd.c384
1 files changed, 384 insertions, 0 deletions
diff --git a/src/regress/lib/libc/sys/t_msgsnd.c b/src/regress/lib/libc/sys/t_msgsnd.c
new file mode 100644
index 0000000000..ab0cc87e6f
--- /dev/null
+++ b/src/regress/lib/libc/sys/t_msgsnd.c
@@ -0,0 +1,384 @@
1/* $OpenBSD: t_msgsnd.c,v 1.1.1.1 2019/11/19 19:57:04 bluhm Exp $ */
2/* $NetBSD: t_msgsnd.c,v 1.4 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/cdefs.h>
36__RCSID("$NetBSD: t_msgsnd.c,v 1.4 2017/10/08 08:31:05 kre Exp $");
37
38#include <sys/msg.h>
39#include <sys/stat.h>
40#include <sys/sysctl.h>
41#include <sys/wait.h>
42
43#include "atf-c.h"
44#include <errno.h>
45#include <limits.h>
46#include <pwd.h>
47#include <signal.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <string.h>
51#include <sysexits.h>
52#include <time.h>
53#include <unistd.h>
54
55#define MSG_KEY 1234
56#define MSG_MTYPE_1 0x41
57#define MSG_MTYPE_2 0x42
58#define MSG_MTYPE_3 0x43
59
60struct msg {
61 long mtype;
62 char buf[3];
63};
64
65static void clean(void);
66
67static void
68clean(void)
69{
70 int id;
71
72 if ((id = msgget(MSG_KEY, 0)) != -1)
73 (void)msgctl(id, IPC_RMID, 0);
74}
75
76ATF_TC_WITH_CLEANUP(msgsnd_block);
77ATF_TC_HEAD(msgsnd_block, tc)
78{
79 atf_tc_set_md_var(tc, "descr", "Test that msgsnd(2) blocks");
80 atf_tc_set_md_var(tc, "timeout", "10");
81}
82
83ATF_TC_BODY(msgsnd_block, tc)
84{
85 struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
86 int id, sta;
87 pid_t pid;
88
89 id = msgget(MSG_KEY, IPC_CREAT | 0600);
90 ATF_REQUIRE(id != -1);
91
92 pid = fork();
93 ATF_REQUIRE(pid >= 0);
94
95 if (pid == 0) {
96
97 /*
98 * Enqueue messages until some limit (e.g. the maximum
99 * number of messages in the queue or the maximum number
100 * of bytes in the queue) is reached. After this the call
101 * should block when the IPC_NOWAIT is not set.
102 */
103 for (;;) {
104
105 if (msgsnd(id, &msg, sizeof(struct msg), 0) < 0)
106 _exit(EXIT_FAILURE);
107 }
108 }
109
110 (void)sleep(2);
111 (void)kill(pid, SIGKILL);
112 (void)wait(&sta);
113
114 if (WIFEXITED(sta) != 0 || WIFSIGNALED(sta) == 0)
115 atf_tc_fail("msgsnd(2) did not block");
116
117 ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
118}
119
120ATF_TC_CLEANUP(msgsnd_block, tc)
121{
122 clean();
123}
124
125ATF_TC_WITH_CLEANUP(msgsnd_count);
126ATF_TC_HEAD(msgsnd_count, tc)
127{
128 atf_tc_set_md_var(tc, "descr",
129 "Test that msgsnd(2) increments the amount of "
130 "message in the queue, as given by msgctl(2)");
131 atf_tc_set_md_var(tc, "timeout", "10");
132}
133
134ATF_TC_BODY(msgsnd_count, tc)
135{
136 struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
137 struct msqid_ds ds;
138 size_t i = 0;
139 int id, rv;
140
141 id = msgget(MSG_KEY, IPC_CREAT | 0600);
142 ATF_REQUIRE(id != -1);
143
144 for (;;) {
145
146 errno = 0;
147 rv = msgsnd(id, &msg, sizeof(struct msg), IPC_NOWAIT);
148
149 if (rv == 0) {
150 i++;
151 continue;
152 }
153
154 if (rv == -1 && errno == EAGAIN)
155 break;
156
157 atf_tc_fail("failed to enqueue a message");
158 }
159
160 (void)memset(&ds, 0, sizeof(struct msqid_ds));
161 (void)msgctl(id, IPC_STAT, &ds);
162
163 if (ds.msg_qnum != i)
164 atf_tc_fail("incorrect message count");
165
166 ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
167}
168
169ATF_TC_CLEANUP(msgsnd_count, tc)
170{
171 clean();
172}
173
174ATF_TC_WITH_CLEANUP(msgsnd_err);
175ATF_TC_HEAD(msgsnd_err, tc)
176{
177 atf_tc_set_md_var(tc, "descr", "Test errors from msgsnd(2)");
178}
179
180ATF_TC_BODY(msgsnd_err, tc)
181{
182 struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
183 int id;
184
185 id = msgget(MSG_KEY, IPC_CREAT | 0600);
186 ATF_REQUIRE(id != -1);
187
188 errno = 0;
189
190 ATF_REQUIRE_ERRNO(EFAULT, msgsnd(id, (void *)-1,
191 sizeof(struct msg), IPC_NOWAIT) == -1);
192
193 errno = 0;
194
195 ATF_REQUIRE_ERRNO(EINVAL, msgsnd(-1, &msg,
196 sizeof(struct msg), IPC_NOWAIT) == -1);
197
198 errno = 0;
199
200 ATF_REQUIRE_ERRNO(EINVAL, msgsnd(-1, &msg,
201 SSIZE_MAX, IPC_NOWAIT) == -1);
202
203 errno = 0;
204 msg.mtype = 0;
205
206 ATF_REQUIRE_ERRNO(EINVAL, msgsnd(id, &msg,
207 sizeof(struct msg), IPC_NOWAIT) == -1);
208
209 ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
210}
211
212ATF_TC_CLEANUP(msgsnd_err, tc)
213{
214 clean();
215}
216
217ATF_TC_WITH_CLEANUP(msgsnd_nonblock);
218ATF_TC_HEAD(msgsnd_nonblock, tc)
219{
220 atf_tc_set_md_var(tc, "descr", "Test msgsnd(2) with IPC_NOWAIT");
221 atf_tc_set_md_var(tc, "timeout", "10");
222}
223
224ATF_TC_BODY(msgsnd_nonblock, tc)
225{
226 struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
227 int id, rv, sta;
228 pid_t pid;
229
230 id = msgget(MSG_KEY, IPC_CREAT | 0600);
231 ATF_REQUIRE(id != -1);
232
233 pid = fork();
234 ATF_REQUIRE(pid >= 0);
235
236 if (pid == 0) {
237
238 for (;;) {
239
240 errno = 0;
241 rv = msgsnd(id, &msg, sizeof(struct msg), IPC_NOWAIT);
242
243 if (rv == -1 && errno == EAGAIN)
244 _exit(EXIT_SUCCESS);
245 }
246 }
247
248 (void)sleep(2);
249 (void)kill(pid, SIGKILL);
250 (void)wait(&sta);
251
252 if (WIFEXITED(sta) == 0 || WIFSIGNALED(sta) != 0)
253 atf_tc_fail("msgsnd(2) blocked with IPC_NOWAIT");
254
255 ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
256}
257
258ATF_TC_CLEANUP(msgsnd_nonblock, tc)
259{
260 clean();
261}
262
263ATF_TC_WITH_CLEANUP(msgsnd_perm);
264ATF_TC_HEAD(msgsnd_perm, tc)
265{
266 atf_tc_set_md_var(tc, "descr", "Test permissions with msgsnd(2)");
267 atf_tc_set_md_var(tc, "require.user", "root");
268}
269
270ATF_TC_BODY(msgsnd_perm, tc)
271{
272 struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
273 struct passwd *pw;
274 int id, sta;
275 pid_t pid;
276 uid_t uid;
277
278 pw = getpwnam("nobody");
279 id = msgget(MSG_KEY, IPC_CREAT | 0600);
280
281 ATF_REQUIRE(id != -1);
282 ATF_REQUIRE(pw != NULL);
283
284 uid = pw->pw_uid;
285 ATF_REQUIRE(uid != 0);
286
287 pid = fork();
288 ATF_REQUIRE(pid >= 0);
289
290 if (pid == 0) {
291
292 /*
293 * Try to enqueue a message to the queue
294 * created by root as RW for owner only.
295 */
296 if (setuid(uid) != 0)
297 _exit(EX_OSERR);
298
299 id = msgget(MSG_KEY, 0);
300
301 if (id == -1)
302 _exit(EX_OSERR);
303
304 errno = 0;
305
306 if (msgsnd(id, &msg, sizeof(struct msg), IPC_NOWAIT) == 0)
307 _exit(EXIT_FAILURE);
308
309 if (errno != EACCES)
310 _exit(EXIT_FAILURE);
311
312 _exit(EXIT_SUCCESS);
313 }
314
315 (void)wait(&sta);
316
317 if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) {
318
319 if (errno == EX_OSERR)
320 atf_tc_fail("system call failed");
321
322 atf_tc_fail("UID %u enqueued message to root's queue", uid);
323 }
324
325 ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
326}
327
328ATF_TC_CLEANUP(msgsnd_perm, tc)
329{
330 clean();
331}
332
333static volatile int sig_caught;
334
335static void
336sigsys_handler(int signum)
337{
338
339 sig_caught = signum;
340}
341
342static int
343no_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
360ATF_TC(msgsnd_query);
361ATF_TC_HEAD(msgsnd_query, tc)
362{
363 atf_tc_set_md_var(tc, "descr", "Skip msgsnd_* tests - no SYSVMSG");
364}
365ATF_TC_BODY(msgsnd_query, tc)
366{
367 atf_tc_skip("No SYSVMSG in kernel");
368}
369
370ATF_TP_ADD_TCS(tp)
371{
372
373 if (no_kernel_sysvmsg()) {
374 ATF_TP_ADD_TC(tp, msgsnd_query);
375 } else {
376 ATF_TP_ADD_TC(tp, msgsnd_block);
377 ATF_TP_ADD_TC(tp, msgsnd_count);
378 ATF_TP_ADD_TC(tp, msgsnd_err);
379 ATF_TP_ADD_TC(tp, msgsnd_nonblock);
380 ATF_TP_ADD_TC(tp, msgsnd_perm);
381 }
382
383 return atf_no_error();
384}