]>
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 | ||
32d5f21d MT |
59 | static 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 | ||
83 | FAIL: | |
84 | return EXIT_FAILURE; | |
85 | } | |
86 | ||
0bd84dc1 MT |
87 | static 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 | ||
101 | FAIL: | |
102 | return EXIT_FAILURE; | |
103 | } | |
32d5f21d | 104 | |
6962faab MT |
105 | static 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 | ||
124 | FAIL: | |
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 |
135 | static 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 | ||
162 | FAIL: | |
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 |
171 | static 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 | ||
198 | FAIL: | |
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 |
209 | static 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 | ||
232 | FAIL: | |
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 |
243 | static 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 | ||
256 | FAIL: | |
257 | if (output) | |
258 | free(output); | |
259 | ||
260 | return r; | |
261 | } | |
262 | ||
cc6e2264 MT |
263 | static 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 | ||
291 | FAIL: | |
292 | if (jail) | |
293 | pakfire_jail_unref(jail); | |
294 | ||
295 | return r; | |
296 | } | |
297 | ||
2015cb92 MT |
298 | static 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 | ||
314 | static 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 | ||
331 | FAIL: | |
332 | if (jail) | |
333 | pakfire_jail_unref(jail); | |
334 | ||
335 | return r; | |
336 | } | |
337 | ||
b0ead88b | 338 | int 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 | } |