4.4-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mateusz Guzik mguzik@redhat.com
commit a3b609ef9f8b1dbfe97034ccad6cd3fe71fbe7ab upstream.
Only functions doing more than one read are modified. Consumeres happened to deal with possibly changing data, but it does not seem like a good thing to rely on.
Signed-off-by: Mateusz Guzik mguzik@redhat.com Acked-by: Cyrill Gorcunov gorcunov@openvz.org Cc: Alexey Dobriyan adobriyan@gmail.com Cc: Jarod Wilson jarod@redhat.com Cc: Jan Stancek jstancek@redhat.com Cc: Al Viro viro@zeniv.linux.org.uk Cc: Anshuman Khandual anshuman.linux@gmail.com Signed-off-by: Andrew Morton akpm@linux-foundation.org Signed-off-by: Linus Torvalds torvalds@linux-foundation.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- fs/proc/base.c | 13 ++++++++++--- mm/util.c | 16 ++++++++++++---- 2 files changed, 22 insertions(+), 7 deletions(-)
--- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -953,6 +953,7 @@ static ssize_t environ_read(struct file unsigned long src = *ppos; int ret = 0; struct mm_struct *mm = file->private_data; + unsigned long env_start, env_end;
/* Ensure the process spawned far enough to have an environment. */ if (!mm || !mm->env_end) @@ -965,19 +966,25 @@ static ssize_t environ_read(struct file ret = 0; if (!atomic_inc_not_zero(&mm->mm_users)) goto free; + + down_read(&mm->mmap_sem); + env_start = mm->env_start; + env_end = mm->env_end; + up_read(&mm->mmap_sem); + while (count > 0) { size_t this_len, max_len; int retval;
- if (src >= (mm->env_end - mm->env_start)) + if (src >= (env_end - env_start)) break;
- this_len = mm->env_end - (mm->env_start + src); + this_len = env_end - (env_start + src);
max_len = min_t(size_t, PAGE_SIZE, count); this_len = min(max_len, this_len);
- retval = access_remote_vm(mm, (mm->env_start + src), + retval = access_remote_vm(mm, (env_start + src), page, this_len, 0);
if (retval <= 0) { --- a/mm/util.c +++ b/mm/util.c @@ -428,17 +428,25 @@ int get_cmdline(struct task_struct *task int res = 0; unsigned int len; struct mm_struct *mm = get_task_mm(task); + unsigned long arg_start, arg_end, env_start, env_end; if (!mm) goto out; if (!mm->arg_end) goto out_mm; /* Shh! No looking before we're done */
- len = mm->arg_end - mm->arg_start; + down_read(&mm->mmap_sem); + arg_start = mm->arg_start; + arg_end = mm->arg_end; + env_start = mm->env_start; + env_end = mm->env_end; + up_read(&mm->mmap_sem); + + len = arg_end - arg_start;
if (len > buflen) len = buflen;
- res = access_process_vm(task, mm->arg_start, buffer, len, 0); + res = access_process_vm(task, arg_start, buffer, len, 0);
/* * If the nul at the end of args has been overwritten, then @@ -449,10 +457,10 @@ int get_cmdline(struct task_struct *task if (len < res) { res = len; } else { - len = mm->env_end - mm->env_start; + len = env_end - env_start; if (len > buflen - res) len = buflen - res; - res += access_process_vm(task, mm->env_start, + res += access_process_vm(task, env_start, buffer+res, len, 0); res = strnlen(buffer, res); }