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
21 static uid_t euid;
22 static struct passwd *pw;
23 static char *qname;
24 static struct rlimit rlim;
25
26 static mqd_t fd, fd2;
27 static mqd_t fd3 = -1;
28 static int max_queues;
29
30 struct 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
43 static void create_queue(void);
44 static void unlink_queue(void);
45 static void set_rlimit(void);
46 static void restore_rlimit(void);
47 static void set_max_queues(void);
48 static void restore_max_queues(void);
49
50 static 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
create_queue(void)144 static 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
unlink_queue(void)151 static 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
set_max_queues(void)162 static 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
restore_max_queues(void)170 static void restore_max_queues(void)
171 {
172 SAFE_SETEUID(euid);
173
174 SAFE_FILE_PRINTF(PROC_MAX_QUEUES, "%d", max_queues);
175 }
176
set_rlimit(void)177 static 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
restore_rlimit(void)187 static void restore_rlimit(void)
188 {
189 SAFE_SETRLIMIT(RLIMIT_NOFILE, &rlim);
190 }
191
setup(void)192 static 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
cleanup(void)201 static 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
do_test(unsigned int i)218 static 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
276 CLEANUP:
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
287 static 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