|
@@ -2332,7 +2332,7 @@ unlock:
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
-static bool fs_fully_visible(struct file_system_type *fs_type);
|
|
|
|
|
|
+static bool fs_fully_visible(struct file_system_type *fs_type, int *new_mnt_flags);
|
|
|
|
|
|
/*
|
|
/*
|
|
* create a new mount for userspace and request it to be added into the
|
|
* create a new mount for userspace and request it to be added into the
|
|
@@ -2366,7 +2366,7 @@ static int do_new_mount(struct path *path, const char *fstype, int flags,
|
|
mnt_flags |= MNT_NODEV | MNT_LOCK_NODEV;
|
|
mnt_flags |= MNT_NODEV | MNT_LOCK_NODEV;
|
|
}
|
|
}
|
|
if (type->fs_flags & FS_USERNS_VISIBLE) {
|
|
if (type->fs_flags & FS_USERNS_VISIBLE) {
|
|
- if (!fs_fully_visible(type))
|
|
|
|
|
|
+ if (!fs_fully_visible(type, &mnt_flags))
|
|
return -EPERM;
|
|
return -EPERM;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -3170,9 +3170,10 @@ bool current_chrooted(void)
|
|
return chrooted;
|
|
return chrooted;
|
|
}
|
|
}
|
|
|
|
|
|
-static bool fs_fully_visible(struct file_system_type *type)
|
|
|
|
|
|
+static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
|
|
{
|
|
{
|
|
struct mnt_namespace *ns = current->nsproxy->mnt_ns;
|
|
struct mnt_namespace *ns = current->nsproxy->mnt_ns;
|
|
|
|
+ int new_flags = *new_mnt_flags;
|
|
struct mount *mnt;
|
|
struct mount *mnt;
|
|
bool visible = false;
|
|
bool visible = false;
|
|
|
|
|
|
@@ -3191,6 +3192,19 @@ static bool fs_fully_visible(struct file_system_type *type)
|
|
if (mnt->mnt.mnt_root != mnt->mnt.mnt_sb->s_root)
|
|
if (mnt->mnt.mnt_root != mnt->mnt.mnt_sb->s_root)
|
|
continue;
|
|
continue;
|
|
|
|
|
|
|
|
+ /* Verify the mount flags are equal to or more permissive
|
|
|
|
+ * than the proposed new mount.
|
|
|
|
+ */
|
|
|
|
+ if ((mnt->mnt.mnt_flags & MNT_LOCK_READONLY) &&
|
|
|
|
+ !(new_flags & MNT_READONLY))
|
|
|
|
+ continue;
|
|
|
|
+ if ((mnt->mnt.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)))
|
|
|
|
+ continue;
|
|
|
|
+
|
|
/* This mount is not fully visible if there are any child mounts
|
|
/* This mount is not fully visible if there are any child mounts
|
|
* that cover anything except for empty directories.
|
|
* that cover anything except for empty directories.
|
|
*/
|
|
*/
|
|
@@ -3201,6 +3215,10 @@ static bool fs_fully_visible(struct file_system_type *type)
|
|
if (inode->i_nlink > 2)
|
|
if (inode->i_nlink > 2)
|
|
goto next;
|
|
goto next;
|
|
}
|
|
}
|
|
|
|
+ /* Preserve the locked attributes */
|
|
|
|
+ *new_mnt_flags |= mnt->mnt.mnt_flags & (MNT_LOCK_READONLY | \
|
|
|
|
+ MNT_LOCK_NODEV | \
|
|
|
|
+ MNT_LOCK_ATIME);
|
|
visible = true;
|
|
visible = true;
|
|
goto found;
|
|
goto found;
|
|
next: ;
|
|
next: ;
|