diff options
author | Jann Horn <jannh@google.com> | 2018-06-25 12:34:19 -0400 |
---|---|---|
committer | Eric W. Biederman <ebiederm@xmission.com> | 2018-08-11 03:05:53 -0400 |
commit | 5820f140edef111a9ea2ef414ab2428b8cb805b1 (patch) | |
tree | 3c8f89bbc5c3dcf1bdc0713dd1bcd1d9997c5da4 /kernel | |
parent | 355139a8dba446cc11a424cddbf7afebc3041ba1 (diff) |
userns: move user access out of the mutex
The old code would hold the userns_state_mutex indefinitely if
memdup_user_nul stalled due to e.g. a userfault region. Prevent that by
moving the memdup_user_nul in front of the mutex_lock().
Note: This changes the error precedence of invalid buf/count/*ppos vs
map already written / capabilities missing.
Fixes: 22d917d80e84 ("userns: Rework the user_namespace adding uid/gid...")
Cc: stable@vger.kernel.org
Signed-off-by: Jann Horn <jannh@google.com>
Acked-by: Christian Brauner <christian@brauner.io>
Acked-by: Serge Hallyn <serge@hallyn.com>
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/user_namespace.c | 24 |
1 files changed, 10 insertions, 14 deletions
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index c3d7583fcd21..e5222b5fb4fe 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c | |||
@@ -859,7 +859,16 @@ static ssize_t map_write(struct file *file, const char __user *buf, | |||
859 | unsigned idx; | 859 | unsigned idx; |
860 | struct uid_gid_extent extent; | 860 | struct uid_gid_extent extent; |
861 | char *kbuf = NULL, *pos, *next_line; | 861 | char *kbuf = NULL, *pos, *next_line; |
862 | ssize_t ret = -EINVAL; | 862 | ssize_t ret; |
863 | |||
864 | /* Only allow < page size writes at the beginning of the file */ | ||
865 | if ((*ppos != 0) || (count >= PAGE_SIZE)) | ||
866 | return -EINVAL; | ||
867 | |||
868 | /* Slurp in the user data */ | ||
869 | kbuf = memdup_user_nul(buf, count); | ||
870 | if (IS_ERR(kbuf)) | ||
871 | return PTR_ERR(kbuf); | ||
863 | 872 | ||
864 | /* | 873 | /* |
865 | * The userns_state_mutex serializes all writes to any given map. | 874 | * The userns_state_mutex serializes all writes to any given map. |
@@ -895,19 +904,6 @@ static ssize_t map_write(struct file *file, const char __user *buf, | |||
895 | if (cap_valid(cap_setid) && !file_ns_capable(file, ns, CAP_SYS_ADMIN)) | 904 | if (cap_valid(cap_setid) && !file_ns_capable(file, ns, CAP_SYS_ADMIN)) |
896 | goto out; | 905 | goto out; |
897 | 906 | ||
898 | /* Only allow < page size writes at the beginning of the file */ | ||
899 | ret = -EINVAL; | ||
900 | if ((*ppos != 0) || (count >= PAGE_SIZE)) | ||
901 | goto out; | ||
902 | |||
903 | /* Slurp in the user data */ | ||
904 | kbuf = memdup_user_nul(buf, count); | ||
905 | if (IS_ERR(kbuf)) { | ||
906 | ret = PTR_ERR(kbuf); | ||
907 | kbuf = NULL; | ||
908 | goto out; | ||
909 | } | ||
910 | |||
911 | /* Parse the user data */ | 907 | /* Parse the user data */ |
912 | ret = -EINVAL; | 908 | ret = -EINVAL; |
913 | pos = kbuf; | 909 | pos = kbuf; |