Unverified Commit dfb71524 by Stéphane Graber Committed by GitHub

Merge pull request #3650 from brauner/2021-02-03/fixes_1

conf: harden various mount paths
parents f8dcf07f cbc2ddf5
...@@ -1242,7 +1242,7 @@ static int lxc_mount_rootfs(struct lxc_conf *conf) ...@@ -1242,7 +1242,7 @@ static int lxc_mount_rootfs(struct lxc_conf *conf)
if (ret < 0) if (ret < 0)
return log_error_errno(-1, errno, "Failed to recursively turn root mount tree into dependent mount"); return log_error_errno(-1, errno, "Failed to recursively turn root mount tree into dependent mount");
rootfs->mntpt_fd = openat(-1, "/", O_RDONLY | O_CLOEXEC | O_DIRECTORY | O_PATH); rootfs->mntpt_fd = open_at(-EBADF, "/", PROTECT_OPATH_DIRECTORY, PROTECT_LOOKUP_ABSOLUTE, 0);
if (rootfs->mntpt_fd < 0) if (rootfs->mntpt_fd < 0)
return -errno; return -errno;
...@@ -2643,8 +2643,7 @@ struct lxc_conf *lxc_conf_init(void) ...@@ -2643,8 +2643,7 @@ struct lxc_conf *lxc_conf_init(void)
new->lsm_se_context = NULL; new->lsm_se_context = NULL;
new->lsm_se_keyring_context = NULL; new->lsm_se_keyring_context = NULL;
new->keyring_disable_session = false; new->keyring_disable_session = false;
new->tmp_umount_proc = false; new->transient_procfs_mnt = false;
new->tmp_umount_proc = 0;
new->shmount.path_host = NULL; new->shmount.path_host = NULL;
new->shmount.path_cont = NULL; new->shmount.path_cont = NULL;
...@@ -2952,19 +2951,88 @@ again: ...@@ -2952,19 +2951,88 @@ again:
return freeid; return freeid;
} }
/*
* Mount a proc under @rootfs if proc self points to a pid other than
* my own. This is needed to have a known-good proc mount for setting
* up LSMs both at container startup and attach.
*
* NOTE: not to be called from inside the container namespace!
*/
static int lxc_transient_proc(struct lxc_rootfs *rootfs)
{
__do_close int fd_proc = -EBADF;
int link_to_pid, link_len, pid_self, ret;
char link[INTTYPE_TO_STRLEN(pid_t) + 1];
link_len = readlinkat(rootfs->mntpt_fd, "proc/self", link, sizeof(link));
if (link_len < 0) {
ret = mkdirat(rootfs->mntpt_fd, "proc", 0000);
if (ret < 0 && errno != EEXIST)
return log_error_errno(-errno, errno, "Failed to create %d(proc)", rootfs->mntpt_fd);
goto domount;
} else if (link_len >= sizeof(link)) {
return log_error_errno(-EIO, EIO, "Truncated link target");
}
link[link_len] = '\0';
pid_self = lxc_raw_getpid();
INFO("Caller's PID is %d; /proc/self points to %s", pid_self, link);
ret = lxc_safe_int(link, &link_to_pid);
if (ret)
return log_error_errno(-ret, ret, "Failed to parse %s", link);
/* Correct procfs is already mounted. */
if (link_to_pid == pid_self)
return log_trace(0, "Correct procfs instance mounted");
fd_proc = open_at(rootfs->mntpt_fd, "proc", PROTECT_OPATH_DIRECTORY,
PROTECT_LOOKUP_BENEATH_XDEV, 0);
if (fd_proc < 0)
return log_error_errno(-errno, errno, "Failed to open transient procfs mountpoint");
ret = snprintf(rootfs->buf, sizeof(rootfs->buf), "/proc/self/fd/%d", fd_proc);
if (ret < 0 || (size_t)ret >= sizeof(rootfs->buf))
return ret_errno(EIO);
ret = umount2(rootfs->buf, MNT_DETACH);
if (ret < 0)
SYSWARN("Failed to umount \"%s\" with MNT_DETACH", rootfs->buf);
domount:
/* rootfs is NULL */
if (!rootfs->path) {
ret = mount("proc", rootfs->buf, "proc", 0, NULL);
} else {
ret = safe_mount_beneath_at(rootfs->mntpt_fd, "none", "proc", "proc", 0, NULL);
if (ret < 0) {
ret = snprintf(rootfs->buf, sizeof(rootfs->buf), "%s/proc", rootfs->path ? rootfs->mount : "");
if (ret < 0 || (size_t)ret >= sizeof(rootfs->buf))
return ret_errno(EIO);
ret = safe_mount("proc", rootfs->buf, "proc", 0, NULL, rootfs->mount);
}
}
if (ret < 0)
return log_error_errno(-1, errno, "Failed to mount temporary procfs");
INFO("Created transient procfs mount");
return 1;
}
/* NOTE: Must not be called from inside the container namespace! */ /* NOTE: Must not be called from inside the container namespace! */
static int lxc_create_tmp_proc_mount(struct lxc_conf *conf) static int lxc_create_tmp_proc_mount(struct lxc_conf *conf)
{ {
int mounted; int mounted;
mounted = lxc_mount_proc_if_needed(conf->rootfs.path ? conf->rootfs.mount : ""); mounted = lxc_transient_proc(&conf->rootfs);
if (mounted == -1) { if (mounted == -1) {
SYSERROR("Failed to mount proc in the container");
/* continue only if there is no rootfs */ /* continue only if there is no rootfs */
if (conf->rootfs.path) if (conf->rootfs.path)
return -1; return log_error_errno(-EPERM, EPERM, "Failed to create transient procfs mount");
} else if (mounted == 1) { } else if (mounted == 1) {
conf->tmp_umount_proc = true; conf->transient_procfs_mnt = true;
} }
return 0; return 0;
...@@ -2972,11 +3040,10 @@ static int lxc_create_tmp_proc_mount(struct lxc_conf *conf) ...@@ -2972,11 +3040,10 @@ static int lxc_create_tmp_proc_mount(struct lxc_conf *conf)
void tmp_proc_unmount(struct lxc_conf *lxc_conf) void tmp_proc_unmount(struct lxc_conf *lxc_conf)
{ {
if (!lxc_conf->tmp_umount_proc) if (lxc_conf->transient_procfs_mnt) {
return; (void)umount2("/proc", MNT_DETACH);
lxc_conf->transient_procfs_mnt = false;
(void)umount2("/proc", MNT_DETACH); }
lxc_conf->tmp_umount_proc = false;
} }
/* Walk /proc/mounts and change any shared entries to dependent mounts. */ /* Walk /proc/mounts and change any shared entries to dependent mounts. */
...@@ -3325,7 +3392,8 @@ int lxc_setup(struct lxc_handler *handler) ...@@ -3325,7 +3392,8 @@ int lxc_setup(struct lxc_handler *handler)
} }
lxc_conf->rootfs.dev_mntpt_fd = open_at(lxc_conf->rootfs.mntpt_fd, "dev", lxc_conf->rootfs.dev_mntpt_fd = open_at(lxc_conf->rootfs.mntpt_fd, "dev",
PROTECT_OPATH_DIRECTORY, PROTECT_LOOKUP_BENEATH_XDEV, 0); PROTECT_OPATH_DIRECTORY,
PROTECT_LOOKUP_BENEATH_XDEV, 0);
if (lxc_conf->rootfs.dev_mntpt_fd < 0 && errno != ENOENT) if (lxc_conf->rootfs.dev_mntpt_fd < 0 && errno != ENOENT)
return log_error_errno(-errno, errno, "Failed to open \"/dev\""); return log_error_errno(-errno, errno, "Failed to open \"/dev\"");
......
...@@ -183,6 +183,7 @@ struct lxc_tty_info { ...@@ -183,6 +183,7 @@ struct lxc_tty_info {
* optionals pivot_root, rootfs mount paths * optionals pivot_root, rootfs mount paths
* @path : the rootfs source (directory or device) * @path : the rootfs source (directory or device)
* @mount : where it is mounted * @mount : where it is mounted
* @buf : static buffer to construct paths
* @bev_type : optional backing store type * @bev_type : optional backing store type
* @options : mount options * @options : mount options
* @mountflags : the portion of @options that are flags * @mountflags : the portion of @options that are flags
...@@ -196,6 +197,7 @@ struct lxc_rootfs { ...@@ -196,6 +197,7 @@ struct lxc_rootfs {
int dev_mntpt_fd; int dev_mntpt_fd;
char *path; char *path;
char *mount; char *mount;
char buf[PATH_MAX];
char *bdev_type; char *bdev_type;
char *options; char *options;
unsigned long mountflags; unsigned long mountflags;
...@@ -360,7 +362,7 @@ struct lxc_conf { ...@@ -360,7 +362,7 @@ struct lxc_conf {
char *lsm_se_context; char *lsm_se_context;
char *lsm_se_keyring_context; char *lsm_se_keyring_context;
bool keyring_disable_session; bool keyring_disable_session;
bool tmp_umount_proc; bool transient_procfs_mnt;
struct lxc_seccomp seccomp; struct lxc_seccomp seccomp;
int maincmd_fd; int maincmd_fd;
unsigned int autodev; /* if 1, mount and fill a /dev at start */ unsigned int autodev; /* if 1, mount and fill a /dev at start */
......
...@@ -1081,8 +1081,8 @@ int __safe_mount_beneath_at(int beneath_fd, const char *src, const char *dst, co ...@@ -1081,8 +1081,8 @@ int __safe_mount_beneath_at(int beneath_fd, const char *src, const char *dst, co
{ {
__do_close int source_fd = -EBADF, target_fd = -EBADF; __do_close int source_fd = -EBADF, target_fd = -EBADF;
struct lxc_open_how how = { struct lxc_open_how how = {
.flags = O_RDONLY | O_CLOEXEC | O_PATH, .flags = PROTECT_OPATH_DIRECTORY,
.resolve = RESOLVE_NO_SYMLINKS | RESOLVE_NO_MAGICLINKS | RESOLVE_BENEATH, .resolve = PROTECT_LOOKUP_BENEATH_WITH_MAGICLINKS,
}; };
int ret; int ret;
char src_buf[LXC_PROC_PID_FD_LEN], tgt_buf[LXC_PROC_PID_FD_LEN]; char src_buf[LXC_PROC_PID_FD_LEN], tgt_buf[LXC_PROC_PID_FD_LEN];
...@@ -1122,7 +1122,7 @@ int safe_mount_beneath(const char *beneath, const char *src, const char *dst, co ...@@ -1122,7 +1122,7 @@ int safe_mount_beneath(const char *beneath, const char *src, const char *dst, co
__do_close int beneath_fd = -EBADF; __do_close int beneath_fd = -EBADF;
const char *path = beneath ? beneath : "/"; const char *path = beneath ? beneath : "/";
beneath_fd = openat(-1, path, O_RDONLY | O_CLOEXEC | O_DIRECTORY | O_PATH); beneath_fd = openat(-1, path, PROTECT_OPATH_DIRECTORY);
if (beneath_fd < 0) if (beneath_fd < 0)
return log_error_errno(-errno, errno, "Failed to open %s", path); return log_error_errno(-errno, errno, "Failed to open %s", path);
...@@ -1208,77 +1208,6 @@ int safe_mount(const char *src, const char *dest, const char *fstype, ...@@ -1208,77 +1208,6 @@ int safe_mount(const char *src, const char *dest, const char *fstype,
return 0; return 0;
} }
/*
* Mount a proc under @rootfs if proc self points to a pid other than
* my own. This is needed to have a known-good proc mount for setting
* up LSMs both at container startup and attach.
*
* @rootfs : the rootfs where proc should be mounted
*
* Returns < 0 on failure, 0 if the correct proc was already mounted
* and 1 if a new proc was mounted.
*
* NOTE: not to be called from inside the container namespace!
*/
int lxc_mount_proc_if_needed(const char *rootfs)
{
char path[PATH_MAX] = {0};
int link_to_pid, linklen, mypid, ret;
char link[INTTYPE_TO_STRLEN(pid_t)] = {0};
ret = snprintf(path, PATH_MAX, "%s/proc/self", rootfs);
if (ret < 0 || ret >= PATH_MAX) {
SYSERROR("The name of proc path is too long");
return -1;
}
linklen = readlink(path, link, sizeof(link));
ret = snprintf(path, PATH_MAX, "%s/proc", rootfs);
if (ret < 0 || ret >= PATH_MAX) {
SYSERROR("The name of proc path is too long");
return -1;
}
/* /proc not mounted */
if (linklen < 0) {
if (mkdir(path, 0755) && errno != EEXIST)
return -1;
goto domount;
} else if (linklen >= sizeof(link)) {
link[linklen - 1] = '\0';
ERROR("Readlink returned truncated content: \"%s\"", link);
return -1;
}
mypid = lxc_raw_getpid();
INFO("I am %d, /proc/self points to \"%s\"", mypid, link);
if (lxc_safe_int(link, &link_to_pid) < 0)
return -1;
/* correct procfs is already mounted */
if (link_to_pid == mypid)
return 0;
ret = umount2(path, MNT_DETACH);
if (ret < 0)
SYSWARN("Failed to umount \"%s\" with MNT_DETACH", path);
domount:
/* rootfs is NULL */
if (!strcmp(rootfs, ""))
ret = mount("proc", path, "proc", 0, NULL);
else
ret = safe_mount("proc", path, "proc", 0, NULL, rootfs);
if (ret < 0)
return -1;
INFO("Mounted /proc in container for security transition");
return 1;
}
int open_devnull(void) int open_devnull(void)
{ {
int fd = open("/dev/null", O_RDWR); int fd = open("/dev/null", O_RDWR);
......
...@@ -144,7 +144,6 @@ __hidden extern bool switch_to_ns(pid_t pid, const char *ns); ...@@ -144,7 +144,6 @@ __hidden extern bool switch_to_ns(pid_t pid, const char *ns);
__hidden extern char *get_template_path(const char *t); __hidden extern char *get_template_path(const char *t);
__hidden extern int safe_mount(const char *src, const char *dest, const char *fstype, __hidden extern int safe_mount(const char *src, const char *dest, const char *fstype,
unsigned long flags, const void *data, const char *rootfs); unsigned long flags, const void *data, const char *rootfs);
__hidden extern int lxc_mount_proc_if_needed(const char *rootfs);
__hidden extern int open_devnull(void); __hidden extern int open_devnull(void);
__hidden extern int set_stdfds(int fd); __hidden extern int set_stdfds(int fd);
__hidden extern int null_stdfds(void); __hidden extern int null_stdfds(void);
......
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