1*d08b9f0cSSami Tolvanen // SPDX-License-Identifier: GPL-2.0 2*d08b9f0cSSami Tolvanen /* 3*d08b9f0cSSami Tolvanen * Shadow Call Stack support. 4*d08b9f0cSSami Tolvanen * 5*d08b9f0cSSami Tolvanen * Copyright (C) 2019 Google LLC 6*d08b9f0cSSami Tolvanen */ 7*d08b9f0cSSami Tolvanen 8*d08b9f0cSSami Tolvanen #include <linux/kasan.h> 9*d08b9f0cSSami Tolvanen #include <linux/scs.h> 10*d08b9f0cSSami Tolvanen #include <linux/slab.h> 11*d08b9f0cSSami Tolvanen #include <asm/scs.h> 12*d08b9f0cSSami Tolvanen 13*d08b9f0cSSami Tolvanen static struct kmem_cache *scs_cache; 14*d08b9f0cSSami Tolvanen 15*d08b9f0cSSami Tolvanen static void *scs_alloc(int node) 16*d08b9f0cSSami Tolvanen { 17*d08b9f0cSSami Tolvanen void *s; 18*d08b9f0cSSami Tolvanen 19*d08b9f0cSSami Tolvanen s = kmem_cache_alloc_node(scs_cache, GFP_SCS, node); 20*d08b9f0cSSami Tolvanen if (s) { 21*d08b9f0cSSami Tolvanen *__scs_magic(s) = SCS_END_MAGIC; 22*d08b9f0cSSami Tolvanen /* 23*d08b9f0cSSami Tolvanen * Poison the allocation to catch unintentional accesses to 24*d08b9f0cSSami Tolvanen * the shadow stack when KASAN is enabled. 25*d08b9f0cSSami Tolvanen */ 26*d08b9f0cSSami Tolvanen kasan_poison_object_data(scs_cache, s); 27*d08b9f0cSSami Tolvanen } 28*d08b9f0cSSami Tolvanen 29*d08b9f0cSSami Tolvanen return s; 30*d08b9f0cSSami Tolvanen } 31*d08b9f0cSSami Tolvanen 32*d08b9f0cSSami Tolvanen static void scs_free(void *s) 33*d08b9f0cSSami Tolvanen { 34*d08b9f0cSSami Tolvanen kasan_unpoison_object_data(scs_cache, s); 35*d08b9f0cSSami Tolvanen kmem_cache_free(scs_cache, s); 36*d08b9f0cSSami Tolvanen } 37*d08b9f0cSSami Tolvanen 38*d08b9f0cSSami Tolvanen void __init scs_init(void) 39*d08b9f0cSSami Tolvanen { 40*d08b9f0cSSami Tolvanen scs_cache = kmem_cache_create("scs_cache", SCS_SIZE, 0, 0, NULL); 41*d08b9f0cSSami Tolvanen } 42*d08b9f0cSSami Tolvanen 43*d08b9f0cSSami Tolvanen int scs_prepare(struct task_struct *tsk, int node) 44*d08b9f0cSSami Tolvanen { 45*d08b9f0cSSami Tolvanen void *s = scs_alloc(node); 46*d08b9f0cSSami Tolvanen 47*d08b9f0cSSami Tolvanen if (!s) 48*d08b9f0cSSami Tolvanen return -ENOMEM; 49*d08b9f0cSSami Tolvanen 50*d08b9f0cSSami Tolvanen task_scs(tsk) = s; 51*d08b9f0cSSami Tolvanen task_scs_offset(tsk) = 0; 52*d08b9f0cSSami Tolvanen 53*d08b9f0cSSami Tolvanen return 0; 54*d08b9f0cSSami Tolvanen } 55*d08b9f0cSSami Tolvanen 56*d08b9f0cSSami Tolvanen void scs_release(struct task_struct *tsk) 57*d08b9f0cSSami Tolvanen { 58*d08b9f0cSSami Tolvanen void *s = task_scs(tsk); 59*d08b9f0cSSami Tolvanen 60*d08b9f0cSSami Tolvanen if (!s) 61*d08b9f0cSSami Tolvanen return; 62*d08b9f0cSSami Tolvanen 63*d08b9f0cSSami Tolvanen WARN(scs_corrupted(tsk), "corrupted shadow stack detected when freeing task\n"); 64*d08b9f0cSSami Tolvanen scs_free(s); 65*d08b9f0cSSami Tolvanen } 66