Subject: [PATCH] More private pidspace work From: Eric W. Biederman Date: 1128958251 -0600 - First stab at x86_64 private pidspace support - Proper pid translation on fork failure - Proper process group translation in proc - Enforce resource limits in copy_process --- arch/i386/kernel/process.c | 11 ++++++++--- arch/x86_64/ia32/sys_ia32.c | 5 ++++- arch/x86_64/kernel/process.c | 12 +++++++++--- fs/proc/array.c | 13 ++++++++----- kernel/pid.c | 11 +++++++++++ 5 files changed, 40 insertions(+), 12 deletions(-) 7f80da373d80b7af13ee901c736c64330973ae58 diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 7f6cbc4..c250e71 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -739,11 +739,13 @@ struct task_struct fastcall * __switch_t asmlinkage int sys_fork(struct pt_regs regs) { - return pid_to_user(do_fork(SIGCHLD, regs.esp, ®s, 0, NULL, NULL)); + int ret = do_fork(SIGCHLD, regs.esp, ®s, 0, NULL, NULL); + return (ret > 0)? pid_to_user(ret) : ret; } asmlinkage int sys_clone(struct pt_regs regs) { + int ret; unsigned long clone_flags; unsigned long newsp; int __user *parent_tidptr, *child_tidptr; @@ -754,7 +756,8 @@ asmlinkage int sys_clone(struct pt_regs child_tidptr = (int __user *)regs.edi; if (!newsp) newsp = regs.esp; - return pid_to_user(do_fork(clone_flags, newsp, ®s, 0, parent_tidptr, child_tidptr)); + ret = do_fork(clone_flags, newsp, ®s, 0, parent_tidptr, child_tidptr); + return (ret > 0)? pid_to_user(ret) : ret; } /* @@ -769,7 +772,9 @@ asmlinkage int sys_clone(struct pt_regs */ asmlinkage int sys_vfork(struct pt_regs regs) { - return pid_to_user(do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, ®s, 0, NULL, NULL)); + int ret; + ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, ®s, 0, NULL, NULL); + return (ret > 0)? pid_to_user(ret) : ret; } /* diff --git a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c index 5389df6..edc040c 100644 --- a/arch/x86_64/ia32/sys_ia32.c +++ b/arch/x86_64/ia32/sys_ia32.c @@ -62,6 +62,7 @@ #include #include #include +#include #include #include #include @@ -948,11 +949,13 @@ asmlinkage long sys32_execve(char __user asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp, struct pt_regs *regs) { + long ret; void __user *parent_tid = (void __user *)regs->rdx; void __user *child_tid = (void __user *)regs->rdi; if (!newsp) newsp = regs->rsp; - return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid); + ret = do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid); + return (ret > 0)? pid_to_user(ret): ret; } /* diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c index b5a89c0..93b90b3 100644 --- a/arch/x86_64/kernel/process.c +++ b/arch/x86_64/kernel/process.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -646,14 +647,17 @@ void set_personality_64bit(void) asmlinkage long sys_fork(struct pt_regs *regs) { - return do_fork(SIGCHLD, regs->rsp, regs, 0, NULL, NULL); + long ret = do_fork(SIGCHLD, regs->rsp, regs, 0, NULL, NULL); + return (ret > 0)? pid_to_user(ret) : ret; } asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, void __user *parent_tid, void __user *child_tid, struct pt_regs *regs) { + long ret; if (!newsp) newsp = regs->rsp; - return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid); + ret = do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid); + return (ret > 0)? pid_to_user(ret) : ret; } /* @@ -668,8 +672,10 @@ asmlinkage long sys_clone(unsigned long */ asmlinkage long sys_vfork(struct pt_regs *regs) { - return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->rsp, regs, 0, + long ret; + ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->rsp, regs, 0, NULL, NULL); + return (ret > 0)? pid_to_user(ret) : ret; } unsigned long get_wchan(struct task_struct *p) diff --git a/fs/proc/array.c b/fs/proc/array.c index 6dfba7f..59abcf7 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -167,8 +167,10 @@ static inline char * task_state(struct t read_lock(&tasklist_lock); tgid = pid_to_user(p->tgid); pid = pid_to_user(p->pid); - ptgid = pid_alive(p) ? pid_to_user(p->group_leader->real_parent->tgid) : 0; - tppid = pid_alive(p) && p->ptrace ? pid_to_user(p->parent->pid) : 0; + ptgid = pid_alive(p) && pid_visible(p->group_leader->real_parent) ? + pid_to_user(p->group_leader->real_parent->tgid) : 0; + tppid = pid_alive(p) && pid_visible(p->parent) && p->ptrace ? + pid_to_user(p->parent->pid) : 0; buffer += sprintf(buffer, "State:\t%s\n" "SleepAVG:\t%lu%%\n" @@ -373,8 +375,8 @@ static int do_task_stat(struct task_stru spin_unlock_irq(&task->sighand->siglock); } if (task->signal) { - if (task->signal->tty) { - tty_pgrp = task->signal->tty->pgrp; + if (task->signal->tty) { + tty_pgrp = pid_to_user(task->signal->tty->pgrp); tty_nr = new_encode_dev(tty_devnum(task->signal->tty)); } pgid = pid_to_user(process_group(task)); @@ -392,7 +394,8 @@ static int do_task_stat(struct task_stru } it_real_value = task->signal->it_real_value; } - ppid = pid_alive(task) ? pid_to_user(task->group_leader->real_parent->tgid) : 0; + ppid = pid_alive(task) && pid_visible(task->group_leader->real_parent) ? + pid_to_user(task->group_leader->real_parent->tgid) : 0; read_unlock(&tasklist_lock); if (!whole || num_threads<2) diff --git a/kernel/pid.c b/kernel/pid.c index 402cf38..fa4be23 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -308,6 +308,17 @@ int copy_pspace(int flags, struct task_s /* For now allocate 1/256 of the pidspace */ pids = p->pspace->max >> 8; + + /* Verify this could fit in my rlimit */ + if ((atomic_read(&p->user->processes) + pids) >= + p->signal->rlim[RLIMIT_NPROC].rlim_cur) { + if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) && + p->user != &root_user) { + put_pspace(p->pspace); + return -EAGAIN; + } + } + pid = -1; if (pids > 0) pid = alloc_pidmap(p->pspace, pids); -- 1.0.GIT