[lxc-devel] [lxc/master] add openat2() and safe_mount_beneath
brauner on Github
lxc-bot at linuxcontainers.org
Sun Aug 9 13:41:28 UTC 2020
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 364 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200809/fab62a9f/attachment.bin>
-------------- next part --------------
From 66ac24bff1df0b5107fcd7521aaf5cc299d0059d Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sun, 9 Aug 2020 12:48:02 +0200
Subject: [PATCH 1/3] syscalls: add openat2()
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
configure.ac | 3 +-
src/lxc/conf.c | 2 +-
src/lxc/syscall_numbers.h | 20 +++++++++++++
src/lxc/syscall_wrappers.h | 57 ++++++++++++++++++++++++++++++++++++++
4 files changed, 80 insertions(+), 2 deletions(-)
diff --git a/configure.ac b/configure.ac
index 70099e3ad0..f58487f5d0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -622,7 +622,8 @@ AC_CHECK_HEADER([ifaddrs.h],
AC_HEADER_MAJOR
# Check for some syscalls functions
-AC_CHECK_FUNCS([setns pivot_root sethostname unshare rand_r confstr faccessat gettid memfd_create move_mount open_tree execveat clone3 fsopen fspick fsconfig fsmount])
+AC_CHECK_FUNCS([setns pivot_root sethostname unshare rand_r confstr faccessat gettid memfd_create move_mount open_tree execveat clone3 fsopen fspick fsconfig fsmount, openat2])
+AC_CHECK_TYPES([struct open_how], [], [], [[#include <linux/openat2.h>]])
AC_CHECK_TYPES([struct clone_args], [], [], [[#include <linux/sched.h>]])
AC_CHECK_MEMBERS([struct clone_args.set_tid],[],[],[[#include <linux/sched.h>]])
AC_CHECK_MEMBERS([struct clone_args.cgroup],[],[],[[#include <linux/sched.h>]])
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 36a2309a43..2e513d1cc7 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -1077,7 +1077,7 @@ static int mount_autodev(const char *name, const struct lxc_rootfs *rootfs,
goto reset_umask;
}
- ret = safe_mount("none", path, "tmpfs", 0, mount_options,
+ ret = safe_mount("none", "dev", "tmpfs", 0, mount_options,
rootfs->path ? rootfs->mount : NULL );
if (ret < 0) {
SYSERROR("Failed to mount tmpfs on \"%s\"", path);
diff --git a/src/lxc/syscall_numbers.h b/src/lxc/syscall_numbers.h
index 72e4ffe460..8305173d6b 100644
--- a/src/lxc/syscall_numbers.h
+++ b/src/lxc/syscall_numbers.h
@@ -640,4 +640,24 @@
#endif
#endif
+#ifndef __NR_openat2
+ #if defined __alpha__
+ #define __NR_openat2 547
+ #elif defined _MIPS_SIM
+ #if _MIPS_SIM == _MIPS_SIM_ABI32 /* o32 */
+ #define __NR_openat2 4437
+ #endif
+ #if _MIPS_SIM == _MIPS_SIM_NABI32 /* n32 */
+ #define __NR_openat2 6437
+ #endif
+ #if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */
+ #define __NR_openat2 5437
+ #endif
+ #elif defined __ia64__
+ #define __NR_openat2 (437 + 1024)
+ #else
+ #define __NR_openat2 437
+ #endif
+#endif
+
#endif /* __LXC_SYSCALL_NUMBERS_H */
diff --git a/src/lxc/syscall_wrappers.h b/src/lxc/syscall_wrappers.h
index 6aaa437226..1c1af73f1f 100644
--- a/src/lxc/syscall_wrappers.h
+++ b/src/lxc/syscall_wrappers.h
@@ -203,4 +203,61 @@ static inline int fsmount_lxc(int fs_fd, unsigned int flags, unsigned int attr_f
extern int fsmount(int fs_fd, unsigned int flags, unsigned int attr_flags);
#endif
+/*
+ * Arguments for how openat2(2) should open the target path. If only @flags and
+ * @mode are non-zero, then openat2(2) operates very similarly to openat(2).
+ *
+ * However, unlike openat(2), unknown or invalid bits in @flags result in
+ * -EINVAL rather than being silently ignored. @mode must be zero unless one of
+ * {O_CREAT, O_TMPFILE} are set.
+ *
+ * @flags: O_* flags.
+ * @mode: O_CREAT/O_TMPFILE file mode.
+ * @resolve: RESOLVE_* flags.
+ */
+struct lxc_open_how {
+ __u64 flags;
+ __u64 mode;
+ __u64 resolve;
+};
+
+/* how->resolve flags for openat2(2). */
+#ifndef RESOLVE_NO_XDEV
+#define RESOLVE_NO_XDEV 0x01 /* Block mount-point crossings
+ (includes bind-mounts). */
+#endif
+
+#ifndef RESOLVE_NO_MAGICLINKS
+#define RESOLVE_NO_MAGICLINKS 0x02 /* Block traversal through procfs-style
+ "magic-links". */
+#endif
+
+#ifndef RESOLVE_NO_SYMLINKS
+#define RESOLVE_NO_SYMLINKS 0x04 /* Block traversal through all symlinks
+ (implies OEXT_NO_MAGICLINKS) */
+#endif
+
+#ifndef RESOLVE_BENEATH
+#define RESOLVE_BENEATH 0x08 /* Block "lexical" trickery like
+ "..", symlinks, and absolute
+ paths which escape the dirfd. */
+#endif
+
+#ifndef RESOLVE_IN_ROOT
+#define RESOLVE_IN_ROOT 0x10 /* Make all jumps to "/" and ".."
+ be scoped inside the dirfd
+ (similar to chroot(2)). */
+#endif
+
+#ifndef HAVE_OPENAT2
+static inline int openat2(int dfd, const char *filename, struct lxc_open_how *how, size_t size)
+{
+ /* When struct open_how is updated we should update lxc as well. */
+#ifndef HAVE_STRUCT_OPEN_HOW
+ BUILD_BUG_ON(sizeof(struct lxc_open_how) != sizeof(struct open_how));
+#endif
+ return syscall(__NR_openat2, dfd, filename, (struct open_how *)how, size);
+}
+#endif /* HAVE_OPENAT2 */
+
#endif /* __LXC_SYSCALL_WRAPPER_H */
From 839314f139190966ec020808c37e48d582815e91 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sun, 9 Aug 2020 15:24:26 +0200
Subject: [PATCH 2/3] utils: add safe_mount_beneath() based on openat2()
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
src/lxc/utils.c | 38 ++++++++++++++++++++++++++++++++++++++
src/lxc/utils.h | 3 +++
2 files changed, 41 insertions(+)
diff --git a/src/lxc/utils.c b/src/lxc/utils.c
index 39de189afc..4efed645ff 100644
--- a/src/lxc/utils.c
+++ b/src/lxc/utils.c
@@ -1079,6 +1079,44 @@ static int open_without_symlink(const char *target, const char *prefix_skip)
return dirfd;
}
+int safe_mount_beneath(const char *beneath, const char *src, const char *dst, const char *fstype,
+ unsigned int flags, const void *data)
+{
+ __do_close int beneath_fd = -EBADF, source_fd = -EBADF, target_fd = -EBADF;
+ const char *path = beneath ? beneath : "/";
+ struct lxc_open_how how = {
+ .flags = O_RDONLY | O_CLOEXEC | O_PATH,
+ .resolve = RESOLVE_NO_XDEV | RESOLVE_NO_SYMLINKS | RESOLVE_NO_MAGICLINKS | RESOLVE_BENEATH,
+ };
+ int ret;
+ char src_buf[LXC_PROC_PID_FD_LEN], tgt_buf[LXC_PROC_PID_FD_LEN];
+
+ beneath_fd = openat(-1, beneath, O_RDONLY | O_CLOEXEC | O_DIRECTORY | O_PATH);
+ if (beneath_fd < 0)
+ return log_error_errno(-errno, errno, "Failed to open %s", path);
+
+ if ((flags & MS_BIND) && src && src[0] != '/') {
+ source_fd = openat2(beneath_fd, src, &how, sizeof(how));
+ if (source_fd < 0)
+ return -errno;
+ snprintf(src_buf, sizeof(src_buf), "/proc/self/fd/%d", source_fd);
+ } else {
+ src_buf[0] = '\0';
+ }
+
+ target_fd = openat2(beneath_fd, dst, &how, sizeof(how));
+ if (target_fd < 0)
+ return -errno;
+ snprintf(tgt_buf, sizeof(tgt_buf), "/proc/self/fd/%d", target_fd);
+
+ if (!is_empty_string(src_buf))
+ ret = mount(src_buf, tgt_buf, fstype, flags, data);
+ else
+ ret = mount(src, tgt_buf, fstype, flags, data);
+
+ return ret;
+}
+
/*
* Safely mount a path into a container, ensuring that the mount target
* is under the container's @rootfs. (If @rootfs is NULL, then the container
diff --git a/src/lxc/utils.h b/src/lxc/utils.h
index 3f9a409150..b0de9d9abc 100644
--- a/src/lxc/utils.h
+++ b/src/lxc/utils.h
@@ -246,4 +246,7 @@ static inline bool gid_valid(gid_t gid)
__hidden extern bool multiply_overflow(int64_t base, uint64_t mult, int64_t *res);
+extern int safe_mount_beneath(const char *beneath, const char *src, const char *dst,
+ const char *fstype, unsigned int flags, const void *data);
+
#endif /* __LXC_UTILS_H */
From 6c2262f903166a7817b45bb84e76b4f6e4fa10be Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sun, 9 Aug 2020 15:37:31 +0200
Subject: [PATCH 3/3] conf: switch mount_autodev() to new safe_mount_beneath()
helper
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
src/lxc/conf.c | 45 +++++++++++++++++++++++++--------------------
1 file changed, 25 insertions(+), 20 deletions(-)
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 2e513d1cc7..5fcfb0afa3 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -1051,50 +1051,55 @@ static int lxc_create_ttys(struct lxc_handler *handler)
static int mount_autodev(const char *name, const struct lxc_rootfs *rootfs,
int autodevtmpfssize, const char *lxcpath)
{
- __do_free char *path = NULL;
+ __do_close int root_mntpt_fd = -EBADF;
+ const char *path = rootfs->path ? rootfs->mount : NULL;
int ret;
- size_t clen;
mode_t cur_mask;
char mount_options[128];
INFO("Preparing \"/dev\"");
- /* $(rootfs->mount) + "/dev/pts" + '\0' */
- clen = (rootfs->path ? strlen(rootfs->mount) : 0) + 9;
- path = must_realloc(NULL, clen);
sprintf(mount_options, "size=%d,mode=755", (autodevtmpfssize != 0) ? autodevtmpfssize : 500000);
DEBUG("Using mount options: %s", mount_options);
- ret = snprintf(path, clen, "%s/dev", rootfs->path ? rootfs->mount : "");
- if (ret < 0 || (size_t)ret >= clen)
- return -1;
+ root_mntpt_fd = openat(-1, path, O_RDONLY | O_CLOEXEC | O_PATH | O_DIRECTORY);
+ if (root_mntpt_fd < 0)
+ return log_error_errno(-errno, errno, "Failed to open \"%s\"", path);
cur_mask = umask(S_IXUSR | S_IXGRP | S_IXOTH);
- ret = mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+ ret = mkdirat(root_mntpt_fd, "dev" , S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
if (ret < 0 && errno != EEXIST) {
SYSERROR("Failed to create \"/dev\" directory");
ret = -errno;
goto reset_umask;
}
- ret = safe_mount("none", "dev", "tmpfs", 0, mount_options,
- rootfs->path ? rootfs->mount : NULL );
+ ret = safe_mount_beneath(path, "none", "dev", "tmpfs", 0, mount_options);
if (ret < 0) {
- SYSERROR("Failed to mount tmpfs on \"%s\"", path);
- goto reset_umask;
- }
- TRACE("Mounted tmpfs on \"%s\"", path);
+ __do_free char *fallback_path = NULL;
- ret = snprintf(path, clen, "%s/dev/pts", rootfs->path ? rootfs->mount : "");
- if (ret < 0 || (size_t)ret >= clen) {
- ret = -1;
- goto reset_umask;
+ if (errno != ENOSYS) {
+ SYSERROR("Failed to mount tmpfs on \"%s\"", path);
+ goto reset_umask;
+ }
+
+ if (path) {
+ fallback_path = must_make_path(path, "/dev", NULL);
+ ret = safe_mount("none", fallback_path, "tmpfs", 0, mount_options, path);
+ } else {
+ ret = safe_mount("none", "dev", "tmpfs", 0, mount_options, NULL);
+ }
+ if (ret < 0) {
+ SYSERROR("Failed to mount tmpfs on \"%s\"", path);
+ goto reset_umask;
+ }
}
+ TRACE("Mounted tmpfs on \"%s\"", path);
/* If we are running on a devtmpfs mapping, dev/pts may already exist.
* If not, then create it and exit if that fails...
*/
- ret = mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+ ret = mkdirat(root_mntpt_fd, "dev/pts", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
if (ret < 0 && errno != EEXIST) {
SYSERROR("Failed to create directory \"%s\"", path);
ret = -errno;
More information about the lxc-devel
mailing list