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

Reply via email to