]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
nsfs: tighten permission checks for ns iteration ioctls
authorChristian Brauner <brauner@kernel.org>
Thu, 26 Feb 2026 13:50:09 +0000 (14:50 +0100)
committerChristian Brauner <brauner@kernel.org>
Fri, 27 Feb 2026 21:00:08 +0000 (22:00 +0100)
Even privileged services should not necessarily be able to see other
privileged service's namespaces so they can't leak information to each
other. Use may_see_all_namespaces() helper that centralizes this policy
until the nstree adapts.

Link: https://patch.msgid.link/20260226-work-visibility-fixes-v1-1-d2c2853313bd@kernel.org
Fixes: a1d220d9dafa ("nsfs: iterate through mount namespaces")
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Cc: stable@kernel.org # v6.12+
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/nsfs.c
include/linux/ns_common.h
kernel/nscommon.c

index db91de2086456bb9fe0547be7dbbd2de87c97ca7..be36c10c38cf81a2862c3d44f4a29e474a350eff 100644 (file)
--- a/fs/nsfs.c
+++ b/fs/nsfs.c
@@ -199,6 +199,17 @@ static bool nsfs_ioctl_valid(unsigned int cmd)
        return false;
 }
 
+static bool may_use_nsfs_ioctl(unsigned int cmd)
+{
+       switch (_IOC_NR(cmd)) {
+       case _IOC_NR(NS_MNT_GET_NEXT):
+               fallthrough;
+       case _IOC_NR(NS_MNT_GET_PREV):
+               return may_see_all_namespaces();
+       }
+       return true;
+}
+
 static long ns_ioctl(struct file *filp, unsigned int ioctl,
                        unsigned long arg)
 {
@@ -214,6 +225,8 @@ static long ns_ioctl(struct file *filp, unsigned int ioctl,
 
        if (!nsfs_ioctl_valid(ioctl))
                return -ENOIOCTLCMD;
+       if (!may_use_nsfs_ioctl(ioctl))
+               return -EPERM;
 
        ns = get_proc_ns(file_inode(filp));
        switch (ioctl) {
index 825f5865bfc5aeef9f3343380e64d8c18749d2c7..c8e227a3f9e22b14d83cc90fd433ad3c15544ac9 100644 (file)
@@ -55,6 +55,8 @@ static __always_inline bool is_ns_init_id(const struct ns_common *ns)
 
 #define ns_common_free(__ns) __ns_common_free(to_ns_common((__ns)))
 
+bool may_see_all_namespaces(void);
+
 static __always_inline __must_check int __ns_ref_active_read(const struct ns_common *ns)
 {
        return atomic_read(&ns->__ns_ref_active);
index bdc3c86231d38e0c46e6c9b118a83256bcb332d0..3166c1fd844afd6141f0042e1455604693872da5 100644 (file)
@@ -309,3 +309,9 @@ void __ns_ref_active_get(struct ns_common *ns)
                        return;
        }
 }
+
+bool may_see_all_namespaces(void)
+{
+       return (task_active_pid_ns(current) == &init_pid_ns) &&
+              ns_capable_noaudit(init_pid_ns.user_ns, CAP_SYS_ADMIN);
+}