Unverified Commit 8f7b7b8d by Stéphane Graber Committed by GitHub

Merge pull request #3811 from brauner/2021-04-25.idmapped_mounts.rootfs

rootfs rework
parents b9f3cd48 4b875ef9
......@@ -483,6 +483,43 @@ int run_script(const char *name, const char *section, const char *script, ...)
return run_buffer(buffer);
}
int lxc_storage_prepare(struct lxc_conf *conf)
{
int ret;
struct lxc_rootfs *rootfs = &conf->rootfs;
if (!rootfs->path) {
ret = mount("", "/", NULL, MS_SLAVE | MS_REC, 0);
if (ret < 0)
return log_error_errno(-1, errno, "Failed to recursively turn root mount tree into dependent mount");
rootfs->dfd_mnt = open_at(-EBADF, "/", PROTECT_OPATH_DIRECTORY, PROTECT_LOOKUP_ABSOLUTE, 0);
if (rootfs->dfd_mnt < 0)
return -errno;
return 0;
}
ret = access(rootfs->mount, F_OK);
if (ret != 0)
return log_error_errno(-1, errno, "Failed to access to \"%s\". Check it is present",
rootfs->mount);
rootfs->storage = storage_init(conf);
if (!rootfs->storage)
return log_error(-1, "Failed to mount rootfs \"%s\" onto \"%s\" with options \"%s\"",
rootfs->path, rootfs->mount,
rootfs->options ? rootfs->options : "(null)");
return 0;
}
void lxc_storage_put(struct lxc_conf *conf)
{
storage_put(conf->rootfs.storage);
conf->rootfs.storage = NULL;
}
/* lxc_rootfs_prepare
* if rootfs is a directory, then open ${rootfs}/.lxc-keep for writing for
* the duration of the container run, to prevent the container from marking
......@@ -490,12 +527,17 @@ int run_script(const char *name, const char *section, const char *script, ...)
* no name pollution is happens.
* don't unlink on NFS to avoid random named stale handles.
*/
int lxc_rootfs_prepare(struct lxc_rootfs *rootfs, bool userns)
int lxc_rootfs_init(struct lxc_conf *conf, bool userns)
{
__do_close int dfd_path = -EBADF, fd_pin = -EBADF, fd_userns = -EBADF;
int ret;
struct stat st;
struct statfs stfs;
struct lxc_rootfs *rootfs = &conf->rootfs;
ret = lxc_storage_prepare(conf);
if (ret)
return syserror_set(-EINVAL, "Failed to prepare rootfs storage");
if (!is_empty_string(rootfs->mnt_opts.userns_path)) {
if (!rootfs->path)
......@@ -503,11 +545,6 @@ int lxc_rootfs_prepare(struct lxc_rootfs *rootfs, bool userns)
if (rootfs->bdev_type && !strequal(rootfs->bdev_type, "dir"))
return syserror_set(-EINVAL, "Idmapped rootfs currently only supports the \"dir\" storage driver");
fd_userns = open_at(-EBADF, rootfs->mnt_opts.userns_path,
PROTECT_OPEN_WITH_TRAILING_SYMLINKS, 0, 0);
if (fd_userns < 0)
return syserror("Failed to open user namespace");
}
if (rootfs->path) {
......@@ -571,6 +608,51 @@ out:
return 0;
}
int lxc_rootfs_prepare_parent(struct lxc_handler *handler)
{
__do_close int dfd_idmapped = -EBADF, fd_userns = -EBADF;
struct lxc_rootfs *rootfs = &handler->conf->rootfs;
struct lxc_storage *storage = rootfs->storage;
int ret;
const char *path_source;
if (lxc_list_empty(&handler->conf->id_map))
return 0;
if (is_empty_string(rootfs->mnt_opts.userns_path))
return 0;
if (handler->conf->rootfs_setup)
return 0;
if (rootfs_is_blockdev(handler->conf))
return syserror_set(-EOPNOTSUPP, "Idmapped mounts on block-backed storage not yet supported");
if (!can_use_bind_mounts())
return syserror_set(-EOPNOTSUPP, "Kernel does not support the new mount api");
if (rootfs->mnt_opts.userns_self)
fd_userns = dup_cloexec(handler->nsfd[LXC_NS_USER]);
else
fd_userns = open_at(-EBADF, rootfs->mnt_opts.userns_path,
PROTECT_OPEN_WITH_TRAILING_SYMLINKS, 0, 0);
if (fd_userns < 0)
return syserror("Failed to open user namespace");
path_source = lxc_storage_get_path(storage->src, storage->type);
dfd_idmapped = create_detached_idmapped_mount(path_source, fd_userns, true);
if (dfd_idmapped < 0)
return syserror("Failed to create detached idmapped mount");
ret = lxc_abstract_unix_send_fds(handler->data_sock[0], &dfd_idmapped, 1, NULL, 0);
if (ret < 0)
return syserror("Failed to send detached idmapped mount fd");
TRACE("Created detached idmapped mount %d", dfd_idmapped);
return 0;
}
static int add_shmount_to_list(struct lxc_conf *conf)
{
char new_mount[PATH_MAX];
......@@ -1286,11 +1368,9 @@ static int lxc_fill_autodev(struct lxc_rootfs *rootfs)
return 0;
}
static int lxc_mount_rootfs(struct lxc_conf *conf)
static int lxc_mount_rootfs(struct lxc_rootfs *rootfs)
{
int ret;
struct lxc_storage *bdev;
struct lxc_rootfs *rootfs = &conf->rootfs;
if (!rootfs->path) {
ret = mount("", "/", NULL, MS_SLAVE | MS_REC, 0);
......@@ -1309,14 +1389,7 @@ static int lxc_mount_rootfs(struct lxc_conf *conf)
return log_error_errno(-1, errno, "Failed to access to \"%s\". Check it is present",
rootfs->mount);
bdev = storage_init(conf);
if (!bdev)
return log_error(-1, "Failed to mount rootfs \"%s\" onto \"%s\" with options \"%s\"",
rootfs->path, rootfs->mount,
rootfs->options ? rootfs->options : "(null)");
ret = bdev->ops->mount(bdev);
storage_put(bdev);
ret = rootfs->storage->ops->mount(rootfs->storage);
if (ret < 0)
return log_error(-1, "Failed to mount rootfs \"%s\" onto \"%s\" with options \"%s\"",
rootfs->path, rootfs->mount,
......@@ -2164,9 +2237,13 @@ int parse_lxc_mntopts(struct lxc_mount_options *opts, char *mnt_opts)
if (is_empty_string(opts->userns_path))
return syserror_set(-EINVAL, "Missing idmap path for \"idmap=<path>\" LXC specific mount option");
fd_userns = open(opts->userns_path, O_RDONLY | O_NOCTTY | O_CLOEXEC);
if (fd_userns < 0)
return syserror("Failed to open user namespace");
if (strequal(opts->userns_path, "container")) {
opts->userns_self = 1;
} else {
fd_userns = open(opts->userns_path, O_RDONLY | O_NOCTTY | O_CLOEXEC);
if (fd_userns < 0)
return syserror("Failed to open user namespace");
}
TRACE("Parse LXC specific mount option %d->\"idmap=%s\"", fd_userns, opts->userns_path);
break;
......@@ -2757,6 +2834,7 @@ struct lxc_conf *lxc_conf_init(void)
new->rootfs.dfd_dev = -EBADF;
new->rootfs.dfd_host = -EBADF;
new->rootfs.fd_path_pin = -EBADF;
new->rootfs.dfd_idmapped = -EBADF;
new->rootfs.mnt_opts.userns_fd = -EBADF;
new->logfd = -1;
lxc_list_init(&new->cgroup);
......@@ -3361,7 +3439,7 @@ int lxc_setup_rootfs_prepare_root(struct lxc_conf *conf, const char *name,
if (ret < 0)
return log_error(-1, "Failed to run pre-mount hooks");
ret = lxc_mount_rootfs(conf);
ret = lxc_mount_rootfs(&conf->rootfs);
if (ret < 0)
return log_error(-1, "Failed to setup rootfs for");
......@@ -3490,12 +3568,40 @@ static int lxc_setup_keyring(struct lsm_ops *lsm_ops, const struct lxc_conf *con
return ret;
}
static int lxc_rootfs_prepare_child(struct lxc_handler *handler)
{
struct lxc_rootfs *rootfs = &handler->conf->rootfs;
int dfd_idmapped = -EBADF;
int ret;
if (lxc_list_empty(&handler->conf->id_map))
return 0;
if (is_empty_string(rootfs->mnt_opts.userns_path))
return 0;
if (handler->conf->rootfs_setup)
return 0;
ret = lxc_abstract_unix_recv_one_fd(handler->data_sock[1], &dfd_idmapped, NULL, 0);
if (ret < 0)
return syserror("Failed to receive idmapped mount fd");
rootfs->dfd_idmapped = dfd_idmapped;
TRACE("Received detached idmapped mount %d", rootfs->dfd_idmapped);
return 0;
}
int lxc_setup(struct lxc_handler *handler)
{
int ret;
const char *lxcpath = handler->lxcpath, *name = handler->name;
struct lxc_conf *lxc_conf = handler->conf;
ret = lxc_rootfs_prepare_child(handler);
if (ret < 0)
return syserror("Failed to prepare rootfs");
ret = lxc_setup_rootfs_prepare_root(lxc_conf, name, lxcpath);
if (ret < 0)
return log_error(-1, "Failed to setup rootfs");
......@@ -4032,7 +4138,6 @@ void lxc_conf_free(struct lxc_conf *conf)
free(conf->rootfs.bdev_type);
free(conf->rootfs.options);
free(conf->rootfs.path);
free(conf->rootfs.data);
put_lxc_rootfs(&conf->rootfs, true);
free(conf->logfile);
if (conf->logfd != -1)
......
......@@ -24,6 +24,7 @@
#include "memory_utils.h"
#include "ringbuf.h"
#include "start.h"
#include "storage/storage.h"
#include "string_utils.h"
#include "terminal.h"
......@@ -197,8 +198,12 @@ struct lxc_mount_options {
int create_file : 1;
int optional : 1;
int relative : 1;
int userns_self : 1;
char userns_path[PATH_MAX];
int userns_fd;
unsigned long mnt_flags;
unsigned long prop_flags;
char *data;
};
/* Defines a structure to store the rootfs location, the
......@@ -208,8 +213,6 @@ struct lxc_mount_options {
* @buf : static buffer to construct paths
* @bev_type : optional backing store type
* @options : mount options
* @mountflags : the portion of @options that are flags
* @data : the portion of @options that are not flags
* @managed : whether it is managed by LXC
* @dfd_mnt : fd for @mount
* @dfd_dev : fd for /dev of the container
......@@ -219,6 +222,7 @@ struct lxc_rootfs {
char *path;
int fd_path_pin;
int dfd_idmapped;
int dfd_mnt;
char *mount;
......@@ -229,9 +233,9 @@ struct lxc_rootfs {
char *bdev_type;
char *options;
unsigned long mountflags;
char *data;
bool managed;
struct lxc_mount_options mnt_opts;
struct lxc_storage *storage;
};
/*
......@@ -500,7 +504,11 @@ extern thread_local struct lxc_conf *current_config;
__hidden extern int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf, char *argv[]);
__hidden extern struct lxc_conf *lxc_conf_init(void);
__hidden extern void lxc_conf_free(struct lxc_conf *conf);
__hidden extern int lxc_rootfs_prepare(struct lxc_rootfs *rootfs, bool userns);
__hidden extern int lxc_storage_prepare(struct lxc_conf *conf);
__hidden extern int lxc_rootfs_prepare(struct lxc_conf *conf, bool userns);
__hidden extern void lxc_storage_put(struct lxc_conf *conf);
__hidden extern int lxc_rootfs_init(struct lxc_conf *conf, bool userns);
__hidden extern int lxc_rootfs_prepare_parent(struct lxc_handler *handler);
__hidden extern int lxc_map_ids(struct lxc_list *idmap, pid_t pid);
__hidden extern int lxc_create_tty(const char *name, struct lxc_conf *conf);
__hidden extern void lxc_delete_tty(struct lxc_tty_info *ttys);
......@@ -576,9 +584,19 @@ static inline const char *get_rootfs_mnt(const struct lxc_rootfs *rootfs)
return !is_empty_string(rootfs->path) ? rootfs->mount : s;
}
static inline bool idmapped_rootfs_mnt(const struct lxc_rootfs *rootfs)
static inline void put_lxc_mount_options(struct lxc_mount_options *mnt_opts)
{
return rootfs->mnt_opts.userns_fd >= 0;
mnt_opts->create_dir = 0;
mnt_opts->create_file = 0;
mnt_opts->optional = 0;
mnt_opts->relative = 0;
mnt_opts->userns_self = 0;
mnt_opts->userns_path[0] = '\0';
mnt_opts->mnt_flags = 0;
mnt_opts->prop_flags = 0;
close_prot_errno_disarm(mnt_opts->userns_fd);
free_disarm(mnt_opts->data);
}
static inline void put_lxc_rootfs(struct lxc_rootfs *rootfs, bool unpin)
......@@ -590,6 +608,10 @@ static inline void put_lxc_rootfs(struct lxc_rootfs *rootfs, bool unpin)
close_prot_errno_disarm(rootfs->mnt_opts.userns_fd);
if (unpin)
close_prot_errno_disarm(rootfs->fd_path_pin);
close_prot_errno_disarm(rootfs->dfd_idmapped);
put_lxc_mount_options(&rootfs->mnt_opts);
storage_put(rootfs->storage);
rootfs->storage = NULL;
}
}
......
......@@ -2791,8 +2791,8 @@ static int set_config_rootfs_options(const char *key, const char *value,
struct lxc_conf *lxc_conf, void *data)
{
__do_free char *dup = NULL, *mdata = NULL, *opts = NULL;
unsigned long mflags = 0, pflags = 0;
struct lxc_rootfs *rootfs = &lxc_conf->rootfs;
struct lxc_mount_options *mnt_opts = &rootfs->mnt_opts;
int ret;
clr_config_rootfs_options(key, lxc_conf, data);
......@@ -2803,15 +2803,15 @@ static int set_config_rootfs_options(const char *key, const char *value,
if (!dup)
return -ENOMEM;
ret = parse_lxc_mntopts(&rootfs->mnt_opts, dup);
ret = parse_lxc_mntopts(mnt_opts, dup);
if (ret < 0)
return ret;
ret = parse_mntopts(dup, &mflags, &mdata);
ret = parse_mntopts(dup, &mnt_opts->mnt_flags, &mdata);
if (ret < 0)
return ret_errno(EINVAL);
ret = parse_propagationopts(dup, &pflags);
ret = parse_propagationopts(dup, &mnt_opts->prop_flags);
if (ret < 0)
return ret_errno(EINVAL);
......@@ -2819,13 +2819,12 @@ static int set_config_rootfs_options(const char *key, const char *value,
if (ret < 0)
return ret_errno(ENOMEM);
if (rootfs->mnt_opts.create_dir || rootfs->mnt_opts.create_file ||
rootfs->mnt_opts.optional || rootfs->mnt_opts.relative)
if (mnt_opts->create_dir || mnt_opts->create_file ||
mnt_opts->optional || mnt_opts->relative)
return syserror_set(-EINVAL, "Invalid LXC specifc mount option for rootfs mount");
rootfs->mountflags = mflags | pflags;
mnt_opts->data = move_ptr(mdata);
rootfs->options = move_ptr(opts);
rootfs->data = move_ptr(mdata);
return 0;
}
......@@ -5017,7 +5016,7 @@ static inline int clr_config_rootfs_options(const char *key, struct lxc_conf *c,
void *data)
{
free_disarm(c->rootfs.options);
free_disarm(c->rootfs.data);
put_lxc_mount_options(&c->rootfs.mnt_opts);
return 0;
}
......
......@@ -964,6 +964,10 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_
if (unshare(CLONE_NEWNS))
goto out_fini_handler;
ret = lxc_storage_prepare(c->lxc_conf);
if (ret)
goto out_fini_handler;
/* CRIU needs the lxc root bind mounted so that it is the root of some
* mount. */
rootfs = &c->lxc_conf->rootfs;
......
......@@ -1345,11 +1345,12 @@ static bool create_run_template(struct lxc_container *c, char *tpath,
_exit(EXIT_FAILURE);
}
bdev = storage_init(c->lxc_conf);
if (!bdev) {
ret = lxc_storage_prepare(conf);
if (ret) {
ERROR("Failed to initialize storage");
_exit(EXIT_FAILURE);
}
bdev = conf->rootfs.storage;
euid = geteuid();
if (euid == 0) {
......@@ -3654,14 +3655,15 @@ static int clone_update_rootfs(struct clone_update_data *data)
if (unshare(CLONE_NEWNS) < 0)
return -1;
bdev = storage_init(c->lxc_conf);
if (!bdev)
ret = lxc_storage_prepare(conf);
if (ret)
return -1;
bdev = conf->rootfs.storage;
if (!strequal(bdev->type, "dir")) {
if (unshare(CLONE_NEWNS) < 0) {
ERROR("error unsharing mounts");
storage_put(bdev);
lxc_storage_put(conf);
return -1;
}
......@@ -3669,7 +3671,7 @@ static int clone_update_rootfs(struct clone_update_data *data)
SYSERROR("Failed to recursively turn root mount tree into dependent mount. Continuing...");
if (bdev->ops->mount(bdev) < 0) {
storage_put(bdev);
lxc_storage_put(conf);
return -1;
}
} else { /* TODO come up with a better way */
......@@ -3696,14 +3698,14 @@ static int clone_update_rootfs(struct clone_update_data *data)
if (run_lxc_hooks(c->name, "clone", conf, hookargs)) {
ERROR("Error executing clone hook for %s", c->name);
storage_put(bdev);
lxc_storage_put(conf);
return -1;
}
}
if (!(flags & LXC_CLONE_KEEPNAME)) {
ret = strnprintf(path, sizeof(path), "%s/etc/hostname", bdev->dest);
storage_put(bdev);
lxc_storage_put(conf);
if (ret < 0)
return -1;
......@@ -3724,7 +3726,7 @@ static int clone_update_rootfs(struct clone_update_data *data)
if (fclose(fout) < 0)
return -1;
} else {
storage_put(bdev);
lxc_storage_put(conf);
}
return 0;
......@@ -3993,14 +3995,14 @@ static bool do_lxcapi_rename(struct lxc_container *c, const char *newname)
return false;
}
bdev = storage_init(c->lxc_conf);
if (!bdev) {
if (lxc_storage_prepare(c->lxc_conf)) {
ERROR("Failed to find original backing store type");
return false;
}
bdev = c->lxc_conf->rootfs.storage;
newc = lxcapi_clone(c, newname, c->config_path, LXC_CLONE_KEEPMACADDR, NULL, bdev->type, 0, NULL);
storage_put(bdev);
lxc_storage_put(c->lxc_conf);
if (!newc) {
lxc_container_put(newc);
return false;
......@@ -4376,11 +4378,11 @@ static bool do_lxcapi_snapshot_restore(struct lxc_container *c, const char *snap
return false;
}
bdev = storage_init(c->lxc_conf);
if (!bdev) {
if (lxc_storage_prepare(c->lxc_conf)) {
ERROR("Failed to find original backing store type");
return false;
}
bdev = c->lxc_conf->rootfs.storage;
/* For an overlay container the rootfs is considered immutable
* and cannot be removed when restoring from a snapshot. We pass this
......@@ -4394,7 +4396,7 @@ static bool do_lxcapi_snapshot_restore(struct lxc_container *c, const char *snap
newname = c->name;
if (!get_snappath_dir(c, clonelxcpath)) {
storage_put(bdev);
lxc_storage_put(c->lxc_conf);
return false;
}
/* how should we lock this? */
......@@ -4406,7 +4408,7 @@ static bool do_lxcapi_snapshot_restore(struct lxc_container *c, const char *snap
if (snap)
lxc_container_put(snap);
storage_put(bdev);
lxc_storage_put(c->lxc_conf);
return false;
}
......@@ -4414,7 +4416,7 @@ static bool do_lxcapi_snapshot_restore(struct lxc_container *c, const char *snap
if (!container_destroy(c, bdev)) {
ERROR("Could not destroy existing container %s", newname);
lxc_container_put(snap);
storage_put(bdev);
lxc_storage_put(c->lxc_conf);
return false;
}
}
......@@ -4427,7 +4429,7 @@ static bool do_lxcapi_snapshot_restore(struct lxc_container *c, const char *snap
rest = lxcapi_clone(snap, newname, c->config_path, flags, bdev->type,
NULL, 0, NULL);
storage_put(bdev);
lxc_storage_put(c->lxc_conf);
if (rest && lxcapi_is_defined(rest))
b = true;
......
......@@ -243,6 +243,7 @@ int create_detached_idmapped_mount(const char *path, int userns_fd, bool recursi
struct lxc_mount_attr attr = {
.attr_set = MOUNT_ATTR_IDMAP,
.userns_fd = userns_fd,
.propagation = MS_SLAVE,
};
int ret;
......
......@@ -1786,6 +1786,12 @@ static int lxc_spawn(struct lxc_handler *handler)
}
}
ret = lxc_rootfs_prepare_parent(handler);
if (ret) {
ERROR("Failed to prepare rootfs");
goto out_delete_net;
}
if (!lxc_sync_wake_child(handler, START_SYNC_STARTUP))
goto out_delete_net;
......@@ -2034,7 +2040,7 @@ int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops,
* it readonly.
* If the container is unprivileged then skip rootfs pinning.
*/
ret = lxc_rootfs_prepare(&conf->rootfs, !lxc_list_empty(&conf->id_map));
ret = lxc_rootfs_init(conf, !lxc_list_empty(&conf->id_map));
if (ret) {
ERROR("Failed to handle rootfs pinning for container \"%s\"", handler->name);
ret = -1;
......@@ -2043,21 +2049,9 @@ int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops,
if (geteuid() == 0 && !lxc_list_empty(&conf->id_map)) {
/*
* This handles two cases: mounting real block devices and
* creating idmapped mounts. The block device case should be
* obivous, i.e. no real filesystem can currently be mounted
* from inside a user namespace.
*
* Idmapped mounts can currently only be created if the caller
* is privileged wrt to the user namespace in which the
* underlying block device has been mounted in. This basically
* (with few exceptions) means we need to be CAP_SYS_ADMIN in
* the initial user namespace since almost no interesting
* filesystems can be mounted inside of user namespaces. This
* is way we need to do the rootfs setup here. In the future
* this may change.
* Most filesystems can't be mounted inside a userns so handle them here.
*/
if (idmapped_rootfs_mnt(&conf->rootfs) || rootfs_is_blockdev(conf)) {
if (rootfs_is_blockdev(conf)) {
ret = unshare(CLONE_NEWNS);
if (ret < 0) {
ERROR("Failed to unshare CLONE_NEWNS");
......
......@@ -127,8 +127,10 @@ bool dir_detect(const char *path)
int dir_mount(struct lxc_storage *bdev)
{
struct lxc_rootfs *rootfs = bdev->rootfs;
struct lxc_mount_options *mnt_opts = &rootfs->mnt_opts;
__do_free char *mntdata = NULL;
unsigned long mflags = 0, mntflags = 0, pflags = 0;
unsigned long mflags = 0;
int ret;
const char *src;
......@@ -138,53 +140,54 @@ int dir_mount(struct lxc_storage *bdev)
if (!bdev->src || !bdev->dest)
return -22;
ret = parse_mntopts(bdev->mntopts, &mntflags, &mntdata);
if (ret < 0)
return log_error_errno(ret, errno, "Failed to parse mount options \"%s\"", bdev->mntopts);
ret = parse_propagationopts(bdev->mntopts, &pflags);
if (ret < 0)
return log_error_errno(-EINVAL, EINVAL, "Failed to parse mount propagation options \"%s\"", bdev->mntopts);
src = lxc_storage_get_path(bdev->src, bdev->type);
if (rootfs->dfd_idmapped >= 0 && !can_use_bind_mounts())
return syserror_set(-EOPNOTSUPP, "Idmapped mount requested but kernel doesn't support new mount API");
if (can_use_bind_mounts()) {
__do_close int fd_source = -EBADF, fd_target = -EBADF;
fd_source = open_at(-EBADF, src, PROTECT_OPATH_DIRECTORY, 0, 0);
if (fd_source < 0)
return syserror("Failed to open \"%s\"", src);
fd_target = open_at(-EBADF, bdev->dest, PROTECT_OPATH_DIRECTORY, 0, 0);
if (fd_target < 0)
return syserror("Failed to open \"%s\"", bdev->dest);
ret = fd_mount_idmapped(fd_source, "", PROTECT_OPATH_DIRECTORY,
PROTECT_LOOKUP_BENEATH, fd_target, "",
PROTECT_OPATH_DIRECTORY,
PROTECT_LOOKUP_BENEATH, 0,
bdev->rootfs->mnt_opts.userns_fd, true);
if (rootfs->dfd_idmapped >= 0) {
ret = move_detached_mount(rootfs->dfd_idmapped, fd_target, "",
PROTECT_OPATH_DIRECTORY,
PROTECT_LOOKUP_BENEATH);
} else {
fd_source = open_at(-EBADF, src, PROTECT_OPATH_DIRECTORY, 0, 0);
if (fd_source < 0)
return syserror("Failed to open \"%s\"", src);
ret = fd_bind_mount(fd_source, "",
PROTECT_OPATH_DIRECTORY,
PROTECT_LOOKUP_BENEATH, fd_target,
"", PROTECT_OPATH_DIRECTORY,
PROTECT_LOOKUP_BENEATH, 0, true);
}
if (ret < 0)
return syserror("Failed to mount \"%s\" onto \"%s\"", src, bdev->dest);
} else {
ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags | pflags, mntdata);
ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC | mnt_opts->mnt_flags | mnt_opts->prop_flags, mntdata);
if (ret < 0)
return log_error_errno(-errno, errno, "Failed to mount \"%s\" on \"%s\"", src, bdev->dest);
if (ret == 0 && (mntflags & MS_RDONLY)) {
mflags = add_required_remount_flags(src, bdev->dest, MS_BIND | MS_REC | mntflags | pflags | MS_REMOUNT);
if (ret == 0 && (mnt_opts->mnt_flags & MS_RDONLY)) {
mflags = add_required_remount_flags(src, bdev->dest, MS_BIND | MS_REC | mnt_opts->mnt_flags | mnt_opts->mnt_flags | MS_REMOUNT);
ret = mount(src, bdev->dest, "bind", mflags, mntdata);
if (ret < 0)
return log_error_errno(-errno, errno, "Failed to remount \"%s\" on \"%s\" read-only with options \"%s\", mount flags \"%lu\", and propagation flags \"%lu\"",
src ? src : "(none)", bdev->dest ? bdev->dest : "(none)", mntdata, mflags, pflags);
src ? src : "(none)", bdev->dest ? bdev->dest : "(none)", mntdata, mflags, mnt_opts->mnt_flags);
else
DEBUG("Remounted \"%s\" on \"%s\" read-only with options \"%s\", mount flags \"%lu\", and propagation flags \"%lu\"",
src ? src : "(none)", bdev->dest ? bdev->dest : "(none)", mntdata, mflags, pflags);
src ? src : "(none)", bdev->dest ? bdev->dest : "(none)", mntdata, mflags, mnt_opts->mnt_flags);
}
TRACE("Mounted \"%s\" on \"%s\" with options \"%s\", mount flags \"%lu\", and propagation flags \"%lu\"",
src ? src : "(none)", bdev->dest ? bdev->dest : "(none)", mntdata, mflags, pflags);
src ? src : "(none)", bdev->dest ? bdev->dest : "(none)", mntdata, mflags, mnt_opts->mnt_flags);
}
TRACE("Mounted \"%s\" onto \"%s\"", src, bdev->dest);
......
......@@ -86,12 +86,14 @@ int lxc_rsync(struct rsync_data *data)
ERROR("Failed mounting \"%s\" on \"%s\"", orig->src, orig->dest);
return -1;
}
TRACE("Mounted \"%s\" on \"%s\"", orig->src, orig->dest);
ret = new->ops->mount(new);
if (ret < 0) {
ERROR("Failed mounting \"%s\" onto \"%s\"", new->src, new->dest);
return -1;
}
TRACE("Mounted \"%s\" on \"%s\"", new->src, new->dest);
if (!lxc_switch_uid_gid(0, 0))
return -1;
......
......@@ -314,6 +314,15 @@ struct lxc_storage *storage_copy(struct lxc_container *c, const char *cname,
const char *oldpath = c->config_path;
char cmd_output[PATH_MAX] = {0};
struct rsync_data data = {0};
struct lxc_rootfs new_rootfs = {
.managed = true,
.dfd_mnt = -EBADF,
.dfd_dev = -EBADF,
.dfd_host = -EBADF,
.fd_path_pin = -EBADF,
.dfd_idmapped = -EBADF,
.mnt_opts.userns_fd = -EBADF,
};
if (!src) {
ERROR("No rootfs specified");
......@@ -329,11 +338,21 @@ struct lxc_storage *storage_copy(struct lxc_container *c, const char *cname,
return NULL;
}
orig = storage_init(c->lxc_conf);
if (!orig) {
ret = lxc_storage_prepare(c->lxc_conf);
if (ret) {
ERROR("Failed to detect storage driver for \"%s\"", oldname);
return NULL;
}
orig = c->lxc_conf->rootfs.storage;
if (c->lxc_conf->rootfs.dfd_idmapped >= 0) {
new_rootfs.dfd_idmapped = dup_cloexec(new_rootfs.dfd_idmapped);
if (new_rootfs.dfd_idmapped < 0) {
SYSERROR("Failed to duplicate user namespace file descriptor");
lxc_storage_put(c->lxc_conf);
return NULL;
}
}
if (!orig->dest) {
size_t len;
......@@ -404,6 +423,7 @@ struct lxc_storage *storage_copy(struct lxc_container *c, const char *cname,
goto on_error_put_orig;
}
TRACE("Initialized %s storage driver", new->type);
new->rootfs = &new_rootfs;
/* create new paths */
ret = new->ops->clone_paths(orig, new, oldname, cname, oldpath, lxcpath,
......@@ -499,7 +519,7 @@ struct lxc_storage *storage_copy(struct lxc_container *c, const char *cname,
}
on_success:
storage_put(orig);
lxc_storage_put(c->lxc_conf);
return new;
......@@ -507,7 +527,7 @@ on_error_put_new:
storage_put(new);
on_error_put_orig:
storage_put(orig);
lxc_storage_put(c->lxc_conf);
return NULL;
}
......@@ -643,10 +663,12 @@ bool storage_is_dir(struct lxc_conf *conf)
void storage_put(struct lxc_storage *bdev)
{
free(bdev->mntopts);
free(bdev->src);
free(bdev->dest);
free(bdev);
if (bdev) {
free_disarm(bdev->mntopts);
free_disarm(bdev->src);
free_disarm(bdev->dest);
free_disarm(bdev);
}
}
bool rootfs_is_blockdev(struct lxc_conf *conf)
......
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