[PATCH 4/8] nsfs: add NS_USER_GET_INFO ioctl to inspect user namespace capabilities

From: Hallgrimur H. Gunnarsson

Date: Wed Oct 28 2026 - 18:26:24 EST


With the introduction of a capability bounding set for user namespaces,
userspace needs a way to inspect the capability ceiling enforced on a
given user namespace.

Introduce the NS_USER_GET_INFO ioctl on nsfs file descriptors to query
user namespace metadata, mirroring the extensible structure pattern
used by NS_MNT_GET_INFO.

Signed-off-by: Hallgrimur H. Gunnarsson <halg@xxxxxxxxxx>
---
fs/nsfs.c | 29 +++++++++++++++++++++++++++++
include/uapi/linux/nsfs.h | 17 +++++++++++++++++
2 files changed, 46 insertions(+)

diff --git a/fs/nsfs.c b/fs/nsfs.c
index c3b6ae76594a..50711362d792 100644
--- a/fs/nsfs.c
+++ b/fs/nsfs.c
@@ -170,6 +170,17 @@ static int copy_ns_info_to_user(const struct mnt_namespace *mnt_ns,
return 0;
}

+static int copy_user_ns_info_to_user(const struct user_namespace *user_ns,
+ struct user_ns_info __user *uinfo,
+ size_t usize, struct user_ns_info *kinfo)
+{
+ kinfo->size = min(usize, sizeof(*kinfo));
+ kinfo->spare = 0;
+ kinfo->cap_bset = user_ns->cap_bset.val;
+
+ return copy_struct_to_user(uinfo, usize, kinfo, sizeof(*kinfo), NULL);
+}
+
static bool nsfs_ioctl_valid(unsigned int cmd)
{
switch (cmd) {
@@ -194,6 +205,8 @@ static bool nsfs_ioctl_valid(unsigned int cmd)
return extensible_ioctl_valid(cmd, NS_MNT_GET_NEXT, MNT_NS_INFO_SIZE_VER0);
case _IOC_NR(NS_MNT_GET_PREV):
return extensible_ioctl_valid(cmd, NS_MNT_GET_PREV, MNT_NS_INFO_SIZE_VER0);
+ case _IOC_NR(NS_USER_GET_INFO):
+ return extensible_ioctl_valid(cmd, NS_USER_GET_INFO, USER_NS_INFO_SIZE_VER0);
}

return false;
@@ -360,6 +373,22 @@ static long ns_ioctl(struct file *filp, unsigned int ioctl,
ret = fd_publish(fdf);
break;
}
+ case _IOC_NR(NS_USER_GET_INFO): {
+ struct user_ns_info __user *uinfo = (struct user_ns_info __user *)arg;
+ struct user_ns_info kinfo = {};
+ size_t usize = _IOC_SIZE(ioctl);
+
+ if (ns->ns_type != CLONE_NEWUSER)
+ return -EINVAL;
+
+ if (!uinfo)
+ return -EINVAL;
+
+ if (usize < USER_NS_INFO_SIZE_VER0)
+ return -EINVAL;
+
+ return copy_user_ns_info_to_user(to_user_ns(ns), uinfo, usize, &kinfo);
+ }
default:
ret = -ENOTTY;
}
diff --git a/include/uapi/linux/nsfs.h b/include/uapi/linux/nsfs.h
index 007fed5971b4..d2996d47c857 100644
--- a/include/uapi/linux/nsfs.h
+++ b/include/uapi/linux/nsfs.h
@@ -44,6 +44,23 @@ struct mnt_ns_info {
#define NS_GET_MNTNS_ID _IOR(NSIO, 5, __u64)
#define NS_GET_ID _IOR(NSIO, 13, __u64)

+/**
+ * struct user_ns_info - information about a user namespace
+ * @size: size of this structure
+ * @spare: reserved for future use
+ * @cap_bset: capability bounding set of the user namespace
+ */
+struct user_ns_info {
+ __u32 size;
+ __u32 spare;
+ __u64 cap_bset;
+};
+
+#define USER_NS_INFO_SIZE_VER0 16 /* sizeof first published struct */
+
+/* Get information about user namespace. */
+#define NS_USER_GET_INFO _IOR(NSIO, 14, struct user_ns_info)
+
enum init_ns_ino {
IPC_NS_INIT_INO = 0xEFFFFFFFU,
UTS_NS_INIT_INO = 0xEFFFFFFEU,
--
2.56.0.313.g2479322e68-goog