]> git.ipfire.org Git - people/ms/pakfire.git/blob - tests/libpakfire/jail.c
jail: Implement bind-mounting anything into the jail
[people/ms/pakfire.git] / tests / libpakfire / jail.c
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
21 #include <sys/mount.h>
22
23 #include <pakfire/cgroup.h>
24 #include <pakfire/jail.h>
25
26 #include "../testsuite.h"
27
28 static const char* cmd_hello_world[] = {
29 "/command", "echo", "Hello World!", NULL,
30 };
31
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
40 static const char* cmd_stat_ownership[] = {
41 "/command", "stat-ownership", NULL,
42 };
43
44 static int test_create(const struct test* t) {
45 struct pakfire_jail* jail = NULL;
46
47 // Create a new jail
48 ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0));
49
50 // Destroy it
51 ASSERT_NULL(pakfire_jail_unref(jail));
52
53 // Create an interactive jail
54 ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, PAKFIRE_JAIL_INTERACTIVE));
55
56 // Destroy it again
57 ASSERT_NULL(pakfire_jail_unref(jail));
58
59 return EXIT_SUCCESS;
60
61 FAIL:
62 return EXIT_FAILURE;
63 }
64
65 static int test_env(const struct test* t) {
66 struct pakfire_jail* jail = NULL;
67
68 // Create a new jail
69 ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0));
70
71 // Check if the default variables are set
72 ASSERT(pakfire_jail_get_env(jail, "LANG"));
73 ASSERT(pakfire_jail_get_env(jail, "TERM"));
74
75 // Fetch a non-existing environment variable
76 ASSERT_NULL(pakfire_jail_get_env(jail, "VARIABLE"));
77
78 // Set a variable
79 ASSERT_SUCCESS(pakfire_jail_set_env(jail, "VARIABLE", "VALUE"));
80
81 // Read the value back
82 ASSERT_STRING_EQUALS(pakfire_jail_get_env(jail, "VARIABLE"), "VALUE");
83
84 // Destroy it
85 ASSERT_NULL(pakfire_jail_unref(jail));
86
87 return EXIT_SUCCESS;
88
89 FAIL:
90 return EXIT_FAILURE;
91 }
92
93 static int test_exec(const struct test* t) {
94 struct pakfire_jail* jail = NULL;
95
96 // Create a new jail
97 ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0));
98
99 // Try to execute something
100 ASSERT_SUCCESS(pakfire_jail_exec(jail, cmd_hello_world, NULL));
101
102 // Destroy it
103 ASSERT_NULL(pakfire_jail_unref(jail));
104
105 return EXIT_SUCCESS;
106
107 FAIL:
108 return EXIT_FAILURE;
109 }
110
111 static int test_launch_into_cgroup(const struct test* t) {
112 struct pakfire_cgroup* cgroup = NULL;
113 struct pakfire_jail* jail = NULL;
114 int r = EXIT_FAILURE;
115
116 // Create a new cgroup
117 ASSERT_SUCCESS(pakfire_cgroup_open(&cgroup, t->pakfire, "pakfire-test", 0));
118
119 // Create a new jail
120 ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0));
121
122 // Connect jail to the cgroup
123 ASSERT_SUCCESS(pakfire_jail_set_cgroup(jail, cgroup));
124
125 // Run command
126 ASSERT(pakfire_jail_exec(jail, cmd_hello_world, NULL) == 0);
127
128 r = EXIT_SUCCESS;
129
130 FAIL:
131 if (cgroup) {
132 pakfire_cgroup_destroy(cgroup);
133 pakfire_cgroup_unref(cgroup);
134 }
135 if (jail)
136 pakfire_jail_unref(jail);
137
138 return r;
139 }
140
141 static int test_nice(const struct test* t) {
142 struct pakfire_jail* jail = NULL;
143 char* output = NULL;
144 int r = EXIT_FAILURE;
145
146 const char* argv[] = {
147 "/command", "print-nice", NULL,
148 };
149
150 // Create a new jail
151 ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0));
152
153 // Set invalid nice levels
154 ASSERT_ERRNO(pakfire_jail_nice(jail, 100), EINVAL);
155 ASSERT_ERRNO(pakfire_jail_nice(jail, -100), EINVAL);
156
157 // Set something sane
158 ASSERT_SUCCESS(pakfire_jail_nice(jail, 5));
159
160 // Check if the nice level has been set
161 ASSERT_SUCCESS(pakfire_jail_exec(jail, argv, &output));
162 ASSERT_STRING_EQUALS(output, "5\n");
163
164 // Success
165 r = EXIT_SUCCESS;
166
167 FAIL:
168 if (jail)
169 pakfire_jail_unref(jail);
170 if (output)
171 free(output);
172
173 return r;
174 }
175
176 static int test_memory_limit(const struct test* t) {
177 struct pakfire_cgroup* cgroup = NULL;
178 struct pakfire_jail* jail = NULL;
179 int r = EXIT_FAILURE;
180
181
182 // Create cgroup
183 ASSERT_SUCCESS(pakfire_cgroup_open(&cgroup, t->pakfire, "pakfire-test", 0));
184
185 // Create jail
186 ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0));
187
188 // Connect jail to the cgroup
189 ASSERT_SUCCESS(pakfire_jail_set_cgroup(jail, cgroup));
190
191 // Set a memory limit of 100 MiB
192 ASSERT_SUCCESS(pakfire_cgroup_set_memory_limit(cgroup, 100 * 1024 * 1024));
193
194 // Try to exhaust all memory
195 ASSERT_FAILURE(pakfire_jail_exec(jail, cmd_exhaust_memory, NULL));
196
197 // A fork bomb should also exhaust all memory
198 ASSERT_FAILURE(pakfire_jail_exec(jail, cmd_fork_bomb, NULL));
199
200 // Success
201 r = EXIT_SUCCESS;
202
203 FAIL:
204 if (jail)
205 pakfire_jail_unref(jail);
206 if (cgroup) {
207 pakfire_cgroup_destroy(cgroup);
208 pakfire_cgroup_unref(cgroup);
209 }
210
211 return r;
212 }
213
214 static int test_pid_limit(const struct test* t) {
215 struct pakfire_cgroup* cgroup = NULL;
216 struct pakfire_jail* jail = NULL;
217 int r = EXIT_FAILURE;
218
219 // Create cgroup
220 ASSERT_SUCCESS(pakfire_cgroup_open(&cgroup, t->pakfire, "pakfire-test", 0));
221
222 // Create jail
223 ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0));
224
225 // Connect jail to the cgroup
226 ASSERT_SUCCESS(pakfire_jail_set_cgroup(jail, cgroup));
227
228 // Set a PID limit of 100 processes
229 ASSERT_SUCCESS(pakfire_cgroup_set_pid_limit(cgroup, 100));
230
231 // Try to fork as many processes as possible
232 ASSERT_FAILURE(pakfire_jail_exec(jail, cmd_fork_bomb, NULL));
233
234 // Success
235 r = EXIT_SUCCESS;
236
237 FAIL:
238 if (jail)
239 pakfire_jail_unref(jail);
240 if (cgroup) {
241 pakfire_cgroup_destroy(cgroup);
242 pakfire_cgroup_unref(cgroup);
243 }
244
245 return r;
246 }
247
248 static int test_file_ownership(const struct test* t) {
249 int r = EXIT_FAILURE;
250 char* output = NULL;
251
252 // Execute a simple command
253 ASSERT_SUCCESS(pakfire_jail_run(t->pakfire, cmd_stat_ownership, 0, &output));
254
255 // Check if the file has been mapped to root/root
256 ASSERT_STRING_EQUALS(output, "uid=0 gid=0\n");
257
258 // Success
259 r = EXIT_SUCCESS;
260
261 FAIL:
262 if (output)
263 free(output);
264
265 return r;
266 }
267
268 static int test_bind(const struct test* t) {
269 struct pakfire_jail* jail = NULL;
270 char* output = NULL;
271 int r = EXIT_FAILURE;
272
273 const char* source = "/";
274 const char* target = "/oldroot";
275
276 const char* argv[] = {
277 "/command", "check-mountpoint", target, NULL,
278 };
279
280 // Create a new jail
281 ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0));
282
283 // Bind-mount nonsense
284 ASSERT_ERRNO(pakfire_jail_bind(jail, NULL, target, 0), EINVAL);
285 ASSERT_ERRNO(pakfire_jail_bind(jail, source, NULL, 0), EINVAL);
286
287 // Bind-mount something
288 ASSERT_SUCCESS(pakfire_jail_bind(jail, source, target, MS_RDONLY));
289
290 // Check if the mount actually works
291 ASSERT_SUCCESS(pakfire_jail_exec(jail, argv, NULL));
292
293 // Success
294 r = EXIT_SUCCESS;
295
296 FAIL:
297 if (jail)
298 pakfire_jail_unref(jail);
299
300 return r;
301 }
302
303 int main(int argc, const char* argv[]) {
304 testsuite_add_test(test_create);
305 testsuite_add_test(test_env);
306 testsuite_add_test(test_exec);
307 testsuite_add_test(test_launch_into_cgroup);
308 testsuite_add_test(test_nice);
309 testsuite_add_test(test_memory_limit);
310 testsuite_add_test(test_pid_limit);
311 testsuite_add_test(test_file_ownership);
312 testsuite_add_test(test_bind);
313
314 return testsuite_run(argc, argv);
315 }