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