On 11/16, Oleg Nesterov wrote: > > On 11/16, Oleg Nesterov wrote: > > > > And I didn't check "make xcheck", I guess it still crashes the kernel. > > Yes it does. I am almost sure the bug should be trivial, but > somehow can't find find it.
Found the trivial but nasty problem. tracehook_finish_clone()->utrace_init_task() sets ->utrace = NULL, but this is too late. If copy_process() fails before, tracehook_free_task() will free parent's ->utrace copied by dup_task_struct(). This is nasty because we need some changes outside of utrace/tracehook files. Perhaps we should send something like the patch below to Andrew right now? And! While this bug could perfectly explain the crash, it doesn't. I appiled this patch --- UTRACE-PTRACE/kernel/fork.c~XXX_CRASH 2009-11-16 20:26:23.000000000 +0100 +++ UTRACE-PTRACE/kernel/fork.c 2009-11-17 20:33:50.000000000 +0100 @@ -1019,6 +1019,7 @@ static struct task_struct *copy_process( if (!p) goto fork_out; +p->utrace = NULL; ftrace_graph_init_task(p); rt_mutex_init_task(p); but "make xcheck" still crashes. Still investigating. Oleg. --- TH/include/linux/ptrace.h~TH_INIT_TASK 2009-11-10 21:31:25.000000000 +0100 +++ TH/include/linux/ptrace.h 2009-11-17 20:43:42.000000000 +0100 @@ -148,6 +148,14 @@ static inline int ptrace_event(int mask, return 1; } +static inline void ptrace_init_task(struct task_struct *child) +{ + INIT_LIST_HEAD(&child->ptrace_entry); + INIT_LIST_HEAD(&child->ptraced); + child->parent = child->real_parent; + child->ptrace = 0; +} + /** * ptrace_init_task - initialize ptrace state for a new child * @child: new child task @@ -158,12 +166,8 @@ static inline int ptrace_event(int mask, * * Called with current's siglock and write_lock_irq(&tasklist_lock) held. */ -static inline void ptrace_init_task(struct task_struct *child, bool ptrace) +static inline void ptrace_finish_clone(struct task_struct *child, bool ptrace) { - INIT_LIST_HEAD(&child->ptrace_entry); - INIT_LIST_HEAD(&child->ptraced); - child->parent = child->real_parent; - child->ptrace = 0; if (unlikely(ptrace) && (current->ptrace & PT_PTRACED)) { child->ptrace = current->ptrace; __ptrace_link(child, current->parent); --- TH/include/linux/tracehook.h~TH_INIT_TASK 2009-11-11 21:49:42.000000000 +0100 +++ TH/include/linux/tracehook.h 2009-11-17 20:42:43.000000000 +0100 @@ -247,6 +247,11 @@ static inline int tracehook_prepare_clon return 0; } +static inline void tracehook_init_task(struct task_struct *child) +{ + ptrace_init_task(child); +} + /** * tracehook_finish_clone - new child created and being attached * @child: new child task @@ -261,7 +266,7 @@ static inline int tracehook_prepare_clon static inline void tracehook_finish_clone(struct task_struct *child, unsigned long clone_flags, int trace) { - ptrace_init_task(child, (clone_flags & CLONE_PTRACE) || trace); + ptrace_finish_clone(child, (clone_flags & CLONE_PTRACE) || trace); } /** --- TH/kernel/fork.c~TH_INIT_TASK 2009-11-07 22:15:15.000000000 +0100 +++ TH/kernel/fork.c 2009-11-17 20:40:52.000000000 +0100 @@ -1018,8 +1018,8 @@ static struct task_struct *copy_process( if (!p) goto fork_out; + tracehook_init_task(p); ftrace_graph_init_task(p); - rt_mutex_init_task(p); #ifdef CONFIG_PROVE_LOCKING