aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm64/kernel/sleep.S2
-rw-r--r--arch/x86/kernel/kprobes/core.c4
-rw-r--r--include/linux/kasan.h2
-rw-r--r--mm/kasan/kasan.c22
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)
44void kasan_unpoison_shadow(const void *address, size_t size); 44void kasan_unpoison_shadow(const void *address, size_t size);
45 45
46void kasan_unpoison_task_stack(struct task_struct *task); 46void kasan_unpoison_task_stack(struct task_struct *task);
47void kasan_unpoison_stack_above_sp_to(const void *watermark);
47 48
48void kasan_alloc_pages(struct page *page, unsigned int order); 49void kasan_alloc_pages(struct page *page, unsigned int order);
49void kasan_free_pages(struct page *page, unsigned int order); 50void kasan_free_pages(struct page *page, unsigned int order);
@@ -85,6 +86,7 @@ size_t kasan_metadata_size(struct kmem_cache *cache);
85static inline void kasan_unpoison_shadow(const void *address, size_t size) {} 86static inline void kasan_unpoison_shadow(const void *address, size_t size) {}
86 87
87static inline void kasan_unpoison_task_stack(struct task_struct *task) {} 88static inline void kasan_unpoison_task_stack(struct task_struct *task) {}
89static inline void kasan_unpoison_stack_above_sp_to(const void *watermark) {}
88 90
89static inline void kasan_enable_current(void) {} 91static inline void kasan_enable_current(void) {}
90static inline void kasan_disable_current(void) {} 92static 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
65static void __kasan_unpoison_stack(struct task_struct *task, void *sp) 66static 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. */
80asmlinkage void kasan_unpoison_remaining_stack(void *sp) 81asmlinkage 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 */
91void 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/*