1 /* $OpenBSD: t_msgrcv.c,v 1.2 2021/12/13 16:56:48 deraadt Exp $ */ 2 /* $NetBSD: t_msgrcv.c,v 1.5 2017/10/08 08:31:05 kre Exp $ */ 3 4 /*- 5 * Copyright (c) 2011 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Jukka Ruohonen. 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 #include "macros.h" 34 35 #include <sys/msg.h> 36 #include <sys/stat.h> 37 #include <sys/sysctl.h> 38 #include <sys/wait.h> 39 40 #include "atf-c.h" 41 #include <errno.h> 42 #include <limits.h> 43 #include <pwd.h> 44 #include <signal.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <sysexits.h> 49 #include <time.h> 50 #include <unistd.h> 51 52 #define MSG_KEY 1234 53 #define MSG_MTYPE_1 0x41 54 #define MSG_MTYPE_2 0x42 55 #define MSG_MTYPE_3 0x43 56 #define MSG_LEN 3 57 58 struct msg { 59 long mtype; 60 char buf[MSG_LEN]; 61 }; 62 63 static void clean(void); 64 65 static void 66 clean(void) 67 { 68 int id; 69 70 if ((id = msgget(MSG_KEY, 0)) != -1) 71 (void)msgctl(id, IPC_RMID, 0); 72 } 73 74 ATF_TC_WITH_CLEANUP(msgrcv_basic); 75 ATF_TC_HEAD(msgrcv_basic, tc) 76 { 77 atf_tc_set_md_var(tc, "descr", "A basic test of msgrcv(2)"); 78 } 79 80 ATF_TC_BODY(msgrcv_basic, tc) 81 { 82 struct msg msg1 = { MSG_MTYPE_1, { 'a', 'b', 'c' } }; 83 struct msg msg2 = { MSG_MTYPE_1, { 'x', 'y', 'z' } }; 84 int id; 85 86 id = msgget(MSG_KEY, IPC_CREAT | 0600); 87 ATF_REQUIRE(id != -1); 88 89 (void)msgsnd(id, &msg1, MSG_LEN, IPC_NOWAIT); 90 (void)msgrcv(id, &msg2, MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT); 91 92 ATF_CHECK(msg1.buf[0] == msg2.buf[0]); 93 ATF_CHECK(msg1.buf[1] == msg2.buf[1]); 94 ATF_CHECK(msg1.buf[2] == msg2.buf[2]); 95 96 ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); 97 } 98 99 ATF_TC_CLEANUP(msgrcv_basic, tc) 100 { 101 clean(); 102 } 103 104 ATF_TC_WITH_CLEANUP(msgrcv_block); 105 ATF_TC_HEAD(msgrcv_block, tc) 106 { 107 atf_tc_set_md_var(tc, "descr", "Test that msgrcv(2) blocks"); 108 } 109 110 ATF_TC_BODY(msgrcv_block, tc) 111 { 112 struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } }; 113 int id, sta; 114 pid_t pid; 115 116 id = msgget(MSG_KEY, IPC_CREAT | 0600); 117 ATF_REQUIRE(id != -1); 118 119 pid = fork(); 120 ATF_REQUIRE(pid >= 0); 121 122 if (pid == 0) { 123 124 if (msgrcv(id, &msg, MSG_LEN, MSG_MTYPE_1, 0) < 0) 125 _exit(EXIT_FAILURE); 126 127 _exit(EXIT_SUCCESS); 128 } 129 130 /* 131 * Below msgsnd(2) should unblock the child, 132 * and hence kill(2) should fail with ESRCH. 133 */ 134 (void)sleep(1); 135 (void)msgsnd(id, &msg, MSG_LEN, IPC_NOWAIT); 136 (void)sleep(1); 137 (void)kill(pid, SIGKILL); 138 (void)wait(&sta); 139 140 if (WIFEXITED(sta) == 0 || WIFSIGNALED(sta) != 0) 141 atf_tc_fail("msgrcv(2) did not block"); 142 143 ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); 144 } 145 146 ATF_TC_CLEANUP(msgrcv_block, tc) 147 { 148 clean(); 149 } 150 151 ATF_TC_WITH_CLEANUP(msgrcv_err); 152 ATF_TC_HEAD(msgrcv_err, tc) 153 { 154 atf_tc_set_md_var(tc, "descr", "Test errors from msgrcv(2)"); 155 } 156 157 ATF_TC_BODY(msgrcv_err, tc) 158 { 159 struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } }; 160 int id, r = 0; 161 162 id = msgget(MSG_KEY, IPC_CREAT | 0600); 163 ATF_REQUIRE(id != -1); 164 165 errno = 0; 166 167 ATF_REQUIRE_ERRNO(ENOMSG, msgrcv(id, &msg, 168 MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT) == -1); 169 170 ATF_REQUIRE(msgsnd(id, &msg, MSG_LEN, IPC_NOWAIT) == 0); 171 172 errno = 0; 173 174 ATF_REQUIRE_ERRNO(EFAULT, msgrcv(id, (void *)-1, 175 MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT) == -1); 176 177 errno = 0; 178 179 ATF_REQUIRE_ERRNO(EINVAL, msgrcv(-1, &msg, 180 MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT) == -1); 181 182 errno = 0; 183 184 ATF_REQUIRE_ERRNO(EINVAL, msgrcv(-1, &msg, 185 SSIZE_MAX, MSG_MTYPE_1, IPC_NOWAIT) == -1); 186 187 ATF_REQUIRE(msgsnd(id, &msg, MSG_LEN, IPC_NOWAIT) == 0); 188 189 errno = 0; 190 191 ATF_REQUIRE_ERRNO(E2BIG, msgrcv(id, &r, 192 MSG_LEN - 1, MSG_MTYPE_1, IPC_NOWAIT) == -1); 193 194 ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); 195 } 196 197 ATF_TC_CLEANUP(msgrcv_err, tc) 198 { 199 clean(); 200 } 201 202 203 ATF_TC_WITH_CLEANUP(msgrcv_mtype); 204 ATF_TC_HEAD(msgrcv_mtype, tc) 205 { 206 atf_tc_set_md_var(tc, "descr", "Test message types with msgrcv(2)"); 207 } 208 209 ATF_TC_BODY(msgrcv_mtype, tc) 210 { 211 struct msg msg1 = { MSG_MTYPE_1, { 'a', 'b', 'c' } }; 212 struct msg msg2 = { MSG_MTYPE_3, { 'x', 'y', 'z' } }; 213 int id; 214 215 id = msgget(MSG_KEY, IPC_CREAT | 0600); 216 ATF_REQUIRE(id != -1); 217 218 (void)msgsnd(id, &msg1, MSG_LEN, IPC_NOWAIT); 219 (void)msgrcv(id, &msg2, MSG_LEN, MSG_MTYPE_2, IPC_NOWAIT); 220 221 ATF_CHECK(msg1.buf[0] != msg2.buf[0]); /* Different mtype. */ 222 ATF_CHECK(msg1.buf[1] != msg2.buf[1]); 223 ATF_CHECK(msg1.buf[2] != msg2.buf[2]); 224 225 (void)msgrcv(id, &msg2, MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT); 226 227 ATF_CHECK(msg1.buf[0] == msg2.buf[0]); /* Same mtype. */ 228 ATF_CHECK(msg1.buf[1] == msg2.buf[1]); 229 ATF_CHECK(msg1.buf[2] == msg2.buf[2]); 230 231 ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); 232 } 233 234 ATF_TC_CLEANUP(msgrcv_mtype, tc) 235 { 236 clean(); 237 } 238 239 ATF_TC_WITH_CLEANUP(msgrcv_nonblock); 240 ATF_TC_HEAD(msgrcv_nonblock, tc) 241 { 242 atf_tc_set_md_var(tc, "descr", "Test msgrcv(2) with IPC_NOWAIT"); 243 atf_tc_set_md_var(tc, "timeout", "10"); 244 } 245 246 ATF_TC_BODY(msgrcv_nonblock, tc) 247 { 248 struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } }; 249 const ssize_t n = 10; 250 int id, sta; 251 ssize_t i; 252 pid_t pid; 253 254 id = msgget(MSG_KEY, IPC_CREAT | 0600); 255 ATF_REQUIRE(id != -1); 256 257 for (i = 0; i < n; i++) { 258 259 ATF_REQUIRE(msgsnd(id, &msg, MSG_LEN, IPC_NOWAIT) == 0); 260 } 261 262 pid = fork(); 263 ATF_REQUIRE(pid >= 0); 264 265 if (pid == 0) { 266 267 while (i != 0) { 268 269 if (msgrcv(id, &msg, MSG_LEN, MSG_MTYPE_1, 270 IPC_NOWAIT) == -1) 271 _exit(EXIT_FAILURE); 272 273 i--; 274 } 275 276 _exit(EXIT_SUCCESS); 277 } 278 279 (void)sleep(2); 280 (void)kill(pid, SIGKILL); 281 (void)wait(&sta); 282 283 if (WIFSIGNALED(sta) != 0 || WTERMSIG(sta) == SIGKILL) 284 atf_tc_fail("msgrcv(2) blocked with IPC_NOWAIT"); 285 286 if (WIFEXITED(sta) == 0 && WEXITSTATUS(sta) != EXIT_SUCCESS) 287 atf_tc_fail("msgrcv(2) failed"); 288 289 ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); 290 } 291 292 ATF_TC_CLEANUP(msgrcv_nonblock, tc) 293 { 294 clean(); 295 } 296 297 ATF_TC_WITH_CLEANUP(msgrcv_truncate); 298 ATF_TC_HEAD(msgrcv_truncate, tc) 299 { 300 atf_tc_set_md_var(tc, "descr", "Test msgrcv(2) with MSG_NOERROR"); 301 } 302 303 ATF_TC_BODY(msgrcv_truncate, tc) 304 { 305 #define MSG_SMALLLEN 2 306 struct msgsmall { 307 long mtype; 308 char buf[MSG_SMALLLEN]; 309 }; 310 311 struct msg msg1 = { MSG_MTYPE_1, { 'a', 'b', 'c' } }; 312 struct msgsmall msg2 = { MSG_MTYPE_1, { 'x', 'y' } }; 313 int id; 314 315 id = msgget(MSG_KEY, IPC_CREAT | 0600); 316 ATF_REQUIRE(id != -1); 317 318 (void)msgsnd(id, &msg1, MSG_LEN, IPC_NOWAIT); 319 (void)msgrcv(id, &msg2, MSG_SMALLLEN, 320 MSG_MTYPE_1, IPC_NOWAIT | MSG_NOERROR); 321 322 ATF_CHECK(msg1.buf[0] == msg2.buf[0]); 323 ATF_CHECK(msg1.buf[1] == msg2.buf[1]); 324 325 ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); 326 } 327 328 ATF_TC_CLEANUP(msgrcv_truncate, tc) 329 { 330 clean(); 331 } 332 333 static volatile int sig_caught; 334 335 static void 336 sigsys_handler(int signum) 337 { 338 339 sig_caught = signum; 340 } 341 342 static int 343 no_kernel_sysvmsg(void) 344 { 345 int id; 346 void (*osig)(int); 347 348 sig_caught = 0; 349 osig = signal(SIGSYS, sigsys_handler); 350 id = msgget(MSG_KEY, IPC_CREAT | 0600); 351 if (sig_caught || id == -1) 352 return 1; 353 354 (void)msgctl(id, IPC_RMID, 0); 355 (void)signal(SIGSYS, osig); 356 357 return 0; 358 } 359 360 ATF_TC(msgrcv_query); 361 ATF_TC_HEAD(msgrcv_query, tc) 362 { 363 atf_tc_set_md_var(tc, "descr", "Skip msgrcv_* tests - no SYSVMSG"); 364 } 365 ATF_TC_BODY(msgrcv_query, tc) 366 { 367 atf_tc_skip("No SYSVMSG in kernel"); 368 } 369 370 ATF_TP_ADD_TCS(tp) 371 { 372 373 if (no_kernel_sysvmsg()) { 374 ATF_TP_ADD_TC(tp, msgrcv_query); 375 } else { 376 ATF_TP_ADD_TC(tp, msgrcv_basic); 377 ATF_TP_ADD_TC(tp, msgrcv_block); 378 ATF_TP_ADD_TC(tp, msgrcv_err); 379 ATF_TP_ADD_TC(tp, msgrcv_mtype); 380 ATF_TP_ADD_TC(tp, msgrcv_nonblock); 381 ATF_TP_ADD_TC(tp, msgrcv_truncate); 382 } 383 384 return atf_no_error(); 385 } 386