diff options
| -rw-r--r-- | fs/namespace.c | 24 |
1 files changed, 21 insertions, 3 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 8e7edaf60fe1..63b9806235e6 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
| @@ -2332,7 +2332,7 @@ unlock: | |||
| 2332 | return err; | 2332 | return err; |
| 2333 | } | 2333 | } |
| 2334 | 2334 | ||
| 2335 | static bool fs_fully_visible(struct file_system_type *fs_type); | 2335 | static bool fs_fully_visible(struct file_system_type *fs_type, int *new_mnt_flags); |
| 2336 | 2336 | ||
| 2337 | /* | 2337 | /* |
| 2338 | * create a new mount for userspace and request it to be added into the | 2338 | * 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, | |||
| 2366 | mnt_flags |= MNT_NODEV | MNT_LOCK_NODEV; | 2366 | mnt_flags |= MNT_NODEV | MNT_LOCK_NODEV; |
| 2367 | } | 2367 | } |
| 2368 | if (type->fs_flags & FS_USERNS_VISIBLE) { | 2368 | if (type->fs_flags & FS_USERNS_VISIBLE) { |
| 2369 | if (!fs_fully_visible(type)) | 2369 | if (!fs_fully_visible(type, &mnt_flags)) |
| 2370 | return -EPERM; | 2370 | return -EPERM; |
| 2371 | } | 2371 | } |
| 2372 | } | 2372 | } |
| @@ -3170,9 +3170,10 @@ bool current_chrooted(void) | |||
| 3170 | return chrooted; | 3170 | return chrooted; |
| 3171 | } | 3171 | } |
| 3172 | 3172 | ||
| 3173 | static bool fs_fully_visible(struct file_system_type *type) | 3173 | static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags) |
| 3174 | { | 3174 | { |
| 3175 | struct mnt_namespace *ns = current->nsproxy->mnt_ns; | 3175 | struct mnt_namespace *ns = current->nsproxy->mnt_ns; |
| 3176 | int new_flags = *new_mnt_flags; | ||
| 3176 | struct mount *mnt; | 3177 | struct mount *mnt; |
| 3177 | bool visible = false; | 3178 | bool visible = false; |
| 3178 | 3179 | ||
| @@ -3191,6 +3192,19 @@ static bool fs_fully_visible(struct file_system_type *type) | |||
| 3191 | if (mnt->mnt.mnt_root != mnt->mnt.mnt_sb->s_root) | 3192 | if (mnt->mnt.mnt_root != mnt->mnt.mnt_sb->s_root) |
| 3192 | continue; | 3193 | continue; |
| 3193 | 3194 | ||
| 3195 | /* Verify the mount flags are equal to or more permissive | ||
| 3196 | * than the proposed new mount. | ||
| 3197 | */ | ||
| 3198 | if ((mnt->mnt.mnt_flags & MNT_LOCK_READONLY) && | ||
| 3199 | !(new_flags & MNT_READONLY)) | ||
| 3200 | continue; | ||
| 3201 | if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) && | ||
| 3202 | !(new_flags & MNT_NODEV)) | ||
| 3203 | continue; | ||
| 3204 | if ((mnt->mnt.mnt_flags & MNT_LOCK_ATIME) && | ||
| 3205 | ((mnt->mnt.mnt_flags & MNT_ATIME_MASK) != (new_flags & MNT_ATIME_MASK))) | ||
| 3206 | continue; | ||
| 3207 | |||
| 3194 | /* This mount is not fully visible if there are any child mounts | 3208 | /* This mount is not fully visible if there are any child mounts |
| 3195 | * that cover anything except for empty directories. | 3209 | * that cover anything except for empty directories. |
| 3196 | */ | 3210 | */ |
| @@ -3201,6 +3215,10 @@ static bool fs_fully_visible(struct file_system_type *type) | |||
| 3201 | if (inode->i_nlink > 2) | 3215 | if (inode->i_nlink > 2) |
| 3202 | goto next; | 3216 | goto next; |
| 3203 | } | 3217 | } |
| 3218 | /* Preserve the locked attributes */ | ||
| 3219 | *new_mnt_flags |= mnt->mnt.mnt_flags & (MNT_LOCK_READONLY | \ | ||
| 3220 | MNT_LOCK_NODEV | \ | ||
| 3221 | MNT_LOCK_ATIME); | ||
| 3204 | visible = true; | 3222 | visible = true; |
| 3205 | goto found; | 3223 | goto found; |
| 3206 | next: ; | 3224 | next: ; |
