Module: xenomai-forge Branch: master Commit: 939df00d7b02698011b3a50f5cf417a12b7eec02 URL: http://git.xenomai.org/?p=xenomai-forge.git;a=commit;h=939df00d7b02698011b3a50f5cf417a12b7eec02
Author: Philippe Gerum <r...@xenomai.org> Date: Sat Apr 13 08:14:47 2013 +0200 cobalt: fix spurious reference to dead mm upon fork+exec A userland shadow which executes another Xenomai-enabled process via a fork+exec sequence will cause a destroyed mm_struct to be reused by the nucleus for scheduling the child process in. [parent] fork() child->mm = dup_mm(parent) [child] pthread_atfork_handler() cobalt_thread_shadow() child_tcb->core.mm = child->mm exec() flush_old_exec() __mmdrop(child->mm) => pre-exec child->mm now dead ... xnarch_switch_to(prev, child) switch_mmu_context(prev_mm, child_tcb->core.mm) => BUG In this case, using a saved copy of the original mm pointer in the Xenomai TCB is not a good idea, since that pointer may become invalid upon exec(). Had the latter worked, the new executable loaded onto the old process slot would have faced a Xenomai binding error anyhow, since the parent binding would still have been in effect. To sum up, a process should not keep its Xenomai capabilities across exec(), which is the root issue. The fix detects such situation, and emulates a Xenomai task exit on behalf of any process dropping its mm context outside of the regular exit path. --- kernel/cobalt/nucleus/shadow.c | 23 ++++++++++++++++++++++- 1 files changed, 22 insertions(+), 1 deletions(-) diff --git a/kernel/cobalt/nucleus/shadow.c b/kernel/cobalt/nucleus/shadow.c index 33d3e9e..0a043c6 100644 --- a/kernel/cobalt/nucleus/shadow.c +++ b/kernel/cobalt/nucleus/shadow.c @@ -738,6 +738,7 @@ static inline void destroy_threadinfo(void) { struct ipipe_threadinfo *p = ipipe_current_threadinfo(); p->thread = NULL; + p->mm = NULL; } /** @@ -2152,6 +2153,7 @@ static int handle_taskexit_event(struct task_struct *p) /* p == current */ XENO_BUGON(NUCLEUS, !xnpod_root_p()); thread = xnshadow_current(); + XENO_BUGON(NUCLEUS, thread == NULL); trace_mark(xn_nucleus, shadow_exit, "thread %p thread_name %s", thread, xnthread_name(thread)); @@ -2161,7 +2163,6 @@ static int handle_taskexit_event(struct task_struct *p) /* p == current */ /* __xnpod_cleanup_thread() -> hook -> xnshadow_unmap() */ __xnpod_cleanup_thread(thread); - destroy_threadinfo(); if (xnthread_test_state(thread, XNUSER)) { xnlock_get_irqsave(&nklock, s); @@ -2172,6 +2173,8 @@ static int handle_taskexit_event(struct task_struct *p) /* p == current */ ppd_remove_mm(mm, detach_ppd); } + destroy_threadinfo(); + return EVENT_PROPAGATE; } @@ -2302,14 +2305,32 @@ static int handle_sigwake_event(struct task_struct *p) static int handle_cleanup_event(struct mm_struct *mm) { struct xnsys_ppd *sys_ppd; + struct xnthread *thread; struct mm_struct *old; + spl_t s; /* We are NOT called for exiting kernel shadows. */ old = xnshadow_swap_mm(mm); + xnlock_get_irqsave(&nklock, s); sys_ppd = xnsys_ppd_get(0); + xnlock_put_irqrestore(&nklock, s); if (sys_ppd != &__xnsys_global_ppd) { + /* + * Detect a userland shadow running exec(), i.e. still + * attached to the current linux task (no prior + * destroy_threadinfo). In this case, we emulate a + * task exit, since the Xenomai binding shall not + * survive the exec() syscall. Since the process will + * keep on running though, we have to disable the + * event notifier manually for it. + */ + thread = xnshadow_current(); + if (thread && (current->flags & PF_EXITING) == 0) { + handle_taskexit_event(current); + ipipe_disable_notifier(current); + } if (xnarch_atomic_dec_and_test(&sys_ppd->refcnt)) ppd_remove_mm(mm, detach_ppd); } _______________________________________________ Xenomai-git mailing list Xenomai-git@xenomai.org http://www.xenomai.org/mailman/listinfo/xenomai-git