forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
scs: Add support for Clang's Shadow Call Stack (SCS)
This change adds generic support for Clang's Shadow Call Stack, which uses a shadow stack to protect return addresses from being overwritten by an attacker. Details are available here: https://clang.llvm.org/docs/ShadowCallStack.html Note that security guarantees in the kernel differ from the ones documented for user space. The kernel must store addresses of shadow stacks in memory, which means an attacker capable reading and writing arbitrary memory may be able to locate them and hijack control flow by modifying the stacks. Signed-off-by: Sami Tolvanen <[email protected]> Reviewed-by: Kees Cook <[email protected]> Reviewed-by: Miguel Ojeda <[email protected]> [will: Numerous cosmetic changes] Signed-off-by: Will Deacon <[email protected]>
- Loading branch information
1 parent
6a8b55e
commit d08b9f0
Showing
10 changed files
with
191 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
/* SPDX-License-Identifier: GPL-2.0 */ | ||
/* | ||
* Shadow Call Stack support. | ||
* | ||
* Copyright (C) 2019 Google LLC | ||
*/ | ||
|
||
#ifndef _LINUX_SCS_H | ||
#define _LINUX_SCS_H | ||
|
||
#include <linux/gfp.h> | ||
#include <linux/poison.h> | ||
#include <linux/sched.h> | ||
#include <linux/sizes.h> | ||
|
||
#ifdef CONFIG_SHADOW_CALL_STACK | ||
|
||
/* | ||
* In testing, 1 KiB shadow stack size (i.e. 128 stack frames on a 64-bit | ||
* architecture) provided ~40% safety margin on stack usage while keeping | ||
* memory allocation overhead reasonable. | ||
*/ | ||
#define SCS_SIZE SZ_1K | ||
#define GFP_SCS (GFP_KERNEL | __GFP_ZERO) | ||
|
||
/* An illegal pointer value to mark the end of the shadow stack. */ | ||
#define SCS_END_MAGIC (0x5f6UL + POISON_POINTER_DELTA) | ||
|
||
#define task_scs(tsk) (task_thread_info(tsk)->scs_base) | ||
#define task_scs_offset(tsk) (task_thread_info(tsk)->scs_offset) | ||
|
||
void scs_init(void); | ||
int scs_prepare(struct task_struct *tsk, int node); | ||
void scs_release(struct task_struct *tsk); | ||
|
||
static inline void scs_task_reset(struct task_struct *tsk) | ||
{ | ||
/* | ||
* Reset the shadow stack to the base address in case the task | ||
* is reused. | ||
*/ | ||
task_scs_offset(tsk) = 0; | ||
} | ||
|
||
static inline unsigned long *__scs_magic(void *s) | ||
{ | ||
return (unsigned long *)(s + SCS_SIZE) - 1; | ||
} | ||
|
||
static inline bool scs_corrupted(struct task_struct *tsk) | ||
{ | ||
unsigned long *magic = __scs_magic(task_scs(tsk)); | ||
|
||
return (task_scs_offset(tsk) >= SCS_SIZE - 1 || | ||
READ_ONCE_NOCHECK(*magic) != SCS_END_MAGIC); | ||
} | ||
|
||
#else /* CONFIG_SHADOW_CALL_STACK */ | ||
|
||
static inline void scs_init(void) {} | ||
static inline void scs_task_reset(struct task_struct *tsk) {} | ||
static inline int scs_prepare(struct task_struct *tsk, int node) { return 0; } | ||
static inline bool scs_corrupted(struct task_struct *tsk) { return false; } | ||
static inline void scs_release(struct task_struct *tsk) {} | ||
|
||
#endif /* CONFIG_SHADOW_CALL_STACK */ | ||
|
||
#endif /* _LINUX_SCS_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* | ||
* Shadow Call Stack support. | ||
* | ||
* Copyright (C) 2019 Google LLC | ||
*/ | ||
|
||
#include <linux/kasan.h> | ||
#include <linux/scs.h> | ||
#include <linux/slab.h> | ||
#include <asm/scs.h> | ||
|
||
static struct kmem_cache *scs_cache; | ||
|
||
static void *scs_alloc(int node) | ||
{ | ||
void *s; | ||
|
||
s = kmem_cache_alloc_node(scs_cache, GFP_SCS, node); | ||
if (s) { | ||
*__scs_magic(s) = SCS_END_MAGIC; | ||
/* | ||
* Poison the allocation to catch unintentional accesses to | ||
* the shadow stack when KASAN is enabled. | ||
*/ | ||
kasan_poison_object_data(scs_cache, s); | ||
} | ||
|
||
return s; | ||
} | ||
|
||
static void scs_free(void *s) | ||
{ | ||
kasan_unpoison_object_data(scs_cache, s); | ||
kmem_cache_free(scs_cache, s); | ||
} | ||
|
||
void __init scs_init(void) | ||
{ | ||
scs_cache = kmem_cache_create("scs_cache", SCS_SIZE, 0, 0, NULL); | ||
} | ||
|
||
int scs_prepare(struct task_struct *tsk, int node) | ||
{ | ||
void *s = scs_alloc(node); | ||
|
||
if (!s) | ||
return -ENOMEM; | ||
|
||
task_scs(tsk) = s; | ||
task_scs_offset(tsk) = 0; | ||
|
||
return 0; | ||
} | ||
|
||
void scs_release(struct task_struct *tsk) | ||
{ | ||
void *s = task_scs(tsk); | ||
|
||
if (!s) | ||
return; | ||
|
||
WARN(scs_corrupted(tsk), "corrupted shadow stack detected when freeing task\n"); | ||
scs_free(s); | ||
} |