|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
1 | 2 | /*
|
2 |
| -* Copyright (c) International Business Machines Corp., 2009 |
3 |
| -* Copyright (c) Nadia Derbey, 2009 |
4 |
| -* This program is free software; you can redistribute it and/or modify |
5 |
| -* it under the terms of the GNU General Public License as published by |
6 |
| -* the Free Software Foundation; either version 2 of the License, or |
7 |
| -* (at your option) any later version. |
8 |
| -* |
9 |
| -* This program is distributed in the hope that it will be useful, |
10 |
| -* but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 |
| -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See |
12 |
| -* the GNU General Public License for more details. |
13 |
| -* You should have received a copy of the GNU General Public License |
14 |
| -* along with this program; if not, write to the Free Software |
15 |
| -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
16 |
| -* |
17 |
| -* Author: Nadia Derbey <[email protected]> |
18 |
| -* |
19 |
| -* Check mqns isolation: child mqns cannot be accessed from father |
20 |
| -* |
21 |
| -* Mount mqueue fs |
22 |
| -* unshare |
23 |
| -* In unshared process: |
24 |
| -* Mount newinstance mqueuefs |
25 |
| -* Create a posix mq -->mq1 |
26 |
| -* Check that mq1 is not readable from father |
27 |
| -* |
28 |
| -* Changelog: |
29 |
| -* Dec 16: accomodate new mqns semantics (Serge Hallyn) |
30 |
| -
|
31 |
| -***************************************************************************/ |
32 |
| - |
33 |
| -#ifndef _GNU_SOURCE |
34 |
| -#define _GNU_SOURCE |
35 |
| -#endif |
36 |
| -#include <sys/wait.h> |
37 |
| -#include <errno.h> |
38 |
| -#include <stdio.h> |
39 |
| -#include <stdlib.h> |
40 |
| -#include <string.h> |
41 |
| -#include <unistd.h> |
42 |
| -#include "mqns.h" |
43 |
| -#include "mqns_helper.h" |
44 |
| - |
45 |
| -char *TCID = "posixmq_namespace_02"; |
46 |
| -int TST_TOTAL = 1; |
47 |
| - |
48 |
| -int p1[2]; |
49 |
| -int p2[2]; |
50 |
| - |
51 |
| -int check_mqueue(void *vtest) |
52 |
| -{ |
53 |
| - char buf[30]; |
54 |
| - mqd_t mqd; |
| 3 | + * Copyright (c) International Business Machines Corp., 2009 |
| 4 | + * Copyright (c) Nadia Derbey, 2009 <[email protected]> |
| 5 | + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <[email protected]> |
| 6 | + */ |
55 | 7 |
|
56 |
| - (void) vtest; |
| 8 | +/*\ |
| 9 | + * [Description] |
| 10 | + * |
| 11 | + * Create a mqueue with the same name in both parent and isolated/forked child, |
| 12 | + * then check namespace isolation. |
| 13 | + */ |
57 | 14 |
|
58 |
| - close(p1[1]); |
59 |
| - close(p2[0]); |
| 15 | +#include "tst_test.h" |
| 16 | +#include "lapi/sched.h" |
| 17 | +#include "tst_safe_posix_ipc.h" |
60 | 18 |
|
61 |
| - if (read(p1[0], buf, 3) < 0) { |
62 |
| - perror("read(p1[0], ..) failed"); |
63 |
| - exit(1); |
64 |
| - } else { |
| 19 | +#define MQNAME "/MQ1" |
65 | 20 |
|
66 |
| - mqd = |
67 |
| - tst_syscall(__NR_mq_open, NOSLASH_MQ1, |
68 |
| - O_RDWR | O_CREAT | O_EXCL, 0777, NULL); |
69 |
| - if (mqd == -1) { |
70 |
| - if (write(p2[1], "mqfail", strlen("mqfail") + 1) < 0) { |
71 |
| - perror("write(p2[1], \"mqfail\", ..) failed"); |
72 |
| - exit(1); |
73 |
| - } |
74 |
| - } else { |
75 |
| - |
76 |
| - if (write(p2[1], "mqopen", strlen("mqopen") + 1) < 0) { |
77 |
| - perror("write(p2[1], \"mqopen\", ..) failed"); |
78 |
| - exit(1); |
79 |
| - } else { |
80 |
| - |
81 |
| - if (read(p1[0], buf, 5) < 0) { |
82 |
| - perror("read(p1[0], ..) failed"); |
83 |
| - exit(1); |
84 |
| - } else { |
85 |
| - |
86 |
| - /* destroy the mqueue */ |
87 |
| - if (mq_close(mqd) < 0) { |
88 |
| - perror("mq_close(mqd) failed"); |
89 |
| - exit(1); |
90 |
| - } else if (tst_syscall(__NR_mq_unlink, |
91 |
| - NOSLASH_MQ1) < 0) { |
92 |
| - perror("mq_unlink(" NOSLASH_MQ1 |
93 |
| - ") failed"); |
94 |
| - exit(1); |
95 |
| - } else if (write(p2[1], "done", |
96 |
| - strlen("done") + 1) |
97 |
| - < 0) { |
98 |
| - perror("write(p2[1], " |
99 |
| - "\"done\", ..) failed"); |
100 |
| - exit(1); |
101 |
| - } |
102 |
| - |
103 |
| - } |
104 |
| - |
105 |
| - } |
| 21 | +static mqd_t mqd; |
| 22 | +static char *str_op; |
106 | 23 |
|
107 |
| - } |
| 24 | +static int create_message_queue(void) |
| 25 | +{ |
| 26 | + return mq_open(MQNAME, O_RDWR | O_CREAT | O_EXCL, 0777, NULL); |
| 27 | +} |
108 | 28 |
|
109 |
| - } |
110 |
| - exit(0); |
| 29 | +static void shared_child(void) |
| 30 | +{ |
| 31 | + mqd_t mqd1 = -1; |
111 | 32 |
|
| 33 | + TST_EXP_FAIL(mqd1 = create_message_queue(), EEXIST); |
| 34 | + |
| 35 | + if (mqd1 != -1) { |
| 36 | + SAFE_MQ_CLOSE(mqd1); |
| 37 | + SAFE_MQ_UNLINK(MQNAME); |
| 38 | + } |
112 | 39 | }
|
113 | 40 |
|
114 |
| -static void setup(void) |
| 41 | +static void isolated_child(void) |
115 | 42 | {
|
116 |
| - tst_require_root(); |
117 |
| - check_mqns(); |
| 43 | + mqd_t mqd1 = -1; |
| 44 | + |
| 45 | + TST_EXP_POSITIVE(mqd1 = create_message_queue()); |
| 46 | + |
| 47 | + if (mqd1 != -1) { |
| 48 | + SAFE_MQ_CLOSE(mqd1); |
| 49 | + SAFE_MQ_UNLINK(MQNAME); |
| 50 | + } |
118 | 51 | }
|
119 | 52 |
|
120 |
| -int main(int argc, char *argv[]) |
| 53 | +static void run(void) |
121 | 54 | {
|
122 |
| - int r; |
123 |
| - mqd_t mqd; |
124 |
| - char buf[30]; |
125 |
| - int use_clone = T_UNSHARE; |
126 |
| - |
127 |
| - setup(); |
128 |
| - |
129 |
| - if (argc == 2 && strcmp(argv[1], "-clone") == 0) { |
130 |
| - tst_resm(TINFO, |
131 |
| - "Testing posix mq namespaces through clone(2)."); |
132 |
| - use_clone = T_CLONE; |
133 |
| - } else |
134 |
| - tst_resm(TINFO, |
135 |
| - "Testing posix mq namespaces through unshare(2)."); |
136 |
| - |
137 |
| - if (pipe(p1) == -1 || pipe(p2) == -1) { |
138 |
| - tst_brkm(TBROK | TERRNO, NULL, "pipe"); |
139 |
| - } |
| 55 | + const struct tst_clone_args clone_args = { CLONE_NEWIPC, SIGCHLD }; |
140 | 56 |
|
141 |
| - /* fire off the test */ |
142 |
| - r = do_clone_unshare_test(use_clone, CLONE_NEWIPC, check_mqueue, NULL); |
143 |
| - if (r < 0) { |
144 |
| - tst_brkm(TFAIL, NULL, "failed clone/unshare"); |
145 |
| - } |
| 57 | + tst_res(TINFO, "Checking namespaces isolation from parent to child"); |
146 | 58 |
|
147 |
| - tst_resm(TINFO, "Checking namespaces isolation (child to parent)"); |
| 59 | + if (str_op && !strcmp(str_op, "clone")) { |
| 60 | + tst_res(TINFO, "Spawning isolated process"); |
148 | 61 |
|
149 |
| - close(p1[0]); |
150 |
| - close(p2[1]); |
151 |
| - if (write(p1[1], "go", strlen("go") + 1) < 0) { |
152 |
| - tst_brkm(TBROK, NULL, "write(p1[1], \"go\", ..) failed"); |
153 |
| - } |
| 62 | + if (!SAFE_CLONE(&clone_args)) { |
| 63 | + isolated_child(); |
| 64 | + return; |
| 65 | + } |
| 66 | + } else if (str_op && !strcmp(str_op, "unshare")) { |
| 67 | + tst_res(TINFO, "Spawning unshared process"); |
154 | 68 |
|
155 |
| - if (read(p2[0], buf, 7) < 0) { |
156 |
| - tst_resm(TBROK | TERRNO, "read(p2[0], ..) failed"); |
157 |
| - } else if (!strcmp(buf, "mqfail")) { |
158 |
| - tst_resm(TFAIL, "child process could not create mqueue"); |
159 |
| - umount(DEV_MQUEUE); |
160 |
| - } else if (strcmp(buf, "mqopen")) { |
161 |
| - tst_resm(TFAIL, "child process could not create mqueue"); |
162 |
| - umount(DEV_MQUEUE); |
163 |
| - } else { |
164 |
| - mqd = tst_syscall(__NR_mq_open, NOSLASH_MQ1, O_RDONLY); |
165 |
| - if (mqd == -1) { |
166 |
| - tst_resm(TPASS, |
167 |
| - "Parent process can't see the mqueue"); |
168 |
| - } else { |
169 |
| - tst_resm(TFAIL | TERRNO, |
170 |
| - "Parent process found mqueue"); |
171 |
| - mq_close(mqd); |
| 69 | + if (!SAFE_FORK()) { |
| 70 | + SAFE_UNSHARE(CLONE_NEWIPC); |
| 71 | + isolated_child(); |
| 72 | + return; |
172 | 73 | }
|
173 |
| - if (write(p1[1], "cont", 5) < 0) { |
174 |
| - tst_resm(TBROK | TERRNO, "write(p1[1], ..) failed"); |
| 74 | + } else { |
| 75 | + tst_res(TINFO, "Spawning plain process"); |
| 76 | + |
| 77 | + if (!SAFE_FORK()) { |
| 78 | + shared_child(); |
| 79 | + return; |
175 | 80 | }
|
176 |
| - read(p2[0], buf, 7); |
177 | 81 | }
|
| 82 | +} |
178 | 83 |
|
179 |
| - tst_exit(); |
| 84 | +static void setup(void) |
| 85 | +{ |
| 86 | + mqd = SAFE_MQ_OPEN(MQNAME, O_RDWR | O_CREAT | O_EXCL, 0777, NULL); |
180 | 87 | }
|
| 88 | + |
| 89 | +static void cleanup(void) |
| 90 | +{ |
| 91 | + if (mqd != -1) { |
| 92 | + SAFE_MQ_CLOSE(mqd); |
| 93 | + SAFE_MQ_UNLINK(MQNAME); |
| 94 | + } |
| 95 | +} |
| 96 | + |
| 97 | +static struct tst_test test = { |
| 98 | + .test_all = run, |
| 99 | + .setup = setup, |
| 100 | + .cleanup = cleanup, |
| 101 | + .needs_root = 1, |
| 102 | + .forks_child = 1, |
| 103 | + .options = (struct tst_option[]) { |
| 104 | + { "m:", &str_op, "Child process isolation <clone|unshare>" }, |
| 105 | + {}, |
| 106 | + }, |
| 107 | + .needs_kconfigs = (const char *[]) { |
| 108 | + "CONFIG_USER_NS", |
| 109 | + NULL |
| 110 | + }, |
| 111 | +}; |
0 commit comments