Merge branch 'dt-for-v5.12' of git://git.kernel.org/pub/scm/linux/kernel/git/iwamatsu...
[linux-2.6-microblaze.git] / mm / kasan / hw_tags.c
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 }