From: Liza Tretyakova Date: Wed, 2 May 2018 08:54:06 +0000 (+0300) Subject: tests: add mount injection tests X-Git-Tag: lxc-3.1.0~195^2~13 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d81423f2a0408c310be3667a0cdd40c6313b6b1d;p=thirdparty%2Flxc.git tests: add mount injection tests Signed-off-by: Liza Tretyakova --- diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index a2179c3ca..00d4c0b7a 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -33,6 +33,7 @@ lxc_test_state_server_SOURCES = state_server.c lxctest.h lxc_test_share_ns_SOURCES = share_ns.c lxctest.h lxc_test_criu_check_feature_SOURCES = criu_check_feature.c lxctest.h lxc_test_raw_clone_SOURCES = lxc_raw_clone.c lxctest.h +lxc_test_mount_injection_SOURCES = mount_injection.c AM_CFLAGS=-DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \ -DLXCPATH=\"$(LXCPATH)\" \ @@ -64,7 +65,8 @@ bin_PROGRAMS = lxc-test-containertests lxc-test-locktests lxc-test-startone \ lxc-test-apparmor lxc-test-utils lxc-test-parse-config-file \ lxc-test-config-jump-table lxc-test-shortlived \ lxc-test-api-reboot lxc-test-state-server lxc-test-share-ns \ - lxc-test-criu-check-feature lxc-test-raw-clone + lxc-test-criu-check-feature lxc-test-raw-clone \ + lxc-test-mount-injection bin_SCRIPTS = if ENABLE_TOOLS @@ -121,6 +123,7 @@ EXTRA_DIST = \ lxc-test-unpriv \ lxc-test-utils.c \ may_control.c \ + mount_injection.c \ parse_config_file.c \ saveconfig.c \ shortlived.c \ diff --git a/src/tests/mount_injection.c b/src/tests/mount_injection.c new file mode 100644 index 000000000..677fd937b --- /dev/null +++ b/src/tests/mount_injection.c @@ -0,0 +1,304 @@ +/* mount_injection + * + * Copyright © 2018 Elizaveta Tretiakova . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lxctest.h" +#include "utils.h" + +#define NAME "mount_injection_test-" +#define TEMPLATE P_tmpdir"/mount_injection_XXXXXX" + +struct mountinfo_strings { + const char *mount_root; + const char *mount_point; + const char *fstype; + const char *mount_source; + const char *message; +}; + +static int comp_field(char *line, const char *str, int nfields) +{ + char *p, *p2; + int i, ret; + + if(!line) + return -1; + + if (!str) + return 0; + + for (p = line, i = 0; p && i < nfields; i++) + p = strchr(p + 1, ' '); + if (!p) + return -1; + p2 = strchr(p + 1, ' '); + if (p2) + *p2 = '\0'; + ret = strcmp(p + 1, str); + if (p2) + *p2 = ' '; + return ret; +} + +static int find_in_proc_mounts(void *data) +{ + char buf[LXC_LINELEN]; + FILE *f; + struct mountinfo_strings *strs = (struct mountinfo_strings *) data; + + fprintf(stderr, "%s", strs->message); + + f = fopen("/proc/self/mountinfo", "r"); + if (!f) + return 0; + while (fgets(buf, LXC_LINELEN, f)) { + if (comp_field(buf, strs->mount_root, 3) == 0 && comp_field(buf, strs->mount_point, 4) == 0) { + char *buf2 = strchr(buf, '-'); + if (comp_field(buf2, strs->fstype, 1) == 0 && comp_field(buf2, strs->mount_source, 2) == 0) { + fclose(f); + fprintf(stderr, "OK\n"); + _exit(EXIT_SUCCESS); + } + } + } + fclose(f); + fprintf(stderr, "ERR\n"); + _exit(EXIT_FAILURE); +} + +static int check_containers_mountinfo(struct lxc_container *c, struct mountinfo_strings *d) +{ + pid_t pid; + int ret = -1; + lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT; + + ret = c->attach(c, find_in_proc_mounts, d, &attach_options, &pid); + if (ret < 0) { + fprintf(stderr, "Check of the container's mountinfo failed\n"); + return ret; + } + + ret = wait_for_pid(pid); + if (ret < 0) + fprintf(stderr, "Attached function failed"); + + return ret; +} + +/* config_items: NULL-terminated array of config pairs */ +static int perform_container_test(const char *name, const char *config_items[]) +{ + int i; + char *sret; + char template_log[sizeof(TEMPLATE)], template_dir[sizeof(TEMPLATE)], + device_message[sizeof("Check urandom device injected into "" - ") - 1 + strlen(name) + 1], + dir_message[sizeof("Check dir "" injected into "" - ") - 1 + sizeof(TEMPLATE) - 1 + strlen(name) + 1]; + struct lxc_container *c; + struct lxc_mount mnt; + struct lxc_log log; + int ret = -1, dev_msg_size = sizeof("Check urandom device injected into "" - ") - 1 + strlen(name) + 1, + dir_msg_size = sizeof("Check dir "" injected into "" - ") - 1 + sizeof(TEMPLATE) - 1 + strlen(name) + 1; + struct mountinfo_strings device = { + .mount_root = "/", + .mount_point = "/mnt/mount_injection_test_urandom", + .fstype = "devtmpfs", + .mount_source = "/dev/urandom", + .message = "" + }, dir = { + .mount_root = template_dir, + .mount_point = template_dir, + .fstype = "ext4", + .mount_source = NULL, + .message = "" + }; + + /* Temp paths and messages setup */ + strcpy(template_dir, TEMPLATE); + sret = mkdtemp(template_dir); + if (!sret) { + lxc_error("Failed to create temporary src file for container %s\n", name); + exit(EXIT_FAILURE); + } + + ret = snprintf(device_message, dev_msg_size, "Check urandom device injected into %s - ", name); + if (ret < 0 || ret >= dev_msg_size) { + fprintf(stderr, "Failed to create message for dev\n"); + exit(EXIT_FAILURE); + } + device.message = &device_message[0]; + + ret = snprintf(dir_message, dir_msg_size, "Check dir %s injected into %s - ", template_dir, name); + if (ret < 0 || ret >= dir_msg_size) { + fprintf(stderr, "Failed to create message for dir\n"); + exit(EXIT_FAILURE); + } + dir.message = &dir_message[0]; + + /* Setup logging*/ + strcpy(template_log, TEMPLATE); + i = lxc_make_tmpfile(template_log, false); + if (i < 0) { + lxc_error("Failed to create temporary log file for container %s\n", name); + exit(EXIT_FAILURE); + } else { + lxc_debug("Using \"%s\" as temporary log file for container %s\n", template_log, name); + close(i); + } + + log.name = name; + log.file = template_log; + log.level = "TRACE"; + log.prefix = "mount-injection"; + log.quiet = false; + log.lxcpath = NULL; + if (lxc_log_init(&log)) + exit(EXIT_FAILURE); + + /* Container setup */ + c = lxc_container_new(name, NULL); + if (!c) { + fprintf(stderr, "Unable to instantiate container (%s)...\n", name); + goto out; + } + + if (c->is_defined(c)) { + fprintf(stderr, "Container (%s) already exists\n", name); + goto out; + } + + for (i = 0; config_items[i]; i += 2) { + if (!c->set_config_item(c, config_items[i], config_items[i + 1])) { + fprintf(stderr, "Failed to set \"%s\" config option to \"%s\"\n", config_items[i], config_items[i + 1]); + goto out; + } + } + + if (!c->create(c, "busybox", NULL, NULL, 1, NULL)) { + fprintf(stderr, "Creating the container (%s) failed...\n", name); + goto out; + } + + c->want_daemonize(c, true); + + if (!c->start(c, false, NULL)) { + fprintf(stderr, "Starting the container (%s) failed...\n", name); + goto out; + } + + mnt.version = LXC_MOUNT_API_V1; + + /* Check device mounted */ + ret = c->mount(c, "/dev/urandom", "/mnt/mount_injection_test_urandom", "devtmpfs", 0, NULL, &mnt); + if (ret < 0) { + fprintf(stderr, "Failed to mount \"/dev/urandom\"\n"); + goto out; + } + + ret = check_containers_mountinfo(c, &device); + if (ret < 0) + goto out; + + /* Check dir mounted */ + ret = c->mount(c, template_dir, template_dir, "ext4", MS_BIND, NULL, &mnt); + if (ret < 0) { + fprintf(stderr, "Failed to mount \"%s\"\n", template_dir); + goto out; + } + + ret = check_containers_mountinfo(c, &dir); + if (ret < 0) + goto out; + + if (!c->stop(c)) { + fprintf(stderr, "Stopping the container (%s) failed...\n", name); + goto out; + } + + if (!c->destroy(c)) { + fprintf(stderr, "Destroying the container (%s) failed...\n", name); + goto out; + } + + ret = 0; +out: + lxc_container_put(c); + + if (ret != 0) { + int fd; + + fd = open(template_log, O_RDONLY); + if (fd >= 0) { + char buf[4096]; + ssize_t buflen; + while ((buflen = read(fd, buf, 1024)) > 0) { + buflen = write(STDERR_FILENO, buf, buflen); + if (buflen <= 0) + break; + } + close(fd); + } + } + + unlink(template_log); + unlink(template_dir); + + return ret; +} + +static int do_priv_container_test() +{ + const char *config_items[] = {"lxc.mount.auto", "shmounts:/tmp/mount_injection_test", NULL}; + return perform_container_test(NAME"privileged", config_items); +} + +static int do_unpriv_container_test() +{ + const char *config_items[] = { + "lxc.mount.auto", "shmounts:/tmp/mount_injection_test", + "lxc.init.uid", "100000", + "lxc.init.gid", "100000", + NULL + }; + return perform_container_test(NAME"unprivileged", config_items); +} + +int main(int argc, char *argv[]) +{ + if (do_priv_container_test()) { + fprintf(stderr, "Privileged mount injection test failed\n"); + return -1; + } + if(do_unpriv_container_test()) { + fprintf(stderr, "Unprivileged mount injection test failed\n"); + return -1; + } + return 0; +}