123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Shadow Call Stack support.
- *
- * Copyright (C) 2019 Google LLC
- */
- #include <linux/cpuhotplug.h>
- #include <linux/kasan.h>
- #include <linux/mm.h>
- #include <linux/mmzone.h>
- #include <linux/scs.h>
- #include <linux/slab.h>
- #include <linux/vmalloc.h>
- #include <linux/vmstat.h>
- #include <asm/scs.h>
- static inline void *__scs_base(struct task_struct *tsk)
- {
- /*
- * To minimize risk the of exposure, architectures may clear a
- * task's thread_info::shadow_call_stack while that task is
- * running, and only save/restore the active shadow call stack
- * pointer when the usual register may be clobbered (e.g. across
- * context switches).
- *
- * The shadow call stack is aligned to SCS_SIZE, and grows
- * upwards, so we can mask out the low bits to extract the base
- * when the task is not running.
- */
- return (void *)((unsigned long)task_scs(tsk) & ~(SCS_SIZE - 1));
- }
- static inline unsigned long *scs_magic(void *s)
- {
- return (unsigned long *)(s + SCS_SIZE) - 1;
- }
- static inline void scs_set_magic(void *s)
- {
- *scs_magic(s) = SCS_END_MAGIC;
- }
- #ifdef CONFIG_SHADOW_CALL_STACK_VMAP
- /* Matches NR_CACHED_STACKS for VMAP_STACK */
- #define NR_CACHED_SCS 2
- static DEFINE_PER_CPU(void *, scs_cache[NR_CACHED_SCS]);
- static void *scs_alloc(int node)
- {
- int i;
- void *s;
- for (i = 0; i < NR_CACHED_SCS; i++) {
- s = this_cpu_xchg(scs_cache[i], NULL);
- if (s) {
- memset(s, 0, SCS_SIZE);
- goto out;
- }
- }
- /*
- * We allocate a full page for the shadow stack, which should be
- * more than we need. Check the assumption nevertheless.
- */
- BUILD_BUG_ON(SCS_SIZE > PAGE_SIZE);
- s = __vmalloc_node_range(PAGE_SIZE, SCS_SIZE,
- VMALLOC_START, VMALLOC_END,
- GFP_SCS, PAGE_KERNEL, 0,
- node, __builtin_return_address(0));
- out:
- if (s)
- scs_set_magic(s);
- /* TODO: poison for KASAN, unpoison in scs_free */
- return s;
- }
- static void scs_free(void *s)
- {
- int i;
- for (i = 0; i < NR_CACHED_SCS; i++)
- if (this_cpu_cmpxchg(scs_cache[i], 0, s) == NULL)
- return;
- vfree_atomic(s);
- }
- static struct page *__scs_page(struct task_struct *tsk)
- {
- return vmalloc_to_page(__scs_base(tsk));
- }
- static int scs_cleanup(unsigned int cpu)
- {
- int i;
- void **cache = per_cpu_ptr(scs_cache, cpu);
- for (i = 0; i < NR_CACHED_SCS; i++) {
- vfree(cache[i]);
- cache[i] = NULL;
- }
- return 0;
- }
- void __init scs_init(void)
- {
- WARN_ON(cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "scs:scs_cache", NULL,
- scs_cleanup) < 0);
- }
- #else /* !CONFIG_SHADOW_CALL_STACK_VMAP */
- static struct kmem_cache *scs_cache;
- static inline void *scs_alloc(int node)
- {
- void *s;
- s = kmem_cache_alloc_node(scs_cache, GFP_SCS, node);
- if (s) {
- scs_set_magic(s);
- /*
- * 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 inline void scs_free(void *s)
- {
- kasan_unpoison_object_data(scs_cache, s);
- kmem_cache_free(scs_cache, s);
- }
- static struct page *__scs_page(struct task_struct *tsk)
- {
- return virt_to_page(__scs_base(tsk));
- }
- void __init scs_init(void)
- {
- scs_cache = kmem_cache_create("scs_cache", SCS_SIZE, SCS_SIZE,
- 0, NULL);
- WARN_ON(!scs_cache);
- }
- #endif /* CONFIG_SHADOW_CALL_STACK_VMAP */
- void scs_task_reset(struct task_struct *tsk)
- {
- /*
- * Reset the shadow stack to the base address in case the task
- * is reused.
- */
- task_set_scs(tsk, __scs_base(tsk));
- }
- static void scs_account(struct task_struct *tsk, int account)
- {
- mod_zone_page_state(page_zone(__scs_page(tsk)), NR_KERNEL_SCS_BYTES,
- account * SCS_SIZE);
- }
- int scs_prepare(struct task_struct *tsk, int node)
- {
- void *s;
- s = scs_alloc(node);
- if (!s)
- return -ENOMEM;
- task_set_scs(tsk, s);
- scs_account(tsk, 1);
- return 0;
- }
- #ifdef CONFIG_DEBUG_STACK_USAGE
- static void scs_check_usage(struct task_struct *tsk)
- {
- static unsigned long highest;
- unsigned long *p = __scs_base(tsk);
- unsigned long *end = scs_magic(p);
- unsigned long prev, curr = highest, used = 0;
- for (; p < end; ++p) {
- if (!READ_ONCE_NOCHECK(*p))
- break;
- used += sizeof(*p);
- }
- while (used > curr) {
- prev = cmpxchg_relaxed(&highest, curr, used);
- if (prev == curr) {
- pr_info("%s (%d): highest shadow stack usage: %lu bytes\n",
- tsk->comm, task_pid_nr(tsk), used);
- break;
- }
- curr = prev;
- }
- }
- #else
- static inline void scs_check_usage(struct task_struct *tsk)
- {
- }
- #endif
- bool scs_corrupted(struct task_struct *tsk)
- {
- unsigned long *magic = scs_magic(__scs_base(tsk));
- return READ_ONCE_NOCHECK(*magic) != SCS_END_MAGIC;
- }
- void scs_release(struct task_struct *tsk)
- {
- void *s;
- s = __scs_base(tsk);
- if (!s)
- return;
- WARN_ON(scs_corrupted(tsk));
- scs_check_usage(tsk);
- scs_account(tsk, -1);
- task_set_scs(tsk, NULL);
- scs_free(s);
- }
|