Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

kfence: add kfence.fault parameter

Add kfence.fault parameter to control the behavior when a KFENCE error is
detected (similar in spirit to kasan.fault=<mode>).

The supported modes for kfence.fault=<mode> are:

- report: print the error report and continue (default).
- oops: print the error report and oops.
- panic: print the error report and panic.

In particular, the 'oops' mode offers a trade-off between no mitigation
on report and panicking outright (if panic_on_oops is not set).

Link: https://lkml.kernel.org/r/20260225203639.3159463-1-elver@google.com
Signed-off-by: Marco Elver <elver@google.com>
Reviewed-by: Alexander Potapenko <glider@google.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Kees Cook <kees@kernel.org>
Cc: Shuah Khan <skhan@linuxfoundation.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Marco Elver and committed by
Andrew Morton
da735962 3efb9800

+89 -12
+6
Documentation/admin-guide/kernel-parameters.txt
··· 2959 2959 Format: <bool> 2960 2960 Default: CONFIG_KFENCE_DEFERRABLE 2961 2961 2962 + kfence.fault= [MM,KFENCE] Controls the behavior when a KFENCE 2963 + error is detected. 2964 + report - print the error report and continue (default). 2965 + oops - print the error report and oops. 2966 + panic - print the error report and panic. 2967 + 2962 2968 kfence.sample_interval= 2963 2969 [MM,KFENCE] KFENCE's sample interval in milliseconds. 2964 2970 Format: <unsigned integer>
+7
Documentation/dev-tools/kfence.rst
··· 81 81 Error reports 82 82 ~~~~~~~~~~~~~ 83 83 84 + The boot parameter ``kfence.fault`` can be used to control the behavior when a 85 + KFENCE error is detected: 86 + 87 + - ``kfence.fault=report``: Print the error report and continue (default). 88 + - ``kfence.fault=oops``: Print the error report and oops. 89 + - ``kfence.fault=panic``: Print the error report and panic. 90 + 84 91 A typical out-of-bounds access looks like this:: 85 92 86 93 ==================================================================
+16 -7
mm/kfence/core.c
··· 51 51 52 52 /* === Data ================================================================= */ 53 53 54 - static bool kfence_enabled __read_mostly; 54 + bool kfence_enabled __read_mostly; 55 55 static bool disabled_by_warn __read_mostly; 56 56 57 57 unsigned long kfence_sample_interval __read_mostly = CONFIG_KFENCE_SAMPLE_INTERVAL; ··· 336 336 static check_canary_attributes bool check_canary_byte(u8 *addr) 337 337 { 338 338 struct kfence_metadata *meta; 339 + enum kfence_fault fault; 339 340 unsigned long flags; 340 341 341 342 if (likely(*addr == KFENCE_CANARY_PATTERN_U8(addr))) ··· 346 345 347 346 meta = addr_to_metadata((unsigned long)addr); 348 347 raw_spin_lock_irqsave(&meta->lock, flags); 349 - kfence_report_error((unsigned long)addr, false, NULL, meta, KFENCE_ERROR_CORRUPTION); 348 + fault = kfence_report_error((unsigned long)addr, false, NULL, meta, KFENCE_ERROR_CORRUPTION); 350 349 raw_spin_unlock_irqrestore(&meta->lock, flags); 350 + kfence_handle_fault(fault); 351 351 352 352 return false; 353 353 } ··· 527 525 raw_spin_lock_irqsave(&meta->lock, flags); 528 526 529 527 if (!kfence_obj_allocated(meta) || meta->addr != (unsigned long)addr) { 528 + enum kfence_fault fault; 529 + 530 530 /* Invalid or double-free, bail out. */ 531 531 atomic_long_inc(&counters[KFENCE_COUNTER_BUGS]); 532 - kfence_report_error((unsigned long)addr, false, NULL, meta, 533 - KFENCE_ERROR_INVALID_FREE); 532 + fault = kfence_report_error((unsigned long)addr, false, NULL, meta, 533 + KFENCE_ERROR_INVALID_FREE); 534 534 raw_spin_unlock_irqrestore(&meta->lock, flags); 535 + kfence_handle_fault(fault); 535 536 return; 536 537 } 537 538 ··· 836 831 static int kfence_check_canary_callback(struct notifier_block *nb, 837 832 unsigned long reason, void *arg) 838 833 { 839 - kfence_check_all_canary(); 834 + if (READ_ONCE(kfence_enabled)) 835 + kfence_check_all_canary(); 840 836 return NOTIFY_OK; 841 837 } 842 838 ··· 1272 1266 struct kfence_metadata *to_report = NULL; 1273 1267 unsigned long unprotected_page = 0; 1274 1268 enum kfence_error_type error_type; 1269 + enum kfence_fault fault; 1275 1270 unsigned long flags; 1276 1271 1277 1272 if (!is_kfence_address((void *)addr)) ··· 1331 1324 if (to_report) { 1332 1325 raw_spin_lock_irqsave(&to_report->lock, flags); 1333 1326 to_report->unprotected_page = unprotected_page; 1334 - kfence_report_error(addr, is_write, regs, to_report, error_type); 1327 + fault = kfence_report_error(addr, is_write, regs, to_report, error_type); 1335 1328 raw_spin_unlock_irqrestore(&to_report->lock, flags); 1336 1329 } else { 1337 1330 /* This may be a UAF or OOB access, but we can't be sure. */ 1338 - kfence_report_error(addr, is_write, regs, NULL, KFENCE_ERROR_INVALID); 1331 + fault = kfence_report_error(addr, is_write, regs, NULL, KFENCE_ERROR_INVALID); 1339 1332 } 1333 + 1334 + kfence_handle_fault(fault); 1340 1335 1341 1336 return kfence_unprotect(addr); /* Unprotect and let access proceed. */ 1342 1337 }
+14 -2
mm/kfence/kfence.h
··· 16 16 17 17 #include "../slab.h" /* for struct kmem_cache */ 18 18 19 + extern bool kfence_enabled; 20 + 19 21 /* 20 22 * Get the canary byte pattern for @addr. Use a pattern that varies based on the 21 23 * lower 3 bits of the address, to detect memory corruptions with higher ··· 142 140 KFENCE_ERROR_INVALID_FREE, /* Invalid free. */ 143 141 }; 144 142 145 - void kfence_report_error(unsigned long address, bool is_write, struct pt_regs *regs, 146 - const struct kfence_metadata *meta, enum kfence_error_type type); 143 + enum kfence_fault { 144 + KFENCE_FAULT_NONE, 145 + KFENCE_FAULT_REPORT, 146 + KFENCE_FAULT_OOPS, 147 + KFENCE_FAULT_PANIC, 148 + }; 149 + 150 + enum kfence_fault 151 + kfence_report_error(unsigned long address, bool is_write, struct pt_regs *regs, 152 + const struct kfence_metadata *meta, enum kfence_error_type type); 153 + 154 + void kfence_handle_fault(enum kfence_fault fault); 147 155 148 156 void kfence_print_object(struct seq_file *seq, const struct kfence_metadata *meta) __must_hold(&meta->lock); 149 157
+46 -3
mm/kfence/report.c
··· 7 7 8 8 #include <linux/stdarg.h> 9 9 10 + #include <linux/bug.h> 11 + #include <linux/init.h> 10 12 #include <linux/kernel.h> 11 13 #include <linux/lockdep.h> 12 14 #include <linux/math.h> 15 + #include <linux/panic.h> 13 16 #include <linux/printk.h> 14 17 #include <linux/sched/debug.h> 15 18 #include <linux/seq_file.h> ··· 31 28 #ifndef ARCH_FUNC_PREFIX 32 29 #define ARCH_FUNC_PREFIX "" 33 30 #endif 31 + 32 + static enum kfence_fault kfence_fault __ro_after_init = KFENCE_FAULT_REPORT; 33 + 34 + static int __init early_kfence_fault(char *arg) 35 + { 36 + if (!arg) 37 + return -EINVAL; 38 + 39 + if (!strcmp(arg, "report")) 40 + kfence_fault = KFENCE_FAULT_REPORT; 41 + else if (!strcmp(arg, "oops")) 42 + kfence_fault = KFENCE_FAULT_OOPS; 43 + else if (!strcmp(arg, "panic")) 44 + kfence_fault = KFENCE_FAULT_PANIC; 45 + else 46 + return -EINVAL; 47 + 48 + return 0; 49 + } 50 + early_param("kfence.fault", early_kfence_fault); 34 51 35 52 /* Helper function to either print to a seq_file or to console. */ 36 53 __printf(2, 3) ··· 212 189 return str_write_read(is_write); 213 190 } 214 191 215 - void kfence_report_error(unsigned long address, bool is_write, struct pt_regs *regs, 216 - const struct kfence_metadata *meta, enum kfence_error_type type) 192 + enum kfence_fault 193 + kfence_report_error(unsigned long address, bool is_write, struct pt_regs *regs, 194 + const struct kfence_metadata *meta, enum kfence_error_type type) 217 195 { 218 196 unsigned long stack_entries[KFENCE_STACK_DEPTH] = { 0 }; 219 197 const ptrdiff_t object_index = meta ? meta - kfence_metadata : -1; ··· 230 206 231 207 /* Require non-NULL meta, except if KFENCE_ERROR_INVALID. */ 232 208 if (WARN_ON(type != KFENCE_ERROR_INVALID && !meta)) 233 - return; 209 + return KFENCE_FAULT_NONE; 234 210 235 211 /* 236 212 * Because we may generate reports in printk-unfriendly parts of the ··· 306 282 307 283 /* We encountered a memory safety error, taint the kernel! */ 308 284 add_taint(TAINT_BAD_PAGE, LOCKDEP_STILL_OK); 285 + 286 + return kfence_fault; 287 + } 288 + 289 + void kfence_handle_fault(enum kfence_fault fault) 290 + { 291 + switch (fault) { 292 + case KFENCE_FAULT_NONE: 293 + case KFENCE_FAULT_REPORT: 294 + break; 295 + case KFENCE_FAULT_OOPS: 296 + BUG(); 297 + break; 298 + case KFENCE_FAULT_PANIC: 299 + /* Disable KFENCE to avoid recursion if check_on_panic is set. */ 300 + WRITE_ONCE(kfence_enabled, false); 301 + panic("kfence.fault=panic set ...\n"); 302 + break; 303 + } 309 304 } 310 305 311 306 #ifdef CONFIG_PRINTK