diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2015-09-11 14:18:28 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2015-09-11 14:18:28 -0400 |
commit | c2172ce2303051764829d4958bd50a11ada0590f (patch) | |
tree | c465594496072249d2ad8ee4642f7c5dcd57e139 | |
parent | a4a5a7379e4ca03c192b732d61e446994eb67bbc (diff) | |
parent | 0b61f2c0f37983c98ed4207f3f5e265938371b68 (diff) |
Merge branch 'uaccess' into fixes
31 files changed, 398 insertions, 139 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 1c5021002fe4..a7a2e328edf9 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -1700,6 +1700,21 @@ config HIGHPTE | |||
1700 | consumed by page tables. Setting this option will allow | 1700 | consumed by page tables. Setting this option will allow |
1701 | user-space 2nd level page tables to reside in high memory. | 1701 | user-space 2nd level page tables to reside in high memory. |
1702 | 1702 | ||
1703 | config CPU_SW_DOMAIN_PAN | ||
1704 | bool "Enable use of CPU domains to implement privileged no-access" | ||
1705 | depends on MMU && !ARM_LPAE | ||
1706 | default y | ||
1707 | help | ||
1708 | Increase kernel security by ensuring that normal kernel accesses | ||
1709 | are unable to access userspace addresses. This can help prevent | ||
1710 | use-after-free bugs becoming an exploitable privilege escalation | ||
1711 | by ensuring that magic values (such as LIST_POISON) will always | ||
1712 | fault when dereferenced. | ||
1713 | |||
1714 | CPUs with low-vector mappings use a best-efforts implementation. | ||
1715 | Their lower 1MB needs to remain accessible for the vectors, but | ||
1716 | the remainder of userspace will become appropriately inaccessible. | ||
1717 | |||
1703 | config HW_PERF_EVENTS | 1718 | config HW_PERF_EVENTS |
1704 | bool "Enable hardware performance counter support for perf events" | 1719 | bool "Enable hardware performance counter support for perf events" |
1705 | depends on PERF_EVENTS | 1720 | depends on PERF_EVENTS |
diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index 4abe57279c66..9007c518d1d8 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h | |||
@@ -445,6 +445,48 @@ THUMB( orr \reg , \reg , #PSR_T_BIT ) | |||
445 | #endif | 445 | #endif |
446 | .endm | 446 | .endm |
447 | 447 | ||
448 | .macro uaccess_disable, tmp, isb=1 | ||
449 | #ifdef CONFIG_CPU_SW_DOMAIN_PAN | ||
450 | /* | ||
451 | * Whenever we re-enter userspace, the domains should always be | ||
452 | * set appropriately. | ||
453 | */ | ||
454 | mov \tmp, #DACR_UACCESS_DISABLE | ||
455 | mcr p15, 0, \tmp, c3, c0, 0 @ Set domain register | ||
456 | .if \isb | ||
457 | instr_sync | ||
458 | .endif | ||
459 | #endif | ||
460 | .endm | ||
461 | |||
462 | .macro uaccess_enable, tmp, isb=1 | ||
463 | #ifdef CONFIG_CPU_SW_DOMAIN_PAN | ||
464 | /* | ||
465 | * Whenever we re-enter userspace, the domains should always be | ||
466 | * set appropriately. | ||
467 | */ | ||
468 | mov \tmp, #DACR_UACCESS_ENABLE | ||
469 | mcr p15, 0, \tmp, c3, c0, 0 | ||
470 | .if \isb | ||
471 | instr_sync | ||
472 | .endif | ||
473 | #endif | ||
474 | .endm | ||
475 | |||
476 | .macro uaccess_save, tmp | ||
477 | #ifdef CONFIG_CPU_SW_DOMAIN_PAN | ||
478 | mrc p15, 0, \tmp, c3, c0, 0 | ||
479 | str \tmp, [sp, #S_FRAME_SIZE] | ||
480 | #endif | ||
481 | .endm | ||
482 | |||
483 | .macro uaccess_restore | ||
484 | #ifdef CONFIG_CPU_SW_DOMAIN_PAN | ||
485 | ldr r0, [sp, #S_FRAME_SIZE] | ||
486 | mcr p15, 0, r0, c3, c0, 0 | ||
487 | #endif | ||
488 | .endm | ||
489 | |||
448 | .irp c,,eq,ne,cs,cc,mi,pl,vs,vc,hi,ls,ge,lt,gt,le,hs,lo | 490 | .irp c,,eq,ne,cs,cc,mi,pl,vs,vc,hi,ls,ge,lt,gt,le,hs,lo |
449 | .macro ret\c, reg | 491 | .macro ret\c, reg |
450 | #if __LINUX_ARM_ARCH__ < 6 | 492 | #if __LINUX_ARM_ARCH__ < 6 |
diff --git a/arch/arm/include/asm/domain.h b/arch/arm/include/asm/domain.h index 6ddbe446425e..fc8ba1663601 100644 --- a/arch/arm/include/asm/domain.h +++ b/arch/arm/include/asm/domain.h | |||
@@ -12,6 +12,7 @@ | |||
12 | 12 | ||
13 | #ifndef __ASSEMBLY__ | 13 | #ifndef __ASSEMBLY__ |
14 | #include <asm/barrier.h> | 14 | #include <asm/barrier.h> |
15 | #include <asm/thread_info.h> | ||
15 | #endif | 16 | #endif |
16 | 17 | ||
17 | /* | 18 | /* |
@@ -34,15 +35,14 @@ | |||
34 | */ | 35 | */ |
35 | #ifndef CONFIG_IO_36 | 36 | #ifndef CONFIG_IO_36 |
36 | #define DOMAIN_KERNEL 0 | 37 | #define DOMAIN_KERNEL 0 |
37 | #define DOMAIN_TABLE 0 | ||
38 | #define DOMAIN_USER 1 | 38 | #define DOMAIN_USER 1 |
39 | #define DOMAIN_IO 2 | 39 | #define DOMAIN_IO 2 |
40 | #else | 40 | #else |
41 | #define DOMAIN_KERNEL 2 | 41 | #define DOMAIN_KERNEL 2 |
42 | #define DOMAIN_TABLE 2 | ||
43 | #define DOMAIN_USER 1 | 42 | #define DOMAIN_USER 1 |
44 | #define DOMAIN_IO 0 | 43 | #define DOMAIN_IO 0 |
45 | #endif | 44 | #endif |
45 | #define DOMAIN_VECTORS 3 | ||
46 | 46 | ||
47 | /* | 47 | /* |
48 | * Domain types | 48 | * Domain types |
@@ -55,30 +55,65 @@ | |||
55 | #define DOMAIN_MANAGER 1 | 55 | #define DOMAIN_MANAGER 1 |
56 | #endif | 56 | #endif |
57 | 57 | ||
58 | #define domain_val(dom,type) ((type) << (2*(dom))) | 58 | #define domain_mask(dom) ((3) << (2 * (dom))) |
59 | #define domain_val(dom,type) ((type) << (2 * (dom))) | ||
60 | |||
61 | #ifdef CONFIG_CPU_SW_DOMAIN_PAN | ||
62 | #define DACR_INIT \ | ||
63 | (domain_val(DOMAIN_USER, DOMAIN_NOACCESS) | \ | ||
64 | domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \ | ||
65 | domain_val(DOMAIN_IO, DOMAIN_CLIENT) | \ | ||
66 | domain_val(DOMAIN_VECTORS, DOMAIN_CLIENT)) | ||
67 | #else | ||
68 | #define DACR_INIT \ | ||
69 | (domain_val(DOMAIN_USER, DOMAIN_CLIENT) | \ | ||
70 | domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \ | ||
71 | domain_val(DOMAIN_IO, DOMAIN_CLIENT) | \ | ||
72 | domain_val(DOMAIN_VECTORS, DOMAIN_CLIENT)) | ||
73 | #endif | ||
74 | |||
75 | #define __DACR_DEFAULT \ | ||
76 | domain_val(DOMAIN_KERNEL, DOMAIN_CLIENT) | \ | ||
77 | domain_val(DOMAIN_IO, DOMAIN_CLIENT) | \ | ||
78 | domain_val(DOMAIN_VECTORS, DOMAIN_CLIENT) | ||
79 | |||
80 | #define DACR_UACCESS_DISABLE \ | ||
81 | (__DACR_DEFAULT | domain_val(DOMAIN_USER, DOMAIN_NOACCESS)) | ||
82 | #define DACR_UACCESS_ENABLE \ | ||
83 | (__DACR_DEFAULT | domain_val(DOMAIN_USER, DOMAIN_CLIENT)) | ||
59 | 84 | ||
60 | #ifndef __ASSEMBLY__ | 85 | #ifndef __ASSEMBLY__ |
61 | 86 | ||
62 | #ifdef CONFIG_CPU_USE_DOMAINS | 87 | static inline unsigned int get_domain(void) |
88 | { | ||
89 | unsigned int domain; | ||
90 | |||
91 | asm( | ||
92 | "mrc p15, 0, %0, c3, c0 @ get domain" | ||
93 | : "=r" (domain) | ||
94 | : "m" (current_thread_info()->cpu_domain)); | ||
95 | |||
96 | return domain; | ||
97 | } | ||
98 | |||
63 | static inline void set_domain(unsigned val) | 99 | static inline void set_domain(unsigned val) |
64 | { | 100 | { |
65 | asm volatile( | 101 | asm volatile( |
66 | "mcr p15, 0, %0, c3, c0 @ set domain" | 102 | "mcr p15, 0, %0, c3, c0 @ set domain" |
67 | : : "r" (val)); | 103 | : : "r" (val) : "memory"); |
68 | isb(); | 104 | isb(); |
69 | } | 105 | } |
70 | 106 | ||
107 | #ifdef CONFIG_CPU_USE_DOMAINS | ||
71 | #define modify_domain(dom,type) \ | 108 | #define modify_domain(dom,type) \ |
72 | do { \ | 109 | do { \ |
73 | struct thread_info *thread = current_thread_info(); \ | 110 | unsigned int domain = get_domain(); \ |
74 | unsigned int domain = thread->cpu_domain; \ | 111 | domain &= ~domain_mask(dom); \ |
75 | domain &= ~domain_val(dom, DOMAIN_MANAGER); \ | 112 | domain = domain | domain_val(dom, type); \ |
76 | thread->cpu_domain = domain | domain_val(dom, type); \ | 113 | set_domain(domain); \ |
77 | set_domain(thread->cpu_domain); \ | ||
78 | } while (0) | 114 | } while (0) |
79 | 115 | ||
80 | #else | 116 | #else |
81 | static inline void set_domain(unsigned val) { } | ||
82 | static inline void modify_domain(unsigned dom, unsigned type) { } | 117 | static inline void modify_domain(unsigned dom, unsigned type) { } |
83 | #endif | 118 | #endif |
84 | 119 | ||
diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h index 5eed82809d82..6795368ad023 100644 --- a/arch/arm/include/asm/futex.h +++ b/arch/arm/include/asm/futex.h | |||
@@ -22,8 +22,11 @@ | |||
22 | #ifdef CONFIG_SMP | 22 | #ifdef CONFIG_SMP |
23 | 23 | ||
24 | #define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \ | 24 | #define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \ |
25 | ({ \ | ||
26 | unsigned int __ua_flags; \ | ||
25 | smp_mb(); \ | 27 | smp_mb(); \ |
26 | prefetchw(uaddr); \ | 28 | prefetchw(uaddr); \ |
29 | __ua_flags = uaccess_save_and_enable(); \ | ||
27 | __asm__ __volatile__( \ | 30 | __asm__ __volatile__( \ |
28 | "1: ldrex %1, [%3]\n" \ | 31 | "1: ldrex %1, [%3]\n" \ |
29 | " " insn "\n" \ | 32 | " " insn "\n" \ |
@@ -34,12 +37,15 @@ | |||
34 | __futex_atomic_ex_table("%5") \ | 37 | __futex_atomic_ex_table("%5") \ |
35 | : "=&r" (ret), "=&r" (oldval), "=&r" (tmp) \ | 38 | : "=&r" (ret), "=&r" (oldval), "=&r" (tmp) \ |
36 | : "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \ | 39 | : "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \ |
37 | : "cc", "memory") | 40 | : "cc", "memory"); \ |
41 | uaccess_restore(__ua_flags); \ | ||
42 | }) | ||
38 | 43 | ||
39 | static inline int | 44 | static inline int |
40 | futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, | 45 | futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, |
41 | u32 oldval, u32 newval) | 46 | u32 oldval, u32 newval) |
42 | { | 47 | { |
48 | unsigned int __ua_flags; | ||
43 | int ret; | 49 | int ret; |
44 | u32 val; | 50 | u32 val; |
45 | 51 | ||
@@ -49,6 +55,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, | |||
49 | smp_mb(); | 55 | smp_mb(); |
50 | /* Prefetching cannot fault */ | 56 | /* Prefetching cannot fault */ |
51 | prefetchw(uaddr); | 57 | prefetchw(uaddr); |
58 | __ua_flags = uaccess_save_and_enable(); | ||
52 | __asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n" | 59 | __asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n" |
53 | "1: ldrex %1, [%4]\n" | 60 | "1: ldrex %1, [%4]\n" |
54 | " teq %1, %2\n" | 61 | " teq %1, %2\n" |
@@ -61,6 +68,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, | |||
61 | : "=&r" (ret), "=&r" (val) | 68 | : "=&r" (ret), "=&r" (val) |
62 | : "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT) | 69 | : "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT) |
63 | : "cc", "memory"); | 70 | : "cc", "memory"); |
71 | uaccess_restore(__ua_flags); | ||
64 | smp_mb(); | 72 | smp_mb(); |
65 | 73 | ||
66 | *uval = val; | 74 | *uval = val; |
@@ -73,6 +81,8 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, | |||
73 | #include <asm/domain.h> | 81 | #include <asm/domain.h> |
74 | 82 | ||
75 | #define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \ | 83 | #define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \ |
84 | ({ \ | ||
85 | unsigned int __ua_flags = uaccess_save_and_enable(); \ | ||
76 | __asm__ __volatile__( \ | 86 | __asm__ __volatile__( \ |
77 | "1: " TUSER(ldr) " %1, [%3]\n" \ | 87 | "1: " TUSER(ldr) " %1, [%3]\n" \ |
78 | " " insn "\n" \ | 88 | " " insn "\n" \ |
@@ -81,12 +91,15 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, | |||
81 | __futex_atomic_ex_table("%5") \ | 91 | __futex_atomic_ex_table("%5") \ |
82 | : "=&r" (ret), "=&r" (oldval), "=&r" (tmp) \ | 92 | : "=&r" (ret), "=&r" (oldval), "=&r" (tmp) \ |
83 | : "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \ | 93 | : "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \ |
84 | : "cc", "memory") | 94 | : "cc", "memory"); \ |
95 | uaccess_restore(__ua_flags); \ | ||
96 | }) | ||
85 | 97 | ||
86 | static inline int | 98 | static inline int |
87 | futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, | 99 | futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, |
88 | u32 oldval, u32 newval) | 100 | u32 oldval, u32 newval) |
89 | { | 101 | { |
102 | unsigned int __ua_flags; | ||
90 | int ret = 0; | 103 | int ret = 0; |
91 | u32 val; | 104 | u32 val; |
92 | 105 | ||
@@ -94,6 +107,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, | |||
94 | return -EFAULT; | 107 | return -EFAULT; |
95 | 108 | ||
96 | preempt_disable(); | 109 | preempt_disable(); |
110 | __ua_flags = uaccess_save_and_enable(); | ||
97 | __asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n" | 111 | __asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n" |
98 | "1: " TUSER(ldr) " %1, [%4]\n" | 112 | "1: " TUSER(ldr) " %1, [%4]\n" |
99 | " teq %1, %2\n" | 113 | " teq %1, %2\n" |
@@ -103,6 +117,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, | |||
103 | : "+r" (ret), "=&r" (val) | 117 | : "+r" (ret), "=&r" (val) |
104 | : "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT) | 118 | : "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT) |
105 | : "cc", "memory"); | 119 | : "cc", "memory"); |
120 | uaccess_restore(__ua_flags); | ||
106 | 121 | ||
107 | *uval = val; | 122 | *uval = val; |
108 | preempt_enable(); | 123 | preempt_enable(); |
diff --git a/arch/arm/include/asm/pgtable-2level-hwdef.h b/arch/arm/include/asm/pgtable-2level-hwdef.h index 5e68278e953e..d0131ee6f6af 100644 --- a/arch/arm/include/asm/pgtable-2level-hwdef.h +++ b/arch/arm/include/asm/pgtable-2level-hwdef.h | |||
@@ -23,6 +23,7 @@ | |||
23 | #define PMD_PXNTABLE (_AT(pmdval_t, 1) << 2) /* v7 */ | 23 | #define PMD_PXNTABLE (_AT(pmdval_t, 1) << 2) /* v7 */ |
24 | #define PMD_BIT4 (_AT(pmdval_t, 1) << 4) | 24 | #define PMD_BIT4 (_AT(pmdval_t, 1) << 4) |
25 | #define PMD_DOMAIN(x) (_AT(pmdval_t, (x)) << 5) | 25 | #define PMD_DOMAIN(x) (_AT(pmdval_t, (x)) << 5) |
26 | #define PMD_DOMAIN_MASK PMD_DOMAIN(0x0f) | ||
26 | #define PMD_PROTECTION (_AT(pmdval_t, 1) << 9) /* v5 */ | 27 | #define PMD_PROTECTION (_AT(pmdval_t, 1) << 9) /* v5 */ |
27 | /* | 28 | /* |
28 | * - section | 29 | * - section |
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index bd32eded3e50..ae02e68b61fc 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h | |||
@@ -25,7 +25,6 @@ | |||
25 | struct task_struct; | 25 | struct task_struct; |
26 | 26 | ||
27 | #include <asm/types.h> | 27 | #include <asm/types.h> |
28 | #include <asm/domain.h> | ||
29 | 28 | ||
30 | typedef unsigned long mm_segment_t; | 29 | typedef unsigned long mm_segment_t; |
31 | 30 | ||
@@ -74,9 +73,6 @@ struct thread_info { | |||
74 | .flags = 0, \ | 73 | .flags = 0, \ |
75 | .preempt_count = INIT_PREEMPT_COUNT, \ | 74 | .preempt_count = INIT_PREEMPT_COUNT, \ |
76 | .addr_limit = KERNEL_DS, \ | 75 | .addr_limit = KERNEL_DS, \ |
77 | .cpu_domain = domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \ | ||
78 | domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \ | ||
79 | domain_val(DOMAIN_IO, DOMAIN_CLIENT), \ | ||
80 | } | 76 | } |
81 | 77 | ||
82 | #define init_thread_info (init_thread_union.thread_info) | 78 | #define init_thread_info (init_thread_union.thread_info) |
diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h index 74b17d09ef7a..01bae13b2cea 100644 --- a/arch/arm/include/asm/uaccess.h +++ b/arch/arm/include/asm/uaccess.h | |||
@@ -50,6 +50,35 @@ struct exception_table_entry | |||
50 | extern int fixup_exception(struct pt_regs *regs); | 50 | extern int fixup_exception(struct pt_regs *regs); |
51 | 51 | ||
52 | /* | 52 | /* |
53 | * These two functions allow hooking accesses to userspace to increase | ||
54 | * system integrity by ensuring that the kernel can not inadvertantly | ||
55 | * perform such accesses (eg, via list poison values) which could then | ||
56 | * be exploited for priviledge escalation. | ||
57 | */ | ||
58 | static inline unsigned int uaccess_save_and_enable(void) | ||
59 | { | ||
60 | #ifdef CONFIG_CPU_SW_DOMAIN_PAN | ||
61 | unsigned int old_domain = get_domain(); | ||
62 | |||
63 | /* Set the current domain access to permit user accesses */ | ||
64 | set_domain((old_domain & ~domain_mask(DOMAIN_USER)) | | ||
65 | domain_val(DOMAIN_USER, DOMAIN_CLIENT)); | ||
66 | |||
67 | return old_domain; | ||
68 | #else | ||
69 | return 0; | ||
70 | #endif | ||
71 | } | ||
72 | |||
73 | static inline void uaccess_restore(unsigned int flags) | ||
74 | { | ||
75 | #ifdef CONFIG_CPU_SW_DOMAIN_PAN | ||
76 | /* Restore the user access mask */ | ||
77 | set_domain(flags); | ||
78 | #endif | ||
79 | } | ||
80 | |||
81 | /* | ||
53 | * These two are intentionally not defined anywhere - if the kernel | 82 | * These two are intentionally not defined anywhere - if the kernel |
54 | * code generates any references to them, that's a bug. | 83 | * code generates any references to them, that's a bug. |
55 | */ | 84 | */ |
@@ -165,6 +194,7 @@ extern int __get_user_64t_4(void *); | |||
165 | register typeof(x) __r2 asm("r2"); \ | 194 | register typeof(x) __r2 asm("r2"); \ |
166 | register unsigned long __l asm("r1") = __limit; \ | 195 | register unsigned long __l asm("r1") = __limit; \ |
167 | register int __e asm("r0"); \ | 196 | register int __e asm("r0"); \ |
197 | unsigned int __ua_flags = uaccess_save_and_enable(); \ | ||
168 | switch (sizeof(*(__p))) { \ | 198 | switch (sizeof(*(__p))) { \ |
169 | case 1: \ | 199 | case 1: \ |
170 | if (sizeof((x)) >= 8) \ | 200 | if (sizeof((x)) >= 8) \ |
@@ -192,6 +222,7 @@ extern int __get_user_64t_4(void *); | |||
192 | break; \ | 222 | break; \ |
193 | default: __e = __get_user_bad(); break; \ | 223 | default: __e = __get_user_bad(); break; \ |
194 | } \ | 224 | } \ |
225 | uaccess_restore(__ua_flags); \ | ||
195 | x = (typeof(*(p))) __r2; \ | 226 | x = (typeof(*(p))) __r2; \ |
196 | __e; \ | 227 | __e; \ |
197 | }) | 228 | }) |
@@ -224,6 +255,7 @@ extern int __put_user_8(void *, unsigned long long); | |||
224 | register const typeof(*(p)) __user *__p asm("r0") = __tmp_p; \ | 255 | register const typeof(*(p)) __user *__p asm("r0") = __tmp_p; \ |
225 | register unsigned long __l asm("r1") = __limit; \ | 256 | register unsigned long __l asm("r1") = __limit; \ |
226 | register int __e asm("r0"); \ | 257 | register int __e asm("r0"); \ |
258 | unsigned int __ua_flags = uaccess_save_and_enable(); \ | ||
227 | switch (sizeof(*(__p))) { \ | 259 | switch (sizeof(*(__p))) { \ |
228 | case 1: \ | 260 | case 1: \ |
229 | __put_user_x(__r2, __p, __e, __l, 1); \ | 261 | __put_user_x(__r2, __p, __e, __l, 1); \ |
@@ -239,6 +271,7 @@ extern int __put_user_8(void *, unsigned long long); | |||
239 | break; \ | 271 | break; \ |
240 | default: __e = __put_user_bad(); break; \ | 272 | default: __e = __put_user_bad(); break; \ |
241 | } \ | 273 | } \ |
274 | uaccess_restore(__ua_flags); \ | ||
242 | __e; \ | 275 | __e; \ |
243 | }) | 276 | }) |
244 | 277 | ||
@@ -300,14 +333,17 @@ static inline void set_fs(mm_segment_t fs) | |||
300 | do { \ | 333 | do { \ |
301 | unsigned long __gu_addr = (unsigned long)(ptr); \ | 334 | unsigned long __gu_addr = (unsigned long)(ptr); \ |
302 | unsigned long __gu_val; \ | 335 | unsigned long __gu_val; \ |
336 | unsigned int __ua_flags; \ | ||
303 | __chk_user_ptr(ptr); \ | 337 | __chk_user_ptr(ptr); \ |
304 | might_fault(); \ | 338 | might_fault(); \ |
339 | __ua_flags = uaccess_save_and_enable(); \ | ||
305 | switch (sizeof(*(ptr))) { \ | 340 | switch (sizeof(*(ptr))) { \ |
306 | case 1: __get_user_asm_byte(__gu_val, __gu_addr, err); break; \ | 341 | case 1: __get_user_asm_byte(__gu_val, __gu_addr, err); break; \ |
307 | case 2: __get_user_asm_half(__gu_val, __gu_addr, err); break; \ | 342 | case 2: __get_user_asm_half(__gu_val, __gu_addr, err); break; \ |
308 | case 4: __get_user_asm_word(__gu_val, __gu_addr, err); break; \ | 343 | case 4: __get_user_asm_word(__gu_val, __gu_addr, err); break; \ |
309 | default: (__gu_val) = __get_user_bad(); \ | 344 | default: (__gu_val) = __get_user_bad(); \ |
310 | } \ | 345 | } \ |
346 | uaccess_restore(__ua_flags); \ | ||
311 | (x) = (__typeof__(*(ptr)))__gu_val; \ | 347 | (x) = (__typeof__(*(ptr)))__gu_val; \ |
312 | } while (0) | 348 | } while (0) |
313 | 349 | ||
@@ -381,9 +417,11 @@ do { \ | |||
381 | #define __put_user_err(x, ptr, err) \ | 417 | #define __put_user_err(x, ptr, err) \ |
382 | do { \ | 418 | do { \ |
383 | unsigned long __pu_addr = (unsigned long)(ptr); \ | 419 | unsigned long __pu_addr = (unsigned long)(ptr); \ |
420 | unsigned int __ua_flags; \ | ||
384 | __typeof__(*(ptr)) __pu_val = (x); \ | 421 | __typeof__(*(ptr)) __pu_val = (x); \ |
385 | __chk_user_ptr(ptr); \ | 422 | __chk_user_ptr(ptr); \ |
386 | might_fault(); \ | 423 | might_fault(); \ |
424 | __ua_flags = uaccess_save_and_enable(); \ | ||
387 | switch (sizeof(*(ptr))) { \ | 425 | switch (sizeof(*(ptr))) { \ |
388 | case 1: __put_user_asm_byte(__pu_val, __pu_addr, err); break; \ | 426 | case 1: __put_user_asm_byte(__pu_val, __pu_addr, err); break; \ |
389 | case 2: __put_user_asm_half(__pu_val, __pu_addr, err); break; \ | 427 | case 2: __put_user_asm_half(__pu_val, __pu_addr, err); break; \ |
@@ -391,6 +429,7 @@ do { \ | |||
391 | case 8: __put_user_asm_dword(__pu_val, __pu_addr, err); break; \ | 429 | case 8: __put_user_asm_dword(__pu_val, __pu_addr, err); break; \ |
392 | default: __put_user_bad(); \ | 430 | default: __put_user_bad(); \ |
393 | } \ | 431 | } \ |
432 | uaccess_restore(__ua_flags); \ | ||
394 | } while (0) | 433 | } while (0) |
395 | 434 | ||
396 | #define __put_user_asm_byte(x, __pu_addr, err) \ | 435 | #define __put_user_asm_byte(x, __pu_addr, err) \ |
@@ -474,11 +513,46 @@ do { \ | |||
474 | 513 | ||
475 | 514 | ||
476 | #ifdef CONFIG_MMU | 515 | #ifdef CONFIG_MMU |
477 | extern unsigned long __must_check __copy_from_user(void *to, const void __user *from, unsigned long n); | 516 | extern unsigned long __must_check |
478 | extern unsigned long __must_check __copy_to_user(void __user *to, const void *from, unsigned long n); | 517 | arm_copy_from_user(void *to, const void __user *from, unsigned long n); |
479 | extern unsigned long __must_check __copy_to_user_std(void __user *to, const void *from, unsigned long n); | 518 | |
480 | extern unsigned long __must_check __clear_user(void __user *addr, unsigned long n); | 519 | static inline unsigned long __must_check |
481 | extern unsigned long __must_check __clear_user_std(void __user *addr, unsigned long n); | 520 | __copy_from_user(void *to, const void __user *from, unsigned long n) |
521 | { | ||
522 | unsigned int __ua_flags = uaccess_save_and_enable(); | ||
523 | n = arm_copy_from_user(to, from, n); | ||
524 | uaccess_restore(__ua_flags); | ||
525 | return n; | ||
526 | } | ||
527 | |||
528 | extern unsigned long __must_check | ||
529 | arm_copy_to_user(void __user *to, const void *from, unsigned long n); | ||
530 | extern unsigned long __must_check | ||
531 | __copy_to_user_std(void __user *to, const void *from, unsigned long n); | ||
532 | |||
533 | static inline unsigned long __must_check | ||
534 | __copy_to_user(void __user *to, const void *from, unsigned long n) | ||
535 | { | ||
536 | unsigned int __ua_flags = uaccess_save_and_enable(); | ||
537 | n = arm_copy_to_user(to, from, n); | ||
538 | uaccess_restore(__ua_flags); | ||
539 | return n; | ||
540 | } | ||
541 | |||
542 | extern unsigned long __must_check | ||
543 | arm_clear_user(void __user *addr, unsigned long n); | ||
544 | extern unsigned long __must_check | ||
545 | __clear_user_std(void __user *addr, unsigned long n); | ||
546 | |||
547 | static inline unsigned long __must_check | ||
548 | __clear_user(void __user *addr, unsigned long n) | ||
549 | { | ||
550 | unsigned int __ua_flags = uaccess_save_and_enable(); | ||
551 | n = arm_clear_user(addr, n); | ||
552 | uaccess_restore(__ua_flags); | ||
553 | return n; | ||
554 | } | ||
555 | |||
482 | #else | 556 | #else |
483 | #define __copy_from_user(to, from, n) (memcpy(to, (void __force *)from, n), 0) | 557 | #define __copy_from_user(to, from, n) (memcpy(to, (void __force *)from, n), 0) |
484 | #define __copy_to_user(to, from, n) (memcpy((void __force *)to, from, n), 0) | 558 | #define __copy_to_user(to, from, n) (memcpy((void __force *)to, from, n), 0) |
@@ -511,6 +585,7 @@ static inline unsigned long __must_check clear_user(void __user *to, unsigned lo | |||
511 | return n; | 585 | return n; |
512 | } | 586 | } |
513 | 587 | ||
588 | /* These are from lib/ code, and use __get_user() and friends */ | ||
514 | extern long strncpy_from_user(char *dest, const char __user *src, long count); | 589 | extern long strncpy_from_user(char *dest, const char __user *src, long count); |
515 | 590 | ||
516 | extern __must_check long strlen_user(const char __user *str); | 591 | extern __must_check long strlen_user(const char __user *str); |
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index 5e5a51a99e68..f89811fb9a55 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c | |||
@@ -97,9 +97,9 @@ EXPORT_SYMBOL(mmiocpy); | |||
97 | #ifdef CONFIG_MMU | 97 | #ifdef CONFIG_MMU |
98 | EXPORT_SYMBOL(copy_page); | 98 | EXPORT_SYMBOL(copy_page); |
99 | 99 | ||
100 | EXPORT_SYMBOL(__copy_from_user); | 100 | EXPORT_SYMBOL(arm_copy_from_user); |
101 | EXPORT_SYMBOL(__copy_to_user); | 101 | EXPORT_SYMBOL(arm_copy_to_user); |
102 | EXPORT_SYMBOL(__clear_user); | 102 | EXPORT_SYMBOL(arm_clear_user); |
103 | 103 | ||
104 | EXPORT_SYMBOL(__get_user_1); | 104 | EXPORT_SYMBOL(__get_user_1); |
105 | EXPORT_SYMBOL(__get_user_2); | 105 | EXPORT_SYMBOL(__get_user_2); |
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index cb4fb1e69778..3e1c26eb32b4 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S | |||
@@ -149,10 +149,10 @@ ENDPROC(__und_invalid) | |||
149 | #define SPFIX(code...) | 149 | #define SPFIX(code...) |
150 | #endif | 150 | #endif |
151 | 151 | ||
152 | .macro svc_entry, stack_hole=0, trace=1 | 152 | .macro svc_entry, stack_hole=0, trace=1, uaccess=1 |
153 | UNWIND(.fnstart ) | 153 | UNWIND(.fnstart ) |
154 | UNWIND(.save {r0 - pc} ) | 154 | UNWIND(.save {r0 - pc} ) |
155 | sub sp, sp, #(S_FRAME_SIZE + \stack_hole - 4) | 155 | sub sp, sp, #(S_FRAME_SIZE + 8 + \stack_hole - 4) |
156 | #ifdef CONFIG_THUMB2_KERNEL | 156 | #ifdef CONFIG_THUMB2_KERNEL |
157 | SPFIX( str r0, [sp] ) @ temporarily saved | 157 | SPFIX( str r0, [sp] ) @ temporarily saved |
158 | SPFIX( mov r0, sp ) | 158 | SPFIX( mov r0, sp ) |
@@ -167,7 +167,7 @@ ENDPROC(__und_invalid) | |||
167 | ldmia r0, {r3 - r5} | 167 | ldmia r0, {r3 - r5} |
168 | add r7, sp, #S_SP - 4 @ here for interlock avoidance | 168 | add r7, sp, #S_SP - 4 @ here for interlock avoidance |
169 | mov r6, #-1 @ "" "" "" "" | 169 | mov r6, #-1 @ "" "" "" "" |
170 | add r2, sp, #(S_FRAME_SIZE + \stack_hole - 4) | 170 | add r2, sp, #(S_FRAME_SIZE + 8 + \stack_hole - 4) |
171 | SPFIX( addeq r2, r2, #4 ) | 171 | SPFIX( addeq r2, r2, #4 ) |
172 | str r3, [sp, #-4]! @ save the "real" r0 copied | 172 | str r3, [sp, #-4]! @ save the "real" r0 copied |
173 | @ from the exception stack | 173 | @ from the exception stack |
@@ -185,6 +185,11 @@ ENDPROC(__und_invalid) | |||
185 | @ | 185 | @ |
186 | stmia r7, {r2 - r6} | 186 | stmia r7, {r2 - r6} |
187 | 187 | ||
188 | uaccess_save r0 | ||
189 | .if \uaccess | ||
190 | uaccess_disable r0 | ||
191 | .endif | ||
192 | |||
188 | .if \trace | 193 | .if \trace |
189 | #ifdef CONFIG_TRACE_IRQFLAGS | 194 | #ifdef CONFIG_TRACE_IRQFLAGS |
190 | bl trace_hardirqs_off | 195 | bl trace_hardirqs_off |
@@ -194,7 +199,7 @@ ENDPROC(__und_invalid) | |||
194 | 199 | ||
195 | .align 5 | 200 | .align 5 |
196 | __dabt_svc: | 201 | __dabt_svc: |
197 | svc_entry | 202 | svc_entry uaccess=0 |
198 | mov r2, sp | 203 | mov r2, sp |
199 | dabt_helper | 204 | dabt_helper |
200 | THUMB( ldr r5, [sp, #S_PSR] ) @ potentially updated CPSR | 205 | THUMB( ldr r5, [sp, #S_PSR] ) @ potentially updated CPSR |
@@ -368,7 +373,7 @@ ENDPROC(__fiq_abt) | |||
368 | #error "sizeof(struct pt_regs) must be a multiple of 8" | 373 | #error "sizeof(struct pt_regs) must be a multiple of 8" |
369 | #endif | 374 | #endif |
370 | 375 | ||
371 | .macro usr_entry, trace=1 | 376 | .macro usr_entry, trace=1, uaccess=1 |
372 | UNWIND(.fnstart ) | 377 | UNWIND(.fnstart ) |
373 | UNWIND(.cantunwind ) @ don't unwind the user space | 378 | UNWIND(.cantunwind ) @ don't unwind the user space |
374 | sub sp, sp, #S_FRAME_SIZE | 379 | sub sp, sp, #S_FRAME_SIZE |
@@ -400,6 +405,10 @@ ENDPROC(__fiq_abt) | |||
400 | ARM( stmdb r0, {sp, lr}^ ) | 405 | ARM( stmdb r0, {sp, lr}^ ) |
401 | THUMB( store_user_sp_lr r0, r1, S_SP - S_PC ) | 406 | THUMB( store_user_sp_lr r0, r1, S_SP - S_PC ) |
402 | 407 | ||
408 | .if \uaccess | ||
409 | uaccess_disable ip | ||
410 | .endif | ||
411 | |||
403 | @ Enable the alignment trap while in kernel mode | 412 | @ Enable the alignment trap while in kernel mode |
404 | ATRAP( teq r8, r7) | 413 | ATRAP( teq r8, r7) |
405 | ATRAP( mcrne p15, 0, r8, c1, c0, 0) | 414 | ATRAP( mcrne p15, 0, r8, c1, c0, 0) |
@@ -435,7 +444,7 @@ ENDPROC(__fiq_abt) | |||
435 | 444 | ||
436 | .align 5 | 445 | .align 5 |
437 | __dabt_usr: | 446 | __dabt_usr: |
438 | usr_entry | 447 | usr_entry uaccess=0 |
439 | kuser_cmpxchg_check | 448 | kuser_cmpxchg_check |
440 | mov r2, sp | 449 | mov r2, sp |
441 | dabt_helper | 450 | dabt_helper |
@@ -458,7 +467,7 @@ ENDPROC(__irq_usr) | |||
458 | 467 | ||
459 | .align 5 | 468 | .align 5 |
460 | __und_usr: | 469 | __und_usr: |
461 | usr_entry | 470 | usr_entry uaccess=0 |
462 | 471 | ||
463 | mov r2, r4 | 472 | mov r2, r4 |
464 | mov r3, r5 | 473 | mov r3, r5 |
@@ -484,6 +493,8 @@ __und_usr: | |||
484 | 1: ldrt r0, [r4] | 493 | 1: ldrt r0, [r4] |
485 | ARM_BE8(rev r0, r0) @ little endian instruction | 494 | ARM_BE8(rev r0, r0) @ little endian instruction |
486 | 495 | ||
496 | uaccess_disable ip | ||
497 | |||
487 | @ r0 = 32-bit ARM instruction which caused the exception | 498 | @ r0 = 32-bit ARM instruction which caused the exception |
488 | @ r2 = PC value for the following instruction (:= regs->ARM_pc) | 499 | @ r2 = PC value for the following instruction (:= regs->ARM_pc) |
489 | @ r4 = PC value for the faulting instruction | 500 | @ r4 = PC value for the faulting instruction |
@@ -518,9 +529,10 @@ __und_usr_thumb: | |||
518 | 2: ldrht r5, [r4] | 529 | 2: ldrht r5, [r4] |
519 | ARM_BE8(rev16 r5, r5) @ little endian instruction | 530 | ARM_BE8(rev16 r5, r5) @ little endian instruction |
520 | cmp r5, #0xe800 @ 32bit instruction if xx != 0 | 531 | cmp r5, #0xe800 @ 32bit instruction if xx != 0 |
521 | blo __und_usr_fault_16 @ 16bit undefined instruction | 532 | blo __und_usr_fault_16_pan @ 16bit undefined instruction |
522 | 3: ldrht r0, [r2] | 533 | 3: ldrht r0, [r2] |
523 | ARM_BE8(rev16 r0, r0) @ little endian instruction | 534 | ARM_BE8(rev16 r0, r0) @ little endian instruction |
535 | uaccess_disable ip | ||
524 | add r2, r2, #2 @ r2 is PC + 2, make it PC + 4 | 536 | add r2, r2, #2 @ r2 is PC + 2, make it PC + 4 |
525 | str r2, [sp, #S_PC] @ it's a 2x16bit instr, update | 537 | str r2, [sp, #S_PC] @ it's a 2x16bit instr, update |
526 | orr r0, r0, r5, lsl #16 | 538 | orr r0, r0, r5, lsl #16 |
@@ -715,6 +727,8 @@ ENDPROC(no_fp) | |||
715 | __und_usr_fault_32: | 727 | __und_usr_fault_32: |
716 | mov r1, #4 | 728 | mov r1, #4 |
717 | b 1f | 729 | b 1f |
730 | __und_usr_fault_16_pan: | ||
731 | uaccess_disable ip | ||
718 | __und_usr_fault_16: | 732 | __und_usr_fault_16: |
719 | mov r1, #2 | 733 | mov r1, #2 |
720 | 1: mov r0, sp | 734 | 1: mov r0, sp |
@@ -770,6 +784,8 @@ ENTRY(__switch_to) | |||
770 | ldr r4, [r2, #TI_TP_VALUE] | 784 | ldr r4, [r2, #TI_TP_VALUE] |
771 | ldr r5, [r2, #TI_TP_VALUE + 4] | 785 | ldr r5, [r2, #TI_TP_VALUE + 4] |
772 | #ifdef CONFIG_CPU_USE_DOMAINS | 786 | #ifdef CONFIG_CPU_USE_DOMAINS |
787 | mrc p15, 0, r6, c3, c0, 0 @ Get domain register | ||
788 | str r6, [r1, #TI_CPU_DOMAIN] @ Save old domain register | ||
773 | ldr r6, [r2, #TI_CPU_DOMAIN] | 789 | ldr r6, [r2, #TI_CPU_DOMAIN] |
774 | #endif | 790 | #endif |
775 | switch_tls r1, r4, r5, r3, r7 | 791 | switch_tls r1, r4, r5, r3, r7 |
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index b48dd4f37f80..61974dfba132 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S | |||
@@ -174,6 +174,8 @@ ENTRY(vector_swi) | |||
174 | USER( ldr scno, [lr, #-4] ) @ get SWI instruction | 174 | USER( ldr scno, [lr, #-4] ) @ get SWI instruction |
175 | #endif | 175 | #endif |
176 | 176 | ||
177 | uaccess_disable tbl | ||
178 | |||
177 | adr tbl, sys_call_table @ load syscall table pointer | 179 | adr tbl, sys_call_table @ load syscall table pointer |
178 | 180 | ||
179 | #if defined(CONFIG_OABI_COMPAT) | 181 | #if defined(CONFIG_OABI_COMPAT) |
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S index 1a0045abead7..0d22ad206d52 100644 --- a/arch/arm/kernel/entry-header.S +++ b/arch/arm/kernel/entry-header.S | |||
@@ -196,7 +196,7 @@ | |||
196 | msr cpsr_c, \rtemp @ switch back to the SVC mode | 196 | msr cpsr_c, \rtemp @ switch back to the SVC mode |
197 | .endm | 197 | .endm |
198 | 198 | ||
199 | #ifndef CONFIG_THUMB2_KERNEL | 199 | |
200 | .macro svc_exit, rpsr, irq = 0 | 200 | .macro svc_exit, rpsr, irq = 0 |
201 | .if \irq != 0 | 201 | .if \irq != 0 |
202 | @ IRQs already off | 202 | @ IRQs already off |
@@ -215,6 +215,10 @@ | |||
215 | blne trace_hardirqs_off | 215 | blne trace_hardirqs_off |
216 | #endif | 216 | #endif |
217 | .endif | 217 | .endif |
218 | uaccess_restore | ||
219 | |||
220 | #ifndef CONFIG_THUMB2_KERNEL | ||
221 | @ ARM mode SVC restore | ||
218 | msr spsr_cxsf, \rpsr | 222 | msr spsr_cxsf, \rpsr |
219 | #if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_32v6K) | 223 | #if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_32v6K) |
220 | @ We must avoid clrex due to Cortex-A15 erratum #830321 | 224 | @ We must avoid clrex due to Cortex-A15 erratum #830321 |
@@ -222,6 +226,20 @@ | |||
222 | strex r1, r2, [r0] @ clear the exclusive monitor | 226 | strex r1, r2, [r0] @ clear the exclusive monitor |
223 | #endif | 227 | #endif |
224 | ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr | 228 | ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr |
229 | #else | ||
230 | @ Thumb mode SVC restore | ||
231 | ldr lr, [sp, #S_SP] @ top of the stack | ||
232 | ldrd r0, r1, [sp, #S_LR] @ calling lr and pc | ||
233 | |||
234 | @ We must avoid clrex due to Cortex-A15 erratum #830321 | ||
235 | strex r2, r1, [sp, #S_LR] @ clear the exclusive monitor | ||
236 | |||
237 | stmdb lr!, {r0, r1, \rpsr} @ calling lr and rfe context | ||
238 | ldmia sp, {r0 - r12} | ||
239 | mov sp, lr | ||
240 | ldr lr, [sp], #4 | ||
241 | rfeia sp! | ||
242 | #endif | ||
225 | .endm | 243 | .endm |
226 | 244 | ||
227 | @ | 245 | @ |
@@ -241,6 +259,9 @@ | |||
241 | @ on the stack remains correct). | 259 | @ on the stack remains correct). |
242 | @ | 260 | @ |
243 | .macro svc_exit_via_fiq | 261 | .macro svc_exit_via_fiq |
262 | uaccess_restore | ||
263 | #ifndef CONFIG_THUMB2_KERNEL | ||
264 | @ ARM mode restore | ||
244 | mov r0, sp | 265 | mov r0, sp |
245 | ldmib r0, {r1 - r14} @ abort is deadly from here onward (it will | 266 | ldmib r0, {r1 - r14} @ abort is deadly from here onward (it will |
246 | @ clobber state restored below) | 267 | @ clobber state restored below) |
@@ -250,9 +271,27 @@ | |||
250 | msr spsr_cxsf, r9 | 271 | msr spsr_cxsf, r9 |
251 | ldr r0, [r0, #S_R0] | 272 | ldr r0, [r0, #S_R0] |
252 | ldmia r8, {pc}^ | 273 | ldmia r8, {pc}^ |
274 | #else | ||
275 | @ Thumb mode restore | ||
276 | add r0, sp, #S_R2 | ||
277 | ldr lr, [sp, #S_LR] | ||
278 | ldr sp, [sp, #S_SP] @ abort is deadly from here onward (it will | ||
279 | @ clobber state restored below) | ||
280 | ldmia r0, {r2 - r12} | ||
281 | mov r1, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT | ||
282 | msr cpsr_c, r1 | ||
283 | sub r0, #S_R2 | ||
284 | add r8, r0, #S_PC | ||
285 | ldmia r0, {r0 - r1} | ||
286 | rfeia r8 | ||
287 | #endif | ||
253 | .endm | 288 | .endm |
254 | 289 | ||
290 | |||
255 | .macro restore_user_regs, fast = 0, offset = 0 | 291 | .macro restore_user_regs, fast = 0, offset = 0 |
292 | uaccess_enable r1, isb=0 | ||
293 | #ifndef CONFIG_THUMB2_KERNEL | ||
294 | @ ARM mode restore | ||
256 | mov r2, sp | 295 | mov r2, sp |
257 | ldr r1, [r2, #\offset + S_PSR] @ get calling cpsr | 296 | ldr r1, [r2, #\offset + S_PSR] @ get calling cpsr |
258 | ldr lr, [r2, #\offset + S_PC]! @ get pc | 297 | ldr lr, [r2, #\offset + S_PC]! @ get pc |
@@ -270,72 +309,16 @@ | |||
270 | @ after ldm {}^ | 309 | @ after ldm {}^ |
271 | add sp, sp, #\offset + S_FRAME_SIZE | 310 | add sp, sp, #\offset + S_FRAME_SIZE |
272 | movs pc, lr @ return & move spsr_svc into cpsr | 311 | movs pc, lr @ return & move spsr_svc into cpsr |
273 | .endm | 312 | #elif defined(CONFIG_CPU_V7M) |
274 | 313 | @ V7M restore. | |
275 | #else /* CONFIG_THUMB2_KERNEL */ | 314 | @ Note that we don't need to do clrex here as clearing the local |
276 | .macro svc_exit, rpsr, irq = 0 | 315 | @ monitor is part of the exception entry and exit sequence. |
277 | .if \irq != 0 | ||
278 | @ IRQs already off | ||
279 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
280 | @ The parent context IRQs must have been enabled to get here in | ||
281 | @ the first place, so there's no point checking the PSR I bit. | ||
282 | bl trace_hardirqs_on | ||
283 | #endif | ||
284 | .else | ||
285 | @ IRQs off again before pulling preserved data off the stack | ||
286 | disable_irq_notrace | ||
287 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
288 | tst \rpsr, #PSR_I_BIT | ||
289 | bleq trace_hardirqs_on | ||
290 | tst \rpsr, #PSR_I_BIT | ||
291 | blne trace_hardirqs_off | ||
292 | #endif | ||
293 | .endif | ||
294 | ldr lr, [sp, #S_SP] @ top of the stack | ||
295 | ldrd r0, r1, [sp, #S_LR] @ calling lr and pc | ||
296 | |||
297 | @ We must avoid clrex due to Cortex-A15 erratum #830321 | ||
298 | strex r2, r1, [sp, #S_LR] @ clear the exclusive monitor | ||
299 | |||
300 | stmdb lr!, {r0, r1, \rpsr} @ calling lr and rfe context | ||
301 | ldmia sp, {r0 - r12} | ||
302 | mov sp, lr | ||
303 | ldr lr, [sp], #4 | ||
304 | rfeia sp! | ||
305 | .endm | ||
306 | |||
307 | @ | ||
308 | @ svc_exit_via_fiq - like svc_exit but switches to FIQ mode before exit | ||
309 | @ | ||
310 | @ For full details see non-Thumb implementation above. | ||
311 | @ | ||
312 | .macro svc_exit_via_fiq | ||
313 | add r0, sp, #S_R2 | ||
314 | ldr lr, [sp, #S_LR] | ||
315 | ldr sp, [sp, #S_SP] @ abort is deadly from here onward (it will | ||
316 | @ clobber state restored below) | ||
317 | ldmia r0, {r2 - r12} | ||
318 | mov r1, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT | ||
319 | msr cpsr_c, r1 | ||
320 | sub r0, #S_R2 | ||
321 | add r8, r0, #S_PC | ||
322 | ldmia r0, {r0 - r1} | ||
323 | rfeia r8 | ||
324 | .endm | ||
325 | |||
326 | #ifdef CONFIG_CPU_V7M | ||
327 | /* | ||
328 | * Note we don't need to do clrex here as clearing the local monitor is | ||
329 | * part of each exception entry and exit sequence. | ||
330 | */ | ||
331 | .macro restore_user_regs, fast = 0, offset = 0 | ||
332 | .if \offset | 316 | .if \offset |
333 | add sp, #\offset | 317 | add sp, #\offset |
334 | .endif | 318 | .endif |
335 | v7m_exception_slow_exit ret_r0 = \fast | 319 | v7m_exception_slow_exit ret_r0 = \fast |
336 | .endm | 320 | #else |
337 | #else /* ifdef CONFIG_CPU_V7M */ | 321 | @ Thumb mode restore |
338 | .macro restore_user_regs, fast = 0, offset = 0 | ||
339 | mov r2, sp | 322 | mov r2, sp |
340 | load_user_sp_lr r2, r3, \offset + S_SP @ calling sp, lr | 323 | load_user_sp_lr r2, r3, \offset + S_SP @ calling sp, lr |
341 | ldr r1, [sp, #\offset + S_PSR] @ get calling cpsr | 324 | ldr r1, [sp, #\offset + S_PSR] @ get calling cpsr |
@@ -353,9 +336,8 @@ | |||
353 | .endif | 336 | .endif |
354 | add sp, sp, #S_FRAME_SIZE - S_SP | 337 | add sp, sp, #S_FRAME_SIZE - S_SP |
355 | movs pc, lr @ return & move spsr_svc into cpsr | 338 | movs pc, lr @ return & move spsr_svc into cpsr |
356 | .endm | ||
357 | #endif /* ifdef CONFIG_CPU_V7M / else */ | ||
358 | #endif /* !CONFIG_THUMB2_KERNEL */ | 339 | #endif /* !CONFIG_THUMB2_KERNEL */ |
340 | .endm | ||
359 | 341 | ||
360 | /* | 342 | /* |
361 | * Context tracking subsystem. Used to instrument transitions | 343 | * Context tracking subsystem. Used to instrument transitions |
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 29e2991465cb..04286fd9e09c 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S | |||
@@ -464,10 +464,7 @@ __enable_mmu: | |||
464 | #ifdef CONFIG_ARM_LPAE | 464 | #ifdef CONFIG_ARM_LPAE |
465 | mcrr p15, 0, r4, r5, c2 @ load TTBR0 | 465 | mcrr p15, 0, r4, r5, c2 @ load TTBR0 |
466 | #else | 466 | #else |
467 | mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \ | 467 | mov r5, #DACR_INIT |
468 | domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \ | ||
469 | domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \ | ||
470 | domain_val(DOMAIN_IO, DOMAIN_CLIENT)) | ||
471 | mcr p15, 0, r5, c3, c0, 0 @ load domain access register | 468 | mcr p15, 0, r5, c3, c0, 0 @ load domain access register |
472 | mcr p15, 0, r4, c2, c0, 0 @ load page table pointer | 469 | mcr p15, 0, r4, c2, c0, 0 @ load page table pointer |
473 | #endif | 470 | #endif |
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index f192a2a41719..e550a4541f48 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c | |||
@@ -129,12 +129,36 @@ void __show_regs(struct pt_regs *regs) | |||
129 | buf[4] = '\0'; | 129 | buf[4] = '\0'; |
130 | 130 | ||
131 | #ifndef CONFIG_CPU_V7M | 131 | #ifndef CONFIG_CPU_V7M |
132 | printk("Flags: %s IRQs o%s FIQs o%s Mode %s ISA %s Segment %s\n", | 132 | { |
133 | buf, interrupts_enabled(regs) ? "n" : "ff", | 133 | unsigned int domain = get_domain(); |
134 | fast_interrupts_enabled(regs) ? "n" : "ff", | 134 | const char *segment; |
135 | processor_modes[processor_mode(regs)], | 135 | |
136 | isa_modes[isa_mode(regs)], | 136 | #ifdef CONFIG_CPU_SW_DOMAIN_PAN |
137 | get_fs() == get_ds() ? "kernel" : "user"); | 137 | /* |
138 | * Get the domain register for the parent context. In user | ||
139 | * mode, we don't save the DACR, so lets use what it should | ||
140 | * be. For other modes, we place it after the pt_regs struct. | ||
141 | */ | ||
142 | if (user_mode(regs)) | ||
143 | domain = DACR_UACCESS_ENABLE; | ||
144 | else | ||
145 | domain = *(unsigned int *)(regs + 1); | ||
146 | #endif | ||
147 | |||
148 | if ((domain & domain_mask(DOMAIN_USER)) == | ||
149 | domain_val(DOMAIN_USER, DOMAIN_NOACCESS)) | ||
150 | segment = "none"; | ||
151 | else if (get_fs() == get_ds()) | ||
152 | segment = "kernel"; | ||
153 | else | ||
154 | segment = "user"; | ||
155 | |||
156 | printk("Flags: %s IRQs o%s FIQs o%s Mode %s ISA %s Segment %s\n", | ||
157 | buf, interrupts_enabled(regs) ? "n" : "ff", | ||
158 | fast_interrupts_enabled(regs) ? "n" : "ff", | ||
159 | processor_modes[processor_mode(regs)], | ||
160 | isa_modes[isa_mode(regs)], segment); | ||
161 | } | ||
138 | #else | 162 | #else |
139 | printk("xPSR: %08lx\n", regs->ARM_cpsr); | 163 | printk("xPSR: %08lx\n", regs->ARM_cpsr); |
140 | #endif | 164 | #endif |
@@ -146,10 +170,9 @@ void __show_regs(struct pt_regs *regs) | |||
146 | buf[0] = '\0'; | 170 | buf[0] = '\0'; |
147 | #ifdef CONFIG_CPU_CP15_MMU | 171 | #ifdef CONFIG_CPU_CP15_MMU |
148 | { | 172 | { |
149 | unsigned int transbase, dac; | 173 | unsigned int transbase, dac = get_domain(); |
150 | asm("mrc p15, 0, %0, c2, c0\n\t" | 174 | asm("mrc p15, 0, %0, c2, c0\n\t" |
151 | "mrc p15, 0, %1, c3, c0\n" | 175 | : "=r" (transbase)); |
152 | : "=r" (transbase), "=r" (dac)); | ||
153 | snprintf(buf, sizeof(buf), " Table: %08x DAC: %08x", | 176 | snprintf(buf, sizeof(buf), " Table: %08x DAC: %08x", |
154 | transbase, dac); | 177 | transbase, dac); |
155 | } | 178 | } |
@@ -210,6 +233,16 @@ copy_thread(unsigned long clone_flags, unsigned long stack_start, | |||
210 | 233 | ||
211 | memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save)); | 234 | memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save)); |
212 | 235 | ||
236 | #ifdef CONFIG_CPU_USE_DOMAINS | ||
237 | /* | ||
238 | * Copy the initial value of the domain access control register | ||
239 | * from the current thread: thread->addr_limit will have been | ||
240 | * copied from the current thread via setup_thread_stack() in | ||
241 | * kernel/fork.c | ||
242 | */ | ||
243 | thread->cpu_domain = get_domain(); | ||
244 | #endif | ||
245 | |||
213 | if (likely(!(p->flags & PF_KTHREAD))) { | 246 | if (likely(!(p->flags & PF_KTHREAD))) { |
214 | *childregs = *current_pt_regs(); | 247 | *childregs = *current_pt_regs(); |
215 | childregs->ARM_r0 = 0; | 248 | childregs->ARM_r0 = 0; |
diff --git a/arch/arm/kernel/swp_emulate.c b/arch/arm/kernel/swp_emulate.c index 1361756782c7..5b26e7efa9ea 100644 --- a/arch/arm/kernel/swp_emulate.c +++ b/arch/arm/kernel/swp_emulate.c | |||
@@ -141,11 +141,14 @@ static int emulate_swpX(unsigned int address, unsigned int *data, | |||
141 | 141 | ||
142 | while (1) { | 142 | while (1) { |
143 | unsigned long temp; | 143 | unsigned long temp; |
144 | unsigned int __ua_flags; | ||
144 | 145 | ||
146 | __ua_flags = uaccess_save_and_enable(); | ||
145 | if (type == TYPE_SWPB) | 147 | if (type == TYPE_SWPB) |
146 | __user_swpb_asm(*data, address, res, temp); | 148 | __user_swpb_asm(*data, address, res, temp); |
147 | else | 149 | else |
148 | __user_swp_asm(*data, address, res, temp); | 150 | __user_swp_asm(*data, address, res, temp); |
151 | uaccess_restore(__ua_flags); | ||
149 | 152 | ||
150 | if (likely(res != -EAGAIN) || signal_pending(current)) | 153 | if (likely(res != -EAGAIN) || signal_pending(current)) |
151 | break; | 154 | break; |
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index d358226236f2..969f9d9e665f 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c | |||
@@ -870,7 +870,6 @@ void __init early_trap_init(void *vectors_base) | |||
870 | kuser_init(vectors_base); | 870 | kuser_init(vectors_base); |
871 | 871 | ||
872 | flush_icache_range(vectors, vectors + PAGE_SIZE * 2); | 872 | flush_icache_range(vectors, vectors + PAGE_SIZE * 2); |
873 | modify_domain(DOMAIN_USER, DOMAIN_CLIENT); | ||
874 | #else /* ifndef CONFIG_CPU_V7M */ | 873 | #else /* ifndef CONFIG_CPU_V7M */ |
875 | /* | 874 | /* |
876 | * on V7-M there is no need to copy the vector table to a dedicated | 875 | * on V7-M there is no need to copy the vector table to a dedicated |
diff --git a/arch/arm/lib/clear_user.S b/arch/arm/lib/clear_user.S index 1710fd7db2d5..970d6c043774 100644 --- a/arch/arm/lib/clear_user.S +++ b/arch/arm/lib/clear_user.S | |||
@@ -12,14 +12,14 @@ | |||
12 | 12 | ||
13 | .text | 13 | .text |
14 | 14 | ||
15 | /* Prototype: int __clear_user(void *addr, size_t sz) | 15 | /* Prototype: unsigned long arm_clear_user(void *addr, size_t sz) |
16 | * Purpose : clear some user memory | 16 | * Purpose : clear some user memory |
17 | * Params : addr - user memory address to clear | 17 | * Params : addr - user memory address to clear |
18 | * : sz - number of bytes to clear | 18 | * : sz - number of bytes to clear |
19 | * Returns : number of bytes NOT cleared | 19 | * Returns : number of bytes NOT cleared |
20 | */ | 20 | */ |
21 | ENTRY(__clear_user_std) | 21 | ENTRY(__clear_user_std) |
22 | WEAK(__clear_user) | 22 | WEAK(arm_clear_user) |
23 | stmfd sp!, {r1, lr} | 23 | stmfd sp!, {r1, lr} |
24 | mov r2, #0 | 24 | mov r2, #0 |
25 | cmp r1, #4 | 25 | cmp r1, #4 |
@@ -44,7 +44,7 @@ WEAK(__clear_user) | |||
44 | USER( strnebt r2, [r0]) | 44 | USER( strnebt r2, [r0]) |
45 | mov r0, #0 | 45 | mov r0, #0 |
46 | ldmfd sp!, {r1, pc} | 46 | ldmfd sp!, {r1, pc} |
47 | ENDPROC(__clear_user) | 47 | ENDPROC(arm_clear_user) |
48 | ENDPROC(__clear_user_std) | 48 | ENDPROC(__clear_user_std) |
49 | 49 | ||
50 | .pushsection .text.fixup,"ax" | 50 | .pushsection .text.fixup,"ax" |
diff --git a/arch/arm/lib/copy_from_user.S b/arch/arm/lib/copy_from_user.S index 7a235b9952be..1512bebfbf1b 100644 --- a/arch/arm/lib/copy_from_user.S +++ b/arch/arm/lib/copy_from_user.S | |||
@@ -17,7 +17,7 @@ | |||
17 | /* | 17 | /* |
18 | * Prototype: | 18 | * Prototype: |
19 | * | 19 | * |
20 | * size_t __copy_from_user(void *to, const void *from, size_t n) | 20 | * size_t arm_copy_from_user(void *to, const void *from, size_t n) |
21 | * | 21 | * |
22 | * Purpose: | 22 | * Purpose: |
23 | * | 23 | * |
@@ -89,11 +89,11 @@ | |||
89 | 89 | ||
90 | .text | 90 | .text |
91 | 91 | ||
92 | ENTRY(__copy_from_user) | 92 | ENTRY(arm_copy_from_user) |
93 | 93 | ||
94 | #include "copy_template.S" | 94 | #include "copy_template.S" |
95 | 95 | ||
96 | ENDPROC(__copy_from_user) | 96 | ENDPROC(arm_copy_from_user) |
97 | 97 | ||
98 | .pushsection .fixup,"ax" | 98 | .pushsection .fixup,"ax" |
99 | .align 0 | 99 | .align 0 |
diff --git a/arch/arm/lib/copy_to_user.S b/arch/arm/lib/copy_to_user.S index 9648b0675a3e..caf5019d8161 100644 --- a/arch/arm/lib/copy_to_user.S +++ b/arch/arm/lib/copy_to_user.S | |||
@@ -17,7 +17,7 @@ | |||
17 | /* | 17 | /* |
18 | * Prototype: | 18 | * Prototype: |
19 | * | 19 | * |
20 | * size_t __copy_to_user(void *to, const void *from, size_t n) | 20 | * size_t arm_copy_to_user(void *to, const void *from, size_t n) |
21 | * | 21 | * |
22 | * Purpose: | 22 | * Purpose: |
23 | * | 23 | * |
@@ -93,11 +93,11 @@ | |||
93 | .text | 93 | .text |
94 | 94 | ||
95 | ENTRY(__copy_to_user_std) | 95 | ENTRY(__copy_to_user_std) |
96 | WEAK(__copy_to_user) | 96 | WEAK(arm_copy_to_user) |
97 | 97 | ||
98 | #include "copy_template.S" | 98 | #include "copy_template.S" |
99 | 99 | ||
100 | ENDPROC(__copy_to_user) | 100 | ENDPROC(arm_copy_to_user) |
101 | ENDPROC(__copy_to_user_std) | 101 | ENDPROC(__copy_to_user_std) |
102 | 102 | ||
103 | .pushsection .text.fixup,"ax" | 103 | .pushsection .text.fixup,"ax" |
diff --git a/arch/arm/lib/csumpartialcopyuser.S b/arch/arm/lib/csumpartialcopyuser.S index 1d0957e61f89..1712f132b80d 100644 --- a/arch/arm/lib/csumpartialcopyuser.S +++ b/arch/arm/lib/csumpartialcopyuser.S | |||
@@ -17,6 +17,19 @@ | |||
17 | 17 | ||
18 | .text | 18 | .text |
19 | 19 | ||
20 | #ifdef CONFIG_CPU_SW_DOMAIN_PAN | ||
21 | .macro save_regs | ||
22 | mrc p15, 0, ip, c3, c0, 0 | ||
23 | stmfd sp!, {r1, r2, r4 - r8, ip, lr} | ||
24 | uaccess_enable ip | ||
25 | .endm | ||
26 | |||
27 | .macro load_regs | ||
28 | ldmfd sp!, {r1, r2, r4 - r8, ip, lr} | ||
29 | mcr p15, 0, ip, c3, c0, 0 | ||
30 | ret lr | ||
31 | .endm | ||
32 | #else | ||
20 | .macro save_regs | 33 | .macro save_regs |
21 | stmfd sp!, {r1, r2, r4 - r8, lr} | 34 | stmfd sp!, {r1, r2, r4 - r8, lr} |
22 | .endm | 35 | .endm |
@@ -24,6 +37,7 @@ | |||
24 | .macro load_regs | 37 | .macro load_regs |
25 | ldmfd sp!, {r1, r2, r4 - r8, pc} | 38 | ldmfd sp!, {r1, r2, r4 - r8, pc} |
26 | .endm | 39 | .endm |
40 | #endif | ||
27 | 41 | ||
28 | .macro load1b, reg1 | 42 | .macro load1b, reg1 |
29 | ldrusr \reg1, r0, 1 | 43 | ldrusr \reg1, r0, 1 |
diff --git a/arch/arm/lib/uaccess_with_memcpy.c b/arch/arm/lib/uaccess_with_memcpy.c index 4b39af2dfda9..d72b90905132 100644 --- a/arch/arm/lib/uaccess_with_memcpy.c +++ b/arch/arm/lib/uaccess_with_memcpy.c | |||
@@ -136,7 +136,7 @@ out: | |||
136 | } | 136 | } |
137 | 137 | ||
138 | unsigned long | 138 | unsigned long |
139 | __copy_to_user(void __user *to, const void *from, unsigned long n) | 139 | arm_copy_to_user(void __user *to, const void *from, unsigned long n) |
140 | { | 140 | { |
141 | /* | 141 | /* |
142 | * This test is stubbed out of the main function above to keep | 142 | * This test is stubbed out of the main function above to keep |
@@ -190,7 +190,7 @@ out: | |||
190 | return n; | 190 | return n; |
191 | } | 191 | } |
192 | 192 | ||
193 | unsigned long __clear_user(void __user *addr, unsigned long n) | 193 | unsigned long arm_clear_user(void __user *addr, unsigned long n) |
194 | { | 194 | { |
195 | /* See rational for this in __copy_to_user() above. */ | 195 | /* See rational for this in __copy_to_user() above. */ |
196 | if (n < 64) | 196 | if (n < 64) |
diff --git a/arch/arm/mm/abort-ev4.S b/arch/arm/mm/abort-ev4.S index 54473cd4aba9..b3b31e30cadd 100644 --- a/arch/arm/mm/abort-ev4.S +++ b/arch/arm/mm/abort-ev4.S | |||
@@ -19,6 +19,7 @@ ENTRY(v4_early_abort) | |||
19 | mrc p15, 0, r1, c5, c0, 0 @ get FSR | 19 | mrc p15, 0, r1, c5, c0, 0 @ get FSR |
20 | mrc p15, 0, r0, c6, c0, 0 @ get FAR | 20 | mrc p15, 0, r0, c6, c0, 0 @ get FAR |
21 | ldr r3, [r4] @ read aborted ARM instruction | 21 | ldr r3, [r4] @ read aborted ARM instruction |
22 | uaccess_disable ip @ disable userspace access | ||
22 | bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR | 23 | bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR |
23 | tst r3, #1 << 20 @ L = 1 -> write? | 24 | tst r3, #1 << 20 @ L = 1 -> write? |
24 | orreq r1, r1, #1 << 11 @ yes. | 25 | orreq r1, r1, #1 << 11 @ yes. |
diff --git a/arch/arm/mm/abort-ev5t.S b/arch/arm/mm/abort-ev5t.S index a0908d4653a3..a6a381a6caa5 100644 --- a/arch/arm/mm/abort-ev5t.S +++ b/arch/arm/mm/abort-ev5t.S | |||
@@ -21,8 +21,10 @@ ENTRY(v5t_early_abort) | |||
21 | mrc p15, 0, r0, c6, c0, 0 @ get FAR | 21 | mrc p15, 0, r0, c6, c0, 0 @ get FAR |
22 | do_thumb_abort fsr=r1, pc=r4, psr=r5, tmp=r3 | 22 | do_thumb_abort fsr=r1, pc=r4, psr=r5, tmp=r3 |
23 | ldreq r3, [r4] @ read aborted ARM instruction | 23 | ldreq r3, [r4] @ read aborted ARM instruction |
24 | uaccess_disable ip @ disable user access | ||
24 | bic r1, r1, #1 << 11 @ clear bits 11 of FSR | 25 | bic r1, r1, #1 << 11 @ clear bits 11 of FSR |
25 | do_ldrd_abort tmp=ip, insn=r3 | 26 | teq_ldrd tmp=ip, insn=r3 @ insn was LDRD? |
27 | beq do_DataAbort @ yes | ||
26 | tst r3, #1 << 20 @ check write | 28 | tst r3, #1 << 20 @ check write |
27 | orreq r1, r1, #1 << 11 | 29 | orreq r1, r1, #1 << 11 |
28 | b do_DataAbort | 30 | b do_DataAbort |
diff --git a/arch/arm/mm/abort-ev5tj.S b/arch/arm/mm/abort-ev5tj.S index 4006b7a61264..00ab011bef58 100644 --- a/arch/arm/mm/abort-ev5tj.S +++ b/arch/arm/mm/abort-ev5tj.S | |||
@@ -24,7 +24,9 @@ ENTRY(v5tj_early_abort) | |||
24 | bne do_DataAbort | 24 | bne do_DataAbort |
25 | do_thumb_abort fsr=r1, pc=r4, psr=r5, tmp=r3 | 25 | do_thumb_abort fsr=r1, pc=r4, psr=r5, tmp=r3 |
26 | ldreq r3, [r4] @ read aborted ARM instruction | 26 | ldreq r3, [r4] @ read aborted ARM instruction |
27 | do_ldrd_abort tmp=ip, insn=r3 | 27 | uaccess_disable ip @ disable userspace access |
28 | teq_ldrd tmp=ip, insn=r3 @ insn was LDRD? | ||
29 | beq do_DataAbort @ yes | ||
28 | tst r3, #1 << 20 @ L = 0 -> write | 30 | tst r3, #1 << 20 @ L = 0 -> write |
29 | orreq r1, r1, #1 << 11 @ yes. | 31 | orreq r1, r1, #1 << 11 @ yes. |
30 | b do_DataAbort | 32 | b do_DataAbort |
diff --git a/arch/arm/mm/abort-ev6.S b/arch/arm/mm/abort-ev6.S index 8c48c5c22a33..8801a15aa105 100644 --- a/arch/arm/mm/abort-ev6.S +++ b/arch/arm/mm/abort-ev6.S | |||
@@ -26,16 +26,18 @@ ENTRY(v6_early_abort) | |||
26 | ldr ip, =0x4107b36 | 26 | ldr ip, =0x4107b36 |
27 | mrc p15, 0, r3, c0, c0, 0 @ get processor id | 27 | mrc p15, 0, r3, c0, c0, 0 @ get processor id |
28 | teq ip, r3, lsr #4 @ r0 ARM1136? | 28 | teq ip, r3, lsr #4 @ r0 ARM1136? |
29 | bne do_DataAbort | 29 | bne 1f |
30 | tst r5, #PSR_J_BIT @ Java? | 30 | tst r5, #PSR_J_BIT @ Java? |
31 | tsteq r5, #PSR_T_BIT @ Thumb? | 31 | tsteq r5, #PSR_T_BIT @ Thumb? |
32 | bne do_DataAbort | 32 | bne 1f |
33 | bic r1, r1, #1 << 11 @ clear bit 11 of FSR | 33 | bic r1, r1, #1 << 11 @ clear bit 11 of FSR |
34 | ldr r3, [r4] @ read aborted ARM instruction | 34 | ldr r3, [r4] @ read aborted ARM instruction |
35 | ARM_BE8(rev r3, r3) | 35 | ARM_BE8(rev r3, r3) |
36 | 36 | ||
37 | do_ldrd_abort tmp=ip, insn=r3 | 37 | teq_ldrd tmp=ip, insn=r3 @ insn was LDRD? |
38 | beq 1f @ yes | ||
38 | tst r3, #1 << 20 @ L = 0 -> write | 39 | tst r3, #1 << 20 @ L = 0 -> write |
39 | orreq r1, r1, #1 << 11 @ yes. | 40 | orreq r1, r1, #1 << 11 @ yes. |
40 | #endif | 41 | #endif |
42 | 1: uaccess_disable ip @ disable userspace access | ||
41 | b do_DataAbort | 43 | b do_DataAbort |
diff --git a/arch/arm/mm/abort-ev7.S b/arch/arm/mm/abort-ev7.S index 4812ad054214..e8d0e08c227f 100644 --- a/arch/arm/mm/abort-ev7.S +++ b/arch/arm/mm/abort-ev7.S | |||
@@ -15,6 +15,7 @@ | |||
15 | ENTRY(v7_early_abort) | 15 | ENTRY(v7_early_abort) |
16 | mrc p15, 0, r1, c5, c0, 0 @ get FSR | 16 | mrc p15, 0, r1, c5, c0, 0 @ get FSR |
17 | mrc p15, 0, r0, c6, c0, 0 @ get FAR | 17 | mrc p15, 0, r0, c6, c0, 0 @ get FAR |
18 | uaccess_disable ip @ disable userspace access | ||
18 | 19 | ||
19 | /* | 20 | /* |
20 | * V6 code adjusts the returned DFSR. | 21 | * V6 code adjusts the returned DFSR. |
diff --git a/arch/arm/mm/abort-lv4t.S b/arch/arm/mm/abort-lv4t.S index f3982580c273..6d8e8e3365d1 100644 --- a/arch/arm/mm/abort-lv4t.S +++ b/arch/arm/mm/abort-lv4t.S | |||
@@ -26,6 +26,7 @@ ENTRY(v4t_late_abort) | |||
26 | #endif | 26 | #endif |
27 | bne .data_thumb_abort | 27 | bne .data_thumb_abort |
28 | ldr r8, [r4] @ read arm instruction | 28 | ldr r8, [r4] @ read arm instruction |
29 | uaccess_disable ip @ disable userspace access | ||
29 | tst r8, #1 << 20 @ L = 1 -> write? | 30 | tst r8, #1 << 20 @ L = 1 -> write? |
30 | orreq r1, r1, #1 << 11 @ yes. | 31 | orreq r1, r1, #1 << 11 @ yes. |
31 | and r7, r8, #15 << 24 | 32 | and r7, r8, #15 << 24 |
@@ -155,6 +156,7 @@ ENTRY(v4t_late_abort) | |||
155 | 156 | ||
156 | .data_thumb_abort: | 157 | .data_thumb_abort: |
157 | ldrh r8, [r4] @ read instruction | 158 | ldrh r8, [r4] @ read instruction |
159 | uaccess_disable ip @ disable userspace access | ||
158 | tst r8, #1 << 11 @ L = 1 -> write? | 160 | tst r8, #1 << 11 @ L = 1 -> write? |
159 | orreq r1, r1, #1 << 8 @ yes | 161 | orreq r1, r1, #1 << 8 @ yes |
160 | and r7, r8, #15 << 12 | 162 | and r7, r8, #15 << 12 |
diff --git a/arch/arm/mm/abort-macro.S b/arch/arm/mm/abort-macro.S index 2cbf68ef0e83..4509bee4e081 100644 --- a/arch/arm/mm/abort-macro.S +++ b/arch/arm/mm/abort-macro.S | |||
@@ -13,6 +13,7 @@ | |||
13 | tst \psr, #PSR_T_BIT | 13 | tst \psr, #PSR_T_BIT |
14 | beq not_thumb | 14 | beq not_thumb |
15 | ldrh \tmp, [\pc] @ Read aborted Thumb instruction | 15 | ldrh \tmp, [\pc] @ Read aborted Thumb instruction |
16 | uaccess_disable ip @ disable userspace access | ||
16 | and \tmp, \tmp, # 0xfe00 @ Mask opcode field | 17 | and \tmp, \tmp, # 0xfe00 @ Mask opcode field |
17 | cmp \tmp, # 0x5600 @ Is it ldrsb? | 18 | cmp \tmp, # 0x5600 @ Is it ldrsb? |
18 | orreq \tmp, \tmp, #1 << 11 @ Set L-bit if yes | 19 | orreq \tmp, \tmp, #1 << 11 @ Set L-bit if yes |
@@ -29,12 +30,9 @@ not_thumb: | |||
29 | * [7:4] == 1101 | 30 | * [7:4] == 1101 |
30 | * [20] == 0 | 31 | * [20] == 0 |
31 | */ | 32 | */ |
32 | .macro do_ldrd_abort, tmp, insn | 33 | .macro teq_ldrd, tmp, insn |
33 | tst \insn, #0x0e100000 @ [27:25,20] == 0 | 34 | mov \tmp, #0x0e100000 |
34 | bne not_ldrd | 35 | orr \tmp, #0x000000f0 |
35 | and \tmp, \insn, #0x000000f0 @ [7:4] == 1101 | 36 | and \tmp, \insn, \tmp |
36 | cmp \tmp, #0x000000d0 | 37 | teq \tmp, #0x000000d0 |
37 | beq do_DataAbort | ||
38 | not_ldrd: | ||
39 | .endm | 38 | .endm |
40 | |||
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 870838a46d52..1cb9c1c1c05f 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c | |||
@@ -291,13 +291,13 @@ static struct mem_type mem_types[] = { | |||
291 | .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | | 291 | .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | |
292 | L_PTE_RDONLY, | 292 | L_PTE_RDONLY, |
293 | .prot_l1 = PMD_TYPE_TABLE, | 293 | .prot_l1 = PMD_TYPE_TABLE, |
294 | .domain = DOMAIN_USER, | 294 | .domain = DOMAIN_VECTORS, |
295 | }, | 295 | }, |
296 | [MT_HIGH_VECTORS] = { | 296 | [MT_HIGH_VECTORS] = { |
297 | .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | | 297 | .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | |
298 | L_PTE_USER | L_PTE_RDONLY, | 298 | L_PTE_USER | L_PTE_RDONLY, |
299 | .prot_l1 = PMD_TYPE_TABLE, | 299 | .prot_l1 = PMD_TYPE_TABLE, |
300 | .domain = DOMAIN_USER, | 300 | .domain = DOMAIN_VECTORS, |
301 | }, | 301 | }, |
302 | [MT_MEMORY_RWX] = { | 302 | [MT_MEMORY_RWX] = { |
303 | .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY, | 303 | .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY, |
diff --git a/arch/arm/mm/pgd.c b/arch/arm/mm/pgd.c index a3681f11dd9f..e683db1b90a3 100644 --- a/arch/arm/mm/pgd.c +++ b/arch/arm/mm/pgd.c | |||
@@ -84,6 +84,16 @@ pgd_t *pgd_alloc(struct mm_struct *mm) | |||
84 | if (!new_pte) | 84 | if (!new_pte) |
85 | goto no_pte; | 85 | goto no_pte; |
86 | 86 | ||
87 | #ifndef CONFIG_ARM_LPAE | ||
88 | /* | ||
89 | * Modify the PTE pointer to have the correct domain. This | ||
90 | * needs to be the vectors domain to avoid the low vectors | ||
91 | * being unmapped. | ||
92 | */ | ||
93 | pmd_val(*new_pmd) &= ~PMD_DOMAIN_MASK; | ||
94 | pmd_val(*new_pmd) |= PMD_DOMAIN(DOMAIN_VECTORS); | ||
95 | #endif | ||
96 | |||
87 | init_pud = pud_offset(init_pgd, 0); | 97 | init_pud = pud_offset(init_pgd, 0); |
88 | init_pmd = pmd_offset(init_pud, 0); | 98 | init_pmd = pmd_offset(init_pud, 0); |
89 | init_pte = pte_offset_map(init_pmd, 0); | 99 | init_pte = pte_offset_map(init_pmd, 0); |
diff --git a/arch/arm/nwfpe/entry.S b/arch/arm/nwfpe/entry.S index 71df43547659..39c20afad7ed 100644 --- a/arch/arm/nwfpe/entry.S +++ b/arch/arm/nwfpe/entry.S | |||
@@ -95,9 +95,10 @@ emulate: | |||
95 | reteq r4 @ no, return failure | 95 | reteq r4 @ no, return failure |
96 | 96 | ||
97 | next: | 97 | next: |
98 | uaccess_enable r3 | ||
98 | .Lx1: ldrt r6, [r5], #4 @ get the next instruction and | 99 | .Lx1: ldrt r6, [r5], #4 @ get the next instruction and |
99 | @ increment PC | 100 | @ increment PC |
100 | 101 | uaccess_disable r3 | |
101 | and r2, r6, #0x0F000000 @ test for FP insns | 102 | and r2, r6, #0x0F000000 @ test for FP insns |
102 | teq r2, #0x0C000000 | 103 | teq r2, #0x0C000000 |
103 | teqne r2, #0x0D000000 | 104 | teqne r2, #0x0D000000 |
diff --git a/arch/arm/xen/hypercall.S b/arch/arm/xen/hypercall.S index f00e08075938..10fd99c568c6 100644 --- a/arch/arm/xen/hypercall.S +++ b/arch/arm/xen/hypercall.S | |||
@@ -98,8 +98,23 @@ ENTRY(privcmd_call) | |||
98 | mov r1, r2 | 98 | mov r1, r2 |
99 | mov r2, r3 | 99 | mov r2, r3 |
100 | ldr r3, [sp, #8] | 100 | ldr r3, [sp, #8] |
101 | /* | ||
102 | * Privcmd calls are issued by the userspace. We need to allow the | ||
103 | * kernel to access the userspace memory before issuing the hypercall. | ||
104 | */ | ||
105 | uaccess_enable r4 | ||
106 | |||
107 | /* r4 is loaded now as we use it as scratch register before */ | ||
101 | ldr r4, [sp, #4] | 108 | ldr r4, [sp, #4] |
102 | __HVC(XEN_IMM) | 109 | __HVC(XEN_IMM) |
110 | |||
111 | /* | ||
112 | * Disable userspace access from kernel. This is fine to do it | ||
113 | * unconditionally as no set_fs(KERNEL_DS)/set_fs(get_ds()) is | ||
114 | * called before. | ||
115 | */ | ||
116 | uaccess_disable r4 | ||
117 | |||
103 | ldm sp!, {r4} | 118 | ldm sp!, {r4} |
104 | ret lr | 119 | ret lr |
105 | ENDPROC(privcmd_call); | 120 | ENDPROC(privcmd_call); |