]>
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 | |
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 | ||
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 | |
68 | ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0)); | |
69 | ||
70 | // Check if we receive the correct exit code | |
71 | ASSERT(pakfire_jail_exec(jail, argv, NULL, NULL, NULL) == 123); | |
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 | |
92 | ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0)); | |
93 | ||
94 | // Check if we receive the correct exit code | |
95 | ASSERT(pakfire_jail_exec(jail, argv, NULL, NULL, NULL) == 139); | |
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 | |
d639929b | 111 | ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0)); |
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 MT |
138 | // Create a new jail |
139 | ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0)); | |
140 | ||
141 | // Try to execute something | |
ccdd2e95 | 142 | ASSERT_SUCCESS(pakfire_jail_exec(jail, cmd_hello_world, NULL, NULL, NULL)); |
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 | |
159 | ASSERT_SUCCESS(pakfire_cgroup_open(&cgroup, t->pakfire, "pakfire-test", 0)); | |
160 | ||
161 | // Create a new jail | |
162 | ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0)); | |
163 | ||
164 | // Connect jail to the cgroup | |
165 | ASSERT_SUCCESS(pakfire_jail_set_cgroup(jail, cgroup)); | |
166 | ||
167 | // Run command | |
ccdd2e95 | 168 | ASSERT(pakfire_jail_exec(jail, cmd_hello_world, NULL, NULL, NULL) == 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 MT |
192 | // Create a new jail |
193 | ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0)); | |
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 MT |
203 | ASSERT_SUCCESS(pakfire_jail_exec(jail, argv, |
204 | NULL, pakfire_jail_capture_stdout, &output)); | |
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 | |
226 | ASSERT_SUCCESS(pakfire_cgroup_open(&cgroup, t->pakfire, "pakfire-test", 0)); | |
227 | ||
228 | // Create jail | |
229 | ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0)); | |
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 | |
ccdd2e95 | 238 | ASSERT_FAILURE(pakfire_jail_exec(jail, cmd_exhaust_memory, NULL, NULL, NULL)); |
93550e9b MT |
239 | |
240 | // A fork bomb should also exhaust all memory | |
ccdd2e95 | 241 | ASSERT_FAILURE(pakfire_jail_exec(jail, cmd_fork_bomb, NULL, NULL, NULL)); |
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 MT |
262 | // Create cgroup |
263 | ASSERT_SUCCESS(pakfire_cgroup_open(&cgroup, t->pakfire, "pakfire-test", 0)); | |
264 | ||
265 | // Create jail | |
266 | ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0)); | |
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 | |
ccdd2e95 | 275 | ASSERT_FAILURE(pakfire_jail_exec(jail, cmd_fork_bomb, NULL, NULL, NULL)); |
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 | |
324 | ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0)); | |
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 | |
ccdd2e95 | 334 | ASSERT_SUCCESS(pakfire_jail_exec(jail, argv, NULL, NULL, NULL)); |
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 MT |
346 | static int callback_stdin(struct pakfire* pakfire, void* data, int fd) { |
347 | const char* lines[] = { "a", "b", "c", NULL }; | |
348 | int r; | |
349 | ||
350 | for (const char** line = lines; *line; line++) { | |
351 | r = dprintf(fd, "%s\n", *line); | |
352 | if (r < 0) { | |
353 | LOG_ERROR("Could not write line (%s) to stdin: %m\n", *line); | |
354 | ||
355 | return 1; | |
356 | } | |
357 | } | |
358 | ||
359 | return 0; | |
360 | } | |
361 | ||
362 | static int test_communicate(const struct test* t) { | |
363 | struct pakfire_jail* jail = NULL; | |
364 | int r = EXIT_FAILURE; | |
365 | ||
366 | const char* argv[] = { | |
367 | "/command", "pipe", NULL, | |
368 | }; | |
369 | ||
370 | // Create a new jail | |
371 | ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0)); | |
372 | ||
373 | // Check if the mount actually works | |
ccdd2e95 | 374 | ASSERT_SUCCESS(pakfire_jail_exec(jail, argv, callback_stdin, NULL, NULL)); |
2015cb92 MT |
375 | |
376 | // Success | |
377 | r = EXIT_SUCCESS; | |
378 | ||
379 | FAIL: | |
380 | if (jail) | |
381 | pakfire_jail_unref(jail); | |
382 | ||
383 | return r; | |
384 | } | |
385 | ||
b0ead88b | 386 | int main(int argc, const char* argv[]) { |
3334e9c0 | 387 | testsuite_add_test(test_create); |
39a10052 | 388 | testsuite_add_test(test_exit_code); |
870f7edb | 389 | testsuite_add_test(test_segv); |
32d5f21d | 390 | testsuite_add_test(test_env); |
0bd84dc1 | 391 | testsuite_add_test(test_exec); |
6962faab | 392 | testsuite_add_test(test_launch_into_cgroup); |
17841bb8 | 393 | testsuite_add_test(test_nice); |
9bc7ec4b | 394 | testsuite_add_test(test_memory_limit); |
d3b93302 | 395 | testsuite_add_test(test_pid_limit); |
bddfe668 | 396 | testsuite_add_test(test_file_ownership); |
cc6e2264 | 397 | testsuite_add_test(test_bind); |
2015cb92 | 398 | testsuite_add_test(test_communicate); |
3334e9c0 | 399 | |
b0ead88b | 400 | return testsuite_run(argc, argv); |
3334e9c0 | 401 | } |