aboutsummaryrefslogtreecommitdiff
path: root/testcases/kernel/containers/mqns/mqns_04.c
blob: 2d943e1b689fd326b76f8a587cfc515b69d6f3de (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright (c) International Business Machines Corp., 2009
 * Copyright (c) Serge Hallyn <serue@us.ibm.com>
 * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
 */

/*\
 * [Description]
 *
 * Test mqueuefs manipulation from child/parent namespaces.
 *
 * [Algorithm]
 *
 * - parent creates mqueue folder in <tmpdir>
 * - child mq_open() /MQ1 mqueue
 * - child mounts mqueue there
 * - parent checks for <tmpdir>/mqueue/MQ1 existence
 * - child exits
 * - parent checks for <tmpdir>/mqueue/MQ1 existence
 * - parent tries 'touch <tmpdir>/mqueue/MQ2' -> should fail
 * - parent umount mqueuefs
 */

#include <sys/wait.h>
#include "tst_test.h"
#include "lapi/sched.h"
#include "tst_safe_posix_ipc.h"
#include "tst_safe_stdio.h"
#include "tst_safe_macros.h"

#define CHECK_MQ_OPEN_RET(x) ((x) >= 0 || ((x) == -1 && errno != EMFILE))

#define DEVDIR "ltp_mqueue"
#define MQNAME1 "/MQ1"
#define MQNAME2 "/MQ2"
#define MQUEUE1 DEVDIR MQNAME1
#define MQUEUE2 DEVDIR MQNAME2

static char *str_op;

static void check_mqueue(void)
{
	mqd_t mqd;

	tst_res(TINFO, "Creating %s mqueue from within child process", MQNAME1);

	mqd = TST_RETRY_FUNC(
		mq_open(MQNAME1, O_RDWR | O_CREAT | O_EXCL, 0755, NULL),
		CHECK_MQ_OPEN_RET);
	if (mqd == -1)
		tst_brk(TBROK | TERRNO, "mq_open failed");

	SAFE_MQ_CLOSE(mqd);

	tst_res(TINFO, "Mount %s from within child process", DEVDIR);

	SAFE_MOUNT("mqueue", DEVDIR, "mqueue", 0, NULL);

	TST_CHECKPOINT_WAKE_AND_WAIT(0);
}

static void run(void)
{
	const struct tst_clone_args clone_args = {
		.flags = CLONE_NEWIPC,
		.exit_signal = SIGCHLD
	};

	if (str_op && !strcmp(str_op, "clone")) {
		tst_res(TINFO, "Spawning isolated process");

		if (!SAFE_CLONE(&clone_args)) {
			check_mqueue();
			return;
		}
	} else if (str_op && !strcmp(str_op, "unshare")) {
		tst_res(TINFO, "Spawning unshared process");

		if (!SAFE_FORK()) {
			SAFE_UNSHARE(CLONE_NEWIPC);
			check_mqueue();
			return;
		}
	}

	TST_CHECKPOINT_WAIT(0);

	if (access(MQUEUE1, F_OK))
		tst_res(TFAIL, MQUEUE1 " can't be accessed from parent");
	else
		tst_res(TPASS, MQUEUE1 " can be accessed from parent");

	TST_CHECKPOINT_WAKE(0);

	tst_res(TINFO, "Waiting child to exit");

	tst_reap_children();

	if (access(MQUEUE1, F_OK))
		tst_res(TFAIL, MQUEUE1 " can't be accessed from parent");
	else
		tst_res(TPASS, MQUEUE1 " can be accessed from parent");

	tst_res(TINFO, "Try to create %s from parent", MQUEUE2);

	TST_EXP_FAIL(creat(MQUEUE2, 0755), EACCES);

	SAFE_UMOUNT(DEVDIR);
}

static void setup(void)
{
	if (!str_op || (strcmp(str_op, "clone") && strcmp(str_op, "unshare")))
		tst_brk(TCONF, "Please specify clone|unshare child isolation");

	SAFE_MKDIR(DEVDIR, 0755);
}

static void cleanup(void)
{
	if (!access(MQUEUE1, F_OK))
		SAFE_MQ_UNLINK(MQNAME1);

	if (!access(MQUEUE2, F_OK))
		SAFE_MQ_UNLINK(MQNAME2);

	if (tst_is_mounted(DEVDIR))
		SAFE_UMOUNT(DEVDIR);
}

static struct tst_test test = {
	.test_all = run,
	.setup = setup,
	.cleanup = cleanup,
	.needs_root = 1,
	.forks_child = 1,
	.needs_checkpoints = 1,
	.options = (struct tst_option[]) {
		{ "m:", &str_op, "Child process isolation <clone|unshare>" },
		{},
	},
	.needs_kconfigs = (const char *[]) {
		"CONFIG_USER_NS",
		NULL
	},
};