1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) Crackerjack Project., 2007-2008 ,Hitachi, Ltd 4 * Author(s): Takahiro Yasui <takahiro.yasui.mp@hitachi.com>, 5 * Yumiko Sugita <yumiko.sugita.yf@hitachi.com>, 6 * Satoshi Fujiwara <sa-fuji@sdl.hitachi.co.jp> 7 * Copyright (c) 2016 Linux Test Project 8 */ 9 10#include <errno.h> 11#include <mqueue.h> 12#include <pwd.h> 13 14#include "tst_test.h" 15#include "tst_safe_file_ops.h" 16#include "tst_safe_posix_ipc.h" 17 18#define QUEUE_NAME "/test_mqueue" 19#define QUEUE_INIT "/init_mqueue" 20 21static uid_t euid; 22static struct passwd *pw; 23static char *qname; 24static struct rlimit rlim; 25 26static mqd_t fd, fd2; 27static mqd_t fd3 = -1; 28static int max_queues; 29 30struct test_case { 31 const char *desc; 32 char *qname; 33 int oflag; 34 struct mq_attr *rq; 35 int ret; 36 int err; 37 void (*setup)(void); 38 void (*cleanup)(void); 39}; 40 41#define PROC_MAX_QUEUES "/proc/sys/fs/mqueue/queues_max" 42 43static void create_queue(void); 44static void unlink_queue(void); 45static void set_rlimit(void); 46static void restore_rlimit(void); 47static void set_max_queues(void); 48static void restore_max_queues(void); 49 50static struct test_case tcase[] = { 51 { 52 .desc = "NORMAL", 53 .qname = QUEUE_NAME, 54 .oflag = O_CREAT, 55 .rq = &(struct mq_attr){.mq_maxmsg = 20, .mq_msgsize = 16384}, 56 .ret = 0, 57 .err = 0, 58 }, 59 { 60 .desc = "NORMAL", 61 .qname = QUEUE_NAME, 62 .oflag = O_CREAT, 63 .ret = 0, 64 .err = 0, 65 }, 66 { 67 .desc = "NORMAL", 68 .qname = "/caaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 69 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 70 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 71 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 72 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 73 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 74 "aaaaaaaaaaaaaaa", 75 .oflag = O_CREAT, 76 .ret = 0, 77 .err = 0, 78 }, 79 { 80 .desc = "NORMAL", 81 .qname = "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 82 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 83 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 84 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 85 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 86 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 87 "aaaaaaaaaaaaaaaa", 88 .oflag = O_CREAT, 89 .ret = -1, 90 .err = ENAMETOOLONG, 91 }, 92 93 { 94 .desc = "NORMAL", 95 .qname = "", 96 .oflag = O_CREAT, 97 .ret = -1, 98 .err = EINVAL, 99 }, 100 { 101 .desc = "NORMAL", 102 .qname = QUEUE_NAME, 103 .ret = -1, 104 .err = EACCES, 105 .setup = create_queue, 106 .cleanup = unlink_queue, 107 }, 108 { 109 .desc = "NORMAL", 110 .qname = QUEUE_NAME, 111 .oflag = O_CREAT | O_EXCL, 112 .ret = -1, 113 .err = EEXIST, 114 .setup = create_queue, 115 .cleanup = unlink_queue, 116 }, 117 { 118 .desc = "NO_FILE", 119 .qname = QUEUE_NAME, 120 .oflag = O_CREAT, 121 .ret = -1, 122 .err = EMFILE, 123 .setup = set_rlimit, 124 .cleanup = restore_rlimit, 125 }, 126 { 127 .desc = "NORMAL", 128 .qname = "/notexist", 129 .oflag = 0, 130 .ret = -1, 131 .err = ENOENT, 132 }, 133 { 134 .desc = "NO_SPACE", 135 .qname = QUEUE_NAME, 136 .oflag = O_CREAT, 137 .ret = -1, 138 .err = ENOSPC, 139 .setup = set_max_queues, 140 .cleanup = restore_max_queues, 141 } 142}; 143 144static void create_queue(void) 145{ 146 fd2 = SAFE_MQ_OPEN(QUEUE_NAME, O_CREAT | O_EXCL | O_RDWR, S_IRWXU, NULL); 147 148 SAFE_SETEUID(pw->pw_uid); 149} 150 151static void unlink_queue(void) 152{ 153 SAFE_SETEUID(euid); 154 if (fd2 > 0) 155 SAFE_CLOSE(fd2); 156 157 if (mq_unlink(QUEUE_NAME)) 158 tst_brk(TBROK | TERRNO, "mq_close(" QUEUE_NAME ") failed"); 159} 160 161 162static void set_max_queues(void) 163{ 164 SAFE_FILE_SCANF(PROC_MAX_QUEUES, "%d", &max_queues); 165 SAFE_FILE_PRINTF(PROC_MAX_QUEUES, "%d", 1); 166 167 SAFE_SETEUID(pw->pw_uid); 168} 169 170static void restore_max_queues(void) 171{ 172 SAFE_SETEUID(euid); 173 174 SAFE_FILE_PRINTF(PROC_MAX_QUEUES, "%d", max_queues); 175} 176 177static void set_rlimit(void) 178{ 179 if (rlim.rlim_cur > 0) { 180 struct rlimit r; 181 r.rlim_cur = 0; 182 r.rlim_max = rlim.rlim_max; 183 SAFE_SETRLIMIT(RLIMIT_NOFILE, &r); 184 } 185} 186 187static void restore_rlimit(void) 188{ 189 SAFE_SETRLIMIT(RLIMIT_NOFILE, &rlim); 190} 191 192static void setup(void) 193{ 194 euid = geteuid(); 195 pw = SAFE_GETPWNAM("nobody"); 196 SAFE_GETRLIMIT(RLIMIT_NOFILE, &rlim); 197 198 fd3 = SAFE_MQ_OPEN(QUEUE_INIT, O_CREAT | O_EXCL | O_RDWR, S_IRWXU, NULL); 199} 200 201static void cleanup(void) 202{ 203 if (fd > 0) 204 mq_close(fd); 205 206 if (fd2 > 0) 207 mq_close(fd2); 208 209 if (fd3 > 0 && mq_close(fd3)) 210 tst_res(TWARN | TERRNO, "mq_close(%s) failed", QUEUE_INIT); 211 212 if (mq_unlink(QUEUE_INIT)) 213 tst_res(TWARN | TERRNO, "mq_unlink(%s) failed", QUEUE_INIT); 214 215 mq_unlink(qname); 216} 217 218static void do_test(unsigned int i) 219{ 220 struct test_case *tc = &tcase[i]; 221 struct mq_attr oldattr; 222 223 qname = tc->qname; 224 fd = fd2 = -1; 225 226 tst_res(TINFO, "queue name \"%s\"", qname); 227 228 if (tc->setup) 229 tc->setup(); 230 231 TEST(fd = mq_open(qname, tc->oflag, S_IRWXU, tc->rq)); 232 233 if (fd > 0 && tc->rq) { 234 if (mq_getattr(fd, &oldattr) < 0) { 235 tst_res(TFAIL | TERRNO, "mq_getattr failed"); 236 goto CLEANUP; 237 } 238 239 if (oldattr.mq_maxmsg != tc->rq->mq_maxmsg 240 || oldattr.mq_msgsize != tc->rq->mq_msgsize) { 241 tst_res(TFAIL, "wrong mq_attr: " 242 "mq_maxmsg expected %ld return %ld, " 243 "mq_msgsize expected %ld return %ld", 244 tc->rq->mq_maxmsg, oldattr.mq_maxmsg, tc->rq->mq_msgsize, 245 oldattr.mq_msgsize); 246 goto CLEANUP; 247 } 248 } 249 250 if (tc->ret == 0) { 251 if (TST_RET < 0) { 252 tst_res(TFAIL | TTERRNO, "%s wrong return code: %ld", 253 tc->desc, TST_RET); 254 } else { 255 tst_res(TPASS | TTERRNO, "%s returned: %ld", 256 tc->desc, TST_RET); 257 } 258 259 goto CLEANUP; 260 } 261 262 if (TST_ERR != tc->err) { 263 tst_res(TFAIL | TTERRNO, "%s expected errno: %d", 264 tc->desc, TST_ERR); 265 goto CLEANUP; 266 } 267 268 if (TST_RET != tc->ret) { 269 tst_res(TFAIL | TTERRNO, "%s wrong return code: %ld", 270 tc->desc, TST_RET); 271 } else { 272 tst_res(TPASS | TTERRNO, "%s returned: %ld", 273 tc->desc, TST_RET); 274 } 275 276CLEANUP: 277 if (tc->cleanup) 278 tc->cleanup(); 279 280 if (TST_RET != -1) { 281 if (fd > 0) 282 SAFE_CLOSE(fd); 283 mq_unlink(qname); 284 } 285} 286 287static struct tst_test test = { 288 .tcnt = ARRAY_SIZE(tcase), 289 .test = do_test, 290 .needs_root = 1, 291 .setup = setup, 292 .cleanup = cleanup, 293}; 294