• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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