UPSTREAM: arm64: dts: rockchip: add three new resets for rk3399 PCIe
[firefly-linux-kernel-4.4.55.git] / fs / namespace.c
index 2b8aa15fd6dfa755368ddf21136eaab5192f1e28..5be02a0635be0e1e84e5a88bed1a5b2ceb5ef6af 100644 (file)
@@ -1562,6 +1562,7 @@ void __detach_mounts(struct dentry *dentry)
                goto out_unlock;
 
        lock_mount_hash();
+       event++;
        while (!hlist_empty(&mp->m_list)) {
                mnt = hlist_entry(mp->m_list.first, struct mount, mnt_mp_list);
                if (mnt->mnt.mnt_flags & MNT_UMOUNT) {
@@ -2401,8 +2402,10 @@ static int do_new_mount(struct path *path, const char *fstype, int flags,
                        mnt_flags |= MNT_NODEV | MNT_LOCK_NODEV;
                }
                if (type->fs_flags & FS_USERNS_VISIBLE) {
-                       if (!fs_fully_visible(type, &mnt_flags))
+                       if (!fs_fully_visible(type, &mnt_flags)) {
+                               put_filesystem(type);
                                return -EPERM;
+                       }
                }
        }
 
@@ -3218,6 +3221,8 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
        down_read(&namespace_sem);
        list_for_each_entry(mnt, &ns->list, mnt_list) {
                struct mount *child;
+               int mnt_flags;
+
                if (mnt->mnt.mnt_sb->s_type != type)
                        continue;
 
@@ -3227,17 +3232,34 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
                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.
+                */
+               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)
+                       mnt_flags |= MNT_LOCK_READONLY;
+
                /* Verify the mount flags are equal to or more permissive
                 * than the proposed new mount.
                 */
-               if ((mnt->mnt.mnt_flags & MNT_LOCK_READONLY) &&
+               if ((mnt_flags & MNT_LOCK_READONLY) &&
                    !(new_flags & MNT_READONLY))
                        continue;
-               if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) &&
+               if ((mnt_flags & MNT_LOCK_NODEV) &&
                    !(new_flags & MNT_NODEV))
                        continue;
-               if ((mnt->mnt.mnt_flags & MNT_LOCK_ATIME) &&
-                   ((mnt->mnt.mnt_flags & MNT_ATIME_MASK) != (new_flags & MNT_ATIME_MASK)))
+               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;
 
                /* This mount is not fully visible if there are any
@@ -3247,16 +3269,18 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
                list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) {
                        struct inode *inode = child->mnt_mountpoint->d_inode;
                        /* Only worry about locked mounts */
-                       if (!(mnt->mnt.mnt_flags & MNT_LOCKED))
+                       if (!(child->mnt.mnt_flags & MNT_LOCKED))
                                continue;
                        /* Is the directory permanetly empty? */
                        if (!is_empty_dir_inode(inode))
                                goto next;
                }
                /* Preserve the locked attributes */
-               *new_mnt_flags |= mnt->mnt.mnt_flags & (MNT_LOCK_READONLY | \
-                                                       MNT_LOCK_NODEV    | \
-                                                       MNT_LOCK_ATIME);
+               *new_mnt_flags |= mnt_flags & (MNT_LOCK_READONLY | \
+                                              MNT_LOCK_NODEV    | \
+                                              MNT_LOCK_NOSUID   | \
+                                              MNT_LOCK_NOEXEC   | \
+                                              MNT_LOCK_ATIME);
                visible = true;
                goto found;
        next:   ;