Module: xenomai-jki
Branch: queues/assorted
Commit: 9667e5e60250473f71724e8e47ca4f3e729d6294
URL:    
http://git.xenomai.org/?p=xenomai-jki.git;a=commit;h=9667e5e60250473f71724e8e47ca4f3e729d6294

Author: Jan Kiszka <jan.kis...@siemens.com>
Date:   Fri Mar  5 12:30:17 2010 +0100

Allow for deregistering current mode user space address

This adds __xn_sys_drop_u_mode, a syscall to deregister the u_mode user
space address passed on shadow creation for the current thread. We need
this in order to safely shut down a thread that wants to release its
u_mode memory (either malloc'ed or TLS-allocated). So far, the kernel
might have touched this memory even after the release which caused
subtle corruptions.

After we released u_mode, we can no longer make reliable decisions based
on it. For the fast mutex use case, we then assume the worst case, ie.
we enforce syscall-based acquisitions unconditionally. For the
assert_nrt case, we simply acquire the required information via
__xn_sys_current_info. The mutex torture test requires no special care
as it cannot retrieve invalid u_mode states.

---

 include/asm-generic/bits/current.h |   24 +++++++----
 include/asm-generic/syscall.h      |    1 +
 ksrc/nucleus/shadow.c              |   51 +++++++++++++++++++++---
 src/rtdk/assert_context.c          |    9 +++-
 src/skins/common/current.c         |   78 +++++++++++++++++++++++++++++++----
 5 files changed, 137 insertions(+), 26 deletions(-)

diff --git a/include/asm-generic/bits/current.h 
b/include/asm-generic/bits/current.h
index 0c3166b..f0e569c 100644
--- a/include/asm-generic/bits/current.h
+++ b/include/asm-generic/bits/current.h
@@ -2,7 +2,9 @@
 #define _XENO_ASM_GENERIC_CURRENT_H
 
 #include <pthread.h>
-#include <nucleus/types.h>
+#include <nucleus/thread.h>
+
+extern pthread_key_t xeno_current_mode_key;
 
 #ifdef HAVE___THREAD
 extern __thread xnhandle_t xeno_current __attribute__ ((tls_model 
("initial-exec")));
@@ -19,15 +21,13 @@ static inline unsigned long xeno_get_current_mode(void)
        return xeno_current_mode;
 }
 
-static inline unsigned long *xeno_init_current_mode(void)
+static inline int xeno_primary_mode(void)
 {
-       return &xeno_current_mode;
+       return xeno_current_mode & XNRELAX;
 }
 
-#define xeno_init_current_keys() do { } while (0)
 #else /* ! HAVE___THREAD */
 extern pthread_key_t xeno_current_key;
