diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-09 20:10:41 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-09 20:10:41 -0400 |
commit | 77e40aae766ccbbbb0324cb92ab22e6e998375d7 (patch) | |
tree | fb4e8e840aaeeaac62249d7585249c4634886baa /fs/namespace.c | |
parent | 96784de59fb35077c2bb33c39328992b836d87d3 (diff) | |
parent | 344470cac42e887e68cfb5bdfa6171baf27f1eb5 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace
Pull namespace updates from Eric Biederman:
"This is a bunch of small changes built against 3.16-rc6. The most
significant change for users is the first patch which makes setns
drmatically faster by removing unneded rcu handling.
The next chunk of changes are so that "mount -o remount,.." will not
allow the user namespace root to drop flags on a mount set by the
system wide root. Aks this forces read-only mounts to stay read-only,
no-dev mounts to stay no-dev, no-suid mounts to stay no-suid, no-exec
mounts to stay no exec and it prevents unprivileged users from messing
with a mounts atime settings. I have included my test case as the
last patch in this series so people performing backports can verify
this change works correctly.
The next change fixes a bug in NFS that was discovered while auditing
nsproxy users for the first optimization. Today you can oops the
kernel by reading /proc/fs/nfsfs/{servers,volumes} if you are clever
with pid namespaces. I rebased and fixed the build of the
!CONFIG_NFS_FS case yesterday when a build bot caught my typo. Given
that no one to my knowledge bases anything on my tree fixing the typo
in place seems more responsible that requiring a typo-fix to be
backported as well.
The last change is a small semantic cleanup introducing
/proc/thread-self and pointing /proc/mounts and /proc/net at it. This
prevents several kinds of problemantic corner cases. It is a
user-visible change so it has a minute chance of causing regressions
so the change to /proc/mounts and /proc/net are individual one line
commits that can be trivially reverted. Unfortunately I lost and
could not find the email of the original reporter so he is not
credited. From at least one perspective this change to /proc/net is a
refgression fix to allow pthread /proc/net uses that were broken by
the introduction of the network namespace"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace:
proc: Point /proc/mounts at /proc/thread-self/mounts instead of /proc/self/mounts
proc: Point /proc/net at /proc/thread-self/net instead of /proc/self/net
proc: Implement /proc/thread-self to point at the directory of the current thread
proc: Have net show up under /proc/<tgid>/task/<tid>
NFS: Fix /proc/fs/nfsfs/servers and /proc/fs/nfsfs/volumes
mnt: Add tests for unprivileged remount cases that have found to be faulty
mnt: Change the default remount atime from relatime to the existing value
mnt: Correct permission checks in do_remount
mnt: Move the test for MNT_LOCK_READONLY from change_mount_flags into do_remount
mnt: Only change user settable mount flags in remount
namespaces: Use task_lock and not rcu to protect nsproxy
Diffstat (limited to 'fs/namespace.c')
-rw-r--r-- | fs/namespace.c | 65 |
1 files changed, 55 insertions, 10 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 2a1447c946e7..0acabea58319 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -890,8 +890,21 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, | |||
890 | 890 | ||
891 | mnt->mnt.mnt_flags = old->mnt.mnt_flags & ~(MNT_WRITE_HOLD|MNT_MARKED); | 891 | mnt->mnt.mnt_flags = old->mnt.mnt_flags & ~(MNT_WRITE_HOLD|MNT_MARKED); |
892 | /* Don't allow unprivileged users to change mount flags */ | 892 | /* Don't allow unprivileged users to change mount flags */ |
893 | if ((flag & CL_UNPRIVILEGED) && (mnt->mnt.mnt_flags & MNT_READONLY)) | 893 | if (flag & CL_UNPRIVILEGED) { |
894 | mnt->mnt.mnt_flags |= MNT_LOCK_READONLY; | 894 | mnt->mnt.mnt_flags |= MNT_LOCK_ATIME; |
895 | |||
896 | if (mnt->mnt.mnt_flags & MNT_READONLY) | ||
897 | mnt->mnt.mnt_flags |= MNT_LOCK_READONLY; | ||
898 | |||
899 | if (mnt->mnt.mnt_flags & MNT_NODEV) | ||
900 | mnt->mnt.mnt_flags |= MNT_LOCK_NODEV; | ||
901 | |||
902 | if (mnt->mnt.mnt_flags & MNT_NOSUID) | ||
903 | mnt->mnt.mnt_flags |= MNT_LOCK_NOSUID; | ||
904 | |||
905 | if (mnt->mnt.mnt_flags & MNT_NOEXEC) | ||
906 | mnt->mnt.mnt_flags |= MNT_LOCK_NOEXEC; | ||
907 | } | ||
895 | 908 | ||
896 | /* Don't allow unprivileged users to reveal what is under a mount */ | 909 | /* Don't allow unprivileged users to reveal what is under a mount */ |
897 | if ((flag & CL_UNPRIVILEGED) && list_empty(&old->mnt_expire)) | 910 | if ((flag & CL_UNPRIVILEGED) && list_empty(&old->mnt_expire)) |
@@ -1896,9 +1909,6 @@ static int change_mount_flags(struct vfsmount *mnt, int ms_flags) | |||
1896 | if (readonly_request == __mnt_is_readonly(mnt)) | 1909 | if (readonly_request == __mnt_is_readonly(mnt)) |
1897 | return 0; | 1910 | return 0; |
1898 | 1911 | ||
1899 | if (mnt->mnt_flags & MNT_LOCK_READONLY) | ||
1900 | return -EPERM; | ||
1901 | |||
1902 | if (readonly_request) | 1912 | if (readonly_request) |
1903 | error = mnt_make_readonly(real_mount(mnt)); | 1913 | error = mnt_make_readonly(real_mount(mnt)); |
1904 | else | 1914 | else |
@@ -1924,6 +1934,33 @@ static int do_remount(struct path *path, int flags, int mnt_flags, | |||
1924 | if (path->dentry != path->mnt->mnt_root) | 1934 | if (path->dentry != path->mnt->mnt_root) |
1925 | return -EINVAL; | 1935 | return -EINVAL; |
1926 | 1936 | ||
1937 | /* Don't allow changing of locked mnt flags. | ||
1938 | * | ||
1939 | * No locks need to be held here while testing the various | ||
1940 | * MNT_LOCK flags because those flags can never be cleared | ||
1941 | * once they are set. | ||
1942 | */ | ||
1943 | if ((mnt->mnt.mnt_flags & MNT_LOCK_READONLY) && | ||
1944 | !(mnt_flags & MNT_READONLY)) { | ||
1945 | return -EPERM; | ||
1946 | } | ||
1947 | if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) && | ||
1948 | !(mnt_flags & MNT_NODEV)) { | ||
1949 | return -EPERM; | ||
1950 | } | ||
1951 | if ((mnt->mnt.mnt_flags & MNT_LOCK_NOSUID) && | ||
1952 | !(mnt_flags & MNT_NOSUID)) { | ||
1953 | return -EPERM; | ||
1954 | } | ||
1955 | if ((mnt->mnt.mnt_flags & MNT_LOCK_NOEXEC) && | ||
1956 | !(mnt_flags & MNT_NOEXEC)) { | ||
1957 | return -EPERM; | ||
1958 | } | ||
1959 | if ((mnt->mnt.mnt_flags & MNT_LOCK_ATIME) && | ||
1960 | ((mnt->mnt.mnt_flags & MNT_ATIME_MASK) != (mnt_flags & MNT_ATIME_MASK))) { | ||
1961 | return -EPERM; | ||
1962 | } | ||
1963 | |||
1927 | err = security_sb_remount(sb, data); | 1964 | err = security_sb_remount(sb, data); |
1928 | if (err) | 1965 | if (err) |
1929 | return err; | 1966 | return err; |
@@ -1937,7 +1974,7 @@ static int do_remount(struct path *path, int flags, int mnt_flags, | |||
1937 | err = do_remount_sb(sb, flags, data, 0); | 1974 | err = do_remount_sb(sb, flags, data, 0); |
1938 | if (!err) { | 1975 | if (!err) { |
1939 | lock_mount_hash(); | 1976 | lock_mount_hash(); |
1940 | mnt_flags |= mnt->mnt.mnt_flags & MNT_PROPAGATION_MASK; | 1977 | mnt_flags |= mnt->mnt.mnt_flags & ~MNT_USER_SETTABLE_MASK; |
1941 | mnt->mnt.mnt_flags = mnt_flags; | 1978 | mnt->mnt.mnt_flags = mnt_flags; |
1942 | touch_mnt_namespace(mnt->mnt_ns); | 1979 | touch_mnt_namespace(mnt->mnt_ns); |
1943 | unlock_mount_hash(); | 1980 | unlock_mount_hash(); |
@@ -2122,7 +2159,7 @@ static int do_new_mount(struct path *path, const char *fstype, int flags, | |||
2122 | */ | 2159 | */ |
2123 | if (!(type->fs_flags & FS_USERNS_DEV_MOUNT)) { | 2160 | if (!(type->fs_flags & FS_USERNS_DEV_MOUNT)) { |
2124 | flags |= MS_NODEV; | 2161 | flags |= MS_NODEV; |
2125 | mnt_flags |= MNT_NODEV; | 2162 | mnt_flags |= MNT_NODEV | MNT_LOCK_NODEV; |
2126 | } | 2163 | } |
2127 | } | 2164 | } |
2128 | 2165 | ||
@@ -2436,6 +2473,14 @@ long do_mount(const char *dev_name, const char *dir_name, | |||
2436 | if (flags & MS_RDONLY) | 2473 | if (flags & MS_RDONLY) |
2437 | mnt_flags |= MNT_READONLY; | 2474 | mnt_flags |= MNT_READONLY; |
2438 | 2475 | ||
2476 | /* The default atime for remount is preservation */ | ||
2477 | if ((flags & MS_REMOUNT) && | ||
2478 | ((flags & (MS_NOATIME | MS_NODIRATIME | MS_RELATIME | | ||
2479 | MS_STRICTATIME)) == 0)) { | ||
2480 | mnt_flags &= ~MNT_ATIME_MASK; | ||
2481 | mnt_flags |= path.mnt->mnt_flags & MNT_ATIME_MASK; | ||
2482 | } | ||
2483 | |||
2439 | flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_BORN | | 2484 | flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_BORN | |
2440 | MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT | | 2485 | MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT | |
2441 | MS_STRICTATIME); | 2486 | MS_STRICTATIME); |
@@ -2972,13 +3017,13 @@ static void *mntns_get(struct task_struct *task) | |||
2972 | struct mnt_namespace *ns = NULL; | 3017 | struct mnt_namespace *ns = NULL; |
2973 | struct nsproxy *nsproxy; | 3018 | struct nsproxy *nsproxy; |
2974 | 3019 | ||
2975 | rcu_read_lock(); | 3020 | task_lock(task); |
2976 | nsproxy = task_nsproxy(task); | 3021 | nsproxy = task->nsproxy; |
2977 | if (nsproxy) { | 3022 | if (nsproxy) { |
2978 | ns = nsproxy->mnt_ns; | 3023 | ns = nsproxy->mnt_ns; |
2979 | get_mnt_ns(ns); | 3024 | get_mnt_ns(ns); |
2980 | } | 3025 | } |
2981 | rcu_read_unlock(); | 3026 | task_unlock(task); |
2982 | 3027 | ||
2983 | return ns; | 3028 | return ns; |
2984 | } | 3029 | } |