From 6ab61ac93e534aec1ea4d16e77c1c355c8286e64 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Thu, 27 Oct 2022 13:14:12 +0200 Subject: [PATCH] namespace: Add hidepid/subset support check Using fsopen()/fsconfig(), we can check if hidepid/subset are supported to avoid the noisy logs from the kernel if they aren't supported. This works on centos/redhat 8 as well since they've backported fsopen()/fsconfig(). (cherry picked from commit 1c265fcd5963603d338233840129ecad8d9c1420) Related #2138081 --- meson.build | 2 ++ src/basic/missing_syscall.h | 40 +++++++++++++++++++++++++++++++ src/core/namespace.c | 47 ++++++++++++++++++++++++++++++++----- 3 files changed, 83 insertions(+), 6 deletions(-) diff --git a/meson.build b/meson.build index 76ad51d3fb..7750534466 100644 --- a/meson.build +++ b/meson.build @@ -606,6 +606,8 @@ foreach ident : [ ['mount_setattr', '''#include '''], ['move_mount', '''#include '''], ['open_tree', '''#include '''], + ['fsopen', '''#include '''], + ['fsconfig', '''#include '''], ['getdents64', '''#include '''], ] diff --git a/src/basic/missing_syscall.h b/src/basic/missing_syscall.h index 793d111c55..d54e59fdf9 100644 --- a/src/basic/missing_syscall.h +++ b/src/basic/missing_syscall.h @@ -593,6 +593,46 @@ static inline int missing_move_mount( /* ======================================================================= */ +#if !HAVE_FSOPEN + +#ifndef FSOPEN_CLOEXEC +#define FSOPEN_CLOEXEC 0x00000001 +#endif + +static inline int missing_fsopen(const char *fsname, unsigned flags) { +# if defined __NR_fsopen && __NR_fsopen >= 0 + return syscall(__NR_fsopen, fsname, flags); +# else + errno = ENOSYS; + return -1; +# endif +} + +# define fsopen missing_fsopen +#endif + +/* ======================================================================= */ + +#if !HAVE_FSCONFIG + +#ifndef FSCONFIG_SET_STRING +#define FSCONFIG_SET_STRING 1 /* Set parameter, supplying a string value */ +#endif + +static inline int missing_fsconfig(int fd, unsigned cmd, const char *key, const void *value, int aux) { +# if defined __NR_fsconfig && __NR_fsconfig >= 0 + return syscall(__NR_fsconfig, fd, cmd, key, value, aux); +# else + errno = ENOSYS; + return -1; +# endif +} + +# define fsconfig missing_fsconfig +#endif + +/* ======================================================================= */ + #if !HAVE_GETDENTS64 static inline ssize_t missing_getdents64(int fd, void *buffer, size_t length) { diff --git a/src/core/namespace.c b/src/core/namespace.c index c3cced7410..852be3bdde 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -26,6 +26,7 @@ #include "list.h" #include "loop-util.h" #include "loopback-setup.h" +#include "missing_syscall.h" #include "mkdir-label.h" #include "mount-util.h" #include "mountpoint-util.h" @@ -1073,6 +1074,27 @@ static int mount_sysfs(const MountEntry *m) { return 1; } +static bool mount_option_supported(const char *fstype, const char *key, const char *value) { + _cleanup_close_ int fd = -1; + int r; + + /* This function assumes support by default. Only if the fsconfig() call fails with -EINVAL/-EOPNOTSUPP + * will it report that the option/value is not supported. */ + + fd = fsopen(fstype, FSOPEN_CLOEXEC); + if (fd < 0) { + if (errno != ENOSYS) + log_debug_errno(errno, "Failed to open superblock context for '%s': %m", fstype); + return true; /* If fsopen() fails for whatever reason, assume the value is supported. */ + } + + r = fsconfig(fd, FSCONFIG_SET_STRING, key, value, 0); + if (r < 0 && !IN_SET(errno, EINVAL, EOPNOTSUPP, ENOSYS)) + log_debug_errno(errno, "Failed to set '%s=%s' on '%s' superblock context: %m", key, value, fstype); + + return r >= 0 || !IN_SET(errno, EINVAL, EOPNOTSUPP); +} + static int mount_procfs(const MountEntry *m, const NamespaceInfo *ns_info) { _cleanup_free_ char *opts = NULL; const char *entry_path; @@ -1090,12 +1112,25 @@ static int mount_procfs(const MountEntry *m, const NamespaceInfo *ns_info) { * per-instance, we'll exclusively use the textual value for hidepid=, since support was * added in the same commit: if it's supported it is thus also per-instance. */ - opts = strjoin("hidepid=", - ns_info->protect_proc == PROTECT_PROC_DEFAULT ? "off" : - protect_proc_to_string(ns_info->protect_proc), - ns_info->proc_subset == PROC_SUBSET_PID ? ",subset=pid" : ""); - if (!opts) - return -ENOMEM; + const char *hpv = ns_info->protect_proc == PROTECT_PROC_DEFAULT ? + "off" : + protect_proc_to_string(ns_info->protect_proc); + + /* hidepid= support was added in 5.8, so we can use fsconfig()/fsopen() (which were added in + * 5.2) to check if hidepid= is supported. This avoids a noisy dmesg log by the kernel when + * trying to use hidepid= on systems where it isn't supported. The same applies for subset=. + * fsopen()/fsconfig() was also backported on some distros which allows us to detect + * hidepid=/subset= support in even more scenarios. */ + + if (mount_option_supported("proc", "hidepid", hpv)) { + opts = strjoin("hidepid=", hpv); + if (!opts) + return -ENOMEM; + } + + if (ns_info->proc_subset == PROC_SUBSET_PID && mount_option_supported("proc", "subset", "pid")) + if (!strextend_with_separator(&opts, ",", "subset=pid")) + return -ENOMEM; } entry_path = mount_entry_path(m);