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.

---
 include/asm-generic/bits/current.h |   24 ++++++++----
 include/asm-generic/syscall.h      |    1 +
 include/nucleus/thread.h           |    2 +
 ksrc/nucleus/shadow.c              |   14 +++++++
 src/rtdk/assert_context.c          |    9 +++-
 src/skins/common/current.c         |   72 ++++++++++++++++++++++++++++--------
 6 files changed, 95 insertions(+), 27 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/include/nucleus/thread.h b/include/nucleus/thread.h
index b2baccb..cb772f7 100644
--- a/include/nucleus/thread.h
+++ b/include/nucleus/thread.h
@@ -328,6 +328,8 @@ typedef struct xnthread {
 #ifdef CONFIG_XENO_OPT_PERVASIVE
        unsigned long __user *u_mode;   /* Thread mode variable in userland. */
 
+       unsigned long u_mode_dump;      /* u_mode points here once userland 
dropped it. */
+
        unsigned u_sigpending;          /* One bit per skin */
 #endif /* CONFIG_XENO_OPT_PERVASIVE */
 
diff --git a/ksrc/nucleus/shadow.c b/ksrc/nucleus/shadow.c
index d82d6c7..8431025 100644
--- a/ksrc/nucleus/shadow.c
+++ b/ksrc/nucleus/shadow.c
@@ -1967,6 +1967,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 = (unsigned long __user*)&cur->u_mode_dump;
+
+       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 +1993,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)
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..1b09390 100644
--- a/src/skins/common/current.c
+++ b/src/skins/common/current.c
@@ -1,10 +1,13 @@
 #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;
@@ -16,36 +19,62 @@ static inline void __xeno_set_current(xnhandle_t current)
        xeno_current = current;
 }
 #else /* !HAVE___THREAD */
-#include <pthread.h>
-
 pthread_key_t xeno_current_key;
-pthread_key_t xeno_current_mode_key;
 
 static inline void __xeno_set_current(xnhandle_t current)
 {
        pthread_setspecific(xeno_current_key, (void *)current);
 }
+#endif /* !HAVE___THREAD */
 
-unsigned long *xeno_init_current_mode(void)
+static void free_current_mode(void *key)
 {
-       unsigned long *mode = malloc(sizeof(unsigned long));
-       pthread_setspecific(xeno_current_mode_key, mode);
-       return mode;
+       unsigned long *mode = key;
+       int err;
+
+       *mode = -1;
+
+       err = XENOMAI_SYSCALL0(__xn_sys_drop_u_mode);
+
+#ifndef HAVE___THREAD
+       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.\n"
+                               "         To reduce the probality, we will "
+                                       "leak a few bytes heap now.\n"
+                               );
+               }
+       } else
+               free(mode);
+#endif /* !HAVE___THREAD */
 }
 
 static void init_current_keys(void)
 {
-       int err = pthread_key_create(&xeno_current_key, NULL);
+       int err;
+
+#ifndef HAVE___THREAD
+       err = pthread_key_create(&xeno_current_key, NULL);
        if (err)
                goto error_exit;
+#endif /* !HAVE___THREAD */
 
-       err = pthread_key_create(&xeno_current_mode_key, free);
-       if (err) {
-         error_exit:
-               fprintf(stderr, "Xenomai: error creating TSD key: %s\n",
-                       strerror(err));
-               exit(EXIT_FAILURE);
-       }
+       err = pthread_key_create(&xeno_current_mode_key, free_current_mode);
+       if (err)
+               goto error_exit;
+
+       return;
+
+  error_exit:
+       fprintf(stderr, "Xenomai: error creating TSD key: %s\n",
+               strerror(err));
+       exit(EXIT_FAILURE);
 }
 
 void xeno_init_current_keys(void)
@@ -53,7 +82,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 +96,15 @@ void xeno_set_current(void)
        }
        __xeno_set_current(current);
 }
+
+unsigned long *xeno_init_current_mode(void)
+{
+#ifdef HAVE___THREAD
+       unsigned long *mode = &xeno_current_mode;
+#else /* !HAVE___THREAD */
+       unsigned long *mode = malloc(sizeof(unsigned long));
+#endif /* !HAVE___THREAD */
+
+       pthread_setspecific(xeno_current_mode_key, mode);
+       return mode;
+}
-- 
1.6.0.2

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

Reply via email to