sh: Fixup __strnlen_user() behaviour.
authorPaul Mundt <lethal@linux-sh.org>
Wed, 27 Sep 2006 08:07:07 +0000 (17:07 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Wed, 27 Sep 2006 08:07:07 +0000 (17:07 +0900)
Drop TIF_USERSPACE and add addr_limit to the thread_info struct.
Subsequently, use that for address checking in strnlen_user() to
ward off bogus -EFAULTs.

Make __strnlen_user() return 0 on exception, rather than -EFAULT.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
arch/sh/kernel/process.c
include/asm-sh/processor.h
include/asm-sh/thread_info.h
include/asm-sh/uaccess.h

index f203131..4a32550 100644 (file)
@@ -263,6 +263,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
                unsigned long unused,
                struct task_struct *p, struct pt_regs *regs)
 {
+       struct thread_info *ti = task_thread_info(p);
        struct pt_regs *childregs;
 #if defined(CONFIG_SH_FPU)
        struct task_struct *tsk = current;
@@ -277,8 +278,10 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
 
        if (user_mode(regs)) {
                childregs->regs[15] = usp;
+               ti->addr_limit = USER_DS;
        } else {
                childregs->regs[15] = (unsigned long)task_stack_page(p) + THREAD_SIZE;
+               ti->addr_limit = KERNEL_DS;
        }
         if (clone_flags & CLONE_SETTLS) {
                childregs->gbr = childregs->regs[0];
index e99aff7..a227320 100644 (file)
@@ -149,6 +149,10 @@ struct thread_struct {
        union sh_fpu_union fpu;
 };
 
+typedef struct {
+       unsigned long seg;
+} mm_segment_t;
+
 /* Count of active tasks with UBC settings */
 extern int ubc_usercnt;
 
index f64dd80..b986a19 100644 (file)
@@ -21,6 +21,7 @@ struct thread_info {
        unsigned long           flags;          /* low level flags */
        __u32                   cpu;
        int                     preempt_count; /* 0 => preemptable, <0 => BUG */
+       mm_segment_t            addr_limit;     /* thread address space */
        struct restart_block    restart_block;
        __u8                    supervisor_stack[0];
 };
@@ -40,6 +41,7 @@ struct thread_info {
        .flags          = 0,                    \
        .cpu            = 0,                    \
        .preempt_count  = 1,                    \
+       .addr_limit     = KERNEL_DS,            \
        .restart_block  = {                     \
                .fn = do_no_restart_syscall,    \
        },                                      \
@@ -95,7 +97,6 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_USEDFPU            16      /* FPU was used by this task this quantum (SMP) */
 #define TIF_POLLING_NRFLAG     17      /* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE             18
-#define TIF_USERSPACE          31      /* true if FS sets userspace */
 
 #define _TIF_SYSCALL_TRACE     (1<<TIF_SYSCALL_TRACE)
 #define _TIF_NOTIFY_RESUME     (1<<TIF_NOTIFY_RESUME)
@@ -103,7 +104,6 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_NEED_RESCHED      (1<<TIF_NEED_RESCHED)
 #define _TIF_USEDFPU           (1<<TIF_USEDFPU)
 #define _TIF_POLLING_NRFLAG    (1<<TIF_POLLING_NRFLAG)
-#define _TIF_USERSPACE         (1<<TIF_USERSPACE)
 
 #define _TIF_WORK_MASK         0x000000FE      /* work to do on interrupt/exception return */
 #define _TIF_ALLWORK_MASK      0x000000FF      /* work to do on any return to u-space */
index 2cb0186..6c0014d 100644 (file)
 #include <linux/errno.h>
 #include <linux/sched.h>
 
-/*
- * NOTE: Macro/functions in this file depends on threads_info.h implementation.
- * Assumes:
- * TI_FLAGS == 8
- * TIF_USERSPACE == 31
- * USER_ADDR_LIMIT == 0x80000000
- */
-
 #define VERIFY_READ    0
 #define VERIFY_WRITE   1
 
-typedef struct {
-       unsigned int is_user_space;
-} mm_segment_t;
-
 /*
  * The fs value determines whether argument validity checking should be
  * performed or not.  If get_fs() == USER_DS, checking is performed, with
@@ -40,12 +28,14 @@ typedef struct {
  */
 
 #define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
-#define segment_eq(a,b)        ((a).is_user_space == (b).is_user_space)
 
-#define USER_ADDR_LIMIT        0x80000000
+#define KERNEL_DS      MAKE_MM_SEG(0xFFFFFFFFUL)
+#define USER_DS                MAKE_MM_SEG(PAGE_OFFSET)
+
+#define segment_eq(a,b)        ((a).seg == (b).seg)
 
-#define KERNEL_DS      MAKE_MM_SEG(0)
-#define USER_DS                MAKE_MM_SEG(1)
+#define __addr_ok(addr) \
+       ((unsigned long)(addr) < (current_thread_info()->addr_limit.seg))
 
 #define get_ds()       (KERNEL_DS)
 
@@ -76,31 +66,8 @@ static inline int __access_ok(unsigned long addr, unsigned long size)
        return ((addr >= memory_start) && ((addr + size) < memory_end));
 }
 #else /* CONFIG_MMU */
-static inline mm_segment_t get_fs(void)
-{
-       return MAKE_MM_SEG(test_thread_flag(TIF_USERSPACE));
-}
-
-static inline void set_fs(mm_segment_t s)
-{
-       unsigned long ti, flag;
-       __asm__ __volatile__(
-               "stc    r7_bank, %0\n\t"
-               "mov.l  @(8,%0), %1\n\t"
-               "shal   %1\n\t"
-               "cmp/pl %2\n\t"
-               "rotcr  %1\n\t"
-               "mov.l  %1, @(8,%0)"
-               : "=&r" (ti), "=&r" (flag)
-               : "r" (s.is_user_space)
-               : "t");
-/****
-       if (s.is_user_space)
-               set_thread_flag(TIF_USERSPACE);
-       else
-               clear_thread_flag(TIF_USERSPACE);
-****/
-}
+#define get_fs()       (current_thread_info()->addr_limit)
+#define set_fs(x)      (current_thread_info()->addr_limit = (x))
 
 /*
  * __access_ok: Check if address with size is OK or not.
@@ -108,7 +75,7 @@ static inline void set_fs(mm_segment_t s)
  * We do three checks:
  * (1) is it user space? 
  * (2) addr + size --> carry?
- * (3) addr + size >= 0x80000000  (USER_ADDR_LIMIT)
+ * (3) addr + size >= 0x80000000  (PAGE_OFFSET)
  *
  * (1) (2) (3) | RESULT
  *  0   0   0  |  ok
@@ -541,7 +508,7 @@ static __inline__ long __strnlen_user(const char __user *__s, long __n)
                "3:\n\t"
                "mov.l  4f, %1\n\t"
                "jmp    @%1\n\t"
-               " mov   %5, %0\n"
+               " mov   #0, %0\n"
                ".balign 4\n"
                "4:     .long 2b\n"
                ".previous\n"
@@ -550,26 +517,20 @@ static __inline__ long __strnlen_user(const char __user *__s, long __n)
                "       .long 1b,3b\n"
                ".previous"
                : "=z" (res), "=&r" (__dummy)
-               : "0" (0), "r" (__s), "r" (__n), "i" (-EFAULT)
+               : "0" (0), "r" (__s), "r" (__n)
                : "t");
        return res;
 }
 
 static __inline__ long strnlen_user(const char __user *s, long n)
 {
-       if (!access_ok(VERIFY_READ, s, n))
+       if (!__addr_ok(s))
                return 0;
        else
                return __strnlen_user(s, n);
 }
 
-static __inline__ long strlen_user(const char __user *s)
-{
-       if (!access_ok(VERIFY_READ, s, 0))
-               return 0;
-       else
-               return __strnlen_user(s, ~0UL >> 1);
-}
+#define strlen_user(str)       strnlen_user(str, ~0UL >> 1)
 
 /*
  * The exception table consists of pairs of addresses: the first is the