diff options
-rw-r--r-- | arch/arm64/kernel/sleep.S | 2 | ||||
-rw-r--r-- | arch/x86/kernel/kprobes/core.c | 4 | ||||
-rw-r--r-- | include/linux/kasan.h | 2 | ||||
-rw-r--r-- | mm/kasan/kasan.c | 22 |
4 files changed, 26 insertions, 4 deletions
diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S index b8799e7c79de..1bec41b5fda3 100644 --- a/arch/arm64/kernel/sleep.S +++ b/arch/arm64/kernel/sleep.S | |||
@@ -135,7 +135,7 @@ ENTRY(_cpu_resume) | |||
135 | 135 | ||
136 | #ifdef CONFIG_KASAN | 136 | #ifdef CONFIG_KASAN |
137 | mov x0, sp | 137 | mov x0, sp |
138 | bl kasan_unpoison_remaining_stack | 138 | bl kasan_unpoison_task_stack_below |
139 | #endif | 139 | #endif |
140 | 140 | ||
141 | ldp x19, x20, [x29, #16] | 141 | ldp x19, x20, [x29, #16] |
diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index f423b0ef23a7..d9d8d16b69db 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c | |||
@@ -50,6 +50,7 @@ | |||
50 | #include <linux/kallsyms.h> | 50 | #include <linux/kallsyms.h> |
51 | #include <linux/ftrace.h> | 51 | #include <linux/ftrace.h> |
52 | #include <linux/frame.h> | 52 | #include <linux/frame.h> |
53 | #include <linux/kasan.h> | ||
53 | 54 | ||
54 | #include <asm/text-patching.h> | 55 | #include <asm/text-patching.h> |
55 | #include <asm/cacheflush.h> | 56 | #include <asm/cacheflush.h> |
@@ -1081,6 +1082,9 @@ void jprobe_return(void) | |||
1081 | { | 1082 | { |
1082 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | 1083 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
1083 | 1084 | ||
1085 | /* Unpoison stack redzones in the frames we are going to jump over. */ | ||
1086 | kasan_unpoison_stack_above_sp_to(kcb->jprobe_saved_sp); | ||
1087 | |||
1084 | asm volatile ( | 1088 | asm volatile ( |
1085 | #ifdef CONFIG_X86_64 | 1089 | #ifdef CONFIG_X86_64 |
1086 | " xchg %%rbx,%%rsp \n" | 1090 | " xchg %%rbx,%%rsp \n" |
diff --git a/include/linux/kasan.h b/include/linux/kasan.h index d600303306eb..820c0ad54a01 100644 --- a/include/linux/kasan.h +++ b/include/linux/kasan.h | |||
@@ -44,6 +44,7 @@ static inline void kasan_disable_current(void) | |||
44 | void kasan_unpoison_shadow(const void *address, size_t size); | 44 | void kasan_unpoison_shadow(const void *address, size_t size); |
45 | 45 | ||
46 | void kasan_unpoison_task_stack(struct task_struct *task); | 46 | void kasan_unpoison_task_stack(struct task_struct *task); |
47 | void kasan_unpoison_stack_above_sp_to(const void *watermark); | ||
47 | 48 | ||
48 | void kasan_alloc_pages(struct page *page, unsigned int order); | 49 | void kasan_alloc_pages(struct page *page, unsigned int order); |
49 | void kasan_free_pages(struct page *page, unsigned int order); | 50 | void kasan_free_pages(struct page *page, unsigned int order); |
@@ -85,6 +86,7 @@ size_t kasan_metadata_size(struct kmem_cache *cache); | |||
85 | static inline void kasan_unpoison_shadow(const void *address, size_t size) {} | 86 | static inline void kasan_unpoison_shadow(const void *address, size_t size) {} |
86 | 87 | ||
87 | static inline void kasan_unpoison_task_stack(struct task_struct *task) {} | 88 | static inline void kasan_unpoison_task_stack(struct task_struct *task) {} |
89 | static inline void kasan_unpoison_stack_above_sp_to(const void *watermark) {} | ||
88 | 90 | ||
89 | static inline void kasan_enable_current(void) {} | 91 | static inline void kasan_enable_current(void) {} |
90 | static inline void kasan_disable_current(void) {} | 92 | static inline void kasan_disable_current(void) {} |
diff --git a/mm/kasan/kasan.c b/mm/kasan/kasan.c index 88af13c00d3c..70c009741aab 100644 --- a/mm/kasan/kasan.c +++ b/mm/kasan/kasan.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/string.h> | 34 | #include <linux/string.h> |
35 | #include <linux/types.h> | 35 | #include <linux/types.h> |
36 | #include <linux/vmalloc.h> | 36 | #include <linux/vmalloc.h> |
37 | #include <linux/bug.h> | ||
37 | 38 | ||
38 | #include "kasan.h" | 39 | #include "kasan.h" |
39 | #include "../slab.h" | 40 | #include "../slab.h" |
@@ -62,7 +63,7 @@ void kasan_unpoison_shadow(const void *address, size_t size) | |||
62 | } | 63 | } |
63 | } | 64 | } |
64 | 65 | ||
65 | static void __kasan_unpoison_stack(struct task_struct *task, void *sp) | 66 | static void __kasan_unpoison_stack(struct task_struct *task, const void *sp) |
66 | { | 67 | { |
67 | void *base = task_stack_page(task); | 68 | void *base = task_stack_page(task); |
68 | size_t size = sp - base; | 69 | size_t size = sp - base; |
@@ -77,9 +78,24 @@ void kasan_unpoison_task_stack(struct task_struct *task) | |||
77 | } | 78 | } |
78 | 79 | ||
79 | /* Unpoison the stack for the current task beyond a watermark sp value. */ | 80 | /* Unpoison the stack for the current task beyond a watermark sp value. */ |
80 | asmlinkage void kasan_unpoison_remaining_stack(void *sp) | 81 | asmlinkage void kasan_unpoison_task_stack_below(const void *watermark) |
81 | { | 82 | { |
82 | __kasan_unpoison_stack(current, sp); | 83 | __kasan_unpoison_stack(current, watermark); |
84 | } | ||
85 | |||
86 | /* | ||
87 | * Clear all poison for the region between the current SP and a provided | ||
88 | * watermark value, as is sometimes required prior to hand-crafted asm function | ||
89 | * returns in the middle of functions. | ||
90 | */ | ||
91 | void kasan_unpoison_stack_above_sp_to(const void *watermark) | ||
92 | { | ||
93 | const void *sp = __builtin_frame_address(0); | ||
94 | size_t size = watermark - sp; | ||
95 | |||
96 | if (WARN_ON(sp > watermark)) | ||
97 | return; | ||
98 | kasan_unpoison_shadow(sp, size); | ||
83 | } | 99 | } |
84 | 100 | ||
85 | /* | 101 | /* |