summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndres Beltran <abeltran@microsoft.com>2024-10-30 18:51:53 +0100
committerAndres Beltran <abeltran@microsoft.com>2024-11-01 19:41:27 +0100
commitedae62120f13b24d51812d1d7c0ab24acb420305 (patch)
tree2d62fab844500d024d58cb72e245716b8345df60 /src
parentcore/service: don't propagate stop jobs if RestartMode=direct (#34768) (diff)
downloadsystemd-edae62120f13b24d51812d1d7c0ab24acb420305.tar.xz
systemd-edae62120f13b24d51812d1d7c0ab24acb420305.zip
namespace-util: add util function to check if id-mapped mounts are supported for a given path
Diffstat (limited to 'src')
-rw-r--r--src/basic/namespace-util.c54
-rw-r--r--src/basic/namespace-util.h2
-rw-r--r--src/test/test-namespace.c8
3 files changed, 64 insertions, 0 deletions
diff --git a/src/basic/namespace-util.c b/src/basic/namespace-util.c
index d9ad25fdd7..16053ff2a9 100644
--- a/src/basic/namespace-util.c
+++ b/src/basic/namespace-util.c
@@ -3,6 +3,9 @@
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
+#if WANT_LINUX_FS_H
+#include <linux/fs.h>
+#endif
#include "errno-util.h"
#include "fd-util.h"
@@ -10,6 +13,8 @@
#include "missing_fs.h"
#include "missing_magic.h"
#include "missing_sched.h"
+#include "missing_syscall.h"
+#include "mountpoint-util.h"
#include "namespace-util.h"
#include "parse-util.h"
#include "process-util.h"
@@ -502,3 +507,52 @@ int is_our_namespace(int fd, NamespaceType request_type) {
return stat_inode_same(&st_ours, &st_fd);
}
+
+int is_idmapping_supported(const char *path) {
+ _cleanup_close_ int mount_fd = -EBADF, userns_fd = -EBADF, dir_fd = -EBADF;
+ _cleanup_free_ char *uid_map = NULL, *gid_map = NULL;
+ int r;
+
+ assert(path);
+
+ if (!mount_new_api_supported())
+ return false;
+
+ r = strextendf(&uid_map, UID_FMT " " UID_FMT " " UID_FMT "\n", UID_NOBODY, UID_NOBODY, 1u);
+ if (r < 0)
+ return r;
+
+ r = strextendf(&gid_map, GID_FMT " " GID_FMT " " GID_FMT "\n", GID_NOBODY, GID_NOBODY, 1u);
+ if (r < 0)
+ return r;
+
+ userns_fd = userns_acquire(uid_map, gid_map);
+ if (ERRNO_IS_NEG_NOT_SUPPORTED(userns_fd))
+ return false;
+ if (userns_fd < 0)
+ return log_debug_errno(userns_fd, "ID-mapping supported namespace acquire failed for '%s' : %m", path);
+
+ dir_fd = RET_NERRNO(open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
+ if (ERRNO_IS_NEG_NOT_SUPPORTED(dir_fd) || dir_fd == -EINVAL)
+ return false;
+ if (dir_fd < 0)
+ return log_debug_errno(dir_fd, "ID-mapping supported open failed for '%s' : %m", path);
+
+ mount_fd = RET_NERRNO(open_tree(dir_fd, "", AT_EMPTY_PATH | OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC));
+ if (ERRNO_IS_NEG_NOT_SUPPORTED(mount_fd) || mount_fd == -EINVAL)
+ return false;
+ if (mount_fd < 0)
+ return log_debug_errno(mount_fd, "ID-mapping supported open_tree failed for '%s' : %m", path);
+
+ r = RET_NERRNO(mount_setattr(mount_fd, "", AT_EMPTY_PATH,
+ &(struct mount_attr) {
+ .attr_set = MOUNT_ATTR_IDMAP | MOUNT_ATTR_NOSUID | MOUNT_ATTR_NOEXEC | MOUNT_ATTR_RDONLY | MOUNT_ATTR_NODEV,
+ .userns_fd = userns_fd,
+ }, sizeof(struct mount_attr)));
+ if (ERRNO_IS_NEG_NOT_SUPPORTED(r) || r == -EINVAL || r == -EPERM)
+ return false;
+ if (r < 0)
+ return log_debug_errno(r, "ID-mapping supported setattr failed for '%s' : %m", path);
+
+ return true;
+}
diff --git a/src/basic/namespace-util.h b/src/basic/namespace-util.h
index c9e1da39ab..105bab6fdb 100644
--- a/src/basic/namespace-util.h
+++ b/src/basic/namespace-util.h
@@ -75,3 +75,5 @@ int parse_userns_uid_range(const char *s, uid_t *ret_uid_shift, uid_t *ret_uid_r
int namespace_open_by_type(NamespaceType type);
int is_our_namespace(int fd, NamespaceType type);
+
+int is_idmapping_supported(const char *path);
diff --git a/src/test/test-namespace.c b/src/test/test-namespace.c
index 2a684ce096..37bce0ae1d 100644
--- a/src/test/test-namespace.c
+++ b/src/test/test-namespace.c
@@ -205,6 +205,14 @@ TEST(protect_kernel_logs) {
assert_se(wait_for_terminate_and_check("ns-kernellogs", pid, WAIT_LOG) == EXIT_SUCCESS);
}
+TEST(idmapping_supported) {
+ assert_se(is_idmapping_supported("/run") >= 0);
+ assert_se(is_idmapping_supported("/var/lib") >= 0);
+ assert_se(is_idmapping_supported("/var/cache") >= 0);
+ assert_se(is_idmapping_supported("/var/log") >= 0);
+ assert_se(is_idmapping_supported("/etc") >= 0);
+}
+
static int intro(void) {
if (!have_namespaces())
return log_tests_skipped("Don't have namespace support");