[PATCH 8/9] Add KASan support
Ahmad Fatoum
a.fatoum at pengutronix.de
Fri Sep 18 06:15:53 EDT 2020
On 9/18/20 10:45 AM, Sascha Hauer wrote:
> - return block_prepare_used(control, block, adjust);
> + void *ret;
> +
> + ret = block_prepare_used(control, block, adjust, size);
> + if (!ret)
> + return ret;
> +
> + return ret;
Debugging leftover? You can just return the function result directly.
> - return block_prepare_used(control, block, adjust);
> + ret = block_prepare_used(control, block, adjust, size);
> + if (!ret)
> + return NULL;
> +
> + return ret;
Likewise
[snip]
> diff --git a/lib/kasan/report.c b/lib/kasan/report.c
> new file mode 100644
> index 0000000000..b7b2d032ee
> --- /dev/null
> +++ b/lib/kasan/report.c
> @@ -0,0 +1,199 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * This file contains common generic and tag-based KASAN error reporting code.
> + *
> + * Copyright (c) 2014 Samsung Electronics Co., Ltd.
> + * Author: Andrey Ryabinin <ryabinin.a.a at gmail.com>
> + *
> + * Some code borrowed from https://github.com/xairy/kasan-prototype by
> + * Andrey Konovalov <andreyknvl at gmail.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#include <common.h>
> +#include <linux/bitops.h>
> +#include <linux/kernel.h>
> +#include <printk.h>
> +#include <asm-generic/sections.h>
> +
> +#include "kasan.h"
> +
> +/* Shadow layout customization. */
> +#define SHADOW_BYTES_PER_BLOCK 1
> +#define SHADOW_BLOCKS_PER_ROW 16
> +#define SHADOW_BYTES_PER_ROW (SHADOW_BLOCKS_PER_ROW * SHADOW_BYTES_PER_BLOCK)
> +#define SHADOW_ROWS_AROUND_ADDR 2
> +
> +static unsigned long kasan_flags;
> +
> +#define KASAN_BIT_REPORTED 0
> +#define KASAN_BIT_MULTI_SHOT 1
> +
> +bool kasan_save_enable_multi_shot(void)
> +{
> + return test_and_set_bit(KASAN_BIT_MULTI_SHOT, &kasan_flags);
> +}
> +EXPORT_SYMBOL_GPL(kasan_save_enable_multi_shot);
> +
> +void kasan_restore_multi_shot(bool enabled)
> +{
> + if (!enabled)
> + clear_bit(KASAN_BIT_MULTI_SHOT, &kasan_flags);
> +}
> +EXPORT_SYMBOL_GPL(kasan_restore_multi_shot);
> +
> +static void print_error_description(struct kasan_access_info *info)
> +{
> + pr_err("BUG: KASAN: %s in %pS\n",
> + get_bug_type(info), (void *)info->ip);
> + pr_err("%s of size %zu at addr %px\n",
> + info->is_write ? "Write" : "Read", info->access_size,
> + info->access_addr);
I just removed the pr_err in ubsan with this rationale:
common: ubsan: replace pr_err with printf
The pr_print family of functions also writes to the barebox
log buffer, which we don't require for printing UBSan errors,
which is a debugging aid. This also improves UBSan coverage as now
undefined behavior within pr_print may be reported as well.
Should we use plain printf here as well? Less code to execute
= less chance to run into a recursion.
> +}
> +
> +static void start_report(unsigned long *flags)
> +{
> + /*
> + * Make sure we don't end up in loop.
> + */
> + kasan_disable_current();
> + pr_err("==================================================================\n");
> +}
> +
> +static void end_report(unsigned long *flags)
> +{
> + pr_err("==================================================================\n");
> + kasan_enable_current();
> +}
> +
> +static inline bool kernel_or_module_addr(const void *addr)
> +{
> + if (addr >= (void *)_stext && addr < (void *)_end)
> + return true;
> + return false;
> +}
> +
> +static void print_address_description(void *addr, u8 tag)
> +{
> + dump_stack();
> + pr_err("\n");
> +
> + if (kernel_or_module_addr(addr)) {
> + pr_err("The buggy address belongs to the variable:\n");
> + pr_err(" %pS\n", addr);
> + }
> +}
> +
> +static bool row_is_guilty(const void *row, const void *guilty)
> +{
> + return (row <= guilty) && (guilty < row + SHADOW_BYTES_PER_ROW);
> +}
> +
> +static int shadow_pointer_offset(const void *row, const void *shadow)
> +{
> + /* The length of ">ff00ff00ff00ff00: " is
> + * 3 + (BITS_PER_LONG/8)*2 chars.
> + */
> + return 3 + (BITS_PER_LONG/8)*2 + (shadow - row)*2 +
> + (shadow - row) / SHADOW_BYTES_PER_BLOCK + 1;
> +}
> +
> +static void print_shadow_for_address(const void *addr)
> +{
> + int i;
> + const void *shadow = kasan_mem_to_shadow(addr);
> + const void *shadow_row;
> +
> + shadow_row = (void *)round_down((unsigned long)shadow,
> + SHADOW_BYTES_PER_ROW)
> + - SHADOW_ROWS_AROUND_ADDR * SHADOW_BYTES_PER_ROW;
> +
> + pr_err("Memory state around the buggy address:\n");
> +
> + for (i = -SHADOW_ROWS_AROUND_ADDR; i <= SHADOW_ROWS_AROUND_ADDR; i++) {
> + const void *kaddr = kasan_shadow_to_mem(shadow_row);
> + char buffer[4 + (BITS_PER_LONG/8)*2];
> + char shadow_buf[SHADOW_BYTES_PER_ROW];
> +
> + snprintf(buffer, sizeof(buffer),
> + (i == 0) ? ">%px: " : " %px: ", kaddr);
> + /*
> + * We should not pass a shadow pointer to generic
> + * function, because generic functions may try to
> + * access kasan mapping for the passed address.
> + */
> + memcpy(shadow_buf, shadow_row, SHADOW_BYTES_PER_ROW);
> + print_hex_dump(KERN_ERR, buffer,
> + DUMP_PREFIX_NONE, SHADOW_BYTES_PER_ROW, 1,
> + shadow_buf, SHADOW_BYTES_PER_ROW, 0);
> +
> + if (row_is_guilty(shadow_row, shadow))
> + printf("%*c\n",
> + shadow_pointer_offset(shadow_row, shadow),
> + '^');
> +
> + shadow_row += SHADOW_BYTES_PER_ROW;
> + }
> +}
> +
> +static bool report_enabled(void)
> +{
> + if (kasan_depth)
> + return false;
> + if (test_bit(KASAN_BIT_MULTI_SHOT, &kasan_flags))
> + return true;
> + return !test_and_set_bit(KASAN_BIT_REPORTED, &kasan_flags);
> +}
> +
> +static void __kasan_report(unsigned long addr, size_t size, bool is_write,
> + unsigned long ip)
> +{
> + struct kasan_access_info info;
> + void *tagged_addr;
> + void *untagged_addr;
> + unsigned long flags;
> +
> + tagged_addr = (void *)addr;
> + untagged_addr = reset_tag(tagged_addr);
> +
> + info.access_addr = tagged_addr;
> + if (addr_has_shadow(untagged_addr))
> + info.first_bad_addr = find_first_bad_addr(tagged_addr, size);
> + else
> + info.first_bad_addr = untagged_addr;
> + info.access_size = size;
> + info.is_write = is_write;
> + info.ip = ip;
> +
> + start_report(&flags);
> +
> + print_error_description(&info);
> + pr_err("\n");
> +
> + if (addr_has_shadow(untagged_addr)) {
> + print_address_description(untagged_addr, get_tag(tagged_addr));
> + pr_err("\n");
> + print_shadow_for_address(info.first_bad_addr);
> + } else {
> + dump_stack();
> + }
> +
> + end_report(&flags);
> +}
> +
> +bool kasan_report(unsigned long addr, size_t size, bool is_write,
> + unsigned long ip)
> +{
> + bool ret = false;
> +
> + if (likely(report_enabled())) {
> + __kasan_report(addr, size, is_write, ip);
> + ret = true;
> + }
> +
> + return ret;
> +}
> diff --git a/scripts/Makefile.kasan b/scripts/Makefile.kasan
> new file mode 100644
> index 0000000000..83f6aa543d
> --- /dev/null
> +++ b/scripts/Makefile.kasan
> @@ -0,0 +1,17 @@
> + # SPDX-License-Identifier: GPL-2.0
> +ifdef CONFIG_KASAN
> +CFLAGS_KASAN_NOSANITIZE := -fno-builtin
> +KASAN_SHADOW_OFFSET ?= $(CONFIG_KASAN_SHADOW_OFFSET)
> +endif
> +
> +CFLAGS_KASAN_MINIMAL := -fsanitize=kernel-address
> +
> +cc-param = $(call cc-option, -mllvm -$(1), $(call cc-option, --param $(1)))
> +
> +CFLAGS_KASAN := $(CFLAGS_KASAN_MINIMAL) \
> + $(call cc-param,asan-globals=1) \
> + $(call cc-param,asan-instrument-allocas=1)
> +
> +ifndef CONFIG_CPU_64
> +CFLAGS_KASAN += $(call cc-param,asan-stack=1)
> +endif
> diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
> index 337430cd00..ab7d9f2bdf 100644
> --- a/scripts/Makefile.lib
> +++ b/scripts/Makefile.lib
> @@ -127,6 +127,16 @@ _c_flags = $(KBUILD_CFLAGS) $(ccflags-y) $(CFLAGS_$(target-stem).o)
> _a_flags = $(KBUILD_AFLAGS) $(asflags-y) $(AFLAGS_$(target-stem).o)
> _cpp_flags = $(KBUILD_CPPFLAGS) $(cppflags-y) $(CPPFLAGS_$(target-stem).lds)
>
> +#
> +# Enable address sanitizer flags for kernel except some files or directories
> +# we don't want to check (depends on variables KASAN_SANITIZE_obj.o, KASAN_SANITIZE)
> +#
> +ifeq ($(CONFIG_KASAN),y)
> +_c_flags += $(if $(part-of-pbl),, $(if $(patsubst n%,, \
> + $(KASAN_SANITIZE_$(basetarget).o)$(KASAN_SANITIZE)y), \
> + $(CFLAGS_KASAN), $(CFLAGS_KASAN_NOSANITIZE)))
> +endif
> +
> ifeq ($(CONFIG_UBSAN),y)
> _CFLAGS_UBSAN = $(eval _CFLAGS_UBSAN := $(CFLAGS_UBSAN))$(_CFLAGS_UBSAN)
> _c_flags += $(if $(patsubst n%,, \
>
--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
More information about the barebox
mailing list