Unverified Commit d81423f2 by Liza Tretyakova Committed by Christian Brauner

tests: add mount injection tests

parent 29df56cd
...@@ -33,6 +33,7 @@ lxc_test_state_server_SOURCES = state_server.c lxctest.h ...@@ -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_share_ns_SOURCES = share_ns.c lxctest.h
lxc_test_criu_check_feature_SOURCES = criu_check_feature.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_raw_clone_SOURCES = lxc_raw_clone.c lxctest.h
lxc_test_mount_injection_SOURCES = mount_injection.c
AM_CFLAGS=-DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \ AM_CFLAGS=-DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \
-DLXCPATH=\"$(LXCPATH)\" \ -DLXCPATH=\"$(LXCPATH)\" \
...@@ -64,7 +65,8 @@ bin_PROGRAMS = lxc-test-containertests lxc-test-locktests lxc-test-startone \ ...@@ -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-apparmor lxc-test-utils lxc-test-parse-config-file \
lxc-test-config-jump-table lxc-test-shortlived \ lxc-test-config-jump-table lxc-test-shortlived \
lxc-test-api-reboot lxc-test-state-server lxc-test-share-ns \ 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 = bin_SCRIPTS =
if ENABLE_TOOLS if ENABLE_TOOLS
...@@ -121,6 +123,7 @@ EXTRA_DIST = \ ...@@ -121,6 +123,7 @@ EXTRA_DIST = \
lxc-test-unpriv \ lxc-test-unpriv \
lxc-test-utils.c \ lxc-test-utils.c \
may_control.c \ may_control.c \
mount_injection.c \
parse_config_file.c \ parse_config_file.c \
saveconfig.c \ saveconfig.c \
shortlived.c \ shortlived.c \
......
/* mount_injection
*
* Copyright © 2018 Elizaveta Tretiakova <elizabet.tretyakova@gmail.com>.
*
* 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 <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <lxc/lxccontainer.h>
#include <lxc/list.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment