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 { 23 KASAN_ARG_DEFAULT, 24 KASAN_ARG_OFF, 25 KASAN_ARG_ON, 26 }; 27 28 enum kasan_arg_stacktrace { 29 KASAN_ARG_STACKTRACE_DEFAULT, 30 KASAN_ARG_STACKTRACE_OFF, 31 KASAN_ARG_STACKTRACE_ON, 32 }; 33 34 enum kasan_arg_fault { 35 KASAN_ARG_FAULT_DEFAULT, 36 KASAN_ARG_FAULT_REPORT, 37 KASAN_ARG_FAULT_PANIC, 38 }; 39 40 static enum kasan_arg kasan_arg __ro_after_init; 41 static enum kasan_arg_stacktrace kasan_arg_stacktrace __ro_after_init; 42 static enum kasan_arg_fault kasan_arg_fault __ro_after_init; 43 44 /* Whether KASAN is enabled at all. */ 45 DEFINE_STATIC_KEY_FALSE(kasan_flag_enabled); 46 EXPORT_SYMBOL(kasan_flag_enabled); 47 48 /* Whether to collect alloc/free stack traces. */ 49 DEFINE_STATIC_KEY_FALSE(kasan_flag_stacktrace); 50 51 /* Whether to panic or print a report and disable tag checking on fault. */ 52 bool kasan_flag_panic __ro_after_init; 53 54 /* kasan=off/on */ 55 static int __init early_kasan_flag(char *arg) 56 { 57 if (!arg) 58 return -EINVAL; 59 60 if (!strcmp(arg, "off")) 61 kasan_arg = KASAN_ARG_OFF; 62 else if (!strcmp(arg, "on")) 63 kasan_arg = KASAN_ARG_ON; 64 else 65 return -EINVAL; 66 67 return 0; 68 } 69 early_param("kasan", early_kasan_flag); 70 71 /* kasan.stacktrace=off/on */ 72 static int __init early_kasan_flag_stacktrace(char *arg) 73 { 74 if (!arg) 75 return -EINVAL; 76 77 if (!strcmp(arg, "off")) 78 kasan_arg_stacktrace = KASAN_ARG_STACKTRACE_OFF; 79 else if (!strcmp(arg, "on")) 80 kasan_arg_stacktrace = KASAN_ARG_STACKTRACE_ON; 81 else 82 return -EINVAL; 83 84 return 0; 85 } 86 early_param("kasan.stacktrace", early_kasan_flag_stacktrace); 87 88 /* kasan.fault=report/panic */ 89 static int __init early_kasan_fault(char *arg) 90 { 91 if (!arg) 92 return -EINVAL; 93 94 if (!strcmp(arg, "report")) 95 kasan_arg_fault = KASAN_ARG_FAULT_REPORT; 96 else if (!strcmp(arg, "panic")) 97 kasan_arg_fault = KASAN_ARG_FAULT_PANIC; 98 else 99 return -EINVAL; 100 101 return 0; 102 } 103 early_param("kasan.fault", early_kasan_fault); 104 105 /* kasan_init_hw_tags_cpu() is called for each CPU. */ 106 void kasan_init_hw_tags_cpu(void) 107 { 108 /* 109 * There's no need to check that the hardware is MTE-capable here, 110 * as this function is only called for MTE-capable hardware. 111 */ 112 113 /* If KASAN is disabled via command line, don't initialize it. */ 114 if (kasan_arg == KASAN_ARG_OFF) 115 return; 116 117 hw_init_tags(KASAN_TAG_MAX); 118 hw_enable_tagging(); 119 } 120 121 /* kasan_init_hw_tags() is called once on boot CPU. */ 122 void __init kasan_init_hw_tags(void) 123 { 124 /* If hardware doesn't support MTE, don't initialize KASAN. */ 125 if (!system_supports_mte()) 126 return; 127 128 /* If KASAN is disabled via command line, don't initialize it. */ 129 if (kasan_arg == KASAN_ARG_OFF) 130 return; 131 132 /* Enable KASAN. */ 133 static_branch_enable(&kasan_flag_enabled); 134 135 switch (kasan_arg_stacktrace) { 136 case KASAN_ARG_STACKTRACE_DEFAULT: 137 /* Default to enabling stack trace collection. */ 138 static_branch_enable(&kasan_flag_stacktrace); 139 break; 140 case KASAN_ARG_STACKTRACE_OFF: 141 /* Do nothing, kasan_flag_stacktrace keeps its default value. */ 142 break; 143 case KASAN_ARG_STACKTRACE_ON: 144 static_branch_enable(&kasan_flag_stacktrace); 145 break; 146 } 147 148 switch (kasan_arg_fault) { 149 case KASAN_ARG_FAULT_DEFAULT: 150 /* 151 * Default to no panic on report. 152 * Do nothing, kasan_flag_panic keeps its default value. 153 */ 154 break; 155 case KASAN_ARG_FAULT_REPORT: 156 /* Do nothing, kasan_flag_panic keeps its default value. */ 157 break; 158 case KASAN_ARG_FAULT_PANIC: 159 /* Enable panic on report. */ 160 kasan_flag_panic = true; 161 break; 162 } 163 164 pr_info("KernelAddressSanitizer initialized\n"); 165 } 166 167 void kasan_set_free_info(struct kmem_cache *cache, 168 void *object, u8 tag) 169 { 170 struct kasan_alloc_meta *alloc_meta; 171 172 alloc_meta = kasan_get_alloc_meta(cache, object); 173 if (alloc_meta) 174 kasan_set_track(&alloc_meta->free_track[0], GFP_NOWAIT); 175 } 176 177 struct kasan_track *kasan_get_free_track(struct kmem_cache *cache, 178 void *object, u8 tag) 179 { 180 struct kasan_alloc_meta *alloc_meta; 181 182 alloc_meta = kasan_get_alloc_meta(cache, object); 183 if (!alloc_meta) 184 return NULL; 185 186 return &alloc_meta->free_track[0]; 187 } 188 189 #if IS_ENABLED(CONFIG_KASAN_KUNIT_TEST) 190 191 void kasan_set_tagging_report_once(bool state) 192 { 193 hw_set_tagging_report_once(state); 194 } 195 EXPORT_SYMBOL_GPL(kasan_set_tagging_report_once); 196 197 void kasan_enable_tagging(void) 198 { 199 hw_enable_tagging(); 200 } 201 EXPORT_SYMBOL_GPL(kasan_enable_tagging); 202 203 #endif 204