]> git.proxmox.com Git - mirror_lxc.git/blame - src/tests/mount_injection.c
tests: include config.h
[mirror_lxc.git] / src / tests / mount_injection.c
CommitLineData
d81423f2
LT
1/* mount_injection
2 *
3 * Copyright © 2018 Elizaveta Tretiakova <elizabet.tretyakova@gmail.com>.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2, as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
e49c56d6 19#include "config.h"
d81423f2 20
d81423f2
LT
21#include <fcntl.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <lxc/lxccontainer.h>
26#include <lxc/list.h>
27#include <string.h>
28#include <sys/mount.h>
29#include <sys/stat.h>
30#include <sys/types.h>
31#include <unistd.h>
32
f994bc87 33#include "config.h"
d81423f2
LT
34#include "lxctest.h"
35#include "utils.h"
36
37#define NAME "mount_injection_test-"
38#define TEMPLATE P_tmpdir"/mount_injection_XXXXXX"
39
c8c568c8 40struct mountinfo_data {
d81423f2
LT
41 const char *mount_root;
42 const char *mount_point;
43 const char *fstype;
44 const char *mount_source;
45 const char *message;
c8c568c8 46 bool should_be_present;
d81423f2
LT
47};
48
49static int comp_field(char *line, const char *str, int nfields)
50{
51 char *p, *p2;
52 int i, ret;
53
54 if(!line)
55 return -1;
56
57 if (!str)
58 return 0;
59
60 for (p = line, i = 0; p && i < nfields; i++)
61 p = strchr(p + 1, ' ');
62 if (!p)
63 return -1;
64 p2 = strchr(p + 1, ' ');
65 if (p2)
66 *p2 = '\0';
67 ret = strcmp(p + 1, str);
68 if (p2)
69 *p2 = ' ';
70 return ret;
71}
72
73static int find_in_proc_mounts(void *data)
74{
75 char buf[LXC_LINELEN];
76 FILE *f;
643bcac9 77 struct mountinfo_data *mdata = (struct mountinfo_data *)data;
d81423f2 78
c8c568c8 79 fprintf(stderr, "%s", mdata->message);
d81423f2
LT
80
81 f = fopen("/proc/self/mountinfo", "r");
82 if (!f)
83 return 0;
643bcac9 84
d81423f2 85 while (fgets(buf, LXC_LINELEN, f)) {
643bcac9
CB
86 char *buf2;
87
88 /* checking mount_root is tricky since it will be prefixed with
89 * whatever path was the source of the mount in the original
90 * mount namespace. So only verify it when we know that root is
91 * in fact "/".
92 */
93 if (mdata->mount_root && comp_field(buf, mdata->mount_root, 3) != 0)
94 continue;
95
96 if (comp_field(buf, mdata->mount_point, 4) != 0)
97 continue;
98
99 if (!mdata->fstype || !mdata->mount_source)
100 goto on_success;
101
102 buf2 = strchr(buf, '-');
103 if (comp_field(buf2, mdata->fstype, 1) != 0 ||
104 comp_field(buf2, mdata->mount_source, 2) != 0)
105 continue;
106
107 on_success:
108 fclose(f);
109 fprintf(stderr, "PRESENT\n");
110 if (mdata->should_be_present)
111 _exit(EXIT_SUCCESS);
112
113 _exit(EXIT_FAILURE);
d81423f2 114 }
643bcac9 115
d81423f2 116 fclose(f);
c8c568c8
LT
117 fprintf(stderr, "MISSING\n");
118 if (!mdata->should_be_present)
119 _exit(EXIT_SUCCESS);
643bcac9 120
d81423f2
LT
121 _exit(EXIT_FAILURE);
122}
123
c8c568c8 124static int check_containers_mountinfo(struct lxc_container *c, struct mountinfo_data *d)
d81423f2
LT
125{
126 pid_t pid;
127 int ret = -1;
128 lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
129
130 ret = c->attach(c, find_in_proc_mounts, d, &attach_options, &pid);
131 if (ret < 0) {
132 fprintf(stderr, "Check of the container's mountinfo failed\n");
133 return ret;
134 }
135
136 ret = wait_for_pid(pid);
137 if (ret < 0)
643bcac9 138 fprintf(stderr, "Attached function failed\n");
d81423f2
LT
139
140 return ret;
141}
142
143/* config_items: NULL-terminated array of config pairs */
144static int perform_container_test(const char *name, const char *config_items[])
145{
146 int i;
147 char *sret;
148 char template_log[sizeof(TEMPLATE)], template_dir[sizeof(TEMPLATE)],
f994bc87
CB
149 device_message[4096],
150 dir_message[4096],
151 fs_message[4096];
d81423f2
LT
152 struct lxc_container *c;
153 struct lxc_mount mnt;
154 struct lxc_log log;
155 int ret = -1, dev_msg_size = sizeof("Check urandom device injected into "" - ") - 1 + strlen(name) + 1,
117deb70
LT
156 dir_msg_size = sizeof("Check dir "" injected into "" - ") - 1 + sizeof(TEMPLATE) - 1 + strlen(name) + 1,
157 fs_msg_size = sizeof("Check devtmpfs injected into "" - ") - 1 + strlen(name) + 1;
c8c568c8 158 struct mountinfo_data device = {
117deb70 159 .mount_root = "/urandom",
d81423f2 160 .mount_point = "/mnt/mount_injection_test_urandom",
117deb70 161 .fstype = NULL,
d81423f2 162 .mount_source = "/dev/urandom",
c8c568c8
LT
163 .message = "",
164 .should_be_present = true
d81423f2 165 }, dir = {
643bcac9 166 .mount_root = NULL,
d81423f2 167 .mount_point = template_dir,
643bcac9 168 .fstype = NULL,
d81423f2 169 .mount_source = NULL,
c8c568c8
LT
170 .message = "",
171 .should_be_present = true
117deb70
LT
172 }, fs = {
173 .mount_root = "/",
174 .mount_point = "/mnt/mount_injection_test_devtmpfs",
175 .fstype = "devtmpfs",
176 .mount_source = NULL,
177 .message = "",
178 .should_be_present = true
d81423f2
LT
179 };
180
181 /* Temp paths and messages setup */
182 strcpy(template_dir, TEMPLATE);
183 sret = mkdtemp(template_dir);
184 if (!sret) {
185 lxc_error("Failed to create temporary src file for container %s\n", name);
186 exit(EXIT_FAILURE);
187 }
188
189 ret = snprintf(device_message, dev_msg_size, "Check urandom device injected into %s - ", name);
190 if (ret < 0 || ret >= dev_msg_size) {
191 fprintf(stderr, "Failed to create message for dev\n");
192 exit(EXIT_FAILURE);
193 }
194 device.message = &device_message[0];
195
196 ret = snprintf(dir_message, dir_msg_size, "Check dir %s injected into %s - ", template_dir, name);
197 if (ret < 0 || ret >= dir_msg_size) {
198 fprintf(stderr, "Failed to create message for dir\n");
199 exit(EXIT_FAILURE);
200 }
201 dir.message = &dir_message[0];
202
117deb70
LT
203 ret = snprintf(fs_message, fs_msg_size, "Check devtmpfs injected into %s - ", name);
204 if (ret < 0 || ret >= fs_msg_size) {
205 fprintf(stderr, "Failed to create message for fs\n");
206 exit(EXIT_FAILURE);
207 }
208 fs.message = &fs_message[0];
209
d81423f2
LT
210 /* Setup logging*/
211 strcpy(template_log, TEMPLATE);
212 i = lxc_make_tmpfile(template_log, false);
213 if (i < 0) {
214 lxc_error("Failed to create temporary log file for container %s\n", name);
215 exit(EXIT_FAILURE);
216 } else {
217 lxc_debug("Using \"%s\" as temporary log file for container %s\n", template_log, name);
218 close(i);
219 }
220
221 log.name = name;
222 log.file = template_log;
223 log.level = "TRACE";
224 log.prefix = "mount-injection";
225 log.quiet = false;
226 log.lxcpath = NULL;
227 if (lxc_log_init(&log))
228 exit(EXIT_FAILURE);
229
230 /* Container setup */
231 c = lxc_container_new(name, NULL);
232 if (!c) {
233 fprintf(stderr, "Unable to instantiate container (%s)...\n", name);
234 goto out;
235 }
236
237 if (c->is_defined(c)) {
238 fprintf(stderr, "Container (%s) already exists\n", name);
239 goto out;
240 }
241
242 for (i = 0; config_items[i]; i += 2) {
243 if (!c->set_config_item(c, config_items[i], config_items[i + 1])) {
244 fprintf(stderr, "Failed to set \"%s\" config option to \"%s\"\n", config_items[i], config_items[i + 1]);
245 goto out;
246 }
247 }
248
249 if (!c->create(c, "busybox", NULL, NULL, 1, NULL)) {
250 fprintf(stderr, "Creating the container (%s) failed...\n", name);
251 goto out;
252 }
253
254 c->want_daemonize(c, true);
255
256 if (!c->start(c, false, NULL)) {
257 fprintf(stderr, "Starting the container (%s) failed...\n", name);
258 goto out;
259 }
260
261 mnt.version = LXC_MOUNT_API_V1;
262
263 /* Check device mounted */
117deb70 264 ret = c->mount(c, "/dev/urandom", "/mnt/mount_injection_test_urandom", NULL, MS_BIND, NULL, &mnt);
d81423f2
LT
265 if (ret < 0) {
266 fprintf(stderr, "Failed to mount \"/dev/urandom\"\n");
267 goto out;
268 }
269
c8c568c8
LT
270 ret = check_containers_mountinfo(c, &device);
271 if (ret < 0)
272 goto out;
273
274 /* Check device unmounted */
275 /* TODO: what about other umount flags? */
276 ret = c->umount(c, "/mnt/mount_injection_test_urandom", MNT_DETACH, &mnt);
277 if (ret < 0) {
278 fprintf(stderr, "Failed to umount2 \"/dev/urandom\"\n");
279 goto out;
280 }
281
282 device.message = "Unmounted \"/mnt/mount_injection_test_urandom\" -- should be missing now: ";
283 device.should_be_present = false;
d81423f2
LT
284 ret = check_containers_mountinfo(c, &device);
285 if (ret < 0)
286 goto out;
287
288 /* Check dir mounted */
643bcac9 289 ret = c->mount(c, template_dir, template_dir, NULL, MS_BIND, NULL, &mnt);
d81423f2
LT
290 if (ret < 0) {
291 fprintf(stderr, "Failed to mount \"%s\"\n", template_dir);
292 goto out;
293 }
294
295 ret = check_containers_mountinfo(c, &dir);
296 if (ret < 0)
297 goto out;
298
c8c568c8
LT
299 /* Check dir unmounted */
300 /* TODO: what about other umount flags? */
301 ret = c->umount(c, template_dir, MNT_DETACH, &mnt);
302 if (ret < 0) {
303 fprintf(stderr, "Failed to umount2 \"%s\"\n", template_dir);
304 goto out;
305 }
306
307 dir.message = "Unmounted dir -- should be missing now: ";
308 dir.should_be_present = false;
309 ret = check_containers_mountinfo(c, &dir);
310 if (ret < 0)
311 goto out;
312
117deb70
LT
313 /* Check fs mounted */
314 ret = c->mount(c, NULL, "/mnt/mount_injection_test_devtmpfs", "devtmpfs", 0, NULL, &mnt);
315 if (ret < 0) {
316 fprintf(stderr, "Failed to mount devtmpfs\n");
317 goto out;
318 }
319
320 ret = check_containers_mountinfo(c, &fs);
321 if (ret < 0)
322 goto out;
323
324 /* Check fs unmounted */
325 /* TODO: what about other umount flags? */
326 ret = c->umount(c, "/mnt/mount_injection_test_devtmpfs", MNT_DETACH, &mnt);
327 if (ret < 0) {
328 fprintf(stderr, "Failed to umount2 devtmpfs\n");
329 goto out;
330 }
331
332 fs.message = "Unmounted \"/mnt/mount_injection_test_devtmpfs\" -- should be missing now: ";
333 fs.should_be_present = false;
334 ret = check_containers_mountinfo(c, &fs);
335 if (ret < 0)
336 goto out;
337
c8c568c8 338 /* Finalize the container */
d81423f2
LT
339 if (!c->stop(c)) {
340 fprintf(stderr, "Stopping the container (%s) failed...\n", name);
341 goto out;
342 }
343
344 if (!c->destroy(c)) {
345 fprintf(stderr, "Destroying the container (%s) failed...\n", name);
346 goto out;
347 }
348
349 ret = 0;
350out:
351 lxc_container_put(c);
352
353 if (ret != 0) {
354 int fd;
355
356 fd = open(template_log, O_RDONLY);
357 if (fd >= 0) {
358 char buf[4096];
359 ssize_t buflen;
360 while ((buflen = read(fd, buf, 1024)) > 0) {
361 buflen = write(STDERR_FILENO, buf, buflen);
362 if (buflen <= 0)
363 break;
364 }
365 close(fd);
366 }
367 }
368
369 unlink(template_log);
370 unlink(template_dir);
371
372 return ret;
373}
374
39b72573 375static int do_priv_container_test(void)
d81423f2
LT
376{
377 const char *config_items[] = {"lxc.mount.auto", "shmounts:/tmp/mount_injection_test", NULL};
378 return perform_container_test(NAME"privileged", config_items);
379}
380
39b72573 381static int do_unpriv_container_test(void)
d81423f2
LT
382{
383 const char *config_items[] = {
384 "lxc.mount.auto", "shmounts:/tmp/mount_injection_test",
d81423f2
LT
385 NULL
386 };
387 return perform_container_test(NAME"unprivileged", config_items);
388}
389
6437f1c1
CB
390static bool lxc_setup_shmount(const char *shmount_path)
391{
392 int ret;
393
394 ret = mkdir_p(shmount_path, 0711);
395 if (ret < 0 && errno != EEXIST) {
396 fprintf(stderr, "Failed to create directory \"%s\"\n", shmount_path);
397 return false;
398 }
399
400 /* Prepare host mountpoint */
401 ret = mount("tmpfs", shmount_path, "tmpfs", 0, "size=100k,mode=0711");
402 if (ret < 0) {
403 fprintf(stderr, "Failed to mount \"%s\"\n", shmount_path);
404 return false;
405 }
406
407 ret = mount(shmount_path, shmount_path, "none", MS_REC | MS_SHARED, "");
408 if (ret < 0) {
409 fprintf(stderr, "Failed to make shared \"%s\"\n", shmount_path);
410 return false;
411 }
412
413 return true;
414}
415
416static void lxc_teardown_shmount(char *shmount_path)
417{
418 (void)umount2(shmount_path, MNT_DETACH);
8408a9cc 419 (void)lxc_rm_rf(shmount_path);
6437f1c1
CB
420}
421
d81423f2
LT
422int main(int argc, char *argv[])
423{
6437f1c1
CB
424 if (!lxc_setup_shmount("/tmp/mount_injection_test"))
425 exit(EXIT_FAILURE);
426
d81423f2
LT
427 if (do_priv_container_test()) {
428 fprintf(stderr, "Privileged mount injection test failed\n");
6437f1c1 429 exit(EXIT_FAILURE);
d81423f2 430 }
117deb70 431
6437f1c1 432 if (do_unpriv_container_test()) {
d81423f2 433 fprintf(stderr, "Unprivileged mount injection test failed\n");
6437f1c1 434 exit(EXIT_FAILURE);
d81423f2 435 }
6437f1c1
CB
436
437 lxc_teardown_shmount("/tmp/mount_injection_test");
438
439 exit(EXIT_SUCCESS);
d81423f2 440}