fs: Treat foreign mounts as nosuid
[deliverable/linux.git] / fs / namespace.c
index 1a69aa7869758348213850862b7f4b9d75d841ef..aabe8e397fc3f42e8a1311d370ab6c21a226fa1f 100644 (file)
@@ -2185,13 +2185,7 @@ static int do_remount(struct path *path, int flags, int mnt_flags,
        }
        if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) &&
            !(mnt_flags & MNT_NODEV)) {
-               /* Was the nodev implicitly added in mount? */
-               if ((mnt->mnt_ns->user_ns != &init_user_ns) &&
-                   !(sb->s_type->fs_flags & FS_USERNS_DEV_MOUNT)) {
-                       mnt_flags |= MNT_NODEV;
-               } else {
-                       return -EPERM;
-               }
+               return -EPERM;
        }
        if ((mnt->mnt.mnt_flags & MNT_LOCK_NOSUID) &&
            !(mnt_flags & MNT_NOSUID)) {
@@ -2385,7 +2379,6 @@ static int do_new_mount(struct path *path, const char *fstype, int flags,
                        int mnt_flags, const char *name, void *data)
 {
        struct file_system_type *type;
-       struct user_namespace *user_ns = current->nsproxy->mnt_ns->user_ns;
        struct vfsmount *mnt;
        int err;
 
@@ -2396,20 +2389,6 @@ static int do_new_mount(struct path *path, const char *fstype, int flags,
        if (!type)
                return -ENODEV;
 
-       if (user_ns != &init_user_ns) {
-               if (!(type->fs_flags & FS_USERNS_MOUNT)) {
-                       put_filesystem(type);
-                       return -EPERM;
-               }
-               /* Only in special cases allow devices from mounts
-                * created outside the initial user namespace.
-                */
-               if (!(type->fs_flags & FS_USERNS_DEV_MOUNT)) {
-                       flags |= MS_NODEV;
-                       mnt_flags |= MNT_NODEV | MNT_LOCK_NODEV;
-               }
-       }
-
        mnt = vfs_kern_mount(type, flags, name, data);
        if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) &&
            !mnt->mnt_sb->s_subtype)
@@ -3236,12 +3215,8 @@ static bool mnt_already_visible(struct mnt_namespace *ns, struct vfsmount *new,
                if (mnt->mnt.mnt_root != mnt->mnt.mnt_sb->s_root)
                        continue;
 
-               /* Read the mount flags and filter out flags that
-                * may safely be ignored.
-                */
+               /* A local view of the mount flags */
                mnt_flags = mnt->mnt.mnt_flags;
-               if (mnt->mnt.mnt_sb->s_iflags & SB_I_NOEXEC)
-                       mnt_flags &= ~(MNT_LOCK_NOSUID | MNT_LOCK_NOEXEC);
 
                /* Don't miss readonly hidden in the superblock flags */
                if (mnt->mnt.mnt_sb->s_flags & MS_RDONLY)
@@ -3253,15 +3228,6 @@ static bool mnt_already_visible(struct mnt_namespace *ns, struct vfsmount *new,
                if ((mnt_flags & MNT_LOCK_READONLY) &&
                    !(new_flags & MNT_READONLY))
                        continue;
-               if ((mnt_flags & MNT_LOCK_NODEV) &&
-                   !(new_flags & MNT_NODEV))
-                       continue;
-               if ((mnt_flags & MNT_LOCK_NOSUID) &&
-                   !(new_flags & MNT_NOSUID))
-                       continue;
-               if ((mnt_flags & MNT_LOCK_NOEXEC) &&
-                   !(new_flags & MNT_NOEXEC))
-                       continue;
                if ((mnt_flags & MNT_LOCK_ATIME) &&
                    ((mnt_flags & MNT_ATIME_MASK) != (new_flags & MNT_ATIME_MASK)))
                        continue;
@@ -3281,9 +3247,6 @@ static bool mnt_already_visible(struct mnt_namespace *ns, struct vfsmount *new,
                }
                /* Preserve the locked attributes */
                *new_mnt_flags |= mnt_flags & (MNT_LOCK_READONLY | \
-                                              MNT_LOCK_NODEV    | \
-                                              MNT_LOCK_NOSUID   | \
-                                              MNT_LOCK_NOEXEC   | \
                                               MNT_LOCK_ATIME);
                visible = true;
                goto found;
@@ -3296,6 +3259,7 @@ found:
 
 static bool mount_too_revealing(struct vfsmount *mnt, int *new_mnt_flags)
 {
+       const unsigned long required_iflags = SB_I_NOEXEC | SB_I_NODEV;
        struct mnt_namespace *ns = current->nsproxy->mnt_ns;
        unsigned long s_iflags;
 
@@ -3307,9 +3271,28 @@ static bool mount_too_revealing(struct vfsmount *mnt, int *new_mnt_flags)
        if (!(s_iflags & SB_I_USERNS_VISIBLE))
                return false;
 
+       if ((s_iflags & required_iflags) != required_iflags) {
+               WARN_ONCE(1, "Expected s_iflags to contain 0x%lx\n",
+                         required_iflags);
+               return true;
+       }
+
        return !mnt_already_visible(ns, mnt, new_mnt_flags);
 }
 
+bool mnt_may_suid(struct vfsmount *mnt)
+{
+       /*
+        * Foreign mounts (accessed via fchdir or through /proc
+        * symlinks) are always treated as if they are nosuid.  This
+        * prevents namespaces from trusting potentially unsafe
+        * suid/sgid bits, file caps, or security labels that originate
+        * in other namespaces.
+        */
+       return !(mnt->mnt_flags & MNT_NOSUID) && check_mnt(real_mount(mnt)) &&
+              current_in_userns(mnt->mnt_sb->s_user_ns);
+}
+
 static struct ns_common *mntns_get(struct task_struct *task)
 {
        struct ns_common *ns = NULL;
This page took 0.065651 seconds and 5 git commands to generate.