diff --git a/fs/proc/base.c b/fs/proc/base.c index 837469a..e95878a 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -255,21 +255,30 @@ static int proc_pid_cmdline(struct task_struct *task, char * buffer) int res = 0; unsigned int len; struct mm_struct *mm = get_task_mm(task); + if (!mm) goto out; + + /* The process was not constructed yet? */ if (!mm->arg_end) goto out_mm; /* Shh! No looking before we're done */ - len = mm->arg_end - mm->arg_start; - + down_read(&mm->arg_sem); + len = mm->arg_end - mm->arg_start; if (len > PAGE_SIZE) len = PAGE_SIZE; - + res = access_process_vm(task, mm->arg_start, buffer, len, 0); - // If the nul at the end of args has been overwritten, then - // assume application is using setproctitle(3). - if (res > 0 && buffer[res-1] != '\0' && len < PAGE_SIZE) { + if (mm->arg_end != mm->env_start) + /* PR_SET_PROCTITLE_AREA used */ + res = strnlen(buffer, res); + else if (res > 0 && buffer[res-1] != '\0' && len < PAGE_SIZE) { + /* + * If the nul at the end of args has been overwritten, + * then assume application is using sendmail's + * SPT_REUSEARGV style argv override. + */ len = strnlen(buffer, res); if (len < res) { res = len; @@ -281,6 +290,8 @@ static int proc_pid_cmdline(struct task_struct *task, char * buffer) res = strnlen(buffer, res); } } + up_read(&mm->arg_sem); + out_mm: mmput(mm); out: diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 84a524a..aff2e8d 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -236,6 +236,7 @@ struct mm_struct { unsigned long stack_vm, reserved_vm, def_flags, nr_ptes; unsigned long start_code, end_code, start_data, end_data; unsigned long start_brk, brk, start_stack; + struct rw_semaphore arg_sem; unsigned long arg_start, arg_end, env_start, env_end; unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */ diff --git a/include/linux/prctl.h b/include/linux/prctl.h index 9311505..e80a11b 100644 --- a/include/linux/prctl.h +++ b/include/linux/prctl.h @@ -90,4 +90,8 @@ #define PR_MCE_KILL 33 + +/* Set process title memory area for setproctitle() */ +#define PR_SET_PROCTITLE_AREA 34 + #endif /* _LINUX_PRCTL_H */ diff --git a/kernel/fork.c b/kernel/fork.c index 266c6af..014999c 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -459,6 +459,7 @@ static struct mm_struct * mm_init(struct mm_struct * mm, struct task_struct *p) mm->cached_hole_size = ~0UL; mm_init_aio(mm); mm_init_owner(mm, p); + init_rwsem(&mm->arg_sem); if (likely(!mm_alloc_pgd(mm))) { mm->def_flags = 0; diff --git a/kernel/sys.c b/kernel/sys.c index 255475d..cd69a06 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1564,6 +1564,29 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, error = 0; break; + case PR_SET_PROCTITLE_AREA: { + struct mm_struct *mm = current->mm; + unsigned long addr = arg2; + unsigned long len = arg3; + unsigned long end = arg2 + arg3; + + if (len > PAGE_SIZE) + return -EINVAL; + + if (addr >= end) + return -EINVAL; + + if (!access_ok(VERIFY_READ, addr, len)) { + return -EFAULT; + } + + down_write(&mm->arg_sem); + mm->arg_start = addr; + mm->arg_end = addr + len; + up_write(&mm->arg_sem); + + return 0; + } default: error = -EINVAL; break;