1 /* $OpenBSD: t_msgget.c,v 1.1.1.1 2019/11/19 19:57:04 bluhm Exp $ */ 2 /* $NetBSD: t_msgget.c,v 1.3 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/cdefs.h> 36 __RCSID("$NetBSD: t_msgget.c,v 1.3 2017/10/08 08:31:05 kre Exp $"); 37 38 #include <sys/msg.h> 39 #include <sys/stat.h> 40 #include <sys/sysctl.h> 41 #include <sys/wait.h> 42 43 #include "atf-c.h" 44 #include <errno.h> 45 #include <pwd.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #include <sysexits.h> 50 #include <time.h> 51 #include <unistd.h> 52 53 #define MSG_KEY 12345689 54 55 static void clean(void); 56 57 static void 58 clean(void) 59 { 60 int id; 61 62 if ((id = msgget(MSG_KEY, 0)) != -1) 63 (void)msgctl(id, IPC_RMID, 0); 64 } 65 66 ATF_TC_WITH_CLEANUP(msgget_excl); 67 ATF_TC_HEAD(msgget_excl, tc) 68 { 69 atf_tc_set_md_var(tc, "descr", "Test msgget(2) with IPC_EXCL"); 70 } 71 72 ATF_TC_BODY(msgget_excl, tc) 73 { 74 int id; 75 76 /* 77 * Create a message queue and re-open it with 78 * O_CREAT and IPC_EXCL set. This should fail. 79 */ 80 id = msgget(MSG_KEY, IPC_CREAT | 0600); 81 82 if (id < 0) 83 atf_tc_fail("failed to create message queue"); 84 85 errno = 0; 86 87 if (msgget(MSG_KEY, IPC_CREAT | IPC_EXCL | 0600) != -1) 88 atf_tc_fail("msgget(2) failed for IPC_EXCL"); 89 90 ATF_REQUIRE(errno == EEXIST); 91 92 /* 93 * However, the same call should succeed 94 * when IPC_EXCL is not set in the flags. 95 */ 96 id = msgget(MSG_KEY, IPC_CREAT | 0600); 97 98 if (id < 0) 99 atf_tc_fail("msgget(2) failed to re-open"); 100 101 ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); 102 } 103 104 ATF_TC_CLEANUP(msgget_excl, tc) 105 { 106 clean(); 107 } 108 109 ATF_TC_WITH_CLEANUP(msgget_exit); 110 ATF_TC_HEAD(msgget_exit, tc) 111 { 112 atf_tc_set_md_var(tc, "descr", 113 "Test that XSI message queues are " 114 "not removed when the process exits"); 115 } 116 117 ATF_TC_BODY(msgget_exit, tc) 118 { 119 int id, sta; 120 pid_t pid; 121 122 pid = fork(); 123 ATF_REQUIRE(pid >= 0); 124 125 if (pid == 0) { 126 127 if (msgget(MSG_KEY, IPC_CREAT | IPC_EXCL | 0600) == -1) 128 _exit(EXIT_FAILURE); 129 130 _exit(EXIT_SUCCESS); 131 } 132 133 (void)wait(&sta); 134 135 if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) 136 atf_tc_fail("failed to create message queue"); 137 138 id = msgget(MSG_KEY, 0); 139 140 if (id == -1) 141 atf_tc_fail("message queue was removed on process exit"); 142 143 ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); 144 } 145 146 ATF_TC_CLEANUP(msgget_exit, tc) 147 { 148 clean(); 149 } 150 151 ATF_TC_WITH_CLEANUP(msgget_init); 152 ATF_TC_HEAD(msgget_init, tc) 153 { 154 atf_tc_set_md_var(tc, "descr", 155 "Test that msgget(2) initializes data structures properly"); 156 } 157 158 ATF_TC_BODY(msgget_init, tc) 159 { 160 const uid_t uid = geteuid(); 161 const gid_t gid = getegid(); 162 struct msqid_ds msgds; 163 time_t t; 164 int id; 165 166 (void)memset(&msgds, 0x9, sizeof(struct msqid_ds)); 167 168 t = time(NULL); 169 id = msgget(MSG_KEY, IPC_CREAT | 0600); 170 171 ATF_REQUIRE(id !=-1); 172 ATF_REQUIRE(msgctl(id, IPC_STAT, &msgds) == 0); 173 174 ATF_CHECK(msgds.msg_qnum == 0); 175 ATF_CHECK(msgds.msg_lspid == 0); 176 ATF_CHECK(msgds.msg_lrpid == 0); 177 ATF_CHECK(msgds.msg_rtime == 0); 178 ATF_CHECK(msgds.msg_stime == 0); 179 ATF_CHECK(msgds.msg_perm.uid == uid); 180 ATF_CHECK(msgds.msg_perm.gid == gid); 181 ATF_CHECK(msgds.msg_perm.cuid == uid); 182 ATF_CHECK(msgds.msg_perm.cgid == gid); 183 ATF_CHECK(msgds.msg_perm.mode == 0600); 184 185 if (llabs(t - msgds.msg_ctime) > 5) 186 atf_tc_fail("msgget(2) initialized current time incorrectly"); 187 188 ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); 189 } 190 191 ATF_TC_CLEANUP(msgget_init, tc) 192 { 193 clean(); 194 } 195 196 ATF_TC(msgget_limit); 197 ATF_TC_HEAD(msgget_limit, tc) 198 { 199 atf_tc_set_md_var(tc, "descr", "Test msgget(2) against system limits"); 200 } 201 202 ATF_TC_BODY(msgget_limit, tc) 203 { 204 size_t len = sizeof(int); 205 bool fail = false; 206 int i, lim = 0; 207 int *buf; 208 209 if (sysctlbyname("kern.ipc.msgmni", &lim, &len, NULL, 0) != 0) 210 atf_tc_skip("failed to read kern.ipc.msgmni sysctl"); 211 212 buf = calloc(lim + 1, sizeof(*buf)); 213 ATF_REQUIRE(buf != NULL); 214 215 for (i = 0; i < lim; i++) { 216 217 buf[i] = msgget(MSG_KEY + i, IPC_CREAT | IPC_EXCL | 0600); 218 219 (void)fprintf(stderr, "key[%d] = %d\n", i, buf[i]); 220 221 /* 222 * This test only works when there are zero existing 223 * message queues. Thus, bypass the unit test when 224 * this precondition is not met, for reason or another. 225 */ 226 if (buf[i] == -1) 227 goto out; 228 } 229 230 i++; 231 errno = 0; 232 233 buf[i] = msgget(MSG_KEY + i, IPC_CREAT | IPC_EXCL | 0600); 234 235 if (buf[i] != -1 || errno != ENOSPC) 236 fail = true; 237 238 out: /* Remember to clean-up. */ 239 for (i = 0; i < lim; i++) 240 (void)msgctl(buf[i], IPC_RMID, 0); 241 242 free(buf); 243 244 if (fail != false) 245 atf_tc_fail("msgget(2) opened more than %d queues", lim); 246 } 247 248 ATF_TC_WITH_CLEANUP(msgget_mode); 249 ATF_TC_HEAD(msgget_mode, tc) 250 { 251 atf_tc_set_md_var(tc, "descr", "Test different modes with msgget(2)"); 252 atf_tc_set_md_var(tc, "require.user", "root"); 253 } 254 255 ATF_TC_BODY(msgget_mode, tc) 256 { 257 static const mode_t mode[] = { 258 S_IRWXU, S_IRUSR, S_IWUSR, S_IXUSR, S_IRWXG, S_IRGRP, 259 S_IWGRP, S_IXGRP, S_IRWXO, S_IROTH, S_IWOTH, S_IXOTH 260 }; 261 262 struct msqid_ds msgds; 263 size_t i; 264 int id; 265 266 for (i = 0; i < __arraycount(mode); i++) { 267 268 (void)fprintf(stderr, "testing mode %d\n", mode[i]); 269 (void)memset(&msgds, 0, sizeof(struct msqid_ds)); 270 271 id = msgget(MSG_KEY, IPC_CREAT | IPC_EXCL | (int)mode[i]); 272 273 ATF_REQUIRE(id != -1); 274 ATF_REQUIRE(msgctl(id, IPC_STAT, &msgds) == 0); 275 ATF_REQUIRE(msgds.msg_perm.mode == mode[i]); 276 ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); 277 } 278 } 279 280 ATF_TC_CLEANUP(msgget_mode, tc) 281 { 282 clean(); 283 } 284 285 static volatile int sig_caught; 286 287 static void 288 sigsys_handler(int signum) 289 { 290 291 sig_caught = signum; 292 } 293 294 static int 295 no_kernel_sysvmsg(void) 296 { 297 int id; 298 void (*osig)(int); 299 300 sig_caught = 0; 301 osig = signal(SIGSYS, sigsys_handler); 302 id = msgget(MSG_KEY, IPC_CREAT | 0600); 303 if (sig_caught || id == -1) 304 return 1; 305 306 (void)msgctl(id, IPC_RMID, 0); 307 (void)signal(SIGSYS, osig); 308 309 return 0; 310 } 311 312 ATF_TC(msgget_query); 313 ATF_TC_HEAD(msgget_query, tc) 314 { 315 atf_tc_set_md_var(tc, "descr", "Skip msgget_* tests - no SYSVMSG"); 316 } 317 ATF_TC_BODY(msgget_query, tc) 318 { 319 atf_tc_skip("No SYSVMSG in kernel"); 320 } 321 322 ATF_TP_ADD_TCS(tp) 323 { 324 325 if (no_kernel_sysvmsg()) { 326 ATF_TP_ADD_TC(tp, msgget_query); 327 } else { 328 ATF_TP_ADD_TC(tp, msgget_excl); 329 ATF_TP_ADD_TC(tp, msgget_exit); 330 ATF_TP_ADD_TC(tp, msgget_init); 331 /* 332 * Adjusted for OpenBSD, not available 333 * ATF_TP_ADD_TC(tp, msgget_limit); 334 */ 335 ATF_TP_ADD_TC(tp, msgget_mode); 336 } 337 338 return atf_no_error(); 339 } 340