]>
Commit | Line | Data |
---|---|---|
2e903b91 AK |
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 | ||
8028caac | 11 | #include <linux/init.h> |
2e903b91 AK |
12 | #include <linux/kasan.h> |
13 | #include <linux/kernel.h> | |
14 | #include <linux/memory.h> | |
15 | #include <linux/mm.h> | |
8028caac | 16 | #include <linux/static_key.h> |
2e903b91 AK |
17 | #include <linux/string.h> |
18 | #include <linux/types.h> | |
19 | ||
20 | #include "kasan.h" | |
21 | ||
8028caac AK |
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 | ||
2e903b91 AK |
108 | /* kasan_init_hw_tags_cpu() is called for each CPU. */ |
109 | void kasan_init_hw_tags_cpu(void) | |
110 | { | |
8028caac AK |
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 | ||
2e903b91 AK |
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 | { | |
8028caac AK |
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 | ||
2e903b91 AK |
181 | pr_info("KernelAddressSanitizer initialized\n"); |
182 | } | |
183 | ||
2e903b91 AK |
184 | void kasan_set_free_info(struct kmem_cache *cache, |
185 | void *object, u8 tag) | |
186 | { | |
187 | struct kasan_alloc_meta *alloc_meta; | |
188 | ||
6476792f | 189 | alloc_meta = kasan_get_alloc_meta(cache, object); |
97593cad AK |
190 | if (alloc_meta) |
191 | kasan_set_track(&alloc_meta->free_track[0], GFP_NOWAIT); | |
2e903b91 AK |
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 | ||
6476792f | 199 | alloc_meta = kasan_get_alloc_meta(cache, object); |
97593cad AK |
200 | if (!alloc_meta) |
201 | return NULL; | |
202 | ||
2e903b91 AK |
203 | return &alloc_meta->free_track[0]; |
204 | } |