162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * KFENCE reporting. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2020, Google LLC. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/stdarg.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/lockdep.h> 1262306a36Sopenharmony_ci#include <linux/math.h> 1362306a36Sopenharmony_ci#include <linux/printk.h> 1462306a36Sopenharmony_ci#include <linux/sched/debug.h> 1562306a36Sopenharmony_ci#include <linux/seq_file.h> 1662306a36Sopenharmony_ci#include <linux/sprintf.h> 1762306a36Sopenharmony_ci#include <linux/stacktrace.h> 1862306a36Sopenharmony_ci#include <linux/string.h> 1962306a36Sopenharmony_ci#include <trace/events/error_report.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <asm/kfence.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include "kfence.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* May be overridden by <asm/kfence.h>. */ 2662306a36Sopenharmony_ci#ifndef ARCH_FUNC_PREFIX 2762306a36Sopenharmony_ci#define ARCH_FUNC_PREFIX "" 2862306a36Sopenharmony_ci#endif 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* Helper function to either print to a seq_file or to console. */ 3162306a36Sopenharmony_ci__printf(2, 3) 3262306a36Sopenharmony_cistatic void seq_con_printf(struct seq_file *seq, const char *fmt, ...) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci va_list args; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci va_start(args, fmt); 3762306a36Sopenharmony_ci if (seq) 3862306a36Sopenharmony_ci seq_vprintf(seq, fmt, args); 3962306a36Sopenharmony_ci else 4062306a36Sopenharmony_ci vprintk(fmt, args); 4162306a36Sopenharmony_ci va_end(args); 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* 4562306a36Sopenharmony_ci * Get the number of stack entries to skip to get out of MM internals. @type is 4662306a36Sopenharmony_ci * optional, and if set to NULL, assumes an allocation or free stack. 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_cistatic int get_stack_skipnr(const unsigned long stack_entries[], int num_entries, 4962306a36Sopenharmony_ci const enum kfence_error_type *type) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci char buf[64]; 5262306a36Sopenharmony_ci int skipnr, fallback = 0; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci if (type) { 5562306a36Sopenharmony_ci /* Depending on error type, find different stack entries. */ 5662306a36Sopenharmony_ci switch (*type) { 5762306a36Sopenharmony_ci case KFENCE_ERROR_UAF: 5862306a36Sopenharmony_ci case KFENCE_ERROR_OOB: 5962306a36Sopenharmony_ci case KFENCE_ERROR_INVALID: 6062306a36Sopenharmony_ci /* 6162306a36Sopenharmony_ci * kfence_handle_page_fault() may be called with pt_regs 6262306a36Sopenharmony_ci * set to NULL; in that case we'll simply show the full 6362306a36Sopenharmony_ci * stack trace. 6462306a36Sopenharmony_ci */ 6562306a36Sopenharmony_ci return 0; 6662306a36Sopenharmony_ci case KFENCE_ERROR_CORRUPTION: 6762306a36Sopenharmony_ci case KFENCE_ERROR_INVALID_FREE: 6862306a36Sopenharmony_ci break; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci for (skipnr = 0; skipnr < num_entries; skipnr++) { 7362306a36Sopenharmony_ci int len = scnprintf(buf, sizeof(buf), "%ps", (void *)stack_entries[skipnr]); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci if (str_has_prefix(buf, ARCH_FUNC_PREFIX "kfence_") || 7662306a36Sopenharmony_ci str_has_prefix(buf, ARCH_FUNC_PREFIX "__kfence_") || 7762306a36Sopenharmony_ci str_has_prefix(buf, ARCH_FUNC_PREFIX "__kmem_cache_free") || 7862306a36Sopenharmony_ci !strncmp(buf, ARCH_FUNC_PREFIX "__slab_free", len)) { 7962306a36Sopenharmony_ci /* 8062306a36Sopenharmony_ci * In case of tail calls from any of the below to any of 8162306a36Sopenharmony_ci * the above, optimized by the compiler such that the 8262306a36Sopenharmony_ci * stack trace would omit the initial entry point below. 8362306a36Sopenharmony_ci */ 8462306a36Sopenharmony_ci fallback = skipnr + 1; 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci /* 8862306a36Sopenharmony_ci * The below list should only include the initial entry points 8962306a36Sopenharmony_ci * into the slab allocators. Includes the *_bulk() variants by 9062306a36Sopenharmony_ci * checking prefixes. 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_ci if (str_has_prefix(buf, ARCH_FUNC_PREFIX "kfree") || 9362306a36Sopenharmony_ci str_has_prefix(buf, ARCH_FUNC_PREFIX "kmem_cache_free") || 9462306a36Sopenharmony_ci str_has_prefix(buf, ARCH_FUNC_PREFIX "__kmalloc") || 9562306a36Sopenharmony_ci str_has_prefix(buf, ARCH_FUNC_PREFIX "kmem_cache_alloc")) 9662306a36Sopenharmony_ci goto found; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci if (fallback < num_entries) 9962306a36Sopenharmony_ci return fallback; 10062306a36Sopenharmony_cifound: 10162306a36Sopenharmony_ci skipnr++; 10262306a36Sopenharmony_ci return skipnr < num_entries ? skipnr : 0; 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic void kfence_print_stack(struct seq_file *seq, const struct kfence_metadata *meta, 10662306a36Sopenharmony_ci bool show_alloc) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci const struct kfence_track *track = show_alloc ? &meta->alloc_track : &meta->free_track; 10962306a36Sopenharmony_ci u64 ts_sec = track->ts_nsec; 11062306a36Sopenharmony_ci unsigned long rem_nsec = do_div(ts_sec, NSEC_PER_SEC); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci /* Timestamp matches printk timestamp format. */ 11362306a36Sopenharmony_ci seq_con_printf(seq, "%s by task %d on cpu %d at %lu.%06lus:\n", 11462306a36Sopenharmony_ci show_alloc ? "allocated" : "freed", track->pid, 11562306a36Sopenharmony_ci track->cpu, (unsigned long)ts_sec, rem_nsec / 1000); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci if (track->num_stack_entries) { 11862306a36Sopenharmony_ci /* Skip allocation/free internals stack. */ 11962306a36Sopenharmony_ci int i = get_stack_skipnr(track->stack_entries, track->num_stack_entries, NULL); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci /* stack_trace_seq_print() does not exist; open code our own. */ 12262306a36Sopenharmony_ci for (; i < track->num_stack_entries; i++) 12362306a36Sopenharmony_ci seq_con_printf(seq, " %pS\n", (void *)track->stack_entries[i]); 12462306a36Sopenharmony_ci } else { 12562306a36Sopenharmony_ci seq_con_printf(seq, " no %s stack\n", show_alloc ? "allocation" : "deallocation"); 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_civoid kfence_print_object(struct seq_file *seq, const struct kfence_metadata *meta) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci const int size = abs(meta->size); 13262306a36Sopenharmony_ci const unsigned long start = meta->addr; 13362306a36Sopenharmony_ci const struct kmem_cache *const cache = meta->cache; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci lockdep_assert_held(&meta->lock); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if (meta->state == KFENCE_OBJECT_UNUSED) { 13862306a36Sopenharmony_ci seq_con_printf(seq, "kfence-#%td unused\n", meta - kfence_metadata); 13962306a36Sopenharmony_ci return; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci seq_con_printf(seq, "kfence-#%td: 0x%p-0x%p, size=%d, cache=%s\n\n", 14362306a36Sopenharmony_ci meta - kfence_metadata, (void *)start, (void *)(start + size - 1), 14462306a36Sopenharmony_ci size, (cache && cache->name) ? cache->name : "<destroyed>"); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci kfence_print_stack(seq, meta, true); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (meta->state == KFENCE_OBJECT_FREED) { 14962306a36Sopenharmony_ci seq_con_printf(seq, "\n"); 15062306a36Sopenharmony_ci kfence_print_stack(seq, meta, false); 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci/* 15562306a36Sopenharmony_ci * Show bytes at @addr that are different from the expected canary values, up to 15662306a36Sopenharmony_ci * @max_bytes. 15762306a36Sopenharmony_ci */ 15862306a36Sopenharmony_cistatic void print_diff_canary(unsigned long address, size_t bytes_to_show, 15962306a36Sopenharmony_ci const struct kfence_metadata *meta) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci const unsigned long show_until_addr = address + bytes_to_show; 16262306a36Sopenharmony_ci const u8 *cur, *end; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* Do not show contents of object nor read into following guard page. */ 16562306a36Sopenharmony_ci end = (const u8 *)(address < meta->addr ? min(show_until_addr, meta->addr) 16662306a36Sopenharmony_ci : min(show_until_addr, PAGE_ALIGN(address))); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci pr_cont("["); 16962306a36Sopenharmony_ci for (cur = (const u8 *)address; cur < end; cur++) { 17062306a36Sopenharmony_ci if (*cur == KFENCE_CANARY_PATTERN_U8(cur)) 17162306a36Sopenharmony_ci pr_cont(" ."); 17262306a36Sopenharmony_ci else if (no_hash_pointers) 17362306a36Sopenharmony_ci pr_cont(" 0x%02x", *cur); 17462306a36Sopenharmony_ci else /* Do not leak kernel memory in non-debug builds. */ 17562306a36Sopenharmony_ci pr_cont(" !"); 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci pr_cont(" ]"); 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic const char *get_access_type(bool is_write) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci return is_write ? "write" : "read"; 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_civoid kfence_report_error(unsigned long address, bool is_write, struct pt_regs *regs, 18662306a36Sopenharmony_ci const struct kfence_metadata *meta, enum kfence_error_type type) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci unsigned long stack_entries[KFENCE_STACK_DEPTH] = { 0 }; 18962306a36Sopenharmony_ci const ptrdiff_t object_index = meta ? meta - kfence_metadata : -1; 19062306a36Sopenharmony_ci int num_stack_entries; 19162306a36Sopenharmony_ci int skipnr = 0; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (regs) { 19462306a36Sopenharmony_ci num_stack_entries = stack_trace_save_regs(regs, stack_entries, KFENCE_STACK_DEPTH, 0); 19562306a36Sopenharmony_ci } else { 19662306a36Sopenharmony_ci num_stack_entries = stack_trace_save(stack_entries, KFENCE_STACK_DEPTH, 1); 19762306a36Sopenharmony_ci skipnr = get_stack_skipnr(stack_entries, num_stack_entries, &type); 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* Require non-NULL meta, except if KFENCE_ERROR_INVALID. */ 20162306a36Sopenharmony_ci if (WARN_ON(type != KFENCE_ERROR_INVALID && !meta)) 20262306a36Sopenharmony_ci return; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci if (meta) 20562306a36Sopenharmony_ci lockdep_assert_held(&meta->lock); 20662306a36Sopenharmony_ci /* 20762306a36Sopenharmony_ci * Because we may generate reports in printk-unfriendly parts of the 20862306a36Sopenharmony_ci * kernel, such as scheduler code, the use of printk() could deadlock. 20962306a36Sopenharmony_ci * Until such time that all printing code here is safe in all parts of 21062306a36Sopenharmony_ci * the kernel, accept the risk, and just get our message out (given the 21162306a36Sopenharmony_ci * system might already behave unpredictably due to the memory error). 21262306a36Sopenharmony_ci * As such, also disable lockdep to hide warnings, and avoid disabling 21362306a36Sopenharmony_ci * lockdep for the rest of the kernel. 21462306a36Sopenharmony_ci */ 21562306a36Sopenharmony_ci lockdep_off(); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci pr_err("==================================================================\n"); 21862306a36Sopenharmony_ci /* Print report header. */ 21962306a36Sopenharmony_ci switch (type) { 22062306a36Sopenharmony_ci case KFENCE_ERROR_OOB: { 22162306a36Sopenharmony_ci const bool left_of_object = address < meta->addr; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci pr_err("BUG: KFENCE: out-of-bounds %s in %pS\n\n", get_access_type(is_write), 22462306a36Sopenharmony_ci (void *)stack_entries[skipnr]); 22562306a36Sopenharmony_ci pr_err("Out-of-bounds %s at 0x%p (%luB %s of kfence-#%td):\n", 22662306a36Sopenharmony_ci get_access_type(is_write), (void *)address, 22762306a36Sopenharmony_ci left_of_object ? meta->addr - address : address - meta->addr, 22862306a36Sopenharmony_ci left_of_object ? "left" : "right", object_index); 22962306a36Sopenharmony_ci break; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci case KFENCE_ERROR_UAF: 23262306a36Sopenharmony_ci pr_err("BUG: KFENCE: use-after-free %s in %pS\n\n", get_access_type(is_write), 23362306a36Sopenharmony_ci (void *)stack_entries[skipnr]); 23462306a36Sopenharmony_ci pr_err("Use-after-free %s at 0x%p (in kfence-#%td):\n", 23562306a36Sopenharmony_ci get_access_type(is_write), (void *)address, object_index); 23662306a36Sopenharmony_ci break; 23762306a36Sopenharmony_ci case KFENCE_ERROR_CORRUPTION: 23862306a36Sopenharmony_ci pr_err("BUG: KFENCE: memory corruption in %pS\n\n", (void *)stack_entries[skipnr]); 23962306a36Sopenharmony_ci pr_err("Corrupted memory at 0x%p ", (void *)address); 24062306a36Sopenharmony_ci print_diff_canary(address, 16, meta); 24162306a36Sopenharmony_ci pr_cont(" (in kfence-#%td):\n", object_index); 24262306a36Sopenharmony_ci break; 24362306a36Sopenharmony_ci case KFENCE_ERROR_INVALID: 24462306a36Sopenharmony_ci pr_err("BUG: KFENCE: invalid %s in %pS\n\n", get_access_type(is_write), 24562306a36Sopenharmony_ci (void *)stack_entries[skipnr]); 24662306a36Sopenharmony_ci pr_err("Invalid %s at 0x%p:\n", get_access_type(is_write), 24762306a36Sopenharmony_ci (void *)address); 24862306a36Sopenharmony_ci break; 24962306a36Sopenharmony_ci case KFENCE_ERROR_INVALID_FREE: 25062306a36Sopenharmony_ci pr_err("BUG: KFENCE: invalid free in %pS\n\n", (void *)stack_entries[skipnr]); 25162306a36Sopenharmony_ci pr_err("Invalid free of 0x%p (in kfence-#%td):\n", (void *)address, 25262306a36Sopenharmony_ci object_index); 25362306a36Sopenharmony_ci break; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci /* Print stack trace and object info. */ 25762306a36Sopenharmony_ci stack_trace_print(stack_entries + skipnr, num_stack_entries - skipnr, 0); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if (meta) { 26062306a36Sopenharmony_ci pr_err("\n"); 26162306a36Sopenharmony_ci kfence_print_object(NULL, meta); 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci /* Print report footer. */ 26562306a36Sopenharmony_ci pr_err("\n"); 26662306a36Sopenharmony_ci if (no_hash_pointers && regs) 26762306a36Sopenharmony_ci show_regs(regs); 26862306a36Sopenharmony_ci else 26962306a36Sopenharmony_ci dump_stack_print_info(KERN_ERR); 27062306a36Sopenharmony_ci trace_error_report_end(ERROR_DETECTOR_KFENCE, address); 27162306a36Sopenharmony_ci pr_err("==================================================================\n"); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci lockdep_on(); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci check_panic_on_warn("KFENCE"); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci /* We encountered a memory safety error, taint the kernel! */ 27862306a36Sopenharmony_ci add_taint(TAINT_BAD_PAGE, LOCKDEP_STILL_OK); 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci#ifdef CONFIG_PRINTK 28262306a36Sopenharmony_cistatic void kfence_to_kp_stack(const struct kfence_track *track, void **kp_stack) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci int i, j; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci i = get_stack_skipnr(track->stack_entries, track->num_stack_entries, NULL); 28762306a36Sopenharmony_ci for (j = 0; i < track->num_stack_entries && j < KS_ADDRS_COUNT; ++i, ++j) 28862306a36Sopenharmony_ci kp_stack[j] = (void *)track->stack_entries[i]; 28962306a36Sopenharmony_ci if (j < KS_ADDRS_COUNT) 29062306a36Sopenharmony_ci kp_stack[j] = NULL; 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cibool __kfence_obj_info(struct kmem_obj_info *kpp, void *object, struct slab *slab) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci struct kfence_metadata *meta = addr_to_metadata((unsigned long)object); 29662306a36Sopenharmony_ci unsigned long flags; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci if (!meta) 29962306a36Sopenharmony_ci return false; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* 30262306a36Sopenharmony_ci * If state is UNUSED at least show the pointer requested; the rest 30362306a36Sopenharmony_ci * would be garbage data. 30462306a36Sopenharmony_ci */ 30562306a36Sopenharmony_ci kpp->kp_ptr = object; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci /* Requesting info an a never-used object is almost certainly a bug. */ 30862306a36Sopenharmony_ci if (WARN_ON(meta->state == KFENCE_OBJECT_UNUSED)) 30962306a36Sopenharmony_ci return true; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci raw_spin_lock_irqsave(&meta->lock, flags); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci kpp->kp_slab = slab; 31462306a36Sopenharmony_ci kpp->kp_slab_cache = meta->cache; 31562306a36Sopenharmony_ci kpp->kp_objp = (void *)meta->addr; 31662306a36Sopenharmony_ci kfence_to_kp_stack(&meta->alloc_track, kpp->kp_stack); 31762306a36Sopenharmony_ci if (meta->state == KFENCE_OBJECT_FREED) 31862306a36Sopenharmony_ci kfence_to_kp_stack(&meta->free_track, kpp->kp_free_stack); 31962306a36Sopenharmony_ci /* get_stack_skipnr() ensures the first entry is outside allocator. */ 32062306a36Sopenharmony_ci kpp->kp_ret = kpp->kp_stack[0]; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&meta->lock, flags); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci return true; 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci#endif 327