Могу ли я смонтировать файловую систему только для чтения в контейнер LXC?

Я работаю над программным обеспечением, созданным поверх LXC. Помимо прочего, мы хотим монтировать папки с хоста в контейнер LXC во время выполнения, поэтому мы не можем поместить наши точки монтирования в нашу lxc.conf (что мы делаем для статических точек монтирования).

Во время монтажа повторная установка только для чтения не работает. Повторное монтирование успешно выполняется на хосте, но точка монтирования по-прежнему отображается как чтение / запись в контейнере.

Пример программы

Я создал небольшую программу, расширяющую пример API LXC ( https://linuxcontainers.org/lxc/documentation/), которая демонстрирует это поведение. Я надеюсь, что вы простите отсутствие удивительности в коде.

#include <stdio.h>                                                                                                                                       
#include <string.h>
#include <stdlib.h>
#include <errno.h>

#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <lxc/lxccontainer.h>

int do_unmount(char *dir) {
    printf("Un-mounting %s\n", dir);
    if(umount(dir) == -1) {
        fprintf(stderr, "Failed to unmount %s\n", dir);
        return 1;
    }
    return 0;
}

int container_test(struct lxc_container *c, char *mountName) {

    if (c->is_defined(c)) {
        fprintf(stderr, "Container already exists\n");
        return 1;
    } else {
        printf("Container now exists, good\n");
    }

    /* Create the container */
    if (!c->createl(c, "busybox", NULL, NULL, LXC_CREATE_QUIET, NULL)) {
        fprintf(stderr, "Failed to create container rootfs\n");
        return 2;
    } else {
        printf("Created container rootfs\n");
    }

    /* Start the container */
    if (!c->start(c, 0, NULL)) {
        fprintf(stderr, "Failed to start the container\n");
        return 3;
    } else {
        printf("Started the container\n");
    }

    /* Query some information */
    printf("Container state: %s\n", c->state(c));
    printf("Container PID: %d\n", c->init_pid(c));

    char *rootfs = c->get_running_config_item(c, "lxc.rootfs");
    printf("Container rootfs: %s\n", rootfs);

    // Set up mount point directory
    const char *mount_relative_dir = "/mount_test";
    size_t rootfs_path_size = strlen(rootfs);
    size_t relative_dir_size = strlen(mount_relative_dir);

    char mount_dir[rootfs_path_size + relative_dir_size + 1];
    strncpy(mount_dir, rootfs, rootfs_path_size + 1);
    strcat(mount_dir, mount_relative_dir);

    // Create the mount point directory
    int dir_status = mkdir(mount_dir, S_IRWXU);
    if (dir_status == -1) {
        fprintf(stderr, "Failed to create directory %s, error: %s\n", mount_dir, strerror(errno));
    }

    printf("Going to mount into: %s\n", mount_dir);
    if (mount(".", mount_dir, NULL, MS_BIND, NULL) == -1) {
        fprintf(stderr, "Failed to mount ./ into %s\n", mount_dir);
        do_unmount(mount_dir);
        return 4;
    }

    printf("Going to re-mount %s read-only\n", mount_dir);
    if (mount(NULL, mount_dir, NULL, MS_BIND | MS_REMOUNT | MS_RDONLY, NULL) == -1) {
        fprintf(stderr, "Failed to re-mount %s read-only\n", mount_dir);
        do_unmount(mount_dir);
        return 5;
    }

    /* Check the mount point from within the container */
    system("lxc-attach -n apicontainer -- /bin/ls -ahl /");
    system("lxc-attach -n apicontainer -- /bin/mount");

    /* We are done with the mount stuff now */
    do_unmount(mount_dir);
    /*  Has to be freed, allocated by LXC */
    free(rootfs);

    printf("Stopping the container\n");
    /* Stop the container */
    if (!c->shutdown(c, 30)) {
        printf("Failed to cleanly shutdown the container, forcing.\n");
        if (!c->stop(c)) {
            fprintf(stderr, "Failed to kill the container.\n");
            return 6;
        }
    }

    printf("Destroying the container\n");
    /* Destroy the container */
    if (!c->destroy(c)) {
        fprintf(stderr, "Failed to destroy the container.\n");
        return 7;
    }

    return 0;
}

int main(int argc, char **argv) {
    struct lxc_container *c;

    if(argc < 2) {
        printf("Usage: %s <source> \n", argv[0]);
        return 1;
    }


    /* Setup container struct */
    c = lxc_container_new("apicontainer", NULL);
    if (!c) {
        fprintf(stderr, "Failed to setup lxc_container struct\n");
    } else {
        printf("Created lxc_container struct\n");
    }

    char *source_dir = argv[1];
    int status = container_test(c, source_dir);
    if(status != 0) {
        fprintf(stderr, "*** Container test FAILED with status %i ***\n", status);
    }

    lxc_container_put(c);
}

Выполнение примера

Я добавил несколько новых строк и комментариев для удобства чтения.

➜  mount-test git:(master) ✗ gcc -o mount-test -llxc -g main.c 
➜  mount-test git:(master) ✗ sudo ./mount-test ./
Created lxc_container struct
Container now exists, good
Created container rootfs
Started the container
Container state: RUNNING
Container PID: 27763
Container rootfs: /var/lib/lxc/apicontainer/rootfs
Going to mount into: /var/lib/lxc/apicontainer/rootfs/mount_test
Going to re-mount /var/lib/lxc/apicontainer/rootfs/mount_test read-only

Вывод из ls -ahl / внутри контейнера

total 60
drwxr-xr-x   18 root     root        4.0K Jun 30 10:55 .
drwxr-xr-x   18 root     root        4.0K Jun 30 10:55 ..
drwxr-xr-x    2 root     root        4.0K Jun 30 10:55 bin
drwxr-xr-x    3 root     root         340 Jun 30 10:55 dev
drwxr-xr-x    3 root     root        4.0K Jun 30 10:55 etc
drwxr-xr-x    2 root     root        4.0K Jun 30 10:55 home
drwxr-xr-x   25 root     root        4.0K Jun  8 18:26 lib
drwxr-xr-x    2 root     root        4.0K May 31 08:42 lib64
drwxr-xr-x    2 root     root        4.0K Jun 30 10:55 mnt
drwxr-xr-x    2 1000     1000        4.0K Jun 30 10:55 mount_test
dr-xr-xr-x  300 root     root           0 Jun 30 10:55 proc
drwxr-xr-x    2 root     root        4.0K Jun 30 10:55 root
drwxr-xr-x    2 root     root        4.0K Jun 30 10:55 sbin
drwxr-xr-x    2 root     root        4.0K Jun 30 10:55 selinux
dr-xr-xr-x   13 root     root           0 Jun 30 10:55 sys
drwxr-xr-x    2 root     root        4.0K Jun 30 10:55 tmp
drwxr-xr-x    7 root     root        4.0K Jun 30 10:55 usr
drwxr-xr-x    3 root     root        4.0K Jun 30 10:55 var

Вывод из /bin/mount внутри контейнера

/dev/md0 on / type ext4 (rw,relatime,errors=remount-ro,stripe=256,data=ordered)
*snip*
/dev/md0 on /mount_test type ext4 (rw,relatime,errors=remount-ro,stripe=256,data=ordered)

Un-mounting /var/lib/lxc/apicontainer/rootfs/mount_test
Stopping the container
Destroying the container

Так что гора удалась, но, как видно выше, она по-прежнему показывает rw в контейнере. Однако в моей хост-системе он отображается только для чтения.

Полуприцепы растворы

Я знаю, что я могу, конечно, при необходимости смонтировать точку монтирования изнутри контейнера, но я бы предпочел, чтобы пользователь контейнера не имел привилегий монтирования по соображениям безопасности (в противном случае пользователь может перемонтировать существующие монтируемые только для чтения монтирования в rw и изменить файлы на хосте)

0 ответов

Другие вопросы по тегам