Skip to content

Commit 8111e67

Browse files
mrutland-armkees
authored andcommitted
stackleak: add on/off stack variants
The stackleak_erase() code dynamically handles being on a task stack or another stack. In most cases, this is a fixed property of the caller, which the caller is aware of, as an architecture might always return using the task stack, or might always return using a trampoline stack. This patch adds stackleak_erase_on_task_stack() and stackleak_erase_off_task_stack() functions which callers can use to avoid on_thread_stack() check and associated redundant work when the calling stack is known. The existing stackleak_erase() is retained as a safe default. There should be no functional change as a result of this patch. Signed-off-by: Mark Rutland <[email protected]> Cc: Alexander Popov <[email protected]> Cc: Andrew Morton <[email protected]> Cc: Andy Lutomirski <[email protected]> Cc: Kees Cook <[email protected]> Signed-off-by: Kees Cook <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent f171d69 commit 8111e67

File tree

1 file changed

+32
-3
lines changed

1 file changed

+32
-3
lines changed

kernel/stackleak.c

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ late_initcall(stackleak_sysctls_init);
7070
#define skip_erasing() false
7171
#endif /* CONFIG_STACKLEAK_RUNTIME_DISABLE */
7272

73-
static __always_inline void __stackleak_erase(void)
73+
static __always_inline void __stackleak_erase(bool on_task_stack)
7474
{
7575
const unsigned long task_stack_low = stackleak_task_low_bound(current);
7676
const unsigned long task_stack_high = stackleak_task_high_bound(current);
@@ -96,7 +96,7 @@ static __always_inline void __stackleak_erase(void)
9696
* function has a fixed-size stack frame, and the current stack pointer
9797
* doesn't change while we write poison.
9898
*/
99-
if (on_thread_stack())
99+
if (on_task_stack)
100100
erase_high = current_stack_pointer;
101101
else
102102
erase_high = task_stack_high;
@@ -110,12 +110,41 @@ static __always_inline void __stackleak_erase(void)
110110
current->lowest_stack = task_stack_high;
111111
}
112112

113+
/*
114+
* Erase and poison the portion of the task stack used since the last erase.
115+
* Can be called from the task stack or an entry stack when the task stack is
116+
* no longer in use.
117+
*/
113118
asmlinkage void noinstr stackleak_erase(void)
114119
{
115120
if (skip_erasing())
116121
return;
117122

118-
__stackleak_erase();
123+
__stackleak_erase(on_thread_stack());
124+
}
125+
126+
/*
127+
* Erase and poison the portion of the task stack used since the last erase.
128+
* Can only be called from the task stack.
129+
*/
130+
asmlinkage void noinstr stackleak_erase_on_task_stack(void)
131+
{
132+
if (skip_erasing())
133+
return;
134+
135+
__stackleak_erase(true);
136+
}
137+
138+
/*
139+
* Erase and poison the portion of the task stack used since the last erase.
140+
* Can only be called from a stack other than the task stack.
141+
*/
142+
asmlinkage void noinstr stackleak_erase_off_task_stack(void)
143+
{
144+
if (skip_erasing())
145+
return;
146+
147+
__stackleak_erase(false);
119148
}
120149

121150
void __used __no_caller_saved_registers noinstr stackleak_track_stack(void)

0 commit comments

Comments
 (0)