]> git.ipfire.org Git - people/ms/pakfire.git/blame - tests/libpakfire/jail.c
mount: Fix bind-mounting read-only shares
[people/ms/pakfire.git] / tests / libpakfire / jail.c
CommitLineData
3334e9c0
MT
1/*#############################################################################
2# #
3# Pakfire - The IPFire package management system #
4# Copyright (C) 2022 Pakfire development team #
5# #
6# This program is free software: you can redistribute it and/or modify #
7# it under the terms of the GNU General Public License as published by #
8# the Free Software Foundation, either version 3 of the License, or #
9# (at your option) any later version. #
10# #
11# This program is distributed in the hope that it will be useful, #
12# but WITHOUT ANY WARRANTY; without even the implied warranty of #
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14# GNU General Public License for more details. #
15# #
16# You should have received a copy of the GNU General Public License #
17# along with this program. If not, see <http://www.gnu.org/licenses/>. #
18# #
19#############################################################################*/
20
cc6e2264
MT
21#include <sys/mount.h>
22
6962faab 23#include <pakfire/cgroup.h>
3334e9c0
MT
24#include <pakfire/jail.h>
25
26#include "../testsuite.h"
27
2e664540
MT
28static const char* cmd_hello_world[] = {
29 "/command", "echo", "Hello World!", NULL,
3334e9c0
MT
30};
31
93550e9b
MT
32static const char* cmd_exhaust_memory[] = {
33 "/command", "exhaust-memory", NULL,
34};
35
36static const char* cmd_fork_bomb[] = {
37 "/command", "fork-bomb", NULL,
38};
39
bddfe668
MT
40static const char* cmd_stat_ownership[] = {
41 "/command", "stat-ownership", NULL,
42};
43
3334e9c0
MT
44static int test_create(const struct test* t) {
45 struct pakfire_jail* jail = NULL;
46
47 // Create a new jail
d639929b 48 ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0));
3334e9c0
MT
49
50 // Destroy it
51 ASSERT_NULL(pakfire_jail_unref(jail));
52
53 return EXIT_SUCCESS;
54
55FAIL:
56 return EXIT_FAILURE;
57}
58
32d5f21d
MT
59static int test_env(const struct test* t) {
60 struct pakfire_jail* jail = NULL;
61
62 // Create a new jail
d639929b 63 ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0));
32d5f21d 64
d5bc8fe0
MT
65 // Check if the default variables are set
66 ASSERT(pakfire_jail_get_env(jail, "LANG"));
67 ASSERT(pakfire_jail_get_env(jail, "TERM"));
68
32d5f21d
MT
69 // Fetch a non-existing environment variable
70 ASSERT_NULL(pakfire_jail_get_env(jail, "VARIABLE"));
71
72 // Set a variable
73 ASSERT_SUCCESS(pakfire_jail_set_env(jail, "VARIABLE", "VALUE"));
74
75 // Read the value back
76 ASSERT_STRING_EQUALS(pakfire_jail_get_env(jail, "VARIABLE"), "VALUE");
77
78 // Destroy it
79 ASSERT_NULL(pakfire_jail_unref(jail));
80
81 return EXIT_SUCCESS;
82
83FAIL:
84 return EXIT_FAILURE;
85}
86
0bd84dc1
MT
87static int test_exec(const struct test* t) {
88 struct pakfire_jail* jail = NULL;
89
0bd84dc1
MT
90 // Create a new jail
91 ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0));
92
93 // Try to execute something
ccdd2e95 94 ASSERT_SUCCESS(pakfire_jail_exec(jail, cmd_hello_world, NULL, NULL, NULL));
0bd84dc1
MT
95
96 // Destroy it
97 ASSERT_NULL(pakfire_jail_unref(jail));
98
99 return EXIT_SUCCESS;
100
101FAIL:
102 return EXIT_FAILURE;
103}
32d5f21d 104
6962faab
MT
105static int test_launch_into_cgroup(const struct test* t) {
106 struct pakfire_cgroup* cgroup = NULL;
107 struct pakfire_jail* jail = NULL;
108 int r = EXIT_FAILURE;
109
110 // Create a new cgroup
111 ASSERT_SUCCESS(pakfire_cgroup_open(&cgroup, t->pakfire, "pakfire-test", 0));
112
113 // Create a new jail
114 ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0));
115
116 // Connect jail to the cgroup
117 ASSERT_SUCCESS(pakfire_jail_set_cgroup(jail, cgroup));
118
119 // Run command
ccdd2e95 120 ASSERT(pakfire_jail_exec(jail, cmd_hello_world, NULL, NULL, NULL) == 0);
6962faab
MT
121
122 r = EXIT_SUCCESS;
123
124FAIL:
125 if (cgroup) {
126 pakfire_cgroup_destroy(cgroup);
127 pakfire_cgroup_unref(cgroup);
128 }
129 if (jail)
130 pakfire_jail_unref(jail);
131
132 return r;
133}
134
17841bb8
MT
135static int test_nice(const struct test* t) {
136 struct pakfire_jail* jail = NULL;
12b9b39f 137 char* output = NULL;
17841bb8
MT
138 int r = EXIT_FAILURE;
139
140 const char* argv[] = {
141 "/command", "print-nice", NULL,
142 };
143
17841bb8
MT
144 // Create a new jail
145 ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0));
146
147 // Set invalid nice levels
148 ASSERT_ERRNO(pakfire_jail_nice(jail, 100), EINVAL);
149 ASSERT_ERRNO(pakfire_jail_nice(jail, -100), EINVAL);
150
151 // Set something sane
152 ASSERT_SUCCESS(pakfire_jail_nice(jail, 5));
153
12b9b39f 154 // Check if the nice level has been set
ccdd2e95
MT
155 ASSERT_SUCCESS(pakfire_jail_exec(jail, argv,
156 NULL, pakfire_jail_capture_stdout, &output));
12b9b39f 157 ASSERT_STRING_EQUALS(output, "5\n");
17841bb8
MT
158
159 // Success
160 r = EXIT_SUCCESS;
161
162FAIL:
163 if (jail)
164 pakfire_jail_unref(jail);
12b9b39f 165 if (output)
17841bb8 166 free(output);
17841bb8
MT
167
168 return r;
169}
170
9bc7ec4b
MT
171static int test_memory_limit(const struct test* t) {
172 struct pakfire_cgroup* cgroup = NULL;
173 struct pakfire_jail* jail = NULL;
174 int r = EXIT_FAILURE;
175
9bc7ec4b
MT
176
177 // Create cgroup
178 ASSERT_SUCCESS(pakfire_cgroup_open(&cgroup, t->pakfire, "pakfire-test", 0));
179
180 // Create jail
181 ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0));
182
183 // Connect jail to the cgroup
184 ASSERT_SUCCESS(pakfire_jail_set_cgroup(jail, cgroup));
185
186 // Set a memory limit of 100 MiB
187 ASSERT_SUCCESS(pakfire_cgroup_set_memory_limit(cgroup, 100 * 1024 * 1024));
188
189 // Try to exhaust all memory
ccdd2e95 190 ASSERT_FAILURE(pakfire_jail_exec(jail, cmd_exhaust_memory, NULL, NULL, NULL));
93550e9b
MT
191
192 // A fork bomb should also exhaust all memory
ccdd2e95 193 ASSERT_FAILURE(pakfire_jail_exec(jail, cmd_fork_bomb, NULL, NULL, NULL));
9bc7ec4b
MT
194
195 // Success
196 r = EXIT_SUCCESS;
197
198FAIL:
199 if (jail)
200 pakfire_jail_unref(jail);
201 if (cgroup) {
202 pakfire_cgroup_destroy(cgroup);
203 pakfire_cgroup_unref(cgroup);
204 }
205
206 return r;
207}
208
d3b93302
MT
209static int test_pid_limit(const struct test* t) {
210 struct pakfire_cgroup* cgroup = NULL;
211 struct pakfire_jail* jail = NULL;
212 int r = EXIT_FAILURE;
213
d3b93302
MT
214 // Create cgroup
215 ASSERT_SUCCESS(pakfire_cgroup_open(&cgroup, t->pakfire, "pakfire-test", 0));
216
217 // Create jail
218 ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0));
219
220 // Connect jail to the cgroup
221 ASSERT_SUCCESS(pakfire_jail_set_cgroup(jail, cgroup));
222
223 // Set a PID limit of 100 processes
224 ASSERT_SUCCESS(pakfire_cgroup_set_pid_limit(cgroup, 100));
225
226 // Try to fork as many processes as possible
ccdd2e95 227 ASSERT_FAILURE(pakfire_jail_exec(jail, cmd_fork_bomb, NULL, NULL, NULL));
d3b93302
MT
228
229 // Success
230 r = EXIT_SUCCESS;
231
232FAIL:
233 if (jail)
234 pakfire_jail_unref(jail);
235 if (cgroup) {
236 pakfire_cgroup_destroy(cgroup);
237 pakfire_cgroup_unref(cgroup);
238 }
239
240 return r;
241}
242
bddfe668
MT
243static int test_file_ownership(const struct test* t) {
244 int r = EXIT_FAILURE;
245 char* output = NULL;
246
247 // Execute a simple command
248 ASSERT_SUCCESS(pakfire_jail_run(t->pakfire, cmd_stat_ownership, 0, &output));
249
250 // Check if the file has been mapped to root/root
251 ASSERT_STRING_EQUALS(output, "uid=0 gid=0\n");
252
253 // Success
254 r = EXIT_SUCCESS;
255
256FAIL:
257 if (output)
258 free(output);
259
260 return r;
261}
262
cc6e2264
MT
263static int test_bind(const struct test* t) {
264 struct pakfire_jail* jail = NULL;
265 char* output = NULL;
266 int r = EXIT_FAILURE;
267
268 const char* source = "/";
269 const char* target = "/oldroot";
270
271 const char* argv[] = {
272 "/command", "check-mountpoint", target, NULL,
273 };
274
275 // Create a new jail
276 ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0));
277
278 // Bind-mount nonsense
279 ASSERT_ERRNO(pakfire_jail_bind(jail, NULL, target, 0), EINVAL);
280 ASSERT_ERRNO(pakfire_jail_bind(jail, source, NULL, 0), EINVAL);
281
282 // Bind-mount something
283 ASSERT_SUCCESS(pakfire_jail_bind(jail, source, target, MS_RDONLY));
284
285 // Check if the mount actually works
ccdd2e95 286 ASSERT_SUCCESS(pakfire_jail_exec(jail, argv, NULL, NULL, NULL));
cc6e2264
MT
287
288 // Success
289 r = EXIT_SUCCESS;
290
291FAIL:
292 if (jail)
293 pakfire_jail_unref(jail);
294
295 return r;
296}
297
2015cb92
MT
298static int callback_stdin(struct pakfire* pakfire, void* data, int fd) {
299 const char* lines[] = { "a", "b", "c", NULL };
300 int r;
301
302 for (const char** line = lines; *line; line++) {
303 r = dprintf(fd, "%s\n", *line);
304 if (r < 0) {
305 LOG_ERROR("Could not write line (%s) to stdin: %m\n", *line);
306
307 return 1;
308 }
309 }
310
311 return 0;
312}
313
314static int test_communicate(const struct test* t) {
315 struct pakfire_jail* jail = NULL;
316 int r = EXIT_FAILURE;
317
318 const char* argv[] = {
319 "/command", "pipe", NULL,
320 };
321
322 // Create a new jail
323 ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0));
324
325 // Check if the mount actually works
ccdd2e95 326 ASSERT_SUCCESS(pakfire_jail_exec(jail, argv, callback_stdin, NULL, NULL));
2015cb92
MT
327
328 // Success
329 r = EXIT_SUCCESS;
330
331FAIL:
332 if (jail)
333 pakfire_jail_unref(jail);
334
335 return r;
336}
337
b0ead88b 338int main(int argc, const char* argv[]) {
3334e9c0 339 testsuite_add_test(test_create);
32d5f21d 340 testsuite_add_test(test_env);
0bd84dc1 341 testsuite_add_test(test_exec);
6962faab 342 testsuite_add_test(test_launch_into_cgroup);
17841bb8 343 testsuite_add_test(test_nice);
9bc7ec4b 344 testsuite_add_test(test_memory_limit);
d3b93302 345 testsuite_add_test(test_pid_limit);
bddfe668 346 testsuite_add_test(test_file_ownership);
cc6e2264 347 testsuite_add_test(test_bind);
2015cb92 348 testsuite_add_test(test_communicate);
3334e9c0 349
b0ead88b 350 return testsuite_run(argc, argv);
3334e9c0 351}