aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMateusz Guzik <mguzik@redhat.com>2016-01-20 18:01:05 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2016-01-20 20:09:18 -0500
commita3b609ef9f8b1dbfe97034ccad6cd3fe71fbe7ab (patch)
tree0162563ac7cab6364a3ec6df61b4b96a876943f4
parentddf1d398e517e660207e2c807f76a90df543a217 (diff)
proc read mm's {arg,env}_{start,end} with mmap semaphore taken.
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>
-rw-r--r--fs/proc/base.c13
-rw-r--r--mm/util.c16
2 files changed, 22 insertions, 7 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c
index e665097c1da5..4f764c2ac1a5 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -953,6 +953,7 @@ static ssize_t environ_read(struct file *file, char __user *buf,
953 unsigned long src = *ppos; 953 unsigned long src = *ppos;
954 int ret = 0; 954 int ret = 0;
955 struct mm_struct *mm = file->private_data; 955 struct mm_struct *mm = file->private_data;
956 unsigned long env_start, env_end;
956 957
957 if (!mm) 958 if (!mm)
958 return 0; 959 return 0;
@@ -964,19 +965,25 @@ static ssize_t environ_read(struct file *file, char __user *buf,
964 ret = 0; 965 ret = 0;
965 if (!atomic_inc_not_zero(&mm->mm_users)) 966 if (!atomic_inc_not_zero(&mm->mm_users))
966 goto free; 967 goto free;
968
969 down_read(&mm->mmap_sem);
970 env_start = mm->env_start;
971 env_end = mm->env_end;
972 up_read(&mm->mmap_sem);
973
967 while (count > 0) { 974 while (count > 0) {
968 size_t this_len, max_len; 975 size_t this_len, max_len;
969 int retval; 976 int retval;
970 977
971 if (src >= (mm->env_end - mm->env_start)) 978 if (src >= (env_end - env_start))
972 break; 979 break;
973 980
974 this_len = mm->env_end - (mm->env_start + src); 981 this_len = env_end - (env_start + src);
975 982
976 max_len = min_t(size_t, PAGE_SIZE, count); 983 max_len = min_t(size_t, PAGE_SIZE, count);
977 this_len = min(max_len, this_len); 984 this_len = min(max_len, this_len);
978 985
979 retval = access_remote_vm(mm, (mm->env_start + src), 986 retval = access_remote_vm(mm, (env_start + src),
980 page, this_len, 0); 987 page, this_len, 0);
981 988
982 if (retval <= 0) { 989 if (retval <= 0) {
diff --git a/mm/util.c b/mm/util.c
index 6d1f9200f74e..c108a6542d05 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -476,17 +476,25 @@ int get_cmdline(struct task_struct *task, char *buffer, int buflen)
476 int res = 0; 476 int res = 0;
477 unsigned int len; 477 unsigned int len;
478 struct mm_struct *mm = get_task_mm(task); 478 struct mm_struct *mm = get_task_mm(task);
479 unsigned long arg_start, arg_end, env_start, env_end;
479 if (!mm) 480 if (!mm)
480 goto out; 481 goto out;
481 if (!mm->arg_end) 482 if (!mm->arg_end)
482 goto out_mm; /* Shh! No looking before we're done */ 483 goto out_mm; /* Shh! No looking before we're done */
483 484
484 len = mm->arg_end - mm->arg_start; 485 down_read(&mm->mmap_sem);
486 arg_start = mm->arg_start;
487 arg_end = mm->arg_end;
488 env_start = mm->env_start;
489 env_end = mm->env_end;
490 up_read(&mm->mmap_sem);
491
492 len = arg_end - arg_start;
485 493
486 if (len > buflen) 494 if (len > buflen)
487 len = buflen; 495 len = buflen;
488 496
489 res = access_process_vm(task, mm->arg_start, buffer, len, 0); 497 res = access_process_vm(task, arg_start, buffer, len, 0);
490 498
491 /* 499 /*
492 * If the nul at the end of args has been overwritten, then 500 * If the nul at the end of args has been overwritten, then
@@ -497,10 +505,10 @@ int get_cmdline(struct task_struct *task, char *buffer, int buflen)
497 if (len < res) { 505 if (len < res) {
498 res = len; 506 res = len;
499 } else { 507 } else {
500 len = mm->env_end - mm->env_start; 508 len = env_end - env_start;
501 if (len > buflen - res) 509 if (len > buflen - res)
502 len = buflen - res; 510 len = buflen - res;
503 res += access_process_vm(task, mm->env_start, 511 res += access_process_vm(task, env_start,
504 buffer+res, len, 0); 512 buffer+res, len, 0);
505 res = strnlen(buffer, res); 513 res = strnlen(buffer, res);
506 } 514 }