xref: /openbmc/linux/kernel/scs.c (revision d08b9f0ca6605e13dcb48f04e55a30545b3c71eb)
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