diff --git a/include/linux/prctl.h b/include/linux/prctl.h index a3baeb2..fbd2451 100644 --- a/include/linux/prctl.h +++ b/include/linux/prctl.h @@ -102,4 +102,6 @@ #define PR_MCE_KILL_GET 34 +#define PR_DETACH 35 + #endif /* _LINUX_PRCTL_H */ diff --git a/kernel/signal.c b/kernel/signal.c index 4e3cff1..2cd495a 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1450,10 +1450,10 @@ int do_notify_parent(struct task_struct *tsk, int sig) BUG_ON(sig == -1); - /* do_notify_parent_cldstop should have been called instead. */ - BUG_ON(task_is_stopped_or_traced(tsk)); + /* do_notify_parent_cldstop should have been called instead. */ + BUG_ON(task_is_stopped_or_traced(tsk)); - BUG_ON(!task_ptrace(tsk) && + BUG_ON(!task_ptrace(tsk) && (tsk->flags & PF_EXITING) && (tsk->group_leader != tsk || !thread_group_empty(tsk))); info.si_signo = sig; diff --git a/kernel/sys.c b/kernel/sys.c index 7f5a0cd..fa10732 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1727,6 +1727,21 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, else error = PR_MCE_KILL_DEFAULT; break; + case PR_DETACH: + error = -EPERM; + if (me->real_parent == init_pid_ns.child_reaper) + break; + if (me->group_leader != me) + break; + exit_ptrace(me); + do_notify_parent(me, me->exit_signal); + me->exit_signal = SIGCHLD; + me->parent = me->real_parent = + init_pid_ns.child_reaper; + list_move_tail(&me->sibling, + &me->real_parent->children); + error = 0; + break; default: error = -EINVAL; break;