1*6618a9bfSkre /* $NetBSD: t_msgctl.c,v 1.7 2017/10/07 17:15:44 kre Exp $ */
262a65142Sjruoho
362a65142Sjruoho /*-
462a65142Sjruoho * Copyright (c) 2011 The NetBSD Foundation, Inc.
562a65142Sjruoho * All rights reserved.
662a65142Sjruoho *
762a65142Sjruoho * This code is derived from software contributed to The NetBSD Foundation
862a65142Sjruoho * by Jukka Ruohonen.
962a65142Sjruoho *
1062a65142Sjruoho * Redistribution and use in source and binary forms, with or without
1162a65142Sjruoho * modification, are permitted provided that the following conditions
1262a65142Sjruoho * are met:
1362a65142Sjruoho * 1. Redistributions of source code must retain the above copyright
1462a65142Sjruoho * notice, this list of conditions and the following disclaimer.
1562a65142Sjruoho * 2. Redistributions in binary form must reproduce the above copyright
1662a65142Sjruoho * notice, this list of conditions and the following disclaimer in the
1762a65142Sjruoho * documentation and/or other materials provided with the distribution.
1862a65142Sjruoho *
1962a65142Sjruoho * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2062a65142Sjruoho * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2162a65142Sjruoho * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2262a65142Sjruoho * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2362a65142Sjruoho * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2462a65142Sjruoho * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2562a65142Sjruoho * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2662a65142Sjruoho * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2762a65142Sjruoho * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2862a65142Sjruoho * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2962a65142Sjruoho * POSSIBILITY OF SUCH DAMAGE.
3062a65142Sjruoho */
3162a65142Sjruoho #include <sys/cdefs.h>
32*6618a9bfSkre __RCSID("$NetBSD: t_msgctl.c,v 1.7 2017/10/07 17:15:44 kre Exp $");
3362a65142Sjruoho
3462a65142Sjruoho #include <sys/msg.h>
3562a65142Sjruoho #include <sys/stat.h>
3662a65142Sjruoho #include <sys/sysctl.h>
3762a65142Sjruoho #include <sys/wait.h>
3862a65142Sjruoho
3962a65142Sjruoho #include <atf-c.h>
4062a65142Sjruoho #include <errno.h>
4193538aecSchristos #include <limits.h>
4262a65142Sjruoho #include <pwd.h>
434ad1e3d9Skre #include <signal.h>
4462a65142Sjruoho #include <stdio.h>
4562a65142Sjruoho #include <stdlib.h>
4662a65142Sjruoho #include <string.h>
4762a65142Sjruoho #include <sysexits.h>
4862a65142Sjruoho #include <time.h>
4962a65142Sjruoho #include <unistd.h>
5062a65142Sjruoho
5162a65142Sjruoho #define MSG_KEY 12345689
5262a65142Sjruoho #define MSG_MTYPE_1 0x41
5362a65142Sjruoho
5462a65142Sjruoho struct msg {
5562a65142Sjruoho long mtype;
5662a65142Sjruoho char buf[3];
5762a65142Sjruoho };
5862a65142Sjruoho
5962a65142Sjruoho static void clean(void);
6062a65142Sjruoho
6162a65142Sjruoho static void
clean(void)6262a65142Sjruoho clean(void)
6362a65142Sjruoho {
6462a65142Sjruoho int id;
6562a65142Sjruoho
6662a65142Sjruoho if ((id = msgget(MSG_KEY, 0)) != -1)
6762a65142Sjruoho (void)msgctl(id, IPC_RMID, 0);
6862a65142Sjruoho }
6962a65142Sjruoho
7062a65142Sjruoho ATF_TC_WITH_CLEANUP(msgctl_err);
ATF_TC_HEAD(msgctl_err,tc)7162a65142Sjruoho ATF_TC_HEAD(msgctl_err, tc)
7262a65142Sjruoho {
7362a65142Sjruoho atf_tc_set_md_var(tc, "descr", "Test errors from msgctl(2)");
7462a65142Sjruoho }
7562a65142Sjruoho
ATF_TC_BODY(msgctl_err,tc)7662a65142Sjruoho ATF_TC_BODY(msgctl_err, tc)
7762a65142Sjruoho {
7862a65142Sjruoho const int cmd[] = { IPC_STAT, IPC_SET, IPC_RMID };
7962a65142Sjruoho struct msqid_ds msgds;
8062a65142Sjruoho size_t i;
8162a65142Sjruoho int id;
8262a65142Sjruoho
8362a65142Sjruoho (void)memset(&msgds, 0, sizeof(struct msqid_ds));
8462a65142Sjruoho
8562a65142Sjruoho id = msgget(MSG_KEY, IPC_CREAT | 0600);
8662a65142Sjruoho ATF_REQUIRE(id != -1);
8762a65142Sjruoho
8862a65142Sjruoho errno = 0;
8962a65142Sjruoho ATF_REQUIRE_ERRNO(EINVAL, msgctl(id, INT_MAX, &msgds) == -1);
9062a65142Sjruoho
9162a65142Sjruoho errno = 0;
9262a65142Sjruoho ATF_REQUIRE_ERRNO(EFAULT, msgctl(id, IPC_STAT, (void *)-1) == -1);
9362a65142Sjruoho
9462a65142Sjruoho for (i = 0; i < __arraycount(cmd); i++) {
9562a65142Sjruoho errno = 0;
9662a65142Sjruoho ATF_REQUIRE_ERRNO(EINVAL, msgctl(-1, cmd[i], &msgds) == -1);
9762a65142Sjruoho }
9862a65142Sjruoho
9962a65142Sjruoho ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
10062a65142Sjruoho }
10162a65142Sjruoho
ATF_TC_CLEANUP(msgctl_err,tc)10262a65142Sjruoho ATF_TC_CLEANUP(msgctl_err, tc)
10362a65142Sjruoho {
10462a65142Sjruoho clean();
10562a65142Sjruoho }
10662a65142Sjruoho
10762a65142Sjruoho ATF_TC_WITH_CLEANUP(msgctl_perm);
ATF_TC_HEAD(msgctl_perm,tc)10862a65142Sjruoho ATF_TC_HEAD(msgctl_perm, tc)
10962a65142Sjruoho {
1108e19d927Sjruoho atf_tc_set_md_var(tc, "descr", "Test permissions with msgctl(2)");
11162a65142Sjruoho atf_tc_set_md_var(tc, "require.user", "root");
11262a65142Sjruoho }
11362a65142Sjruoho
ATF_TC_BODY(msgctl_perm,tc)11462a65142Sjruoho ATF_TC_BODY(msgctl_perm, tc)
11562a65142Sjruoho {
11662a65142Sjruoho struct msqid_ds msgds;
11762a65142Sjruoho struct passwd *pw;
11862a65142Sjruoho pid_t pid;
11962a65142Sjruoho int sta;
12062a65142Sjruoho int id;
12162a65142Sjruoho
12262a65142Sjruoho (void)memset(&msgds, 0, sizeof(struct msqid_ds));
12362a65142Sjruoho
12462a65142Sjruoho pw = getpwnam("nobody");
12562a65142Sjruoho id = msgget(MSG_KEY, IPC_CREAT | 0600);
12662a65142Sjruoho
12762a65142Sjruoho ATF_REQUIRE(id != -1);
12862a65142Sjruoho ATF_REQUIRE(pw != NULL);
12962a65142Sjruoho ATF_REQUIRE(msgctl(id, IPC_STAT, &msgds) == 0);
13062a65142Sjruoho
13162a65142Sjruoho pid = fork();
13262a65142Sjruoho ATF_REQUIRE(pid >= 0);
13362a65142Sjruoho
13462a65142Sjruoho if (pid == 0) {
13562a65142Sjruoho
13662a65142Sjruoho if (setuid(pw->pw_uid) != 0)
13762a65142Sjruoho _exit(EX_OSERR);
13862a65142Sjruoho
13962a65142Sjruoho msgds.msg_perm.uid = getuid();
14062a65142Sjruoho msgds.msg_perm.gid = getgid();
14162a65142Sjruoho
14262a65142Sjruoho errno = 0;
14362a65142Sjruoho
14462a65142Sjruoho if (msgctl(id, IPC_SET, &msgds) == 0)
14562a65142Sjruoho _exit(EXIT_FAILURE);
14662a65142Sjruoho
14762a65142Sjruoho if (errno != EPERM)
14862a65142Sjruoho _exit(EXIT_FAILURE);
14962a65142Sjruoho
15062a65142Sjruoho (void)memset(&msgds, 0, sizeof(struct msqid_ds));
15162a65142Sjruoho
15262a65142Sjruoho if (msgctl(id, IPC_STAT, &msgds) != 0)
15362a65142Sjruoho _exit(EX_OSERR);
15462a65142Sjruoho
15562a65142Sjruoho msgds.msg_qbytes = 1;
15662a65142Sjruoho
15762a65142Sjruoho if (msgctl(id, IPC_SET, &msgds) == 0)
15862a65142Sjruoho _exit(EXIT_FAILURE);
15962a65142Sjruoho
16062a65142Sjruoho if (errno != EPERM)
16162a65142Sjruoho _exit(EXIT_FAILURE);
16262a65142Sjruoho
16362a65142Sjruoho _exit(EXIT_SUCCESS);
16462a65142Sjruoho }
16562a65142Sjruoho
16662a65142Sjruoho (void)wait(&sta);
16762a65142Sjruoho
16862a65142Sjruoho if (WIFEXITED(sta) == 0) {
16962a65142Sjruoho
17062a65142Sjruoho if (WEXITSTATUS(sta) == EX_OSERR)
17162a65142Sjruoho atf_tc_fail("system call failed");
17262a65142Sjruoho
17362a65142Sjruoho if (WEXITSTATUS(sta) == EXIT_FAILURE)
17462a65142Sjruoho atf_tc_fail("UID %u manipulated root's "
17562a65142Sjruoho "message queue", pw->pw_uid);
17662a65142Sjruoho }
17762a65142Sjruoho
17862a65142Sjruoho ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
17962a65142Sjruoho }
18062a65142Sjruoho
ATF_TC_CLEANUP(msgctl_perm,tc)18162a65142Sjruoho ATF_TC_CLEANUP(msgctl_perm, tc)
18262a65142Sjruoho {
18362a65142Sjruoho clean();
18462a65142Sjruoho }
18562a65142Sjruoho
18662a65142Sjruoho ATF_TC_WITH_CLEANUP(msgctl_pid);
ATF_TC_HEAD(msgctl_pid,tc)18762a65142Sjruoho ATF_TC_HEAD(msgctl_pid, tc)
18862a65142Sjruoho {
18962a65142Sjruoho atf_tc_set_md_var(tc, "descr", "Test that PIDs are updated");
19062a65142Sjruoho }
19162a65142Sjruoho
ATF_TC_BODY(msgctl_pid,tc)19262a65142Sjruoho ATF_TC_BODY(msgctl_pid, tc)
19362a65142Sjruoho {
19462a65142Sjruoho struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
19562a65142Sjruoho struct msqid_ds msgds;
19662a65142Sjruoho int id, sta;
19762a65142Sjruoho pid_t pid;
19862a65142Sjruoho
19962a65142Sjruoho id = msgget(MSG_KEY, IPC_CREAT | 0600);
20062a65142Sjruoho ATF_REQUIRE(id != -1);
20162a65142Sjruoho
20262a65142Sjruoho pid = fork();
20362a65142Sjruoho ATF_REQUIRE(pid >= 0);
20462a65142Sjruoho
20562a65142Sjruoho if (pid == 0) {
20662a65142Sjruoho
20762a65142Sjruoho (void)msgsnd(id, &msg, sizeof(struct msg), IPC_NOWAIT);
20862a65142Sjruoho
20962a65142Sjruoho _exit(EXIT_SUCCESS);
21062a65142Sjruoho }
21162a65142Sjruoho
21262a65142Sjruoho (void)sleep(1);
21362a65142Sjruoho (void)wait(&sta);
21462a65142Sjruoho (void)memset(&msgds, 0, sizeof(struct msqid_ds));
21562a65142Sjruoho
21662a65142Sjruoho ATF_REQUIRE(msgctl(id, IPC_STAT, &msgds) == 0);
21762a65142Sjruoho
21862a65142Sjruoho if (pid != msgds.msg_lspid)
21962a65142Sjruoho atf_tc_fail("the PID of last msgsnd(2) was not updated");
22062a65142Sjruoho
22162a65142Sjruoho pid = fork();
22262a65142Sjruoho ATF_REQUIRE(pid >= 0);
22362a65142Sjruoho
22462a65142Sjruoho if (pid == 0) {
22562a65142Sjruoho
22662a65142Sjruoho (void)msgrcv(id, &msg,
22762a65142Sjruoho sizeof(struct msg), MSG_MTYPE_1, IPC_NOWAIT);
22862a65142Sjruoho
22962a65142Sjruoho _exit(EXIT_SUCCESS);
23062a65142Sjruoho }
23162a65142Sjruoho
23262a65142Sjruoho (void)sleep(1);
23362a65142Sjruoho (void)wait(&sta);
23462a65142Sjruoho (void)memset(&msgds, 0, sizeof(struct msqid_ds));
23562a65142Sjruoho
23662a65142Sjruoho ATF_REQUIRE(msgctl(id, IPC_STAT, &msgds) == 0);
23762a65142Sjruoho
23862a65142Sjruoho if (pid != msgds.msg_lrpid)
23962a65142Sjruoho atf_tc_fail("the PID of last msgrcv(2) was not updated");
24062a65142Sjruoho
24162a65142Sjruoho ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
24262a65142Sjruoho }
24362a65142Sjruoho
ATF_TC_CLEANUP(msgctl_pid,tc)24462a65142Sjruoho ATF_TC_CLEANUP(msgctl_pid, tc)
24562a65142Sjruoho {
24662a65142Sjruoho clean();
24762a65142Sjruoho }
24862a65142Sjruoho
24962a65142Sjruoho ATF_TC_WITH_CLEANUP(msgctl_set);
ATF_TC_HEAD(msgctl_set,tc)25062a65142Sjruoho ATF_TC_HEAD(msgctl_set, tc)
25162a65142Sjruoho {
25262a65142Sjruoho atf_tc_set_md_var(tc, "descr", "Test msgctl(2) with IPC_SET");
25362a65142Sjruoho atf_tc_set_md_var(tc, "require.user", "root");
25462a65142Sjruoho }
25562a65142Sjruoho
ATF_TC_BODY(msgctl_set,tc)25662a65142Sjruoho ATF_TC_BODY(msgctl_set, tc)
25762a65142Sjruoho {
25862a65142Sjruoho struct msqid_ds msgds;
25962a65142Sjruoho struct passwd *pw;
26062a65142Sjruoho int id;
26162a65142Sjruoho
26262a65142Sjruoho (void)memset(&msgds, 0, sizeof(struct msqid_ds));
26362a65142Sjruoho
26462a65142Sjruoho pw = getpwnam("nobody");
26562a65142Sjruoho id = msgget(MSG_KEY, IPC_CREAT | 0600);
26662a65142Sjruoho
26762a65142Sjruoho ATF_REQUIRE(id != -1);
26862a65142Sjruoho ATF_REQUIRE(pw != NULL);
26962a65142Sjruoho ATF_REQUIRE(msgctl(id, IPC_STAT, &msgds) == 0);
27062a65142Sjruoho
27162a65142Sjruoho msgds.msg_perm.uid = pw->pw_uid;
27262a65142Sjruoho
27362a65142Sjruoho if (msgctl(id, IPC_SET, &msgds) != 0)
27462a65142Sjruoho atf_tc_fail("root failed to change the UID of message queue");
27562a65142Sjruoho
27662a65142Sjruoho msgds.msg_perm.uid = getuid();
27762a65142Sjruoho msgds.msg_perm.gid = pw->pw_gid;
27862a65142Sjruoho
27962a65142Sjruoho if (msgctl(id, IPC_SET, &msgds) != 0)
28062a65142Sjruoho atf_tc_fail("root failed to change the GID of message queue");
28162a65142Sjruoho
28262a65142Sjruoho /*
283fbcca3eaSjruoho * Note: setting the qbytes to zero fails even as root.
28462a65142Sjruoho */
28562a65142Sjruoho msgds.msg_qbytes = 1;
28662a65142Sjruoho msgds.msg_perm.gid = getgid();
28762a65142Sjruoho
28862a65142Sjruoho if (msgctl(id, IPC_SET, &msgds) != 0)
28962a65142Sjruoho atf_tc_fail("root failed to change qbytes of message queue");
29062a65142Sjruoho
29162a65142Sjruoho ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
29262a65142Sjruoho }
29362a65142Sjruoho
ATF_TC_CLEANUP(msgctl_set,tc)29462a65142Sjruoho ATF_TC_CLEANUP(msgctl_set, tc)
29562a65142Sjruoho {
29662a65142Sjruoho clean();
29762a65142Sjruoho }
29862a65142Sjruoho
29962a65142Sjruoho ATF_TC_WITH_CLEANUP(msgctl_time);
ATF_TC_HEAD(msgctl_time,tc)30062a65142Sjruoho ATF_TC_HEAD(msgctl_time, tc)
30162a65142Sjruoho {
302fbcca3eaSjruoho atf_tc_set_md_var(tc, "descr", "Test that access times are updated");
30362a65142Sjruoho }
30462a65142Sjruoho
ATF_TC_BODY(msgctl_time,tc)30562a65142Sjruoho ATF_TC_BODY(msgctl_time, tc)
30662a65142Sjruoho {
30762a65142Sjruoho struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
30862a65142Sjruoho struct msqid_ds msgds;
30962a65142Sjruoho time_t t;
31062a65142Sjruoho int id;
31162a65142Sjruoho
31262a65142Sjruoho id = msgget(MSG_KEY, IPC_CREAT | 0600);
31362a65142Sjruoho ATF_REQUIRE(id != -1);
31462a65142Sjruoho
31562a65142Sjruoho t = time(NULL);
31662a65142Sjruoho
31762a65142Sjruoho (void)memset(&msgds, 0, sizeof(struct msqid_ds));
31862a65142Sjruoho (void)msgsnd(id, &msg, sizeof(struct msg), IPC_NOWAIT);
31962a65142Sjruoho (void)msgctl(id, IPC_STAT, &msgds);
32062a65142Sjruoho
321f161b30dSjoerg if (llabs(t - msgds.msg_stime) > 1)
32262a65142Sjruoho atf_tc_fail("time of last msgsnd(2) was not updated");
32362a65142Sjruoho
32462a65142Sjruoho if (msgds.msg_rtime != 0)
32562a65142Sjruoho atf_tc_fail("time of last msgrcv(2) was updated incorrectly");
32662a65142Sjruoho
32762a65142Sjruoho t = time(NULL);
32862a65142Sjruoho
32962a65142Sjruoho (void)memset(&msgds, 0, sizeof(struct msqid_ds));
33062a65142Sjruoho (void)msgrcv(id, &msg, sizeof(struct msg), MSG_MTYPE_1, IPC_NOWAIT);
33162a65142Sjruoho (void)msgctl(id, IPC_STAT, &msgds);
33262a65142Sjruoho
333f161b30dSjoerg if (llabs(t - msgds.msg_rtime) > 1)
33462a65142Sjruoho atf_tc_fail("time of last msgrcv(2) was not updated");
33562a65142Sjruoho
33662a65142Sjruoho /*
337fbcca3eaSjruoho * Note: this is non-zero even after the memset(3).
33862a65142Sjruoho */
33962a65142Sjruoho if (msgds.msg_stime == 0)
34062a65142Sjruoho atf_tc_fail("time of last msgsnd(2) was updated incorrectly");
34162a65142Sjruoho
34262a65142Sjruoho ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
34362a65142Sjruoho }
34462a65142Sjruoho
ATF_TC_CLEANUP(msgctl_time,tc)34562a65142Sjruoho ATF_TC_CLEANUP(msgctl_time, tc)
34662a65142Sjruoho {
34762a65142Sjruoho clean();
34862a65142Sjruoho }
34962a65142Sjruoho
3504ad1e3d9Skre static volatile int sig_caught;
3514ad1e3d9Skre
3524ad1e3d9Skre static void
sigsys_handler(int signum)3534ad1e3d9Skre sigsys_handler(int signum)
3544ad1e3d9Skre {
3554ad1e3d9Skre
3564ad1e3d9Skre sig_caught = signum;
3574ad1e3d9Skre }
3584ad1e3d9Skre
3594ad1e3d9Skre static int
no_kernel_sysvmsg(void)3604ad1e3d9Skre no_kernel_sysvmsg(void)
3614ad1e3d9Skre {
3624ad1e3d9Skre int id;
363*6618a9bfSkre void (*osig)(int);
3644ad1e3d9Skre
3654ad1e3d9Skre sig_caught = 0;
366*6618a9bfSkre osig = signal(SIGSYS, sigsys_handler);
3674ad1e3d9Skre id = msgget(MSG_KEY, IPC_CREAT | 0600);
3684ad1e3d9Skre if (sig_caught || id == -1)
3694ad1e3d9Skre return 1;
3704ad1e3d9Skre
3714ad1e3d9Skre (void)msgctl(id, IPC_RMID, 0);
372*6618a9bfSkre (void)signal(SIGSYS, osig);
3734ad1e3d9Skre
3744ad1e3d9Skre return 0;
3754ad1e3d9Skre }
3764ad1e3d9Skre
3774ad1e3d9Skre ATF_TC(msgctl_query);
ATF_TC_HEAD(msgctl_query,tc)3784ad1e3d9Skre ATF_TC_HEAD(msgctl_query, tc)
3794ad1e3d9Skre {
3804ad1e3d9Skre atf_tc_set_md_var(tc, "descr", "Skip msgctl_* tests - no SYSVMSG");
3814ad1e3d9Skre }
ATF_TC_BODY(msgctl_query,tc)3824ad1e3d9Skre ATF_TC_BODY(msgctl_query, tc)
3834ad1e3d9Skre {
3844ad1e3d9Skre atf_tc_skip("No SYSVMSG in kernel");
3854ad1e3d9Skre }
3864ad1e3d9Skre
ATF_TP_ADD_TCS(tp)38762a65142Sjruoho ATF_TP_ADD_TCS(tp)
38862a65142Sjruoho {
38962a65142Sjruoho
3904ad1e3d9Skre if (no_kernel_sysvmsg()) {
3914ad1e3d9Skre ATF_TP_ADD_TC(tp, msgctl_query);
3924ad1e3d9Skre } else {
39362a65142Sjruoho ATF_TP_ADD_TC(tp, msgctl_err);
39462a65142Sjruoho ATF_TP_ADD_TC(tp, msgctl_perm);
39562a65142Sjruoho ATF_TP_ADD_TC(tp, msgctl_pid);
39662a65142Sjruoho ATF_TP_ADD_TC(tp, msgctl_set);
39762a65142Sjruoho ATF_TP_ADD_TC(tp, msgctl_time);
3984ad1e3d9Skre }
39962a65142Sjruoho
40062a65142Sjruoho return atf_no_error();
40162a65142Sjruoho }
402