]>
Commit | Line | Data |
---|---|---|
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 |
28 | static const char* cmd_hello_world[] = { |
29 | "/command", "echo", "Hello World!", NULL, | |
3334e9c0 MT |
30 | }; |
31 | ||
93550e9b MT |
32 | static const char* cmd_exhaust_memory[] = { |
33 | "/command", "exhaust-memory", NULL, | |
34 | }; | |
35 | ||
36 | static const char* cmd_fork_bomb[] = { | |
37 | "/command", "fork-bomb", NULL, | |
38 | }; | |
39 | ||
bddfe668 MT |
40 | static const char* cmd_stat_ownership[] = { |
41 | "/command", "stat-ownership", NULL, | |
42 | }; | |
43 | ||
3334e9c0 MT |
44 | static int test_create(const struct test* t) { |
45 | struct pakfire_jail* jail = NULL; | |
46 | ||
47 | // Create a new jail | |
1b55a8bf | 48 | ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire)); |
3334e9c0 MT |
49 | |
50 | // Destroy it | |
51 | ASSERT_NULL(pakfire_jail_unref(jail)); | |
52 | ||
53 | return EXIT_SUCCESS; | |
54 | ||
55 | FAIL: | |
56 | return EXIT_FAILURE; | |
57 | } | |
58 | ||
39a10052 MT |
59 | static int test_exit_code(const struct test* t) { |
60 | struct pakfire_jail* jail = NULL; | |
61 | int r = EXIT_FAILURE; | |
62 | ||
63 | const char* argv[] = { | |
64 | "/command", "exit-with-code", "123", NULL, | |
65 | }; | |
66 | ||
67 | // Create a new jail | |
1b55a8bf | 68 | ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire)); |
39a10052 MT |
69 | |
70 | // Check if we receive the correct exit code | |
1b55a8bf | 71 | ASSERT(pakfire_jail_exec(jail, argv, NULL, NULL, NULL, 0) == 123); |
39a10052 MT |
72 | |
73 | // Success | |
74 | r = EXIT_SUCCESS; | |
75 | ||
76 | FAIL: | |
77 | if (jail) | |
78 | pakfire_jail_unref(jail); | |
79 | ||
80 | return r; | |
81 | } | |
82 | ||
870f7edb MT |
83 | static int test_segv(const struct test* t) { |
84 | struct pakfire_jail* jail = NULL; | |
85 | int r = EXIT_FAILURE; | |
86 | ||
87 | const char* argv[] = { | |
88 | "/command", "segv", NULL, | |
89 | }; | |
90 | ||
91 | // Create a new jail | |
1b55a8bf | 92 | ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire)); |
870f7edb MT |
93 | |
94 | // Check if we receive the correct exit code | |
1b55a8bf | 95 | ASSERT(pakfire_jail_exec(jail, argv, NULL, NULL, NULL, 0) == 139); |
870f7edb MT |
96 | |
97 | // Success | |
98 | r = EXIT_SUCCESS; | |
99 | ||
100 | FAIL: | |
101 | if (jail) | |
102 | pakfire_jail_unref(jail); | |
103 | ||
104 | return r; | |
105 | } | |
106 | ||
32d5f21d MT |
107 | static int test_env(const struct test* t) { |
108 | struct pakfire_jail* jail = NULL; | |
109 | ||
110 | // Create a new jail | |
1b55a8bf | 111 | ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire)); |
32d5f21d | 112 | |
d5bc8fe0 MT |
113 | // Check if the default variables are set |
114 | ASSERT(pakfire_jail_get_env(jail, "LANG")); | |
115 | ASSERT(pakfire_jail_get_env(jail, "TERM")); | |
116 | ||
32d5f21d MT |
117 | // Fetch a non-existing environment variable |
118 | ASSERT_NULL(pakfire_jail_get_env(jail, "VARIABLE")); | |
119 | ||
120 | // Set a variable | |
121 | ASSERT_SUCCESS(pakfire_jail_set_env(jail, "VARIABLE", "VALUE")); | |
122 | ||
123 | // Read the value back | |
124 | ASSERT_STRING_EQUALS(pakfire_jail_get_env(jail, "VARIABLE"), "VALUE"); | |
125 | ||
126 | // Destroy it | |
127 | ASSERT_NULL(pakfire_jail_unref(jail)); | |
128 | ||
129 | return EXIT_SUCCESS; | |
130 | ||
131 | FAIL: | |
132 | return EXIT_FAILURE; | |
133 | } | |
134 | ||
0bd84dc1 MT |
135 | static int test_exec(const struct test* t) { |
136 | struct pakfire_jail* jail = NULL; | |
137 | ||
0bd84dc1 | 138 | // Create a new jail |
1b55a8bf | 139 | ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire)); |
0bd84dc1 MT |
140 | |
141 | // Try to execute something | |
1b55a8bf | 142 | ASSERT_SUCCESS(pakfire_jail_exec(jail, cmd_hello_world, NULL, NULL, NULL, 0)); |
0bd84dc1 MT |
143 | |
144 | // Destroy it | |
145 | ASSERT_NULL(pakfire_jail_unref(jail)); | |
146 | ||
147 | return EXIT_SUCCESS; | |
148 | ||
149 | FAIL: | |
150 | return EXIT_FAILURE; | |
151 | } | |
32d5f21d | 152 | |
6962faab MT |
153 | static int test_launch_into_cgroup(const struct test* t) { |
154 | struct pakfire_cgroup* cgroup = NULL; | |
155 | struct pakfire_jail* jail = NULL; | |
156 | int r = EXIT_FAILURE; | |
157 | ||
158 | // Create a new cgroup | |
35bf392c | 159 | ASSERT_SUCCESS(pakfire_cgroup_open(&cgroup, t->ctx, "pakfire-test", 0)); |
6962faab MT |
160 | |
161 | // Create a new jail | |
1b55a8bf | 162 | ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire)); |
6962faab MT |
163 | |
164 | // Connect jail to the cgroup | |
165 | ASSERT_SUCCESS(pakfire_jail_set_cgroup(jail, cgroup)); | |
166 | ||
167 | // Run command | |
1b55a8bf | 168 | ASSERT(pakfire_jail_exec(jail, cmd_hello_world, NULL, NULL, NULL, 0) == 0); |
6962faab MT |
169 | |
170 | r = EXIT_SUCCESS; | |
171 | ||
172 | FAIL: | |
173 | if (cgroup) { | |
174 | pakfire_cgroup_destroy(cgroup); | |
175 | pakfire_cgroup_unref(cgroup); | |
176 | } | |
177 | if (jail) | |
178 | pakfire_jail_unref(jail); | |
179 | ||
180 | return r; | |
181 | } | |
182 | ||
17841bb8 MT |
183 | static int test_nice(const struct test* t) { |
184 | struct pakfire_jail* jail = NULL; | |
12b9b39f | 185 | char* output = NULL; |
17841bb8 MT |
186 | int r = EXIT_FAILURE; |
187 | ||
188 | const char* argv[] = { | |
189 | "/command", "print-nice", NULL, | |
190 | }; | |
191 | ||
17841bb8 | 192 | // Create a new jail |
1b55a8bf | 193 | ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire)); |
17841bb8 MT |
194 | |
195 | // Set invalid nice levels | |
196 | ASSERT_ERRNO(pakfire_jail_nice(jail, 100), EINVAL); | |
197 | ASSERT_ERRNO(pakfire_jail_nice(jail, -100), EINVAL); | |
198 | ||
199 | // Set something sane | |
200 | ASSERT_SUCCESS(pakfire_jail_nice(jail, 5)); | |
201 | ||
12b9b39f | 202 | // Check if the nice level has been set |
ccdd2e95 | 203 | ASSERT_SUCCESS(pakfire_jail_exec(jail, argv, |
1b55a8bf | 204 | NULL, pakfire_jail_capture_stdout, &output, 0)); |
12b9b39f | 205 | ASSERT_STRING_EQUALS(output, "5\n"); |
17841bb8 MT |
206 | |
207 | // Success | |
208 | r = EXIT_SUCCESS; | |
209 | ||
210 | FAIL: | |
211 | if (jail) | |
212 | pakfire_jail_unref(jail); | |
12b9b39f | 213 | if (output) |
17841bb8 | 214 | free(output); |
17841bb8 MT |
215 | |
216 | return r; | |
217 | } | |
218 | ||
9bc7ec4b MT |
219 | static int test_memory_limit(const struct test* t) { |
220 | struct pakfire_cgroup* cgroup = NULL; | |
221 | struct pakfire_jail* jail = NULL; | |
222 | int r = EXIT_FAILURE; | |
223 | ||
9bc7ec4b MT |
224 | |
225 | // Create cgroup | |
35bf392c | 226 | ASSERT_SUCCESS(pakfire_cgroup_open(&cgroup, t->ctx, "pakfire-test", 0)); |
9bc7ec4b MT |
227 | |
228 | // Create jail | |
1b55a8bf | 229 | ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire)); |
9bc7ec4b MT |
230 | |
231 | // Connect jail to the cgroup | |
232 | ASSERT_SUCCESS(pakfire_jail_set_cgroup(jail, cgroup)); | |
233 | ||
234 | // Set a memory limit of 100 MiB | |
235 | ASSERT_SUCCESS(pakfire_cgroup_set_memory_limit(cgroup, 100 * 1024 * 1024)); | |
236 | ||
237 | // Try to exhaust all memory | |
1b55a8bf | 238 | ASSERT_FAILURE(pakfire_jail_exec(jail, cmd_exhaust_memory, NULL, NULL, NULL, 0)); |
93550e9b MT |
239 | |
240 | // A fork bomb should also exhaust all memory | |
1b55a8bf | 241 | ASSERT_FAILURE(pakfire_jail_exec(jail, cmd_fork_bomb, NULL, NULL, NULL, 0)); |
9bc7ec4b MT |
242 | |
243 | // Success | |
244 | r = EXIT_SUCCESS; | |
245 | ||
246 | FAIL: | |
247 | if (jail) | |
248 | pakfire_jail_unref(jail); | |
249 | if (cgroup) { | |
250 | pakfire_cgroup_destroy(cgroup); | |
251 | pakfire_cgroup_unref(cgroup); | |
252 | } | |
253 | ||
254 | return r; | |
255 | } | |
256 | ||
d3b93302 MT |
257 | static int test_pid_limit(const struct test* t) { |
258 | struct pakfire_cgroup* cgroup = NULL; | |
259 | struct pakfire_jail* jail = NULL; | |
260 | int r = EXIT_FAILURE; | |
261 | ||
d3b93302 | 262 | // Create cgroup |
35bf392c | 263 | ASSERT_SUCCESS(pakfire_cgroup_open(&cgroup, t->ctx, "pakfire-test", 0)); |
d3b93302 MT |
264 | |
265 | // Create jail | |
1b55a8bf | 266 | ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire)); |
d3b93302 MT |
267 | |
268 | // Connect jail to the cgroup | |
269 | ASSERT_SUCCESS(pakfire_jail_set_cgroup(jail, cgroup)); | |
270 | ||
271 | // Set a PID limit of 100 processes | |
272 | ASSERT_SUCCESS(pakfire_cgroup_set_pid_limit(cgroup, 100)); | |
273 | ||
274 | // Try to fork as many processes as possible | |
1b55a8bf | 275 | ASSERT_FAILURE(pakfire_jail_exec(jail, cmd_fork_bomb, NULL, NULL, NULL, 0)); |
d3b93302 MT |
276 | |
277 | // Success | |
278 | r = EXIT_SUCCESS; | |
279 | ||
280 | FAIL: | |
281 | if (jail) | |
282 | pakfire_jail_unref(jail); | |
283 | if (cgroup) { | |
284 | pakfire_cgroup_destroy(cgroup); | |
285 | pakfire_cgroup_unref(cgroup); | |
286 | } | |
287 | ||
288 | return r; | |
289 | } | |
290 | ||
bddfe668 MT |
291 | static int test_file_ownership(const struct test* t) { |
292 | int r = EXIT_FAILURE; | |
293 | char* output = NULL; | |
294 | ||
295 | // Execute a simple command | |
296 | ASSERT_SUCCESS(pakfire_jail_run(t->pakfire, cmd_stat_ownership, 0, &output)); | |
297 | ||
298 | // Check if the file has been mapped to root/root | |
299 | ASSERT_STRING_EQUALS(output, "uid=0 gid=0\n"); | |
300 | ||
301 | // Success | |
302 | r = EXIT_SUCCESS; | |
303 | ||
304 | FAIL: | |
305 | if (output) | |
306 | free(output); | |
307 | ||
308 | return r; | |
309 | } | |
310 | ||
cc6e2264 MT |
311 | static int test_bind(const struct test* t) { |
312 | struct pakfire_jail* jail = NULL; | |
313 | char* output = NULL; | |
314 | int r = EXIT_FAILURE; | |
315 | ||
316 | const char* source = "/"; | |
317 | const char* target = "/oldroot"; | |
318 | ||
319 | const char* argv[] = { | |
320 | "/command", "check-mountpoint", target, NULL, | |
321 | }; | |
322 | ||
323 | // Create a new jail | |
1b55a8bf | 324 | ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire)); |
cc6e2264 MT |
325 | |
326 | // Bind-mount nonsense | |
327 | ASSERT_ERRNO(pakfire_jail_bind(jail, NULL, target, 0), EINVAL); | |
328 | ASSERT_ERRNO(pakfire_jail_bind(jail, source, NULL, 0), EINVAL); | |
329 | ||
330 | // Bind-mount something | |
331 | ASSERT_SUCCESS(pakfire_jail_bind(jail, source, target, MS_RDONLY)); | |
332 | ||
333 | // Check if the mount actually works | |
1b55a8bf | 334 | ASSERT_SUCCESS(pakfire_jail_exec(jail, argv, NULL, NULL, NULL, 0)); |
cc6e2264 MT |
335 | |
336 | // Success | |
337 | r = EXIT_SUCCESS; | |
338 | ||
339 | FAIL: | |
340 | if (jail) | |
341 | pakfire_jail_unref(jail); | |
342 | ||
343 | return r; | |
344 | } | |
345 | ||
2015cb92 | 346 | static int callback_stdin(struct pakfire* pakfire, void* data, int fd) { |
06b864ae | 347 | int* lines = (int*)data; |
2015cb92 MT |
348 | int r; |
349 | ||
06b864ae MT |
350 | while (*lines > 0) { |
351 | r = dprintf(fd, "LINE %d\n", *lines); | |
2015cb92 | 352 | if (r < 0) { |
06b864ae | 353 | LOG_ERROR("Could not write line (%u) to stdin: %m\n", *lines); |
2015cb92 MT |
354 | |
355 | return 1; | |
356 | } | |
06b864ae MT |
357 | |
358 | // Decrement the lines counter | |
359 | (*lines)--; | |
2015cb92 MT |
360 | } |
361 | ||
06b864ae | 362 | return EOF; |
2015cb92 MT |
363 | } |
364 | ||
365 | static int test_communicate(const struct test* t) { | |
366 | struct pakfire_jail* jail = NULL; | |
367 | int r = EXIT_FAILURE; | |
368 | ||
06b864ae MT |
369 | // How many lines to send? |
370 | int lines = 65535; | |
371 | ||
2015cb92 MT |
372 | const char* argv[] = { |
373 | "/command", "pipe", NULL, | |
374 | }; | |
375 | ||
376 | // Create a new jail | |
1b55a8bf | 377 | ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire)); |
2015cb92 MT |
378 | |
379 | // Check if the mount actually works | |
1b55a8bf | 380 | ASSERT_SUCCESS(pakfire_jail_exec(jail, argv, callback_stdin, NULL, &lines, 0)); |
2015cb92 MT |
381 | |
382 | // Success | |
383 | r = EXIT_SUCCESS; | |
384 | ||
385 | FAIL: | |
386 | if (jail) | |
387 | pakfire_jail_unref(jail); | |
388 | ||
389 | return r; | |
390 | } | |
391 | ||
72d37c72 MT |
392 | static int test_send_one_signal(const struct test* t, |
393 | struct pakfire_jail* jail, const char* signal) { | |
394 | const char* argv[] = { | |
395 | "/command", "send-signal", signal, NULL, | |
396 | }; | |
397 | ||
398 | // Perform the command | |
1b55a8bf | 399 | return pakfire_jail_exec(jail, argv, NULL, NULL, NULL, 0); |
72d37c72 MT |
400 | } |
401 | ||
402 | static int test_send_signal(const struct test* t) { | |
403 | struct pakfire_jail* jail = NULL; | |
404 | int r = EXIT_FAILURE; | |
405 | ||
406 | // Create a new jail | |
1b55a8bf | 407 | ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire)); |
72d37c72 MT |
408 | |
409 | // Sending SIGTERM to ourselves | |
410 | ASSERT(test_send_one_signal(t, jail, "15") == 0); | |
411 | ||
412 | // Sending SIGKILL to ourselves | |
413 | ASSERT(test_send_one_signal(t, jail, "9") == 0); | |
414 | ||
415 | // Sending SIGSTOP to ourselves (this should be ignored by the jail) | |
416 | ASSERT(test_send_one_signal(t, jail, "23") == 0); | |
417 | ||
418 | // Success | |
419 | r = EXIT_SUCCESS; | |
420 | ||
421 | FAIL: | |
422 | if (jail) | |
423 | pakfire_jail_unref(jail); | |
424 | ||
425 | return r; | |
426 | } | |
427 | ||
335b8a44 MT |
428 | static int test_timeout(const struct test* t) { |
429 | struct pakfire_jail* jail = NULL; | |
430 | int r = EXIT_FAILURE; | |
431 | ||
432 | const char* argv[] = { | |
433 | "/command", "sleep", "5", NULL, | |
434 | }; | |
435 | ||
436 | // Create a new jail | |
1b55a8bf | 437 | ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire)); |
335b8a44 MT |
438 | |
439 | // Set a timeout of one second | |
440 | ASSERT_SUCCESS(pakfire_jail_set_timeout(jail, 1)); | |
441 | ||
442 | // Check if we receive the correct exit code | |
1b55a8bf | 443 | ASSERT(pakfire_jail_exec(jail, argv, NULL, NULL, NULL, 0) == 139); |
335b8a44 MT |
444 | |
445 | // Success | |
446 | r = EXIT_SUCCESS; | |
447 | ||
448 | FAIL: | |
449 | if (jail) | |
450 | pakfire_jail_unref(jail); | |
451 | ||
452 | return r; | |
453 | } | |
454 | ||
b0ead88b | 455 | int main(int argc, const char* argv[]) { |
f96ed3ac MT |
456 | testsuite_add_test(test_create, TEST_WANTS_PAKFIRE); |
457 | testsuite_add_test(test_exit_code, TEST_WANTS_PAKFIRE); | |
458 | testsuite_add_test(test_segv, TEST_WANTS_PAKFIRE); | |
459 | testsuite_add_test(test_env, TEST_WANTS_PAKFIRE); | |
460 | testsuite_add_test(test_exec, TEST_WANTS_PAKFIRE); | |
461 | testsuite_add_test(test_launch_into_cgroup, TEST_WANTS_PAKFIRE); | |
462 | testsuite_add_test(test_nice, TEST_WANTS_PAKFIRE); | |
463 | testsuite_add_test(test_memory_limit, TEST_WANTS_PAKFIRE); | |
464 | testsuite_add_test(test_pid_limit, TEST_WANTS_PAKFIRE); | |
465 | testsuite_add_test(test_file_ownership, TEST_WANTS_PAKFIRE); | |
466 | testsuite_add_test(test_bind, TEST_WANTS_PAKFIRE); | |
467 | testsuite_add_test(test_communicate, TEST_WANTS_PAKFIRE); | |
468 | testsuite_add_test(test_send_signal, TEST_WANTS_PAKFIRE); | |
469 | testsuite_add_test(test_timeout, TEST_WANTS_PAKFIRE); | |
3334e9c0 | 470 | |
b0ead88b | 471 | return testsuite_run(argc, argv); |
3334e9c0 | 472 | } |