-extern pthread_key_t xeno_current_mode_key;
 
 static inline xnhandle_t xeno_get_current(void)
 {
@@ -41,14 +41,22 @@ static inline xnhandle_t xeno_get_current(void)
 
 static inline unsigned long xeno_get_current_mode(void)
 {
-       return *(unsigned long *)pthread_getspecific(xeno_current_mode_key);
+       unsigned long *mode = pthread_getspecific(xeno_current_mode_key);
+
+       return mode ? *mode : -1;
 }
 
-unsigned long *xeno_init_current_mode(void);
+static inline int xeno_primary_mode(void)
+{
+       unsigned long *mode = pthread_getspecific(xeno_current_mode_key);
 
-void xeno_init_current_keys(void);
+       return mode ? (*mode & XNRELAX) : 0;
+}
 #endif /* ! HAVE___THREAD */
 
 void xeno_set_current(void);
 
+unsigned long *xeno_init_current_mode(void);
+void xeno_init_current_keys(void);
+
 #endif /* _XENO_ASM_GENERIC_CURRENT_H */
diff --git a/include/asm-generic/syscall.h b/include/asm-generic/syscall.h
index 315822e..62f7aa2 100644
--- a/include/asm-generic/syscall.h
+++ b/include/asm-generic/syscall.h
@@ -46,6 +46,7 @@
 #define __xn_sys_current       8       /* threadh = xnthread_handle(cur) */
 #define __xn_sys_current_info  9       /* r = xnshadow_current_info(&info) */
 #define __xn_sys_get_next_sigs 10      /* only unqueue pending signals. */
+#define __xn_sys_drop_u_mode   11      /* stop updating thread->u_mode */
 
 #define XENOMAI_LINUX_DOMAIN  0
 #define XENOMAI_XENO_DOMAIN   1
diff --git a/ksrc/nucleus/shadow.c b/ksrc/nucleus/shadow.c
index d82d6c7..8a50cbb 100644
--- a/ksrc/nucleus/shadow.c
+++ b/ksrc/nucleus/shadow.c
@@ -1018,7 +1018,8 @@ redo:
                /* Grab the request token. */
                return -ERESTARTSYS;
 
-       __xn_put_user(0, thread->u_mode);
+       if (thread->u_mode)
+               __xn_put_user(0, thread->u_mode);
 
        preempt_disable();
 
@@ -1208,7 +1209,8 @@ void xnshadow_relax(int notify, int reason)
        /* "current" is now running into the Linux domain on behalf of the
           root thread. */
 
-       __xn_put_user(XNRELAX, thread->u_mode);
+       if (thread->u_mode)
+               __xn_put_user(XNRELAX, thread->u_mode);
 
        trace_mark(xn_nucleus, shadow_relaxed,
                  "thread %p thread_name %s comm %s",
@@ -1382,7 +1384,8 @@ int xnshadow_map(xnthread_t *thread, xncompletion_t 
__user *u_completion,
        if (ret)
                return ret;
 
-       __xn_put_user(XNRELAX, u_mode);
+       if (thread->u_mode)
+               __xn_put_user(XNRELAX, u_mode);
 
        ret = xnshadow_harden();
 
@@ -1967,6 +1970,18 @@ static int xnshadow_sys_get_next_sigs(struct pt_regs 
*regs)
        return -EINTR;
 }
 
+static int xnshadow_sys_drop_u_mode(struct pt_regs *regs)
+{
+       xnthread_t *cur = xnshadow_thread(current);
+
+       if (!cur)
+               return -EPERM;
+
+       cur->u_mode = NULL;
+
+       return 0;
+}
+
 static xnsysent_t __systab[] = {
        [__xn_sys_migrate] = {&xnshadow_sys_migrate, __xn_exec_current},
        [__xn_sys_arch] = {&xnshadow_sys_arch, __xn_exec_any},
@@ -1981,6 +1996,8 @@ static xnsysent_t __systab[] = {
                {&xnshadow_sys_current_info, __xn_exec_shadow},
        [__xn_sys_get_next_sigs] = 
                {&xnshadow_sys_get_next_sigs, __xn_exec_conforming},
+       [__xn_sys_drop_u_mode] =
+               {&xnshadow_sys_drop_u_mode, __xn_exec_shadow},
 };
 
 static void post_ppd_release(struct xnheap *h)
@@ -2034,8 +2051,30 @@ static struct xnskin_props __props = {
        .module = NULL
 };
 
-static inline int substitute_linux_syscall(struct pt_regs *regs)
+static void handle_shadow_exit(xnthread_t *thread)
 {
+       static int warned;
+
+       /*
+        * If user space did not deregister u_mode at this point, we
+        * are confronted with old libraries and should warn about
+        * potential instabilities.
+        */
+       if (thread->u_mode && !warned) {
+               warned = 1;
+               printk(KERN_WARNING
+                      "Xenomai: old Xenomai libs detected which may crash "
+                      "on thread termination\n");
+       }
+       thread->u_mode = NULL;
+}
+
+static inline int
+substitute_linux_syscall(xnthread_t *thread, struct pt_regs *regs)
+{
+       if (unlikely(__xn_reg_mux(regs) == __NR_exit))
+               handle_shadow_exit(thread);
+
        /* No real-time replacement for now -- let Linux handle this call. */
        return 0;
 }
@@ -2204,7 +2243,7 @@ static inline int do_hisyscall_event(unsigned event, 
unsigned domid, void *data)
         * From now on, we know that we have a valid shadow thread
         * pointer.
         */
-       if (substitute_linux_syscall(regs))
+       if (substitute_linux_syscall(thread, regs))
                /*
                 * This is a Linux syscall issued on behalf of a
                 * shadow thread running inside the Xenomai
@@ -2265,7 +2304,7 @@ static inline int do_losyscall_event(unsigned event, 
unsigned domid, void *data)
        if (__xn_reg_mux_p(regs))
                goto xenomai_syscall;
 
-       if (!thread || !substitute_linux_syscall(regs))
+       if (!thread || !substitute_linux_syscall(thread, regs))
                /* Fall back to Linux syscall handling. */
                return RTHAL_EVENT_PROPAGATE;
 
diff --git a/src/rtdk/assert_context.c b/src/rtdk/assert_context.c
index f67bcd8..bad19f3 100644
--- a/src/rtdk/assert_context.c
+++ b/src/rtdk/assert_context.c
@@ -30,9 +30,12 @@ void assert_nrt(void)
        xnthread_info_t info;
        int err;
 
-       if (unlikely(xeno_get_current() != XN_NO_HANDLE &&
-                    !(xeno_get_current_mode() & XNRELAX))) {
+       if (xeno_get_current() != XN_NO_HANDLE)
+               return;
 
+       info.state = xeno_get_current_mode();
+
+       if (unlikely(!(info.state & XNRELAX) || info.state == -1)) {
                err = XENOMAI_SYSCALL1(__xn_sys_current_info, &info);
 
                if (err) {
@@ -41,7 +44,7 @@ void assert_nrt(void)
                        return;
                }
 
-               if (info.state & XNTRAPSW)
+               if ((info.state & (XNRELAX | XNTRAPSW)) == XNTRAPSW)
                        pthread_kill(pthread_self(), SIGXCPU);
        }
 }
diff --git a/src/skins/common/current.c b/src/skins/common/current.c
index 2922d6e..7db66c0 100644
--- a/src/skins/common/current.c
+++ b/src/skins/common/current.c
@@ -1,45 +1,98 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <pthread.h>
 
 #include <asm/xenomai/syscall.h>
 #include <nucleus/types.h>
 
+pthread_key_t xeno_current_mode_key;
+
 #ifdef HAVE___THREAD
 __thread __attribute__ ((tls_model ("initial-exec")))
 xnhandle_t xeno_current = XN_NO_HANDLE;
 __thread __attribute__ ((tls_model ("initial-exec")))
 unsigned long xeno_current_mode;
 
+static inline int create_current_key(void) { return 0; }
+
 static inline void __xeno_set_current(xnhandle_t current)
 {
        xeno_current = current;
 }
+
+static inline unsigned long *create_current_mode(void)
+{
+       return &xeno_current_mode;
+}
+
+static inline void free_current_mode(unsigned long *mode) { }
+
+#define XENO_MODE_LEAK_WARNING ""
+
 #else /* !HAVE___THREAD */
-#include <pthread.h>
 
 pthread_key_t xeno_current_key;
-pthread_key_t xeno_current_mode_key;
+
+static inline int create_current_key(void)
+{
+       return pthread_key_create(&xeno_current_key, NULL);
+}
 
 static inline void __xeno_set_current(xnhandle_t current)
 {
        pthread_setspecific(xeno_current_key, (void *)current);
 }
 
-unsigned long *xeno_init_current_mode(void)
+static inline unsigned long *create_current_mode(void)
 {
-       unsigned long *mode = malloc(sizeof(unsigned long));
-       pthread_setspecific(xeno_current_mode_key, mode);
-       return mode;
+       return malloc(sizeof(unsigned long));
+}
+
+static inline void free_current_mode(unsigned long *mode)
+{
+       free(mode);
+}
+
+#define XENO_MODE_LEAK_WARNING \
+       "         To reduce the probality, we leak a few bytes of heap " \
+       "per thread.\n"
+
+#endif /* !HAVE___THREAD */
+
+static void cleanup_current_mode(void *key)
+{
+       unsigned long *mode = key;
+       int err;
+
+       *mode = -1;
+
+       err = XENOMAI_SYSCALL0(__xn_sys_drop_u_mode);
+
+       if (err) {
+               static int warned;
+
+               if (!warned) {
+                       warned = 1;
+                       fprintf(stderr,
+                               "\nXenomai: WARNING, this Xenomai kernel can "
+                                       "cause spurious application\n"
+                               "         crashes on thread termination. "
+                                       "Upgrade is highly recommended.\n%s\n",
+                               XENO_MODE_LEAK_WARNING);
+               }
+       } else
+               free_current_mode(mode);
 }
 
 static void init_current_keys(void)
 {
-       int err = pthread_key_create(&xeno_current_key, NULL);
+       int err = create_current_key();
+
        if (err)
                goto error_exit;
 
-       err = pthread_key_create(&xeno_current_mode_key, free);
+       err = pthread_key_create(&xeno_current_mode_key, cleanup_current_mode);
        if (err) {
          error_exit:
                fprintf(stderr, "Xenomai: error creating TSD key: %s\n",
@@ -53,7 +106,6 @@ void xeno_init_current_keys(void)
        static pthread_once_t xeno_init_current_keys_once = PTHREAD_ONCE_INIT;
        pthread_once(&xeno_init_current_keys_once, init_current_keys);
 }
-#endif /* !HAVE___THREAD */
 
 void xeno_set_current(void)
 {
@@ -68,3 +120,11 @@ void xeno_set_current(void)
        }
        __xeno_set_current(current);
 }
+
+unsigned long *xeno_init_current_mode(void)
+{
+       unsigned long *mode = create_current_mode();
+
+       pthread_setspecific(xeno_current_mode_key, mode);
+       return mode;
+}


_______________________________________________
Xenomai-git mailing list
Xenomai-git@gna.org
https://mail.gna.org/listinfo/xenomai-git

Reply via email to