UPSTREAM: kfence: report sensitive information based on no_hash_pointers

We cannot rely on CONFIG_DEBUG_KERNEL to decide if we're running a "debug
kernel" where we can safely show potentially sensitive information in the
kernel log.

Instead, simply rely on the newly introduced "no_hash_pointers" to print
unhashed kernel pointers, as well as decide if our reports can include
other potentially sensitive information such as registers and corrupted
bytes.

Link: https://lkml.kernel.org/r/[email protected]
Signed-off-by: Marco Elver <[email protected]>
Cc: Timur Tabi <[email protected]>
Cc: Alexander Potapenko <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: Andrey Konovalov <[email protected]>
Cc: Jann Horn <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>

Bug: 177201466
Bug: 180086542
(cherry picked from commit 35beccf0926d42ee0d56e41979ec8cdf814c4769)
Signed-off-by: Alexander Potapenko <[email protected]>
Change-Id: Ie76403ee1b902742a6ac300ad13bd117a02f93f1
This commit is contained in:
Marco Elver 2021-02-25 17:19:40 -08:00 • committed by Michael Bestas
commit 5f44e5ced3
No known key found for this signature in database
GPG key ID: CC95044519BE6669
5 changed files with 18 additions and 27 deletions

View file

@ -646,13 +646,9 @@ void __init kfence_init(void)
WRITE_ONCE(kfence_enabled, true);
schedule_delayed_work(&kfence_timer, 0);
pr_info("initialized - using %lu bytes for %d objects", KFENCE_POOL_SIZE,
CONFIG_KFENCE_NUM_OBJECTS);
if (IS_ENABLED(CONFIG_DEBUG_KERNEL))
pr_cont(" at 0x%px-0x%px\n", (void *)__kfence_pool,
(void *)(__kfence_pool + KFENCE_POOL_SIZE));
else
pr_cont("\n");
pr_info("initialized - using %lu bytes for %d objects at 0x%p-0x%p\n", KFENCE_POOL_SIZE,
CONFIG_KFENCE_NUM_OBJECTS, (void *)__kfence_pool,
(void *)(__kfence_pool + KFENCE_POOL_SIZE));
}
void kfence_shutdown_cache(struct kmem_cache *s)

View file

@ -16,13 +16,6 @@
#include "../slab.h" /* for struct kmem_cache */
/* For non-debug builds, avoid leaking kernel pointers into dmesg. */
#ifdef CONFIG_DEBUG_KERNEL
#define PTR_FMT "%px"
#else
#define PTR_FMT "%p"
#endif
/*
* Get the canary byte pattern for @addr. Use a pattern that varies based on the
* lower 3 bits of the address, to detect memory corruptions with higher

View file

@ -146,7 +146,7 @@ static bool report_matches(const struct expect_report *r)
break;
}
cur += scnprintf(cur, end - cur, " 0x" PTR_FMT, (void *)r->addr);
cur += scnprintf(cur, end - cur, " 0x%p", (void *)r->addr);
spin_lock_irqsave(&observed.lock, flags);
if (!report_available())

View file

@ -20,6 +20,8 @@
#include "kfence.h"
extern bool no_hash_pointers;
/* Helper function to either print to a seq_file or to console. */
__printf(2, 3)
static void seq_con_printf(struct seq_file *seq, const char *fmt, ...)
@ -119,7 +121,7 @@ void kfence_print_object(struct seq_file *seq, const struct kfence_metadata *met
}
seq_con_printf(seq,
"kfence-#%zd [0x" PTR_FMT "-0x" PTR_FMT
"kfence-#%zd [0x%p-0x%p"
", size=%d, cache=%s] allocated by task %d:\n",
meta - kfence_metadata, (void *)start, (void *)(start + size - 1), size,
(cache && cache->name) ? cache->name : "<destroyed>", meta->alloc_track.pid);
@ -149,7 +151,7 @@ static void print_diff_canary(unsigned long address, size_t bytes_to_show,
for (cur = (const u8 *)address; cur < end; cur++) {
if (*cur == KFENCE_CANARY_PATTERN(cur))
pr_cont(" .");
else if (IS_ENABLED(CONFIG_DEBUG_KERNEL))
else if (no_hash_pointers)
pr_cont(" 0x%02x", *cur);
else /* Do not leak kernel memory in non-debug builds. */
pr_cont(" !");
@ -202,7 +204,7 @@ void kfence_report_error(unsigned long address, bool is_write, struct pt_regs *r
pr_err("BUG: KFENCE: out-of-bounds %s in %pS\n\n", get_access_type(is_write),
(void *)stack_entries[skipnr]);
pr_err("Out-of-bounds %s at 0x" PTR_FMT " (%luB %s of kfence-#%zd):\n",
pr_err("Out-of-bounds %s at 0x%p (%luB %s of kfence-#%zd):\n",
get_access_type(is_write), (void *)address,
left_of_object ? meta->addr - address : address - meta->addr,
left_of_object ? "left" : "right", object_index);
@ -211,24 +213,24 @@ void kfence_report_error(unsigned long address, bool is_write, struct pt_regs *r
case KFENCE_ERROR_UAF:
pr_err("BUG: KFENCE: use-after-free %s in %pS\n\n", get_access_type(is_write),
(void *)stack_entries[skipnr]);
pr_err("Use-after-free %s at 0x" PTR_FMT " (in kfence-#%zd):\n",
pr_err("Use-after-free %s at 0x%p (in kfence-#%zd):\n",
get_access_type(is_write), (void *)address, object_index);
break;
case KFENCE_ERROR_CORRUPTION:
pr_err("BUG: KFENCE: memory corruption in %pS\n\n", (void *)stack_entries[skipnr]);
pr_err("Corrupted memory at 0x" PTR_FMT " ", (void *)address);
pr_err("Corrupted memory at 0x%p ", (void *)address);
print_diff_canary(address, 16, meta);
pr_cont(" (in kfence-#%zd):\n", object_index);
break;
case KFENCE_ERROR_INVALID:
pr_err("BUG: KFENCE: invalid %s in %pS\n\n", get_access_type(is_write),
(void *)stack_entries[skipnr]);
pr_err("Invalid %s at 0x" PTR_FMT ":\n", get_access_type(is_write),
pr_err("Invalid %s at 0x%p:\n", get_access_type(is_write),
(void *)address);
break;
case KFENCE_ERROR_INVALID_FREE:
pr_err("BUG: KFENCE: invalid free in %pS\n\n", (void *)stack_entries[skipnr]);
pr_err("Invalid free of 0x" PTR_FMT " (in kfence-#%zd):\n", (void *)address,
pr_err("Invalid free of 0x%p (in kfence-#%zd):\n", (void *)address,
object_index);
break;
}
@ -243,7 +245,7 @@ void kfence_report_error(unsigned long address, bool is_write, struct pt_regs *r
/* Print report footer. */
pr_err("\n");
if (IS_ENABLED(CONFIG_DEBUG_KERNEL) && regs)
if (no_hash_pointers && regs)
show_regs(regs);
else
dump_stack_print_info(KERN_ERR);