]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
proc read mm's {arg,env}_{start,end} with mmap semaphore taken.
authorMateusz Guzik <mguzik@redhat.com>
Wed, 20 Jan 2016 23:01:05 +0000 (15:01 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 26 May 2018 06:48:55 +0000 (08:48 +0200)
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
mm/util.c

index dd732400578e36d226dd932d55f427b815dae94c..b7c3ba4891f81e7fc28c47bb85f72b5917bf765b 100644 (file)
@@ -953,6 +953,7 @@ static ssize_t environ_read(struct file *file, char __user *buf,
        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 *file, char __user *buf,
        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) {
index 818bbae84721f4d877ac1054553b04bcb2419a91..5fae5b9c28850b7872f643f1dacfba050a490842 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -428,17 +428,25 @@ int get_cmdline(struct task_struct *task, char *buffer, int buflen)
        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, char *buffer, int buflen)
                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);
                }