1*57718be8SEnji Cooper /* $NetBSD: t_msgctl.c,v 1.4 2014/02/27 00:59:50 joerg Exp $ */ 2*57718be8SEnji Cooper 3*57718be8SEnji Cooper /*- 4*57718be8SEnji Cooper * Copyright (c) 2011 The NetBSD Foundation, Inc. 5*57718be8SEnji Cooper * All rights reserved. 6*57718be8SEnji Cooper * 7*57718be8SEnji Cooper * This code is derived from software contributed to The NetBSD Foundation 8*57718be8SEnji Cooper * by Jukka Ruohonen. 9*57718be8SEnji Cooper * 10*57718be8SEnji Cooper * Redistribution and use in source and binary forms, with or without 11*57718be8SEnji Cooper * modification, are permitted provided that the following conditions 12*57718be8SEnji Cooper * are met: 13*57718be8SEnji Cooper * 1. Redistributions of source code must retain the above copyright 14*57718be8SEnji Cooper * notice, this list of conditions and the following disclaimer. 15*57718be8SEnji Cooper * 2. Redistributions in binary form must reproduce the above copyright 16*57718be8SEnji Cooper * notice, this list of conditions and the following disclaimer in the 17*57718be8SEnji Cooper * documentation and/or other materials provided with the distribution. 18*57718be8SEnji Cooper * 19*57718be8SEnji Cooper * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20*57718be8SEnji Cooper * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21*57718be8SEnji Cooper * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22*57718be8SEnji Cooper * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23*57718be8SEnji Cooper * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24*57718be8SEnji Cooper * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25*57718be8SEnji Cooper * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26*57718be8SEnji Cooper * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27*57718be8SEnji Cooper * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28*57718be8SEnji Cooper * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29*57718be8SEnji Cooper * POSSIBILITY OF SUCH DAMAGE. 30*57718be8SEnji Cooper */ 31*57718be8SEnji Cooper #include <sys/cdefs.h> 32*57718be8SEnji Cooper __RCSID("$NetBSD: t_msgctl.c,v 1.4 2014/02/27 00:59:50 joerg Exp $"); 33*57718be8SEnji Cooper 34*57718be8SEnji Cooper #include <sys/msg.h> 35*57718be8SEnji Cooper #include <sys/stat.h> 36*57718be8SEnji Cooper #include <sys/sysctl.h> 37*57718be8SEnji Cooper #include <sys/wait.h> 38*57718be8SEnji Cooper 39*57718be8SEnji Cooper #include <atf-c.h> 40*57718be8SEnji Cooper #include <errno.h> 41*57718be8SEnji Cooper #include <pwd.h> 42*57718be8SEnji Cooper #include <stdio.h> 43*57718be8SEnji Cooper #include <stdlib.h> 44*57718be8SEnji Cooper #include <string.h> 45*57718be8SEnji Cooper #include <sysexits.h> 46*57718be8SEnji Cooper #include <time.h> 47*57718be8SEnji Cooper #include <unistd.h> 48*57718be8SEnji Cooper 49*57718be8SEnji Cooper #define MSG_KEY 12345689 50*57718be8SEnji Cooper #define MSG_MTYPE_1 0x41 51*57718be8SEnji Cooper 52*57718be8SEnji Cooper struct msg { 53*57718be8SEnji Cooper long mtype; 54*57718be8SEnji Cooper char buf[3]; 55*57718be8SEnji Cooper }; 56*57718be8SEnji Cooper 57*57718be8SEnji Cooper static void clean(void); 58*57718be8SEnji Cooper 59*57718be8SEnji Cooper static void 60*57718be8SEnji Cooper clean(void) 61*57718be8SEnji Cooper { 62*57718be8SEnji Cooper int id; 63*57718be8SEnji Cooper 64*57718be8SEnji Cooper if ((id = msgget(MSG_KEY, 0)) != -1) 65*57718be8SEnji Cooper (void)msgctl(id, IPC_RMID, 0); 66*57718be8SEnji Cooper } 67*57718be8SEnji Cooper 68*57718be8SEnji Cooper ATF_TC_WITH_CLEANUP(msgctl_err); 69*57718be8SEnji Cooper ATF_TC_HEAD(msgctl_err, tc) 70*57718be8SEnji Cooper { 71*57718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Test errors from msgctl(2)"); 72*57718be8SEnji Cooper } 73*57718be8SEnji Cooper 74*57718be8SEnji Cooper ATF_TC_BODY(msgctl_err, tc) 75*57718be8SEnji Cooper { 76*57718be8SEnji Cooper const int cmd[] = { IPC_STAT, IPC_SET, IPC_RMID }; 77*57718be8SEnji Cooper struct msqid_ds msgds; 78*57718be8SEnji Cooper size_t i; 79*57718be8SEnji Cooper int id; 80*57718be8SEnji Cooper 81*57718be8SEnji Cooper (void)memset(&msgds, 0, sizeof(struct msqid_ds)); 82*57718be8SEnji Cooper 83*57718be8SEnji Cooper id = msgget(MSG_KEY, IPC_CREAT | 0600); 84*57718be8SEnji Cooper ATF_REQUIRE(id != -1); 85*57718be8SEnji Cooper 86*57718be8SEnji Cooper errno = 0; 87*57718be8SEnji Cooper ATF_REQUIRE_ERRNO(EINVAL, msgctl(id, INT_MAX, &msgds) == -1); 88*57718be8SEnji Cooper 89*57718be8SEnji Cooper errno = 0; 90*57718be8SEnji Cooper ATF_REQUIRE_ERRNO(EFAULT, msgctl(id, IPC_STAT, (void *)-1) == -1); 91*57718be8SEnji Cooper 92*57718be8SEnji Cooper for (i = 0; i < __arraycount(cmd); i++) { 93*57718be8SEnji Cooper errno = 0; 94*57718be8SEnji Cooper ATF_REQUIRE_ERRNO(EINVAL, msgctl(-1, cmd[i], &msgds) == -1); 95*57718be8SEnji Cooper } 96*57718be8SEnji Cooper 97*57718be8SEnji Cooper ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); 98*57718be8SEnji Cooper } 99*57718be8SEnji Cooper 100*57718be8SEnji Cooper ATF_TC_CLEANUP(msgctl_err, tc) 101*57718be8SEnji Cooper { 102*57718be8SEnji Cooper clean(); 103*57718be8SEnji Cooper } 104*57718be8SEnji Cooper 105*57718be8SEnji Cooper ATF_TC_WITH_CLEANUP(msgctl_perm); 106*57718be8SEnji Cooper ATF_TC_HEAD(msgctl_perm, tc) 107*57718be8SEnji Cooper { 108*57718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Test permissions with msgctl(2)"); 109*57718be8SEnji Cooper atf_tc_set_md_var(tc, "require.user", "root"); 110*57718be8SEnji Cooper } 111*57718be8SEnji Cooper 112*57718be8SEnji Cooper ATF_TC_BODY(msgctl_perm, tc) 113*57718be8SEnji Cooper { 114*57718be8SEnji Cooper struct msqid_ds msgds; 115*57718be8SEnji Cooper struct passwd *pw; 116*57718be8SEnji Cooper pid_t pid; 117*57718be8SEnji Cooper int sta; 118*57718be8SEnji Cooper int id; 119*57718be8SEnji Cooper 120*57718be8SEnji Cooper (void)memset(&msgds, 0, sizeof(struct msqid_ds)); 121*57718be8SEnji Cooper 122*57718be8SEnji Cooper pw = getpwnam("nobody"); 123*57718be8SEnji Cooper id = msgget(MSG_KEY, IPC_CREAT | 0600); 124*57718be8SEnji Cooper 125*57718be8SEnji Cooper ATF_REQUIRE(id != -1); 126*57718be8SEnji Cooper ATF_REQUIRE(pw != NULL); 127*57718be8SEnji Cooper ATF_REQUIRE(msgctl(id, IPC_STAT, &msgds) == 0); 128*57718be8SEnji Cooper 129*57718be8SEnji Cooper pid = fork(); 130*57718be8SEnji Cooper ATF_REQUIRE(pid >= 0); 131*57718be8SEnji Cooper 132*57718be8SEnji Cooper if (pid == 0) { 133*57718be8SEnji Cooper 134*57718be8SEnji Cooper if (setuid(pw->pw_uid) != 0) 135*57718be8SEnji Cooper _exit(EX_OSERR); 136*57718be8SEnji Cooper 137*57718be8SEnji Cooper msgds.msg_perm.uid = getuid(); 138*57718be8SEnji Cooper msgds.msg_perm.gid = getgid(); 139*57718be8SEnji Cooper 140*57718be8SEnji Cooper errno = 0; 141*57718be8SEnji Cooper 142*57718be8SEnji Cooper if (msgctl(id, IPC_SET, &msgds) == 0) 143*57718be8SEnji Cooper _exit(EXIT_FAILURE); 144*57718be8SEnji Cooper 145*57718be8SEnji Cooper if (errno != EPERM) 146*57718be8SEnji Cooper _exit(EXIT_FAILURE); 147*57718be8SEnji Cooper 148*57718be8SEnji Cooper (void)memset(&msgds, 0, sizeof(struct msqid_ds)); 149*57718be8SEnji Cooper 150*57718be8SEnji Cooper if (msgctl(id, IPC_STAT, &msgds) != 0) 151*57718be8SEnji Cooper _exit(EX_OSERR); 152*57718be8SEnji Cooper 153*57718be8SEnji Cooper msgds.msg_qbytes = 1; 154*57718be8SEnji Cooper 155*57718be8SEnji Cooper if (msgctl(id, IPC_SET, &msgds) == 0) 156*57718be8SEnji Cooper _exit(EXIT_FAILURE); 157*57718be8SEnji Cooper 158*57718be8SEnji Cooper if (errno != EPERM) 159*57718be8SEnji Cooper _exit(EXIT_FAILURE); 160*57718be8SEnji Cooper 161*57718be8SEnji Cooper _exit(EXIT_SUCCESS); 162*57718be8SEnji Cooper } 163*57718be8SEnji Cooper 164*57718be8SEnji Cooper (void)wait(&sta); 165*57718be8SEnji Cooper 166*57718be8SEnji Cooper if (WIFEXITED(sta) == 0) { 167*57718be8SEnji Cooper 168*57718be8SEnji Cooper if (WEXITSTATUS(sta) == EX_OSERR) 169*57718be8SEnji Cooper atf_tc_fail("system call failed"); 170*57718be8SEnji Cooper 171*57718be8SEnji Cooper if (WEXITSTATUS(sta) == EXIT_FAILURE) 172*57718be8SEnji Cooper atf_tc_fail("UID %u manipulated root's " 173*57718be8SEnji Cooper "message queue", pw->pw_uid); 174*57718be8SEnji Cooper } 175*57718be8SEnji Cooper 176*57718be8SEnji Cooper ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); 177*57718be8SEnji Cooper } 178*57718be8SEnji Cooper 179*57718be8SEnji Cooper ATF_TC_CLEANUP(msgctl_perm, tc) 180*57718be8SEnji Cooper { 181*57718be8SEnji Cooper clean(); 182*57718be8SEnji Cooper } 183*57718be8SEnji Cooper 184*57718be8SEnji Cooper ATF_TC_WITH_CLEANUP(msgctl_pid); 185*57718be8SEnji Cooper ATF_TC_HEAD(msgctl_pid, tc) 186*57718be8SEnji Cooper { 187*57718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Test that PIDs are updated"); 188*57718be8SEnji Cooper } 189*57718be8SEnji Cooper 190*57718be8SEnji Cooper ATF_TC_BODY(msgctl_pid, tc) 191*57718be8SEnji Cooper { 192*57718be8SEnji Cooper struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } }; 193*57718be8SEnji Cooper struct msqid_ds msgds; 194*57718be8SEnji Cooper int id, sta; 195*57718be8SEnji Cooper pid_t pid; 196*57718be8SEnji Cooper 197*57718be8SEnji Cooper id = msgget(MSG_KEY, IPC_CREAT | 0600); 198*57718be8SEnji Cooper ATF_REQUIRE(id != -1); 199*57718be8SEnji Cooper 200*57718be8SEnji Cooper pid = fork(); 201*57718be8SEnji Cooper ATF_REQUIRE(pid >= 0); 202*57718be8SEnji Cooper 203*57718be8SEnji Cooper if (pid == 0) { 204*57718be8SEnji Cooper 205*57718be8SEnji Cooper (void)msgsnd(id, &msg, sizeof(struct msg), IPC_NOWAIT); 206*57718be8SEnji Cooper 207*57718be8SEnji Cooper _exit(EXIT_SUCCESS); 208*57718be8SEnji Cooper } 209*57718be8SEnji Cooper 210*57718be8SEnji Cooper (void)sleep(1); 211*57718be8SEnji Cooper (void)wait(&sta); 212*57718be8SEnji Cooper (void)memset(&msgds, 0, sizeof(struct msqid_ds)); 213*57718be8SEnji Cooper 214*57718be8SEnji Cooper ATF_REQUIRE(msgctl(id, IPC_STAT, &msgds) == 0); 215*57718be8SEnji Cooper 216*57718be8SEnji Cooper if (pid != msgds.msg_lspid) 217*57718be8SEnji Cooper atf_tc_fail("the PID of last msgsnd(2) was not updated"); 218*57718be8SEnji Cooper 219*57718be8SEnji Cooper pid = fork(); 220*57718be8SEnji Cooper ATF_REQUIRE(pid >= 0); 221*57718be8SEnji Cooper 222*57718be8SEnji Cooper if (pid == 0) { 223*57718be8SEnji Cooper 224*57718be8SEnji Cooper (void)msgrcv(id, &msg, 225*57718be8SEnji Cooper sizeof(struct msg), MSG_MTYPE_1, IPC_NOWAIT); 226*57718be8SEnji Cooper 227*57718be8SEnji Cooper _exit(EXIT_SUCCESS); 228*57718be8SEnji Cooper } 229*57718be8SEnji Cooper 230*57718be8SEnji Cooper (void)sleep(1); 231*57718be8SEnji Cooper (void)wait(&sta); 232*57718be8SEnji Cooper (void)memset(&msgds, 0, sizeof(struct msqid_ds)); 233*57718be8SEnji Cooper 234*57718be8SEnji Cooper ATF_REQUIRE(msgctl(id, IPC_STAT, &msgds) == 0); 235*57718be8SEnji Cooper 236*57718be8SEnji Cooper if (pid != msgds.msg_lrpid) 237*57718be8SEnji Cooper atf_tc_fail("the PID of last msgrcv(2) was not updated"); 238*57718be8SEnji Cooper 239*57718be8SEnji Cooper ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); 240*57718be8SEnji Cooper } 241*57718be8SEnji Cooper 242*57718be8SEnji Cooper ATF_TC_CLEANUP(msgctl_pid, tc) 243*57718be8SEnji Cooper { 244*57718be8SEnji Cooper clean(); 245*57718be8SEnji Cooper } 246*57718be8SEnji Cooper 247*57718be8SEnji Cooper ATF_TC_WITH_CLEANUP(msgctl_set); 248*57718be8SEnji Cooper ATF_TC_HEAD(msgctl_set, tc) 249*57718be8SEnji Cooper { 250*57718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Test msgctl(2) with IPC_SET"); 251*57718be8SEnji Cooper atf_tc_set_md_var(tc, "require.user", "root"); 252*57718be8SEnji Cooper } 253*57718be8SEnji Cooper 254*57718be8SEnji Cooper ATF_TC_BODY(msgctl_set, tc) 255*57718be8SEnji Cooper { 256*57718be8SEnji Cooper struct msqid_ds msgds; 257*57718be8SEnji Cooper struct passwd *pw; 258*57718be8SEnji Cooper int id; 259*57718be8SEnji Cooper 260*57718be8SEnji Cooper (void)memset(&msgds, 0, sizeof(struct msqid_ds)); 261*57718be8SEnji Cooper 262*57718be8SEnji Cooper pw = getpwnam("nobody"); 263*57718be8SEnji Cooper id = msgget(MSG_KEY, IPC_CREAT | 0600); 264*57718be8SEnji Cooper 265*57718be8SEnji Cooper ATF_REQUIRE(id != -1); 266*57718be8SEnji Cooper ATF_REQUIRE(pw != NULL); 267*57718be8SEnji Cooper ATF_REQUIRE(msgctl(id, IPC_STAT, &msgds) == 0); 268*57718be8SEnji Cooper 269*57718be8SEnji Cooper msgds.msg_perm.uid = pw->pw_uid; 270*57718be8SEnji Cooper 271*57718be8SEnji Cooper if (msgctl(id, IPC_SET, &msgds) != 0) 272*57718be8SEnji Cooper atf_tc_fail("root failed to change the UID of message queue"); 273*57718be8SEnji Cooper 274*57718be8SEnji Cooper msgds.msg_perm.uid = getuid(); 275*57718be8SEnji Cooper msgds.msg_perm.gid = pw->pw_gid; 276*57718be8SEnji Cooper 277*57718be8SEnji Cooper if (msgctl(id, IPC_SET, &msgds) != 0) 278*57718be8SEnji Cooper atf_tc_fail("root failed to change the GID of message queue"); 279*57718be8SEnji Cooper 280*57718be8SEnji Cooper /* 281*57718be8SEnji Cooper * Note: setting the qbytes to zero fails even as root. 282*57718be8SEnji Cooper */ 283*57718be8SEnji Cooper msgds.msg_qbytes = 1; 284*57718be8SEnji Cooper msgds.msg_perm.gid = getgid(); 285*57718be8SEnji Cooper 286*57718be8SEnji Cooper if (msgctl(id, IPC_SET, &msgds) != 0) 287*57718be8SEnji Cooper atf_tc_fail("root failed to change qbytes of message queue"); 288*57718be8SEnji Cooper 289*57718be8SEnji Cooper ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); 290*57718be8SEnji Cooper } 291*57718be8SEnji Cooper 292*57718be8SEnji Cooper ATF_TC_CLEANUP(msgctl_set, tc) 293*57718be8SEnji Cooper { 294*57718be8SEnji Cooper clean(); 295*57718be8SEnji Cooper } 296*57718be8SEnji Cooper 297*57718be8SEnji Cooper ATF_TC_WITH_CLEANUP(msgctl_time); 298*57718be8SEnji Cooper ATF_TC_HEAD(msgctl_time, tc) 299*57718be8SEnji Cooper { 300*57718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Test that access times are updated"); 301*57718be8SEnji Cooper } 302*57718be8SEnji Cooper 303*57718be8SEnji Cooper ATF_TC_BODY(msgctl_time, tc) 304*57718be8SEnji Cooper { 305*57718be8SEnji Cooper struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } }; 306*57718be8SEnji Cooper struct msqid_ds msgds; 307*57718be8SEnji Cooper time_t t; 308*57718be8SEnji Cooper int id; 309*57718be8SEnji Cooper 310*57718be8SEnji Cooper id = msgget(MSG_KEY, IPC_CREAT | 0600); 311*57718be8SEnji Cooper ATF_REQUIRE(id != -1); 312*57718be8SEnji Cooper 313*57718be8SEnji Cooper t = time(NULL); 314*57718be8SEnji Cooper 315*57718be8SEnji Cooper (void)memset(&msgds, 0, sizeof(struct msqid_ds)); 316*57718be8SEnji Cooper (void)msgsnd(id, &msg, sizeof(struct msg), IPC_NOWAIT); 317*57718be8SEnji Cooper (void)msgctl(id, IPC_STAT, &msgds); 318*57718be8SEnji Cooper 319*57718be8SEnji Cooper if (llabs(t - msgds.msg_stime) > 1) 320*57718be8SEnji Cooper atf_tc_fail("time of last msgsnd(2) was not updated"); 321*57718be8SEnji Cooper 322*57718be8SEnji Cooper if (msgds.msg_rtime != 0) 323*57718be8SEnji Cooper atf_tc_fail("time of last msgrcv(2) was updated incorrectly"); 324*57718be8SEnji Cooper 325*57718be8SEnji Cooper t = time(NULL); 326*57718be8SEnji Cooper 327*57718be8SEnji Cooper (void)memset(&msgds, 0, sizeof(struct msqid_ds)); 328*57718be8SEnji Cooper (void)msgrcv(id, &msg, sizeof(struct msg), MSG_MTYPE_1, IPC_NOWAIT); 329*57718be8SEnji Cooper (void)msgctl(id, IPC_STAT, &msgds); 330*57718be8SEnji Cooper 331*57718be8SEnji Cooper if (llabs(t - msgds.msg_rtime) > 1) 332*57718be8SEnji Cooper atf_tc_fail("time of last msgrcv(2) was not updated"); 333*57718be8SEnji Cooper 334*57718be8SEnji Cooper /* 335*57718be8SEnji Cooper * Note: this is non-zero even after the memset(3). 336*57718be8SEnji Cooper */ 337*57718be8SEnji Cooper if (msgds.msg_stime == 0) 338*57718be8SEnji Cooper atf_tc_fail("time of last msgsnd(2) was updated incorrectly"); 339*57718be8SEnji Cooper 340*57718be8SEnji Cooper ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); 341*57718be8SEnji Cooper } 342*57718be8SEnji Cooper 343*57718be8SEnji Cooper ATF_TC_CLEANUP(msgctl_time, tc) 344*57718be8SEnji Cooper { 345*57718be8SEnji Cooper clean(); 346*57718be8SEnji Cooper } 347*57718be8SEnji Cooper 348*57718be8SEnji Cooper ATF_TP_ADD_TCS(tp) 349*57718be8SEnji Cooper { 350*57718be8SEnji Cooper 351*57718be8SEnji Cooper ATF_TP_ADD_TC(tp, msgctl_err); 352*57718be8SEnji Cooper ATF_TP_ADD_TC(tp, msgctl_perm); 353*57718be8SEnji Cooper ATF_TP_ADD_TC(tp, msgctl_pid); 354*57718be8SEnji Cooper ATF_TP_ADD_TC(tp, msgctl_set); 355*57718be8SEnji Cooper ATF_TP_ADD_TC(tp, msgctl_time); 356*57718be8SEnji Cooper 357*57718be8SEnji Cooper return atf_no_error(); 358*57718be8SEnji Cooper } 359