1314817Sngie/* $NetBSD: t_msgsnd.c,v 1.3 2017/01/13 20:44:45 christos Exp $ */ 2272343Sngie 3272343Sngie/*- 4272343Sngie * Copyright (c) 2011 The NetBSD Foundation, Inc. 5272343Sngie * All rights reserved. 6272343Sngie * 7272343Sngie * This code is derived from software contributed to The NetBSD Foundation 8272343Sngie * by Jukka Ruohonen. 9272343Sngie * 10272343Sngie * Redistribution and use in source and binary forms, with or without 11272343Sngie * modification, are permitted provided that the following conditions 12272343Sngie * are met: 13272343Sngie * 1. Redistributions of source code must retain the above copyright 14272343Sngie * notice, this list of conditions and the following disclaimer. 15272343Sngie * 2. Redistributions in binary form must reproduce the above copyright 16272343Sngie * notice, this list of conditions and the following disclaimer in the 17272343Sngie * documentation and/or other materials provided with the distribution. 18272343Sngie * 19272343Sngie * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20272343Sngie * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21272343Sngie * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22272343Sngie * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23272343Sngie * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24272343Sngie * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25272343Sngie * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26272343Sngie * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27272343Sngie * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28272343Sngie * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29272343Sngie * POSSIBILITY OF SUCH DAMAGE. 30272343Sngie */ 31272343Sngie#include <sys/cdefs.h> 32314817Sngie__RCSID("$NetBSD: t_msgsnd.c,v 1.3 2017/01/13 20:44:45 christos Exp $"); 33272343Sngie 34272343Sngie#include <sys/msg.h> 35272343Sngie#include <sys/stat.h> 36272343Sngie#include <sys/sysctl.h> 37272343Sngie#include <sys/wait.h> 38272343Sngie 39272343Sngie#include <atf-c.h> 40272343Sngie#include <errno.h> 41314817Sngie#include <limits.h> 42272343Sngie#include <pwd.h> 43272343Sngie#include <signal.h> 44272343Sngie#include <stdio.h> 45272343Sngie#include <stdlib.h> 46272343Sngie#include <string.h> 47272343Sngie#include <sysexits.h> 48272343Sngie#include <time.h> 49272343Sngie#include <unistd.h> 50272343Sngie 51272343Sngie#define MSG_KEY 1234 52272343Sngie#define MSG_MTYPE_1 0x41 53272343Sngie#define MSG_MTYPE_2 0x42 54272343Sngie#define MSG_MTYPE_3 0x43 55272343Sngie 56272343Sngiestruct msg { 57272343Sngie long mtype; 58272343Sngie char buf[3]; 59272343Sngie}; 60272343Sngie 61272343Sngiestatic void clean(void); 62272343Sngie 63272343Sngiestatic void 64272343Sngieclean(void) 65272343Sngie{ 66272343Sngie int id; 67272343Sngie 68272343Sngie if ((id = msgget(MSG_KEY, 0)) != -1) 69272343Sngie (void)msgctl(id, IPC_RMID, 0); 70272343Sngie} 71272343Sngie 72272343SngieATF_TC_WITH_CLEANUP(msgsnd_block); 73272343SngieATF_TC_HEAD(msgsnd_block, tc) 74272343Sngie{ 75272343Sngie atf_tc_set_md_var(tc, "descr", "Test that msgsnd(2) blocks"); 76272343Sngie atf_tc_set_md_var(tc, "timeout", "10"); 77272343Sngie} 78272343Sngie 79272343SngieATF_TC_BODY(msgsnd_block, tc) 80272343Sngie{ 81272343Sngie struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } }; 82272343Sngie int id, sta; 83272343Sngie pid_t pid; 84272343Sngie 85272343Sngie id = msgget(MSG_KEY, IPC_CREAT | 0600); 86272343Sngie ATF_REQUIRE(id != -1); 87272343Sngie 88272343Sngie pid = fork(); 89272343Sngie ATF_REQUIRE(pid >= 0); 90272343Sngie 91272343Sngie if (pid == 0) { 92272343Sngie 93272343Sngie /* 94272343Sngie * Enqueue messages until some limit (e.g. the maximum 95272343Sngie * number of messages in the queue or the maximum number 96272343Sngie * of bytes in the queue) is reached. After this the call 97272343Sngie * should block when the IPC_NOWAIT is not set. 98272343Sngie */ 99272343Sngie for (;;) { 100272343Sngie 101319094Sngie#ifdef __FreeBSD__ 102319094Sngie if (msgsnd(id, &msg, sizeof(msg.buf), 0) < 0) 103319094Sngie#else 104272343Sngie if (msgsnd(id, &msg, sizeof(struct msg), 0) < 0) 105319094Sngie#endif 106272343Sngie _exit(EXIT_FAILURE); 107272343Sngie } 108272343Sngie } 109272343Sngie 110272343Sngie (void)sleep(2); 111272343Sngie (void)kill(pid, SIGKILL); 112272343Sngie (void)wait(&sta); 113272343Sngie 114272343Sngie if (WIFEXITED(sta) != 0 || WIFSIGNALED(sta) == 0) 115272343Sngie atf_tc_fail("msgsnd(2) did not block"); 116272343Sngie 117272343Sngie ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); 118272343Sngie} 119272343Sngie 120272343SngieATF_TC_CLEANUP(msgsnd_block, tc) 121272343Sngie{ 122272343Sngie clean(); 123272343Sngie} 124272343Sngie 125272343SngieATF_TC_WITH_CLEANUP(msgsnd_count); 126272343SngieATF_TC_HEAD(msgsnd_count, tc) 127272343Sngie{ 128272343Sngie atf_tc_set_md_var(tc, "descr", 129272343Sngie "Test that msgsnd(2) increments the amount of " 130272343Sngie "message in the queue, as given by msgctl(2)"); 131272343Sngie atf_tc_set_md_var(tc, "timeout", "10"); 132272343Sngie} 133272343Sngie 134272343SngieATF_TC_BODY(msgsnd_count, tc) 135272343Sngie{ 136272343Sngie struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } }; 137272343Sngie struct msqid_ds ds; 138272343Sngie size_t i = 0; 139272343Sngie int id, rv; 140272343Sngie 141272343Sngie id = msgget(MSG_KEY, IPC_CREAT | 0600); 142272343Sngie ATF_REQUIRE(id != -1); 143272343Sngie 144272343Sngie for (;;) { 145272343Sngie 146272343Sngie errno = 0; 147319094Sngie#ifdef __FreeBSD__ 148319094Sngie rv = msgsnd(id, &msg, sizeof(msg.buf), IPC_NOWAIT); 149319094Sngie#else 150272343Sngie rv = msgsnd(id, &msg, sizeof(struct msg), IPC_NOWAIT); 151319094Sngie#endif 152272343Sngie 153272343Sngie if (rv == 0) { 154272343Sngie i++; 155272343Sngie continue; 156272343Sngie } 157272343Sngie 158272343Sngie if (rv == -1 && errno == EAGAIN) 159272343Sngie break; 160272343Sngie 161272343Sngie atf_tc_fail("failed to enqueue a message"); 162272343Sngie } 163272343Sngie 164272343Sngie (void)memset(&ds, 0, sizeof(struct msqid_ds)); 165272343Sngie (void)msgctl(id, IPC_STAT, &ds); 166272343Sngie 167272343Sngie if (ds.msg_qnum != i) 168272343Sngie atf_tc_fail("incorrect message count"); 169272343Sngie 170272343Sngie ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); 171272343Sngie} 172272343Sngie 173272343SngieATF_TC_CLEANUP(msgsnd_count, tc) 174272343Sngie{ 175272343Sngie clean(); 176272343Sngie} 177272343Sngie 178272343SngieATF_TC_WITH_CLEANUP(msgsnd_err); 179272343SngieATF_TC_HEAD(msgsnd_err, tc) 180272343Sngie{ 181272343Sngie atf_tc_set_md_var(tc, "descr", "Test errors from msgsnd(2)"); 182272343Sngie} 183272343Sngie 184272343SngieATF_TC_BODY(msgsnd_err, tc) 185272343Sngie{ 186272343Sngie struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } }; 187272343Sngie int id; 188272343Sngie 189272343Sngie id = msgget(MSG_KEY, IPC_CREAT | 0600); 190272343Sngie ATF_REQUIRE(id != -1); 191272343Sngie 192272343Sngie errno = 0; 193272343Sngie 194272343Sngie ATF_REQUIRE_ERRNO(EFAULT, msgsnd(id, (void *)-1, 195319094Sngie#ifdef __FreeBSD__ 196319094Sngie sizeof(msg.buf), IPC_NOWAIT) == -1); 197319094Sngie#else 198272343Sngie sizeof(struct msg), IPC_NOWAIT) == -1); 199319094Sngie#endif 200272343Sngie 201272343Sngie errno = 0; 202272343Sngie 203272343Sngie ATF_REQUIRE_ERRNO(EINVAL, msgsnd(-1, &msg, 204319094Sngie#ifdef __FreeBSD__ 205319094Sngie sizeof(msg.buf), IPC_NOWAIT) == -1); 206319094Sngie#else 207272343Sngie sizeof(struct msg), IPC_NOWAIT) == -1); 208319094Sngie#endif 209272343Sngie 210272343Sngie errno = 0; 211272343Sngie 212272343Sngie ATF_REQUIRE_ERRNO(EINVAL, msgsnd(-1, &msg, 213272343Sngie SSIZE_MAX, IPC_NOWAIT) == -1); 214272343Sngie 215272343Sngie errno = 0; 216272343Sngie msg.mtype = 0; 217272343Sngie 218272343Sngie ATF_REQUIRE_ERRNO(EINVAL, msgsnd(id, &msg, 219319094Sngie#ifdef __FreeBSD__ 220319094Sngie sizeof(msg.buf), IPC_NOWAIT) == -1); 221319094Sngie#else 222272343Sngie sizeof(struct msg), IPC_NOWAIT) == -1); 223319094Sngie#endif 224272343Sngie 225272343Sngie ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); 226272343Sngie} 227272343Sngie 228272343SngieATF_TC_CLEANUP(msgsnd_err, tc) 229272343Sngie{ 230272343Sngie clean(); 231272343Sngie} 232272343Sngie 233272343SngieATF_TC_WITH_CLEANUP(msgsnd_nonblock); 234272343SngieATF_TC_HEAD(msgsnd_nonblock, tc) 235272343Sngie{ 236272343Sngie atf_tc_set_md_var(tc, "descr", "Test msgsnd(2) with IPC_NOWAIT"); 237272343Sngie atf_tc_set_md_var(tc, "timeout", "10"); 238272343Sngie} 239272343Sngie 240272343SngieATF_TC_BODY(msgsnd_nonblock, tc) 241272343Sngie{ 242272343Sngie struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } }; 243272343Sngie int id, rv, sta; 244272343Sngie pid_t pid; 245272343Sngie 246272343Sngie id = msgget(MSG_KEY, IPC_CREAT | 0600); 247272343Sngie ATF_REQUIRE(id != -1); 248272343Sngie 249272343Sngie pid = fork(); 250272343Sngie ATF_REQUIRE(pid >= 0); 251272343Sngie 252272343Sngie if (pid == 0) { 253272343Sngie 254272343Sngie for (;;) { 255272343Sngie 256272343Sngie errno = 0; 257319094Sngie#ifdef __FreeBSD__ 258319094Sngie rv = msgsnd(id, &msg, sizeof(msg.buf), IPC_NOWAIT); 259319094Sngie#else 260272343Sngie rv = msgsnd(id, &msg, sizeof(struct msg), IPC_NOWAIT); 261319094Sngie#endif 262272343Sngie 263272343Sngie if (rv == -1 && errno == EAGAIN) 264272343Sngie _exit(EXIT_SUCCESS); 265272343Sngie } 266272343Sngie } 267272343Sngie 268272343Sngie (void)sleep(2); 269272343Sngie (void)kill(pid, SIGKILL); 270272343Sngie (void)wait(&sta); 271272343Sngie 272272343Sngie if (WIFEXITED(sta) == 0 || WIFSIGNALED(sta) != 0) 273272343Sngie atf_tc_fail("msgsnd(2) blocked with IPC_NOWAIT"); 274272343Sngie 275272343Sngie ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); 276272343Sngie} 277272343Sngie 278272343SngieATF_TC_CLEANUP(msgsnd_nonblock, tc) 279272343Sngie{ 280272343Sngie clean(); 281272343Sngie} 282272343Sngie 283272343SngieATF_TC_WITH_CLEANUP(msgsnd_perm); 284272343SngieATF_TC_HEAD(msgsnd_perm, tc) 285272343Sngie{ 286272343Sngie atf_tc_set_md_var(tc, "descr", "Test permissions with msgsnd(2)"); 287272343Sngie atf_tc_set_md_var(tc, "require.user", "root"); 288272343Sngie} 289272343Sngie 290272343SngieATF_TC_BODY(msgsnd_perm, tc) 291272343Sngie{ 292272343Sngie struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } }; 293272343Sngie struct passwd *pw; 294272343Sngie int id, sta; 295272343Sngie pid_t pid; 296272343Sngie uid_t uid; 297272343Sngie 298272343Sngie pw = getpwnam("nobody"); 299272343Sngie id = msgget(MSG_KEY, IPC_CREAT | 0600); 300272343Sngie 301272343Sngie ATF_REQUIRE(id != -1); 302272343Sngie ATF_REQUIRE(pw != NULL); 303272343Sngie 304272343Sngie uid = pw->pw_uid; 305272343Sngie ATF_REQUIRE(uid != 0); 306272343Sngie 307272343Sngie pid = fork(); 308272343Sngie ATF_REQUIRE(pid >= 0); 309272343Sngie 310272343Sngie if (pid == 0) { 311272343Sngie 312272343Sngie /* 313272343Sngie * Try to enqueue a message to the queue 314272343Sngie * created by root as RW for owner only. 315272343Sngie */ 316272343Sngie if (setuid(uid) != 0) 317272343Sngie _exit(EX_OSERR); 318272343Sngie 319272343Sngie id = msgget(MSG_KEY, 0); 320272343Sngie 321272343Sngie if (id == -1) 322272343Sngie _exit(EX_OSERR); 323272343Sngie 324272343Sngie errno = 0; 325272343Sngie 326319094Sngie#ifdef __FreeBSD__ 327319094Sngie if (msgsnd(id, &msg, sizeof(msg.buf), IPC_NOWAIT) == 0) 328319094Sngie#else 329272343Sngie if (msgsnd(id, &msg, sizeof(struct msg), IPC_NOWAIT) == 0) 330319094Sngie#endif 331272343Sngie _exit(EXIT_FAILURE); 332272343Sngie 333272343Sngie if (errno != EACCES) 334272343Sngie _exit(EXIT_FAILURE); 335272343Sngie 336272343Sngie _exit(EXIT_SUCCESS); 337272343Sngie } 338272343Sngie 339272343Sngie (void)wait(&sta); 340272343Sngie 341272343Sngie if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) { 342272343Sngie 343272343Sngie if (errno == EX_OSERR) 344272343Sngie atf_tc_fail("system call failed"); 345272343Sngie 346272343Sngie atf_tc_fail("UID %u enqueued message to root's queue", uid); 347272343Sngie } 348272343Sngie 349272343Sngie ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); 350272343Sngie} 351272343Sngie 352272343SngieATF_TC_CLEANUP(msgsnd_perm, tc) 353272343Sngie{ 354272343Sngie clean(); 355272343Sngie} 356272343Sngie 357272343SngieATF_TP_ADD_TCS(tp) 358272343Sngie{ 359272343Sngie 360272343Sngie ATF_TP_ADD_TC(tp, msgsnd_block); 361272343Sngie ATF_TP_ADD_TC(tp, msgsnd_count); 362272343Sngie ATF_TP_ADD_TC(tp, msgsnd_err); 363272343Sngie ATF_TP_ADD_TC(tp, msgsnd_nonblock); 364272343Sngie ATF_TP_ADD_TC(tp, msgsnd_perm); 365272343Sngie 366272343Sngie return atf_no_error(); 367272343Sngie} 368