xref: /openbmc/linux/mm/kasan/hw_tags.c (revision 8b8f095b)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * This file contains core hardware tag-based KASAN code.
4  *
5  * Copyright (c) 2020 Google, Inc.
6  * Author: Andrey Konovalov <andreyknvl@google.com>
7  */
8 
9 #define pr_fmt(fmt) "kasan: " fmt
10 
11 #include <linux/init.h>
12 #include <linux/kasan.h>
13 #include <linux/kernel.h>
14 #include <linux/memory.h>
15 #include <linux/mm.h>
16 #include <linux/static_key.h>
17 #include <linux/string.h>
18 #include <linux/types.h>
19 
20 #include "kasan.h"
21 
22 enum kasan_arg_mode {
23 	KASAN_ARG_MODE_DEFAULT,
24 	KASAN_ARG_MODE_OFF,
25 	KASAN_ARG_MODE_PROD,
26 	KASAN_ARG_MODE_FULL,
27 };
28 
29 enum kasan_arg_stacktrace {
30 	KASAN_ARG_STACKTRACE_DEFAULT,
31 	KASAN_ARG_STACKTRACE_OFF,
32 	KASAN_ARG_STACKTRACE_ON,
33 };
34 
35 enum kasan_arg_fault {
36 	KASAN_ARG_FAULT_DEFAULT,
37 	KASAN_ARG_FAULT_REPORT,
38 	KASAN_ARG_FAULT_PANIC,
39 };
40 
41 static enum kasan_arg_mode kasan_arg_mode __ro_after_init;
42 static enum kasan_arg_stacktrace kasan_arg_stacktrace __ro_after_init;
43 static enum kasan_arg_fault kasan_arg_fault __ro_after_init;
44 
45 /* Whether KASAN is enabled at all. */
46 DEFINE_STATIC_KEY_FALSE(kasan_flag_enabled);
47 EXPORT_SYMBOL(kasan_flag_enabled);
48 
49 /* Whether to collect alloc/free stack traces. */
50 DEFINE_STATIC_KEY_FALSE(kasan_flag_stacktrace);
51 
52 /* Whether panic or disable tag checking on fault. */
53 bool kasan_flag_panic __ro_after_init;
54 
55 /* kasan.mode=off/prod/full */
56 static int __init early_kasan_mode(char *arg)
57 {
58 	if (!arg)
59 		return -EINVAL;
60 
61 	if (!strcmp(arg, "off"))
62 		kasan_arg_mode = KASAN_ARG_MODE_OFF;
63 	else if (!strcmp(arg, "prod"))
64 		kasan_arg_mode = KASAN_ARG_MODE_PROD;
65 	else if (!strcmp(arg, "full"))
66 		kasan_arg_mode = KASAN_ARG_MODE_FULL;
67 	else
68 		return -EINVAL;
69 
70 	return 0;
71 }
72 early_param("kasan.mode", early_kasan_mode);
73 
74 /* kasan.stack=off/on */
75 static int __init early_kasan_flag_stacktrace(char *arg)
76 {
77 	if (!arg)
78 		return -EINVAL;
79 
80 	if (!strcmp(arg, "off"))
81 		kasan_arg_stacktrace = KASAN_ARG_STACKTRACE_OFF;
82 	else if (!strcmp(arg, "on"))
83 		kasan_arg_stacktrace = KASAN_ARG_STACKTRACE_ON;
84 	else
85 		return -EINVAL;
86 
87 	return 0;
88 }
89 early_param("kasan.stacktrace", early_kasan_flag_stacktrace);
90 
91 /* kasan.fault=report/panic */
92 static int __init early_kasan_fault(char *arg)
93 {
94 	if (!arg)
95 		return -EINVAL;
96 
97 	if (!strcmp(arg, "report"))
98 		kasan_arg_fault = KASAN_ARG_FAULT_REPORT;
99 	else if (!strcmp(arg, "panic"))
100 		kasan_arg_fault = KASAN_ARG_FAULT_PANIC;
101 	else
102 		return -EINVAL;
103 
104 	return 0;
105 }
106 early_param("kasan.fault", early_kasan_fault);
107 
108 /* kasan_init_hw_tags_cpu() is called for each CPU. */
109 void kasan_init_hw_tags_cpu(void)
110 {
111 	/*
112 	 * There's no need to check that the hardware is MTE-capable here,
113 	 * as this function is only called for MTE-capable hardware.
114 	 */
115 
116 	/* If KASAN is disabled, do nothing. */
117 	if (kasan_arg_mode == KASAN_ARG_MODE_OFF)
118 		return;
119 
120 	hw_init_tags(KASAN_TAG_MAX);
121 	hw_enable_tagging();
122 }
123 
124 /* kasan_init_hw_tags() is called once on boot CPU. */
125 void __init kasan_init_hw_tags(void)
126 {
127 	/* If hardware doesn't support MTE, do nothing. */
128 	if (!system_supports_mte())
129 		return;
130 
131 	/* Choose KASAN mode if kasan boot parameter is not provided. */
132 	if (kasan_arg_mode == KASAN_ARG_MODE_DEFAULT) {
133 		if (IS_ENABLED(CONFIG_DEBUG_KERNEL))
134 			kasan_arg_mode = KASAN_ARG_MODE_FULL;
135 		else
136 			kasan_arg_mode = KASAN_ARG_MODE_PROD;
137 	}
138 
139 	/* Preset parameter values based on the mode. */
140 	switch (kasan_arg_mode) {
141 	case KASAN_ARG_MODE_DEFAULT:
142 		/* Shouldn't happen as per the check above. */
143 		WARN_ON(1);
144 		return;
145 	case KASAN_ARG_MODE_OFF:
146 		/* If KASAN is disabled, do nothing. */
147 		return;
148 	case KASAN_ARG_MODE_PROD:
149 		static_branch_enable(&kasan_flag_enabled);
150 		break;
151 	case KASAN_ARG_MODE_FULL:
152 		static_branch_enable(&kasan_flag_enabled);
153 		static_branch_enable(&kasan_flag_stacktrace);
154 		break;
155 	}
156 
157 	/* Now, optionally override the presets. */
158 
159 	switch (kasan_arg_stacktrace) {
160 	case KASAN_ARG_STACKTRACE_DEFAULT:
161 		break;
162 	case KASAN_ARG_STACKTRACE_OFF:
163 		static_branch_disable(&kasan_flag_stacktrace);
164 		break;
165 	case KASAN_ARG_STACKTRACE_ON:
166 		static_branch_enable(&kasan_flag_stacktrace);
167 		break;
168 	}
169 
170 	switch (kasan_arg_fault) {
171 	case KASAN_ARG_FAULT_DEFAULT:
172 		break;
173 	case KASAN_ARG_FAULT_REPORT:
174 		kasan_flag_panic = false;
175 		break;
176 	case KASAN_ARG_FAULT_PANIC:
177 		kasan_flag_panic = true;
178 		break;
179 	}
180 
181 	pr_info("KernelAddressSanitizer initialized\n");
182 }
183 
184 void kasan_set_free_info(struct kmem_cache *cache,
185 				void *object, u8 tag)
186 {
187 	struct kasan_alloc_meta *alloc_meta;
188 
189 	alloc_meta = kasan_get_alloc_meta(cache, object);
190 	if (alloc_meta)
191 		kasan_set_track(&alloc_meta->free_track[0], GFP_NOWAIT);
192 }
193 
194 struct kasan_track *kasan_get_free_track(struct kmem_cache *cache,
195 				void *object, u8 tag)
196 {
197 	struct kasan_alloc_meta *alloc_meta;
198 
199 	alloc_meta = kasan_get_alloc_meta(cache, object);
200 	if (!alloc_meta)
201 		return NULL;
202 
203 	return &alloc_meta->free_track[0];
204 }
205