]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/3.16.3/mnt-correct-permission-checks-in-do_remount.patch
4.9-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 3.16.3 / mnt-correct-permission-checks-in-do_remount.patch
1 From 9566d6742852c527bf5af38af5cbb878dad75705 Mon Sep 17 00:00:00 2001
2 From: "Eric W. Biederman" <ebiederm@xmission.com>
3 Date: Mon, 28 Jul 2014 17:26:07 -0700
4 Subject: mnt: Correct permission checks in do_remount
5
6 From: "Eric W. Biederman" <ebiederm@xmission.com>
7
8 commit 9566d6742852c527bf5af38af5cbb878dad75705 upstream.
9
10 While invesgiating the issue where in "mount --bind -oremount,ro ..."
11 would result in later "mount --bind -oremount,rw" succeeding even if
12 the mount started off locked I realized that there are several
13 additional mount flags that should be locked and are not.
14
15 In particular MNT_NOSUID, MNT_NODEV, MNT_NOEXEC, and the atime
16 flags in addition to MNT_READONLY should all be locked. These
17 flags are all per superblock, can all be changed with MS_BIND,
18 and should not be changable if set by a more privileged user.
19
20 The following additions to the current logic are added in this patch.
21 - nosuid may not be clearable by a less privileged user.
22 - nodev may not be clearable by a less privielged user.
23 - noexec may not be clearable by a less privileged user.
24 - atime flags may not be changeable by a less privileged user.
25
26 The logic with atime is that always setting atime on access is a
27 global policy and backup software and auditing software could break if
28 atime bits are not updated (when they are configured to be updated),
29 and serious performance degradation could result (DOS attack) if atime
30 updates happen when they have been explicitly disabled. Therefore an
31 unprivileged user should not be able to mess with the atime bits set
32 by a more privileged user.
33
34 The additional restrictions are implemented with the addition of
35 MNT_LOCK_NOSUID, MNT_LOCK_NODEV, MNT_LOCK_NOEXEC, and MNT_LOCK_ATIME
36 mnt flags.
37
38 Taken together these changes and the fixes for MNT_LOCK_READONLY
39 should make it safe for an unprivileged user to create a user
40 namespace and to call "mount --bind -o remount,... ..." without
41 the danger of mount flags being changed maliciously.
42
43 Acked-by: Serge E. Hallyn <serge.hallyn@ubuntu.com>
44 Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
45 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
46
47 ---
48 fs/namespace.c | 36 +++++++++++++++++++++++++++++++++---
49 include/linux/mount.h | 5 +++++
50 2 files changed, 38 insertions(+), 3 deletions(-)
51
52 --- a/fs/namespace.c
53 +++ b/fs/namespace.c
54 @@ -890,8 +890,21 @@ static struct mount *clone_mnt(struct mo
55
56 mnt->mnt.mnt_flags = old->mnt.mnt_flags & ~(MNT_WRITE_HOLD|MNT_MARKED);
57 /* Don't allow unprivileged users to change mount flags */
58 - if ((flag & CL_UNPRIVILEGED) && (mnt->mnt.mnt_flags & MNT_READONLY))
59 - mnt->mnt.mnt_flags |= MNT_LOCK_READONLY;
60 + if (flag & CL_UNPRIVILEGED) {
61 + mnt->mnt.mnt_flags |= MNT_LOCK_ATIME;
62 +
63 + if (mnt->mnt.mnt_flags & MNT_READONLY)
64 + mnt->mnt.mnt_flags |= MNT_LOCK_READONLY;
65 +
66 + if (mnt->mnt.mnt_flags & MNT_NODEV)
67 + mnt->mnt.mnt_flags |= MNT_LOCK_NODEV;
68 +
69 + if (mnt->mnt.mnt_flags & MNT_NOSUID)
70 + mnt->mnt.mnt_flags |= MNT_LOCK_NOSUID;
71 +
72 + if (mnt->mnt.mnt_flags & MNT_NOEXEC)
73 + mnt->mnt.mnt_flags |= MNT_LOCK_NOEXEC;
74 + }
75
76 /* Don't allow unprivileged users to reveal what is under a mount */
77 if ((flag & CL_UNPRIVILEGED) && list_empty(&old->mnt_expire))
78 @@ -1931,6 +1944,23 @@ static int do_remount(struct path *path,
79 !(mnt_flags & MNT_READONLY)) {
80 return -EPERM;
81 }
82 + if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) &&
83 + !(mnt_flags & MNT_NODEV)) {
84 + return -EPERM;
85 + }
86 + if ((mnt->mnt.mnt_flags & MNT_LOCK_NOSUID) &&
87 + !(mnt_flags & MNT_NOSUID)) {
88 + return -EPERM;
89 + }
90 + if ((mnt->mnt.mnt_flags & MNT_LOCK_NOEXEC) &&
91 + !(mnt_flags & MNT_NOEXEC)) {
92 + return -EPERM;
93 + }
94 + if ((mnt->mnt.mnt_flags & MNT_LOCK_ATIME) &&
95 + ((mnt->mnt.mnt_flags & MNT_ATIME_MASK) != (mnt_flags & MNT_ATIME_MASK))) {
96 + return -EPERM;
97 + }
98 +
99 err = security_sb_remount(sb, data);
100 if (err)
101 return err;
102 @@ -2129,7 +2159,7 @@ static int do_new_mount(struct path *pat
103 */
104 if (!(type->fs_flags & FS_USERNS_DEV_MOUNT)) {
105 flags |= MS_NODEV;
106 - mnt_flags |= MNT_NODEV;
107 + mnt_flags |= MNT_NODEV | MNT_LOCK_NODEV;
108 }
109 }
110
111 --- a/include/linux/mount.h
112 +++ b/include/linux/mount.h
113 @@ -45,12 +45,17 @@ struct mnt_namespace;
114 #define MNT_USER_SETTABLE_MASK (MNT_NOSUID | MNT_NODEV | MNT_NOEXEC \
115 | MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME \
116 | MNT_READONLY)
117 +#define MNT_ATIME_MASK (MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME )
118
119 #define MNT_INTERNAL_FLAGS (MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL | \
120 MNT_DOOMED | MNT_SYNC_UMOUNT | MNT_MARKED)
121
122 #define MNT_INTERNAL 0x4000
123
124 +#define MNT_LOCK_ATIME 0x040000
125 +#define MNT_LOCK_NOEXEC 0x080000
126 +#define MNT_LOCK_NOSUID 0x100000
127 +#define MNT_LOCK_NODEV 0x200000
128 #define MNT_LOCK_READONLY 0x400000
129 #define MNT_LOCKED 0x800000
130 #define MNT_DOOMED 0x1000000