]> git.ipfire.org Git - pakfire.git/blob - tests/libpakfire/jail.c
build: Move interactive flag from jail
[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 return EXIT_SUCCESS;
54
55 FAIL:
56 return EXIT_FAILURE;
57 }
58
59 static int test_env(const struct test* t) {
60 struct pakfire_jail* jail = NULL;
61
62 // Create a new jail
63 ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0));
64
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
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
87 static int test_exec(const struct test* t) {
88 struct pakfire_jail* jail = NULL;
89
90 // Create a new jail
91 ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0));
92
93 // Try to execute something
94 ASSERT_SUCCESS(pakfire_jail_exec(jail, cmd_hello_world, NULL));
95
96 // Destroy it
97 ASSERT_NULL(pakfire_jail_unref(jail));
98
99 return EXIT_SUCCESS;
100
101 FAIL:
102 return EXIT_FAILURE;
103 }
104
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
120 ASSERT(pakfire_jail_exec(jail, cmd_hello_world, NULL) == 0);
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
135 static int test_nice(const struct test* t) {
136 struct pakfire_jail* jail = NULL;
137 char* output = NULL;
138 int r = EXIT_FAILURE;
139
140 const char* argv[] = {
141 "/command", "print-nice", NULL,
142 };
143
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
154 // Check if the nice level has been set
155 ASSERT_SUCCESS(pakfire_jail_exec(jail, argv, &output));
156 ASSERT_STRING_EQUALS(output, "5\n");
157
158 // Success
159 r = EXIT_SUCCESS;
160
161 FAIL:
162 if (jail)
163 pakfire_jail_unref(jail);
164 if (output)
165 free(output);
166
167 return r;
168 }
169
170 static int test_memory_limit(const struct test* t) {
171 struct pakfire_cgroup* cgroup = NULL;
172 struct pakfire_jail* jail = NULL;
173 int r = EXIT_FAILURE;
174
175
176 // Create cgroup
177 ASSERT_SUCCESS(pakfire_cgroup_open(&cgroup, t->pakfire, "pakfire-test", 0));
178
179 // Create jail
180 ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0));
181
182 // Connect jail to the cgroup
183 ASSERT_SUCCESS(pakfire_jail_set_cgroup(jail, cgroup));
184
185 // Set a memory limit of 100 MiB
186 ASSERT_SUCCESS(pakfire_cgroup_set_memory_limit(cgroup, 100 * 1024 * 1024));
187
188 // Try to exhaust all memory
189 ASSERT_FAILURE(pakfire_jail_exec(jail, cmd_exhaust_memory, NULL));
190
191 // A fork bomb should also exhaust all memory
192 ASSERT_FAILURE(pakfire_jail_exec(jail, cmd_fork_bomb, NULL));
193
194 // Success
195 r = EXIT_SUCCESS;
196
197 FAIL:
198 if (jail)
199 pakfire_jail_unref(jail);
200 if (cgroup) {
201 pakfire_cgroup_destroy(cgroup);
202 pakfire_cgroup_unref(cgroup);
203 }
204
205 return r;
206 }
207
208 static int test_pid_limit(const struct test* t) {
209 struct pakfire_cgroup* cgroup = NULL;
210 struct pakfire_jail* jail = NULL;
211 int r = EXIT_FAILURE;
212
213 // Create cgroup
214 ASSERT_SUCCESS(pakfire_cgroup_open(&cgroup, t->pakfire, "pakfire-test", 0));
215
216 // Create jail
217 ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0));
218
219 // Connect jail to the cgroup
220 ASSERT_SUCCESS(pakfire_jail_set_cgroup(jail, cgroup));
221
222 // Set a PID limit of 100 processes
223 ASSERT_SUCCESS(pakfire_cgroup_set_pid_limit(cgroup, 100));
224
225 // Try to fork as many processes as possible
226 ASSERT_FAILURE(pakfire_jail_exec(jail, cmd_fork_bomb, NULL));
227
228 // Success
229 r = EXIT_SUCCESS;
230
231 FAIL:
232 if (jail)
233 pakfire_jail_unref(jail);
234 if (cgroup) {
235 pakfire_cgroup_destroy(cgroup);
236 pakfire_cgroup_unref(cgroup);
237 }
238
239 return r;
240 }
241
242 static int test_file_ownership(const struct test* t) {
243 int r = EXIT_FAILURE;
244 char* output = NULL;
245
246 // Execute a simple command
247 ASSERT_SUCCESS(pakfire_jail_run(t->pakfire, cmd_stat_ownership, 0, &output));
248
249 // Check if the file has been mapped to root/root
250 ASSERT_STRING_EQUALS(output, "uid=0 gid=0\n");
251
252 // Success
253 r = EXIT_SUCCESS;
254
255 FAIL:
256 if (output)
257 free(output);
258
259 return r;
260 }
261
262 static int test_bind(const struct test* t) {
263 struct pakfire_jail* jail = NULL;
264 char* output = NULL;
265 int r = EXIT_FAILURE;
266
267 const char* source = "/";
268 const char* target = "/oldroot";
269
270 const char* argv[] = {
271 "/command", "check-mountpoint", target, NULL,
272 };
273
274 // Create a new jail
275 ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0));
276
277 // Bind-mount nonsense
278 ASSERT_ERRNO(pakfire_jail_bind(jail, NULL, target, 0), EINVAL);
279 ASSERT_ERRNO(pakfire_jail_bind(jail, source, NULL, 0), EINVAL);
280
281 // Bind-mount something
282 ASSERT_SUCCESS(pakfire_jail_bind(jail, source, target, MS_RDONLY));
283
284 // Check if the mount actually works
285 ASSERT_SUCCESS(pakfire_jail_exec(jail, argv, NULL));
286
287 // Success
288 r = EXIT_SUCCESS;
289
290 FAIL:
291 if (jail)
292 pakfire_jail_unref(jail);
293
294 return r;
295 }
296
297 int main(int argc, const char* argv[]) {
298 testsuite_add_test(test_create);
299 testsuite_add_test(test_env);
300 testsuite_add_test(test_exec);
301 testsuite_add_test(test_launch_into_cgroup);
302 testsuite_add_test(test_nice);
303 testsuite_add_test(test_memory_limit);
304 testsuite_add_test(test_pid_limit);
305 testsuite_add_test(test_file_ownership);
306 testsuite_add_test(test_bind);
307
308 return testsuite_run(argc, argv);
309 }