xref: /netbsd-src/tests/kernel/t_sysv.c (revision b47b148d8347aa85ff5700233a31447915785760)
1 /*	$NetBSD: t_sysv.c,v 1.6 2022/05/14 14:02:03 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 1999, 2007 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9  * NASA Ames Research Center, and by Andrew Doran.
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 /*
34  * Test the SVID-compatible Message Queue facility.
35  */
36 
37 #include <atf-c.h>
38 
39 #include <err.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <signal.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <time.h>
47 #include <unistd.h>
48 
49 #include <sys/ipc.h>
50 #include <sys/msg.h>
51 #include <sys/param.h>
52 #include <sys/sem.h>
53 #include <sys/shm.h>
54 #include <sys/wait.h>
55 
56 volatile int did_sigsys;
57 
58 void	sigsys_handler(int);
59 
60 key_t	get_ftok(int);
61 
62 void	print_msqid_ds(struct msqid_ds *, mode_t);
63 void	receiver(void);
64 
65 void	print_semid_ds(struct semid_ds *, mode_t);
66 void	waiter(void);
67 
68 void	print_shmid_ds(struct shmid_ds *, mode_t);
69 void	sharer(void);
70 
71 #define	MESSAGE_TEXT_LEN	256
72 
73 struct testmsg {
74 	long	mtype;
75 	char	mtext[MESSAGE_TEXT_LEN];
76 };
77 
78 const char *m1_str = "California is overrated.";
79 const char *m2_str = "The quick brown fox jumped over the lazy dog.";
80 
81 size_t	pgsize;
82 
83 #define	MTYPE_1		1
84 #define	MTYPE_1_ACK	2
85 
86 #define	MTYPE_2		3
87 #define	MTYPE_2_ACK	4
88 
89 pid_t	child_pid;
90 
91 key_t	msgkey, semkey, shmkey;
92 
93 int	maxloop = 1;
94 
95 union semun {
96 	int	val;		/* value for SETVAL */
97 	struct	semid_ds *buf;	/* buffer for IPC_{STAT,SET} */
98 	u_short	*array;		/* array for GETALL & SETALL */
99 };
100 
101 
102 /* Writes an integer to a file.  To be used from the body of the test
103  * cases below to pass any global identifiers to the cleanup routine. */
104 static void
write_int(const char * path,const int value)105 write_int(const char *path, const int value)
106 {
107 	int output;
108 
109 	output = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
110 	ATF_REQUIRE_MSG(output != -1, "Failed to create %s", path);
111 	write(output, &value, sizeof(value));
112 	close(output);
113 }
114 
115 
116 /* Reads an integer from a file.  To be used from the cleanup routines
117  * of the test cases below. */
118 static int
read_int(const char * path)119 read_int(const char *path)
120 {
121 	int input, value;
122 
123 	input = open(path, O_RDONLY);
124 	if (input == -1)
125 		return -1;
126 
127 	read(input, &value, sizeof(value));
128 	return value;
129 }
130 
131 
132 void
sigsys_handler(int signo)133 sigsys_handler(int signo)
134 {
135 
136 	did_sigsys = 1;
137 }
138 
get_ftok(int id)139 key_t get_ftok(int id)
140 {
141 	int fd;
142 	char token_key[64], token_dir[64];
143 	char *tmpdir;
144 	key_t key;
145 
146 	strlcpy(token_key, "/tmp/t_sysv.XXXXXX", sizeof(token_key));
147 	tmpdir = mkdtemp(token_key);
148 	ATF_REQUIRE_MSG(tmpdir != NULL, "mkdtemp() failed: %d", errno);
149 
150 	strlcpy(token_dir, tmpdir, sizeof(token_dir));
151 	strlcpy(token_key, tmpdir, sizeof(token_key));
152 	strlcat(token_key, "/token_key", sizeof(token_key));
153 
154 	/* Create the file, since ftok() requires it to exist! */
155 
156 	fd = open(token_key, O_RDWR | O_CREAT | O_EXCL, 0600);
157 	if (fd == -1) {
158 		rmdir(tmpdir);
159 		atf_tc_fail("open() of temp file failed: %d", errno);
160 		return (key_t)-1;
161 	}
162 
163 	close(fd);
164 
165 	key = ftok(token_key, id);
166 	ATF_REQUIRE_MSG(key != (key_t)-1, "ftok() failed");
167 
168 	ATF_REQUIRE_MSG(unlink(token_key) != -1, "unlink() failed: %d", errno);
169 	ATF_REQUIRE_MSG(rmdir(token_dir) != -1, "rmdir() failed: %d", errno);
170 
171 	return key;
172 }
173 
174 ATF_TC_WITH_CLEANUP(msg);
ATF_TC_HEAD(msg,tc)175 ATF_TC_HEAD(msg, tc)
176 {
177 
178 	atf_tc_set_md_var(tc, "timeout", "3");
179 	atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing");
180 }
181 
ATF_TC_BODY(msg,tc)182 ATF_TC_BODY(msg, tc)
183 {
184 	struct sigaction sa;
185 	struct msqid_ds m_ds;
186 	struct testmsg m;
187 	int sender_msqid;
188 	int loop;
189 	int c_status;
190 	pid_t wait_result;
191 
192 	/*
193 	 * Install a SIGSYS handler so that we can exit gracefully if
194 	 * System V Message Queue support isn't in the kernel.
195 	 */
196 	did_sigsys = 0;
197 	sa.sa_handler = sigsys_handler;
198 	sigemptyset(&sa.sa_mask);
199 	sa.sa_flags = 0;
200 	ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
201 	    "sigaction SIGSYS: %d", errno);
202 
203 	msgkey = get_ftok(4160);
204 	ATF_REQUIRE_MSG(msgkey != (key_t)-1, "get_ftok failed");
205 
206 	sender_msqid = msgget(msgkey, IPC_CREAT | 0640);
207 	ATF_REQUIRE_MSG(sender_msqid != -1, "msgget: %d", errno);
208 	write_int("sender_msqid", sender_msqid);
209 
210 	if (did_sigsys) {
211 		atf_tc_skip("SYSV Message Queue not supported");
212 		return;
213 	}
214 
215 	ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1,
216 	"msgctl IPC_STAT 1: %d", errno);
217 
218 	print_msqid_ds(&m_ds, 0640);
219 
220 	m_ds.msg_perm.mode = (m_ds.msg_perm.mode & ~0777) | 0600;
221 
222 	ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_SET, &m_ds) != -1,
223 	    "msgctl IPC_SET: %d", errno);
224 
225 	memset(&m_ds, 0, sizeof(m_ds));
226 
227 	ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1,
228 	    "msgctl IPC_STAT 2: %d", errno);
229 
230 	ATF_REQUIRE_MSG((m_ds.msg_perm.mode & 0777) == 0600,
231 	    "IPC_SET of mode didn't hold");
232 
233 	print_msqid_ds(&m_ds, 0600);
234 
235 	fflush(stdout);
236 
237 	switch ((child_pid = fork())) {
238 	case -1:
239 		atf_tc_fail("fork: %d", errno);
240 		return;
241 
242 	case 0:
243 		receiver();
244 		break;
245 
246 	default:
247 		break;
248 	}
249 
250 	for (loop = 0; loop < maxloop; loop++) {
251 		/*
252 		 * Send the first message to the receiver and wait for the ACK.
253 		 */
254 		m.mtype = MTYPE_1;
255 		strcpy(m.mtext, m1_str);
256 		ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN,
257 		    0) != -1, "sender: msgsnd 1: %d", errno);
258 
259 		ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN,
260 		    MTYPE_1_ACK, 0) == MESSAGE_TEXT_LEN,
261 		    "sender: msgrcv 1 ack: %d", errno);
262 
263 		print_msqid_ds(&m_ds, 0600);
264 
265 		/*
266 		 * Send the second message to the receiver and wait for the ACK.
267 		 */
268 		m.mtype = MTYPE_2;
269 		strcpy(m.mtext, m2_str);
270 		ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN, 0)
271 		    != -1, "sender: msgsnd 2: %d", errno);
272 
273 		ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN,
274 		    MTYPE_2_ACK, 0) == MESSAGE_TEXT_LEN,
275 		    "sender: msgrcv 2 ack: %d", errno);
276 	}
277 
278 	/*
279 	 * Wait for child to finish
280 	 */
281 	wait_result = wait(&c_status);
282 	ATF_REQUIRE_EQ_MSG(wait_result, child_pid, "wait returned %d (%s)",
283 	    wait_result, wait_result == -1 ? strerror(errno) : "");
284 	ATF_REQUIRE_MSG(WIFEXITED(c_status), "child abnormal exit: %d (sig %d)",
285 	    c_status, WTERMSIG(c_status));
286 	ATF_REQUIRE_EQ_MSG(WEXITSTATUS(c_status), 0, "child status: %d",
287 	    WEXITSTATUS(c_status));
288 
289 	ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1,
290 	    "msgctl IPC_STAT: %d", errno);
291 
292 	print_msqid_ds(&m_ds, 0600);
293 }
294 
ATF_TC_CLEANUP(msg,tc)295 ATF_TC_CLEANUP(msg, tc)
296 {
297 	int sender_msqid;
298 
299 	/*
300 	 * Remove the message queue if it exists.
301 	 */
302 	sender_msqid = read_int("sender_msqid");
303 	if (sender_msqid == -1)
304 		return;
305 	if (msgctl(sender_msqid, IPC_RMID, NULL) == -1)
306 		err(EXIT_FAILURE, "msgctl IPC_RMID");
307 }
308 
309 void
print_msqid_ds(struct msqid_ds * mp,mode_t mode)310 print_msqid_ds(struct msqid_ds *mp, mode_t mode)
311 {
312 	uid_t uid = geteuid();
313 	gid_t gid = getegid();
314 
315 	printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
316 	    mp->msg_perm.uid, mp->msg_perm.gid,
317 	    mp->msg_perm.cuid, mp->msg_perm.cgid,
318 	    mp->msg_perm.mode & 0777);
319 
320 	printf("qnum %lu, qbytes %ju, lspid %d, lrpid %d\n",
321 	    mp->msg_qnum, (uintmax_t)mp->msg_qbytes, mp->msg_lspid,
322 	    mp->msg_lrpid);
323 
324 	printf("stime: %s", ctime(&mp->msg_stime));
325 	printf("rtime: %s", ctime(&mp->msg_rtime));
326 	printf("ctime: %s", ctime(&mp->msg_ctime));
327 
328 	/*
329 	 * Sanity check a few things.
330 	 */
331 
332 	ATF_REQUIRE_MSG(mp->msg_perm.uid == uid && mp->msg_perm.cuid == uid,
333 	    "uid mismatch");
334 
335 	ATF_REQUIRE_MSG(mp->msg_perm.gid == gid && mp->msg_perm.cgid == gid,
336 	    "gid mismatch");
337 
338 	ATF_REQUIRE_MSG((mp->msg_perm.mode & 0777) == mode, "mode mismatch");
339 }
340 
341 void
receiver(void)342 receiver(void)
343 {
344 	struct testmsg m;
345 	int msqid, loop;
346 
347 	if ((msqid = msgget(msgkey, 0)) == -1)
348 		err(EXIT_FAILURE, "receiver: msgget");
349 
350 	for (loop = 0; loop < maxloop; loop++) {
351 		/*
352 		 * Receive the first message, print it, and send an ACK.
353 		 */
354 		if (msgrcv(msqid, &m, MESSAGE_TEXT_LEN, MTYPE_1, 0)
355 		    != MESSAGE_TEXT_LEN)
356 			err(EXIT_FAILURE, "receiver: msgrcv 1");
357 
358 		printf("%s\n", m.mtext);
359 		if (strcmp(m.mtext, m1_str) != 0)
360 			errx(EXIT_FAILURE,
361 			    "receiver: message 1 data isn't correct");
362 
363 		m.mtype = MTYPE_1_ACK;
364 
365 		if (msgsnd(msqid, &m, MESSAGE_TEXT_LEN, 0) == -1)
366 			err(EXIT_FAILURE, "receiver: msgsnd ack 1");
367 
368 		/*
369 		 * Receive the second message, print it, and send an ACK.
370 		 */
371 
372 		if (msgrcv(msqid, &m, MESSAGE_TEXT_LEN, MTYPE_2, 0)
373 		    != MESSAGE_TEXT_LEN)
374 			err(EXIT_FAILURE, "receiver: msgrcv 2");
375 
376 		printf("%s\n", m.mtext);
377 		if (strcmp(m.mtext, m2_str) != 0)
378 			errx(EXIT_FAILURE,
379 			    "receiver: message 2 data isn't correct");
380 
381 		m.mtype = MTYPE_2_ACK;
382 
383 		if (msgsnd(msqid, &m, MESSAGE_TEXT_LEN, 0) == -1)
384 			err(EXIT_FAILURE, "receiver: msgsnd ack 2");
385 	}
386 
387 	exit(EXIT_SUCCESS);
388 }
389 
390 /*
391  * Test the SVID-compatible Semaphore facility.
392  */
393 
394 ATF_TC_WITH_CLEANUP(sem);
ATF_TC_HEAD(sem,tc)395 ATF_TC_HEAD(sem, tc)
396 {
397 
398 	atf_tc_set_md_var(tc, "timeout", "3");
399 	atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing");
400 }
401 
ATF_TC_BODY(sem,tc)402 ATF_TC_BODY(sem, tc)
403 {
404 	struct sigaction sa;
405 	union semun sun;
406 	struct semid_ds s_ds;
407 	int sender_semid;
408 	int i;
409 	int c_status;
410 	int child_count;
411 	pid_t wait_result;
412 
413 	/*
414 	 * Install a SIGSYS handler so that we can exit gracefully if
415 	 * System V Semaphore support isn't in the kernel.
416 	 */
417 	did_sigsys = 0;
418 	sa.sa_handler = sigsys_handler;
419 	sigemptyset(&sa.sa_mask);
420 	sa.sa_flags = 0;
421 	ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
422 	    "sigaction SIGSYS: %d", errno);
423 
424 	semkey = get_ftok(4160);
425 	ATF_REQUIRE_MSG(semkey != (key_t)-1, "get_ftok failed");
426 
427 	sender_semid = semget(semkey, 1, IPC_CREAT | 0640);
428 	ATF_REQUIRE_MSG(sender_semid != -1, "semget: %d", errno);
429 	write_int("sender_semid", sender_semid);
430 
431 	if (did_sigsys) {
432 		atf_tc_skip("SYSV Semaphore not supported");
433 		return;
434 	}
435 
436 	sun.buf = &s_ds;
437 	ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1,
438 	    "semctl IPC_STAT: %d", errno);
439 
440 	print_semid_ds(&s_ds, 0640);
441 
442 	s_ds.sem_perm.mode = (s_ds.sem_perm.mode & ~0777) | 0600;
443 
444 	sun.buf = &s_ds;
445 	ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_SET, sun) != -1,
446 	    "semctl IPC_SET: %d", errno);
447 
448 	memset(&s_ds, 0, sizeof(s_ds));
449 
450 	sun.buf = &s_ds;
451 	ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1,
452 	    "semctl IPC_STAT: %d", errno);
453 
454 	ATF_REQUIRE_MSG((s_ds.sem_perm.mode & 0777) == 0600,
455 	    "IPC_SET of mode didn't hold");
456 
457 	print_semid_ds(&s_ds, 0600);
458 
459 	fflush(stdout);
460 
461 	for (child_count = 0; child_count < 5; child_count++) {
462 		switch ((child_pid = fork())) {
463 		case -1:
464 			atf_tc_fail("fork: %d", errno);
465 			return;
466 
467 		case 0:
468 			waiter();
469 			break;
470 
471 		default:
472 			break;
473 		}
474 	}
475 
476 	/*
477 	 * Wait for all of the waiters to be attempting to acquire the
478 	 * semaphore.
479 	 */
480 	for (;;) {
481 		i = semctl(sender_semid, 0, GETNCNT);
482 		if (i == -1)
483 			atf_tc_fail("semctl GETNCNT: %d", i);
484 		if (i == 5)
485 			break;
486 	}
487 
488 	/*
489 	 * Now set the thundering herd in motion by initializing the
490 	 * semaphore to the value 1.
491 	 */
492 	sun.val = 1;
493 	ATF_REQUIRE_MSG(semctl(sender_semid, 0, SETVAL, sun) != -1,
494 	    "sender: semctl SETVAL to 1: %d", errno);
495 
496 	/*
497 	 * Wait for all children to finish
498 	 */
499 	while (child_count-- > 0) {
500 		wait_result = wait(&c_status);
501 		ATF_REQUIRE_MSG(wait_result != -1, "wait failed: %s",
502 		    strerror(errno));
503 		ATF_REQUIRE_MSG(WIFEXITED(c_status),
504 		    "child abnormal exit: %d (sig %d)",
505 		    c_status, WTERMSIG(c_status));
506 		ATF_REQUIRE_EQ_MSG(WEXITSTATUS(c_status), 0, "child status: %d",
507 		    WEXITSTATUS(c_status));
508 
509 		sun.buf = &s_ds;
510 		ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1,
511 		    "semctl IPC_STAT: %d", errno);
512 
513 		print_semid_ds(&s_ds, 0600);
514 	}
515 }
516 
ATF_TC_CLEANUP(sem,tc)517 ATF_TC_CLEANUP(sem, tc)
518 {
519 	int sender_semid;
520 
521 	/*
522 	 * Remove the semaphore if it exists
523 	 */
524 	sender_semid = read_int("sender_semid");
525 	if (sender_semid == -1)
526 		return;
527 	if (semctl(sender_semid, 0, IPC_RMID) == -1)
528 		err(EXIT_FAILURE, "semctl IPC_RMID");
529 }
530 
531 void
print_semid_ds(struct semid_ds * sp,mode_t mode)532 print_semid_ds(struct semid_ds *sp, mode_t mode)
533 {
534 	uid_t uid = geteuid();
535 	gid_t gid = getegid();
536 
537 	printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
538 	    sp->sem_perm.uid, sp->sem_perm.gid,
539 	    sp->sem_perm.cuid, sp->sem_perm.cgid,
540 	    sp->sem_perm.mode & 0777);
541 
542 	printf("nsems %u\n", sp->sem_nsems);
543 
544 	printf("otime: %s", ctime(&sp->sem_otime));
545 	printf("ctime: %s", ctime(&sp->sem_ctime));
546 
547 	/*
548 	 * Sanity check a few things.
549 	 */
550 
551 	ATF_REQUIRE_MSG(sp->sem_perm.uid == uid && sp->sem_perm.cuid == uid,
552 	    "uid mismatch");
553 
554 	ATF_REQUIRE_MSG(sp->sem_perm.gid == gid && sp->sem_perm.cgid == gid,
555 	    "gid mismatch");
556 
557 	ATF_REQUIRE_MSG((sp->sem_perm.mode & 0777) == mode,
558 	    "mode mismatch %o != %o", (sp->sem_perm.mode & 0777), mode);
559 }
560 
561 void
waiter(void)562 waiter(void)
563 {
564 	struct sembuf s;
565 	int semid;
566 
567 	if ((semid = semget(semkey, 1, 0)) == -1)
568 		err(EXIT_FAILURE, "waiter: semget");
569 
570 	/*
571 	 * Attempt to acquire the semaphore.
572 	 */
573 	s.sem_num = 0;
574 	s.sem_op = -1;
575 	s.sem_flg = SEM_UNDO;
576 
577 	if (semop(semid, &s, 1) == -1)
578 		err(EXIT_FAILURE, "waiter: semop -1");
579 
580 	printf("WOO!  GOT THE SEMAPHORE!\n");
581 	usleep(10000);
582 
583 	/*
584 	 * Release the semaphore and exit.
585 	 */
586 	s.sem_num = 0;
587 	s.sem_op = 1;
588 	s.sem_flg = SEM_UNDO;
589 
590 	if (semop(semid, &s, 1) == -1)
591 		err(EXIT_FAILURE, "waiter: semop +1");
592 
593 	exit(EXIT_SUCCESS);
594 }
595 
596 /*
597  * Test the SVID-compatible Shared Memory facility.
598  */
599 
600 ATF_TC_WITH_CLEANUP(shm);
ATF_TC_HEAD(shm,tc)601 ATF_TC_HEAD(shm, tc)
602 {
603 
604 	atf_tc_set_md_var(tc, "timeout", "3");
605 	atf_tc_set_md_var(tc, "descr", "Checks sysv shared memory");
606 }
607 
ATF_TC_BODY(shm,tc)608 ATF_TC_BODY(shm, tc)
609 {
610 	struct sigaction sa;
611 	struct shmid_ds s_ds;
612 	char *shm_buf;
613 	int sender_shmid;
614 	int c_status;
615 	pid_t wait_result;
616 
617 	/*
618 	 * Install a SIGSYS handler so that we can exit gracefully if
619 	 * System V Shared Memory support isn't in the kernel.
620 	 */
621 	did_sigsys = 0;
622 	sa.sa_handler = sigsys_handler;
623 	sigemptyset(&sa.sa_mask);
624 	sa.sa_flags = 0;
625 	ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
626 	    "sigaction SIGSYS: %d", errno);
627 
628 	pgsize = sysconf(_SC_PAGESIZE);
629 
630 	shmkey = get_ftok(4160);
631 	ATF_REQUIRE_MSG(shmkey != (key_t)-1, "get_ftok failed");
632 
633 	ATF_REQUIRE_MSG((sender_shmid = shmget(shmkey, pgsize,
634 					       IPC_CREAT | 0640)) != -1,
635 	    "shmget: %d", errno);
636 	write_int("sender_shmid", sender_shmid);
637 
638 	ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1,
639 	    "shmctl IPC_STAT: %d", errno);
640 
641 	print_shmid_ds(&s_ds, 0640);
642 
643 	s_ds.shm_perm.mode = (s_ds.shm_perm.mode & ~0777) | 0600;
644 
645 	ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_SET, &s_ds) != -1,
646 	    "shmctl IPC_SET: %d", errno);
647 
648 	memset(&s_ds, 0, sizeof(s_ds));
649 
650 	ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1,
651 	    "shmctl IPC_STAT: %d", errno);
652 
653 	ATF_REQUIRE_MSG((s_ds.shm_perm.mode & 0777) == 0600,
654 	    "IPC_SET of mode didn't hold");
655 
656 	print_shmid_ds(&s_ds, 0600);
657 
658 	shm_buf = shmat(sender_shmid, NULL, 0);
659 	ATF_REQUIRE_MSG(shm_buf != (void *) -1, "sender: shmat: %d", errno);
660 
661 	/*
662 	 * Write the test pattern into the shared memory buffer.
663 	 */
664 	strcpy(shm_buf, m2_str);
665 
666 	fflush(stdout);
667 
668 	switch ((child_pid = fork())) {
669 	case -1:
670 		atf_tc_fail("fork: %d", errno);
671 		return;
672 
673 	case 0:
674 		sharer();
675 		break;
676 
677 	default:
678 		break;
679 	}
680 
681 	/*
682 	 * Wait for child to finish
683 	 */
684 	wait_result = wait(&c_status);
685 	ATF_REQUIRE_EQ_MSG(wait_result, child_pid, "wait returned %d (%s)",
686 	    wait_result, wait_result == -1 ? strerror(errno) : "");
687 	ATF_REQUIRE_MSG(WIFEXITED(c_status), "child abnormal exit: %d (sig %d)",
688 	    c_status, WTERMSIG(c_status));
689 	ATF_REQUIRE_EQ_MSG(WEXITSTATUS(c_status), 0, "child status: %d",
690 	    WEXITSTATUS(c_status));
691 
692 	ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1,
693 	    "shmctl IPC_STAT: %d", errno);
694 
695 	print_shmid_ds(&s_ds, 0600);
696 }
697 
ATF_TC_CLEANUP(shm,tc)698 ATF_TC_CLEANUP(shm, tc)
699 {
700 	int sender_shmid;
701 
702 	/*
703 	 * Remove the shared memory area if it exists.
704 	 */
705 	sender_shmid = read_int("sender_shmid");
706 	if (sender_shmid == -1)
707 		return;
708 	if (shmctl(sender_shmid, IPC_RMID, NULL) == -1)
709 		err(EXIT_FAILURE, "shmctl IPC_RMID");
710 }
711 
712 void
print_shmid_ds(struct shmid_ds * sp,mode_t mode)713 print_shmid_ds(struct shmid_ds *sp, mode_t mode)
714 {
715 	uid_t uid = geteuid();
716 	gid_t gid = getegid();
717 
718 	printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
719 	    sp->shm_perm.uid, sp->shm_perm.gid,
720 	    sp->shm_perm.cuid, sp->shm_perm.cgid,
721 	    sp->shm_perm.mode & 0777);
722 
723 	printf("segsz %ju, lpid %d, cpid %d, nattch %u\n",
724 	    (uintmax_t)sp->shm_segsz, sp->shm_lpid, sp->shm_cpid,
725 	    sp->shm_nattch);
726 
727 	printf("atime: %s", ctime(&sp->shm_atime));
728 	printf("dtime: %s", ctime(&sp->shm_dtime));
729 	printf("ctime: %s", ctime(&sp->shm_ctime));
730 
731 	/*
732 	 * Sanity check a few things.
733 	 */
734 
735 	ATF_REQUIRE_MSG(sp->shm_perm.uid == uid && sp->shm_perm.cuid == uid,
736 	    "uid mismatch");
737 
738 	ATF_REQUIRE_MSG(sp->shm_perm.gid == gid && sp->shm_perm.cgid == gid,
739 	    "gid mismatch");
740 
741 	ATF_REQUIRE_MSG((sp->shm_perm.mode & 0777) == mode,
742 	    "mode mismatch %o != %o", sp->shm_perm.mode & 0777, mode);
743 }
744 
745 void
sharer(void)746 sharer(void)
747 {
748 	int shmid;
749 	void *shm_buf;
750 
751 	shmid = shmget(shmkey, pgsize, 0);
752 	if (shmid == -1)
753 		err(EXIT_FAILURE, "receiver: shmget");
754 
755 	shm_buf = shmat(shmid, NULL, 0);
756 	if (shm_buf == (void *) -1)
757 		err(EXIT_FAILURE, "receiver: shmat");
758 
759 	printf("%s\n", (const char *)shm_buf);
760 
761 	if (strcmp((const char *)shm_buf, m2_str) != 0)
762 		errx(EXIT_FAILURE, "receiver: data isn't correct");
763 
764 	exit(EXIT_SUCCESS);
765 }
766 
ATF_TP_ADD_TCS(tp)767 ATF_TP_ADD_TCS(tp)
768 {
769 
770 	ATF_TP_ADD_TC(tp, msg);
771 	ATF_TP_ADD_TC(tp, sem);
772 	ATF_TP_ADD_TC(tp, shm);
773 
774 	return atf_no_error();
775 }
776