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