14Srgrimes/* $NetBSD: t_msgsnd.c,v 1.3 2017/01/13 20:44:45 christos Exp $ */
2122295Speter
3549Srgrimes/*-
44Srgrimes * Copyright (c) 2011 The NetBSD Foundation, Inc.
54Srgrimes * All rights reserved.
64Srgrimes *
74Srgrimes * This code is derived from software contributed to The NetBSD Foundation
84Srgrimes * by Jukka Ruohonen.
94Srgrimes *
104Srgrimes * Redistribution and use in source and binary forms, with or without
114Srgrimes * modification, are permitted provided that the following conditions
124Srgrimes * are met:
134Srgrimes * 1. Redistributions of source code must retain the above copyright
144Srgrimes *    notice, this list of conditions and the following disclaimer.
154Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
164Srgrimes *    notice, this list of conditions and the following disclaimer in the
174Srgrimes *    documentation and/or other materials provided with the distribution.
184Srgrimes *
194Srgrimes * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
204Srgrimes * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
214Srgrimes * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
224Srgrimes * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
234Srgrimes * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
244Srgrimes * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
254Srgrimes * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
264Srgrimes * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
274Srgrimes * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
284Srgrimes * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
294Srgrimes * POSSIBILITY OF SUCH DAMAGE.
304Srgrimes */
314Srgrimes#include <sys/cdefs.h>
324Srgrimes__RCSID("$NetBSD: t_msgsnd.c,v 1.3 2017/01/13 20:44:45 christos Exp $");
334Srgrimes
344Srgrimes#include <sys/msg.h>
354Srgrimes#include <sys/stat.h>
364Srgrimes#include <sys/sysctl.h>
374Srgrimes#include <sys/wait.h>
38123180Speter
394Srgrimes#include <atf-c.h>
4071261Speter#include <errno.h>
41118031Sobrien#include <limits.h>
42118031Sobrien#include <pwd.h>
43118031Sobrien#include <signal.h>
4436605Sbde#include <stdio.h>
45122849Speter#include <stdlib.h>
4652150Smarcel#include <string.h>
4731544Sjmg#include <sysexits.h>
4813228Swollman#include <time.h>
4936605Sbde#include <unistd.h>
5036605Sbde
5171785Speter#define MSG_KEY		1234
52118235Speter#define MSG_MTYPE_1	0x41
5328976Sbde#define	MSG_MTYPE_2	0x42
54222853Savg#define MSG_MTYPE_3	0x43
5514825Swollman
56250840Smarcelstruct msg {
57178471Sjeff	long		 mtype;
58211924Srpaulo	char		 buf[3];
594Srgrimes};
601549Srgrimes
61141378Snjlstatic void		clean(void);
621549Srgrimes
63141237Snjlstatic void
64141237Snjlclean(void)
65141237Snjl{
66141237Snjl	int id;
67141378Snjl
68141237Snjl	if ((id = msgget(MSG_KEY, 0)) != -1)
69270344Semaste		(void)msgctl(id, IPC_RMID, 0);
70141237Snjl}
71141378Snjl
72102561SjakeATF_TC_WITH_CLEANUP(msgsnd_block);
73131941SmarcelATF_TC_HEAD(msgsnd_block, tc)
741549Srgrimes{
7565557Sjasone	atf_tc_set_md_var(tc, "descr", "Test that msgsnd(2) blocks");
7640089Smsmith	atf_tc_set_md_var(tc, "timeout", "10");
7774912Sjhb}
7854188Sluoqi
79238310SjhbATF_TC_BODY(msgsnd_block, tc)
80141378Snjl{
8167357Sjhb	struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
8276440Sjhb	int id, sta;
83141378Snjl	pid_t pid;
841549Srgrimes
85248084Sattilio	id = msgget(MSG_KEY, IPC_CREAT | 0600);
86104964Sjeff	ATF_REQUIRE(id != -1);
87141237Snjl
88219473Sjkim	pid = fork();
89219473Sjkim	ATF_REQUIRE(pid >= 0);
90219473Sjkim
91209613Sjhb	if (pid == 0) {
92141378Snjl
932254Ssos		/*
94141237Snjl		 * Enqueue messages until some limit (e.g. the maximum
9590776Sdeischen		 * number of messages in the queue or the maximum number
9612662Sdg		 * of bytes in the queue) is reached. After this the call
974Srgrimes		 * should block when the IPC_NOWAIT is not set.
982056Swollman		 */
99141378Snjl		for (;;) {
1002056Swollman
1012056Swollman#ifdef __FreeBSD__
10212662Sdg			if (msgsnd(id, &msg, sizeof(msg.buf), 0) < 0)
103141378Snjl#else
1049507Sdg			if (msgsnd(id, &msg, sizeof(struct msg), 0) < 0)
105141378Snjl#endif
1064Srgrimes				_exit(EXIT_FAILURE);
107133903Speter		}
108133903Speter	}
109133903Speter
110133903Speter	(void)sleep(2);
111195410Sjhb	(void)kill(pid, SIGKILL);
112195410Sjhb	(void)wait(&sta);
113133903Speter
1147090Sbde	if (WIFEXITED(sta) != 0 || WIFSIGNALED(sta) == 0)
1152772Swollman		atf_tc_fail("msgsnd(2) did not block");
1162772Swollman
117141378Snjl	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
1182056Swollman}
11964592Sjhb
120122849SpeterATF_TC_CLEANUP(msgsnd_block, tc)
121214630Sjhb{
1227090Sbde	clean();
123141378Snjl}
124222853Savg
125135691SpeterATF_TC_WITH_CLEANUP(msgsnd_count);
126141378SnjlATF_TC_HEAD(msgsnd_count, tc)
12785449Sjhb{
128141378Snjl	atf_tc_set_md_var(tc, "descr",
129141378Snjl	    "Test that msgsnd(2) increments the amount of "
130141378Snjl	    "message in the queue, as given by msgctl(2)");
13114825Swollman	atf_tc_set_md_var(tc, "timeout", "10");
13214825Swollman}
13314825Swollman
134114349SpeterATF_TC_BODY(msgsnd_count, tc)
135122849Speter{
136122849Speter	struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
137122849Speter	struct msqid_ds ds;
138250840Smarcel	size_t i = 0;
139250840Smarcel	int id, rv;
140250840Smarcel
141556Srgrimes	id = msgget(MSG_KEY, IPC_CREAT | 0600);
142163267Sjhb	ATF_REQUIRE(id != -1);
143204309Sattilio
144163267Sjhb	for (;;) {
145152651Sjhb
146163267Sjhb		errno = 0;
147122849Speter#ifdef	__FreeBSD__
148122849Speter		rv = msgsnd(id, &msg, sizeof(msg.buf), IPC_NOWAIT);
14947642Sdfr#else
1504Srgrimes		rv = msgsnd(id, &msg, sizeof(struct msg), IPC_NOWAIT);
151122930Speter#endif
152122930Speter
153122930Speter		if (rv == 0) {
154115431Speter			i++;
15510358Sjulian			continue;
15624112Skato		}
157114349Speter
15824112Skato		if (rv == -1 && errno == EAGAIN)
15913085Sdg			break;
16061220Sbde
16161220Sbde		atf_tc_fail("failed to enqueue a message");
16261220Sbde	}
16392770Salfred
164230426Skib	(void)memset(&ds, 0, sizeof(struct msqid_ds));
165230426Skib	(void)msgctl(id, IPC_STAT, &ds);
166230426Skib
167230426Skib	if (ds.msg_qnum != i)
168177253Srwatson		atf_tc_fail("incorrect message count");
16910358Sjulian
170220090Salc	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
171220090Salc}
172220090Salc
173220090SalcATF_TC_CLEANUP(msgsnd_count, tc)
174220090Salc{
175131941Smarcel	clean();
176131941Smarcel}
177131941Smarcel
178131941SmarcelATF_TC_WITH_CLEANUP(msgsnd_err);
179202897SalcATF_TC_HEAD(msgsnd_err, tc)
180202897Salc{
181174557Srpaulo	atf_tc_set_md_var(tc, "descr", "Test errors from msgsnd(2)");
182174557Srpaulo}
183174557Srpaulo
184174557SrpauloATF_TC_BODY(msgsnd_err, tc)
185190620Skib{
186556Srgrimes	struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
18715392Sphk	int id;
18812623Sphk
189102600Speter	id = msgget(MSG_KEY, IPC_CREAT | 0600);
190142866Sobrien	ATF_REQUIRE(id != -1);
1914Srgrimes
192170253Salc	errno = 0;
193170253Salc
194170253Salc	ATF_REQUIRE_ERRNO(EFAULT, msgsnd(id, (void *)-1,
195170253Salc#ifdef	__FreeBSD__
196170253Salc		sizeof(msg.buf), IPC_NOWAIT) == -1);
197170253Salc#else
198170253Salc		sizeof(struct msg), IPC_NOWAIT) == -1);
199974Sdg#endif
200162112Sjhb
201162112Sjhb	errno = 0;
202162112Sjhb
2039578Sdg	ATF_REQUIRE_ERRNO(EINVAL, msgsnd(-1, &msg,
204147671Speter#ifdef	__FreeBSD__
205147671Speter		sizeof(msg.buf), IPC_NOWAIT) == -1);
2069578Sdg#else
20782127Sdillon		sizeof(struct msg), IPC_NOWAIT) == -1);
20882127Sdillon#endif
20964529Speter
210122849Speter	errno = 0;
211556Srgrimes
212122849Speter	ATF_REQUIRE_ERRNO(EINVAL, msgsnd(-1, &msg,
213122849Speter		SSIZE_MAX, IPC_NOWAIT) == -1);
21488322Sjhb
21565557Sjasone	errno = 0;
216238310Sjhb	msg.mtype = 0;
217238310Sjhb
218190620Skib	ATF_REQUIRE_ERRNO(EINVAL, msgsnd(id, &msg,
219190620Skib#ifdef	__FreeBSD__
220261275Sjhb		sizeof(msg.buf), IPC_NOWAIT) == -1);
221261275Sjhb#else
22210358Sjulian		sizeof(struct msg), IPC_NOWAIT) == -1);
22311390Sbde#endif
22411390Sbde
2254Srgrimes	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
226190599Sjkim}
227174557Srpaulo
228174557SrpauloATF_TC_CLEANUP(msgsnd_err, tc)
2294Srgrimes{
230174557Srpaulo	clean();
231174557Srpaulo}
232174557Srpaulo
233174557SrpauloATF_TC_WITH_CLEANUP(msgsnd_nonblock);
234174557SrpauloATF_TC_HEAD(msgsnd_nonblock, tc)
235174557Srpaulo{
236174557Srpaulo	atf_tc_set_md_var(tc, "descr", "Test msgsnd(2) with IPC_NOWAIT");
237174557Srpaulo	atf_tc_set_md_var(tc, "timeout", "10");
238174557Srpaulo}
239195907Srpaulo
240196033SedATF_TC_BODY(msgsnd_nonblock, tc)
241271541Spfg{
242195907Srpaulo	struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
243195907Srpaulo	int id, rv, sta;
244196390Sed	pid_t pid;
245271541Spfg
246195907Srpaulo	id = msgget(MSG_KEY, IPC_CREAT | 0600);
247174557Srpaulo	ATF_REQUIRE(id != -1);
248174557Srpaulo
249174557Srpaulo	pid = fork();
250174557Srpaulo	ATF_REQUIRE(pid >= 0);
251174557Srpaulo
252174557Srpaulo	if (pid == 0) {
253174557Srpaulo
254174557Srpaulo		for (;;) {
255174557Srpaulo
2564Srgrimes			errno = 0;
2574Srgrimes#ifdef	__FreeBSD__
2582014Swollman			rv = msgsnd(id, &msg, sizeof(msg.buf), IPC_NOWAIT);
25924112Skato#else
26024112Skato			rv = msgsnd(id, &msg, sizeof(struct msg), IPC_NOWAIT);
26117014Swollman#endif
26217014Swollman
26317014Swollman			if (rv == -1 && errno == EAGAIN)
264196412Sjkim				_exit(EXIT_SUCCESS);
265196412Sjkim		}
266196412Sjkim	}
267196412Sjkim
268196412Sjkim	(void)wait(&sta);
269190599Sjkim
270190599Sjkim	if (WIFEXITED(sta) == 0 || WIFSIGNALED(sta) != 0)
271196412Sjkim		atf_tc_fail("msgsnd(2) blocked with IPC_NOWAIT");
272190599Sjkim
273196412Sjkim	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
274196412Sjkim}
275196412Sjkim
276196412SjkimATF_TC_CLEANUP(msgsnd_nonblock, tc)
277258996Sroyger{
278196412Sjkim	clean();
2799578Sdg}
2809578Sdg
2819578SdgATF_TC_WITH_CLEANUP(msgsnd_perm);
28229109SdgATF_TC_HEAD(msgsnd_perm, tc)
28329109Sdg{
2844Srgrimes	atf_tc_set_md_var(tc, "descr", "Test permissions with msgsnd(2)");
28529109Sdg	atf_tc_set_md_var(tc, "require.user", "root");
28629109Sdg}
287112569Sjake
2889578SdgATF_TC_BODY(msgsnd_perm, tc)
289112569Sjake{
290112569Sjake	struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
291112569Sjake	struct passwd *pw;
292112569Sjake	int id, sta;
293112569Sjake	pid_t pid;
294112569Sjake	uid_t uid;
2959578Sdg
2969578Sdg	pw = getpwnam("nobody");
2979578Sdg	id = msgget(MSG_KEY, IPC_CREAT | 0600);
29882127Sdillon
29982127Sdillon	ATF_REQUIRE(id != -1);
300190599Sjkim	ATF_REQUIRE(pw != NULL);
301170170Sattilio
302170170Sattilio	uid = pw->pw_uid;
3031298Sdg	ATF_REQUIRE(uid != 0);
30428808Speter
30528808Speter	pid = fork();
30628808Speter	ATF_REQUIRE(pid >= 0);
30728808Speter
30828808Speter	if (pid == 0) {
30928808Speter
31064529Speter		/*
3114Srgrimes		 * Try to enqueue a message to the queue
3124Srgrimes		 * created by root as RW for owner only.
3134Srgrimes		 */
3144Srgrimes		if (setuid(uid) != 0)
3154Srgrimes			_exit(EX_OSERR);
3164Srgrimes
317190620Skib		id = msgget(MSG_KEY, 0);
3184Srgrimes
3194Srgrimes		if (id == -1)
3204Srgrimes			_exit(EX_OSERR);
3214Srgrimes
3224Srgrimes		errno = 0;
32351792Smarcel
324151316Sdavidxu#ifdef	__FreeBSD__
32551792Smarcel		if (msgsnd(id, &msg, sizeof(msg.buf), IPC_NOWAIT) == 0)
326105950Speter#else
327216634Sjkim		if (msgsnd(id, &msg, sizeof(struct msg), IPC_NOWAIT) == 0)
32861220Sbde#endif
32983366Sjulian			_exit(EXIT_FAILURE);
33061220Sbde
331107521Sdeischen		if (errno != EACCES)
33251792Smarcel			_exit(EXIT_FAILURE);
333230426Skib
334230426Skib		_exit(EXIT_SUCCESS);
335156694Speter	}
33652140Sluoqi
33751792Smarcel	(void)wait(&sta);
33883366Sjulian
339216634Sjkim	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) {
34083366Sjulian
34183163Sjhb		if (errno == EX_OSERR)
342151316Sdavidxu			atf_tc_fail("system call failed");
34361220Sbde
344114983Sjhb		atf_tc_fail("UID %u enqueued message to root's queue", uid);
34583366Sjulian	}
346114349Speter
34751792Smarcel	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
348230426Skib}
349230426Skib
350230426SkibATF_TC_CLEANUP(msgsnd_perm, tc)
351230426Skib{
352230426Skib	clean();
353230426Skib}
354230426Skib
355230426SkibATF_TP_ADD_TCS(tp)
35661220Sbde{
35761220Sbde
35851792Smarcel	ATF_TP_ADD_TC(tp, msgsnd_block);
359124092Sdavidxu	ATF_TP_ADD_TC(tp, msgsnd_count);
360124092Sdavidxu	ATF_TP_ADD_TC(tp, msgsnd_err);
36169379Smarcel	ATF_TP_ADD_TC(tp, msgsnd_nonblock);
36269379Smarcel	ATF_TP_ADD_TC(tp, msgsnd_perm);
363114951Speter
364103407Smini	return atf_no_error();
365230426Skib}
366103407Smini