kasan: add hardware tag-based mode for arm64
Subsystems (16)
v3 cover kasan: add hardware tag-based mode for arm64
This patchset adds a new hardware tag-based mode to KASAN [1]. The new mode is similar to the existing software tag-based KASAN, but relies on arm64 Memory Tagging Extension (MTE) [2] to perform memory and pointer tagging (instead of shadow memory and compiler instrumentation).
This patchset is co-developed by
Vincenzo Frascino <[email protected]>.
This patchset is available here:
https://github.com/xairy/linux/tree/up-kasan-mte-v2
and has also been uploaded to the Linux kernel Gerrit instance:
https://linux-review.googlesource.com/c/linux/kernel/git/torvalds/linux/+/2700
This patchset is based on the v10 of the user MTE patchset [3].
This patchset essentially consists of four parts:
1. Rework KASAN code to allow easier integration of the hardware tag-based mode.
2. Introduce config option for the new mode.
3. Introduce core in-kernel MTE routines.
4. Combine the previous parts together to implement the new mode.
For testing in QEMU hardware tag-based KASAN requires:
1. QEMU built from master [4] (use "-machine virt,mte=on -cpu max" arguments to run).
2. GCC version 10.
[1] https://www.kernel.org/doc/html/latest/dev-tools/kasan.html
[2] https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/enhancing-memory-safety
[3] git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux for-next/mte
[4] https://github.com/qemu/qemu
====== Overview
The underlying ideas of the approach used by hardware tag-based KASAN are:
1. By relying on the Top Byte Ignore (TBI) arm64 CPU feature, pointer tags are stored in the top byte of each kernel pointer.
2. With the Memory Tagging Extension (MTE) arm64 CPU feature, memory tags for kernel memory allocations are stored in a dedicated memory not accessible via normal instuctions.
3. On each memory allocation, a random tag is generated, embedded it into the returned pointer, and the corresponding memory is tagged with the same tag value.
4. With MTE the CPU performs a check on each memory access to make sure that the pointer tag matches the memory tag.
5. On a tag mismatch the CPU generates a tag fault, and a KASAN report is printed.
Same as other KASAN modes, hardware tag-based KASAN is intended as a debugging feature at this point.
====== Rationale
There are two main reasons for this new hardware tag-based mode:
1. Previously implemented software tag-based KASAN is being successfully used on dogfood testing devices due to its low memory overhead (as initially planned). The new hardware mode keeps the same low memory overhead, and is expected to have significantly lower performance impact, due to the tag checks being performed by the hardware. Therefore the new mode can be used as a better alternative in dogfood testing for hardware that supports MTE.
2. The new mode lays the groundwork for the planned in-kernel MTE-based memory corruption mitigation to be used in production.
====== Technical details
From the implementation perspective, hardware tag-based KASAN is almost identical to the software mode. The key difference is using MTE for assigning and checking tags.
Compared to the software mode, the hardware mode uses 4 bits per tag, as dictated by MTE. Pointer tags are stored in bits [56:60), the top 4 bits have the normal value 0xF. Having less distict tags increases the probablity of false negatives (from ~1/256 to ~1/16) in certain cases.
Only synchronous exceptions are set up and used by hardware tag-based KASAN.
====== Benchmarks
Note: all measurements have been performed with software emulation of Memory Tagging Extension, performance numbers for hardware tag-based KASAN on the actual hardware are expected to be better.
Boot time [1]:
* 2.8 sec for clean kernel
* 5.7 sec for hardware tag-based KASAN
* 11.8 sec for software tag-based KASAN
* 11.6 sec for generic KASAN
Slab memory usage after boot [2]:
* 7.0 kb for clean kernel
* 9.7 kb for hardware tag-based KASAN
* 9.7 kb for software tag-based KASAN
* 41.3 kb for generic KASAN
Measurements have been performed with:
* defconfig-based configs
* Manually built QEMU master
* QEMU arguments: -machine virt,mte=on -cpu max
* CONFIG_KASAN_STACK_ENABLE disabled
* CONFIG_KASAN_INLINE enabled
* clang-10 as the compiler and gcc-10 as the assembler
[1] Time before the ext4 driver is initialized.
[2] Measured as cat /proc/meminfo | grep Slab.
====== Notes
The cover letter for software tag-based KASAN patchset can be found here:
====== History
Changes v2->v3:
(Vincenzo:)
- Use ARM64_ASM_PREAMBLE for asm macros.
- Rename mte-helper.h to mte-kasan.h. The new header is meant to contain only macros and prototypes directly used in KASAN. The rest is defined in mte.h.
- Update mte_get_mem_tag()/mte_get_random_tag() to used directly asm volatile() macros instead of calling library functions.
- Harden mte_assign_mem_tag_range() to prevent an infinite loop in case of unaligned size.
- Made sure that report_tag_fault() is executed only once.
- Simplify the mte code in __cpu_setup.
- Remove kprobes.h from mte.c includes.
- General cleanup of the code.
(Andrey:)
- Use READ/WRITE_ONCE when accessing reported in do_tag_recovery().
- Move .unreq mte_tcr under CONFIG_ARM64_MTE to avoid build errors when MTE is not enabled.
- Improve mm/kasan/shadow.c comment header.
- Clarify what is a memory granule in "kasan: rename KASAN_SHADOW_* to KASAN_GRANULE_" commit description.
- Rename (report_)tags_sw/hw.c to to (report_)sw/hw_tags.c and drop unnecessary rename commit.
- Adopt 100 lines limit for some mm/kasan/ changes.
- Align arguments for stack_trace_save() call in mm/slub.c.
- Restore comment before kasan_init_tags().
- Remove GNU headers from all mm/kasan/ files.
- Simplify check_invalid_free() implementation tag-based modes.
- Drop subsequently removed report_tag_fault() implementation.
- Add KASAN_GRANULE_PAGE and use instead of PAGE_SIZE * KASAN_GRANULE_SIZE.
- Move kasan_enable/disable_current() declarations to simplify include/linux/kasan.h.
- Drop dependency on CONFIG_SLUB_DEBUG.
- Clarify the purpose of CONFIG_STACKTRACE in KASAN Kconfig.
Changes v1->v2:
- Rebase onto v10 of the user MTE patchset.
- Only enable in-kernel MTE when KASAN_HW_TAGS is enabled.
- Add a layer of arch-level indirection, so KASAN doesn't call MTE helpers directly (this will be useful in case more architectures will add support for HW_TAGS).
- Don't do arm64_skip_faulting_instruction() on MTE fault, disable MTE instead.
- Don't allow software tags with MTE via arch/arm64/Kconfig instead of lib/Kconfig.kasan.
- Rename mm/kasan/tags.c to tags_sw.c and mte.c to tags_hw.c, and do the same for report_*.c files.
- Reword HW_TAGS Kconfig help text to make it less MTE specific.
- Reword and clarify Documentation.
- Drop unnecessary is_el1_mte_sync_tag_check_fault().
- Change report_tag_fault() to only call kasan_report() once HW_TAGS is introduced.
- Rename arch/arm64/include/asm/mte_asm.h to mte-helpers.h and move all MTE-related defines and some helper functions there.
- Change mm/kasan/kasan.h to include mte-def.h instead of mte.h.
- Add WARN_ON() on unaligned size to mte_set_mem_tag_range().
- Implement ldg/irg MTE routines as inline assembly.
- Remove smp_wmb() from mte_set_mem_tag_range().
- Drop __must_check from mte_set_mem_tag_range() as KASAN has no use for the return value.
- Drop zero size check from mte_assign_mem_tag_range().
- Drop unnecessary include <asm/kasan.h> from low-level arm64 code.
- Move enabling TBI1 into __cpu_setup().
- Drop stale comment about callee-saved register from arch/arm64/kernel/entry.S.
- Mark gcr_kernel_excl as __ro_after_init.
- Use GENMASK() in mte_init_tags().
Andrey Konovalov (32):
kasan: drop unnecessary GPL text from comment headers
kasan: KASAN_VMALLOC depends on KASAN_GENERIC
kasan: group vmalloc code
kasan: shadow declarations only for software modes
kasan: rename (un)poison_shadow to (un)poison_memory
kasan: rename KASAN_SHADOW_* to KASAN_GRANULE_*
kasan: only build init.c for software modes
kasan: split out shadow.c from common.c
kasan: define KASAN_GRANULE_PAGE
kasan: rename report and tags files
kasan: don't duplicate config dependencies
kasan: hide invalid free check implementation
kasan: decode stack frame only with KASAN_STACK_ENABLE kasan, arm64: only init shadow for software modes kasan, arm64: only use kasan_depth for software modes
kasan: rename addr_has_shadow to addr_has_metadata
kasan: rename print_shadow_for_address to print_memory_metadata
kasan: kasan_non_canonical_hook only for software modes
kasan: rename SHADOW layout macros to META
kasan: separate metadata_fetch_row for each mode
kasan: don't allow SW_TAGS with ARM64_MTE
kasan: introduce CONFIG_KASAN_HW_TAGS
arm64: kasan: Add arch layer for memory tagging helpers
arm64: kasan: Align allocations for HW_TAGS
kasan: define KASAN_GRANULE_SIZE for HW_TAGS
kasan, x86, s390: update undef CONFIG_KASAN
kasan, arm64: expand CONFIG_KASAN checks
kasan, arm64: implement HW_TAGS runtime
kasan, arm64: print report from tag fault handler kasan, slub: reset tags when accessing metadata kasan, arm64: enable CONFIG_KASAN_HW_TAGS
kasan: add documentation for hardware tag-based mode
Vincenzo Frascino (7):
arm64: Enable armv8.5-a asm-arch option
arm64: mte: Add in-kernel MTE helpers
arm64: mte: Add in-kernel tag fault handler
arm64: kasan: Enable in-kernel MTE
arm64: mte: Convert gcr_user into an exclude mask
arm64: mte: Switch GCR_EL1 in kernel entry and exit
arm64: kasan: Enable TBI EL1
Documentation/dev-tools/kasan.rst | 80 ++-
arch/arm64/Kconfig | 9 +-
arch/arm64/Makefile | 7 +-
arch/arm64/include/asm/assembler.h | 2 +-
arch/arm64/include/asm/cache.h | 3 +
arch/arm64/include/asm/esr.h | 1 +
arch/arm64/include/asm/kasan.h | 8 +-
arch/arm64/include/asm/memory.h | 14 +-
arch/arm64/include/asm/mte-kasan.h | 66 +++
arch/arm64/include/asm/mte.h | 19 +-
arch/arm64/include/asm/processor.h | 2 +-
arch/arm64/include/asm/string.h | 5 +-
arch/arm64/include/asm/uaccess.h | 23 +
arch/arm64/kernel/asm-offsets.c | 3 +
arch/arm64/kernel/cpufeature.c | 10 +
arch/arm64/kernel/entry.S | 47 ++
arch/arm64/kernel/head.S | 2 +-
arch/arm64/kernel/image-vars.h | 2 +-
arch/arm64/kernel/mte.c | 85 ++-
arch/arm64/kernel/setup.c | 5 +-
arch/arm64/lib/mte.S | 19 +
arch/arm64/mm/dump.c | 6 +-
arch/arm64/mm/fault.c | 52 +-
arch/arm64/mm/kasan_init.c | 22 +-
arch/arm64/mm/proc.S | 24 +-
arch/s390/boot/string.c | 1 +
arch/x86/boot/compressed/misc.h | 1 +
include/linux/kasan-checks.h | 2 +-
include/linux/kasan.h | 104 ++--
include/linux/mm.h | 2 +-
include/linux/moduleloader.h | 3 +-
include/linux/page-flags-layout.h | 2 +-
include/linux/sched.h | 2 +-
include/linux/string.h | 2 +-
init/init_task.c | 2 +-
kernel/fork.c | 4 +-
lib/Kconfig.kasan | 66 ++-
lib/test_kasan.c | 2 +-
mm/kasan/Makefile | 25 +-
mm/kasan/common.c | 560 +------------------
mm/kasan/generic.c | 38 +-
mm/kasan/generic_report.c | 165 ------
mm/kasan/hw_tags.c | 70 +++
mm/kasan/init.c | 17 +-
mm/kasan/kasan.h | 64 ++-
mm/kasan/quarantine.c | 10 -
mm/kasan/report.c | 259 ++-------
mm/kasan/report_generic.c | 326 +++++++++++
mm/kasan/report_hw_tags.c | 42 ++
mm/kasan/{tags_report.c => report_sw_tags.c} | 14 +-
mm/kasan/shadow.c | 503 +++++++++++++++++
mm/kasan/{tags.c => sw_tags.c} | 18 +-
mm/page_poison.c | 2 +-
mm/ptdump.c | 13 +-
mm/slab_common.c | 2 +-
mm/slub.c | 25 +-
scripts/Makefile.lib | 2 +
57 files changed, 1727 insertions(+), 1137 deletions(-)
create mode 100644 arch/arm64/include/asm/mte-kasan.h
delete mode 100644 mm/kasan/generic_report.c
create mode 100644 mm/kasan/hw_tags.c
create mode 100644 mm/kasan/report_generic.c
create mode 100644 mm/kasan/report_hw_tags.c
rename mm/kasan/{tags_report.c => report_sw_tags.c} (87%)
create mode 100644 mm/kasan/shadow.c
rename mm/kasan/{tags.c => sw_tags.c} (94%)Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
PATCH v3 1/39 kasan: drop unnecessary GPL text from comment headers
Don't mention "GNU General Public License version 2" text explicitly, as it's already covered by the SPDX-License-Identifier.
---
Change-Id: If0a2690042a2aa0fca70cea601ae9aabe72fa233
--- mm/kasan/common.c | 5 ----- mm/kasan/generic.c | 5 ----- mm/kasan/generic_report.c | 5 ----- mm/kasan/init.c | 5 ----- mm/kasan/quarantine.c | 10 ---------- mm/kasan/report.c | 5 ----- mm/kasan/tags.c | 5 ----- mm/kasan/tags_report.c | 5 ----- 8 files changed, 45 deletions(-)
mm/kasan/common.c +0 -5
@@ -7,11 +7,6 @@* * Some code borrowed from https://github.com/xairy/kasan-prototype by * Andrey Konovalov <[email protected]> -* -* 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 <linux/export.h>
mm/kasan/generic.c +0 -5
@@ -7,11 +7,6 @@* * Some code borrowed from https://github.com/xairy/kasan-prototype by * Andrey Konovalov <[email protected]> -* -* 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. -* */ #define pr_fmt (fmt) KBUILD_MODNAME ": " fmt
mm/kasan/generic_report.c +0 -5
@@ -7,11 +7,6 @@* * Some code borrowed from https://github.com/xairy/kasan-prototype by * Andrey Konovalov <[email protected]> -* -* 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 <linux/bitops.h>
mm/kasan/init.c +0 -5
@@ -4,11 +4,6 @@* * Copyright (c) 2015 Samsung Electronics Co., Ltd. * Author: Andrey Ryabinin <[email protected]> -* -* 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 <linux/memblock.h>
mm/kasan/quarantine.c +0 -10
@@ -6,16 +6,6 @@* Copyright (C) 2016 Google, Inc. * * Based on code by Dmitry Chernenkov. -* -* 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. -* -* This program is distributed in the hope that it will be useful, but -* WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* */ #include <linux/gfp.h>
mm/kasan/report.c +0 -5
@@ -7,11 +7,6 @@* * Some code borrowed from https://github.com/xairy/kasan-prototype by * Andrey Konovalov <[email protected]> -* -* 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 <linux/bitops.h>
mm/kasan/tags.c +0 -5
@@ -4,11 +4,6 @@* * Copyright (c) 2018 Google, Inc. * Author: Andrey Konovalov <[email protected]> -* -* 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. -* */ #define pr_fmt (fmt) KBUILD_MODNAME ": " fmt
mm/kasan/tags_report.c +0 -5
@@ -7,11 +7,6 @@* * Some code borrowed from https://github.com/xairy/kasan-prototype by * Andrey Konovalov <[email protected]> -* -* 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 <linux/bitops.h>
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 01/39] kasan: drop unnecessary GPL text from comment headers
Quoted 5 lines · Andrey Konovalov
Don't mention "GNU General Public License version 2" text explicitly, as it's already covered by the SPDX-License-Identifier.
Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>
Quoted 149 lines
---
Change-Id: If0a2690042a2aa0fca70cea601ae9aabe72fa233--- mm/kasan/common.c | 5 ----- mm/kasan/generic.c | 5 ----- mm/kasan/generic_report.c | 5 ----- mm/kasan/init.c | 5 ----- mm/kasan/quarantine.c | 10 ---------- mm/kasan/report.c | 5 ----- mm/kasan/tags.c | 5 ----- mm/kasan/tags_report.c | 5 ----- 8 files changed, 45 deletions(-)mm/kasan/common.c +0
-5@@ -7,11 +7,6 @@* * Some code borrowed from https://github.com/xairy/kasan-prototype by * Andrey Konovalov <[email protected]> -* -* 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 <linux/export.h> mm/kasan/generic.c +0
-5@@ -7,11 +7,6 @@* * Some code borrowed from https://github.com/xairy/kasan-prototype by * Andrey Konovalov <[email protected]> -* -* 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. -* */ #define pr_fmt (fmt) KBUILD_MODNAME ": " fmtmm/kasan/generic_report.c +0
-5@@ -7,11 +7,6 @@* * Some code borrowed from https://github.com/xairy/kasan-prototype by * Andrey Konovalov <[email protected]> -* -* 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 <linux/bitops.h> mm/kasan/init.c +0
-5@@ -4,11 +4,6 @@* * Copyright (c) 2015 Samsung Electronics Co., Ltd. * Author: Andrey Ryabinin <[email protected]> -* -* 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 <linux/memblock.h> mm/kasan/quarantine.c +0
-10@@ -6,16 +6,6 @@* Copyright (C) 2016 Google, Inc. * * Based on code by Dmitry Chernenkov. -* -* 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. -* -* This program is distributed in the hope that it will be useful, but -* WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* */ #include <linux/gfp.h> mm/kasan/report.c +0
-5@@ -7,11 +7,6 @@* * Some code borrowed from https://github.com/xairy/kasan-prototype by * Andrey Konovalov <[email protected]> -* -* 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 <linux/bitops.h> mm/kasan/tags.c +0
-5@@ -4,11 +4,6 @@* * Copyright (c) 2018 Google, Inc. * Author: Andrey Konovalov <[email protected]> -* -* 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. -* */ #define pr_fmt (fmt) KBUILD_MODNAME ": " fmtmm/kasan/tags_report.c +0
-5@@ -7,11 +7,6 @@* * Some code borrowed from https://github.com/xairy/kasan-prototype by * Andrey Konovalov <[email protected]> -* -* 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 <linux/bitops.h> Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
PATCH v3 2/39 kasan: KASAN_VMALLOC depends on KASAN_GENERIC
In reply to Andrey KonovalovCurrently only generic KASAN mode supports vmalloc, reflect that in the config.
---
Change-Id: I1889e5b3bed28cc5d607802fb6ae43ba461c0dc1
--- lib/Kconfig.kasan | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
lib/Kconfig.kasan +1 -1
@@ -156,7 +156,7 @@ config KASAN_SW_TAGS_IDENTIFY config KASAN_VMALLOC bool "Back mappings in vmalloc space with real shadow memory" - depends on HAVE_ARCH_KASAN_VMALLOC + depends on KASAN_GENERIC && HAVE_ARCH_KASAN_VMALLOC help By default, the shadow region for vmalloc space is the read-only zero page. This means that KASAN cannot detect errors involving
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 02/39] kasan: KASAN_VMALLOC depends on KASAN_GENERIC
Quoted 5 lines · Andrey Konovalov
Currently only generic KASAN mode supports vmalloc, reflect that in the config.
Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>
Quoted 22 lines
---
Change-Id: I1889e5b3bed28cc5d607802fb6ae43ba461c0dc1--- lib/Kconfig.kasan | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)lib/Kconfig.kasan +1
-1@@ -156,7 +156,7 @@ config KASAN_SW_TAGS_IDENTIFY config KASAN_VMALLOC bool "Back mappings in vmalloc space with real shadow memory" - depends on HAVE_ARCH_KASAN_VMALLOC + depends on KASAN_GENERIC && HAVE_ARCH_KASAN_VMALLOC help By default, the shadow region for vmalloc space is the read-only zero page. This means that KASAN cannot detect errors involvingSignature · 1 line
2.28.0.681.g6f77f65b4e-goog
PATCH v3 3/39 kasan: group vmalloc code
In reply to Andrey KonovalovThis is a preparatory commit for the upcoming addition of a new hardware tag-based (MTE-based) KASAN mode.
Group all vmalloc-related function declarations in include/linux/kasan.h, and their implementations in mm/kasan/common.c.
No functional changes.
---
Change-Id: Ie20b6c689203cd6de4fd7f2c465ec081c00c5f15
--- include/linux/kasan.h | 41 +++++++++++++---------- mm/kasan/common.c | 78 ++++++++++++++++++++++--------------------- 2 files changed, 63 insertions(+), 56 deletions(-)
include/linux/kasan.h +23 -18
@@ -69,19 +69,6 @@ struct kasan_cache {int free_meta_offset; }; -/* -* These functions provide a special case to support backing module -* allocations with real shadow memory. With KASAN vmalloc, the special -* case is unnecessary, as the work is handled in the generic case. -*/ -#ifndef CONFIG_KASAN_VMALLOC -int kasan_module_alloc (void *addr,size_t size); -void kasan_free_shadow (const struct vm_struct *vm); -#else -static inline int kasan_module_alloc (void *addr,size_t size) {return 0 ; } -static inline void kasan_free_shadow (const struct vm_struct *vm) {} -#endif -int kasan_add_zero_shadow (void *start,unsigned long size);void kasan_remove_zero_shadow (void *start,unsigned long size);
@@ -150,9 +137,6 @@ static inline bool kasan_slab_free(struct kmem_cache *s, void *object,return false; } -static inline int kasan_module_alloc (void *addr,size_t size) {return 0 ; } -static inline void kasan_free_shadow (const struct vm_struct *vm) {} -static inline int kasan_add_zero_shadow (void *start,unsigned long size) {return 0 ;
@@ -205,13 +189,16 @@ static inline void *kasan_reset_tag(const void *addr)#endif /* CONFIG_KASAN_SW_TAGS */ #ifdef CONFIG_KASAN_VMALLOC +int kasan_populate_vmalloc (unsigned long addr,unsigned long size);void kasan_poison_vmalloc (const void *start,unsigned long size);void kasan_unpoison_vmalloc (const void *start,unsigned long size);void kasan_release_vmalloc (unsigned long start,unsigned long end,unsigned long free_region_start,unsigned long free_region_end); -#else + +#else /* CONFIG_KASAN_VMALLOC */ +static inline int kasan_populate_vmalloc (unsigned long start,unsigned long size) {
@@ -226,7 +213,25 @@ static inline void kasan_release_vmalloc(unsigned long start, unsigned long end, unsigned long free_region_start, unsigned long free_region_end) {} -#endif + +#endif /* CONFIG_KASAN_VMALLOC */ + +#if defined(CONFIG_KASAN ) && !defined(CONFIG_KASAN_VMALLOC ) + +/* +* These functions provide a special case to support backing module +* allocations with real shadow memory. With KASAN vmalloc, the special +* case is unnecessary, as the work is handled in the generic case. +*/ +int kasan_module_alloc (void *addr,size_t size); +void kasan_free_shadow (const struct vm_struct *vm); + +#else /* CONFIG_KASAN && !CONFIG_KASAN_VMALLOC */ + +static inline int kasan_module_alloc (void *addr,size_t size) {return 0 ; } +static inline void kasan_free_shadow (const struct vm_struct *vm) {} + +#endif /* CONFIG_KASAN && !CONFIG_KASAN_VMALLOC */ #ifdef CONFIG_KASAN_INLINE void kasan_non_canonical_hook (unsigned long addr);
mm/kasan/common.c +40 -38
94 lines not on this page · raw message
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 03/39] kasan: group vmalloc code
Quoted 10 lines · Andrey Konovalov
This is a preparatory commit for the upcoming addition of a new hardware tag-based (MTE-based) KASAN mode.
Group all vmalloc-related function declarations in
include/linux/kasan.h, and their implementations inmm/kasan/common.c.No functional changes.
Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>
Quoted 190 lines
---
Change-Id: Ie20b6c689203cd6de4fd7f2c465ec081c00c5f15--- include/linux/kasan.h | 41 +++++++++++++---------- mm/kasan/common.c | 78 ++++++++++++++++++++++--------------------- 2 files changed, 63 insertions(+), 56 deletions(-)include/linux/kasan.h +23
-18@@ -69,19 +69,6 @@ struct kasan_cache {int free_meta_offset; }; -/* -* These functions provide a special case to support backing module -* allocations with real shadow memory. With KASAN vmalloc, the special -* case is unnecessary, as the work is handled in the generic case. -*/ -#ifndef CONFIG_KASAN_VMALLOC -int kasan_module_alloc (void *addr,size_t size); -void kasan_free_shadow (const struct vm_struct *vm); -#else -static inline int kasan_module_alloc (void *addr,size_t size) {return 0 ; } -static inline void kasan_free_shadow (const struct vm_struct *vm) {} -#endif -int kasan_add_zero_shadow (void *start,unsigned long size);void kasan_remove_zero_shadow (void *start,unsigned long size);@@ -150,9 +137,6 @@ static inline bool kasan_slab_free(struct kmem_cache *s, void *object,return false; } -static inline int kasan_module_alloc (void *addr,size_t size) {return 0 ; } -static inline void kasan_free_shadow (const struct vm_struct *vm) {} -static inline int kasan_add_zero_shadow (void *start,unsigned long size) {return 0 ;@@ -205,13 +189,16 @@ static inline void *kasan_reset_tag(const void *addr)#endif /* CONFIG_KASAN_SW_TAGS */ #ifdef CONFIG_KASAN_VMALLOC +int kasan_populate_vmalloc (unsigned long addr,unsigned long size);void kasan_poison_vmalloc (const void *start,unsigned long size);void kasan_unpoison_vmalloc (const void *start,unsigned long size);void kasan_release_vmalloc (unsigned long start,unsigned long end,unsigned long free_region_start,unsigned long free_region_end); -#else + +#else /* CONFIG_KASAN_VMALLOC */ +static inline int kasan_populate_vmalloc (unsigned long start,unsigned long size) {@@ -226,7 +213,25 @@ static inline void kasan_release_vmalloc(unsigned long start, unsigned long end, unsigned long free_region_start, unsigned long free_region_end) {} -#endif + +#endif /* CONFIG_KASAN_VMALLOC */ + +#if defined(CONFIG_KASAN ) && !defined(CONFIG_KASAN_VMALLOC ) + +/* +* These functions provide a special case to support backing module +* allocations with real shadow memory. With KASAN vmalloc, the special +* case is unnecessary, as the work is handled in the generic case. +*/ +int kasan_module_alloc (void *addr,size_t size); +void kasan_free_shadow (const struct vm_struct *vm); + +#else /* CONFIG_KASAN && !CONFIG_KASAN_VMALLOC */ + +static inline int kasan_module_alloc (void *addr,size_t size) {return 0 ; } +static inline void kasan_free_shadow (const struct vm_struct *vm) {} + +#endif /* CONFIG_KASAN && !CONFIG_KASAN_VMALLOC */ #ifdef CONFIG_KASAN_INLINE void kasan_non_canonical_hook (unsigned long addr);mm/kasan/common.c +40
-38@@ -536,44 +536,6 @@ void kasan_kfree_large(void *ptr, unsigned long ip)/* The object will be poisoned by page_alloc. */ } -#ifndef CONFIG_KASAN_VMALLOC -int kasan_module_alloc (void *addr,size_t size) -{ -void *ret; -size_t scaled_size; -size_t shadow_size; -unsigned long shadow_start; - - shadow_start = (unsigned long )kasan_mem_to_shadow (addr); - scaled_size = (size +KASAN_SHADOW_MASK ) >>KASAN_SHADOW_SCALE_SHIFT ; - shadow_size =round_up (scaled_size,PAGE_SIZE ); - -if (WARN_ON (!PAGE_ALIGNED (shadow_start))) -return -EINVAL ; - - ret =__vmalloc_node_range (shadow_size,1 , shadow_start, - shadow_start + shadow_size, -GFP_KERNEL , -PAGE_KERNEL ,VM_NO_GUARD ,NUMA_NO_NODE , -__builtin_return_address (0 )); - -if (ret) { -__memset (ret,KASAN_SHADOW_INIT , shadow_size); -find_vm_area (addr)->flags |=VM_KASAN ; -kmemleak_ignore (ret); -return 0 ; - } - -return -ENOMEM ; -} - -void kasan_free_shadow (const struct vm_struct *vm) -{ -if (vm->flags &VM_KASAN ) -vfree (kasan_mem_to_shadow (vm->addr)); -} -#endif -#ifdef CONFIG_MEMORY_HOTPLUG static bool shadow_mapped (unsigned long addr) {@@ -685,6 +647,7 @@ core_initcall(kasan_memhotplug_init);#endif #ifdef CONFIG_KASAN_VMALLOC +static int kasan_populate_vmalloc_pte (pte_t *ptep,unsigned long addr,void *unused) {@@ -923,4 +886,43 @@ void kasan_release_vmalloc(unsigned long start, unsigned long end, (unsigned long)shadow_end); } } + +#else /* CONFIG_KASAN_VMALLOC */ + +int kasan_module_alloc (void *addr,size_t size) +{ +void *ret; +size_t scaled_size; +size_t shadow_size; +unsigned long shadow_start; + + shadow_start = (unsigned long )kasan_mem_to_shadow (addr); + scaled_size = (size +KASAN_SHADOW_MASK ) >>KASAN_SHADOW_SCALE_SHIFT ; + shadow_size =round_up (scaled_size,PAGE_SIZE ); + +if (WARN_ON (!PAGE_ALIGNED (shadow_start))) +return -EINVAL ; + + ret =__vmalloc_node_range (shadow_size,1 , shadow_start, + shadow_start + shadow_size, +GFP_KERNEL , +PAGE_KERNEL ,VM_NO_GUARD ,NUMA_NO_NODE , +__builtin_return_address (0 )); + +if (ret) { +__memset (ret,KASAN_SHADOW_INIT , shadow_size); +find_vm_area (addr)->flags |=VM_KASAN ; +kmemleak_ignore (ret); +return 0 ; + } + +return -ENOMEM ; +} + +void kasan_free_shadow (const struct vm_struct *vm) +{ +if (vm->flags &VM_KASAN ) +vfree (kasan_mem_to_shadow (vm->addr)); +} +#endif Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
PATCH v3 4/39 kasan: shadow declarations only for software modes
In reply to Andrey KonovalovThis is a preparatory commit for the upcoming addition of a new hardware tag-based (MTE-based) KASAN mode.
Group shadow-related KASAN function declarations and only define them for the two existing software modes.
No functional changes for software modes.
---
Change-Id: I864be75a88b91b443c55e9c2042865e15703e164
--- include/linux/kasan.h | 44 ++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 17 deletions(-)
include/linux/kasan.h +27 -17
@@ -3,16 +3,24 @@#define _LINUX_KASAN_H#include <linux/types.h> +#include <asm/kasan.h> struct kmem_cache ;struct page ;struct vm_struct ;struct task_struct ; -#ifdef CONFIG_KASAN +#if defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS )#include <linux/pgtable.h> -#include <asm/kasan.h> + +/* Software KASAN implementations use shadow memory. */ + +#ifdef CONFIG_KASAN_SW_TAGS +#define KASAN_SHADOW_INIT 0xFF +#else +#define KASAN_SHADOW_INIT 0 +#endif extern unsigned char kasan_early_shadow_page[PAGE_SIZE ];extern pte_t kasan_early_shadow_pte[PTRS_PER_PTE ];
@@ -29,6 +37,23 @@ static inline void *kasan_mem_to_shadow(const void *addr) + KASAN_SHADOW_OFFSET; } +int kasan_add_zero_shadow (void *start,unsigned long size); +void kasan_remove_zero_shadow (void *start,unsigned long size); + +#else /* CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS */ + +static inline int kasan_add_zero_shadow (void *start,unsigned long size) +{ +return 0 ; +} +static inline void kasan_remove_zero_shadow (void *start, +unsigned long size) +{} + +#endif /* CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS */ + +#ifdef CONFIG_KASAN +/* Enable reporting bugs after kasan_disable_current() */ extern void kasan_enable_current (void );
@@ -69,9 +94,6 @@ struct kasan_cache {int free_meta_offset; }; -int kasan_add_zero_shadow (void *start,unsigned long size); -void kasan_remove_zero_shadow (void *start,unsigned long size); -size_t __ksize (const void *);static inline void kasan_unpoison_slab (const void *ptr) {
@@ -137,14 +159,6 @@ static inline bool kasan_slab_free(struct kmem_cache *s, void *object,return false; } -static inline int kasan_add_zero_shadow (void *start,unsigned long size) -{ -return 0 ; -} -static inline void kasan_remove_zero_shadow (void *start, -unsigned long size) -{} -static inline void kasan_unpoison_slab (const void *ptr) { }static inline size_t kasan_metadata_size (struct kmem_cache *cache) {return 0 ; }
@@ -152,8 +166,6 @@ static inline size_t kasan_metadata_size(struct kmem_cache *cache) { return 0; }#ifdef CONFIG_KASAN_GENERIC -#define KASAN_SHADOW_INIT 0 -void kasan_cache_shrink (struct kmem_cache *cache);void kasan_cache_shutdown (struct kmem_cache *cache);void kasan_record_aux_stack (void *ptr);
@@ -168,8 +180,6 @@ static inline void kasan_record_aux_stack(void *ptr) {}#ifdef CONFIG_KASAN_SW_TAGS -#define KASAN_SHADOW_INIT 0xFF -void kasan_init_tags (void );void *kasan_reset_tag (const void *addr);
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 04/39] kasan: shadow declarations only for software modes
Quoted 10 lines · Andrey Konovalov
This is a preparatory commit for the upcoming addition of a new hardware tag-based (MTE-based) KASAN mode.
Group shadow-related KASAN function declarations and only define them for the two existing software modes.
No functional changes for software modes.
Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>
Quoted 107 lines
---
Change-Id: I864be75a88b91b443c55e9c2042865e15703e164--- include/linux/kasan.h | 44 ++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 17 deletions(-)include/linux/kasan.h +27
-17@@ -3,16 +3,24 @@#define _LINUX_KASAN_H#include <linux/types.h> +#include <asm/kasan.h> struct kmem_cache ;struct page ;struct vm_struct ;struct task_struct ; -#ifdef CONFIG_KASAN +#if defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS )#include <linux/pgtable.h> -#include <asm/kasan.h> + +/* Software KASAN implementations use shadow memory. */ + +#ifdef CONFIG_KASAN_SW_TAGS +#define KASAN_SHADOW_INIT 0xFF +#else +#define KASAN_SHADOW_INIT 0 +#endif extern unsigned char kasan_early_shadow_page[PAGE_SIZE ];extern pte_t kasan_early_shadow_pte[PTRS_PER_PTE ];@@ -29,6 +37,23 @@ static inline void *kasan_mem_to_shadow(const void *addr) + KASAN_SHADOW_OFFSET; } +int kasan_add_zero_shadow (void *start,unsigned long size); +void kasan_remove_zero_shadow (void *start,unsigned long size); + +#else /* CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS */ + +static inline int kasan_add_zero_shadow (void *start,unsigned long size) +{ +return 0 ; +} +static inline void kasan_remove_zero_shadow (void *start, +unsigned long size) +{} + +#endif /* CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS */ + +#ifdef CONFIG_KASAN +/* Enable reporting bugs after kasan_disable_current() */ extern void kasan_enable_current (void );@@ -69,9 +94,6 @@ struct kasan_cache {int free_meta_offset; }; -int kasan_add_zero_shadow (void *start,unsigned long size); -void kasan_remove_zero_shadow (void *start,unsigned long size); -size_t __ksize (const void *);static inline void kasan_unpoison_slab (const void *ptr) {@@ -137,14 +159,6 @@ static inline bool kasan_slab_free(struct kmem_cache *s, void *object,return false; } -static inline int kasan_add_zero_shadow (void *start,unsigned long size) -{ -return 0 ; -} -static inline void kasan_remove_zero_shadow (void *start, -unsigned long size) -{} -static inline void kasan_unpoison_slab (const void *ptr) { }static inline size_t kasan_metadata_size (struct kmem_cache *cache) {return 0 ; }@@ -152,8 +166,6 @@ static inline size_t kasan_metadata_size(struct kmem_cache *cache) { return 0; }#ifdef CONFIG_KASAN_GENERIC -#define KASAN_SHADOW_INIT 0 -void kasan_cache_shrink (struct kmem_cache *cache);void kasan_cache_shutdown (struct kmem_cache *cache);void kasan_record_aux_stack (void *ptr);@@ -168,8 +180,6 @@ static inline void kasan_record_aux_stack(void *ptr) {}#ifdef CONFIG_KASAN_SW_TAGS -#define KASAN_SHADOW_INIT 0xFF -void kasan_init_tags (void );void *kasan_reset_tag (const void *addr);Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
PATCH v3 5/39 kasan: rename (un)poison_shadow to (un)poison_memory
In reply to Andrey KonovalovThis is a preparatory commit for the upcoming addition of a new hardware tag-based (MTE-based) KASAN mode.
The new mode won't be using shadow memory, but will reuse the same functions. Rename kasan_unpoison_shadow to kasan_unpoison_memory, and kasan_poison_shadow to kasan_poison_memory.
No functional changes.
---
Change-Id: Ia359f32815242c4704e49a5f1639ca2d2f8cba69
--- include/linux/kasan.h | 6 +++--- kernel/fork.c | 4 ++-- mm/kasan/common.c | 38 +++++++++++++++++++------------------- mm/kasan/generic.c | 12 ++++++------ mm/kasan/kasan.h | 2 +- mm/kasan/tags.c | 2 +- mm/slab_common.c | 2 +- 7 files changed, 33 insertions(+), 33 deletions(-)
include/linux/kasan.h +3 -3
@@ -60,7 +60,7 @@ extern void kasan_enable_current(void);/* Disable reporting bugs for current task */ extern void kasan_disable_current (void ); -void kasan_unpoison_shadow (const void *address,size_t size); +void kasan_unpoison_memory (const void *address,size_t size);void kasan_unpoison_task_stack (struct task_struct *task);
@@ -97,7 +97,7 @@ struct kasan_cache {size_t __ksize (const void *);static inline void kasan_unpoison_slab (const void *ptr) { -kasan_unpoison_shadow (ptr,__ksize (ptr)); +kasan_unpoison_memory (ptr,__ksize (ptr)); }size_t kasan_metadata_size (struct kmem_cache *cache);
@@ -106,7 +106,7 @@ void kasan_restore_multi_shot(bool enabled);#else /* CONFIG_KASAN */ -static inline void kasan_unpoison_shadow (const void *address,size_t size) {} +static inline void kasan_unpoison_memory (const void *address,size_t size) {}static inline void kasan_unpoison_task_stack (struct task_struct *task) {}
kernel/fork.c +2 -2
@@ -224,8 +224,8 @@ static unsigned long *alloc_thread_stack_node(struct task_struct *tsk, int node)if (!s)continue ; -/* Clear the KASAN shadow of the stack. */ -kasan_unpoison_shadow (s->addr,THREAD_SIZE ); +/* Mark stack accessible for KASAN. */ +kasan_unpoison_memory (s->addr,THREAD_SIZE );/* Clear stale pointers from reused stack. */ memset (s->addr,0 ,THREAD_SIZE );
mm/kasan/common.c +19 -19
@@ -108,7 +108,7 @@ void *memcpy(void *dest, const void *src, size_t len)* Poisons the shadow memory for 'size' bytes starting from 'addr'. * Memory addresses should be aligned to KASAN_SHADOW_SCALE_SIZE. */ -void kasan_poison_shadow (const void *address,size_t size,u8 value) +void kasan_poison_memory (const void *address,size_t size,u8 value) {void *shadow_start, *shadow_end;
@@ -125,7 +125,7 @@ void kasan_poison_shadow(const void *address, size_t size, u8 value)__memset (shadow_start, value, shadow_end - shadow_start); } -void kasan_unpoison_shadow (const void *address,size_t size) +void kasan_unpoison_memory (const void *address,size_t size) {u8 tag =get_tag (address);
@@ -136,7 +136,7 @@ void kasan_unpoison_shadow(const void *address, size_t size)*/ address =reset_tag (address); -kasan_poison_shadow (address, size, tag); +kasan_poison_memory (address, size, tag);if (size &KASAN_SHADOW_MASK ) {u8 *shadow = (u8 *)kasan_mem_to_shadow (address + size);
@@ -153,7 +153,7 @@ static void __kasan_unpoison_stack(struct task_struct *task, const void *sp)void *base =task_stack_page (task);size_t size = sp - base; -kasan_unpoison_shadow (base, size); +kasan_unpoison_memory (base, size); }/* Unpoison the entire stack for a task. */
@@ -172,7 +172,7 @@ asmlinkage void kasan_unpoison_task_stack_below(const void *watermark)*/ void *base = (void *)((unsigned long )watermark & ~(THREAD_SIZE -1 )); -kasan_unpoison_shadow (base, watermark - base); +kasan_unpoison_memory (base, watermark - base); }void kasan_alloc_pages (struct page *page,unsigned int order)
@@ -186,13 +186,13 @@ void kasan_alloc_pages(struct page *page, unsigned int order) tag =random_tag ();for (i =0 ; i < (1 << order); i++)page_kasan_tag_set (page + i, tag); -kasan_unpoison_shadow (page_address (page),PAGE_SIZE << order); +kasan_unpoison_memory (page_address (page),PAGE_SIZE << order); }void kasan_free_pages (struct page *page,unsigned int order) {if (likely (!PageHighMem (page))) -kasan_poison_shadow (page_address (page), +kasan_poison_memory (page_address (page),PAGE_SIZE << order,KASAN_FREE_PAGE ); }
@@ -284,18 +284,18 @@ void kasan_poison_slab(struct page *page)for (i =0 ; i <compound_nr (page); i++)page_kasan_tag_reset (page + i); -kasan_poison_shadow (page_address (page),page_size (page), +kasan_poison_memory (page_address (page),page_size (page),KASAN_KMALLOC_REDZONE ); }void kasan_unpoison_object_data (struct kmem_cache *cache,void *object) { -kasan_unpoison_shadow (object, cache->object_size); +kasan_unpoison_memory (object, cache->object_size); }void kasan_poison_object_data (struct kmem_cache *cache,void *object) { -kasan_poison_shadow (object, +kasan_poison_memory (object,round_up (cache->object_size,KASAN_SHADOW_SCALE_SIZE ),KASAN_KMALLOC_REDZONE ); }
@@ -408,7 +408,7 @@ static bool __kasan_slab_free(struct kmem_cache *cache, void *object, } rounded_up_size =round_up (cache->object_size,KASAN_SHADOW_SCALE_SIZE ); -kasan_poison_shadow (object, rounded_up_size,KASAN_KMALLOC_FREE ); +kasan_poison_memory (object, rounded_up_size,KASAN_KMALLOC_FREE );if ((IS_ENABLED (CONFIG_KASAN_GENERIC ) && !quarantine) ||unlikely (!(cache->flags &SLAB_KASAN )))
@@ -448,8 +448,8 @@ static void *__kasan_kmalloc(struct kmem_cache *cache, const void *object, tag =assign_tag (cache, object, false, keep_tag);/* Tag is ignored in set_tag without CONFIG_KASAN_SW_TAGS */ -kasan_unpoison_shadow (set_tag (object, tag), size); -kasan_poison_shadow ((void *)redzone_start, redzone_end - redzone_start, +kasan_unpoison_memory (set_tag (object, tag), size); +kasan_poison_memory ((void *)redzone_start, redzone_end - redzone_start,KASAN_KMALLOC_REDZONE );if (cache->flags &SLAB_KASAN )
@@ -489,8 +489,8 @@ void * __must_check kasan_kmalloc_large(const void *ptr, size_t size, KASAN_SHADOW_SCALE_SIZE); redzone_end = (unsigned long )ptr +page_size (page); -kasan_unpoison_shadow (ptr, size); -kasan_poison_shadow ((void *)redzone_start, redzone_end - redzone_start, +kasan_unpoison_memory (ptr, size); +kasan_poison_memory ((void *)redzone_start, redzone_end - redzone_start,KASAN_PAGE_REDZONE );return (void *)ptr;
@@ -523,7 +523,7 @@ void kasan_poison_kfree(void *ptr, unsigned long ip)kasan_report_invalid_free (ptr, ip);return ; } -kasan_poison_shadow (ptr,page_size (page),KASAN_FREE_PAGE ); +kasan_poison_memory (ptr,page_size (page),KASAN_FREE_PAGE ); }else {__kasan_slab_free (page->slab_cache, ptr, ip, false); }
@@ -709,7 +709,7 @@ int kasan_populate_vmalloc(unsigned long addr, unsigned long size)* // vmalloc() allocates memory * // let a = area->addr * // we reach kasan_populate_vmalloc -* // and call kasan_unpoison_shadow: +* // and call kasan_unpoison_memory: * STORE shadow(a), unpoison_val * ... * STORE shadow(a+99), unpoison_val x = LOAD p
@@ -744,7 +744,7 @@ void kasan_poison_vmalloc(const void *start, unsigned long size)return ; size =round_up (size,KASAN_SHADOW_SCALE_SIZE ); -kasan_poison_shadow (start, size,KASAN_VMALLOC_INVALID ); +kasan_poison_memory (start, size,KASAN_VMALLOC_INVALID ); }void kasan_unpoison_vmalloc (const void *start,unsigned long size)
@@ -752,7 +752,7 @@ void kasan_unpoison_vmalloc(const void *start, unsigned long size)if (!is_vmalloc_or_module_addr (start))return ; -kasan_unpoison_shadow (start, size); +kasan_unpoison_memory (start, size); } static int kasan_depopulate_vmalloc_pte(pte_t *ptep, unsigned long addr,
mm/kasan/generic.c +6 -6
@@ -202,9 +202,9 @@ static void register_global(struct kasan_global *global) {size_t aligned_size =round_up (global->size,KASAN_SHADOW_SCALE_SIZE ); -kasan_unpoison_shadow (global->beg, global->size); +kasan_unpoison_memory (global->beg, global->size); -kasan_poison_shadow (global->beg + aligned_size, +kasan_poison_memory (global->beg + aligned_size, global->size_with_redzone - aligned_size,KASAN_GLOBAL_REDZONE ); }
@@ -285,11 +285,11 @@ void __asan_alloca_poison(unsigned long addr, size_t size)WARN_ON (!IS_ALIGNED (addr,KASAN_ALLOCA_REDZONE_SIZE )); -kasan_unpoison_shadow ((const void *)(addr + rounded_down_size), +kasan_unpoison_memory ((const void *)(addr + rounded_down_size), size - rounded_down_size); -kasan_poison_shadow (left_redzone,KASAN_ALLOCA_REDZONE_SIZE , +kasan_poison_memory (left_redzone,KASAN_ALLOCA_REDZONE_SIZE ,KASAN_ALLOCA_LEFT ); -kasan_poison_shadow (right_redzone, +kasan_poison_memory (right_redzone, padding_size +KASAN_ALLOCA_REDZONE_SIZE ,KASAN_ALLOCA_RIGHT ); }
@@ -301,7 +301,7 @@ void __asan_allocas_unpoison(const void *stack_top, const void *stack_bottom)if (unlikely (!stack_top || stack_top > stack_bottom))return ; -kasan_unpoison_shadow (stack_top, stack_bottom - stack_top); +kasan_unpoison_memory (stack_top, stack_bottom - stack_top); }EXPORT_SYMBOL (__asan_allocas_unpoison);
mm/kasan/kasan.h +1 -1
@@ -150,7 +150,7 @@ static inline bool addr_has_shadow(const void *addr)return (addr >=kasan_shadow_to_mem ((void *)KASAN_SHADOW_START )); } -void kasan_poison_shadow (const void *address,size_t size,u8 value); +void kasan_poison_memory (const void *address,size_t size,u8 value);/** * check_memory_region - Check memory region, and report if invalid access.
mm/kasan/tags.c +1 -1
@@ -153,7 +153,7 @@ EXPORT_SYMBOL(__hwasan_storeN_noabort);void __hwasan_tag_memory (unsigned long addr,u8 tag,unsigned long size) { -kasan_poison_shadow ((void *)addr, size, tag); +kasan_poison_memory ((void *)addr, size, tag); }EXPORT_SYMBOL (__hwasan_tag_memory);
mm/slab_common.c +1 -1
@@ -1176,7 +1176,7 @@ size_t ksize(const void *objp)* We assume that ksize callers could use whole allocated area, * so we need to unpoison this area. */ -kasan_unpoison_shadow (objp, size); +kasan_unpoison_memory (objp, size);return size; }EXPORT_SYMBOL (ksize);
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 05/39] kasan: rename (un)poison_shadow to (un)poison_memory
Quoted 11 lines · Andrey Konovalov
This is a preparatory commit for the upcoming addition of a new hardware tag-based (MTE-based) KASAN mode.
The new mode won't be using shadow memory, but will reuse the same functions. Rename
kasan_unpoison_shadowtokasan_unpoison_memory, andkasan_poison_shadowtokasan_poison_memory.No functional changes.
Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>
Quoted 294 lines
---
Change-Id: Ia359f32815242c4704e49a5f1639ca2d2f8cba69--- include/linux/kasan.h | 6 +++--- kernel/fork.c | 4 ++-- mm/kasan/common.c | 38 +++++++++++++++++++------------------- mm/kasan/generic.c | 12 ++++++------ mm/kasan/kasan.h | 2 +- mm/kasan/tags.c | 2 +- mm/slab_common.c | 2 +- 7 files changed, 33 insertions(+), 33 deletions(-)include/linux/kasan.h +3
-3@@ -60,7 +60,7 @@ extern void kasan_enable_current(void);/* Disable reporting bugs for current task */ extern void kasan_disable_current (void ); -void kasan_unpoison_shadow (const void *address,size_t size); +void kasan_unpoison_memory (const void *address,size_t size);void kasan_unpoison_task_stack (struct task_struct *task);@@ -97,7 +97,7 @@ struct kasan_cache {size_t __ksize (const void *);static inline void kasan_unpoison_slab (const void *ptr) { -kasan_unpoison_shadow (ptr,__ksize (ptr)); +kasan_unpoison_memory (ptr,__ksize (ptr)); }size_t kasan_metadata_size (struct kmem_cache *cache);@@ -106,7 +106,7 @@ void kasan_restore_multi_shot(bool enabled);#else /* CONFIG_KASAN */ -static inline void kasan_unpoison_shadow (const void *address,size_t size) {} +static inline void kasan_unpoison_memory (const void *address,size_t size) {}static inline void kasan_unpoison_task_stack (struct task_struct *task) {}kernel/fork.c +2
-2@@ -224,8 +224,8 @@ static unsigned long *alloc_thread_stack_node(struct task_struct *tsk, int node)if (!s)continue ; -/* Clear the KASAN shadow of the stack. */ -kasan_unpoison_shadow (s->addr,THREAD_SIZE ); +/* Mark stack accessible for KASAN. */ +kasan_unpoison_memory (s->addr,THREAD_SIZE );/* Clear stale pointers from reused stack. */ memset (s->addr,0 ,THREAD_SIZE );mm/kasan/common.c +19
-19@@ -108,7 +108,7 @@ void *memcpy(void *dest, const void *src, size_t len)* Poisons the shadow memory for 'size' bytes starting from 'addr'. * Memory addresses should be aligned to KASAN_SHADOW_SCALE_SIZE. */ -void kasan_poison_shadow (const void *address,size_t size,u8 value) +void kasan_poison_memory (const void *address,size_t size,u8 value) {void *shadow_start, *shadow_end;@@ -125,7 +125,7 @@ void kasan_poison_shadow(const void *address, size_t size, u8 value)__memset (shadow_start, value, shadow_end - shadow_start); } -void kasan_unpoison_shadow (const void *address,size_t size) +void kasan_unpoison_memory (const void *address,size_t size) {u8 tag =get_tag (address);@@ -136,7 +136,7 @@ void kasan_unpoison_shadow(const void *address, size_t size)*/ address =reset_tag (address); -kasan_poison_shadow (address, size, tag); +kasan_poison_memory (address, size, tag);if (size &KASAN_SHADOW_MASK ) {u8 *shadow = (u8 *)kasan_mem_to_shadow (address + size);@@ -153,7 +153,7 @@ static void __kasan_unpoison_stack(struct task_struct *task, const void *sp)void *base =task_stack_page (task);size_t size = sp - base; -kasan_unpoison_shadow (base, size); +kasan_unpoison_memory (base, size); }/* Unpoison the entire stack for a task. */ @@ -172,7 +172,7 @@ asmlinkage void kasan_unpoison_task_stack_below(const void *watermark)*/ void *base = (void *)((unsigned long )watermark & ~(THREAD_SIZE -1 )); -kasan_unpoison_shadow (base, watermark - base); +kasan_unpoison_memory (base, watermark - base); }void kasan_alloc_pages (struct page *page,unsigned int order)@@ -186,13 +186,13 @@ void kasan_alloc_pages(struct page *page, unsigned int order) tag =random_tag ();for (i =0 ; i < (1 << order); i++)page_kasan_tag_set (page + i, tag); -kasan_unpoison_shadow (page_address (page),PAGE_SIZE << order); +kasan_unpoison_memory (page_address (page),PAGE_SIZE << order); }void kasan_free_pages (struct page *page,unsigned int order) {if (likely (!PageHighMem (page))) -kasan_poison_shadow (page_address (page), +kasan_poison_memory (page_address (page),PAGE_SIZE << order,KASAN_FREE_PAGE ); }@@ -284,18 +284,18 @@ void kasan_poison_slab(struct page *page)for (i =0 ; i <compound_nr (page); i++)page_kasan_tag_reset (page + i); -kasan_poison_shadow (page_address (page),page_size (page), +kasan_poison_memory (page_address (page),page_size (page),KASAN_KMALLOC_REDZONE ); }void kasan_unpoison_object_data (struct kmem_cache *cache,void *object) { -kasan_unpoison_shadow (object, cache->object_size); +kasan_unpoison_memory (object, cache->object_size); }void kasan_poison_object_data (struct kmem_cache *cache,void *object) { -kasan_poison_shadow (object, +kasan_poison_memory (object,round_up (cache->object_size,KASAN_SHADOW_SCALE_SIZE ),KASAN_KMALLOC_REDZONE ); }@@ -408,7 +408,7 @@ static bool __kasan_slab_free(struct kmem_cache *cache, void *object, } rounded_up_size =round_up (cache->object_size,KASAN_SHADOW_SCALE_SIZE ); -kasan_poison_shadow (object, rounded_up_size,KASAN_KMALLOC_FREE ); +kasan_poison_memory (object, rounded_up_size,KASAN_KMALLOC_FREE );if ((IS_ENABLED (CONFIG_KASAN_GENERIC ) && !quarantine) ||unlikely (!(cache->flags &SLAB_KASAN )))@@ -448,8 +448,8 @@ static void *__kasan_kmalloc(struct kmem_cache *cache, const void *object, tag =assign_tag (cache, object, false, keep_tag);/* Tag is ignored in set_tag without CONFIG_KASAN_SW_TAGS */ -kasan_unpoison_shadow (set_tag (object, tag), size); -kasan_poison_shadow ((void *)redzone_start, redzone_end - redzone_start, +kasan_unpoison_memory (set_tag (object, tag), size); +kasan_poison_memory ((void *)redzone_start, redzone_end - redzone_start,KASAN_KMALLOC_REDZONE );if (cache->flags &SLAB_KASAN )@@ -489,8 +489,8 @@ void * __must_check kasan_kmalloc_large(const void *ptr, size_t size, KASAN_SHADOW_SCALE_SIZE); redzone_end = (unsigned long )ptr +page_size (page); -kasan_unpoison_shadow (ptr, size); -kasan_poison_shadow ((void *)redzone_start, redzone_end - redzone_start, +kasan_unpoison_memory (ptr, size); +kasan_poison_memory ((void *)redzone_start, redzone_end - redzone_start,KASAN_PAGE_REDZONE );return (void *)ptr;@@ -523,7 +523,7 @@ void kasan_poison_kfree(void *ptr, unsigned long ip)kasan_report_invalid_free (ptr, ip);return ; } -kasan_poison_shadow (ptr,page_size (page),KASAN_FREE_PAGE ); +kasan_poison_memory (ptr,page_size (page),KASAN_FREE_PAGE ); }else {__kasan_slab_free (page->slab_cache, ptr, ip, false); }@@ -709,7 +709,7 @@ int kasan_populate_vmalloc(unsigned long addr, unsigned long size)* // vmalloc() allocates memory * // let a = area->addr * // we reach kasan_populate_vmalloc -* // and call kasan_unpoison_shadow: +* // and call kasan_unpoison_memory: * STORE shadow(a), unpoison_val * ... * STORE shadow(a+99), unpoison_val x = LOAD p @@ -744,7 +744,7 @@ void kasan_poison_vmalloc(const void *start, unsigned long size)return ; size =round_up (size,KASAN_SHADOW_SCALE_SIZE ); -kasan_poison_shadow (start, size,KASAN_VMALLOC_INVALID ); +kasan_poison_memory (start, size,KASAN_VMALLOC_INVALID ); }void kasan_unpoison_vmalloc (const void *start,unsigned long size)@@ -752,7 +752,7 @@ void kasan_unpoison_vmalloc(const void *start, unsigned long size)if (!is_vmalloc_or_module_addr (start))return ; -kasan_unpoison_shadow (start, size); +kasan_unpoison_memory (start, size); } static int kasan_depopulate_vmalloc_pte(pte_t *ptep, unsigned long addr,mm/kasan/generic.c +6
-6@@ -202,9 +202,9 @@ static void register_global(struct kasan_global *global) {size_t aligned_size =round_up (global->size,KASAN_SHADOW_SCALE_SIZE ); -kasan_unpoison_shadow (global->beg, global->size); +kasan_unpoison_memory (global->beg, global->size); -kasan_poison_shadow (global->beg + aligned_size, +kasan_poison_memory (global->beg + aligned_size, global->size_with_redzone - aligned_size,KASAN_GLOBAL_REDZONE ); }@@ -285,11 +285,11 @@ void __asan_alloca_poison(unsigned long addr, size_t size)WARN_ON (!IS_ALIGNED (addr,KASAN_ALLOCA_REDZONE_SIZE )); -kasan_unpoison_shadow ((const void *)(addr + rounded_down_size), +kasan_unpoison_memory ((const void *)(addr + rounded_down_size), size - rounded_down_size); -kasan_poison_shadow (left_redzone,KASAN_ALLOCA_REDZONE_SIZE , +kasan_poison_memory (left_redzone,KASAN_ALLOCA_REDZONE_SIZE ,KASAN_ALLOCA_LEFT ); -kasan_poison_shadow (right_redzone, +kasan_poison_memory (right_redzone, padding_size +KASAN_ALLOCA_REDZONE_SIZE ,KASAN_ALLOCA_RIGHT ); }@@ -301,7 +301,7 @@ void __asan_allocas_unpoison(const void *stack_top, const void *stack_bottom)if (unlikely (!stack_top || stack_top > stack_bottom))return ; -kasan_unpoison_shadow (stack_top, stack_bottom - stack_top); +kasan_unpoison_memory (stack_top, stack_bottom - stack_top); }EXPORT_SYMBOL (__asan_allocas_unpoison);mm/kasan/kasan.h +1
-1@@ -150,7 +150,7 @@ static inline bool addr_has_shadow(const void *addr)return (addr >=kasan_shadow_to_mem ((void *)KASAN_SHADOW_START )); } -void kasan_poison_shadow (const void *address,size_t size,u8 value); +void kasan_poison_memory (const void *address,size_t size,u8 value);/** * check_memory_region - Check memory region, and report if invalid access. mm/kasan/tags.c +1
-1@@ -153,7 +153,7 @@ EXPORT_SYMBOL(__hwasan_storeN_noabort);void __hwasan_tag_memory (unsigned long addr,u8 tag,unsigned long size) { -kasan_poison_shadow ((void *)addr, size, tag); +kasan_poison_memory ((void *)addr, size, tag); }EXPORT_SYMBOL (__hwasan_tag_memory);mm/slab_common.c +1
-1@@ -1176,7 +1176,7 @@ size_t ksize(const void *objp)* We assume that ksize callers could use whole allocated area, * so we need to unpoison this area. */ -kasan_unpoison_shadow (objp, size); +kasan_unpoison_memory (objp, size);return size; }EXPORT_SYMBOL (ksize);Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
PATCH v3 6/39 kasan: rename KASAN_SHADOW_* to KASAN_GRANULE_*
In reply to Andrey KonovalovThis is a preparatory commit for the upcoming addition of a new hardware tag-based (MTE-based) KASAN mode.
The new mode won't be using shadow memory, but will still use the concept of memory granules. Each memory granule maps to a single metadata entry:
8 bytes per one shadow byte for generic mode, 16 bytes per one shadow byte for software tag-based mode, and 16 bytes per one allocation tag for hardware tag-based mode.
Rename KASAN_SHADOW_SCALE_SIZE to KASAN_GRANULE_SIZE, and KASAN_SHADOW_MASK to KASAN_GRANULE_MASK.
Also use MASK when used as a mask, otherwise use SIZE.
No functional changes.
---
Change-Id: Iac733e2248aa9d29f6fc425d8946ba07cca73ecf
--- Documentation/dev-tools/kasan.rst | 2 +- lib/test_kasan.c | 2 +- mm/kasan/common.c | 39 ++++++++++++++++--------------- mm/kasan/generic.c | 14 +++++------ mm/kasan/generic_report.c | 8 +++---- mm/kasan/init.c | 8 +++---- mm/kasan/kasan.h | 4 ++-- mm/kasan/report.c | 10 ++++---- mm/kasan/tags_report.c | 2 +- 9 files changed, 45 insertions(+), 44 deletions(-)
Documentation/dev-tools/kasan.rst +1 -1
@@ -264,7 +264,7 @@ Most mappings in vmalloc space are small, requiring less than a full page of shadow space. Allocating a full shadow page per mapping would therefore be wasteful. Furthermore, to ensure that different mappings use different shadow pages, mappings would have to be aligned to -``KASAN_SHADOW_SCALE_SIZE * PAGE_SIZE``. +``KASAN_GRANULE_SIZE * PAGE_SIZE``. Instead, we share backing space across multiple mappings. We allocate a backing page when a mapping in vmalloc space uses a particular page
lib/test_kasan.c +1 -1
@@ -25,7 +25,7 @@#include "../mm/kasan/kasan.h" -#define OOB_TAG_OFF (IS_ENABLED(CONFIG_KASAN_GENERIC) ? 0 : KASAN_SHADOW_SCALE_SIZE) +#define OOB_TAG_OFF (IS_ENABLED(CONFIG_KASAN_GENERIC) ? 0 : KASAN_GRANULE_SIZE)/* * We assign some test results to these globals to make sure the tests
mm/kasan/common.c +20 -19
@@ -106,7 +106,7 @@ void *memcpy(void *dest, const void *src, size_t len)/* * Poisons the shadow memory for 'size' bytes starting from 'addr'. -* Memory addresses should be aligned to KASAN_SHADOW_SCALE_SIZE. +* Memory addresses should be aligned to KASAN_GRANULE_SIZE. */ void kasan_poison_memory (const void *address,size_t size,u8 value) {
@@ -138,13 +138,13 @@ void kasan_unpoison_memory(const void *address, size_t size)kasan_poison_memory (address, size, tag); -if (size &KASAN_SHADOW_MASK ) { +if (size &KASAN_GRANULE_MASK ) {u8 *shadow = (u8 *)kasan_mem_to_shadow (address + size);if (IS_ENABLED (CONFIG_KASAN_SW_TAGS )) *shadow = tag;else - *shadow = size &KASAN_SHADOW_MASK ; + *shadow = size &KASAN_GRANULE_MASK ; } }
@@ -296,7 +296,7 @@ void kasan_unpoison_object_data(struct kmem_cache *cache, void *object)void kasan_poison_object_data (struct kmem_cache *cache,void *object) {kasan_poison_memory (object, -round_up (cache->object_size,KASAN_SHADOW_SCALE_SIZE ), +round_up (cache->object_size,KASAN_GRANULE_SIZE ),KASAN_KMALLOC_REDZONE ); }
@@ -368,7 +368,7 @@ static inline bool shadow_invalid(u8 tag, s8 shadow_byte) {if (IS_ENABLED (CONFIG_KASAN_GENERIC ))return shadow_byte <0 || - shadow_byte >=KASAN_SHADOW_SCALE_SIZE ; + shadow_byte >=KASAN_GRANULE_SIZE ;/* else CONFIG_KASAN_SW_TAGS: */ if ((u8 )shadow_byte ==KASAN_TAG_INVALID )
@@ -407,7 +407,7 @@ static bool __kasan_slab_free(struct kmem_cache *cache, void *object,return true; } - rounded_up_size =round_up (cache->object_size,KASAN_SHADOW_SCALE_SIZE ); + rounded_up_size =round_up (cache->object_size,KASAN_GRANULE_SIZE );kasan_poison_memory (object, rounded_up_size,KASAN_KMALLOC_FREE ); if ((IS_ENABLED(CONFIG_KASAN_GENERIC) && !quarantine) ||
@@ -440,9 +440,9 @@ static void *__kasan_kmalloc(struct kmem_cache *cache, const void *object,return NULL ; redzone_start =round_up ((unsigned long )(object + size), -KASAN_SHADOW_SCALE_SIZE ); +KASAN_GRANULE_SIZE ); redzone_end =round_up ((unsigned long )object + cache->object_size, -KASAN_SHADOW_SCALE_SIZE ); +KASAN_GRANULE_SIZE );if (IS_ENABLED (CONFIG_KASAN_SW_TAGS )) tag =assign_tag (cache, object, false, keep_tag);
@@ -486,7 +486,7 @@ void * __must_check kasan_kmalloc_large(const void *ptr, size_t size, page =virt_to_page (ptr); redzone_start =round_up ((unsigned long )(ptr + size), -KASAN_SHADOW_SCALE_SIZE ); +KASAN_GRANULE_SIZE ); redzone_end = (unsigned long )ptr +page_size (page);kasan_unpoison_memory (ptr, size);
@@ -584,8 +584,8 @@ static int __meminit kasan_mem_notifier(struct notifier_block *nb, shadow_size = nr_shadow_pages <<PAGE_SHIFT ; shadow_end = shadow_start + shadow_size; -if (WARN_ON (mem_data->nr_pages %KASAN_SHADOW_SCALE_SIZE ) || -WARN_ON (start_kaddr % (KASAN_SHADOW_SCALE_SIZE <<PAGE_SHIFT ))) +if (WARN_ON (mem_data->nr_pages %KASAN_GRANULE_SIZE ) || +WARN_ON (start_kaddr % (KASAN_GRANULE_SIZE <<PAGE_SHIFT )))return NOTIFY_BAD ;switch (action) {
@@ -743,7 +743,7 @@ void kasan_poison_vmalloc(const void *start, unsigned long size)if (!is_vmalloc_or_module_addr (start))return ; - size =round_up (size,KASAN_SHADOW_SCALE_SIZE ); + size =round_up (size,KASAN_GRANULE_SIZE );kasan_poison_memory (start, size,KASAN_VMALLOC_INVALID ); }
@@ -856,22 +856,22 @@ void kasan_release_vmalloc(unsigned long start, unsigned long end,unsigned long region_start, region_end;unsigned long size; - region_start =ALIGN (start,PAGE_SIZE *KASAN_SHADOW_SCALE_SIZE ); - region_end =ALIGN_DOWN (end,PAGE_SIZE *KASAN_SHADOW_SCALE_SIZE ); + region_start =ALIGN (start,PAGE_SIZE *KASAN_GRANULE_SIZE ); + region_end =ALIGN_DOWN (end,PAGE_SIZE *KASAN_GRANULE_SIZE ); free_region_start =ALIGN (free_region_start, -PAGE_SIZE *KASAN_SHADOW_SCALE_SIZE ); +PAGE_SIZE *KASAN_GRANULE_SIZE );if (start != region_start && free_region_start < region_start) - region_start -=PAGE_SIZE *KASAN_SHADOW_SCALE_SIZE ; + region_start -=PAGE_SIZE *KASAN_GRANULE_SIZE ; free_region_end =ALIGN_DOWN (free_region_end, -PAGE_SIZE *KASAN_SHADOW_SCALE_SIZE ); +PAGE_SIZE *KASAN_GRANULE_SIZE );if (end != region_end && free_region_end > region_end) - region_end +=PAGE_SIZE *KASAN_SHADOW_SCALE_SIZE ; + region_end +=PAGE_SIZE *KASAN_GRANULE_SIZE ; shadow_start =kasan_mem_to_shadow ((void *)region_start); shadow_end =kasan_mem_to_shadow ((void *)region_end);
@@ -897,7 +897,8 @@ int kasan_module_alloc(void *addr, size_t size)unsigned long shadow_start; shadow_start = (unsigned long )kasan_mem_to_shadow (addr); - scaled_size = (size +KASAN_SHADOW_MASK ) >>KASAN_SHADOW_SCALE_SHIFT ; + scaled_size = (size +KASAN_GRANULE_SIZE -1 ) >> +KASAN_SHADOW_SCALE_SHIFT ; shadow_size =round_up (scaled_size,PAGE_SIZE );if (WARN_ON (!PAGE_ALIGNED (shadow_start)))
mm/kasan/generic.c +7 -7
@@ -46,7 +46,7 @@ static __always_inline bool memory_is_poisoned_1(unsigned long addr)s8 shadow_value = *(s8 *)kasan_mem_to_shadow ((void *)addr);if (unlikely (shadow_value)) { -s8 last_accessible_byte = addr &KASAN_SHADOW_MASK ; +s8 last_accessible_byte = addr &KASAN_GRANULE_MASK ;return unlikely (last_accessible_byte >= shadow_value); }
@@ -62,7 +62,7 @@ static __always_inline bool memory_is_poisoned_2_4_8(unsigned long addr,* Access crosses 8(shadow size)-byte boundary. Such access maps * into 2 shadow bytes, so we need to check them both. */ -if (unlikely (((addr + size -1 ) &KASAN_SHADOW_MASK ) < size -1 )) +if (unlikely (((addr + size -1 ) &KASAN_GRANULE_MASK ) < size -1 ))return *shadow_addr ||memory_is_poisoned_1 (addr + size -1 );return memory_is_poisoned_1 (addr + size -1 );
@@ -73,7 +73,7 @@ static __always_inline bool memory_is_poisoned_16(unsigned long addr)u16 *shadow_addr = (u16 *)kasan_mem_to_shadow ((void *)addr);/* Unaligned 16-bytes access maps into 3 shadow bytes. */ -if (unlikely (!IS_ALIGNED (addr,KASAN_SHADOW_SCALE_SIZE ))) +if (unlikely (!IS_ALIGNED (addr,KASAN_GRANULE_SIZE )))return *shadow_addr ||memory_is_poisoned_1 (addr +15 );return *shadow_addr;
@@ -134,7 +134,7 @@ static __always_inline bool memory_is_poisoned_n(unsigned long addr,s8 *last_shadow = (s8 *)kasan_mem_to_shadow ((void *)last_byte);if (unlikely (ret != (unsigned long )last_shadow || - ((long )(last_byte &KASAN_SHADOW_MASK ) >= *last_shadow))) + ((long )(last_byte &KASAN_GRANULE_MASK ) >= *last_shadow)))return true; }return false;
@@ -200,7 +200,7 @@ void kasan_cache_shutdown(struct kmem_cache *cache)static void register_global (struct kasan_global *global) { -size_t aligned_size =round_up (global->size,KASAN_SHADOW_SCALE_SIZE ); +size_t aligned_size =round_up (global->size,KASAN_GRANULE_SIZE );kasan_unpoison_memory (global->beg, global->size);
@@ -274,10 +274,10 @@ EXPORT_SYMBOL(__asan_handle_no_return);/* Emitted by compiler to poison alloca()ed objects. */ void __asan_alloca_poison (unsigned long addr,size_t size) { -size_t rounded_up_size =round_up (size,KASAN_SHADOW_SCALE_SIZE ); +size_t rounded_up_size =round_up (size,KASAN_GRANULE_SIZE );size_t padding_size =round_up (size,KASAN_ALLOCA_REDZONE_SIZE ) - rounded_up_size; -size_t rounded_down_size =round_down (size,KASAN_SHADOW_SCALE_SIZE ); +size_t rounded_down_size =round_down (size,KASAN_GRANULE_SIZE );const void *left_redzone = (const void *)(addr -KASAN_ALLOCA_REDZONE_SIZE );
mm/kasan/generic_report.c +4 -4
@@ -34,7 +34,7 @@ void *find_first_bad_addr(void *addr, size_t size)void *p = addr;while (p < addr + size && !(*(u8 *)kasan_mem_to_shadow (p))) - p +=KASAN_SHADOW_SCALE_SIZE ; + p +=KASAN_GRANULE_SIZE ;return p; }
@@ -46,14 +46,14 @@ static const char *get_shadow_bug_type(struct kasan_access_info *info) shadow_addr = (u8 *)kasan_mem_to_shadow (info->first_bad_addr);/* -* If shadow byte value is in [0, KASAN_SHADOW_SCALE_SIZE) we can look +* If shadow byte value is in [0, KASAN_GRANULE_SIZE) we can look * at the next shadow byte to determine the type of the bad access. */ -if (*shadow_addr >0 && *shadow_addr <=KASAN_SHADOW_SCALE_SIZE -1 ) +if (*shadow_addr >0 && *shadow_addr <=KASAN_GRANULE_SIZE -1 ) shadow_addr++;switch (*shadow_addr) { - case 0 ... KASAN_SHADOW_SCALE_SIZE - 1: + case 0 ... KASAN_GRANULE_SIZE - 1:/* * In theory it's still possible to see these shadow values * due to a data race in the kernel code.
mm/kasan/init.c +4 -4
@@ -442,8 +442,8 @@ void kasan_remove_zero_shadow(void *start, unsigned long size) end = addr + (size >>KASAN_SHADOW_SCALE_SHIFT );if (WARN_ON ((unsigned long )start % - (KASAN_SHADOW_SCALE_SIZE *PAGE_SIZE )) || -WARN_ON (size % (KASAN_SHADOW_SCALE_SIZE *PAGE_SIZE ))) + (KASAN_GRANULE_SIZE *PAGE_SIZE )) || +WARN_ON (size % (KASAN_GRANULE_SIZE *PAGE_SIZE )))return ;for (; addr < end; addr = next) {
@@ -477,8 +477,8 @@ int kasan_add_zero_shadow(void *start, unsigned long size) shadow_end = shadow_start + (size >>KASAN_SHADOW_SCALE_SHIFT );if (WARN_ON ((unsigned long )start % - (KASAN_SHADOW_SCALE_SIZE *PAGE_SIZE )) || -WARN_ON (size % (KASAN_SHADOW_SCALE_SIZE *PAGE_SIZE ))) + (KASAN_GRANULE_SIZE *PAGE_SIZE )) || +WARN_ON (size % (KASAN_GRANULE_SIZE *PAGE_SIZE )))return -EINVAL ; ret =kasan_populate_early_shadow (shadow_start, shadow_end);
mm/kasan/kasan.h +2 -2
@@ -5,8 +5,8 @@#include <linux/kasan.h> #include <linux/stackdepot.h> -#define KASAN_SHADOW_SCALE_SIZE (1UL << KASAN_SHADOW_SCALE_SHIFT) -#define KASAN_SHADOW_MASK (KASAN_SHADOW_SCALE_SIZE - 1) +#define KASAN_GRANULE_SIZE (1UL << KASAN_SHADOW_SCALE_SHIFT) +#define KASAN_GRANULE_MASK (KASAN_GRANULE_SIZE - 1)#define KASAN_TAG_KERNEL 0xFF/* native kernel pointers tag */ #define KASAN_TAG_INVALID 0xFE/* inaccessible memory tag */
mm/kasan/report.c +5 -5
@@ -312,24 +312,24 @@ static bool __must_check get_address_stack_frame_info(const void *addr,return false; aligned_addr =round_down ((unsigned long )addr,sizeof (long )); - mem_ptr =round_down (aligned_addr,KASAN_SHADOW_SCALE_SIZE ); + mem_ptr =round_down (aligned_addr,KASAN_GRANULE_SIZE ); shadow_ptr =kasan_mem_to_shadow ((void *)aligned_addr); shadow_bottom =kasan_mem_to_shadow (end_of_stack (current));while (shadow_ptr >= shadow_bottom && *shadow_ptr !=KASAN_STACK_LEFT ) { shadow_ptr--; - mem_ptr -=KASAN_SHADOW_SCALE_SIZE ; + mem_ptr -=KASAN_GRANULE_SIZE ; }while (shadow_ptr >= shadow_bottom && *shadow_ptr ==KASAN_STACK_LEFT ) { shadow_ptr--; - mem_ptr -=KASAN_SHADOW_SCALE_SIZE ; + mem_ptr -=KASAN_GRANULE_SIZE ; }if (shadow_ptr < shadow_bottom)return false; - frame = (const unsigned long *)(mem_ptr +KASAN_SHADOW_SCALE_SIZE ); + frame = (const unsigned long *)(mem_ptr +KASAN_GRANULE_SIZE );if (frame[0 ] !=KASAN_CURRENT_STACK_FRAME_MAGIC ) {pr_err ("KASAN internal error: frame info validation failed; invalid marker: %lu\n" , frame[0 ]);
@@ -567,6 +567,6 @@ void kasan_non_canonical_hook(unsigned long addr) else bug_type ="maybe wild-memory-access" ;pr_alert ("KASAN: %s in range [0x%016lx-0x%016lx]\n" , bug_type, - orig_addr, orig_addr + KASAN_SHADOW_MASK); + orig_addr, orig_addr + KASAN_GRANULE_SIZE - 1); }#endif
mm/kasan/tags_report.c +1 -1
@@ -76,7 +76,7 @@ void *find_first_bad_addr(void *addr, size_t size)void *end = p + size;while (p < end && tag == *(u8 *)kasan_mem_to_shadow (p)) - p +=KASAN_SHADOW_SCALE_SIZE ; + p +=KASAN_GRANULE_SIZE ;return p; }
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 06/39] kasan: rename KASAN_SHADOW_* to KASAN_GRANULE_*
Quoted 12 lines · Andrey Konovalov
This is a preparatory commit for the upcoming addition of a new hardware tag-based (MTE-based) KASAN mode.
The new mode won't be using shadow memory, but will still use the concept of memory granules. Each memory granule maps to a single metadata entry:
8 bytes per one shadow byte for generic mode, 16 bytes per one shadow byte for software tag-based mode, and 16 bytes per one allocation tag for hardware tag-based mode.Rename
KASAN_SHADOW_SCALE_SIZEtoKASAN_GRANULE_SIZE, andKASAN_SHADOW_MASKtoKASAN_GRANULE_MASK.
Quoted 6 lines
Also use MASK when used as a mask, otherwise use SIZE.
No functional changes.
Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>
Quoted 367 lines
---
Change-Id: Iac733e2248aa9d29f6fc425d8946ba07cca73ecf--- Documentation/dev-tools/kasan.rst | 2 +- lib/test_kasan.c | 2 +- mm/kasan/common.c | 39 ++++++++++++++++--------------- mm/kasan/generic.c | 14 +++++------ mm/kasan/generic_report.c | 8 +++---- mm/kasan/init.c | 8 +++---- mm/kasan/kasan.h | 4 ++-- mm/kasan/report.c | 10 ++++---- mm/kasan/tags_report.c | 2 +- 9 files changed, 45 insertions(+), 44 deletions(-)Documentation/dev-tools/kasan.rst +1
-1@@ -264,7 +264,7 @@ Most mappings in vmalloc space are small, requiring less than a full page of shadow space. Allocating a full shadow page per mapping would therefore be wasteful. Furthermore, to ensure that different mappings use different shadow pages, mappings would have to be aligned to -``KASAN_SHADOW_SCALE_SIZE * PAGE_SIZE``. +``KASAN_GRANULE_SIZE * PAGE_SIZE``. Instead, we share backing space across multiple mappings. We allocate a backing page when a mapping in vmalloc space uses a particular pagelib/test_kasan.c +1
-1@@ -25,7 +25,7 @@#include "../mm/kasan/kasan.h" -#define OOB_TAG_OFF (IS_ENABLED(CONFIG_KASAN_GENERIC) ? 0 : KASAN_SHADOW_SCALE_SIZE) +#define OOB_TAG_OFF (IS_ENABLED(CONFIG_KASAN_GENERIC) ? 0 : KASAN_GRANULE_SIZE)/* * We assign some test results to these globals to make sure the tests mm/kasan/common.c +20
-19@@ -106,7 +106,7 @@ void *memcpy(void *dest, const void *src, size_t len)/* * Poisons the shadow memory for 'size' bytes starting from 'addr'. -* Memory addresses should be aligned to KASAN_SHADOW_SCALE_SIZE. +* Memory addresses should be aligned to KASAN_GRANULE_SIZE. */ void kasan_poison_memory (const void *address,size_t size,u8 value) {@@ -138,13 +138,13 @@ void kasan_unpoison_memory(const void *address, size_t size)kasan_poison_memory (address, size, tag); -if (size &KASAN_SHADOW_MASK ) { +if (size &KASAN_GRANULE_MASK ) {u8 *shadow = (u8 *)kasan_mem_to_shadow (address + size);if (IS_ENABLED (CONFIG_KASAN_SW_TAGS )) *shadow = tag;else - *shadow = size &KASAN_SHADOW_MASK ; + *shadow = size &KASAN_GRANULE_MASK ; } }@@ -296,7 +296,7 @@ void kasan_unpoison_object_data(struct kmem_cache *cache, void *object)void kasan_poison_object_data (struct kmem_cache *cache,void *object) {kasan_poison_memory (object, -round_up (cache->object_size,KASAN_SHADOW_SCALE_SIZE ), +round_up (cache->object_size,KASAN_GRANULE_SIZE ),KASAN_KMALLOC_REDZONE ); }@@ -368,7 +368,7 @@ static inline bool shadow_invalid(u8 tag, s8 shadow_byte) {if (IS_ENABLED (CONFIG_KASAN_GENERIC ))return shadow_byte <0 || - shadow_byte >=KASAN_SHADOW_SCALE_SIZE ; + shadow_byte >=KASAN_GRANULE_SIZE ;/* else CONFIG_KASAN_SW_TAGS: */ if ((u8 )shadow_byte ==KASAN_TAG_INVALID )@@ -407,7 +407,7 @@ static bool __kasan_slab_free(struct kmem_cache *cache, void *object,return true; } - rounded_up_size =round_up (cache->object_size,KASAN_SHADOW_SCALE_SIZE ); + rounded_up_size =round_up (cache->object_size,KASAN_GRANULE_SIZE );kasan_poison_memory (object, rounded_up_size,KASAN_KMALLOC_FREE ); if ((IS_ENABLED(CONFIG_KASAN_GENERIC) && !quarantine) ||@@ -440,9 +440,9 @@ static void *__kasan_kmalloc(struct kmem_cache *cache, const void *object,return NULL ; redzone_start =round_up ((unsigned long )(object + size), -KASAN_SHADOW_SCALE_SIZE ); +KASAN_GRANULE_SIZE ); redzone_end =round_up ((unsigned long )object + cache->object_size, -KASAN_SHADOW_SCALE_SIZE ); +KASAN_GRANULE_SIZE );if (IS_ENABLED (CONFIG_KASAN_SW_TAGS )) tag =assign_tag (cache, object, false, keep_tag);@@ -486,7 +486,7 @@ void * __must_check kasan_kmalloc_large(const void *ptr, size_t size, page =virt_to_page (ptr); redzone_start =round_up ((unsigned long )(ptr + size), -KASAN_SHADOW_SCALE_SIZE ); +KASAN_GRANULE_SIZE ); redzone_end = (unsigned long )ptr +page_size (page);kasan_unpoison_memory (ptr, size);@@ -584,8 +584,8 @@ static int __meminit kasan_mem_notifier(struct notifier_block *nb, shadow_size = nr_shadow_pages <<PAGE_SHIFT ; shadow_end = shadow_start + shadow_size; -if (WARN_ON (mem_data->nr_pages %KASAN_SHADOW_SCALE_SIZE ) || -WARN_ON (start_kaddr % (KASAN_SHADOW_SCALE_SIZE <<PAGE_SHIFT ))) +if (WARN_ON (mem_data->nr_pages %KASAN_GRANULE_SIZE ) || +WARN_ON (start_kaddr % (KASAN_GRANULE_SIZE <<PAGE_SHIFT )))return NOTIFY_BAD ;switch (action) {@@ -743,7 +743,7 @@ void kasan_poison_vmalloc(const void *start, unsigned long size)if (!is_vmalloc_or_module_addr (start))return ; - size =round_up (size,KASAN_SHADOW_SCALE_SIZE ); + size =round_up (size,KASAN_GRANULE_SIZE );kasan_poison_memory (start, size,KASAN_VMALLOC_INVALID ); }@@ -856,22 +856,22 @@ void kasan_release_vmalloc(unsigned long start, unsigned long end,unsigned long region_start, region_end;unsigned long size; - region_start =ALIGN (start,PAGE_SIZE *KASAN_SHADOW_SCALE_SIZE ); - region_end =ALIGN_DOWN (end,PAGE_SIZE *KASAN_SHADOW_SCALE_SIZE ); + region_start =ALIGN (start,PAGE_SIZE *KASAN_GRANULE_SIZE ); + region_end =ALIGN_DOWN (end,PAGE_SIZE *KASAN_GRANULE_SIZE ); free_region_start =ALIGN (free_region_start, -PAGE_SIZE *KASAN_SHADOW_SCALE_SIZE ); +PAGE_SIZE *KASAN_GRANULE_SIZE );if (start != region_start && free_region_start < region_start) - region_start -=PAGE_SIZE *KASAN_SHADOW_SCALE_SIZE ; + region_start -=PAGE_SIZE *KASAN_GRANULE_SIZE ; free_region_end =ALIGN_DOWN (free_region_end, -PAGE_SIZE *KASAN_SHADOW_SCALE_SIZE ); +PAGE_SIZE *KASAN_GRANULE_SIZE );if (end != region_end && free_region_end > region_end) - region_end +=PAGE_SIZE *KASAN_SHADOW_SCALE_SIZE ; + region_end +=PAGE_SIZE *KASAN_GRANULE_SIZE ; shadow_start =kasan_mem_to_shadow ((void *)region_start); shadow_end =kasan_mem_to_shadow ((void *)region_end);@@ -897,7 +897,8 @@ int kasan_module_alloc(void *addr, size_t size)unsigned long shadow_start; shadow_start = (unsigned long )kasan_mem_to_shadow (addr); - scaled_size = (size +KASAN_SHADOW_MASK ) >>KASAN_SHADOW_SCALE_SHIFT ; + scaled_size = (size +KASAN_GRANULE_SIZE -1 ) >> +KASAN_SHADOW_SCALE_SHIFT ; shadow_size =round_up (scaled_size,PAGE_SIZE );if (WARN_ON (!PAGE_ALIGNED (shadow_start)))mm/kasan/generic.c +7
-7@@ -46,7 +46,7 @@ static __always_inline bool memory_is_poisoned_1(unsigned long addr)s8 shadow_value = *(s8 *)kasan_mem_to_shadow ((void *)addr);if (unlikely (shadow_value)) { -s8 last_accessible_byte = addr &KASAN_SHADOW_MASK ; +s8 last_accessible_byte = addr &KASAN_GRANULE_MASK ;return unlikely (last_accessible_byte >= shadow_value); }@@ -62,7 +62,7 @@ static __always_inline bool memory_is_poisoned_2_4_8(unsigned long addr,* Access crosses 8(shadow size)-byte boundary. Such access maps * into 2 shadow bytes, so we need to check them both. */ -if (unlikely (((addr + size -1 ) &KASAN_SHADOW_MASK ) < size -1 )) +if (unlikely (((addr + size -1 ) &KASAN_GRANULE_MASK ) < size -1 ))return *shadow_addr ||memory_is_poisoned_1 (addr + size -1 );return memory_is_poisoned_1 (addr + size -1 );@@ -73,7 +73,7 @@ static __always_inline bool memory_is_poisoned_16(unsigned long addr)u16 *shadow_addr = (u16 *)kasan_mem_to_shadow ((void *)addr);/* Unaligned 16-bytes access maps into 3 shadow bytes. */ -if (unlikely (!IS_ALIGNED (addr,KASAN_SHADOW_SCALE_SIZE ))) +if (unlikely (!IS_ALIGNED (addr,KASAN_GRANULE_SIZE )))return *shadow_addr ||memory_is_poisoned_1 (addr +15 );return *shadow_addr;@@ -134,7 +134,7 @@ static __always_inline bool memory_is_poisoned_n(unsigned long addr,s8 *last_shadow = (s8 *)kasan_mem_to_shadow ((void *)last_byte);if (unlikely (ret != (unsigned long )last_shadow || - ((long )(last_byte &KASAN_SHADOW_MASK ) >= *last_shadow))) + ((long )(last_byte &KASAN_GRANULE_MASK ) >= *last_shadow)))return true; }return false;@@ -200,7 +200,7 @@ void kasan_cache_shutdown(struct kmem_cache *cache)static void register_global (struct kasan_global *global) { -size_t aligned_size =round_up (global->size,KASAN_SHADOW_SCALE_SIZE ); +size_t aligned_size =round_up (global->size,KASAN_GRANULE_SIZE );kasan_unpoison_memory (global->beg, global->size);@@ -274,10 +274,10 @@ EXPORT_SYMBOL(__asan_handle_no_return);/* Emitted by compiler to poison alloca()ed objects. */ void __asan_alloca_poison (unsigned long addr,size_t size) { -size_t rounded_up_size =round_up (size,KASAN_SHADOW_SCALE_SIZE ); +size_t rounded_up_size =round_up (size,KASAN_GRANULE_SIZE );size_t padding_size =round_up (size,KASAN_ALLOCA_REDZONE_SIZE ) - rounded_up_size; -size_t rounded_down_size =round_down (size,KASAN_SHADOW_SCALE_SIZE ); +size_t rounded_down_size =round_down (size,KASAN_GRANULE_SIZE );const void *left_redzone = (const void *)(addr -KASAN_ALLOCA_REDZONE_SIZE );mm/kasan/generic_report.c +4
-4@@ -34,7 +34,7 @@ void *find_first_bad_addr(void *addr, size_t size)void *p = addr;while (p < addr + size && !(*(u8 *)kasan_mem_to_shadow (p))) - p +=KASAN_SHADOW_SCALE_SIZE ; + p +=KASAN_GRANULE_SIZE ;return p; }@@ -46,14 +46,14 @@ static const char *get_shadow_bug_type(struct kasan_access_info *info) shadow_addr = (u8 *)kasan_mem_to_shadow (info->first_bad_addr);/* -* If shadow byte value is in [0, KASAN_SHADOW_SCALE_SIZE) we can look +* If shadow byte value is in [0, KASAN_GRANULE_SIZE) we can look * at the next shadow byte to determine the type of the bad access. */ -if (*shadow_addr >0 && *shadow_addr <=KASAN_SHADOW_SCALE_SIZE -1 ) +if (*shadow_addr >0 && *shadow_addr <=KASAN_GRANULE_SIZE -1 ) shadow_addr++;switch (*shadow_addr) { - case 0 ... KASAN_SHADOW_SCALE_SIZE - 1: + case 0 ... KASAN_GRANULE_SIZE - 1:/* * In theory it's still possible to see these shadow values * due to a data race in the kernel code. mm/kasan/init.c +4
-4@@ -442,8 +442,8 @@ void kasan_remove_zero_shadow(void *start, unsigned long size) end = addr + (size >>KASAN_SHADOW_SCALE_SHIFT );if (WARN_ON ((unsigned long )start % - (KASAN_SHADOW_SCALE_SIZE *PAGE_SIZE )) || -WARN_ON (size % (KASAN_SHADOW_SCALE_SIZE *PAGE_SIZE ))) + (KASAN_GRANULE_SIZE *PAGE_SIZE )) || +WARN_ON (size % (KASAN_GRANULE_SIZE *PAGE_SIZE )))return ;for (; addr < end; addr = next) {@@ -477,8 +477,8 @@ int kasan_add_zero_shadow(void *start, unsigned long size) shadow_end = shadow_start + (size >>KASAN_SHADOW_SCALE_SHIFT );if (WARN_ON ((unsigned long )start % - (KASAN_SHADOW_SCALE_SIZE *PAGE_SIZE )) || -WARN_ON (size % (KASAN_SHADOW_SCALE_SIZE *PAGE_SIZE ))) + (KASAN_GRANULE_SIZE *PAGE_SIZE )) || +WARN_ON (size % (KASAN_GRANULE_SIZE *PAGE_SIZE )))return -EINVAL ; ret =kasan_populate_early_shadow (shadow_start, shadow_end);mm/kasan/kasan.h +2
-2@@ -5,8 +5,8 @@#include <linux/kasan.h> #include <linux/stackdepot.h> -#define KASAN_SHADOW_SCALE_SIZE (1UL << KASAN_SHADOW_SCALE_SHIFT) -#define KASAN_SHADOW_MASK (KASAN_SHADOW_SCALE_SIZE - 1) +#define KASAN_GRANULE_SIZE (1UL << KASAN_SHADOW_SCALE_SHIFT) +#define KASAN_GRANULE_MASK (KASAN_GRANULE_SIZE - 1)#define KASAN_TAG_KERNEL 0xFF/* native kernel pointers tag */ #define KASAN_TAG_INVALID 0xFE/* inaccessible memory tag */ mm/kasan/report.c +5
-5@@ -312,24 +312,24 @@ static bool __must_check get_address_stack_frame_info(const void *addr,return false; aligned_addr =round_down ((unsigned long )addr,sizeof (long )); - mem_ptr =round_down (aligned_addr,KASAN_SHADOW_SCALE_SIZE ); + mem_ptr =round_down (aligned_addr,KASAN_GRANULE_SIZE ); shadow_ptr =kasan_mem_to_shadow ((void *)aligned_addr); shadow_bottom =kasan_mem_to_shadow (end_of_stack (current));while (shadow_ptr >= shadow_bottom && *shadow_ptr !=KASAN_STACK_LEFT ) { shadow_ptr--; - mem_ptr -=KASAN_SHADOW_SCALE_SIZE ; + mem_ptr -=KASAN_GRANULE_SIZE ; }while (shadow_ptr >= shadow_bottom && *shadow_ptr ==KASAN_STACK_LEFT ) { shadow_ptr--; - mem_ptr -=KASAN_SHADOW_SCALE_SIZE ; + mem_ptr -=KASAN_GRANULE_SIZE ; }if (shadow_ptr < shadow_bottom)return false; - frame = (const unsigned long *)(mem_ptr +KASAN_SHADOW_SCALE_SIZE ); + frame = (const unsigned long *)(mem_ptr +KASAN_GRANULE_SIZE );if (frame[0 ] !=KASAN_CURRENT_STACK_FRAME_MAGIC ) {pr_err ("KASAN internal error: frame info validation failed; invalid marker: %lu\n" , frame[0 ]);@@ -567,6 +567,6 @@ void kasan_non_canonical_hook(unsigned long addr) else bug_type ="maybe wild-memory-access" ;pr_alert ("KASAN: %s in range [0x%016lx-0x%016lx]\n" , bug_type, - orig_addr, orig_addr + KASAN_SHADOW_MASK); + orig_addr, orig_addr + KASAN_GRANULE_SIZE - 1); }#endif mm/kasan/tags_report.c +1
-1@@ -76,7 +76,7 @@ void *find_first_bad_addr(void *addr, size_t size)void *end = p + size;while (p < end && tag == *(u8 *)kasan_mem_to_shadow (p)) - p +=KASAN_SHADOW_SCALE_SIZE ; + p +=KASAN_GRANULE_SIZE ;return p; }Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
PATCH v3 7/39 kasan: only build init.c for software modes
In reply to Andrey KonovalovThis is a preparatory commit for the upcoming addition of a new hardware tag-based (MTE-based) KASAN mode.
The new mode won't be using shadow memory, so only build init.c that contains shadow initialization code for software modes.
No functional changes for software modes.
---
Change-Id: I8d68c47345afc1dbedadde738f34a874dcae5080
--- mm/kasan/Makefile | 6 +++--- mm/kasan/init.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-)
mm/kasan/Makefile +3 -3
@@ -29,6 +29,6 @@ CFLAGS_report.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_tags.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_tags_report.o := $(CC_FLAGS_KASAN_RUNTIME) -obj-$(CONFIG_KASAN) := common.o init.o report.o -obj-$(CONFIG_KASAN_GENERIC) += generic.o generic_report.o quarantine.o -obj-$(CONFIG_KASAN_SW_TAGS) += tags.o tags_report.o +obj-$(CONFIG_KASAN) := common.o report.o +obj-$(CONFIG_KASAN_GENERIC) += init.o generic.o generic_report.o quarantine.o +obj-$(CONFIG_KASAN_SW_TAGS) += init.o tags.o tags_report.o
mm/kasan/init.c +1 -1
@@ -1,6 +1,6 @@// SPDX-License-Identifier: GPL-2.0 /* -* This file contains some kasan initialization code. +* This file contains KASAN shadow initialization code. * * Copyright (c) 2015 Samsung Electronics Co., Ltd. * Author: Andrey Ryabinin <[email protected]>
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 07/39] kasan: only build init.c for software modes
Quoted 10 lines · Andrey Konovalov
This is a preparatory commit for the upcoming addition of a new hardware tag-based (MTE-based) KASAN mode.
The new mode won't be using shadow memory, so only build
init.cthat contains shadow initialization code for software modes.No functional changes for software modes.
Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>
Quoted 36 lines
---
Change-Id: I8d68c47345afc1dbedadde738f34a874dcae5080--- mm/kasan/Makefile | 6 +++--- mm/kasan/init.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-)mm/kasan/Makefile +3
-3@@ -29,6 +29,6 @@ CFLAGS_report.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_tags.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_tags_report.o := $(CC_FLAGS_KASAN_RUNTIME) -obj-$(CONFIG_KASAN) := common.o init.o report.o -obj-$(CONFIG_KASAN_GENERIC) += generic.o generic_report.o quarantine.o -obj-$(CONFIG_KASAN_SW_TAGS) += tags.o tags_report.o +obj-$(CONFIG_KASAN) := common.o report.o +obj-$(CONFIG_KASAN_GENERIC) += init.o generic.o generic_report.o quarantine.o +obj-$(CONFIG_KASAN_SW_TAGS) += init.o tags.o tags_report.omm/kasan/init.c +1
-1@@ -1,6 +1,6 @@// SPDX-License-Identifier: GPL-2.0 /* -* This file contains some kasan initialization code. +* This file contains KASAN shadow initialization code. * * Copyright (c) 2015 Samsung Electronics Co., Ltd. * Author: Andrey Ryabinin <[email protected]> Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
PATCH v3 8/39 kasan: split out shadow.c from common.c
In reply to Andrey KonovalovThis is a preparatory commit for the upcoming addition of a new hardware tag-based (MTE-based) KASAN mode.
The new mode won't be using shadow memory. Move all shadow-related code to shadow.c, which is only enabled for software KASAN modes that use shadow memory.
No functional changes for software modes.
---
Change-Id: Ic1c32ce72d4649848e9e6a1f2c8dd269c77673f2
--- mm/kasan/Makefile | 6 +- mm/kasan/common.c | 486 +------------------------------------------- mm/kasan/shadow.c | 505 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 510 insertions(+), 487 deletions(-) create mode 100644 mm/kasan/shadow.c
mm/kasan/Makefile +4 -2
@@ -10,6 +10,7 @@ CFLAGS_REMOVE_generic_report.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_init.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_quarantine.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_report.o = $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_shadow.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_tags.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_tags_report.o = $(CC_FLAGS_FTRACE)
@@ -26,9 +27,10 @@ CFLAGS_generic_report.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_init.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_quarantine.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_report.o := $(CC_FLAGS_KASAN_RUNTIME) +CFLAGS_shadow.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_tags.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_tags_report.o := $(CC_FLAGS_KASAN_RUNTIME) obj-$(CONFIG_KASAN) := common.o report.o -obj-$(CONFIG_KASAN_GENERIC) += init.o generic.o generic_report.o quarantine.o -obj-$(CONFIG_KASAN_SW_TAGS) += init.o tags.o tags_report.o +obj-$(CONFIG_KASAN_GENERIC) += init.o generic.o generic_report.o shadow.o quarantine.o +obj-$(CONFIG_KASAN_SW_TAGS) += init.o shadow.o tags.o tags_report.o
mm/kasan/common.c +1 -485
514 lines not on this page · raw message
mm/kasan/shadow.c new file +505 -0
505 lines not on this page · raw message
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 08/39] kasan: split out shadow.c from common.c
Quoted 11 lines · Andrey Konovalov
This is a preparatory commit for the upcoming addition of a new hardware tag-based (MTE-based) KASAN mode.
The new mode won't be using shadow memory. Move all shadow-related code to
shadow.c, which is only enabled for software KASAN modes that use shadow memory.No functional changes for software modes.
Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>
Quoted 1,071 lines
---
Change-Id: Ic1c32ce72d4649848e9e6a1f2c8dd269c77673f2--- mm/kasan/Makefile | 6 +- mm/kasan/common.c | 486 +------------------------------------------- mm/kasan/shadow.c | 505 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 510 insertions(+), 487 deletions(-) create mode 100644 mm/kasan/shadow.cmm/kasan/Makefile +4
-2@@ -10,6 +10,7 @@ CFLAGS_REMOVE_generic_report.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_init.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_quarantine.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_report.o = $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_shadow.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_tags.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_tags_report.o = $(CC_FLAGS_FTRACE)@@ -26,9 +27,10 @@ CFLAGS_generic_report.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_init.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_quarantine.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_report.o := $(CC_FLAGS_KASAN_RUNTIME) +CFLAGS_shadow.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_tags.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_tags_report.o := $(CC_FLAGS_KASAN_RUNTIME) obj-$(CONFIG_KASAN) := common.o report.o -obj-$(CONFIG_KASAN_GENERIC) += init.o generic.o generic_report.o quarantine.o -obj-$(CONFIG_KASAN_SW_TAGS) += init.o tags.o tags_report.o +obj-$(CONFIG_KASAN_GENERIC) += init.o generic.o generic_report.o shadow.o quarantine.o +obj-$(CONFIG_KASAN_SW_TAGS) += init.o shadow.o tags.o tags_report.omm/kasan/common.c +1
-485@@ -1,6 +1,6 @@// SPDX-License-Identifier: GPL-2.0 /* -* This file contains common generic and tag-based KASAN code. +* This file contains common KASAN code. * * Copyright (c) 2014 Samsung Electronics Co., Ltd. * Author: Andrey Ryabinin <[email protected]> @@ -13,7 +13,6 @@#include <linux/init.h> #include <linux/kasan.h> #include <linux/kernel.h> -#include <linux/kmemleak.h> #include <linux/linkage.h> #include <linux/memblock.h> #include <linux/memory.h> @@ -26,12 +25,8 @@#include <linux/stacktrace.h> #include <linux/string.h> #include <linux/types.h> -#include <linux/vmalloc.h> #include <linux/bug.h> -#include <asm/cacheflush.h> -#include <asm/tlbflush.h> -#include "kasan.h" #include "../slab.h" @@ -61,93 +56,6 @@ void kasan_disable_current(void) current->kasan_depth--; } -bool __kasan_check_read (const volatile void *p,unsigned int size) -{ -return check_memory_region ((unsigned long )p, size, false, _RET_IP_); -} -EXPORT_SYMBOL (__kasan_check_read); - -bool __kasan_check_write (const volatile void *p,unsigned int size) -{ -return check_memory_region ((unsigned long )p, size, true, _RET_IP_); -} -EXPORT_SYMBOL (__kasan_check_write); - -#undef memset -void *memset (void *addr,int c,size_t len) -{ -if (!check_memory_region ((unsigned long )addr, len, true, _RET_IP_)) -return NULL ; - -return __memset (addr, c, len); -} - -#ifdef __HAVE_ARCH_MEMMOVE -#undef memmove -void *memmove (void *dest,const void *src,size_t len) -{ -if (!check_memory_region ((unsigned long )src, len, false, _RET_IP_) || - !check_memory_region ((unsigned long )dest, len, true, _RET_IP_)) -return NULL ; - -return __memmove (dest, src, len); -} -#endif - -#undef memcpy -void *memcpy (void *dest,const void *src,size_t len) -{ -if (!check_memory_region ((unsigned long )src, len, false, _RET_IP_) || - !check_memory_region ((unsigned long )dest, len, true, _RET_IP_)) -return NULL ; - -return __memcpy (dest, src, len); -} - -/* -* Poisons the shadow memory for 'size' bytes starting from 'addr'. -* Memory addresses should be aligned to KASAN_GRANULE_SIZE. -*/ -void kasan_poison_memory (const void *address,size_t size,u8 value) -{ -void *shadow_start, *shadow_end; - -/* -* Perform shadow offset calculation based on untagged address, as -* some of the callers (e.g. kasan_poison_object_data) pass tagged -* addresses to this function. -*/ - address =reset_tag (address); - - shadow_start =kasan_mem_to_shadow (address); - shadow_end =kasan_mem_to_shadow (address + size); - -__memset (shadow_start, value, shadow_end - shadow_start); -} - -void kasan_unpoison_memory (const void *address,size_t size) -{ -u8 tag =get_tag (address); - -/* -* Perform shadow offset calculation based on untagged address, as -* some of the callers (e.g. kasan_unpoison_object_data) pass tagged -* addresses to this function. -*/ - address =reset_tag (address); - -kasan_poison_memory (address, size, tag); - -if (size &KASAN_GRANULE_MASK ) { -u8 *shadow = (u8 *)kasan_mem_to_shadow (address + size); - -if (IS_ENABLED (CONFIG_KASAN_SW_TAGS )) - *shadow = tag; -else - *shadow = size &KASAN_GRANULE_MASK ; - } -} -static void __kasan_unpoison_stack (struct task_struct *task,const void *sp) {void *base =task_stack_page (task);@@ -535,395 +443,3 @@ void kasan_kfree_large(void *ptr, unsigned long ip)kasan_report_invalid_free (ptr, ip);/* The object will be poisoned by page_alloc. */ } - -#ifdef CONFIG_MEMORY_HOTPLUG -static bool shadow_mapped (unsigned long addr) -{ -pgd_t *pgd =pgd_offset_k (addr); -p4d_t *p4d; -pud_t *pud; -pmd_t *pmd; -pte_t *pte; - -if (pgd_none (*pgd)) -return false; - p4d =p4d_offset (pgd, addr); -if (p4d_none (*p4d)) -return false; - pud =pud_offset (p4d, addr); -if (pud_none (*pud)) -return false; - -/* -* We can't use pud_large() or pud_huge(), the first one is -* arch-specific, the last one depends on HUGETLB_PAGE. So let's abuse -* pud_bad(), if pud is bad then it's bad because it's huge. -*/ -if (pud_bad (*pud)) -return true; - pmd =pmd_offset (pud, addr); -if (pmd_none (*pmd)) -return false; - -if (pmd_bad (*pmd)) -return true; - pte =pte_offset_kernel (pmd, addr); -return !pte_none (*pte); -} - -static int __meminit kasan_mem_notifier (struct notifier_block *nb, -unsigned long action,void *data) -{ -struct memory_notify *mem_data = data; -unsigned long nr_shadow_pages, start_kaddr, shadow_start; -unsigned long shadow_end, shadow_size; - - nr_shadow_pages = mem_data->nr_pages >>KASAN_SHADOW_SCALE_SHIFT ; - start_kaddr = (unsigned long )pfn_to_kaddr (mem_data->start_pfn); - shadow_start = (unsigned long )kasan_mem_to_shadow ((void *)start_kaddr); - shadow_size = nr_shadow_pages <<PAGE_SHIFT ; - shadow_end = shadow_start + shadow_size; - -if (WARN_ON (mem_data->nr_pages %KASAN_GRANULE_SIZE ) || -WARN_ON (start_kaddr % (KASAN_GRANULE_SIZE <<PAGE_SHIFT ))) -return NOTIFY_BAD ; - -switch (action) { -case MEM_GOING_ONLINE : { -void *ret; - -/* -* If shadow is mapped already than it must have been mapped -* during the boot. This could happen if we onlining previously -* offlined memory. -*/ -if (shadow_mapped (shadow_start)) -return NOTIFY_OK ; - - ret =__vmalloc_node_range (shadow_size,PAGE_SIZE , shadow_start, - shadow_end,GFP_KERNEL , -PAGE_KERNEL ,VM_NO_GUARD , -pfn_to_nid (mem_data->start_pfn), -__builtin_return_address (0 )); -if (!ret) -return NOTIFY_BAD ; - -kmemleak_ignore (ret); -return NOTIFY_OK ; - } -case MEM_CANCEL_ONLINE : -case MEM_OFFLINE : { -struct vm_struct *vm; - -/* -* shadow_start was either mapped during boot by kasan_init() -* or during memory online by __vmalloc_node_range(). -* In the latter case we can use vfree() to free shadow. -* Non-NULL result of the find_vm_area() will tell us if -* that was the second case. -* -* Currently it's not possible to free shadow mapped -* during boot by kasan_init(). It's because the code -* to do that hasn't been written yet. So we'll just -* leak the memory. -*/ - vm =find_vm_area ((void *)shadow_start); -if (vm) -vfree ((void *)shadow_start); - } - } - -return NOTIFY_OK ; -} - -static int __init kasan_memhotplug_init (void ) -{ -hotplug_memory_notifier (kasan_mem_notifier,0 ); - -return 0 ; -} - -core_initcall (kasan_memhotplug_init); -#endif - -#ifdef CONFIG_KASAN_VMALLOC - -static int kasan_populate_vmalloc_pte (pte_t *ptep,unsigned long addr, -void *unused) -{ -unsigned long page; -pte_t pte; - -if (likely (!pte_none (*ptep))) -return 0 ; - - page =__get_free_page (GFP_KERNEL ); -if (!page) -return -ENOMEM ; - -memset ((void *)page,KASAN_VMALLOC_INVALID ,PAGE_SIZE ); - pte =pfn_pte (PFN_DOWN (__pa (page)),PAGE_KERNEL ); - -spin_lock (&init_mm.page_table_lock); -if (likely (pte_none (*ptep))) { -set_pte_at (&init_mm, addr, ptep, pte); - page =0 ; - } -spin_unlock (&init_mm.page_table_lock); -if (page) -free_page (page); -return 0 ; -} - -int kasan_populate_vmalloc (unsigned long addr,unsigned long size) -{ -unsigned long shadow_start, shadow_end; -int ret; - -if (!is_vmalloc_or_module_addr ((void *)addr)) -return 0 ; - - shadow_start = (unsigned long )kasan_mem_to_shadow ((void *)addr); - shadow_start =ALIGN_DOWN (shadow_start,PAGE_SIZE ); - shadow_end = (unsigned long )kasan_mem_to_shadow ((void *)addr + size); - shadow_end =ALIGN (shadow_end,PAGE_SIZE ); - - ret =apply_to_page_range (&init_mm, shadow_start, - shadow_end - shadow_start, - kasan_populate_vmalloc_pte,NULL ); -if (ret) -return ret; - -flush_cache_vmap (shadow_start, shadow_end); - -/* -* We need to be careful about inter-cpu effects here. Consider: -* -* CPU#0 CPU#1 -* WRITE_ONCE(p, vmalloc(100)); while (x = READ_ONCE(p)) ; -* p[99] = 1; -* -* With compiler instrumentation, that ends up looking like this: -* -* CPU#0 CPU#1 -* // vmalloc() allocates memory -* // let a = area->addr -* // we reach kasan_populate_vmalloc -* // and call kasan_unpoison_memory: -* STORE shadow(a), unpoison_val -* ... -* STORE shadow(a+99), unpoison_val x = LOAD p -* // rest of vmalloc process <data dependency> -* STORE p, a LOAD shadow(x+99) -* -* If there is no barrier between the end of unpoisioning the shadow -* and the store of the result to p, the stores could be committed -* in a different order by CPU#0, and CPU#1 could erroneously observe -* poison in the shadow. -* -* We need some sort of barrier between the stores. -* -* In the vmalloc() case, this is provided by a smp_wmb() in -* clear_vm_uninitialized_flag(). In the per-cpu allocator and in -* get_vm_area() and friends, the caller gets shadow allocated but -* doesn't have any pages mapped into the virtual address space that -* has been reserved. Mapping those pages in will involve taking and -* releasing a page-table lock, which will provide the barrier. -*/ - -return 0 ; -} - -/* -* Poison the shadow for a vmalloc region. Called as part of the -* freeing process at the time the region is freed. -*/ -void kasan_poison_vmalloc (const void *start,unsigned long size) -{ -if (!is_vmalloc_or_module_addr (start)) -return ; - - size =round_up (size,KASAN_GRANULE_SIZE ); -kasan_poison_memory (start, size,KASAN_VMALLOC_INVALID ); -} - -void kasan_unpoison_vmalloc (const void *start,unsigned long size) -{ -if (!is_vmalloc_or_module_addr (start)) -return ; - -kasan_unpoison_memory (start, size); -} - -static int kasan_depopulate_vmalloc_pte (pte_t *ptep,unsigned long addr, -void *unused) -{ -unsigned long page; - - page = (unsigned long )__va (pte_pfn (*ptep) <<PAGE_SHIFT ); - -spin_lock (&init_mm.page_table_lock); - -if (likely (!pte_none (*ptep))) { -pte_clear (&init_mm, addr, ptep); -free_page (page); - } -spin_unlock (&init_mm.page_table_lock); - -return 0 ; -} - -/* -* Release the backing for the vmalloc region [start, end), which -* lies within the free region [free_region_start, free_region_end). -* -* This can be run lazily, long after the region was freed. It runs -* under vmap_area_lock, so it's not safe to interact with the vmalloc/vmap -* infrastructure. -* -* How does this work? -* ------------------- -* -* We have a region that is page aligned, labelled as A. -* That might not map onto the shadow in a way that is page-aligned: -* -* start end -* v v -* |????????|????????|AAAAAAAA|AA....AA|AAAAAAAA|????????| < vmalloc -* -------- -------- -------- -------- -------- -* | | | | | -* | | | /-------/ | -* \-------\|/------/ |/---------------/ -* ||| || -* |??AAAAAA|AAAAAAAA|AA??????| < shadow -* (1) (2) (3) -* -* First we align the start upwards and the end downwards, so that the -* shadow of the region aligns with shadow page boundaries. In the -* example, this gives us the shadow page (2). This is the shadow entirely -* covered by this allocation. -* -* Then we have the tricky bits. We want to know if we can free the -* partially covered shadow pages - (1) and (3) in the example. For this, -* we are given the start and end of the free region that contains this -* allocation. Extending our previous example, we could have: -* -* free_region_start free_region_end -* | start end | -* v v v v -* |FFFFFFFF|FFFFFFFF|AAAAAAAA|AA....AA|AAAAAAAA|FFFFFFFF| < vmalloc -* -------- -------- -------- -------- -------- -* | | | | | -* | | | /-------/ | -* \-------\|/------/ |/---------------/ -* ||| || -* |FFAAAAAA|AAAAAAAA|AAF?????| < shadow -* (1) (2) (3) -* -* Once again, we align the start of the free region up, and the end of -* the free region down so that the shadow is page aligned. So we can free -* page (1) - we know no allocation currently uses anything in that page, -* because all of it is in the vmalloc free region. But we cannot free -* page (3), because we can't be sure that the rest of it is unused. -* -* We only consider pages that contain part of the original region for -* freeing: we don't try to free other pages from the free region or we'd -* end up trying to free huge chunks of virtual address space. -* -* Concurrency -* ----------- -* -* How do we know that we're not freeing a page that is simultaneously -* being used for a fresh allocation in kasan_populate_vmalloc(_pte)? -* -* We _can_ have kasan_release_vmalloc and kasan_populate_vmalloc running -* at the same time. While we run under free_vmap_area_lock, the population -* code does not. -* -* free_vmap_area_lock instead operates to ensure that the larger range -* [free_region_start, free_region_end) is safe: because __alloc_vmap_area and -* the per-cpu region-finding algorithm both run under free_vmap_area_lock, -* no space identified as free will become used while we are running. This -* means that so long as we are careful with alignment and only free shadow -* pages entirely covered by the free region, we will not run in to any -* trouble - any simultaneous allocations will be for disjoint regions. -*/ -void kasan_release_vmalloc (unsigned long start,unsigned long end, -unsigned long free_region_start, -unsigned long free_region_end) -{ -void *shadow_start, *shadow_end; -unsigned long region_start, region_end; -unsigned long size; - - region_start =ALIGN (start,PAGE_SIZE *KASAN_GRANULE_SIZE ); - region_end =ALIGN_DOWN (end,PAGE_SIZE *KASAN_GRANULE_SIZE ); - - free_region_start =ALIGN (free_region_start, -PAGE_SIZE *KASAN_GRANULE_SIZE ); - -if (start != region_start && - free_region_start < region_start) - region_start -=PAGE_SIZE *KASAN_GRANULE_SIZE ; - - free_region_end =ALIGN_DOWN (free_region_end, -PAGE_SIZE *KASAN_GRANULE_SIZE ); - -if (end != region_end && - free_region_end > region_end) - region_end +=PAGE_SIZE *KASAN_GRANULE_SIZE ; - - shadow_start =kasan_mem_to_shadow ((void *)region_start); - shadow_end =kasan_mem_to_shadow ((void *)region_end); - -if (shadow_end > shadow_start) { - size = shadow_end - shadow_start; -apply_to_existing_page_range (&init_mm, - (unsigned long )shadow_start, - size, kasan_depopulate_vmalloc_pte, -NULL ); -flush_tlb_kernel_range ((unsigned long )shadow_start, - (unsigned long )shadow_end); - } -} - -#else /* CONFIG_KASAN_VMALLOC */ - -int kasan_module_alloc (void *addr,size_t size) -{ -void *ret; -size_t scaled_size; -size_t shadow_size; -unsigned long shadow_start; - - shadow_start = (unsigned long )kasan_mem_to_shadow (addr); - scaled_size = (size +KASAN_GRANULE_SIZE -1 ) >> -KASAN_SHADOW_SCALE_SHIFT ; - shadow_size =round_up (scaled_size,PAGE_SIZE ); - -if (WARN_ON (!PAGE_ALIGNED (shadow_start))) -return -EINVAL ; - - ret =__vmalloc_node_range (shadow_size,1 , shadow_start, - shadow_start + shadow_size, -GFP_KERNEL , -PAGE_KERNEL ,VM_NO_GUARD ,NUMA_NO_NODE , -__builtin_return_address (0 )); - -if (ret) { -__memset (ret,KASAN_SHADOW_INIT , shadow_size); -find_vm_area (addr)->flags |=VM_KASAN ; -kmemleak_ignore (ret); -return 0 ; - } - -return -ENOMEM ; -} - -void kasan_free_shadow (const struct vm_struct *vm) -{ -if (vm->flags &VM_KASAN ) -vfree (kasan_mem_to_shadow (vm->addr)); -} - -#endif mm/kasan/shadow.c new file +505
-0@@ -0,0 +1,505 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* This file contains KASAN runtime code that manages shadow memory for +* generic and software tag-based KASAN modes. +* +* Copyright (c) 2014 Samsung Electronics Co., Ltd. +* Author: Andrey Ryabinin <[email protected]> +* +* Some code borrowed from https://github.com/xairy/kasan-prototype by +* Andrey Konovalov <[email protected]> +*/ + +#include <linux/init.h> +#include <linux/kasan.h> +#include <linux/kernel.h> +#include <linux/kmemleak.h> +#include <linux/memory.h> +#include <linux/mm.h> +#include <linux/string.h> +#include <linux/types.h> +#include <linux/vmalloc.h> + +#include <asm/cacheflush.h> +#include <asm/tlbflush.h> + +#include "kasan.h" + +bool __kasan_check_read (const volatile void *p,unsigned int size) +{ +return check_memory_region ((unsigned long )p, size, false, _RET_IP_); +} +EXPORT_SYMBOL (__kasan_check_read); + +bool __kasan_check_write (const volatile void *p,unsigned int size) +{ +return check_memory_region ((unsigned long )p, size, true, _RET_IP_); +} +EXPORT_SYMBOL (__kasan_check_write); + +#undef memset +void *memset (void *addr,int c,size_t len) +{ +if (!check_memory_region ((unsigned long )addr, len, true, _RET_IP_)) +return NULL ; + +return __memset (addr, c, len); +} + +#ifdef __HAVE_ARCH_MEMMOVE +#undef memmove +void *memmove (void *dest,const void *src,size_t len) +{ +if (!check_memory_region ((unsigned long )src, len, false, _RET_IP_) || + !check_memory_region ((unsigned long )dest, len, true, _RET_IP_)) +return NULL ; + +return __memmove (dest, src, len); +} +#endif + +#undef memcpy +void *memcpy (void *dest,const void *src,size_t len) +{ +if (!check_memory_region ((unsigned long )src, len, false, _RET_IP_) || + !check_memory_region ((unsigned long )dest, len, true, _RET_IP_)) +return NULL ; + +return __memcpy (dest, src, len); +} + +/* +* Poisons the shadow memory for 'size' bytes starting from 'addr'. +* Memory addresses should be aligned to KASAN_GRANULE_SIZE. +*/ +void kasan_poison_memory (const void *address,size_t size,u8 value) +{ +void *shadow_start, *shadow_end; + +/* +* Perform shadow offset calculation based on untagged address, as +* some of the callers (e.g. kasan_poison_object_data) pass tagged +* addresses to this function. +*/ + address =reset_tag (address); + + shadow_start =kasan_mem_to_shadow (address); + shadow_end =kasan_mem_to_shadow (address + size); + +__memset (shadow_start, value, shadow_end - shadow_start); +} + +void kasan_unpoison_memory (const void *address,size_t size) +{ +u8 tag =get_tag (address); + +/* +* Perform shadow offset calculation based on untagged address, as +* some of the callers (e.g. kasan_unpoison_object_data) pass tagged +* addresses to this function. +*/ + address =reset_tag (address); + +kasan_poison_memory (address, size, tag); + +if (size &KASAN_GRANULE_MASK ) { +u8 *shadow = (u8 *)kasan_mem_to_shadow (address + size); + +if (IS_ENABLED (CONFIG_KASAN_SW_TAGS )) + *shadow = tag; +else + *shadow = size &KASAN_GRANULE_MASK ; + } +} + +#ifdef CONFIG_MEMORY_HOTPLUG +static bool shadow_mapped (unsigned long addr) +{ +pgd_t *pgd =pgd_offset_k (addr); +p4d_t *p4d; +pud_t *pud; +pmd_t *pmd; +pte_t *pte; + +if (pgd_none (*pgd)) +return false; + p4d =p4d_offset (pgd, addr); +if (p4d_none (*p4d)) +return false; + pud =pud_offset (p4d, addr); +if (pud_none (*pud)) +return false; + +/* +* We can't use pud_large() or pud_huge(), the first one is +* arch-specific, the last one depends on HUGETLB_PAGE. So let's abuse +* pud_bad(), if pud is bad then it's bad because it's huge. +*/ +if (pud_bad (*pud)) +return true; + pmd =pmd_offset (pud, addr); +if (pmd_none (*pmd)) +return false; + +if (pmd_bad (*pmd)) +return true; + pte =pte_offset_kernel (pmd, addr); +return !pte_none (*pte); +} + +static int __meminit kasan_mem_notifier (struct notifier_block *nb, +unsigned long action,void *data) +{ +struct memory_notify *mem_data = data; +unsigned long nr_shadow_pages, start_kaddr, shadow_start; +unsigned long shadow_end, shadow_size; + + nr_shadow_pages = mem_data->nr_pages >>KASAN_SHADOW_SCALE_SHIFT ; + start_kaddr = (unsigned long )pfn_to_kaddr (mem_data->start_pfn); + shadow_start = (unsigned long )kasan_mem_to_shadow ((void *)start_kaddr); + shadow_size = nr_shadow_pages <<PAGE_SHIFT ; + shadow_end = shadow_start + shadow_size; + +if (WARN_ON (mem_data->nr_pages %KASAN_GRANULE_SIZE ) || +WARN_ON (start_kaddr % (KASAN_GRANULE_SIZE <<PAGE_SHIFT ))) +return NOTIFY_BAD ; + +switch (action) { +case MEM_GOING_ONLINE : { +void *ret; + +/* +* If shadow is mapped already than it must have been mapped +* during the boot. This could happen if we onlining previously +* offlined memory. +*/ +if (shadow_mapped (shadow_start)) +return NOTIFY_OK ; + + ret =__vmalloc_node_range (shadow_size,PAGE_SIZE , shadow_start, + shadow_end,GFP_KERNEL , +PAGE_KERNEL ,VM_NO_GUARD , +pfn_to_nid (mem_data->start_pfn), +__builtin_return_address (0 )); +if (!ret) +return NOTIFY_BAD ; + +kmemleak_ignore (ret); +return NOTIFY_OK ; + } +case MEM_CANCEL_ONLINE : +case MEM_OFFLINE : { +struct vm_struct *vm; + +/* +* shadow_start was either mapped during boot by kasan_init() +* or during memory online by __vmalloc_node_range(). +* In the latter case we can use vfree() to free shadow. +* Non-NULL result of the find_vm_area() will tell us if +* that was the second case. +* +* Currently it's not possible to free shadow mapped +* during boot by kasan_init(). It's because the code +* to do that hasn't been written yet. So we'll just +* leak the memory. +*/ + vm =find_vm_area ((void *)shadow_start); +if (vm) +vfree ((void *)shadow_start); + } + } + +return NOTIFY_OK ; +} + +static int __init kasan_memhotplug_init (void ) +{ +hotplug_memory_notifier (kasan_mem_notifier,0 ); + +return 0 ; +} + +core_initcall (kasan_memhotplug_init); +#endif + +#ifdef CONFIG_KASAN_VMALLOC + +static int kasan_populate_vmalloc_pte (pte_t *ptep,unsigned long addr, +void *unused) +{ +unsigned long page; +pte_t pte; + +if (likely (!pte_none (*ptep))) +return 0 ; + + page =__get_free_page (GFP_KERNEL ); +if (!page) +return -ENOMEM ; + +memset ((void *)page,KASAN_VMALLOC_INVALID ,PAGE_SIZE ); + pte =pfn_pte (PFN_DOWN (__pa (page)),PAGE_KERNEL ); + +spin_lock (&init_mm.page_table_lock); +if (likely (pte_none (*ptep))) { +set_pte_at (&init_mm, addr, ptep, pte); + page =0 ; + } +spin_unlock (&init_mm.page_table_lock); +if (page) +free_page (page); +return 0 ; +} + +int kasan_populate_vmalloc (unsigned long addr,unsigned long size) +{ +unsigned long shadow_start, shadow_end; +int ret; + +if (!is_vmalloc_or_module_addr ((void *)addr)) +return 0 ; + + shadow_start = (unsigned long )kasan_mem_to_shadow ((void *)addr); + shadow_start =ALIGN_DOWN (shadow_start,PAGE_SIZE ); + shadow_end = (unsigned long )kasan_mem_to_shadow ((void *)addr + size); + shadow_end =ALIGN (shadow_end,PAGE_SIZE ); + + ret =apply_to_page_range (&init_mm, shadow_start, + shadow_end - shadow_start, + kasan_populate_vmalloc_pte,NULL ); +if (ret) +return ret; + +flush_cache_vmap (shadow_start, shadow_end); + +/* +* We need to be careful about inter-cpu effects here. Consider: +* +* CPU#0 CPU#1 +* WRITE_ONCE(p, vmalloc(100)); while (x = READ_ONCE(p)) ; +* p[99] = 1; +* +* With compiler instrumentation, that ends up looking like this: +* +* CPU#0 CPU#1 +* // vmalloc() allocates memory +* // let a = area->addr +* // we reach kasan_populate_vmalloc +* // and call kasan_unpoison_memory: +* STORE shadow(a), unpoison_val +* ... +* STORE shadow(a+99), unpoison_val x = LOAD p +* // rest of vmalloc process <data dependency> +* STORE p, a LOAD shadow(x+99) +* +* If there is no barrier between the end of unpoisioning the shadow +* and the store of the result to p, the stores could be committed +* in a different order by CPU#0, and CPU#1 could erroneously observe +* poison in the shadow. +* +* We need some sort of barrier between the stores. +* +* In the vmalloc() case, this is provided by a smp_wmb() in +* clear_vm_uninitialized_flag(). In the per-cpu allocator and in +* get_vm_area() and friends, the caller gets shadow allocated but +* doesn't have any pages mapped into the virtual address space that +* has been reserved. Mapping those pages in will involve taking and +* releasing a page-table lock, which will provide the barrier. +*/ + +return 0 ; +} + +/* +* Poison the shadow for a vmalloc region. Called as part of the +* freeing process at the time the region is freed. +*/ +void kasan_poison_vmalloc (const void *start,unsigned long size) +{ +if (!is_vmalloc_or_module_addr (start)) +return ; + + size =round_up (size,KASAN_GRANULE_SIZE ); +kasan_poison_memory (start, size,KASAN_VMALLOC_INVALID ); +} + +void kasan_unpoison_vmalloc (const void *start,unsigned long size) +{ +if (!is_vmalloc_or_module_addr (start)) +return ; + +kasan_unpoison_memory (start, size); +} + +static int kasan_depopulate_vmalloc_pte (pte_t *ptep,unsigned long addr, +void *unused) +{ +unsigned long page; + + page = (unsigned long )__va (pte_pfn (*ptep) <<PAGE_SHIFT ); + +spin_lock (&init_mm.page_table_lock); + +if (likely (!pte_none (*ptep))) { +pte_clear (&init_mm, addr, ptep); +free_page (page); + } +spin_unlock (&init_mm.page_table_lock); + +return 0 ; +} + +/* +* Release the backing for the vmalloc region [start, end), which +* lies within the free region [free_region_start, free_region_end). +* +* This can be run lazily, long after the region was freed. It runs +* under vmap_area_lock, so it's not safe to interact with the vmalloc/vmap +* infrastructure. +* +* How does this work? +* ------------------- +* +* We have a region that is page aligned, labelled as A. +* That might not map onto the shadow in a way that is page-aligned: +* +* start end +* v v +* |????????|????????|AAAAAAAA|AA....AA|AAAAAAAA|????????| < vmalloc +* -------- -------- -------- -------- -------- +* | | | | | +* | | | /-------/ | +* \-------\|/------/ |/---------------/ +* ||| || +* |??AAAAAA|AAAAAAAA|AA??????| < shadow +* (1) (2) (3) +* +* First we align the start upwards and the end downwards, so that the +* shadow of the region aligns with shadow page boundaries. In the +* example, this gives us the shadow page (2). This is the shadow entirely +* covered by this allocation. +* +* Then we have the tricky bits. We want to know if we can free the +* partially covered shadow pages - (1) and (3) in the example. For this, +* we are given the start and end of the free region that contains this +* allocation. Extending our previous example, we could have: +* +* free_region_start free_region_end +* | start end | +* v v v v +* |FFFFFFFF|FFFFFFFF|AAAAAAAA|AA....AA|AAAAAAAA|FFFFFFFF| < vmalloc +* -------- -------- -------- -------- -------- +* | | | | | +* | | | /-------/ | +* \-------\|/------/ |/---------------/ +* ||| || +* |FFAAAAAA|AAAAAAAA|AAF?????| < shadow +* (1) (2) (3) +* +* Once again, we align the start of the free region up, and the end of +* the free region down so that the shadow is page aligned. So we can free +* page (1) - we know no allocation currently uses anything in that page, +* because all of it is in the vmalloc free region. But we cannot free +* page (3), because we can't be sure that the rest of it is unused. +* +* We only consider pages that contain part of the original region for +* freeing: we don't try to free other pages from the free region or we'd +* end up trying to free huge chunks of virtual address space. +* +* Concurrency +* ----------- +* +* How do we know that we're not freeing a page that is simultaneously +* being used for a fresh allocation in kasan_populate_vmalloc(_pte)? +* +* We _can_ have kasan_release_vmalloc and kasan_populate_vmalloc running +* at the same time. While we run under free_vmap_area_lock, the population +* code does not. +* +* free_vmap_area_lock instead operates to ensure that the larger range +* [free_region_start, free_region_end) is safe: because __alloc_vmap_area and +* the per-cpu region-finding algorithm both run under free_vmap_area_lock, +* no space identified as free will become used while we are running. This +* means that so long as we are careful with alignment and only free shadow +* pages entirely covered by the free region, we will not run in to any +* trouble - any simultaneous allocations will be for disjoint regions. +*/ +void kasan_release_vmalloc (unsigned long start,unsigned long end, +unsigned long free_region_start, +unsigned long free_region_end) +{ +void *shadow_start, *shadow_end; +unsigned long region_start, region_end; +unsigned long size; + + region_start =ALIGN (start,PAGE_SIZE *KASAN_GRANULE_SIZE ); + region_end =ALIGN_DOWN (end,PAGE_SIZE *KASAN_GRANULE_SIZE ); + + free_region_start =ALIGN (free_region_start, +PAGE_SIZE *KASAN_GRANULE_SIZE ); + +if (start != region_start && + free_region_start < region_start) + region_start -=PAGE_SIZE *KASAN_GRANULE_SIZE ; + + free_region_end =ALIGN_DOWN (free_region_end, +PAGE_SIZE *KASAN_GRANULE_SIZE ); + +if (end != region_end && + free_region_end > region_end) + region_end +=PAGE_SIZE *KASAN_GRANULE_SIZE ; + + shadow_start =kasan_mem_to_shadow ((void *)region_start); + shadow_end =kasan_mem_to_shadow ((void *)region_end); + +if (shadow_end > shadow_start) { + size = shadow_end - shadow_start; +apply_to_existing_page_range (&init_mm, + (unsigned long )shadow_start, + size, kasan_depopulate_vmalloc_pte, +NULL ); +flush_tlb_kernel_range ((unsigned long )shadow_start, + (unsigned long )shadow_end); + } +} + +#else /* CONFIG_KASAN_VMALLOC */ + +int kasan_module_alloc (void *addr,size_t size) +{ +void *ret; +size_t scaled_size; +size_t shadow_size; +unsigned long shadow_start; + + shadow_start = (unsigned long )kasan_mem_to_shadow (addr); + scaled_size = (size +KASAN_GRANULE_SIZE -1 ) >> +KASAN_SHADOW_SCALE_SHIFT ; + shadow_size =round_up (scaled_size,PAGE_SIZE ); + +if (WARN_ON (!PAGE_ALIGNED (shadow_start))) +return -EINVAL ; + + ret =__vmalloc_node_range (shadow_size,1 , shadow_start, + shadow_start + shadow_size, +GFP_KERNEL , +PAGE_KERNEL ,VM_NO_GUARD ,NUMA_NO_NODE , +__builtin_return_address (0 )); + +if (ret) { +__memset (ret,KASAN_SHADOW_INIT , shadow_size); +find_vm_area (addr)->flags |=VM_KASAN ; +kmemleak_ignore (ret); +return 0 ; + } + +return -ENOMEM ; +} + +void kasan_free_shadow (const struct vm_struct *vm) +{ +if (vm->flags &VM_KASAN ) +vfree (kasan_mem_to_shadow (vm->addr)); +} + +#endif Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
PATCH v3 9/39 kasan: define KASAN_GRANULE_PAGE
In reply to Andrey KonovalovDefine KASAN_GRANULE_PAGE as (KASAN_GRANULE_SIZE << PAGE_SHIFT), which is the same as (KASAN_GRANULE_SIZE * PAGE_SIZE), and use it across KASAN code to simplify it.
---
Change-Id: I0b627b24187d06c8b9bb2f1d04d94b3d06945e73
--- mm/kasan/init.c | 10 ++++------ mm/kasan/kasan.h | 1 + mm/kasan/shadow.c | 16 +++++++--------- 3 files changed, 12 insertions(+), 15 deletions(-)
mm/kasan/init.c +4 -6
@@ -441,9 +441,8 @@ void kasan_remove_zero_shadow(void *start, unsigned long size) addr = (unsigned long )kasan_mem_to_shadow (start); end = addr + (size >>KASAN_SHADOW_SCALE_SHIFT ); -if (WARN_ON ((unsigned long )start % - (KASAN_GRANULE_SIZE *PAGE_SIZE )) || -WARN_ON (size % (KASAN_GRANULE_SIZE *PAGE_SIZE ))) +if (WARN_ON ((unsigned long )start %KASAN_GRANULE_PAGE ) || +WARN_ON (size %KASAN_GRANULE_PAGE ))return ;for (; addr < end; addr = next) {
@@ -476,9 +475,8 @@ int kasan_add_zero_shadow(void *start, unsigned long size) shadow_start =kasan_mem_to_shadow (start); shadow_end = shadow_start + (size >>KASAN_SHADOW_SCALE_SHIFT ); -if (WARN_ON ((unsigned long )start % - (KASAN_GRANULE_SIZE *PAGE_SIZE )) || -WARN_ON (size % (KASAN_GRANULE_SIZE *PAGE_SIZE ))) +if (WARN_ON ((unsigned long )start %KASAN_GRANULE_PAGE ) || +WARN_ON (size %KASAN_GRANULE_PAGE ))return -EINVAL ; ret =kasan_populate_early_shadow (shadow_start, shadow_end);
mm/kasan/kasan.h +1 -0
@@ -7,6 +7,7 @@#define KASAN_GRANULE_SIZE (1UL << KASAN_SHADOW_SCALE_SHIFT)#define KASAN_GRANULE_MASK (KASAN_GRANULE_SIZE - 1) +#define KASAN_GRANULE_PAGE (KASAN_GRANULE_SIZE << PAGE_SHIFT)#define KASAN_TAG_KERNEL 0xFF/* native kernel pointers tag */ #define KASAN_TAG_INVALID 0xFE/* inaccessible memory tag */
mm/kasan/shadow.c +7 -9
@@ -161,7 +161,7 @@ static int __meminit kasan_mem_notifier(struct notifier_block *nb, shadow_end = shadow_start + shadow_size;if (WARN_ON (mem_data->nr_pages %KASAN_GRANULE_SIZE ) || -WARN_ON (start_kaddr % (KASAN_GRANULE_SIZE <<PAGE_SHIFT ))) +WARN_ON (start_kaddr %KASAN_GRANULE_PAGE ))return NOTIFY_BAD ;switch (action) {
@@ -432,22 +432,20 @@ void kasan_release_vmalloc(unsigned long start, unsigned long end,unsigned long region_start, region_end;unsigned long size; - region_start =ALIGN (start,PAGE_SIZE *KASAN_GRANULE_SIZE ); - region_end =ALIGN_DOWN (end,PAGE_SIZE *KASAN_GRANULE_SIZE ); + region_start =ALIGN (start,KASAN_GRANULE_PAGE ); + region_end =ALIGN_DOWN (end,KASAN_GRANULE_PAGE ); - free_region_start =ALIGN (free_region_start, -PAGE_SIZE *KASAN_GRANULE_SIZE ); + free_region_start =ALIGN (free_region_start,KASAN_GRANULE_PAGE );if (start != region_start && free_region_start < region_start) - region_start -=PAGE_SIZE *KASAN_GRANULE_SIZE ; + region_start -=KASAN_GRANULE_PAGE ; - free_region_end =ALIGN_DOWN (free_region_end, -PAGE_SIZE *KASAN_GRANULE_SIZE ); + free_region_end =ALIGN_DOWN (free_region_end,KASAN_GRANULE_PAGE );if (end != region_end && free_region_end > region_end) - region_end +=PAGE_SIZE *KASAN_GRANULE_SIZE ; + region_end +=KASAN_GRANULE_PAGE ; shadow_start =kasan_mem_to_shadow ((void *)region_start); shadow_end =kasan_mem_to_shadow ((void *)region_end);
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 09/39] kasan: define KASAN_GRANULE_PAGE
Quoted 6 lines · Andrey Konovalov
Define
KASAN_GRANULE_PAGEas (KASAN_GRANULE_SIZE<<PAGE_SHIFT), which is the same as (KASAN_GRANULE_SIZE*PAGE_SIZE), and use it across KASAN code to simplify it.Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>
Quoted 93 lines
---
Change-Id: I0b627b24187d06c8b9bb2f1d04d94b3d06945e73--- mm/kasan/init.c | 10 ++++------ mm/kasan/kasan.h | 1 + mm/kasan/shadow.c | 16 +++++++--------- 3 files changed, 12 insertions(+), 15 deletions(-)mm/kasan/init.c +4
-6@@ -441,9 +441,8 @@ void kasan_remove_zero_shadow(void *start, unsigned long size) addr = (unsigned long )kasan_mem_to_shadow (start); end = addr + (size >>KASAN_SHADOW_SCALE_SHIFT ); -if (WARN_ON ((unsigned long )start % - (KASAN_GRANULE_SIZE *PAGE_SIZE )) || -WARN_ON (size % (KASAN_GRANULE_SIZE *PAGE_SIZE ))) +if (WARN_ON ((unsigned long )start %KASAN_GRANULE_PAGE ) || +WARN_ON (size %KASAN_GRANULE_PAGE ))return ;for (; addr < end; addr = next) {@@ -476,9 +475,8 @@ int kasan_add_zero_shadow(void *start, unsigned long size) shadow_start =kasan_mem_to_shadow (start); shadow_end = shadow_start + (size >>KASAN_SHADOW_SCALE_SHIFT ); -if (WARN_ON ((unsigned long )start % - (KASAN_GRANULE_SIZE *PAGE_SIZE )) || -WARN_ON (size % (KASAN_GRANULE_SIZE *PAGE_SIZE ))) +if (WARN_ON ((unsigned long )start %KASAN_GRANULE_PAGE ) || +WARN_ON (size %KASAN_GRANULE_PAGE ))return -EINVAL ; ret =kasan_populate_early_shadow (shadow_start, shadow_end);mm/kasan/kasan.h +1
-0@@ -7,6 +7,7 @@#define KASAN_GRANULE_SIZE (1UL << KASAN_SHADOW_SCALE_SHIFT)#define KASAN_GRANULE_MASK (KASAN_GRANULE_SIZE - 1) +#define KASAN_GRANULE_PAGE (KASAN_GRANULE_SIZE << PAGE_SHIFT)#define KASAN_TAG_KERNEL 0xFF/* native kernel pointers tag */ #define KASAN_TAG_INVALID 0xFE/* inaccessible memory tag */ mm/kasan/shadow.c +7
-9@@ -161,7 +161,7 @@ static int __meminit kasan_mem_notifier(struct notifier_block *nb, shadow_end = shadow_start + shadow_size;if (WARN_ON (mem_data->nr_pages %KASAN_GRANULE_SIZE ) || -WARN_ON (start_kaddr % (KASAN_GRANULE_SIZE <<PAGE_SHIFT ))) +WARN_ON (start_kaddr %KASAN_GRANULE_PAGE ))return NOTIFY_BAD ;switch (action) {@@ -432,22 +432,20 @@ void kasan_release_vmalloc(unsigned long start, unsigned long end,unsigned long region_start, region_end;unsigned long size; - region_start =ALIGN (start,PAGE_SIZE *KASAN_GRANULE_SIZE ); - region_end =ALIGN_DOWN (end,PAGE_SIZE *KASAN_GRANULE_SIZE ); + region_start =ALIGN (start,KASAN_GRANULE_PAGE ); + region_end =ALIGN_DOWN (end,KASAN_GRANULE_PAGE ); - free_region_start =ALIGN (free_region_start, -PAGE_SIZE *KASAN_GRANULE_SIZE ); + free_region_start =ALIGN (free_region_start,KASAN_GRANULE_PAGE );if (start != region_start && free_region_start < region_start) - region_start -=PAGE_SIZE *KASAN_GRANULE_SIZE ; + region_start -=KASAN_GRANULE_PAGE ; - free_region_end =ALIGN_DOWN (free_region_end, -PAGE_SIZE *KASAN_GRANULE_SIZE ); + free_region_end =ALIGN_DOWN (free_region_end,KASAN_GRANULE_PAGE );if (end != region_end && free_region_end > region_end) - region_end +=PAGE_SIZE *KASAN_GRANULE_SIZE ; + region_end +=KASAN_GRANULE_PAGE ; shadow_start =kasan_mem_to_shadow ((void *)region_start); shadow_end =kasan_mem_to_shadow ((void *)region_end);Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
PATCH v3 10/39 kasan: rename report and tags files
In reply to Andrey KonovalovRename generic_report.c to report_generic.c and tags_report.c to report_sw_tags.c, as their content is more relevant to report.c file. Also rename tags.c to sw_tags.c to better reflect that this file contains code for software tag-based mode.
No functional changes.
---
Change-Id: If77d21f655d52ef3e58c4c37fd6621a07f505f18
---
mm/kasan/Makefile | 16 ++++++++--------
mm/kasan/report.c | 2 +-
mm/kasan/{generic_report.c => report_generic.c} | 0
mm/kasan/{tags_report.c => report_sw_tags.c} | 0
mm/kasan/{tags.c => sw_tags.c} | 0
5 files changed, 9 insertions(+), 9 deletions(-)
rename mm/kasan/{generic_report.c => report_generic.c} (100%)
rename mm/kasan/{tags_report.c => report_sw_tags.c} (100%)
rename mm/kasan/{tags.c => sw_tags.c} (100%)mm/kasan/Makefile +8 -8
@@ -6,13 +6,13 @@ KCOV_INSTRUMENT := n # Disable ftrace to avoid recursion. CFLAGS_REMOVE_common.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_generic.o = $(CC_FLAGS_FTRACE) -CFLAGS_REMOVE_generic_report.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_init.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_quarantine.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_report.o = $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_report_generic.o = $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_report_sw_tags.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_shadow.o = $(CC_FLAGS_FTRACE) -CFLAGS_REMOVE_tags.o = $(CC_FLAGS_FTRACE) -CFLAGS_REMOVE_tags_report.o = $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_sw_tags.o = $(CC_FLAGS_FTRACE) # Function splitter causes unnecessary splits in __asan_load1/__asan_store1 # see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63533
@@ -23,14 +23,14 @@ CC_FLAGS_KASAN_RUNTIME += -DDISABLE_BRANCH_PROFILING CFLAGS_common.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_generic.o := $(CC_FLAGS_KASAN_RUNTIME) -CFLAGS_generic_report.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_init.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_quarantine.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_report.o := $(CC_FLAGS_KASAN_RUNTIME) +CFLAGS_report_generic.o := $(CC_FLAGS_KASAN_RUNTIME) +CFLAGS_report_sw_tags.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_shadow.o := $(CC_FLAGS_KASAN_RUNTIME) -CFLAGS_tags.o := $(CC_FLAGS_KASAN_RUNTIME) -CFLAGS_tags_report.o := $(CC_FLAGS_KASAN_RUNTIME) +CFLAGS_sw_tags.o := $(CC_FLAGS_KASAN_RUNTIME) obj-$(CONFIG_KASAN) := common.o report.o -obj-$(CONFIG_KASAN_GENERIC) += init.o generic.o generic_report.o shadow.o quarantine.o -obj-$(CONFIG_KASAN_SW_TAGS) += init.o shadow.o tags.o tags_report.o +obj-$(CONFIG_KASAN_GENERIC) += init.o generic.o report_generic.o shadow.o quarantine.o +obj-$(CONFIG_KASAN_SW_TAGS) += init.o report_sw_tags.o shadow.o sw_tags.o
mm/kasan/report.c +1 -1
@@ -1,6 +1,6 @@// SPDX-License-Identifier: GPL-2.0 /* -* This file contains common generic and tag-based KASAN error reporting code. +* This file contains common KASAN error reporting code. * * Copyright (c) 2014 Samsung Electronics Co., Ltd. * Author: Andrey Ryabinin <[email protected]>
mm/kasan/report_generic.c renamed from mm/kasan/generic_report.c +0 -0
mm/kasan/report_sw_tags.c renamed from mm/kasan/tags_report.c +0 -0
mm/kasan/sw_tags.c renamed from mm/kasan/tags.c +0 -0
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 10/39] kasan: rename report and tags files
Quoted 9 lines · Andrey Konovalov
Rename
generic_report.ctoreport_generic.candtags_report.ctoreport_sw_tags.c, as their content is more relevant toreport.cfile. Also renametags.ctosw_tags.cto better reflect that this file contains code for software tag-based mode.No functional changes.
Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>
Quoted 81 lines
---
Change-Id: If77d21f655d52ef3e58c4c37fd6621a07f505f18--- mm/kasan/Makefile | 16 ++++++++-------- mm/kasan/report.c | 2 +- mm/kasan/{generic_report.c => report_generic.c} | 0 mm/kasan/{tags_report.c => report_sw_tags.c} | 0 mm/kasan/{tags.c => sw_tags.c} | 0 5 files changed, 9 insertions(+), 9 deletions(-) rename mm/kasan/{generic_report.c => report_generic.c} (100%) rename mm/kasan/{tags_report.c => report_sw_tags.c} (100%) rename mm/kasan/{tags.c => sw_tags.c} (100%)mm/kasan/Makefile +8
-8@@ -6,13 +6,13 @@ KCOV_INSTRUMENT := n # Disable ftrace to avoid recursion. CFLAGS_REMOVE_common.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_generic.o = $(CC_FLAGS_FTRACE) -CFLAGS_REMOVE_generic_report.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_init.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_quarantine.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_report.o = $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_report_generic.o = $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_report_sw_tags.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_shadow.o = $(CC_FLAGS_FTRACE) -CFLAGS_REMOVE_tags.o = $(CC_FLAGS_FTRACE) -CFLAGS_REMOVE_tags_report.o = $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_sw_tags.o = $(CC_FLAGS_FTRACE) # Function splitter causes unnecessary splits in __asan_load1/__asan_store1 # see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63533@@ -23,14 +23,14 @@ CC_FLAGS_KASAN_RUNTIME += -DDISABLE_BRANCH_PROFILING CFLAGS_common.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_generic.o := $(CC_FLAGS_KASAN_RUNTIME) -CFLAGS_generic_report.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_init.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_quarantine.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_report.o := $(CC_FLAGS_KASAN_RUNTIME) +CFLAGS_report_generic.o := $(CC_FLAGS_KASAN_RUNTIME) +CFLAGS_report_sw_tags.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_shadow.o := $(CC_FLAGS_KASAN_RUNTIME) -CFLAGS_tags.o := $(CC_FLAGS_KASAN_RUNTIME) -CFLAGS_tags_report.o := $(CC_FLAGS_KASAN_RUNTIME) +CFLAGS_sw_tags.o := $(CC_FLAGS_KASAN_RUNTIME) obj-$(CONFIG_KASAN) := common.o report.o -obj-$(CONFIG_KASAN_GENERIC) += init.o generic.o generic_report.o shadow.o quarantine.o -obj-$(CONFIG_KASAN_SW_TAGS) += init.o shadow.o tags.o tags_report.o +obj-$(CONFIG_KASAN_GENERIC) += init.o generic.o report_generic.o shadow.o quarantine.o +obj-$(CONFIG_KASAN_SW_TAGS) += init.o report_sw_tags.o shadow.o sw_tags.omm/kasan/report.c +1
-1@@ -1,6 +1,6 @@// SPDX-License-Identifier: GPL-2.0 /* -* This file contains common generic and tag-based KASAN error reporting code. +* This file contains common KASAN error reporting code. * * Copyright (c) 2014 Samsung Electronics Co., Ltd. * Author: Andrey Ryabinin <[email protected]> mm/kasan/report_generic.c renamed from mm/kasan/generic_report.c +0
-0mm/kasan/report_sw_tags.c renamed from mm/kasan/tags_report.c +0
-0mm/kasan/sw_tags.c renamed from mm/kasan/tags.c +0
-0Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
PATCH v3 11/39 kasan: don't duplicate config dependencies
In reply to Andrey KonovalovBoth KASAN_GENERIC and KASAN_SW_TAGS have common dependencies, move those to KASAN.
---
Change-Id: I77e475802e8f1750b9154fe4a6e6da4456054fcd
--- lib/Kconfig.kasan | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-)
lib/Kconfig.kasan +3 -8
@@ -24,6 +24,9 @@ menuconfig KASAN (HAVE_ARCH_KASAN_SW_TAGS && CC_HAS_KASAN_SW_TAGS) depends on (SLUB && SYSFS) || (SLAB && !DEBUG_SLAB) depends on CC_HAS_WORKING_NOSANITIZE_ADDRESS + select SLUB_DEBUG if SLUB + select CONSTRUCTORS + select STACKDEPOT help Enables KASAN (KernelAddressSANitizer) - runtime memory debugger, designed to find out-of-bounds accesses and use-after-free bugs.
@@ -46,10 +49,6 @@ choice config KASAN_GENERIC bool "Generic mode" depends on HAVE_ARCH_KASAN && CC_HAS_KASAN_GENERIC - depends on (SLUB && SYSFS) || (SLAB && !DEBUG_SLAB) - select SLUB_DEBUG if SLUB - select CONSTRUCTORS - select STACKDEPOT help Enables generic KASAN mode.
@@ -70,10 +69,6 @@ config KASAN_GENERIC config KASAN_SW_TAGS bool "Software tag-based mode" depends on HAVE_ARCH_KASAN_SW_TAGS && CC_HAS_KASAN_SW_TAGS - depends on (SLUB && SYSFS) || (SLAB && !DEBUG_SLAB) - select SLUB_DEBUG if SLUB - select CONSTRUCTORS - select STACKDEPOT help Enables software tag-based KASAN mode.
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 11/39] kasan: don't duplicate config dependencies
Quoted 5 lines · Andrey Konovalov
Both
KASAN_GENERICandKASAN_SW_TAGShave common dependencies, move those to KASAN.Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>
But see comment below:
Quoted 11 lines
---
Change-Id: I77e475802e8f1750b9154fe4a6e6da4456054fcd--- lib/Kconfig.kasan | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-)lib/Kconfig.kasan +0
-0
lib/Kconfig.kasan menuconfig KASAN · line 29
Quoted 6 lines
lib/Kconfig.kasan +3
-0@@ -24,6 +24,9 @@ menuconfig KASAN (HAVE_ARCH_KASAN_SW_TAGS && CC_HAS_KASAN_SW_TAGS) depends on (SLUB && SYSFS) || (SLAB && !DEBUG_SLAB) depends on CC_HAS_WORKING_NOSANITIZE_ADDRESS + select SLUB_DEBUG if SLUB + select CONSTRUCTORS + select STACKDEPOT
In the later patch your move 'select SLUB_DEBUG' back to where they were here it seems. The end result is the same, so I leave it to you if you want to change it.
Quoted 28 lines
lib/Kconfig.kasan +0
-8help Enables KASAN (KernelAddressSANitizer) - runtime memory debugger, designed to find out-of-bounds accesses and use-after-free bugs.@@ -46,10 +49,6 @@ choice config KASAN_GENERIC bool "Generic mode" depends on HAVE_ARCH_KASAN && CC_HAS_KASAN_GENERIC - depends on (SLUB && SYSFS) || (SLAB && !DEBUG_SLAB) - select SLUB_DEBUG if SLUB - select CONSTRUCTORS - select STACKDEPOT help Enables generic KASAN mode.@@ -70,10 +69,6 @@ config KASAN_GENERIC config KASAN_SW_TAGS bool "Software tag-based mode" depends on HAVE_ARCH_KASAN_SW_TAGS && CC_HAS_KASAN_SW_TAGS - depends on (SLUB && SYSFS) || (SLAB && !DEBUG_SLAB) - select SLUB_DEBUG if SLUB - select CONSTRUCTORS - select STACKDEPOT help Enables software tag-based KASAN mode.Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 11/39] kasan: don't duplicate config dependencies
Quoted 18 lines · On Thu, Oct 1, 2020 at 7:39 PM <[email protected]> wrote:
Quoted 5 lines · Andrey Konovalov
Both
KASAN_GENERICandKASAN_SW_TAGShave common dependencies, move those to KASAN.Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>Reviewed-by Marco Elver <[email protected]>But see comment below:
Quoted 6 lines
---
Change-Id: I77e475802e8f1750b9154fe4a6e6da4456054fcd--- lib/Kconfig.kasan | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-)
Quoted 15 lines
lib/Kconfig.kasan menuconfig KASAN · line 29
Quoted 11 lines
lib/Kconfig.kasan +3
-0@@ -24,6 +24,9 @@ menuconfig KASAN (HAVE_ARCH_KASAN_SW_TAGS && CC_HAS_KASAN_SW_TAGS) depends on (SLUB && SYSFS) || (SLAB && !DEBUG_SLAB) depends on CC_HAS_WORKING_NOSANITIZE_ADDRESS + select SLUB_DEBUG if SLUB + select CONSTRUCTORS + select STACKDEPOTIn the later patch your move 'select
SLUB_DEBUG' back to where they were here it seems. The end result is the same, so I leave it to you if you want to change it.
Will fix in v4, thank you!
Quoted 29 lines
Quoted 29 lines
lib/Kconfig.kasan +0
-9help Enables KASAN (KernelAddressSANitizer) - runtime memory debugger, designed to find out-of-bounds accesses and use-after-free bugs.@@ -46,10 +49,6 @@ choice config KASAN_GENERIC bool "Generic mode" depends on HAVE_ARCH_KASAN && CC_HAS_KASAN_GENERIC - depends on (SLUB && SYSFS) || (SLAB && !DEBUG_SLAB) - select SLUB_DEBUG if SLUB - select CONSTRUCTORS - select STACKDEPOT help Enables generic KASAN mode.@@ -70,10 +69,6 @@ config KASAN_GENERIC config KASAN_SW_TAGS bool "Software tag-based mode" depends on HAVE_ARCH_KASAN_SW_TAGS && CC_HAS_KASAN_SW_TAGS - depends on (SLUB && SYSFS) || (SLAB && !DEBUG_SLAB) - select SLUB_DEBUG if SLUB - select CONSTRUCTORS - select STACKDEPOT help Enables software tag-based KASAN mode. --2.28.0.681.g6f77f65b4e-goog
PATCH v3 12/39 kasan: hide invalid free check implementation
In reply to Andrey KonovalovThis is a preparatory commit for the upcoming addition of a new hardware tag-based (MTE-based) KASAN mode.
For software KASAN modes the check is based on the value in the shadow memory. Hardware tag-based KASAN won't be using shadow, so hide the implementation of the check in check_invalid_free().
Also simplify the code for software tag-based mode.
No functional changes for software modes.
---
Change-Id: I5fae9531c9fc948eb4d4e0c589744032fc5a0789
--- mm/kasan/common.c | 19 +------------------ mm/kasan/generic.c | 7 +++++++ mm/kasan/kasan.h | 2 ++ mm/kasan/sw_tags.c | 9 +++++++++ 4 files changed, 19 insertions(+), 18 deletions(-)
mm/kasan/common.c +1 -18
@@ -272,25 +272,9 @@ void * __must_check kasan_init_slab_obj(struct kmem_cache *cache,return (void *)object; } -static inline bool shadow_invalid (u8 tag,s8 shadow_byte) -{ -if (IS_ENABLED (CONFIG_KASAN_GENERIC )) -return shadow_byte <0 || - shadow_byte >=KASAN_GRANULE_SIZE ; - -/* else CONFIG_KASAN_SW_TAGS: */ -if ((u8 )shadow_byte ==KASAN_TAG_INVALID ) -return true; -if ((tag !=KASAN_TAG_KERNEL ) && (tag != (u8 )shadow_byte)) -return true; - -return false; -} -static bool __kasan_slab_free (struct kmem_cache *cache,void *object,unsigned long ip,bool quarantine) { -s8 shadow_byte;u8 tag;void *tagged_object;unsigned long rounded_up_size;
@@ -309,8 +293,7 @@ static bool __kasan_slab_free(struct kmem_cache *cache, void *object,if (unlikely (cache->flags &SLAB_TYPESAFE_BY_RCU ))return false; - shadow_byte =READ_ONCE (*(s8 *)kasan_mem_to_shadow (object)); -if (shadow_invalid (tag, shadow_byte)) { +if (check_invalid_free (tagged_object)) {kasan_report_invalid_free (tagged_object, ip);return true; }
mm/kasan/generic.c +7 -0
@@ -187,6 +187,13 @@ bool check_memory_region(unsigned long addr, size_t size, bool write,return check_memory_region_inline (addr, size, write, ret_ip); } +bool check_invalid_free (void *addr) +{ +s8 shadow_byte =READ_ONCE (*(s8 *)kasan_mem_to_shadow (addr)); + +return shadow_byte <0 || shadow_byte >=KASAN_GRANULE_SIZE ; +} +void kasan_cache_shrink (struct kmem_cache *cache) {quarantine_remove_cache (cache);
mm/kasan/kasan.h +2 -0
@@ -164,6 +164,8 @@ void kasan_poison_memory(const void *address, size_t size, u8 value);bool check_memory_region (unsigned long addr,size_t size,bool write,unsigned long ret_ip); +bool check_invalid_free (void *addr); +void *find_first_bad_addr (void *addr,size_t size);const char *get_bug_type (struct kasan_access_info *info);
mm/kasan/sw_tags.c +9 -0
@@ -121,6 +121,15 @@ bool check_memory_region(unsigned long addr, size_t size, bool write,return true; } +bool check_invalid_free (void *addr) +{ +u8 tag =get_tag (addr); +u8 shadow_byte =READ_ONCE (*(u8 *)kasan_mem_to_shadow (reset_tag (addr))); + +return (shadow_byte ==KASAN_TAG_INVALID ) || + (tag !=KASAN_TAG_KERNEL && tag != shadow_byte); +} +#define DEFINE_HWASAN_LOAD_STORE (size) \ void __hwasan_load##size##_noabort(unsigned long addr) \ { \
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 12/39] kasan: hide invalid free check implementation
Quoted 7 lines · Andrey Konovalov
This is a preparatory commit for the upcoming addition of a new hardware tag-based (MTE-based) KASAN mode.
For software KASAN modes the check is based on the value in the shadow memory. Hardware tag-based KASAN won't be using shadow, so hide the implementation of the check in
check_invalid_free().
Quoted 6 lines
Also simplify the code for software tag-based mode.
No functional changes for software modes.
Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>
Quoted 103 lines
---
Change-Id: I5fae9531c9fc948eb4d4e0c589744032fc5a0789--- mm/kasan/common.c | 19 +------------------ mm/kasan/generic.c | 7 +++++++ mm/kasan/kasan.h | 2 ++ mm/kasan/sw_tags.c | 9 +++++++++ 4 files changed, 19 insertions(+), 18 deletions(-)mm/kasan/common.c +1
-18@@ -272,25 +272,9 @@ void * __must_check kasan_init_slab_obj(struct kmem_cache *cache,return (void *)object; } -static inline bool shadow_invalid (u8 tag,s8 shadow_byte) -{ -if (IS_ENABLED (CONFIG_KASAN_GENERIC )) -return shadow_byte <0 || - shadow_byte >=KASAN_GRANULE_SIZE ; - -/* else CONFIG_KASAN_SW_TAGS: */ -if ((u8 )shadow_byte ==KASAN_TAG_INVALID ) -return true; -if ((tag !=KASAN_TAG_KERNEL ) && (tag != (u8 )shadow_byte)) -return true; - -return false; -} -static bool __kasan_slab_free (struct kmem_cache *cache,void *object,unsigned long ip,bool quarantine) { -s8 shadow_byte;u8 tag;void *tagged_object;unsigned long rounded_up_size;@@ -309,8 +293,7 @@ static bool __kasan_slab_free(struct kmem_cache *cache, void *object,if (unlikely (cache->flags &SLAB_TYPESAFE_BY_RCU ))return false; - shadow_byte =READ_ONCE (*(s8 *)kasan_mem_to_shadow (object)); -if (shadow_invalid (tag, shadow_byte)) { +if (check_invalid_free (tagged_object)) {kasan_report_invalid_free (tagged_object, ip);return true; }mm/kasan/generic.c +7
-0@@ -187,6 +187,13 @@ bool check_memory_region(unsigned long addr, size_t size, bool write,return check_memory_region_inline (addr, size, write, ret_ip); } +bool check_invalid_free (void *addr) +{ +s8 shadow_byte =READ_ONCE (*(s8 *)kasan_mem_to_shadow (addr)); + +return shadow_byte <0 || shadow_byte >=KASAN_GRANULE_SIZE ; +} +void kasan_cache_shrink (struct kmem_cache *cache) {quarantine_remove_cache (cache);mm/kasan/kasan.h +2
-0@@ -164,6 +164,8 @@ void kasan_poison_memory(const void *address, size_t size, u8 value);bool check_memory_region (unsigned long addr,size_t size,bool write,unsigned long ret_ip); +bool check_invalid_free (void *addr); +void *find_first_bad_addr (void *addr,size_t size);const char *get_bug_type (struct kasan_access_info *info);mm/kasan/sw_tags.c +9
-0@@ -121,6 +121,15 @@ bool check_memory_region(unsigned long addr, size_t size, bool write,return true; } +bool check_invalid_free (void *addr) +{ +u8 tag =get_tag (addr); +u8 shadow_byte =READ_ONCE (*(u8 *)kasan_mem_to_shadow (reset_tag (addr))); + +return (shadow_byte ==KASAN_TAG_INVALID ) || + (tag !=KASAN_TAG_KERNEL && tag != shadow_byte); +} +#define DEFINE_HWASAN_LOAD_STORE (size) \ void __hwasan_load##size##_noabort(unsigned long addr) \ { \Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
PATCH v3 13/39 kasan: decode stack frame only with KASAN_STACK_ENABLE
In reply to Andrey KonovalovDecoding routines aren't needed when CONFIG_KASAN_STACK_ENABLE is not enabled. Currently only generic KASAN mode implements stack error reporting.
No functional changes for software modes.
---
Change-Id: I084e3214f2b40dc0bef7c5a9fafdc6f5c42b06a2
--- mm/kasan/kasan.h | 6 ++ mm/kasan/report.c | 162 -------------------------------------- mm/kasan/report_generic.c | 161 +++++++++++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+), 162 deletions(-)
mm/kasan/kasan.h +6 -0
@@ -169,6 +169,12 @@ bool check_invalid_free(void *addr);void *find_first_bad_addr (void *addr,size_t size);const char *get_bug_type (struct kasan_access_info *info); +#ifdef CONFIG_KASAN_STACK_ENABLE +void print_address_stack_frame (const void *addr); +#else +static inline void print_address_stack_frame (const void *addr) { } +#endif +bool kasan_report (unsigned long addr,size_t size,bool is_write,unsigned long ip);void kasan_report_invalid_free (void *object,unsigned long ip);
mm/kasan/report.c +0 -162
168 lines not on this page · raw message
mm/kasan/report_generic.c +161 -0
167 lines not on this page · raw message
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 13/39] kasan: decode stack frame only with KASAN_STACK_ENABLE
Quoted 8 lines · Andrey Konovalov
Decoding routines aren't needed when
CONFIG_KASAN_STACK_ENABLEis not enabled. Currently only generic KASAN mode implements stack error reporting.No functional changes for software modes.
Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>
Quoted 373 lines
---
Change-Id: I084e3214f2b40dc0bef7c5a9fafdc6f5c42b06a2--- mm/kasan/kasan.h | 6 ++ mm/kasan/report.c | 162 -------------------------------------- mm/kasan/report_generic.c | 161 +++++++++++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+), 162 deletions(-)mm/kasan/kasan.h +6
-0@@ -169,6 +169,12 @@ bool check_invalid_free(void *addr);void *find_first_bad_addr (void *addr,size_t size);const char *get_bug_type (struct kasan_access_info *info); +#ifdef CONFIG_KASAN_STACK_ENABLE +void print_address_stack_frame (const void *addr); +#else +static inline void print_address_stack_frame (const void *addr) { } +#endif +bool kasan_report (unsigned long addr,size_t size,bool is_write,unsigned long ip);void kasan_report_invalid_free (void *object,unsigned long ip);mm/kasan/report.c +0
-162@@ -209,168 +209,6 @@ static inline bool init_task_stack_addr(const void *addr) sizeof(init_thread_union.stack)); } -static bool __must_check tokenize_frame_descr (const char **frame_descr, -char *token,size_t max_tok_len, -unsigned long *value) -{ -const char *sep =strchr (*frame_descr,' ' ); - -if (sep ==NULL ) - sep = *frame_descr +strlen (*frame_descr); - -if (token !=NULL ) { -const size_t tok_len = sep - *frame_descr; - -if (tok_len +1 > max_tok_len) { -pr_err ("KASAN internal error: frame description too long: %s\n" , - *frame_descr); -return false; - } - -/* Copy token (+ 1 byte for '\0'). */ -strlcpy (token, *frame_descr, tok_len +1 ); - } - -/* Advance frame_descr past separator. */ - *frame_descr = sep +1 ; - -if (value !=NULL &&kstrtoul (token,10 , value)) { -pr_err ("KASAN internal error: not a valid number: %s\n" , token); -return false; - } - -return true; -} - -static void print_decoded_frame_descr (const char *frame_descr) -{ -/* -* We need to parse the following string: -* "n alloc_1 alloc_2 ... alloc_n" -* where alloc_i looks like -* "offset size len name" -* or "offset size len name:line". -*/ - -char token[64 ]; -unsigned long num_objects; - -if (!tokenize_frame_descr (&frame_descr, token,sizeof (token), - &num_objects)) -return ; - -pr_err ("\n" ); -pr_err ("this frame has %lu %s:\n" , num_objects, - num_objects ==1 ?"object" :"objects" ); - -while (num_objects--) { -unsigned long offset; -unsigned long size; - -/* access offset */ -if (!tokenize_frame_descr (&frame_descr, token,sizeof (token), - &offset)) -return ; -/* access size */ -if (!tokenize_frame_descr (&frame_descr, token,sizeof (token), - &size)) -return ; -/* name length (unused) */ -if (!tokenize_frame_descr (&frame_descr,NULL ,0 ,NULL )) -return ; -/* object name */ -if (!tokenize_frame_descr (&frame_descr, token,sizeof (token), -NULL )) -return ; - -/* Strip line number; without filename it's not very helpful. */ -strreplace (token,':' ,'\0' ); - -/* Finally, print object information. */ -pr_err (" [%lu, %lu) '%s'" , offset, offset + size, token); - } -} - -static bool __must_check get_address_stack_frame_info (const void *addr, -unsigned long *offset, -const char **frame_descr, -const void **frame_pc) -{ -unsigned long aligned_addr; -unsigned long mem_ptr; -const u8 *shadow_bottom; -const u8 *shadow_ptr; -const unsigned long *frame; - -BUILD_BUG_ON (IS_ENABLED (CONFIG_STACK_GROWSUP )); - -/* -* NOTE: We currently only support printing frame information for -* accesses to the task's own stack. -*/ -if (!object_is_on_stack (addr)) -return false; - - aligned_addr =round_down ((unsigned long )addr,sizeof (long )); - mem_ptr =round_down (aligned_addr,KASAN_GRANULE_SIZE ); - shadow_ptr =kasan_mem_to_shadow ((void *)aligned_addr); - shadow_bottom =kasan_mem_to_shadow (end_of_stack (current)); - -while (shadow_ptr >= shadow_bottom && *shadow_ptr !=KASAN_STACK_LEFT ) { - shadow_ptr--; - mem_ptr -=KASAN_GRANULE_SIZE ; - } - -while (shadow_ptr >= shadow_bottom && *shadow_ptr ==KASAN_STACK_LEFT ) { - shadow_ptr--; - mem_ptr -=KASAN_GRANULE_SIZE ; - } - -if (shadow_ptr < shadow_bottom) -return false; - - frame = (const unsigned long *)(mem_ptr +KASAN_GRANULE_SIZE ); -if (frame[0 ] !=KASAN_CURRENT_STACK_FRAME_MAGIC ) { -pr_err ("KASAN internal error: frame info validation failed; invalid marker: %lu\n" , - frame[0 ]); -return false; - } - - *offset = (unsigned long )addr - (unsigned long )frame; - *frame_descr = (const char *)frame[1 ]; - *frame_pc = (void *)frame[2 ]; - -return true; -} - -static void print_address_stack_frame (const void *addr) -{ -unsigned long offset; -const char *frame_descr; -const void *frame_pc; - -if (IS_ENABLED (CONFIG_KASAN_SW_TAGS )) -return ; - -if (!get_address_stack_frame_info (addr, &offset, &frame_descr, - &frame_pc)) -return ; - -/* -* get_address_stack_frame_info only returns true if the given addr is -* on the current task's stack. -*/ -pr_err ("\n" ); -pr_err ("addr %px is located in stack of task %s/%d at offset %lu in frame:\n" , - addr, current->comm,task_pid_nr (current), offset); -pr_err (" %pS\n" , frame_pc); - -if (!frame_descr) -return ; - -print_decoded_frame_descr (frame_descr); -} -static void print_address_description (void *addr,u8 tag) {struct page *page =kasan_addr_to_page (addr);mm/kasan/report_generic.c +161
-0@@ -122,6 +122,167 @@ const char *get_bug_type(struct kasan_access_info *info)return get_wild_bug_type (info); } +#ifdef CONFIG_KASAN_STACK_ENABLE +static bool __must_check tokenize_frame_descr (const char **frame_descr, +char *token,size_t max_tok_len, +unsigned long *value) +{ +const char *sep =strchr (*frame_descr,' ' ); + +if (sep ==NULL ) + sep = *frame_descr +strlen (*frame_descr); + +if (token !=NULL ) { +const size_t tok_len = sep - *frame_descr; + +if (tok_len +1 > max_tok_len) { +pr_err ("KASAN internal error: frame description too long: %s\n" , + *frame_descr); +return false; + } + +/* Copy token (+ 1 byte for '\0'). */ +strlcpy (token, *frame_descr, tok_len +1 ); + } + +/* Advance frame_descr past separator. */ + *frame_descr = sep +1 ; + +if (value !=NULL &&kstrtoul (token,10 , value)) { +pr_err ("KASAN internal error: not a valid number: %s\n" , token); +return false; + } + +return true; +} + +static void print_decoded_frame_descr (const char *frame_descr) +{ +/* +* We need to parse the following string: +* "n alloc_1 alloc_2 ... alloc_n" +* where alloc_i looks like +* "offset size len name" +* or "offset size len name:line". +*/ + +char token[64 ]; +unsigned long num_objects; + +if (!tokenize_frame_descr (&frame_descr, token,sizeof (token), + &num_objects)) +return ; + +pr_err ("\n" ); +pr_err ("this frame has %lu %s:\n" , num_objects, + num_objects ==1 ?"object" :"objects" ); + +while (num_objects--) { +unsigned long offset; +unsigned long size; + +/* access offset */ +if (!tokenize_frame_descr (&frame_descr, token,sizeof (token), + &offset)) +return ; +/* access size */ +if (!tokenize_frame_descr (&frame_descr, token,sizeof (token), + &size)) +return ; +/* name length (unused) */ +if (!tokenize_frame_descr (&frame_descr,NULL ,0 ,NULL )) +return ; +/* object name */ +if (!tokenize_frame_descr (&frame_descr, token,sizeof (token), +NULL )) +return ; + +/* Strip line number; without filename it's not very helpful. */ +strreplace (token,':' ,'\0' ); + +/* Finally, print object information. */ +pr_err (" [%lu, %lu) '%s'" , offset, offset + size, token); + } +} + +static bool __must_check get_address_stack_frame_info (const void *addr, +unsigned long *offset, +const char **frame_descr, +const void **frame_pc) +{ +unsigned long aligned_addr; +unsigned long mem_ptr; +const u8 *shadow_bottom; +const u8 *shadow_ptr; +const unsigned long *frame; + +BUILD_BUG_ON (IS_ENABLED (CONFIG_STACK_GROWSUP )); + +/* +* NOTE: We currently only support printing frame information for +* accesses to the task's own stack. +*/ +if (!object_is_on_stack (addr)) +return false; + + aligned_addr =round_down ((unsigned long )addr,sizeof (long )); + mem_ptr =round_down (aligned_addr,KASAN_GRANULE_SIZE ); + shadow_ptr =kasan_mem_to_shadow ((void *)aligned_addr); + shadow_bottom =kasan_mem_to_shadow (end_of_stack (current)); + +while (shadow_ptr >= shadow_bottom && *shadow_ptr !=KASAN_STACK_LEFT ) { + shadow_ptr--; + mem_ptr -=KASAN_GRANULE_SIZE ; + } + +while (shadow_ptr >= shadow_bottom && *shadow_ptr ==KASAN_STACK_LEFT ) { + shadow_ptr--; + mem_ptr -=KASAN_GRANULE_SIZE ; + } + +if (shadow_ptr < shadow_bottom) +return false; + + frame = (const unsigned long *)(mem_ptr +KASAN_GRANULE_SIZE ); +if (frame[0 ] !=KASAN_CURRENT_STACK_FRAME_MAGIC ) { +pr_err ("KASAN internal error: frame info validation failed; invalid marker: %lu\n" , + frame[0 ]); +return false; + } + + *offset = (unsigned long )addr - (unsigned long )frame; + *frame_descr = (const char *)frame[1 ]; + *frame_pc = (void *)frame[2 ]; + +return true; +} + +void print_address_stack_frame (const void *addr) +{ +unsigned long offset; +const char *frame_descr; +const void *frame_pc; + +if (!get_address_stack_frame_info (addr, &offset, &frame_descr, + &frame_pc)) +return ; + +/* +* get_address_stack_frame_info only returns true if the given addr is +* on the current task's stack. +*/ +pr_err ("\n" ); +pr_err ("addr %px is located in stack of task %s/%d at offset %lu in frame:\n" , + addr, current->comm,task_pid_nr (current), offset); +pr_err (" %pS\n" , frame_pc); + +if (!frame_descr) +return ; + +print_decoded_frame_descr (frame_descr); +} +#endif /* CONFIG_KASAN_STACK_ENABLE */ +#define DEFINE_ASAN_REPORT_LOAD (size) \ void __asan_report_load##size##_noabort(unsigned long addr) \ { \Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
PATCH v3 14/39 kasan, arm64: only init shadow for software modes
In reply to Andrey KonovalovThis is a preparatory commit for the upcoming addition of a new hardware tag-based (MTE-based) KASAN mode.
Hardware tag-based KASAN won't be using shadow memory. Only initialize it when one of the software KASAN modes are enabled.
No functional changes for software modes.
---
Change-Id: I055e0651369b14d3e54cdaa8c48e6329b2e8952d
--- arch/arm64/include/asm/kasan.h | 8 ++++++-- arch/arm64/mm/kasan_init.c | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-)
arch/arm64/include/asm/kasan.h +6 -2
@@ -13,6 +13,12 @@#define arch_kasan_get_tag (addr) __tag_get(addr)#ifdef CONFIG_KASAN +void kasan_init (void ); +#else +static inline void kasan_init (void ) { } +#endif + +#if defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS )/* * KASAN_SHADOW_START: beginning of the kernel virtual addresses.
@@ -33,12 +39,10 @@#define _KASAN_SHADOW_START (va) (KASAN_SHADOW_END - (1UL << ((va) - KASAN_SHADOW_SCALE_SHIFT)))#define KASAN_SHADOW_START _KASAN_SHADOW_START(vabits_actual) -void kasan_init (void );void kasan_copy_shadow (pgd_t *pgdir); asmlinkage void kasan_early_init(void);#else -static inline void kasan_init (void ) { }static inline void kasan_copy_shadow (pgd_t *pgdir) { }#endif
arch/arm64/mm/kasan_init.c +14 -1
@@ -21,6 +21,8 @@#include <asm/sections.h> #include <asm/tlbflush.h> +#if defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS ) +static pgd_t tmp_pg_dir[PTRS_PER_PGD ]__initdata __aligned(PGD_SIZE) ;/*
@@ -208,7 +210,7 @@ static void __init clear_pgds(unsigned long start,set_pgd (pgd_offset_k (start),__pgd (0 )); } -void __init kasan_init (void ) +static void __init kasan_init_shadow (void ) {u64 kimg_shadow_start, kimg_shadow_end;u64 mod_shadow_start, mod_shadow_end;
@@ -269,6 +271,17 @@ void __init kasan_init(void)memset (kasan_early_shadow_page,KASAN_SHADOW_INIT ,PAGE_SIZE ); cpu_replace_ttbr1(lm_alias(swapper_pg_dir)); +} + +#else /* CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS) */ + +static inline void __init kasan_init_shadow (void ) { } + +#endif /* CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS */ + +void __init kasan_init (void ) +{ +kasan_init_shadow ();/* At this point kasan is fully initialized. Enable error messages */ init_task.kasan_depth =0 ;
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
PATCH v3 15/39 kasan, arm64: only use kasan_depth for software modes
In reply to Andrey KonovalovThis is a preparatory commit for the upcoming addition of a new hardware tag-based (MTE-based) KASAN mode.
Hardware tag-based KASAN won't use kasan_depth. Only define and use it when one of the software KASAN modes are enabled.
No functional changes for software modes.
---
Change-Id: I6109ea96c8df41ef6d75ad71bf22c1c8fa234a9a
--- arch/arm64/mm/kasan_init.c | 11 ++++++++--- include/linux/kasan.h | 18 +++++++++--------- include/linux/sched.h | 2 +- init/init_task.c | 2 +- mm/kasan/common.c | 2 ++ mm/kasan/report.c | 2 ++ 6 files changed, 23 insertions(+), 14 deletions(-)
arch/arm64/mm/kasan_init.c +8 -3
@@ -273,17 +273,22 @@ static void __init kasan_init_shadow(void) cpu_replace_ttbr1(lm_alias(swapper_pg_dir)); } +void __init kasan_init_depth (void ) +{ + init_task.kasan_depth =0 ; +} +#else /* CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS) */ static inline void __init kasan_init_shadow (void ) { } +static inline void __init kasan_init_depth (void ) { } +#endif /* CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS */ void __init kasan_init (void ) {kasan_init_shadow (); - -/* At this point kasan is fully initialized. Enable error messages */ - init_task.kasan_depth =0 ; +kasan_init_depth ();pr_info ("KernelAddressSanitizer initialized\n" ); }
include/linux/kasan.h +9 -9
@@ -40,6 +40,12 @@ static inline void *kasan_mem_to_shadow(const void *addr)int kasan_add_zero_shadow (void *start,unsigned long size);void kasan_remove_zero_shadow (void *start,unsigned long size); +/* Enable reporting bugs after kasan_disable_current() */ +extern void kasan_enable_current (void ); + +/* Disable reporting bugs for current task */ +extern void kasan_disable_current (void ); +#else /* CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS */ static inline int kasan_add_zero_shadow (void *start,unsigned long size)
@@ -50,16 +56,13 @@ static inline void kasan_remove_zero_shadow(void *start, unsigned long size) {} +static inline void kasan_enable_current (void ) {} +static inline void kasan_disable_current (void ) {} +#endif /* CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS */ #ifdef CONFIG_KASAN -/* Enable reporting bugs after kasan_disable_current() */ -extern void kasan_enable_current (void ); - -/* Disable reporting bugs for current task */ -extern void kasan_disable_current (void ); -void kasan_unpoison_memory (const void *address,size_t size);void kasan_unpoison_task_stack (struct task_struct *task);
@@ -110,9 +113,6 @@ static inline void kasan_unpoison_memory(const void *address, size_t size) {}static inline void kasan_unpoison_task_stack (struct task_struct *task) {} -static inline void kasan_enable_current (void ) {} -static inline void kasan_disable_current (void ) {} -static inline void kasan_alloc_pages (struct page *page,unsigned int order) {}static inline void kasan_free_pages (struct page *page,unsigned int order) {}
include/linux/sched.h +1 -1
@@ -1192,7 +1192,7 @@ struct task_struct {u64 timer_slack_ns;u64 default_timer_slack_ns; -#ifdef CONFIG_KASAN +#if defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS )unsigned int kasan_depth;#endif
init/init_task.c +1 -1
@@ -173,7 +173,7 @@ struct task_struct init_task .numa_group = NULL, .numa_faults = NULL,#endif -#ifdef CONFIG_KASAN +#if defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS ) .kasan_depth = 1,#endif #ifdef CONFIG_KCSAN
mm/kasan/common.c +2 -0
@@ -46,6 +46,7 @@ void kasan_set_track(struct kasan_track *track, gfp_t flags) track->stack =kasan_save_stack (flags); } +#if defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS )void kasan_enable_current (void ) { current->kasan_depth++;
@@ -55,6 +56,7 @@ void kasan_disable_current(void) { current->kasan_depth--; } +#endif /* CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS */ static void __kasan_unpoison_stack (struct task_struct *task,const void *sp) {
mm/kasan/report.c +2 -0
@@ -290,8 +290,10 @@ static void print_shadow_for_address(const void *addr)static bool report_enabled (void ) { +#if defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS )if (current->kasan_depth)return false; +#endif if (test_bit (KASAN_BIT_MULTI_SHOT , &kasan_flags))return true;return !test_and_set_bit (KASAN_BIT_REPORTED , &kasan_flags);
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
PATCH v3 16/39 kasan: rename addr_has_shadow to addr_has_metadata
In reply to Andrey KonovalovThis is a preparatory commit for the upcoming addition of a new hardware tag-based (MTE-based) KASAN mode.
Hardware tag-based KASAN won't be using shadow memory, but will reuse this function. Rename "shadow" to implementation-neutral "metadata".
No functional changes.
---
Change-Id: I03706fe34b38da7860c39aa0968e00001a7d1873
--- mm/kasan/kasan.h | 2 +- mm/kasan/report.c | 6 +++--- mm/kasan/report_generic.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-)
mm/kasan/kasan.h +1 -1
@@ -146,7 +146,7 @@ static inline const void *kasan_shadow_to_mem(const void *shadow_addr) << KASAN_SHADOW_SCALE_SHIFT); } -static inline bool addr_has_shadow (const void *addr) +static inline bool addr_has_metadata (const void *addr) {return (addr >=kasan_shadow_to_mem ((void *)KASAN_SHADOW_START )); }
mm/kasan/report.c +3 -3
@@ -329,7 +329,7 @@ static void __kasan_report(unsigned long addr, size_t size, bool is_write, untagged_addr =reset_tag (tagged_addr); info.access_addr = tagged_addr; -if (addr_has_shadow (untagged_addr)) +if (addr_has_metadata (untagged_addr)) info.first_bad_addr =find_first_bad_addr (tagged_addr, size);else info.first_bad_addr = untagged_addr;
@@ -340,11 +340,11 @@ static void __kasan_report(unsigned long addr, size_t size, bool is_write,start_report (&flags);print_error_description (&info); -if (addr_has_shadow (untagged_addr)) +if (addr_has_metadata (untagged_addr))print_tags (get_tag (tagged_addr), info.first_bad_addr);pr_err ("\n" ); -if (addr_has_shadow (untagged_addr)) { +if (addr_has_metadata (untagged_addr)) {print_address_description (untagged_addr,get_tag (tagged_addr));pr_err ("\n" );print_shadow_for_address (info.first_bad_addr);
mm/kasan/report_generic.c +1 -1
@@ -117,7 +117,7 @@ const char *get_bug_type(struct kasan_access_info *info)if (info->access_addr + info->access_size < info->access_addr)return "out-of-bounds" ; -if (addr_has_shadow (info->access_addr)) +if (addr_has_metadata (info->access_addr))return get_shadow_bug_type (info);return get_wild_bug_type (info); }
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 16/39] kasan: rename addr_has_shadow to addr_has_metadata
Quoted 10 lines · Andrey Konovalov' via kasan-dev
This is a preparatory commit for the upcoming addition of a new hardware tag-based (MTE-based) KASAN mode.
Hardware tag-based KASAN won't be using shadow memory, but will reuse this function. Rename "shadow" to implementation-neutral "metadata".
No functional changes.
Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>
Quoted 68 lines
---
Change-Id: I03706fe34b38da7860c39aa0968e00001a7d1873--- mm/kasan/kasan.h | 2 +- mm/kasan/report.c | 6 +++--- mm/kasan/report_generic.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-)mm/kasan/kasan.h +1
-1@@ -146,7 +146,7 @@ static inline const void *kasan_shadow_to_mem(const void *shadow_addr) << KASAN_SHADOW_SCALE_SHIFT); } -static inline bool addr_has_shadow (const void *addr) +static inline bool addr_has_metadata (const void *addr) {return (addr >=kasan_shadow_to_mem ((void *)KASAN_SHADOW_START )); }mm/kasan/report.c +3
-3@@ -329,7 +329,7 @@ static void __kasan_report(unsigned long addr, size_t size, bool is_write, untagged_addr =reset_tag (tagged_addr); info.access_addr = tagged_addr; -if (addr_has_shadow (untagged_addr)) +if (addr_has_metadata (untagged_addr)) info.first_bad_addr =find_first_bad_addr (tagged_addr, size);else info.first_bad_addr = untagged_addr;@@ -340,11 +340,11 @@ static void __kasan_report(unsigned long addr, size_t size, bool is_write,start_report (&flags);print_error_description (&info); -if (addr_has_shadow (untagged_addr)) +if (addr_has_metadata (untagged_addr))print_tags (get_tag (tagged_addr), info.first_bad_addr);pr_err ("\n" ); -if (addr_has_shadow (untagged_addr)) { +if (addr_has_metadata (untagged_addr)) {print_address_description (untagged_addr,get_tag (tagged_addr));pr_err ("\n" );print_shadow_for_address (info.first_bad_addr);mm/kasan/report_generic.c +1
-1@@ -117,7 +117,7 @@ const char *get_bug_type(struct kasan_access_info *info)if (info->access_addr + info->access_size < info->access_addr)return "out-of-bounds" ; -if (addr_has_shadow (info->access_addr)) +if (addr_has_metadata (info->access_addr))return get_shadow_bug_type (info);return get_wild_bug_type (info); }Signature · 6 lines
2.28.0.681.g6f77f65b4e-goog -- You received this message because you are subscribed to the Google Groups "kasan-dev" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/kasan-dev/fd0103571c825317241bfdc43ef19766fd370e4f.1600987622.git.andreyknvl%40google.com.
PATCH v3 17/39 kasan: rename print_shadow_for_address to print_memory_metadata
In reply to Andrey KonovalovThis is a preparatory commit for the upcoming addition of a new hardware tag-based (MTE-based) KASAN mode.
Hardware tag-based KASAN won't be using shadow memory, but will reuse this function. Rename "shadow" to implementation-neutral "metadata".
No functional changes.
---
Change-Id: I18397dddbed6bc6d365ddcaf063a83948e1150a5
--- mm/kasan/report.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
mm/kasan/report.c +3 -3
@@ -250,7 +250,7 @@ static int shadow_pointer_offset(const void *row, const void *shadow) (shadow - row) /SHADOW_BYTES_PER_BLOCK +1 ; } -static void print_shadow_for_address (const void *addr) +static void print_memory_metadata (const void *addr) {int i;const void *shadow =kasan_mem_to_shadow (addr);
@@ -311,7 +311,7 @@ void kasan_report_invalid_free(void *object, unsigned long ip)pr_err ("\n" );print_address_description (object, tag);pr_err ("\n" ); -print_shadow_for_address (object); +print_memory_metadata (object);end_report (&flags); }
@@ -347,7 +347,7 @@ static void __kasan_report(unsigned long addr, size_t size, bool is_write,if (addr_has_metadata (untagged_addr)) {print_address_description (untagged_addr,get_tag (tagged_addr));pr_err ("\n" ); -print_shadow_for_address (info.first_bad_addr); +print_memory_metadata (info.first_bad_addr); }else {dump_stack (); }
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 17/39] kasan: rename print_shadow_for_address to print_memory_metadata
Quoted 10 lines · Andrey Konovalov
This is a preparatory commit for the upcoming addition of a new hardware tag-based (MTE-based) KASAN mode.
Hardware tag-based KASAN won't be using shadow memory, but will reuse this function. Rename "shadow" to implementation-neutral "metadata".
No functional changes.
Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>
Quoted 40 lines
---
Change-Id: I18397dddbed6bc6d365ddcaf063a83948e1150a5--- mm/kasan/report.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)mm/kasan/report.c +3
-3@@ -250,7 +250,7 @@ static int shadow_pointer_offset(const void *row, const void *shadow) (shadow - row) /SHADOW_BYTES_PER_BLOCK +1 ; } -static void print_shadow_for_address (const void *addr) +static void print_memory_metadata (const void *addr) {int i;const void *shadow =kasan_mem_to_shadow (addr);@@ -311,7 +311,7 @@ void kasan_report_invalid_free(void *object, unsigned long ip)pr_err ("\n" );print_address_description (object, tag);pr_err ("\n" ); -print_shadow_for_address (object); +print_memory_metadata (object);end_report (&flags); }@@ -347,7 +347,7 @@ static void __kasan_report(unsigned long addr, size_t size, bool is_write,if (addr_has_metadata (untagged_addr)) {print_address_description (untagged_addr,get_tag (tagged_addr));pr_err ("\n" ); -print_shadow_for_address (info.first_bad_addr); +print_memory_metadata (info.first_bad_addr); }else {dump_stack (); }Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
PATCH v3 18/39 kasan: kasan_non_canonical_hook only for software modes
In reply to Andrey KonovalovThis is a preparatory commit for the upcoming addition of a new hardware tag-based (MTE-based) KASAN mode.
kasan_non_canonical_hook() is only applicable to KASAN modes that use shadow memory, and won't be needed for hardware tag-based KASAN.
No functional changes for software modes.
---
Change-Id: Icc9f5ef100a2e86f3a4214a0c3131a68266181b2
--- mm/kasan/report.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
mm/kasan/report.c +2 -1
@@ -371,7 +371,8 @@ bool kasan_report(unsigned long addr, size_t size, bool is_write,return ret; } -#ifdef CONFIG_KASAN_INLINE +#if (defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS )) && \ + defined(CONFIG_KASAN_INLINE )/* * With CONFIG_KASAN_INLINE, accesses to bogus pointers (outside the high * canonical half of the address space) cause out-of-bounds shadow memory reads
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 18/39] kasan: kasan_non_canonical_hook only for software modes
Quoted 10 lines · Andrey Konovalov
This is a preparatory commit for the upcoming addition of a new hardware tag-based (MTE-based) KASAN mode.
kasan_non_canonical_hook()is only applicable to KASAN modes that use shadow memory, and won't be needed for hardware tag-based KASAN.No functional changes for software modes.
Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>
Quoted 23 lines
---
Change-Id: Icc9f5ef100a2e86f3a4214a0c3131a68266181b2--- mm/kasan/report.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)mm/kasan/report.c +2
-1@@ -371,7 +371,8 @@ bool kasan_report(unsigned long addr, size_t size, bool is_write,return ret; } -#ifdef CONFIG_KASAN_INLINE +#if (defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS )) && \ + defined(CONFIG_KASAN_INLINE )/* * With CONFIG_KASAN_INLINE, accesses to bogus pointers (outside the high * canonical half of the address space) cause out-of-bounds shadow memory reads Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
PATCH v3 19/39 kasan: rename SHADOW layout macros to META
In reply to Andrey KonovalovThis is a preparatory commit for the upcoming addition of a new hardware tag-based (MTE-based) KASAN mode.
Hardware tag-based KASAN won't be using shadow memory, but will reuse these macros. Rename "SHADOW" to implementation-neutral "META".
No functional changes.
---
Change-Id: Id2d836bf43b401bce1221cc06e745185f17b1cc
--- mm/kasan/report.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-)
mm/kasan/report.c +15 -15
@@ -31,11 +31,11 @@#include "kasan.h" #include "../slab.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 +/* Metadata layout customization. */ +#define META_BYTES_PER_BLOCK 1 +#define META_BLOCKS_PER_ROW 16 +#define META_BYTES_PER_ROW (META_BLOCKS_PER_ROW * META_BYTES_PER_BLOCK) +#define META_ROWS_AROUND_ADDR 2static unsigned long kasan_flags;
@@ -238,7 +238,7 @@ static void print_address_description(void *addr, u8 tag)static bool row_is_guilty (const void *row,const void *guilty) { -return (row <= guilty) && (guilty < row +SHADOW_BYTES_PER_ROW ); +return (row <= guilty) && (guilty < row +META_BYTES_PER_ROW ); }static int shadow_pointer_offset (const void *row,const void *shadow)
@@ -247,7 +247,7 @@ static int shadow_pointer_offset(const void *row, const void *shadow)* 3 + (BITS_PER_LONG/8)*2 chars. */ return 3 + (BITS_PER_LONG /8 )*2 + (shadow - row)*2 + - (shadow - row) /SHADOW_BYTES_PER_BLOCK +1 ; + (shadow - row) /META_BYTES_PER_BLOCK +1 ; }static void print_memory_metadata (const void *addr)
@@ -257,15 +257,15 @@ static void print_memory_metadata(const void *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 ; +META_BYTES_PER_ROW ) + -META_ROWS_AROUND_ADDR *META_BYTES_PER_ROW ;pr_err ("Memory state around the buggy address:\n" ); -for (i = -SHADOW_ROWS_AROUND_ADDR ; i <=SHADOW_ROWS_AROUND_ADDR ; i++) { +for (i = -META_ROWS_AROUND_ADDR ; i <=META_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 ]; +char shadow_buf[META_BYTES_PER_ROW ];snprintf (buffer,sizeof (buffer), (i ==0 ) ?">%px: " :" %px: " , kaddr);
@@ -274,17 +274,17 @@ static void print_memory_metadata(const void *addr)* function, because generic functions may try to * access kasan mapping for the passed address. */ -memcpy (shadow_buf, shadow_row,SHADOW_BYTES_PER_ROW ); +memcpy (shadow_buf, shadow_row,META_BYTES_PER_ROW );print_hex_dump (KERN_ERR , buffer, -DUMP_PREFIX_NONE ,SHADOW_BYTES_PER_ROW ,1 , - shadow_buf,SHADOW_BYTES_PER_ROW ,0 ); +DUMP_PREFIX_NONE ,META_BYTES_PER_ROW ,1 , + shadow_buf,META_BYTES_PER_ROW ,0 );if (row_is_guilty (shadow_row, shadow))pr_err ("%*c\n" ,shadow_pointer_offset (shadow_row, shadow),'^' ); - shadow_row +=SHADOW_BYTES_PER_ROW ; + shadow_row +=META_BYTES_PER_ROW ; } }
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 19/39] kasan: rename SHADOW layout macros to META
Quoted 10 lines · Andrey Konovalov
This is a preparatory commit for the upcoming addition of a new hardware tag-based (MTE-based) KASAN mode.
Hardware tag-based KASAN won't be using shadow memory, but will reuse these macros. Rename "SHADOW" to implementation-neutral "META".
No functional changes.
Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>
Quoted 90 lines
---
Change-Id: Id2d836bf43b401bce1221cc06e745185f17b1cc--- mm/kasan/report.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-)mm/kasan/report.c +15
-15@@ -31,11 +31,11 @@#include "kasan.h" #include "../slab.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 +/* Metadata layout customization. */ +#define META_BYTES_PER_BLOCK 1 +#define META_BLOCKS_PER_ROW 16 +#define META_BYTES_PER_ROW (META_BLOCKS_PER_ROW * META_BYTES_PER_BLOCK) +#define META_ROWS_AROUND_ADDR 2static unsigned long kasan_flags;@@ -238,7 +238,7 @@ static void print_address_description(void *addr, u8 tag)static bool row_is_guilty (const void *row,const void *guilty) { -return (row <= guilty) && (guilty < row +SHADOW_BYTES_PER_ROW ); +return (row <= guilty) && (guilty < row +META_BYTES_PER_ROW ); }static int shadow_pointer_offset (const void *row,const void *shadow)@@ -247,7 +247,7 @@ static int shadow_pointer_offset(const void *row, const void *shadow)* 3 + (BITS_PER_LONG/8)*2 chars. */ return 3 + (BITS_PER_LONG /8 )*2 + (shadow - row)*2 + - (shadow - row) /SHADOW_BYTES_PER_BLOCK +1 ; + (shadow - row) /META_BYTES_PER_BLOCK +1 ; }static void print_memory_metadata (const void *addr)@@ -257,15 +257,15 @@ static void print_memory_metadata(const void *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 ; +META_BYTES_PER_ROW ) + -META_ROWS_AROUND_ADDR *META_BYTES_PER_ROW ;pr_err ("Memory state around the buggy address:\n" ); -for (i = -SHADOW_ROWS_AROUND_ADDR ; i <=SHADOW_ROWS_AROUND_ADDR ; i++) { +for (i = -META_ROWS_AROUND_ADDR ; i <=META_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 ]; +char shadow_buf[META_BYTES_PER_ROW ];snprintf (buffer,sizeof (buffer), (i ==0 ) ?">%px: " :" %px: " , kaddr);@@ -274,17 +274,17 @@ static void print_memory_metadata(const void *addr)* function, because generic functions may try to * access kasan mapping for the passed address. */ -memcpy (shadow_buf, shadow_row,SHADOW_BYTES_PER_ROW ); +memcpy (shadow_buf, shadow_row,META_BYTES_PER_ROW );print_hex_dump (KERN_ERR , buffer, -DUMP_PREFIX_NONE ,SHADOW_BYTES_PER_ROW ,1 , - shadow_buf,SHADOW_BYTES_PER_ROW ,0 ); +DUMP_PREFIX_NONE ,META_BYTES_PER_ROW ,1 , + shadow_buf,META_BYTES_PER_ROW ,0 );if (row_is_guilty (shadow_row, shadow))pr_err ("%*c\n" ,shadow_pointer_offset (shadow_row, shadow),'^' ); - shadow_row +=SHADOW_BYTES_PER_ROW ; + shadow_row +=META_BYTES_PER_ROW ; } }Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
PATCH v3 20/39 kasan: separate metadata_fetch_row for each mode
In reply to Andrey KonovalovThis is a preparatory commit for the upcoming addition of a new hardware tag-based (MTE-based) KASAN mode.
Rework print_memory_metadata() to make it agnostic with regard to the way metadata is stored. Allow providing a separate metadata_fetch_row() implementation for each KASAN mode. Hardware tag-based KASAN will provide its own implementation that doesn't use shadow memory.
No functional changes for software modes.
---
Change-Id: I5b0ed1d079ea776e620beca6a529a861e7dced95
--- mm/kasan/kasan.h | 8 ++++++ mm/kasan/report.c | 56 +++++++++++++++++++-------------------- mm/kasan/report_generic.c | 5 ++++ mm/kasan/report_sw_tags.c | 5 ++++ 4 files changed, 45 insertions(+), 29 deletions(-)
mm/kasan/kasan.h +8 -0
@@ -57,6 +57,13 @@#define KASAN_ABI_VERSION 1#endif +/* Metadata layout customization. */ +#define META_BYTES_PER_BLOCK 1 +#define META_BLOCKS_PER_ROW 16 +#define META_BYTES_PER_ROW (META_BLOCKS_PER_ROW * META_BYTES_PER_BLOCK) +#define META_MEM_BYTES_PER_ROW (META_BYTES_PER_ROW * KASAN_GRANULE_SIZE) +#define META_ROWS_AROUND_ADDR 2 +struct kasan_access_info {const void *access_addr;const void *first_bad_addr;
@@ -168,6 +175,7 @@ bool check_invalid_free(void *addr);void *find_first_bad_addr (void *addr,size_t size);const char *get_bug_type (struct kasan_access_info *info); +void metadata_fetch_row (char *buffer,void *row);#ifdef CONFIG_KASAN_STACK_ENABLE void print_address_stack_frame (const void *addr);
mm/kasan/report.c +27 -29
94 lines not on this page · raw message
mm/kasan/report_generic.c +5 -0
@@ -122,6 +122,11 @@ const char *get_bug_type(struct kasan_access_info *info)return get_wild_bug_type (info); } +void metadata_fetch_row (char *buffer,void *row) +{ +memcpy (buffer,kasan_mem_to_shadow (row),META_BYTES_PER_ROW ); +} +#ifdef CONFIG_KASAN_STACK_ENABLE static bool __must_check tokenize_frame_descr(const char **frame_descr, char *token, size_t max_tok_len,
mm/kasan/report_sw_tags.c +5 -0
@@ -80,6 +80,11 @@ void *find_first_bad_addr(void *addr, size_t size)return p; } +void metadata_fetch_row (char *buffer,void *row) +{ +memcpy (buffer,kasan_mem_to_shadow (row),META_BYTES_PER_ROW ); +} +void print_tags (u8 addr_tag,const void *addr) {u8 *shadow = (u8 *)kasan_mem_to_shadow (addr);
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 20/39] kasan: separate metadata_fetch_row for each mode
Quoted 2 lines · Andrey Konovalov
This is a preparatory commit for the upcoming addition of a new hardware tag-based (MTE-based) KASAN mode.
Not sure why I've only noticed this now, but all these patches seem to say "This is a preparatory commit" -- I don't think "commit" is applicable, and "This .. patch" is discouraged.
Maybe just change it to say "This is to prepare for the upcoming ..." after the below paragraph?
Quoted 4 lines
Rework
print_memory_metadata()to make it agnostic with regard to the way metadata is stored. Allow providing a separatemetadata_fetch_row()implementation for each KASAN mode. Hardware tag-based KASAN will provide its own implementation that doesn't use shadow memory.
(i.e. move it here)
Quoted 4 lines
No functional changes for software modes.
Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>
Other than that,
Quoted 170 lines
---
Change-Id: I5b0ed1d079ea776e620beca6a529a861e7dced95--- mm/kasan/kasan.h | 8 ++++++ mm/kasan/report.c | 56 +++++++++++++++++++-------------------- mm/kasan/report_generic.c | 5 ++++ mm/kasan/report_sw_tags.c | 5 ++++ 4 files changed, 45 insertions(+), 29 deletions(-)mm/kasan/kasan.h +8
-0@@ -57,6 +57,13 @@#define KASAN_ABI_VERSION 1#endif +/* Metadata layout customization. */ +#define META_BYTES_PER_BLOCK 1 +#define META_BLOCKS_PER_ROW 16 +#define META_BYTES_PER_ROW (META_BLOCKS_PER_ROW * META_BYTES_PER_BLOCK) +#define META_MEM_BYTES_PER_ROW (META_BYTES_PER_ROW * KASAN_GRANULE_SIZE) +#define META_ROWS_AROUND_ADDR 2 +struct kasan_access_info {const void *access_addr;const void *first_bad_addr;@@ -168,6 +175,7 @@ bool check_invalid_free(void *addr);void *find_first_bad_addr (void *addr,size_t size);const char *get_bug_type (struct kasan_access_info *info); +void metadata_fetch_row (char *buffer,void *row);#ifdef CONFIG_KASAN_STACK_ENABLE void print_address_stack_frame (const void *addr);mm/kasan/report.c +27
-29@@ -31,12 +31,6 @@#include "kasan.h" #include "../slab.h" -/* Metadata layout customization. */ -#define META_BYTES_PER_BLOCK 1 -#define META_BLOCKS_PER_ROW 16 -#define META_BYTES_PER_ROW (META_BLOCKS_PER_ROW * META_BYTES_PER_BLOCK) -#define META_ROWS_AROUND_ADDR 2 -static unsigned long kasan_flags;#define KASAN_BIT_REPORTED 0@@ -236,55 +230,59 @@ static void print_address_description(void *addr, u8 tag)print_address_stack_frame (addr); } -static bool row_is_guilty (const void *row,const void *guilty) +static bool meta_row_is_guilty (const void *row,const void *addr) { -return (row <= guilty) && (guilty < row +META_BYTES_PER_ROW ); +return (row <= addr) && (addr < row +META_MEM_BYTES_PER_ROW ); } -static int shadow_pointer_offset (const void *row,const void *shadow) +static int meta_pointer_offset (const void *row,const void *addr) { -/* The length of ">ff00ff00ff00ff00: " is -* 3 + (BITS_PER_LONG/8)*2 chars. +/* +* Memory state around the buggy address: +* ff00ff00ff00ff00: 00 00 00 05 fe fe fe fe fe fe fe fe fe fe fe fe +* ... +* +* The length of ">ff00ff00ff00ff00: " is +* 3 + (BITS_PER_LONG / 8) * 2 chars. +* The length of each granule metadata is 2 bytes +* plus 1 byte for space. */ -return 3 + (BITS_PER_LONG /8 )*2 + (shadow - row)*2 + - (shadow - row) /META_BYTES_PER_BLOCK +1 ; +return 3 + (BITS_PER_LONG /8 ) *2 + + (addr - row) /KASAN_GRANULE_SIZE *3 +1 ; }static void print_memory_metadata (const void *addr) {int i; -const void *shadow =kasan_mem_to_shadow (addr); -const void *shadow_row; +void *row; - shadow_row = (void *)round_down ((unsigned long )shadow, -META_BYTES_PER_ROW ) - -META_ROWS_AROUND_ADDR *META_BYTES_PER_ROW ; + row = (void *)round_down ((unsigned long )addr,META_MEM_BYTES_PER_ROW ) + -META_ROWS_AROUND_ADDR *META_MEM_BYTES_PER_ROW ;pr_err ("Memory state around the buggy address:\n" );for (i = -META_ROWS_AROUND_ADDR ; i <=META_ROWS_AROUND_ADDR ; i++) { -const void *kaddr =kasan_shadow_to_mem (shadow_row); -char buffer[4 + (BITS_PER_LONG /8 )*2 ]; -char shadow_buf[META_BYTES_PER_ROW ]; +char buffer[4 + (BITS_PER_LONG /8 ) *2 ]; +char metadata[META_BYTES_PER_ROW ];snprintf (buffer,sizeof (buffer), - (i ==0 ) ?">%px: " :" %px: " , kaddr); + (i ==0 ) ?">%px: " :" %px: " , row); +/* * 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,META_BYTES_PER_ROW ); +metadata_fetch_row (&metadata[0 ], row); +print_hex_dump (KERN_ERR , buffer,DUMP_PREFIX_NONE ,META_BYTES_PER_ROW ,1 , - shadow_buf,META_BYTES_PER_ROW ,0 ); + metadata,META_BYTES_PER_ROW ,0 ); -if (row_is_guilty (shadow_row, shadow)) -pr_err ("%*c\n" , -shadow_pointer_offset (shadow_row, shadow), -'^' ); +if (meta_row_is_guilty (row, addr)) +pr_err ("%*c\n" ,meta_pointer_offset (row, addr),'^' ); - shadow_row +=META_BYTES_PER_ROW ; + row +=META_MEM_BYTES_PER_ROW ; } }mm/kasan/report_generic.c +5
-0@@ -122,6 +122,11 @@ const char *get_bug_type(struct kasan_access_info *info)return get_wild_bug_type (info); } +void metadata_fetch_row (char *buffer,void *row) +{ +memcpy (buffer,kasan_mem_to_shadow (row),META_BYTES_PER_ROW ); +} +#ifdef CONFIG_KASAN_STACK_ENABLE static bool __must_check tokenize_frame_descr(const char **frame_descr, char *token, size_t max_tok_len,mm/kasan/report_sw_tags.c +5
-0@@ -80,6 +80,11 @@ void *find_first_bad_addr(void *addr, size_t size)return p; } +void metadata_fetch_row (char *buffer,void *row) +{ +memcpy (buffer,kasan_mem_to_shadow (row),META_BYTES_PER_ROW ); +} +void print_tags (u8 addr_tag,const void *addr) {u8 *shadow = (u8 *)kasan_mem_to_shadow (addr);Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 20/39] kasan: separate metadata_fetch_row for each mode
Quoted 8 lines · On Thu, Oct 1, 2020 at 7:54 PM <[email protected]> wrote:
Quoted 2 lines · Andrey Konovalov
This is a preparatory commit for the upcoming addition of a new hardware tag-based (MTE-based) KASAN mode.
Not sure why I've only noticed this now, but all these patches seem to say "This is a preparatory commit" -- I don't think "commit" is applicable, and "This .. patch" is discouraged.
"This commit" is used all over the place if you do git log, so it should be fine.
Quoted 11 lines
Maybe just change it to say "This is to prepare for the upcoming ..." after the below paragraph?
Quoted 4 lines
Rework
print_memory_metadata()to make it agnostic with regard to the way metadata is stored. Allow providing a separatemetadata_fetch_row()implementation for each KASAN mode. Hardware tag-based KASAN will provide its own implementation that doesn't use shadow memory.(i.e. move it here)
Quoted 8 lines
Quoted 4 lines
No functional changes for software modes.
Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>Other than that,
Reviewed-by Marco Elver <[email protected]>
Thanks!
Quoted 171 lines
Quoted 171 lines
---
Change-Id: I5b0ed1d079ea776e620beca6a529a861e7dced95--- mm/kasan/kasan.h | 8 ++++++ mm/kasan/report.c | 56 +++++++++++++++++++-------------------- mm/kasan/report_generic.c | 5 ++++ mm/kasan/report_sw_tags.c | 5 ++++ 4 files changed, 45 insertions(+), 29 deletions(-)mm/kasan/kasan.h +8
-0@@ -57,6 +57,13 @@#define KASAN_ABI_VERSION 1#endif +/* Metadata layout customization. */ +#define META_BYTES_PER_BLOCK 1 +#define META_BLOCKS_PER_ROW 16 +#define META_BYTES_PER_ROW (META_BLOCKS_PER_ROW * META_BYTES_PER_BLOCK) +#define META_MEM_BYTES_PER_ROW (META_BYTES_PER_ROW * KASAN_GRANULE_SIZE) +#define META_ROWS_AROUND_ADDR 2 +struct kasan_access_info {const void *access_addr;const void *first_bad_addr;@@ -168,6 +175,7 @@ bool check_invalid_free(void *addr);void *find_first_bad_addr (void *addr,size_t size);const char *get_bug_type (struct kasan_access_info *info); +void metadata_fetch_row (char *buffer,void *row);#ifdef CONFIG_KASAN_STACK_ENABLE void print_address_stack_frame (const void *addr);mm/kasan/report.c +27
-29@@ -31,12 +31,6 @@#include "kasan.h" #include "../slab.h" -/* Metadata layout customization. */ -#define META_BYTES_PER_BLOCK 1 -#define META_BLOCKS_PER_ROW 16 -#define META_BYTES_PER_ROW (META_BLOCKS_PER_ROW * META_BYTES_PER_BLOCK) -#define META_ROWS_AROUND_ADDR 2 -static unsigned long kasan_flags;#define KASAN_BIT_REPORTED 0@@ -236,55 +230,59 @@ static void print_address_description(void *addr, u8 tag)print_address_stack_frame (addr); } -static bool row_is_guilty (const void *row,const void *guilty) +static bool meta_row_is_guilty (const void *row,const void *addr) { -return (row <= guilty) && (guilty < row +META_BYTES_PER_ROW ); +return (row <= addr) && (addr < row +META_MEM_BYTES_PER_ROW ); } -static int shadow_pointer_offset (const void *row,const void *shadow) +static int meta_pointer_offset (const void *row,const void *addr) { -/* The length of ">ff00ff00ff00ff00: " is -* 3 + (BITS_PER_LONG/8)*2 chars. +/* +* Memory state around the buggy address: +* ff00ff00ff00ff00: 00 00 00 05 fe fe fe fe fe fe fe fe fe fe fe fe +* ... +* +* The length of ">ff00ff00ff00ff00: " is +* 3 + (BITS_PER_LONG / 8) * 2 chars. +* The length of each granule metadata is 2 bytes +* plus 1 byte for space. */ -return 3 + (BITS_PER_LONG /8 )*2 + (shadow - row)*2 + - (shadow - row) /META_BYTES_PER_BLOCK +1 ; +return 3 + (BITS_PER_LONG /8 ) *2 + + (addr - row) /KASAN_GRANULE_SIZE *3 +1 ; }static void print_memory_metadata (const void *addr) {int i; -const void *shadow =kasan_mem_to_shadow (addr); -const void *shadow_row; +void *row; - shadow_row = (void *)round_down ((unsigned long )shadow, -META_BYTES_PER_ROW ) - -META_ROWS_AROUND_ADDR *META_BYTES_PER_ROW ; + row = (void *)round_down ((unsigned long )addr,META_MEM_BYTES_PER_ROW ) + -META_ROWS_AROUND_ADDR *META_MEM_BYTES_PER_ROW ;pr_err ("Memory state around the buggy address:\n" );for (i = -META_ROWS_AROUND_ADDR ; i <=META_ROWS_AROUND_ADDR ; i++) { -const void *kaddr =kasan_shadow_to_mem (shadow_row); -char buffer[4 + (BITS_PER_LONG /8 )*2 ]; -char shadow_buf[META_BYTES_PER_ROW ]; +char buffer[4 + (BITS_PER_LONG /8 ) *2 ]; +char metadata[META_BYTES_PER_ROW ];snprintf (buffer,sizeof (buffer), - (i ==0 ) ?">%px: " :" %px: " , kaddr); + (i ==0 ) ?">%px: " :" %px: " , row); +/* * 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,META_BYTES_PER_ROW ); +metadata_fetch_row (&metadata[0 ], row); +print_hex_dump (KERN_ERR , buffer,DUMP_PREFIX_NONE ,META_BYTES_PER_ROW ,1 , - shadow_buf,META_BYTES_PER_ROW ,0 ); + metadata,META_BYTES_PER_ROW ,0 ); -if (row_is_guilty (shadow_row, shadow)) -pr_err ("%*c\n" , -shadow_pointer_offset (shadow_row, shadow), -'^' ); +if (meta_row_is_guilty (row, addr)) +pr_err ("%*c\n" ,meta_pointer_offset (row, addr),'^' ); - shadow_row +=META_BYTES_PER_ROW ; + row +=META_MEM_BYTES_PER_ROW ; } }mm/kasan/report_generic.c +5
-0@@ -122,6 +122,11 @@ const char *get_bug_type(struct kasan_access_info *info)return get_wild_bug_type (info); } +void metadata_fetch_row (char *buffer,void *row) +{ +memcpy (buffer,kasan_mem_to_shadow (row),META_BYTES_PER_ROW ); +} +#ifdef CONFIG_KASAN_STACK_ENABLE static bool __must_check tokenize_frame_descr(const char **frame_descr, char *token, size_t max_tok_len,mm/kasan/report_sw_tags.c +5
-1@@ -80,6 +80,11 @@ void *find_first_bad_addr(void *addr, size_t size)return p; } +void metadata_fetch_row (char *buffer,void *row) +{ +memcpy (buffer,kasan_mem_to_shadow (row),META_BYTES_PER_ROW ); +} +void print_tags (u8 addr_tag,const void *addr) {u8 *shadow = (u8 *)kasan_mem_to_shadow (addr); --2.28.0.681.g6f77f65b4e-goog
PATCH v3 21/39 kasan: don't allow SW_TAGS with ARM64_MTE
In reply to Andrey KonovalovSoftware tag-based KASAN provides its own tag checking machinery that can conflict with MTE. Don't allow enabling software tag-based KASAN when MTE is enabled.
---
Change-Id: Icd29bd0c6b1d3d7a0ee3d50c20490f404d34fc97
--- arch/arm64/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm64/Kconfig +1 -1
@@ -131,7 +131,7 @@ config ARM64 select HAVE_ARCH_JUMP_LABEL select HAVE_ARCH_JUMP_LABEL_RELATIVE select HAVE_ARCH_KASAN if !(ARM64_16K_PAGES && ARM64_VA_BITS_48) - select HAVE_ARCH_KASAN_SW_TAGS if HAVE_ARCH_KASAN + select HAVE_ARCH_KASAN_SW_TAGS if (HAVE_ARCH_KASAN && !ARM64_MTE) select HAVE_ARCH_KGDB select HAVE_ARCH_MMAP_RND_BITS select HAVE_ARCH_MMAP_RND_COMPAT_BITS if COMPAT
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 21/39] kasan: don't allow SW_TAGS with ARM64_MTE
Does that patch title need an ", arm64" in it, like the others?
Quoted 29 lines · Andrey Konovalov
Software tag-based KASAN provides its own tag checking machinery that can conflict with MTE. Don't allow enabling software tag-based KASAN when MTE is enabled.
Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>Reviewed-by Catalin Marinas <[email protected]>---
Change-Id: Icd29bd0c6b1d3d7a0ee3d50c20490f404d34fc97--- arch/arm64/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)arch/arm64/Kconfig +1
-1@@ -131,7 +131,7 @@ config ARM64 select HAVE_ARCH_JUMP_LABEL select HAVE_ARCH_JUMP_LABEL_RELATIVE select HAVE_ARCH_KASAN if !(ARM64_16K_PAGES && ARM64_VA_BITS_48) - select HAVE_ARCH_KASAN_SW_TAGS if HAVE_ARCH_KASAN + select HAVE_ARCH_KASAN_SW_TAGS if (HAVE_ARCH_KASAN && !ARM64_MTE) select HAVE_ARCH_KGDB select HAVE_ARCH_MMAP_RND_BITS select HAVE_ARCH_MMAP_RND_COMPAT_BITS if COMPATSignature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 21/39] kasan: don't allow SW_TAGS with ARM64_MTE
Quoted 2 lines · On Thu, Oct 1, 2020 at 7:55 PM <[email protected]> wrote:
Does that patch title need an ", arm64" in it, like the others?
Yes, will fix in v4, thanks!
Quoted 31 lines · Andrey Konovalov
Quoted 29 lines
Software tag-based KASAN provides its own tag checking machinery that can conflict with MTE. Don't allow enabling software tag-based KASAN when MTE is enabled.
Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>Reviewed-by Catalin Marinas <[email protected]>---
Change-Id: Icd29bd0c6b1d3d7a0ee3d50c20490f404d34fc97--- arch/arm64/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)arch/arm64/Kconfig +1
-2@@ -131,7 +131,7 @@ config ARM64 select HAVE_ARCH_JUMP_LABEL select HAVE_ARCH_JUMP_LABEL_RELATIVE select HAVE_ARCH_KASAN if !(ARM64_16K_PAGES && ARM64_VA_BITS_48) - select HAVE_ARCH_KASAN_SW_TAGS if HAVE_ARCH_KASAN + select HAVE_ARCH_KASAN_SW_TAGS if (HAVE_ARCH_KASAN && !ARM64_MTE) select HAVE_ARCH_KGDB select HAVE_ARCH_MMAP_RND_BITS select HAVE_ARCH_MMAP_RND_COMPAT_BITS if COMPAT --2.28.0.681.g6f77f65b4e-goog
PATCH v3 22/39 kasan: introduce CONFIG_KASAN_HW_TAGS
In reply to Andrey KonovalovThis patch adds a configuration option for a new KASAN mode called hardware tag-based KASAN. This mode uses the memory tagging approach like the software tag-based mode, but relies on arm64 Memory Tagging Extension feature for tag management and access checking.
---
Change-Id: I246c2def9fffa6563278db1bddfbe742ca7bdefe
--- lib/Kconfig.kasan | 59 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 18 deletions(-)
lib/Kconfig.kasan +41 -18
@@ -6,7 +6,10 @@ config HAVE_ARCH_KASAN config HAVE_ARCH_KASAN_SW_TAGS bool -config HAVE_ARCH_KASAN_VMALLOC +config HAVE_ARCH_KASAN_HW_TAGS + bool + +config HAVE_ARCH_KASAN_VMALLOC bool config CC_HAS_KASAN_GENERIC
@@ -20,11 +23,11 @@ config CC_HAS_WORKING_NOSANITIZE_ADDRESS menuconfig KASAN bool "KASAN: runtime memory debugger" - depends on (HAVE_ARCH_KASAN && CC_HAS_KASAN_GENERIC) || \ - (HAVE_ARCH_KASAN_SW_TAGS && CC_HAS_KASAN_SW_TAGS) + depends on (((HAVE_ARCH_KASAN && CC_HAS_KASAN_GENERIC) || \ + (HAVE_ARCH_KASAN_SW_TAGS && CC_HAS_KASAN_SW_TAGS)) && \ + CC_HAS_WORKING_NOSANITIZE_ADDRESS) || \ + HAVE_ARCH_KASAN_HW_TAGS depends on (SLUB && SYSFS) || (SLAB && !DEBUG_SLAB) - depends on CC_HAS_WORKING_NOSANITIZE_ADDRESS - select SLUB_DEBUG if SLUB select CONSTRUCTORS select STACKDEPOT help
@@ -38,17 +41,23 @@ choice prompt "KASAN mode" default KASAN_GENERIC help - KASAN has two modes: generic KASAN (similar to userspace ASan, - x86_64/arm64/xtensa, enabled with CONFIG_KASAN_GENERIC) and - software tag-based KASAN (a version based on software memory - tagging, arm64 only, similar to userspace HWASan, enabled with - CONFIG_KASAN_SW_TAGS). + KASAN has three modes: + 1. generic KASAN (similar to userspace ASan, + x86_64/arm64/xtensa, enabled with CONFIG_KASAN_GENERIC), + 2. software tag-based KASAN (arm64 only, based on software + memory tagging (similar to userspace HWASan), enabled with + CONFIG_KASAN_SW_TAGS), and + 3. hardware tag-based KASAN (arm64 only, based on hardware + memory tagging, enabled with CONFIG_KASAN_HW_TAGS). + + All KASAN modes are strictly debugging features. - Both generic and tag-based KASAN are strictly debugging features. + For better error reports enable CONFIG_STACKTRACE. config KASAN_GENERIC bool "Generic mode" depends on HAVE_ARCH_KASAN && CC_HAS_KASAN_GENERIC + select SLUB_DEBUG if SLUB help Enables generic KASAN mode.
@@ -61,20 +70,21 @@ config KASAN_GENERIC and introduces an overhead of ~x1.5 for the rest of the allocations. The performance slowdown is ~x3. - For better error detection enable CONFIG_STACKTRACE. - Currently CONFIG_KASAN_GENERIC doesn't work with CONFIG_DEBUG_SLAB (the resulting kernel does not boot). config KASAN_SW_TAGS bool "Software tag-based mode" depends on HAVE_ARCH_KASAN_SW_TAGS && CC_HAS_KASAN_SW_TAGS + select SLUB_DEBUG if SLUB help Enables software tag-based KASAN mode. - This mode requires Top Byte Ignore support by the CPU and therefore - is only supported for arm64. This mode requires Clang version 7.0.0 - or later. + This mode require software memory tagging support in the form of + HWASan-like compiler instrumentation. + + Currently this mode is only implemented for arm64 CPUs and relies on + Top Byte Ignore. This mode requires Clang version 7.0.0 or later. This mode consumes about 1/16th of available memory at kernel start and introduces an overhead of ~20% for the rest of the allocations.
@@ -82,15 +92,27 @@ config KASAN_SW_TAGS casting and comparison, as it embeds tags into the top byte of each pointer. - For better error detection enable CONFIG_STACKTRACE. - Currently CONFIG_KASAN_SW_TAGS doesn't work with CONFIG_DEBUG_SLAB (the resulting kernel does not boot). +config KASAN_HW_TAGS + bool "Hardware tag-based mode" + depends on HAVE_ARCH_KASAN_HW_TAGS + depends on SLUB + help + Enables hardware tag-based KASAN mode. + + This mode requires hardware memory tagging support, and can be used + by any architecture that provides it. + + Currently this mode is only implemented for arm64 CPUs starting from + ARMv8.5 and relies on Memory Tagging Extension and Top Byte Ignore. + endchoice choice prompt "Instrumentation type" + depends on KASAN_GENERIC || KASAN_SW_TAGS default KASAN_OUTLINE config KASAN_OUTLINE
@@ -114,6 +136,7 @@ endchoice config KASAN_STACK_ENABLE bool "Enable stack instrumentation (unsafe)" if CC_IS_CLANG && !COMPILE_TEST + depends on KASAN_GENERIC || KASAN_SW_TAGS help The LLVM stack address sanitizer has a know problem that causes excessive stack usage in a lot of functions, see
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 22/39] kasan: introduce CONFIG_KASAN_HW_TAGS
Quoted 7 lines · Andrey Konovalov
This patch adds a configuration option for a new KASAN mode called hardware tag-based KASAN. This mode uses the memory tagging approach like the software tag-based mode, but relies on arm64 Memory Tagging Extension feature for tag management and access checking.
Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>
Quoted 25 lines
---
Change-Id: I246c2def9fffa6563278db1bddfbe742ca7bdefe--- lib/Kconfig.kasan | 59 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 18 deletions(-)lib/Kconfig.kasan +4
-1@@ -6,7 +6,10 @@ config HAVE_ARCH_KASAN config HAVE_ARCH_KASAN_SW_TAGS bool -config HAVE_ARCH_KASAN_VMALLOC +config HAVE_ARCH_KASAN_HW_TAGS + bool + +config HAVE_ARCH_KASAN_VMALLOC bool config CC_HAS_KASAN_GENERIC@@ -20,11 +23,11 @@ config CC_HAS_WORKING_NOSANITIZE_ADDRESS menuconfig KASAN
lib/Kconfig.kasan config CC_HAS_WORKING_NOSANITIZE_ADDRESS · line 27
Quoted 10 lines
lib/Kconfig.kasan +4
-4bool "KASAN: runtime memory debugger" - depends on (HAVE_ARCH_KASAN && CC_HAS_KASAN_GENERIC) || \ - (HAVE_ARCH_KASAN_SW_TAGS && CC_HAS_KASAN_SW_TAGS) + depends on (((HAVE_ARCH_KASAN && CC_HAS_KASAN_GENERIC) || \ + (HAVE_ARCH_KASAN_SW_TAGS && CC_HAS_KASAN_SW_TAGS)) && \ + CC_HAS_WORKING_NOSANITIZE_ADDRESS) || \ + HAVE_ARCH_KASAN_HW_TAGS depends on (SLUB && SYSFS) || (SLAB && !DEBUG_SLAB) - depends on CC_HAS_WORKING_NOSANITIZE_ADDRESS - select SLUB_DEBUG if SLUB
See my comment in the other patch about moving this line again.
Quoted 101 lines
lib/Kconfig.kasan +33
-13select CONSTRUCTORS select STACKDEPOT help@@ -38,17 +41,23 @@ choice prompt "KASAN mode" default KASAN_GENERIC help - KASAN has two modes: generic KASAN (similar to userspace ASan, - x86_64/arm64/xtensa, enabled with CONFIG_KASAN_GENERIC) and - software tag-based KASAN (a version based on software memory - tagging, arm64 only, similar to userspace HWASan, enabled with - CONFIG_KASAN_SW_TAGS). + KASAN has three modes: + 1. generic KASAN (similar to userspace ASan, + x86_64/arm64/xtensa, enabled with CONFIG_KASAN_GENERIC), + 2. software tag-based KASAN (arm64 only, based on software + memory tagging (similar to userspace HWASan), enabled with + CONFIG_KASAN_SW_TAGS), and + 3. hardware tag-based KASAN (arm64 only, based on hardware + memory tagging, enabled with CONFIG_KASAN_HW_TAGS). + + All KASAN modes are strictly debugging features. - Both generic and tag-based KASAN are strictly debugging features. + For better error reports enable CONFIG_STACKTRACE. config KASAN_GENERIC bool "Generic mode" depends on HAVE_ARCH_KASAN && CC_HAS_KASAN_GENERIC + select SLUB_DEBUG if SLUB help Enables generic KASAN mode.@@ -61,20 +70,21 @@ config KASAN_GENERIC and introduces an overhead of ~x1.5 for the rest of the allocations. The performance slowdown is ~x3. - For better error detection enable CONFIG_STACKTRACE. - Currently CONFIG_KASAN_GENERIC doesn't work with CONFIG_DEBUG_SLAB (the resulting kernel does not boot). config KASAN_SW_TAGS bool "Software tag-based mode" depends on HAVE_ARCH_KASAN_SW_TAGS && CC_HAS_KASAN_SW_TAGS + select SLUB_DEBUG if SLUB help Enables software tag-based KASAN mode. - This mode requires Top Byte Ignore support by the CPU and therefore - is only supported for arm64. This mode requires Clang version 7.0.0 - or later. + This mode require software memory tagging support in the form of + HWASan-like compiler instrumentation. + + Currently this mode is only implemented for arm64 CPUs and relies on + Top Byte Ignore. This mode requires Clang version 7.0.0 or later. This mode consumes about 1/16th of available memory at kernel start and introduces an overhead of ~20% for the rest of the allocations.@@ -82,15 +92,27 @@ config KASAN_SW_TAGS casting and comparison, as it embeds tags into the top byte of each pointer. - For better error detection enable CONFIG_STACKTRACE. - Currently CONFIG_KASAN_SW_TAGS doesn't work with CONFIG_DEBUG_SLAB (the resulting kernel does not boot). +config KASAN_HW_TAGS + bool "Hardware tag-based mode" + depends on HAVE_ARCH_KASAN_HW_TAGS + depends on SLUB + help + Enables hardware tag-based KASAN mode. + + This mode requires hardware memory tagging support, and can be used + by any architecture that provides it. + + Currently this mode is only implemented for arm64 CPUs starting from + ARMv8.5 and relies on Memory Tagging Extension and Top Byte Ignore. + endchoice choice prompt "Instrumentation type" + depends on KASAN_GENERIC || KASAN_SW_TAGS default KASAN_OUTLINE config KASAN_OUTLINE@@ -114,6 +136,7 @@ endchoice config KASAN_STACK_ENABLE bool "Enable stack instrumentation (unsafe)" if CC_IS_CLANG && !COMPILE_TEST + depends on KASAN_GENERIC || KASAN_SW_TAGS help The LLVM stack address sanitizer has a know problem that causes excessive stack usage in a lot of functions, seeSignature · 1 line
2.28.0.681.g6f77f65b4e-goog
PATCH v3 23/39 arm64: Enable armv8.5-a asm-arch option
In reply to Andrey KonovalovFrom: Vincenzo Frascino <[email protected]>
Hardware tag-based KASAN relies on Memory Tagging Extension (MTE) which is an armv8.5-a architecture extension.
Enable the correct asm option when the compiler supports it in order to allow the usage of ALTERNATIVE()s with MTE instructions.
---
Change-Id: I172e15e4c189f073e4c14a10276b276092e76536
--- arch/arm64/Kconfig | 4 ++++ arch/arm64/Makefile | 5 +++++ 2 files changed, 9 insertions(+)
arch/arm64/Kconfig +4 -0
@@ -1600,6 +1600,9 @@ endmenu menu "ARMv8.5 architectural features" +config AS_HAS_ARMV8_5 + def_bool $(cc-option,-Wa$(comma)-march=armv8.5-a) + config ARM64_BTI bool "Branch Target Identification support" default y
@@ -1676,6 +1679,7 @@ config ARM64_MTE bool "Memory Tagging Extension support" default y depends on ARM64_AS_HAS_MTE && ARM64_TAGGED_ADDR_ABI + depends on AS_HAS_ARMV8_5 select ARCH_USES_HIGH_VMA_FLAGS help Memory Tagging (part of the ARMv8.5 Extensions) provides
arch/arm64/Makefile +5 -0
@@ -94,6 +94,11 @@ ifeq ($(CONFIG_AS_HAS_ARMV8_4), y) asm-arch := armv8.4-a endif +ifeq ($(CONFIG_AS_HAS_ARMV8_5), y) +# make sure to pass the newest target architecture to -march. +asm-arch := armv8.5-a +endif + ifdef asm-arch KBUILD_CFLAGS += -Wa,-march=$(asm-arch) \ -DARM64_ASM_ARCH='"$(asm-arch)"'
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 23/39] arm64: Enable armv8.5-a asm-arch option
Quoted 10 lines · Andrey Konovalov
From: Vincenzo Frascino <[email protected]>
Hardware tag-based KASAN relies on Memory Tagging Extension (MTE) which is an armv8.5-a architecture extension.
Enable the correct asm option when the compiler supports it in order to allow the usage of ALTERNATIVE()s with MTE instructions.
Signed-off-by Vincenzo Frascino <[email protected]>Signed-off-by Andrey Konovalov <[email protected]>
PATCH v3 24/39 arm64: mte: Add in-kernel MTE helpers
In reply to Andrey KonovalovFrom: Vincenzo Frascino <[email protected]>
Provide helper functions to manipulate allocation and pointer tags for kernel addresses.
Low-level helper functions (mte_assign_*, written in assembly) operate tag values from the [0x0, 0xF] range. High-level helper functions (mte_get/set_*) use the [0xF0, 0xFF] range to preserve compatibility with normal kernel pointers that have 0xFF in their top byte.
MTE_GRANULE_SIZE and related definitions are moved to mte-def.h header that doesn't have any dependencies and is safe to include into any low-level header.
---
Change-Id: I1b5230254f90dc21a913447cb17f07fea7944ece
--- arch/arm64/include/asm/esr.h | 1 + arch/arm64/include/asm/mte-kasan.h | 60 ++++++++++++++++++++++++++++++ arch/arm64/include/asm/mte.h | 17 ++++++--- arch/arm64/kernel/mte.c | 44 ++++++++++++++++++++++ arch/arm64/lib/mte.S | 19 ++++++++++ 5 files changed, 135 insertions(+), 6 deletions(-) create mode 100644 arch/arm64/include/asm/mte-kasan.h
arch/arm64/include/asm/esr.h +1 -0
@@ -103,6 +103,7 @@#define ESR_ELx_FSC (0x3F)#define ESR_ELx_FSC_TYPE (0x3C)#define ESR_ELx_FSC_EXTABT (0x10) +#define ESR_ELx_FSC_MTE (0x11)#define ESR_ELx_FSC_SERROR (0x11)#define ESR_ELx_FSC_ACCESS (0x08)#define ESR_ELx_FSC_FAULT (0x04)
arch/arm64/include/asm/mte-kasan.h new file +60 -0
60 lines not on this page · raw message
arch/arm64/include/asm/mte.h +11 -6
@@ -5,14 +5,13 @@#ifndef __ASM_MTE_H#define __ASM_MTE_H -#define MTE_GRANULE_SIZE UL(16) -#define MTE_GRANULE_MASK (~(MTE_GRANULE_SIZE - 1)) -#define MTE_TAG_SHIFT 56 -#define MTE_TAG_SIZE 4 +#include <asm/mte-kasan.h> #ifndef __ASSEMBLY__ +#include <linux/bitfield.h> #include <linux/page-flags.h> +#include <linux/types.h> #include <asm/pgtable-types.h>
@@ -45,7 +44,9 @@ long get_mte_ctrl(struct task_struct *task);int mte_ptrace_copy_tags (struct task_struct *child,long request,unsigned long addr,unsigned long data); -#else +void mte_assign_mem_tag_range (void *addr,size_t size); + +#else /* CONFIG_ARM64_MTE */ /* unused if !CONFIG_ARM64_MTE, silence the compiler */ #define PG_mte_tagged 0
@@ -80,7 +81,11 @@ static inline int mte_ptrace_copy_tags(struct task_struct *child,return -EIO ; } -#endif +static inline void mte_assign_mem_tag_range (void *addr,size_t size) +{ +} + +#endif /* CONFIG_ARM64_MTE */ #endif /* __ASSEMBLY__ */ #endif /* __ASM_MTE_H */
arch/arm64/kernel/mte.c +44 -0
58 lines not on this page · raw message
arch/arm64/lib/mte.S +19 -0
@@ -149,3 +149,22 @@ SYM_FUNC_START(mte_restore_page_tags) ret SYM_FUNC_END(mte_restore_page_tags) + +/* + * Assign allocation tags for a region of memory based on the pointer tag + * x0 - source pointer + * x1 - size + * + * Note: size must be non-zero and MTE_GRANULE_SIZE aligned + */ +SYM_FUNC_START(mte_assign_mem_tag_range) + /* if (src == NULL) return; */ + cbz x0, 2f + /* if (size == 0) return; */ + cbz x1, 2f +1: stg x0, [x0] + add x0, x0, #MTE_GRANULE_SIZE + subs x1, x1, #MTE_GRANULE_SIZE + b.gt 1b +2: ret +SYM_FUNC_END(mte_assign_mem_tag_range)
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Catalin Marinas
maintainerRe: [PATCH v3 24/39] arm64: mte: Add in-kernel MTE helpers
Quoted 18 lines · Andrey Konovalov
arch/arm64/include/asm/esr.h +1
-0@@ -103,6 +103,7 @@#define ESR_ELx_FSC (0x3F)#define ESR_ELx_FSC_TYPE (0x3C)#define ESR_ELx_FSC_EXTABT (0x10) +#define ESR_ELx_FSC_MTE (0x11)#define ESR_ELx_FSC_SERROR (0x11)#define ESR_ELx_FSC_ACCESS (0x08)#define ESR_ELx_FSC_FAULT (0x04)arch/arm64/include/asm/mte-kasan.h new file +0
-0
arch/arm64/include/asm/mte-kasan.h line 10
Quoted 10 lines
arch/arm64/include/asm/mte-kasan.h new file +10
-0@@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2020 ARM Ltd. +*/ +#ifndef __ASM_MTE_ASM_H +#define __ASM_MTE_ASM_H + +#include <asm/compiler.h> + +#define __MTE_PREAMBLE ARM64_ASM_PREAMBLE ".arch_extension memtag\n"
Can this not live in mte.h?
arch/arm64/include/asm/mte-kasan.h line 17
Quoted 6 lines
arch/arm64/include/asm/mte-kasan.h new file +6
-0+#define MTE_GRANULE_SIZE UL(16) +#define MTE_GRANULE_MASK (~(MTE_GRANULE_SIZE - 1)) +#define MTE_TAG_SHIFT 56 +#define MTE_TAG_SIZE 4 +#define MTE_TAG_MASK GENMASK((MTE_TAG_SHIFT + (MTE_TAG_SIZE - 1)), MTE_TAG_SHIFT) +#define MTE_TAG_MAX (MTE_TAG_MASK >> MTE_TAG_SHIFT)
I'd still like these MTE_* macros in a separate mte-hwdef.h file. The only reason I see they were not in mte.h is because they need to be included in asm/cache.h. They are not KASAN specific.
arch/arm64/include/asm/mte-kasan.h line 30
Quoted 13 lines
arch/arm64/include/asm/mte-kasan.h new file +13
-0+ +#ifndef __ASSEMBLY__ + +#include <linux/types.h> + +#ifdef CONFIG_ARM64_MTE + +static inline u8 mte_get_ptr_tag (void *ptr) +{ +u8 tag = (u8)(((u64)(ptr)) >>MTE_TAG_SHIFT ); + +return tag; +}
So this returns the top 8 bits of the address (i.e. no masking with MTE_TAG_MASK). Fine by me.
Quoted 14 lines
arch/arm64/include/asm/mte-kasan.h new file +14
-0+ +u8 mte_get_mem_tag (void *addr); +u8 mte_get_random_tag (void ); +void *mte_set_mem_tag_range (void *addr,size_t size,u8 tag); + +#else /* CONFIG_ARM64_MTE */ + +static inline u8 mte_get_ptr_tag (void *ptr) +{ +return 0xFF ; +} + +static inline u8 mte_get_mem_tag (void *addr) +{
arch/arm64/include/asm/mte-kasan.h line 54
Quoted 10 lines
arch/arm64/include/asm/mte-kasan.h new file +10
-0+return 0xFF ; +} +static inline u8 mte_get_random_tag (void ) +{ +return 0xFF ; +} +static inline void *mte_set_mem_tag_range (void *addr,size_t size,u8 tag) +{ +return addr; +}
Maybe these can stay in mte-kasan.h, although they are not a direct interface for KASAN AFAICT (the arch_* equivalent are defined in asm/memory.h. If there's no good reason, we could move them to mte.h.
Quoted 23 lines
arch/arm64/include/asm/mte.h +3
-4@@ -5,14 +5,13 @@#ifndef __ASM_MTE_H#define __ASM_MTE_H -#define MTE_GRANULE_SIZE UL(16) -#define MTE_GRANULE_MASK (~(MTE_GRANULE_SIZE - 1)) -#define MTE_TAG_SHIFT 56 -#define MTE_TAG_SIZE 4 +#include <asm/mte-kasan.h> #ifndef __ASSEMBLY__ +#include <linux/bitfield.h> #include <linux/page-flags.h> +#include <linux/types.h> #include <asm/pgtable-types.h>
arch/arm64/include/asm/mte.h long get_mte_ctrl(struct task_struct *task); · line 47
Quoted 5 lines
arch/arm64/include/asm/mte.h +1
-1@@ -45,7 +44,9 @@ long get_mte_ctrl(struct task_struct *task);int mte_ptrace_copy_tags (struct task_struct *child,long request,unsigned long addr,unsigned long data); -#else +void mte_assign_mem_tag_range (void *addr,size_t size);
So mte_set_mem_tag_range() is KASAN specific but mte_assign_mem_tag_range() is not. Slightly confusing.
Quoted 16 lines
arch/arm64/kernel/mte.c +2
-0@@ -13,8 +13,10 @@#include <linux/swap.h> #include <linux/swapops.h> #include <linux/thread_info.h> +#include <linux/types.h> #include <linux/uio.h> +#include <asm/barrier.h> #include <asm/cpufeature.h> #include <asm/mte.h> #include <asm/ptrace.h>
arch/arm64/kernel/mte.c int memcmp_pages(struct page *page1, struct page *page2) · line 83
Quoted 10 lines
arch/arm64/kernel/mte.c +7
-0@@ -72,6 +74,48 @@ int memcmp_pages(struct page *page1, struct page *page2)return ret; } +u8 mte_get_mem_tag (void *addr) +{ +if (!system_supports_mte ()) +return 0xFF ; + + asmvolatile (__MTE_PREAMBLE"ldg %0, [%0]" + :"+r" (addr));
Nitpick: do we need volatile or plain asm would do?
I wonder whether we'd need the "memory" clobber. I don't see how this would fail though, maybe later on with stack tagging if the compiler writes tags behind our back.
arch/arm64/kernel/mte.c int memcmp_pages(struct page *page1, struct page *page2) · line 85
Quoted 2 lines
arch/arm64/kernel/mte.c +2
-0+ +return 0xF0 |mte_get_ptr_tag (addr);
Since mte_get_ptr_tag() returns the top byte of the address, we don't need the additional 0xF0 or'ing. LDG only sets bits 59:56.
arch/arm64/kernel/mte.c int memcmp_pages(struct page *page1, struct page *page2) · line 98
Quoted 13 lines
arch/arm64/kernel/mte.c +13
-0+} + +u8 mte_get_random_tag (void ) +{ +void *addr; + +if (!system_supports_mte ()) +return 0xFF ; + + asmvolatile (__MTE_PREAMBLE"irg %0, %0" + :"+r" (addr)); + +return 0xF0 |mte_get_ptr_tag (addr);
Same here.
arch/arm64/kernel/mte.c int memcmp_pages(struct page *page1, struct page *page2) · line 109
Quoted 11 lines
arch/arm64/kernel/mte.c +11
-0+} + +void *mte_set_mem_tag_range (void *addr,size_t size,u8 tag) +{ +void *ptr = addr; + +if ((!system_supports_mte ()) || (size ==0 )) +return addr; + +/* Make sure that size is aligned. */ +WARN_ON (size & (MTE_GRANULE_SIZE -1 ));
Doesn't the address need to be aligned as well?
Quoted 17 lines
arch/arm64/kernel/mte.c +9
-0+ + tag =0xF0 | tag; + ptr = (void *)__tag_set (ptr, tag); + +mte_assign_mem_tag_range (ptr, size); + +return ptr; +} +static void update_sctlr_el1_tcf0 (u64 tcf0) {/* ISB required for the kernel uaccess routines */ arch/arm64/lib/mte.S +0
-0
arch/arm64/lib/mte.S SYM_FUNC_START(mte_restore_page_tags) · line 158
Quoted 10 lines
arch/arm64/lib/mte.S +7
-0@@ -149,3 +149,22 @@ SYM_FUNC_START(mte_restore_page_tags) ret SYM_FUNC_END(mte_restore_page_tags) + +/* + * Assign allocation tags for a region of memory based on the pointer tag + * x0 - source pointer + * x1 - size + * + * Note: size must be non-zero and MTE_GRANULE_SIZE aligned
Doesn't the address need to be aligned as well?
arch/arm64/lib/mte.S SYM_FUNC_START(mte_restore_page_tags) · line 164
Quoted 6 lines
arch/arm64/lib/mte.S +6
-0+ */ +SYM_FUNC_START(mte_assign_mem_tag_range) + /* if (src == NULL) return; */ + cbz x0, 2f + /* if (size == 0) return; */ + cbz x1, 2f
I find these checks unnecessary, as I said a couple of times before, just document the function pre-conditions. They are also incomplete (i.e. you check for NULL but not alignment).
Quoted 8 lines
arch/arm64/lib/mte.S +6
-0+1: stg x0, [x0] + add x0, x0, #MTE_GRANULE_SIZE + subs x1, x1, #MTE_GRANULE_SIZE + b.gt 1b +2: ret +SYM_FUNC_END(mte_assign_mem_tag_range)Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Signature · 1 line
Catalin
Vincenzo Frascino
reviewerRe: [PATCH v3 24/39] arm64: mte: Add in-kernel MTE helpers
Quoted 23 lines · Catalin Marinas
Quoted 22 lines · Andrey Konovalov
arch/arm64/include/asm/esr.h +1
-0@@ -103,6 +103,7 @@#define ESR_ELx_FSC (0x3F)#define ESR_ELx_FSC_TYPE (0x3C)#define ESR_ELx_FSC_EXTABT (0x10) +#define ESR_ELx_FSC_MTE (0x11)#define ESR_ELx_FSC_SERROR (0x11)#define ESR_ELx_FSC_ACCESS (0x08)#define ESR_ELx_FSC_FAULT (0x04)arch/arm64/include/asm/mte-kasan.h new file +4
-0@@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2020 ARM Ltd. +*/
Quoted 9 lines
arch/arm64/include/asm/mte-kasan.h line 10
Quoted 6 lines
arch/arm64/include/asm/mte-kasan.h new file +6
-0+#ifndef __ASM_MTE_ASM_H +#define __ASM_MTE_ASM_H + +#include <asm/compiler.h> + +#define __MTE_PREAMBLE ARM64_ASM_PREAMBLE ".arch_extension memtag\n"Can this not live in
mte.h?
Yes, I can move it there in the next version.
Quoted 11 lines
arch/arm64/include/asm/mte-kasan.h line 17
Quoted 6 lines
arch/arm64/include/asm/mte-kasan.h new file +6
-0+#define MTE_GRANULE_SIZE UL(16) +#define MTE_GRANULE_MASK (~(MTE_GRANULE_SIZE - 1)) +#define MTE_TAG_SHIFT 56 +#define MTE_TAG_SIZE 4 +#define MTE_TAG_MASK GENMASK((MTE_TAG_SHIFT + (MTE_TAG_SIZE - 1)), MTE_TAG_SHIFT) +#define MTE_TAG_MAX (MTE_TAG_MASK >> MTE_TAG_SHIFT)I'd still like these MTE_* macros in a separate
mte-hwdef.hfile. The only reason I see they were not inmte.his because they need to be included inasm/cache.h. They are not KASAN specific.
Ok, fine I will reintroduce it in the next version.
Quoted 37 lines
arch/arm64/include/asm/mte-kasan.h line 30
Quoted 13 lines
arch/arm64/include/asm/mte-kasan.h new file +13
-0+ +#ifndef __ASSEMBLY__ + +#include <linux/types.h> + +#ifdef CONFIG_ARM64_MTE + +static inline u8 mte_get_ptr_tag (void *ptr) +{ +u8 tag = (u8)(((u64)(ptr)) >>MTE_TAG_SHIFT ); + +return tag; +}So this returns the top 8 bits of the address (i.e. no masking with
MTE_TAG_MASK). Fine by me.Quoted 20 lines
arch/arm64/include/asm/mte-kasan.h new file +20
-0+ +u8 mte_get_mem_tag (void *addr); +u8 mte_get_random_tag (void ); +void *mte_set_mem_tag_range (void *addr,size_t size,u8 tag); + +#else /* CONFIG_ARM64_MTE */ + +static inline u8 mte_get_ptr_tag (void *ptr) +{ +return 0xFF ; +} + +static inline u8 mte_get_mem_tag (void *addr) +{ +return 0xFF ; +} +static inline u8 mte_get_random_tag (void ) +{ +return 0xFF ; +}
Quoted 9 lines
arch/arm64/include/asm/mte-kasan.h line 54
Quoted 4 lines
arch/arm64/include/asm/mte-kasan.h new file +4
-0+static inline void *mte_set_mem_tag_range (void *addr,size_t size,u8 tag) +{ +return addr; +}Maybe these can stay in
mte-kasan.h, although they are not a direct interface for KASAN AFAICT (the arch_* equivalent are defined inasm/memory.h. If there's no good reason, we could move them tomte.h.
This is here because it is not a direct interface as you noticed. I tried to keep the separation (even if it I have something to fix based on your comment below ;)).
The other kasan implementation define the arch_* indirection in asm/memory.h in every architecture. I think maintaining the design is the best way to non create confusion.
Quoted 26 lines
Quoted 26 lines
arch/arm64/include/asm/mte.h +3
-4@@ -5,14 +5,13 @@#ifndef __ASM_MTE_H#define __ASM_MTE_H -#define MTE_GRANULE_SIZE UL(16) -#define MTE_GRANULE_MASK (~(MTE_GRANULE_SIZE - 1)) -#define MTE_TAG_SHIFT 56 -#define MTE_TAG_SIZE 4 +#include <asm/mte-kasan.h> #ifndef __ASSEMBLY__ +#include <linux/bitfield.h> #include <linux/page-flags.h> +#include <linux/types.h> #include <asm/pgtable-types.h> @@ -45,7 +44,9 @@ long get_mte_ctrl(struct task_struct *task);int mte_ptrace_copy_tags (struct task_struct *child,long request,unsigned long addr,unsigned long data);
Quoted 6 lines
arch/arm64/include/asm/mte.h long get_mte_ctrl(struct task_struct *task); · line 47
Quoted 2 lines
arch/arm64/include/asm/mte.h +1
-1-#else +void mte_assign_mem_tag_range (void *addr,size_t size);So
mte_set_mem_tag_range()is KASAN specific butmte_assign_mem_tag_range()is not. Slightly confusing.
mte_assign_mem_tag_range() is the internal function implemented in assembler which is not used directly by KASAN. Is it the name that you find confusing? Do you have a better proposal?
Quoted 19 lines
Quoted 19 lines
arch/arm64/kernel/mte.c +2
-0@@ -13,8 +13,10 @@#include <linux/swap.h> #include <linux/swapops.h> #include <linux/thread_info.h> +#include <linux/types.h> #include <linux/uio.h> +#include <asm/barrier.h> #include <asm/cpufeature.h> #include <asm/mte.h> #include <asm/ptrace.h> @@ -72,6 +74,48 @@ int memcmp_pages(struct page *page1, struct page *page2)return ret; }
Quoted 10 lines
arch/arm64/kernel/mte.c int memcmp_pages(struct page *page1, struct page *page2) · line 83
Quoted 7 lines
arch/arm64/kernel/mte.c +7
-0+u8 mte_get_mem_tag (void *addr) +{ +if (!system_supports_mte ()) +return 0xFF ; + + asmvolatile (__MTE_PREAMBLE"ldg %0, [%0]" + :"+r" (addr));Nitpick: do we need volatile or plain asm would do?
No we clearly don't anymore :) I will remove it in the next iteration.
Quoted 4 lines
I wonder whether we'd need the "memory" clobber. I don't see how this would fail though, maybe later on with stack tagging if the compiler writes tags behind our back.
As you said, I do not see how this can fail either. We can be overcautious though here and add a comment that the clobber has been added in prevision of stack tagging.
Quoted 6 lines
arch/arm64/kernel/mte.c int memcmp_pages(struct page *page1, struct page *page2) · line 85
Quoted 2 lines
arch/arm64/kernel/mte.c +2
-0+ +return 0xF0 |mte_get_ptr_tag (addr);Since
mte_get_ptr_tag()returns the top byte of the address, we don't need the additional0xF0or'ing. LDG only sets bits 59:56.
Yes, this can clearly go away.
Quoted 7 lines
Quoted 7 lines
arch/arm64/kernel/mte.c +7
-0+} + +u8 mte_get_random_tag (void ) +{ +void *addr; + +if (!system_supports_mte ())
Quoted 9 lines
arch/arm64/kernel/mte.c int memcmp_pages(struct page *page1, struct page *page2) · line 98
Quoted 6 lines
arch/arm64/kernel/mte.c +6
-0+return 0xFF ; + + asmvolatile (__MTE_PREAMBLE"irg %0, %0" + :"+r" (addr)); + +return 0xF0 |mte_get_ptr_tag (addr);Same here.
Agreed.
Quoted 5 lines
Quoted 5 lines
arch/arm64/kernel/mte.c +5
-0+} + +void *mte_set_mem_tag_range (void *addr,size_t size,u8 tag) +{ +void *ptr = addr;
Quoted 9 lines
arch/arm64/kernel/mte.c int memcmp_pages(struct page *page1, struct page *page2) · line 109
Quoted 6 lines
arch/arm64/kernel/mte.c +6
-0+ +if ((!system_supports_mte ()) || (size ==0 )) +return addr; + +/* Make sure that size is aligned. */ +WARN_ON (size & (MTE_GRANULE_SIZE -1 ));Doesn't the address need to be aligned as well?
Yes, we need an extra WARN_ON here. I will add it in the next version.
Quoted 18 lines
Quoted 18 lines
arch/arm64/kernel/mte.c +9
-0+ + tag =0xF0 | tag; + ptr = (void *)__tag_set (ptr, tag); + +mte_assign_mem_tag_range (ptr, size); + +return ptr; +} +static void update_sctlr_el1_tcf0 (u64 tcf0) {/* ISB required for the kernel uaccess routines */ arch/arm64/lib/mte.S +0
-0@@ -149,3 +149,22 @@ SYM_FUNC_START(mte_restore_page_tags)
Quoted 12 lines
arch/arm64/lib/mte.S SYM_FUNC_START(mte_restore_page_tags) · line 158
Quoted 9 lines
arch/arm64/lib/mte.S +7
-0ret SYM_FUNC_END(mte_restore_page_tags) + +/* + * Assign allocation tags for a region of memory based on the pointer tag + * x0 - source pointer + * x1 - size + * + * Note: size must be non-zero and MTE_GRANULE_SIZE alignedDoesn't the address need to be aligned as well?
The comment can be extended.
Quoted 11 lines
arch/arm64/lib/mte.S SYM_FUNC_START(mte_restore_page_tags) · line 164
Quoted 6 lines
arch/arm64/lib/mte.S +6
-0+ */ +SYM_FUNC_START(mte_assign_mem_tag_range) + /* if (src == NULL) return; */ + cbz x0, 2f + /* if (size == 0) return; */ + cbz x1, 2fI find these checks unnecessary, as I said a couple of times before, just document the function pre-conditions. They are also incomplete (i.e. you check for NULL but not alignment).
I thought we agreed to harden the code further, based on [1]. Maybe I misunderstood. I am going to remove them and extend the comment in the next version.
[1]
https://lore.kernel.org/linux-arm-kernel/[email protected]/
Quoted 9 lines
Quoted 8 lines
arch/arm64/lib/mte.S +6
-0+1: stg x0, [x0] + add x0, x0, #MTE_GRANULE_SIZE + subs x1, x1, #MTE_GRANULE_SIZE + b.gt 1b +2: ret +SYM_FUNC_END(mte_assign_mem_tag_range)Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Signature · 2 lines
Regards, Vincenzo
Catalin Marinas
maintainerRe: [PATCH v3 24/39] arm64: mte: Add in-kernel MTE helpers
Quoted 30 lines · Vincenzo Frascino
Quoted 20 lines · Catalin Marinas
Quoted 19 lines · Andrey Konovalov
arch/arm64/include/asm/mte-kasan.h new file +19
-0+u8 mte_get_mem_tag (void *addr); +u8 mte_get_random_tag (void ); +void *mte_set_mem_tag_range (void *addr,size_t size,u8 tag); + +#else /* CONFIG_ARM64_MTE */ + +static inline u8 mte_get_ptr_tag (void *ptr) +{ +return 0xFF ; +} + +static inline u8 mte_get_mem_tag (void *addr) +{ +return 0xFF ; +} +static inline u8 mte_get_random_tag (void ) +{ +return 0xFF ; +}Quoted 8 lines
arch/arm64/include/asm/mte-kasan.h line 54
Quoted 4 lines
arch/arm64/include/asm/mte-kasan.h new file +4
-0+static inline void *mte_set_mem_tag_range (void *addr,size_t size,u8 tag) +{ +return addr; +}Maybe these can stay in
mte-kasan.h, although they are not a direct interface for KASAN AFAICT (the arch_* equivalent are defined inasm/memory.h. If there's no good reason, we could move them tomte.h.
Quoted 7 lines
This is here because it is not a direct interface as you noticed. I tried to keep the separation (even if it I have something to fix based on your comment below ;)).
The other kasan implementation define the arch_* indirection in
asm/memory.hin every architecture. I think maintaining the design is the best way to non create confusion.
I'm ok with asm/memory.h for kasan, no need to change that. You can also keep these functions in asm/mte-kasan.h but add a comment that they are only for the kasan interface defined in asm/memory.h.
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
arch/arm64/include/asm/mte.h +0
-0@@ -5,14 +5,13 @@#ifndef __ASM_MTE_H#define __ASM_MTE_H
Quoted 5 lines
Quoted 5 lines
arch/arm64/include/asm/mte.h line 8
Quoted 5 lines
arch/arm64/include/asm/mte.h +1
-4-#define MTE_GRANULE_SIZE UL(16) -#define MTE_GRANULE_MASK (~(MTE_GRANULE_SIZE - 1)) -#define MTE_TAG_SHIFT 56 -#define MTE_TAG_SIZE 4 +#include <asm/mte-kasan.h>
And this include should be replaced by asm/mte-hwdef.h.
Quoted 18 lines
Quoted 12 lines
Quoted 12 lines
arch/arm64/include/asm/mte.h +2
-0#ifndef __ASSEMBLY__ +#include <linux/bitfield.h> #include <linux/page-flags.h> +#include <linux/types.h> #include <asm/pgtable-types.h> @@ -45,7 +44,9 @@ long get_mte_ctrl(struct task_struct *task);int mte_ptrace_copy_tags (struct task_struct *child,long request,unsigned long addr,unsigned long data);Quoted 5 lines
arch/arm64/include/asm/mte.h long get_mte_ctrl(struct task_struct *task); · line 47
Quoted 2 lines
arch/arm64/include/asm/mte.h +1
-1-#else +void mte_assign_mem_tag_range (void *addr,size_t size);So
mte_set_mem_tag_range()is KASAN specific butmte_assign_mem_tag_range()is not. Slightly confusing.
Quoted 3 lines
mte_assign_mem_tag_range()is the internal function implemented in assembler which is not used directly by KASAN. Is it the name that you find confusing? Do you have a better proposal?
I don't mind the name, just trying to find some consistency in the headers.
Quoted 26 lines
Quoted 26 lines
Quoted 26 lines
arch/arm64/kernel/mte.c +9
-0@@ -13,8 +13,10 @@#include <linux/swap.h> #include <linux/swapops.h> #include <linux/thread_info.h> +#include <linux/types.h> #include <linux/uio.h> +#include <asm/barrier.h> #include <asm/cpufeature.h> #include <asm/mte.h> #include <asm/ptrace.h> @@ -72,6 +74,48 @@ int memcmp_pages(struct page *page1, struct page *page2)return ret; } +u8 mte_get_mem_tag (void *addr) +{ +if (!system_supports_mte ()) +return 0xFF ; + + asmvolatile (__MTE_PREAMBLE"ldg %0, [%0]" + :"+r" (addr));
[...]
Quoted 8 lines
Quoted 4 lines
I wonder whether we'd need the "memory" clobber. I don't see how this would fail though, maybe later on with stack tagging if the compiler writes tags behind our back.
As you said, I do not see how this can fail either. We can be overcautious though here and add a comment that the clobber has been added in prevision of stack tagging.
I don't think we should bother, it may not even matter.
Quoted 12 lines
Quoted 11 lines
arch/arm64/kernel/mte.c
Quoted 6 lines
+ */
arch/arm64/kernel/mte.c +5
-0+SYM_FUNC_START (mte_assign_mem_tag_range) +/* if (src == NULL) return; */ + cbz x0, 2f +/* if (size == 0) return; */ + cbz x1, 2fI find these checks unnecessary, as I said a couple of times before, just document the function pre-conditions. They are also incomplete (i.e. you check for NULL but not alignment).
Quoted 5 lines
I thought we agreed to harden the code further, based on [1]. Maybe I misunderstood. I am going to remove them and extend the comment in the next version.
[1]
https://lore.kernel.org/linux-arm-kernel/[email protected]/
Well, you concluded that but I haven't confirmed ;). Since it's called from a single place which does the checks already, I don't see the point in duplicating them. Documenting should be sufficient.
Signature · 1 line
Catalin
Vincenzo Frascino
reviewerRe: [PATCH v3 24/39] arm64: mte: Add in-kernel MTE helpers
Quoted 10 lines · Catalin Marinas
Quoted 10 lines
Quoted 10 lines
arch/arm64/lib/mte.S SYM_FUNC_START(mte_restore_page_tags) · line 164
Quoted 6 lines
+ */
arch/arm64/lib/mte.S +5
-0+SYM_FUNC_START(mte_assign_mem_tag_range) + /* if (src == NULL) return; */ + cbz x0, 2f + /* if (size == 0) return; */ + cbz x1, 2fI find these checks unnecessary, as I said a couple of times before, just document the function pre-conditions. They are also incomplete (i.e. you check for NULL but not alignment).
Quoted 8 lines
Quoted 5 lines
I thought we agreed to harden the code further, based on [1]. Maybe I misunderstood. I am going to remove them and extend the comment in the next version.
[1]
https://lore.kernel.org/linux-arm-kernel/[email protected]/Well, you concluded that but I haven't confirmed ;). Since it's called from a single place which does the checks already, I don't see the point in duplicating them. Documenting should be sufficient.
Have you ever heard about "tacit consent"? ;) Anw, fine by me, I will add a comment here.
Signature · 2 lines
Regards, Vincenzo
PATCH v3 25/39 arm64: kasan: Add arch layer for memory tagging helpers
In reply to Andrey KonovalovThis patch add a set of arch_*() memory tagging helpers currently only defined for arm64 when hardware tag-based KASAN is enabled. These helpers will be used by KASAN runtime to implement the hardware tag-based mode.
The arch-level indirection level is introduced to simplify adding hardware tag-based KASAN support for other architectures in the future by defining the appropriate arch_*() macros.
---
Change-Id: I42b0795a28067872f8308e00c6f0195bca435c2a
--- arch/arm64/include/asm/memory.h | 8 ++++++++ mm/kasan/kasan.h | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+)
arch/arm64/include/asm/memory.h +8 -0
@@ -231,6 +231,14 @@ static inline const void *__tag_set(const void *addr, u8 tag)return (const void *)(__addr |__tag_shifted (tag)); } +#ifdef CONFIG_KASAN_HW_TAGS +#define arch_init_tags (max_tag) mte_init_tags(max_tag) +#define arch_get_random_tag () mte_get_random_tag() +#define arch_get_mem_tag (addr) mte_get_mem_tag(addr) +#define arch_set_mem_tag_range (addr, size, tag) \ + mte_set_mem_tag_range((addr), (size), (tag)) +#endif /* CONFIG_KASAN_HW_TAGS */ +/* * Physical vs virtual RAM address space conversion. These are * private definitions which should NOT be used outside memory.h
mm/kasan/kasan.h +18 -0
@@ -241,6 +241,24 @@ static inline const void *arch_kasan_set_tag(const void *addr, u8 tag)#define reset_tag (addr) ((void *)arch_kasan_reset_tag(addr))#define get_tag (addr) arch_kasan_get_tag(addr) +#ifndef arch_init_tags +#define arch_init_tags (max_tag) +#endif +#ifndef arch_get_random_tag +#define arch_get_random_tag () (0xFF) +#endif +#ifndef arch_get_mem_tag +#define arch_get_mem_tag (addr) (0xFF) +#endif +#ifndef arch_set_mem_tag_range +#define arch_set_mem_tag_range (addr, size, tag) ((void *)(addr)) +#endif + +#define init_tags (max_tag) arch_init_tags(max_tag) +#define get_random_tag () arch_get_random_tag() +#define get_mem_tag (addr) arch_get_mem_tag(addr) +#define set_mem_tag_range (addr, size, tag) arch_set_mem_tag_range((addr), (size), (tag)) +/* * Exported functions for interfaces called from assembly or from generated * code. Declarations here to avoid warning about missing declarations.
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
PATCH v3 26/39 arm64: mte: Add in-kernel tag fault handler
In reply to Andrey KonovalovFrom: Vincenzo Frascino <[email protected]>
Add the implementation of the in-kernel fault handler.
When a tag fault happens on a kernel address:
* MTE is disabled on the current CPU,
* the execution continues.
When a tag fault happens on a user address:
* the kernel executes do_bad_area() and panics.
The tag fault handler for kernel addresses is currently empty and will be filled in by a future commit.
---
Change-Id: I9b8aa79567f7c45f4d6a1290efcf34567e620717
--- arch/arm64/include/asm/uaccess.h | 23 +++++++++++++++++++ arch/arm64/mm/fault.c | 38 +++++++++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 1 deletion(-)
arch/arm64/include/asm/uaccess.h +23 -0
@@ -200,13 +200,36 @@ do { \ CONFIG_ARM64_PAN)); \ }while (0 ) +/* +* The Tag Check Flag (TCF) mode for MTE is per EL, hence TCF0 +* affects EL0 and TCF affects EL1 irrespective of which TTBR is +* used. +* The kernel accesses TTBR0 usually with LDTR/STTR instructions +* when UAO is available, so these would act as EL0 accesses using +* TCF0. +* However futex.h code uses exclusives which would be executed as +* EL1, this can potentially cause a tag check fault even if the +* user disables TCF0. +* +* To address the problem we set the PSTATE.TCO bit in uaccess_enable() +* and reset it in uaccess_disable(). +* +* The Tag check override (TCO) bit disables temporarily the tag checking +* preventing the issue. +*/ static inline void uaccess_disable(void) { + asm volatile(ALTERNATIVE("nop", SET_PSTATE_TCO(0), + ARM64_MTE, CONFIG_KASAN_HW_TAGS)); +__uaccess_disable (ARM64_HAS_PAN ); }static inline void uaccess_enable (void ) { + asm volatile(ALTERNATIVE("nop", SET_PSTATE_TCO(1), + ARM64_MTE, CONFIG_KASAN_HW_TAGS)); +__uaccess_enable (ARM64_HAS_PAN ); }
arch/arm64/mm/fault.c +37 -1
@@ -33,6 +33,7 @@#include <asm/debug-monitors.h> #include <asm/esr.h> #include <asm/kprobes.h> +#include <asm/mte.h> #include <asm/processor.h> #include <asm/sysreg.h> #include <asm/system_misc.h>
@@ -294,6 +295,11 @@ static void die_kernel_fault(const char *msg, unsigned long addr,do_exit (SIGKILL ); } +static void report_tag_fault (unsigned long addr,unsigned int esr, +struct pt_regs *regs) +{ +} +static void __do_kernel_fault (unsigned long addr,unsigned int esr,struct pt_regs *regs) {
@@ -641,10 +647,40 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)return 0 ; } +static void do_tag_recovery (unsigned long addr,unsigned int esr, +struct pt_regs *regs) +{ +static bool reported = false; + +if (!READ_ONCE (reported)) { +report_tag_fault (addr, esr, regs); +WRITE_ONCE (reported, true); + } + +/* +* Disable MTE Tag Checking on the local CPU for the current EL. +* It will be done lazily on the other CPUs when they will hit a +* tag fault. +*/ +sysreg_clear_set (sctlr_el1, SCTLR_ELx_TCF_MASK, SCTLR_ELx_TCF_NONE); +isb (); +} + +static int do_tag_check_fault (unsigned long addr,unsigned int esr,struct pt_regs *regs) { -do_bad_area (addr, esr, regs); +/* +* The tag check fault (TCF) is per EL, hence TCF0 affects +* EL0 and TCF affects EL1. +* TTBR0 address belong by convention to EL0 hence to correctly +* discriminate we use the is_ttbr0_addr() macro. +*/ +if (is_ttbr0_addr (addr)) +do_bad_area (addr, esr, regs); +else +do_tag_recovery (addr, esr, regs); +return 0 ; }
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Catalin Marinas
maintainerRe: [PATCH v3 26/39] arm64: mte: Add in-kernel tag fault handler
Quoted 30 lines · Andrey Konovalov
arch/arm64/include/asm/uaccess.h +20
-0@@ -200,13 +200,36 @@ do { \ CONFIG_ARM64_PAN)); \ }while (0 ) +/* +* The Tag Check Flag (TCF) mode for MTE is per EL, hence TCF0 +* affects EL0 and TCF affects EL1 irrespective of which TTBR is +* used. +* The kernel accesses TTBR0 usually with LDTR/STTR instructions +* when UAO is available, so these would act as EL0 accesses using +* TCF0. +* However futex.h code uses exclusives which would be executed as +* EL1, this can potentially cause a tag check fault even if the +* user disables TCF0. +* +* To address the problem we set the PSTATE.TCO bit in uaccess_enable() +* and reset it in uaccess_disable(). +* +* The Tag check override (TCO) bit disables temporarily the tag checking +* preventing the issue. +*/ static inline void uaccess_disable(void) { + asm volatile(ALTERNATIVE("nop", SET_PSTATE_TCO(0), + ARM64_MTE, CONFIG_KASAN_HW_TAGS)); +
arch/arm64/include/asm/uaccess.h do { \ · line 234
Quoted 10 lines
arch/arm64/include/asm/uaccess.h +3
-0__uaccess_disable (ARM64_HAS_PAN ); }static inline void uaccess_enable (void ) { + asm volatile(ALTERNATIVE("nop", SET_PSTATE_TCO(1), + ARM64_MTE, CONFIG_KASAN_HW_TAGS)); +__uaccess_enable (ARM64_HAS_PAN ); }
This look fine.
Quoted 13 lines
arch/arm64/mm/fault.c +1
-0@@ -33,6 +33,7 @@#include <asm/debug-monitors.h> #include <asm/esr.h> #include <asm/kprobes.h> +#include <asm/mte.h> #include <asm/processor.h> #include <asm/sysreg.h> #include <asm/system_misc.h>
arch/arm64/mm/fault.c static void die_kernel_fault(const char *msg, unsigned long addr, · line 301
Quoted 7 lines
arch/arm64/mm/fault.c +4
-0@@ -294,6 +295,11 @@ static void die_kernel_fault(const char *msg, unsigned long addr,do_exit (SIGKILL ); } +static void report_tag_fault (unsigned long addr,unsigned int esr, +struct pt_regs *regs) +{ +}
Do we need to introduce report_tag_fault() in this patch? It's fine but add a note in the commit log that it will be populated in a subsequent patch.
Quoted 7 lines
arch/arm64/mm/fault.c +1
-0+static void __do_kernel_fault (unsigned long addr,unsigned int esr,struct pt_regs *regs) {@@ -641,10 +647,40 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)return 0 ; }
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 658
Quoted 10 lines
arch/arm64/mm/fault.c +9
-0+static void do_tag_recovery (unsigned long addr,unsigned int esr, +struct pt_regs *regs) +{ +static bool reported = false; + +if (!READ_ONCE (reported)) { +report_tag_fault (addr, esr, regs); +WRITE_ONCE (reported, true); + }
I don't mind the READ_ONCE/WRITE_ONCE here but not sure what they help with.
Signature · 1 line
Catalin
Re: [PATCH v3 26/39] arm64: mte: Add in-kernel tag fault handler
Quoted 17 lines · Catalin Marinas
Quoted 17 lines
arch/arm64/mm/fault.c +1
-0@@ -33,6 +33,7 @@#include <asm/debug-monitors.h> #include <asm/esr.h> #include <asm/kprobes.h> +#include <asm/mte.h> #include <asm/processor.h> #include <asm/sysreg.h> #include <asm/system_misc.h> @@ -294,6 +295,11 @@ static void die_kernel_fault(const char *msg, unsigned long addr,do_exit (SIGKILL ); }
Quoted 8 lines
arch/arm64/mm/fault.c static void die_kernel_fault(const char *msg, unsigned long addr, · line 301
Quoted 4 lines
arch/arm64/mm/fault.c +4
-0+static void report_tag_fault (unsigned long addr,unsigned int esr, +struct pt_regs *regs) +{ +}Do we need to introduce
report_tag_fault()in this patch? It's fine but add a note in the commit log that it will be populated in a subsequent patch.
I did, see the last line of the commit description.
Quoted 8 lines
Quoted 8 lines
arch/arm64/mm/fault.c +1
-0+static void __do_kernel_fault (unsigned long addr,unsigned int esr,struct pt_regs *regs) {@@ -641,10 +647,40 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)return 0 ; }
Quoted 12 lines
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 658
Quoted 9 lines
arch/arm64/mm/fault.c +9
-0+static void do_tag_recovery (unsigned long addr,unsigned int esr, +struct pt_regs *regs) +{ +static bool reported = false; + +if (!READ_ONCE (reported)) { +report_tag_fault (addr, esr, regs); +WRITE_ONCE (reported, true); + }I don't mind the READ_ONCE/WRITE_ONCE here but not sure what they help with.
The fault can happen on multiple cores at the same time, right? In that case without READ/WRITE_ONCE() we'll have a data-race here.
Catalin Marinas
maintainerRe: [PATCH v3 26/39] arm64: mte: Add in-kernel tag fault handler
Quoted 27 lines · Andrey Konovalov
Quoted 16 lines · Catalin Marinas
Quoted 16 lines
arch/arm64/mm/fault.c +1
-0@@ -33,6 +33,7 @@#include <asm/debug-monitors.h> #include <asm/esr.h> #include <asm/kprobes.h> +#include <asm/mte.h> #include <asm/processor.h> #include <asm/sysreg.h> #include <asm/system_misc.h> @@ -294,6 +295,11 @@ static void die_kernel_fault(const char *msg, unsigned long addr,do_exit (SIGKILL ); }Quoted 8 lines
arch/arm64/mm/fault.c static void die_kernel_fault(const char *msg, unsigned long addr, · line 301
Quoted 4 lines
arch/arm64/mm/fault.c +4
-0+static void report_tag_fault (unsigned long addr,unsigned int esr, +struct pt_regs *regs) +{ +}Do we need to introduce
report_tag_fault()in this patch? It's fine but add a note in the commit log that it will be populated in a subsequent patch.
Quoted 1 line
I did, see the last line of the commit description.
Sorry, I missed that.
Quoted 21 lines
Quoted 8 lines
Quoted 8 lines
arch/arm64/mm/fault.c +1
-0+static void __do_kernel_fault (unsigned long addr,unsigned int esr,struct pt_regs *regs) {@@ -641,10 +647,40 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)return 0 ; }Quoted 12 lines
arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 658
Quoted 9 lines
arch/arm64/mm/fault.c +9
-0+static void do_tag_recovery (unsigned long addr,unsigned int esr, +struct pt_regs *regs) +{ +static bool reported = false; + +if (!READ_ONCE (reported)) { +report_tag_fault (addr, esr, regs); +WRITE_ONCE (reported, true); + }I don't mind the READ_ONCE/WRITE_ONCE here but not sure what they help with.
Quoted 2 lines
The fault can happen on multiple cores at the same time, right? In that case without READ/WRITE_ONCE() we'll have a data-race here.
READ/WRITE_ONCE won't magically solve such races. If two CPUs enter simultaneously in do_tag_recovery(), they'd both read 'reported' as false and both print the fault info.
If you really care about this race, you need to atomically both read and update the variable with an xchg() or cmpxchg().
Signature · 1 line
Catalin
Re: [PATCH v3 26/39] arm64: mte: Add in-kernel tag fault handler
Quoted 29 lines · Catalin Marinas
Quoted 27 lines · Andrey Konovalov
Quoted 24 lines · Catalin Marinas
Quoted 13 lines
arch/arm64/mm/fault.c +1
-0@@ -33,6 +33,7 @@#include <asm/debug-monitors.h> #include <asm/esr.h> #include <asm/kprobes.h> +#include <asm/mte.h> #include <asm/processor.h> #include <asm/sysreg.h> #include <asm/system_misc.h> arch/arm64/mm/fault.c static void die_kernel_fault(const char *msg, unsigned long addr, · line 301
Quoted 7 lines
arch/arm64/mm/fault.c +4
-0@@ -294,6 +295,11 @@ static void die_kernel_fault(const char *msg, unsigned long addr,do_exit (SIGKILL ); } +static void report_tag_fault (unsigned long addr,unsigned int esr, +struct pt_regs *regs) +{ +}Do we need to introduce
report_tag_fault()in this patch? It's fine but add a note in the commit log that it will be populated in a subsequent patch.
Quoted 3 lines
Quoted 1 line
I did, see the last line of the commit description.
Sorry, I missed that.
No problem!
Quoted 21 lines
Quoted 21 lines
Quoted 20 lines
Quoted 7 lines
arch/arm64/mm/fault.c +1
-0+static void __do_kernel_fault (unsigned long addr,unsigned int esr,struct pt_regs *regs) {@@ -641,10 +647,40 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)return 0 ; }arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 658
Quoted 10 lines
arch/arm64/mm/fault.c +9
-0+static void do_tag_recovery (unsigned long addr,unsigned int esr, +struct pt_regs *regs) +{ +static bool reported = false; + +if (!READ_ONCE (reported)) { +report_tag_fault (addr, esr, regs); +WRITE_ONCE (reported, true); + }I don't mind the READ_ONCE/WRITE_ONCE here but not sure what they help with.
Quoted 6 lines
Quoted 2 lines
The fault can happen on multiple cores at the same time, right? In that case without READ/WRITE_ONCE() we'll have a data-race here.
READ/WRITE_ONCE won't magically solve such races. If two CPUs enter simultaneously in
do_tag_recovery(), they'd both read 'reported' as false and both print the fault info.
They won't solve the race condition, but they will solve the data race. I guess here we don't really care about the race condition, as printing a tag fault twice is OK. But having a data race here will lead to KCSAN reports, although won't probably break anything in practice.
Quoted 2 lines
If you really care about this race, you need to atomically both read and update the variable with an
xchg()orcmpxchg().
Catalin Marinas
maintainerRe: [PATCH v3 26/39] arm64: mte: Add in-kernel tag fault handler
Quoted 32 lines · Andrey Konovalov
Quoted 24 lines · Catalin Marinas
Quoted 23 lines · Andrey Konovalov
Quoted 20 lines · Catalin Marinas
Quoted 7 lines
arch/arm64/mm/fault.c +1
-0+static void __do_kernel_fault (unsigned long addr,unsigned int esr,struct pt_regs *regs) {@@ -641,10 +647,40 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)return 0 ; }arch/arm64/mm/fault.c static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) · line 658
Quoted 10 lines
arch/arm64/mm/fault.c +9
-0+static void do_tag_recovery (unsigned long addr,unsigned int esr, +struct pt_regs *regs) +{ +static bool reported = false; + +if (!READ_ONCE (reported)) { +report_tag_fault (addr, esr, regs); +WRITE_ONCE (reported, true); + }I don't mind the READ_ONCE/WRITE_ONCE here but not sure what they help with.
Quoted 6 lines
Quoted 2 lines
The fault can happen on multiple cores at the same time, right? In that case without READ/WRITE_ONCE() we'll have a data-race here.
READ/WRITE_ONCE won't magically solve such races. If two CPUs enter simultaneously in
do_tag_recovery(), they'd both read 'reported' as false and both print the fault info.
Quoted 5 lines
They won't solve the race condition, but they will solve the data race. I guess here we don't really care about the race condition, as printing a tag fault twice is OK. But having a data race here will lead to KCSAN reports, although won't probably break anything in practice.
I agree, in practice it should be fine. Anyway, it doesn't hurt leaving them in place.
Signature · 1 line
Catalin
Re: [PATCH v3 26/39] arm64: mte: Add in-kernel tag fault handler
In reply to Andrey KonovalovQuoted 11 lines · Andrey Konovalov
From: Vincenzo Frascino <[email protected]>
Add the implementation of the in-kernel fault handler.
When a tag fault happens on a kernel address:
* MTE is disabled on the current CPU,
* the execution continues.When a tag fault happens on a user address:
* the kernel executesdo_bad_area()and panics.
Quoted 6 lines
The tag fault handler for kernel addresses is currently empty and will be filled in by a future commit.
Signed-off-by Vincenzo Frascino <[email protected]>Co-developed-by Andrey Konovalov <[email protected]>Signed-off-by Andrey Konovalov <[email protected]>
PATCH v3 27/39 arm64: kasan: Enable in-kernel MTE
In reply to Andrey KonovalovFrom: Vincenzo Frascino <[email protected]>
Hardware tag-based KASAN relies on Memory Tagging Extension (MTE) feature and requires it to be enabled.
The Tag Checking operation causes a synchronous data abort as a consequence of a tag check fault when MTE is configured in synchronous mode.
Enable MTE in Synchronous mode in EL1 to provide a more immediate way of tag check failure detection in the kernel.
As part of this change enable match-all tag for EL1 to allow the kernel to access user pages without faulting. This is required because the kernel does not have knowledge of the tags set by the user in a page.
Note: For MTE, the TCF bit field in SCTLR_EL1 affects only EL1 in a similar way as TCF0 affects EL0.
---
Change-Id: I4d67497268bb7f0c2fc5dcacefa1e273df4af71d
--- arch/arm64/kernel/cpufeature.c | 7 +++++++ arch/arm64/mm/proc.S | 11 +++++++++++ 2 files changed, 18 insertions(+)
arch/arm64/kernel/cpufeature.c +7 -0
@@ -1718,6 +1718,13 @@ static void cpu_enable_mte(struct arm64_cpu_capabilities const *cap) cleared_zero_page = true; mte_clear_page_tags(lm_alias(empty_zero_page)); } + +/* Enable in-kernel MTE only if KASAN_HW_TAGS is enabled */ +if (IS_ENABLED (CONFIG_KASAN_HW_TAGS )) { +/* Enable MTE Sync Mode for EL1 */ +sysreg_clear_set (sctlr_el1, SCTLR_ELx_TCF_MASK, SCTLR_ELx_TCF_SYNC); +isb (); + } }#endif /* CONFIG_ARM64_MTE */
arch/arm64/mm/proc.S +11 -0
@@ -427,6 +427,10 @@ SYM_FUNC_START(__cpu_setup) */ mov_q x5, MAIR_EL1_SET #ifdef CONFIG_ARM64_MTE + mte_tcr .req x20 + + mov mte_tcr, #0 + /* * Update MAIR_EL1, GCR_EL1 and TFSR*_EL1 if MTE is supported * (ID_AA64PFR1_EL1[11:8] > 1).
@@ -447,6 +451,9 @@ SYM_FUNC_START(__cpu_setup) /* clear any pending tag check faults in TFSR*_EL1 */ msr_s SYS_TFSR_EL1, xzr msr_s SYS_TFSRE0_EL1, xzr + + /* set the TCR_EL1 bits */ + orr mte_tcr, mte_tcr, #SYS_TCR_EL1_TCMA1 1: #endif msr mair_el1, x5
@@ -457,6 +464,10 @@ SYM_FUNC_START(__cpu_setup) mov_q x10, TCR_TxSZ(VA_BITS) | TCR_CACHE_FLAGS | TCR_SMP_FLAGS | \ TCR_TG_FLAGS | TCR_KASLR_FLAGS | TCR_ASID16 | \ TCR_TBI0 | TCR_A1 | TCR_KASAN_FLAGS +#ifdef CONFIG_ARM64_MTE + orr x10, x10, mte_tcr + .unreq mte_tcr +#endif tcr_clear_errata_bits x10, x9, x5 #ifdef CONFIG_ARM64_VA_BITS_52
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 27/39] arm64: kasan: Enable in-kernel MTE
Quoted 26 lines · Andrey Konovalov
arch/arm64/mm/proc.S +7
-0@@ -427,6 +427,10 @@ SYM_FUNC_START(__cpu_setup) */ mov_q x5, MAIR_EL1_SET #ifdef CONFIG_ARM64_MTE + mte_tcr .req x20 + + mov mte_tcr, #0 + /* * Update MAIR_EL1, GCR_EL1 and TFSR*_EL1 if MTE is supported * (ID_AA64PFR1_EL1[11:8] > 1).@@ -447,6 +451,9 @@ SYM_FUNC_START(__cpu_setup) /* clear any pending tag check faults in TFSR*_EL1 */ msr_s SYS_TFSR_EL1, xzr msr_s SYS_TFSRE0_EL1, xzr + + /* set the TCR_EL1 bits */ + orr mte_tcr, mte_tcr, #SYS_TCR_EL1_TCMA1 1: #endif msr mair_el1, x5
arch/arm64/mm/proc.S SYM_FUNC_START(__cpu_setup) · line 471
Quoted 8 lines
arch/arm64/mm/proc.S +4
-0@@ -457,6 +464,10 @@ SYM_FUNC_START(__cpu_setup) mov_q x10, TCR_TxSZ(VA_BITS) | TCR_CACHE_FLAGS | TCR_SMP_FLAGS | \ TCR_TG_FLAGS | TCR_KASLR_FLAGS | TCR_ASID16 | \ TCR_TBI0 | TCR_A1 | TCR_KASAN_FLAGS +#ifdef CONFIG_ARM64_MTE + orr x10, x10, mte_tcr + .unreq mte_tcr +#endif tcr_clear_errata_bits x10, x9, x5
I had a slightly different preference (see the previous version) to avoid the #ifdef altogether but this works as well.
PATCH v3 28/39 arm64: mte: Convert gcr_user into an exclude mask
In reply to Andrey KonovalovFrom: Vincenzo Frascino <[email protected]>
The gcr_user mask is a per thread mask that represents the tags that are excluded from random generation when the Memory Tagging Extension is present and an 'irg' instruction is invoked.
gcr_user affects the behavior on EL0 only.
Currently that mask is an include mask and it is controlled by the user via prctl() while GCR_EL1 accepts an exclude mask.
Convert the include mask into an exclude one to make it easier the register setting.
Note: This change will affect gcr_kernel (for EL1) introduced with a future patch.
---
Change-Id: Id15c0b47582fb51594bb26fb8353d78c7d0953c1
--- arch/arm64/include/asm/processor.h | 2 +- arch/arm64/kernel/mte.c | 29 +++++++++++++++-------------- 2 files changed, 16 insertions(+), 15 deletions(-)
arch/arm64/include/asm/processor.h +1 -1
@@ -153,7 +153,7 @@ struct thread_struct {#endif #ifdef CONFIG_ARM64_MTE u64 sctlr_tcf0; -u64 gcr_user_incl; +u64 gcr_user_excl;#endif };
arch/arm64/kernel/mte.c +15 -14
@@ -136,23 +136,22 @@ static void set_sctlr_el1_tcf0(u64 tcf0)preempt_enable (); } -static void update_gcr_el1_excl (u64 incl) +static void update_gcr_el1_excl (u64 excl) { -u64 excl = ~incl &SYS_GCR_EL1_EXCL_MASK ;/* -* Note that 'incl' is an include mask (controlled by the user via -* prctl()) while GCR_EL1 accepts an exclude mask. +* Note that the mask controlled by the user via prctl() is an +* include while GCR_EL1 accepts an exclude mask. * No need for ISB since this only affects EL0 currently, implicit * with ERET. */ sysreg_clear_set_s (SYS_GCR_EL1 ,SYS_GCR_EL1_EXCL_MASK , excl); } -static void set_gcr_el1_excl (u64 incl) +static void set_gcr_el1_excl (u64 excl) { - current->thread.gcr_user_incl = incl; -update_gcr_el1_excl (incl); + current->thread.gcr_user_excl = excl; +update_gcr_el1_excl (excl); }void flush_mte_state (void )
@@ -167,7 +166,7 @@ void flush_mte_state(void)/* disable tag checking */ set_sctlr_el1_tcf0 (SCTLR_EL1_TCF0_NONE );/* reset tag generation mask */ -set_gcr_el1_excl (0 ); +set_gcr_el1_excl (SYS_GCR_EL1_EXCL_MASK ); }void mte_thread_switch (struct task_struct *next)
@@ -178,7 +177,7 @@ void mte_thread_switch(struct task_struct *next)/* avoid expensive SCTLR_EL1 accesses if no change */ if (current->thread.sctlr_tcf0 != next->thread.sctlr_tcf0)update_sctlr_el1_tcf0 (next->thread.sctlr_tcf0); -update_gcr_el1_excl (next->thread.gcr_user_incl); +update_gcr_el1_excl (next->thread.gcr_user_excl); }void mte_suspend_exit (void )
@@ -186,13 +185,14 @@ void mte_suspend_exit(void)if (!system_supports_mte ())return ; -update_gcr_el1_excl (current->thread.gcr_user_incl); +update_gcr_el1_excl (current->thread.gcr_user_excl); }long set_mte_ctrl (struct task_struct *task,unsigned long arg) {u64 tcf0; -u64 gcr_incl = (arg &PR_MTE_TAG_MASK ) >>PR_MTE_TAG_SHIFT ; +u64 gcr_excl = ~((arg &PR_MTE_TAG_MASK ) >>PR_MTE_TAG_SHIFT ) & +SYS_GCR_EL1_EXCL_MASK ;if (!system_supports_mte ())return 0 ;
@@ -213,10 +213,10 @@ long set_mte_ctrl(struct task_struct *task, unsigned long arg)if (task != current) { task->thread.sctlr_tcf0 = tcf0; - task->thread.gcr_user_incl = gcr_incl; + task->thread.gcr_user_excl = gcr_excl; }else {set_sctlr_el1_tcf0 (tcf0); -set_gcr_el1_excl (gcr_incl); +set_gcr_el1_excl (gcr_excl); }return 0 ;
@@ -225,11 +225,12 @@ long set_mte_ctrl(struct task_struct *task, unsigned long arg)long get_mte_ctrl (struct task_struct *task) {unsigned long ret; +u64 incl = ~task->thread.gcr_user_excl &SYS_GCR_EL1_EXCL_MASK ;if (!system_supports_mte ())return 0 ; - ret = task->thread.gcr_user_incl <<PR_MTE_TAG_SHIFT ; + ret = incl <<PR_MTE_TAG_SHIFT ;switch (task->thread.sctlr_tcf0) {case SCTLR_EL1_TCF0_NONE :
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
PATCH v3 29/39 arm64: mte: Switch GCR_EL1 in kernel entry and exit
In reply to Andrey KonovalovFrom: Vincenzo Frascino <[email protected]>
When MTE is present, the GCR_EL1 register contains the tags mask that allows to exclude tags from the random generation via the IRG instruction.
With the introduction of the new Tag-Based KASAN API that provides a mechanism to reserve tags for special reasons, the MTE implementation has to make sure that the GCR_EL1 setting for the kernel does not affect the userspace processes and viceversa.
Save and restore the kernel/user mask in GCR_EL1 in kernel entry and exit.
---
Change-Id: I0081cba5ace27a9111bebb239075c9a466af4c84
--- arch/arm64/include/asm/mte-kasan.h | 6 ++++ arch/arm64/include/asm/mte.h | 2 ++ arch/arm64/kernel/asm-offsets.c | 3 ++ arch/arm64/kernel/cpufeature.c | 3 ++ arch/arm64/kernel/entry.S | 47 ++++++++++++++++++++++++++++++ arch/arm64/kernel/mte.c | 18 ++++++++++-- 6 files changed, 76 insertions(+), 3 deletions(-)
arch/arm64/include/asm/mte-kasan.h +6 -0
@@ -33,6 +33,8 @@ u8 mte_get_mem_tag(void *addr);u8 mte_get_random_tag (void );void *mte_set_mem_tag_range (void *addr,size_t size,u8 tag); +void mte_init_tags (u64 max_tag); +#else /* CONFIG_ARM64_MTE */ static inline u8 mte_get_ptr_tag (void *ptr)
@@ -53,6 +55,10 @@ static inline void *mte_set_mem_tag_range(void *addr, size_t size, u8 tag)return addr; } +static inline void mte_init_tags (u64 max_tag) +{ +} +#endif /* CONFIG_ARM64_MTE */ #endif /* __ASSEMBLY__ */
arch/arm64/include/asm/mte.h +2 -0
@@ -15,6 +15,8 @@#include <asm/pgtable-types.h> +extern u64 gcr_kernel_excl; +void mte_clear_page_tags (void *addr);unsigned long mte_copy_tags_from_user (void *to,const void __user *from,unsigned long n);
arch/arm64/kernel/asm-offsets.c +3 -0
@@ -47,6 +47,9 @@ int main(void)#ifdef CONFIG_ARM64_PTR_AUTH DEFINE(THREAD_KEYS_USER, offsetof(struct task_struct, thread.keys_user)); DEFINE(THREAD_KEYS_KERNEL, offsetof(struct task_struct, thread.keys_kernel)); +#endif +#ifdef CONFIG_ARM64_MTE + DEFINE(THREAD_GCR_EL1_USER, offsetof(struct task_struct, thread.gcr_user_excl));#endif BLANK (); DEFINE(S_X0, offsetof(struct pt_regs, regs[0]));
arch/arm64/kernel/cpufeature.c +3 -0
@@ -1721,6 +1721,9 @@ static void cpu_enable_mte(struct arm64_cpu_capabilities const *cap)/* Enable in-kernel MTE only if KASAN_HW_TAGS is enabled */ if (IS_ENABLED (CONFIG_KASAN_HW_TAGS )) { +/* Enable the kernel exclude mask for random tags generation */ +write_sysreg_s (SYS_GCR_EL1_RRND | gcr_kernel_excl,SYS_GCR_EL1 ); +/* Enable MTE Sync Mode for EL1 */ sysreg_clear_set (sctlr_el1, SCTLR_ELx_TCF_MASK, SCTLR_ELx_TCF_SYNC);isb ();
arch/arm64/kernel/entry.S +47 -0
65 lines not on this page · raw message
arch/arm64/kernel/mte.c +15 -3
@@ -22,6 +22,8 @@#include <asm/ptrace.h> #include <asm/sysreg.h> +u64 gcr_kernel_excl__ro_after_init ; +static void mte_sync_page_tags (struct page *page,pte_t *ptep,bool check_swap) {pte_t old_pte =READ_ONCE (*ptep);
@@ -116,6 +118,13 @@ void *mte_set_mem_tag_range(void *addr, size_t size, u8 tag)return ptr; } +void mte_init_tags (u64 max_tag) +{ +u64 incl =GENMASK (max_tag &MTE_TAG_MAX ,0 ); + + gcr_kernel_excl = ~incl &SYS_GCR_EL1_EXCL_MASK ; +} +static void update_sctlr_el1_tcf0 (u64 tcf0) {/* ISB required for the kernel uaccess routines */
@@ -151,7 +160,11 @@ static void update_gcr_el1_excl(u64 excl)static void set_gcr_el1_excl (u64 excl) { current->thread.gcr_user_excl = excl; -update_gcr_el1_excl (excl); + +/* +* SYS_GCR_EL1 will be set to current->thread.gcr_user_incl value +* by mte_restore_gcr() in kernel_exit, +*/ }void flush_mte_state (void )
@@ -177,7 +190,6 @@ void mte_thread_switch(struct task_struct *next)/* avoid expensive SCTLR_EL1 accesses if no change */ if (current->thread.sctlr_tcf0 != next->thread.sctlr_tcf0)update_sctlr_el1_tcf0 (next->thread.sctlr_tcf0); -update_gcr_el1_excl (next->thread.gcr_user_excl); }void mte_suspend_exit (void )
@@ -185,7 +197,7 @@ void mte_suspend_exit(void)if (!system_supports_mte ())return ; -update_gcr_el1_excl (current->thread.gcr_user_excl); +update_gcr_el1_excl (gcr_kernel_excl); }long set_mte_ctrl (struct task_struct *task,unsigned long arg)
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Catalin Marinas
maintainerRe: [PATCH v3 29/39] arm64: mte: Switch GCR_EL1 in kernel entry and exit
arch/arm64/kernel/entry.S alternative_else_nop_endif · line 182
Quoted 13 lines · Andrey Konovalov
arch/arm64/kernel/entry.S +5
-0@@ -175,6 +175,49 @@ alternative_else_nop_endif #endif .endm + .macro mte_set_gcr, tmp, tmp2 +#ifdef CONFIG_ARM64_MTE +alternative_if_not ARM64_MTE + b 1f +alternative_else_nop_endif
You don't need the alternative here. The macro is only invoked in an alternative path already (I'd be surprised if it even works, we don't handle nested alternatives well).
arch/arm64/kernel/entry.S alternative_else_nop_endif · line 195
Quoted 13 lines
arch/arm64/kernel/entry.S +13
-0+ /* + * Calculate and set the exclude mask preserving + * the RRND (bit[16]) setting. + */ + mrs_s \tmp2, SYS_GCR_EL1 + bfi \tmp2, \tmp, #0, #16 + msr_s SYS_GCR_EL1, \tmp2 + isb +1: +#endif + .endm + + .macro mte_set_kernel_gcr, tsk, tmp, tmp2
What's the point of a 'tsk' argument here?
arch/arm64/kernel/entry.S alternative_else_nop_endif · line 197
Quoted 2 lines
arch/arm64/kernel/entry.S +2
-0+#ifdef CONFIG_KASAN_HW_TAGS +#ifdef CONFIG_ARM64_MTE
Does KASAN_HW_TAGS depend on ARM64_MTE already? Just to avoid too may ifdefs. Otherwise, you can always write it as:
#if defined(CONFIG_KASAN_HW_TAGS) && defined(CONFIG_ARM64_MTE)
to save two lines (and its easier to read).
Quoted 72 lines
arch/arm64/kernel/entry.S +27
-0+alternative_if_not ARM64_MTE + b 1f +alternative_else_nop_endif + ldr_l \tmp, gcr_kernel_excl + + mte_set_gcr \tmp, \tmp2 +1: +#endif +#endif + .endm + + .macro mte_set_user_gcr, tsk, tmp, tmp2 +#ifdef CONFIG_ARM64_MTE +alternative_if_not ARM64_MTE + b 1f +alternative_else_nop_endif + ldr \tmp, [\tsk, #THREAD_GCR_EL1_USER] + + mte_set_gcr \tmp, \tmp2 +1: +#endif + .endm + .macro kernel_entry, el, regsize = 64 .if \regsize == 32 mov w0, w0 // zero upper 32 bits of x0@@ -214,6 +257,8 @@ alternative_else_nop_endif ptrauth_keys_install_kernel tsk, x20, x22, x23 + mte_set_kernel_gcr tsk, x22, x23 + scs_load tsk, x20 .else add x21, sp, #S_FRAME_SIZE@@ -332,6 +377,8 @@ alternative_else_nop_endif /* No kernel C function calls after this as user keys are set. */ ptrauth_keys_install_user tsk, x0, x1, x2 + mte_set_user_gcr tsk, x0, x1 + apply_ssbd 0, x0, x1 .endifarch/arm64/kernel/mte.c +9
-0@@ -22,6 +22,8 @@#include <asm/ptrace.h> #include <asm/sysreg.h> +u64 gcr_kernel_excl__ro_after_init ; +static void mte_sync_page_tags (struct page *page,pte_t *ptep,bool check_swap) {pte_t old_pte =READ_ONCE (*ptep);@@ -116,6 +118,13 @@ void *mte_set_mem_tag_range(void *addr, size_t size, u8 tag)return ptr; } +void mte_init_tags (u64 max_tag) +{ +u64 incl =GENMASK (max_tag &MTE_TAG_MAX ,0 ); + + gcr_kernel_excl = ~incl &SYS_GCR_EL1_EXCL_MASK ; +} +static void update_sctlr_el1_tcf0 (u64 tcf0) {/* ISB required for the kernel uaccess routines */
arch/arm64/kernel/mte.c static void update_gcr_el1_excl(u64 excl) · line 165
Quoted 7 lines
arch/arm64/kernel/mte.c +3
-1@@ -151,7 +160,11 @@ static void update_gcr_el1_excl(u64 excl)static void set_gcr_el1_excl (u64 excl) { current->thread.gcr_user_excl = excl; -update_gcr_el1_excl (excl); + +/* +* SYS_GCR_EL1 will be set to current->thread.gcr_user_incl value
^^^^^^^^^^^^^
That's gcr_user_excl now.
arch/arm64/kernel/mte.c static void update_gcr_el1_excl(u64 excl) · line 166
Quoted 1 line
arch/arm64/kernel/mte.c +1
-0+* by mte_restore_gcr() in kernel_exit,
I don't think mte_restore_gcr is still around in this patch.
Signature · 1 line
Catalin
Vincenzo Frascino
reviewerRe: [PATCH v3 29/39] arm64: mte: Switch GCR_EL1 in kernel entry and exit
Quoted 9 lines · Catalin Marinas
Quoted 8 lines · Andrey Konovalov
arch/arm64/kernel/entry.S +0
-0@@ -175,6 +175,49 @@ alternative_else_nop_endif #endif .endm
Quoted 10 lines
arch/arm64/kernel/entry.S alternative_else_nop_endif · line 182
Quoted 5 lines
arch/arm64/kernel/entry.S +5
-0+ .macro mte_set_gcr, tmp, tmp2 +#ifdef CONFIG_ARM64_MTE +alternative_if_not ARM64_MTE + b 1f +alternative_else_nop_endifYou don't need the alternative here. The macro is only invoked in an alternative path already (I'd be surprised if it even works, we don't handle nested alternatives well).
Yes, you are right. I forgot to remove it.
Quoted 7 lines
Quoted 7 lines
arch/arm64/kernel/entry.S +7
-0+ /* + * Calculate and set the exclude mask preserving + * the RRND (bit[16]) setting. + */ + mrs_s \tmp2, SYS_GCR_EL1 + bfi \tmp2, \tmp, #0, #16 + msr_s SYS_GCR_EL1, \tmp2
Quoted 9 lines
arch/arm64/kernel/entry.S alternative_else_nop_endif · line 195
Quoted 6 lines
arch/arm64/kernel/entry.S +6
-0+ isb +1: +#endif + .endm + + .macro mte_set_kernel_gcr, tsk, tmp, tmp2What's the point of a 'tsk' argument here?
It is unused. I kept the interface same in between kernel and user. I can either add a comment or remove it. Which one do you prefer?
Quoted 10 lines
arch/arm64/kernel/entry.S alternative_else_nop_endif · line 197
Quoted 2 lines
arch/arm64/kernel/entry.S +2
-0+#ifdef CONFIG_KASAN_HW_TAGS +#ifdef CONFIG_ARM64_MTEDoes
KASAN_HW_TAGSdepend onARM64_MTEalready? Just to avoid too may ifdefs. Otherwise, you can always write it as:#if
defined(CONFIG_KASAN_HW_TAGS)&&defined(CONFIG_ARM64_MTE)to save two lines (and its easier to read).
It is indeed. I forgot to remove CONFIG_ARM64_MTE.
Quoted 80 lines
Quoted 72 lines
arch/arm64/kernel/entry.S +27
-0+alternative_if_not ARM64_MTE + b 1f +alternative_else_nop_endif + ldr_l \tmp, gcr_kernel_excl + + mte_set_gcr \tmp, \tmp2 +1: +#endif +#endif + .endm + + .macro mte_set_user_gcr, tsk, tmp, tmp2 +#ifdef CONFIG_ARM64_MTE +alternative_if_not ARM64_MTE + b 1f +alternative_else_nop_endif + ldr \tmp, [\tsk, #THREAD_GCR_EL1_USER] + + mte_set_gcr \tmp, \tmp2 +1: +#endif + .endm + .macro kernel_entry, el, regsize = 64 .if \regsize == 32 mov w0, w0 // zero upper 32 bits of x0@@ -214,6 +257,8 @@ alternative_else_nop_endif ptrauth_keys_install_kernel tsk, x20, x22, x23 + mte_set_kernel_gcr tsk, x22, x23 + scs_load tsk, x20 .else add x21, sp, #S_FRAME_SIZE@@ -332,6 +377,8 @@ alternative_else_nop_endif /* No kernel C function calls after this as user keys are set. */ ptrauth_keys_install_user tsk, x0, x1, x2 + mte_set_user_gcr tsk, x0, x1 + apply_ssbd 0, x0, x1 .endifarch/arm64/kernel/mte.c +9
-0@@ -22,6 +22,8 @@#include <asm/ptrace.h> #include <asm/sysreg.h> +u64 gcr_kernel_excl__ro_after_init ; +static void mte_sync_page_tags (struct page *page,pte_t *ptep,bool check_swap) {pte_t old_pte =READ_ONCE (*ptep);@@ -116,6 +118,13 @@ void *mte_set_mem_tag_range(void *addr, size_t size, u8 tag)return ptr; } +void mte_init_tags (u64 max_tag) +{ +u64 incl =GENMASK (max_tag &MTE_TAG_MAX ,0 ); + + gcr_kernel_excl = ~incl &SYS_GCR_EL1_EXCL_MASK ; +} +static void update_sctlr_el1_tcf0 (u64 tcf0) {/* ISB required for the kernel uaccess routines */ arch/arm64/kernel/mte.c static void update_gcr_el1_excl(u64 excl) · line 165
Quoted 7 lines
arch/arm64/kernel/mte.c +3
-1@@ -151,7 +160,11 @@ static void update_gcr_el1_excl(u64 excl)static void set_gcr_el1_excl (u64 excl) { current->thread.gcr_user_excl = excl; -update_gcr_el1_excl (excl); + +/* +* SYS_GCR_EL1 will be set to current->thread.gcr_user_incl value ^^^^^^^^^^^^^
Quoted 6 lines
That's
gcr_user_exclnow.arch/arm64/kernel/mte.c static void update_gcr_el1_excl(u64 excl) · line 166
Quoted 1 line
arch/arm64/kernel/mte.c +1
-0+* by mte_restore_gcr() in kernel_exit, I don't think
mte_restore_gcris still around in this patch.
This comment requires updating. I missed it.
Signature · 2 lines
Regards, Vincenzo
Catalin Marinas
maintainerRe: [PATCH v3 29/39] arm64: mte: Switch GCR_EL1 in kernel entry and exit
Quoted 18 lines · Vincenzo Frascino
Quoted 16 lines · Catalin Marinas
arch/arm64/kernel/entry.S alternative_else_nop_endif · line 195
Quoted 13 lines · Andrey Konovalov
arch/arm64/kernel/entry.S +13
-0+ /* + * Calculate and set the exclude mask preserving + * the RRND (bit[16]) setting. + */ + mrs_s \tmp2, SYS_GCR_EL1 + bfi \tmp2, \tmp, #0, #16 + msr_s SYS_GCR_EL1, \tmp2 + isb +1: +#endif + .endm + + .macro mte_set_kernel_gcr, tsk, tmp, tmp2What's the point of a 'tsk' argument here?
Quoted 2 lines
It is unused. I kept the interface same in between kernel and user. I can either add a comment or remove it. Which one do you prefer?
Please remove it. Having the same interface is more confusing since you have a single kernel gcr_excl but multiple user gcr_excl.
Signature · 1 line
Catalin
PATCH v3 30/39 arm64: kasan: Enable TBI EL1
In reply to Andrey KonovalovFrom: Vincenzo Frascino <[email protected]>
Hardware tag-based KASAN relies on Memory Tagging Extension (MTE) that is built on top of the Top Byte Ignore (TBI) feature.
Enable in-kernel TBI when CONFIG_KASAN_HW_TAGS is turned on by enabling the TCR_TBI1 bit in proc.S.
---
Change-Id: I91944903bc9c9c9044f0d50e74bcd6b9971d21ff
--- arch/arm64/mm/proc.S | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
arch/arm64/mm/proc.S +10 -3
@@ -40,9 +40,13 @@ #define TCR_CACHE_FLAGS TCR_IRGN_WBWA | TCR_ORGN_WBWA #ifdef CONFIG_KASAN_SW_TAGS -#define TCR_KASAN_FLAGS TCR_TBI1 +#define TCR_KASAN_SW_FLAGS TCR_TBI1 #else -#define TCR_KASAN_FLAGS 0 +#define TCR_KASAN_SW_FLAGS 0 +#endif + +#ifdef CONFIG_KASAN_HW_TAGS +#define TCR_KASAN_HW_FLAGS TCR_TBI1 #endif /*
@@ -454,6 +458,9 @@ SYM_FUNC_START(__cpu_setup) /* set the TCR_EL1 bits */ orr mte_tcr, mte_tcr, #SYS_TCR_EL1_TCMA1 +#ifdef CONFIG_KASAN_HW_TAGS + orr mte_tcr, mte_tcr, #TCR_KASAN_HW_FLAGS +#endif 1: #endif msr mair_el1, x5
@@ -463,7 +470,7 @@ SYM_FUNC_START(__cpu_setup) */ mov_q x10, TCR_TxSZ(VA_BITS) | TCR_CACHE_FLAGS | TCR_SMP_FLAGS | \ TCR_TG_FLAGS | TCR_KASLR_FLAGS | TCR_ASID16 | \ - TCR_TBI0 | TCR_A1 | TCR_KASAN_FLAGS + TCR_TBI0 | TCR_A1 | TCR_KASAN_SW_FLAGS #ifdef CONFIG_ARM64_MTE orr x10, x10, mte_tcr .unreq mte_tcr
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Catalin Marinas
maintainerRe: [PATCH v3 30/39] arm64: kasan: Enable TBI EL1
Quoted 21 lines · Andrey Konovalov
arch/arm64/mm/proc.S +6
-2@@ -40,9 +40,13 @@ #define TCR_CACHE_FLAGS TCR_IRGN_WBWA | TCR_ORGN_WBWA #ifdef CONFIG_KASAN_SW_TAGS -#define TCR_KASAN_FLAGS TCR_TBI1 +#define TCR_KASAN_SW_FLAGS TCR_TBI1 #else -#define TCR_KASAN_FLAGS 0 +#define TCR_KASAN_SW_FLAGS 0 +#endif + +#ifdef CONFIG_KASAN_HW_TAGS +#define TCR_KASAN_HW_FLAGS TCR_TBI1 #endif /*
arch/arm64/mm/proc.S SYM_FUNC_START(__cpu_setup) · line 463
Quoted 6 lines
arch/arm64/mm/proc.S +3
-0@@ -454,6 +458,9 @@ SYM_FUNC_START(__cpu_setup) /* set the TCR_EL1 bits */ orr mte_tcr, mte_tcr, #SYS_TCR_EL1_TCMA1 +#ifdef CONFIG_KASAN_HW_TAGS + orr mte_tcr, mte_tcr, #TCR_KASAN_HW_FLAGS +#endif
I missed this in an earlier patch. Do we need TCMA1 set without KASAN_HW? If not, we could add them both to TCR_KASAN_HW_FLAGS.
Signature · 1 line
Catalin
Vincenzo Frascino
reviewerRe: [PATCH v3 30/39] arm64: kasan: Enable TBI EL1
Quoted 23 lines · Catalin Marinas
Quoted 22 lines · Andrey Konovalov
arch/arm64/mm/proc.S +6
-2@@ -40,9 +40,13 @@ #define TCR_CACHE_FLAGS TCR_IRGN_WBWA | TCR_ORGN_WBWA #ifdef CONFIG_KASAN_SW_TAGS -#define TCR_KASAN_FLAGS TCR_TBI1 +#define TCR_KASAN_SW_FLAGS TCR_TBI1 #else -#define TCR_KASAN_FLAGS 0 +#define TCR_KASAN_SW_FLAGS 0 +#endif + +#ifdef CONFIG_KASAN_HW_TAGS +#define TCR_KASAN_HW_FLAGS TCR_TBI1 #endif /*@@ -454,6 +458,9 @@ SYM_FUNC_START(__cpu_setup)
Quoted 9 lines
arch/arm64/mm/proc.S SYM_FUNC_START(__cpu_setup) · line 463
Quoted 5 lines
arch/arm64/mm/proc.S +3
-0/* set the TCR_EL1 bits */ orr mte_tcr, mte_tcr, #SYS_TCR_EL1_TCMA1 +#ifdef CONFIG_KASAN_HW_TAGS + orr mte_tcr, mte_tcr, #TCR_KASAN_HW_FLAGS +#endifI missed this in an earlier patch. Do we need TCMA1 set without
KASAN_HW? If not, we could add them both toTCR_KASAN_HW_FLAGS.
We don't. I will move the code around in the next version.
Signature · 2 lines
Regards, Vincenzo
PATCH v3 31/39 arm64: kasan: Align allocations for HW_TAGS
In reply to Andrey KonovalovHardware tag-based KASAN uses the memory tagging approach, which requires all allocations to be aligned to the memory granule size. Align the allocations to MTE_GRANULE_SIZE via ARCH_SLAB_MINALIGN when CONFIG_KASAN_HW_TAGS is enabled.
---
Change-Id: I51ebd3f9645e6330e5a92973bf7c86b62d632c2b
--- arch/arm64/include/asm/cache.h | 3 +++ 1 file changed, 3 insertions(+)
arch/arm64/include/asm/cache.h +3 -0
@@ -6,6 +6,7 @@#define __ASM_CACHE_H#include <asm/cputype.h> +#include <asm/mte-kasan.h> #define CTR_L1IP_SHIFT 14#define CTR_L1IP_MASK 3
@@ -50,6 +51,8 @@#ifdef CONFIG_KASAN_SW_TAGS #define ARCH_SLAB_MINALIGN (1ULL << KASAN_SHADOW_SCALE_SHIFT) +#elif defined(CONFIG_KASAN_HW_TAGS ) +#define ARCH_SLAB_MINALIGN MTE_GRANULE_SIZE#endif #ifndef __ASSEMBLY__
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
PATCH v3 32/39 kasan: define KASAN_GRANULE_SIZE for HW_TAGS
In reply to Andrey KonovalovHardware tag-based KASAN has granules of MTE_GRANULE_SIZE. Define KASAN_GRANULE_SIZE to MTE_GRANULE_SIZE for CONFIG_KASAN_HW_TAGS.
---
Change-Id: I5d1117e6a991cbca00d2cfb4ba66e8ae2d8f513a
--- mm/kasan/kasan.h | 6 ++++++ 1 file changed, 6 insertions(+)
mm/kasan/kasan.h +6 -0
@@ -5,7 +5,13 @@#include <linux/kasan.h> #include <linux/stackdepot.h> +#if defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS )#define KASAN_GRANULE_SIZE (1UL << KASAN_SHADOW_SCALE_SHIFT) +#else +#include <asm/mte-kasan.h> +#define KASAN_GRANULE_SIZE (MTE_GRANULE_SIZE) +#endif +#define KASAN_GRANULE_MASK (KASAN_GRANULE_SIZE - 1)#define KASAN_GRANULE_PAGE (KASAN_GRANULE_SIZE << PAGE_SHIFT)
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 32/39] kasan: define KASAN_GRANULE_SIZE for HW_TAGS
Quoted 5 lines · Andrey Konovalov
Hardware tag-based KASAN has granules of
MTE_GRANULE_SIZE. DefineKASAN_GRANULE_SIZEtoMTE_GRANULE_SIZEforCONFIG_KASAN_HW_TAGS.Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>
Quoted 11 lines
---
Change-Id: I5d1117e6a991cbca00d2cfb4ba66e8ae2d8f513a--- mm/kasan/kasan.h | 6 ++++++ 1 file changed, 6 insertions(+)mm/kasan/kasan.h +0
-0
mm/kasan/kasan.h line 12
Quoted 8 lines
mm/kasan/kasan.h +4
-0@@ -5,7 +5,13 @@#include <linux/kasan.h> #include <linux/stackdepot.h> +#if defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS )#define KASAN_GRANULE_SIZE (1UL << KASAN_SHADOW_SCALE_SHIFT) +#else +#include <asm/mte-kasan.h> +#define KASAN_GRANULE_SIZE (MTE_GRANULE_SIZE)
Why braces? Shouldn't MTE_GRANULE_SIZE already have braces?
Quoted 8 lines
mm/kasan/kasan.h +2
-0+#endif +#define KASAN_GRANULE_MASK (KASAN_GRANULE_SIZE - 1)#define KASAN_GRANULE_PAGE (KASAN_GRANULE_SIZE << PAGE_SHIFT)Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 32/39] kasan: define KASAN_GRANULE_SIZE for HW_TAGS
Quoted 24 lines · On Thu, Oct 1, 2020 at 7:58 PM <[email protected]> wrote:
Quoted 5 lines · Andrey Konovalov
Hardware tag-based KASAN has granules of
MTE_GRANULE_SIZE. DefineKASAN_GRANULE_SIZEtoMTE_GRANULE_SIZEforCONFIG_KASAN_HW_TAGS.Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>Reviewed-by Marco Elver <[email protected]>Quoted 14 lines
---
Change-Id: I5d1117e6a991cbca00d2cfb4ba66e8ae2d8f513a--- mm/kasan/kasan.h | 6 ++++++ 1 file changed, 6 insertions(+)mm/kasan/kasan.h +0
-0@@ -5,7 +5,13 @@#include <linux/kasan.h> #include <linux/stackdepot.h>
Quoted 7 lines
mm/kasan/kasan.h line 12
Quoted 5 lines
mm/kasan/kasan.h +4
-0+#if defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS )#define KASAN_GRANULE_SIZE (1UL << KASAN_SHADOW_SCALE_SHIFT) +#else +#include <asm/mte-kasan.h> +#define KASAN_GRANULE_SIZE (MTE_GRANULE_SIZE)Why braces? Shouldn't
MTE_GRANULE_SIZEalready have braces?
Will fix in v4, thanks!
Quoted 9 lines
Quoted 9 lines
mm/kasan/kasan.h +2
-1+#endif +#define KASAN_GRANULE_MASK (KASAN_GRANULE_SIZE - 1)#define KASAN_GRANULE_PAGE (KASAN_GRANULE_SIZE << PAGE_SHIFT) --2.28.0.681.g6f77f65b4e-goog
PATCH v3 33/39 kasan, x86, s390: update undef CONFIG_KASAN
In reply to Andrey KonovalovWith the intoduction of hardware tag-based KASAN some kernel checks of this kind:
ifdef CONFIG_KASAN
will be updated to:
if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
x86 and s390 use a trick to #undef CONFIG_KASAN for some of the code that isn't linked with KASAN runtime and shouldn't have any KASAN annotations.
Also #undef CONFIG_KASAN_GENERIC with CONFIG_KASAN.
---
Change-Id: I2a622db0cb86a8feb60c30d8cb09190075be2a90
--- arch/s390/boot/string.c | 1 + arch/x86/boot/compressed/misc.h | 1 + 2 files changed, 2 insertions(+)
arch/s390/boot/string.c +1 -0
@@ -3,6 +3,7 @@#include <linux/kernel.h> #include <linux/errno.h> #undef CONFIG_KASAN +#undef CONFIG_KASAN_GENERIC#include "../lib/string.c" int strncmp (const char *cs,const char *ct,size_t count)
arch/x86/boot/compressed/misc.h +1 -0
@@ -12,6 +12,7 @@#undef CONFIG_PARAVIRT_XXL#undef CONFIG_PARAVIRT_SPINLOCKS#undef CONFIG_KASAN +#undef CONFIG_KASAN_GENERIC/* cpu_feature_enabled() cannot be used this early */ #define USE_EARLY_PGTABLE_L5
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 33/39] kasan, x86, s390: update undef CONFIG_KASAN
Quoted 9 lines · Andrey Konovalov
With the intoduction of hardware tag-based KASAN some kernel checks of this kind:
ifdef
CONFIG_KASANwill be updated to:
if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
Quoted 8 lines
x86 and s390 use a trick to #undef
CONFIG_KASANfor some of the code that isn't linked with KASAN runtime and shouldn't have any KASAN annotations.Also #undef
CONFIG_KASAN_GENERICwithCONFIG_KASAN.Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>
Quoted 34 lines
---
Change-Id: I2a622db0cb86a8feb60c30d8cb09190075be2a90--- arch/s390/boot/string.c | 1 + arch/x86/boot/compressed/misc.h | 1 + 2 files changed, 2 insertions(+)arch/s390/boot/string.c +1
-0@@ -3,6 +3,7 @@#include <linux/kernel.h> #include <linux/errno.h> #undef CONFIG_KASAN +#undef CONFIG_KASAN_GENERIC#include "../lib/string.c" int strncmp (const char *cs,const char *ct,size_t count)arch/x86/boot/compressed/misc.h +1
-0@@ -12,6 +12,7 @@#undef CONFIG_PARAVIRT_XXL#undef CONFIG_PARAVIRT_SPINLOCKS#undef CONFIG_KASAN +#undef CONFIG_KASAN_GENERIC/* cpu_feature_enabled() cannot be used this early */ #define USE_EARLY_PGTABLE_L5 Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
PATCH v3 34/39 kasan, arm64: expand CONFIG_KASAN checks
In reply to Andrey KonovalovSome #ifdef CONFIG_KASAN checks are only relevant for software KASAN modes (either related to shadow memory or compiler instrumentation). Expand those into CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS.
---
Change-Id: I91e661e2c1627783cb845d877c6371dfc8779505
--- arch/arm64/Kconfig | 2 +- arch/arm64/Makefile | 2 +- arch/arm64/include/asm/assembler.h | 2 +- arch/arm64/include/asm/memory.h | 2 +- arch/arm64/include/asm/string.h | 5 +++-- arch/arm64/kernel/head.S | 2 +- arch/arm64/kernel/image-vars.h | 2 +- arch/arm64/mm/dump.c | 6 +++--- include/linux/kasan-checks.h | 2 +- include/linux/kasan.h | 7 ++++--- include/linux/moduleloader.h | 3 ++- include/linux/string.h | 2 +- mm/ptdump.c | 13 ++++++++----- scripts/Makefile.lib | 2 ++ 14 files changed, 30 insertions(+), 22 deletions(-)
arch/arm64/Kconfig +1 -1
@@ -320,7 +320,7 @@ config BROKEN_GAS_INST config KASAN_SHADOW_OFFSET hex - depends on KASAN + depends on KASAN_GENERIC || KASAN_SW_TAGS default 0xdfffa00000000000 if (ARM64_VA_BITS_48 || ARM64_VA_BITS_52) && !KASAN_SW_TAGS default 0xdfffd00000000000 if ARM64_VA_BITS_47 && !KASAN_SW_TAGS default 0xdffffe8000000000 if ARM64_VA_BITS_42 && !KASAN_SW_TAGS
arch/arm64/Makefile +1 -1
@@ -142,7 +142,7 @@ TEXT_OFFSET := 0x0 ifeq ($(CONFIG_KASAN_SW_TAGS), y) KASAN_SHADOW_SCALE_SHIFT := 4 -else +else ifeq ($(CONFIG_KASAN_GENERIC), y) KASAN_SHADOW_SCALE_SHIFT := 3 endif
arch/arm64/include/asm/assembler.h +1 -1
@@ -464,7 +464,7 @@ USER(\label, ic ivau, \tmp2) // invalidate I line PoU#define NOKPROBE (x)#endif -#ifdef CONFIG_KASAN +#if defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS )#define EXPORT_SYMBOL_NOKASAN (name)#else #define EXPORT_SYMBOL_NOKASAN (name) EXPORT_SYMBOL(name)
arch/arm64/include/asm/memory.h +1 -1
@@ -72,7 +72,7 @@* address space for the shadow region respectively. They can bloat the stack * significantly, so double the (minimum) stack size when they are in use. */ -#ifdef CONFIG_KASAN +#if defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS )#define KASAN_SHADOW_OFFSET _AC(CONFIG_KASAN_SHADOW_OFFSET, UL)#define KASAN_SHADOW_END ((UL(1) << (64 - KASAN_SHADOW_SCALE_SHIFT)) \ + KASAN_SHADOW_OFFSET)
arch/arm64/include/asm/string.h +3 -2
@@ -5,7 +5,7 @@#ifndef __ASM_STRING_H#define __ASM_STRING_H -#ifndef CONFIG_KASAN +#if !(defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS ))#define __HAVE_ARCH_STRRCHRextern char *strrchr (const char *,int c);
@@ -48,7 +48,8 @@ extern void *__memset(void *, int, __kernel_size_t);void memcpy_flushcache (void *dst,const void *src,size_t cnt);#endif -#if defined(CONFIG_KASAN ) && !defined(__SANITIZE_ADDRESS__) +#if (defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS )) && \ + !defined(__SANITIZE_ADDRESS__)/* * For files that are not instrumented (e.g. mm/slub.c) we
arch/arm64/kernel/head.S +1 -1
@@ -452,7 +452,7 @@ SYM_FUNC_START_LOCAL(__primary_switched) bl __pi_memset dsb ishst // Make zero page visible to PTW -#ifdef CONFIG_KASAN +#if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS) bl kasan_early_init #endif #ifdef CONFIG_RANDOMIZE_BASE
arch/arm64/kernel/image-vars.h +1 -1
@@ -37,7 +37,7 @@ __efistub_strncmp = __pi_strncmp; __efistub_strrchr = __pi_strrchr; __efistub___clean_dcache_area_poc = __pi___clean_dcache_area_poc; -#ifdef CONFIG_KASAN +#if defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS ) __efistub___memcpy = __pi_memcpy; __efistub___memmove = __pi_memmove; __efistub___memset = __pi_memset;
arch/arm64/mm/dump.c +3 -3
@@ -29,7 +29,7 @@enum address_markers_idx {PAGE_OFFSET_NR =0 ,PAGE_END_NR , -#ifdef CONFIG_KASAN +#if defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS )KASAN_START_NR ,#endif };
@@ -37,7 +37,7 @@ enum address_markers_idx {static struct addr_marker address_markers[] = { {PAGE_OFFSET ,"Linear Mapping start" }, {0 /* PAGE_END */ ,"Linear Mapping end" }, -#ifdef CONFIG_KASAN +#if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS) {0 /* KASAN_SHADOW_START */ ,"Kasan shadow start" }, {KASAN_SHADOW_END ,"Kasan shadow end" }, #endif
@@ -381,7 +381,7 @@ void ptdump_check_wx(void)static int ptdump_init (void ) { address_markers[PAGE_END_NR ].start_address =PAGE_END ; -#ifdef CONFIG_KASAN +#if defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS ) address_markers[KASAN_START_NR ].start_address =KASAN_SHADOW_START ;#endif ptdump_initialize ();
include/linux/kasan-checks.h +1 -1
@@ -9,7 +9,7 @@* even in compilation units that selectively disable KASAN, but must use KASAN * to validate access to an address. Never use these in header files! */ -#ifdef CONFIG_KASAN +#if defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS )bool __kasan_check_read (const volatile void *p,unsigned int size);bool __kasan_check_write (const volatile void *p,unsigned int size);#else
include/linux/kasan.h +4 -3
@@ -226,7 +226,8 @@ static inline void kasan_release_vmalloc(unsigned long start,#endif /* CONFIG_KASAN_VMALLOC */ -#if defined(CONFIG_KASAN ) && !defined(CONFIG_KASAN_VMALLOC ) +#if (defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS )) && \ + !defined(CONFIG_KASAN_VMALLOC )/* * These functions provide a special case to support backing module
@@ -236,12 +237,12 @@ static inline void kasan_release_vmalloc(unsigned long start,int kasan_module_alloc (void *addr,size_t size);void kasan_free_shadow (const struct vm_struct *vm); -#else /* CONFIG_KASAN && !CONFIG_KASAN_VMALLOC */ +#else /* (CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS) && !CONFIG_KASAN_VMALLOC */ static inline int kasan_module_alloc (void *addr,size_t size) {return 0 ; }static inline void kasan_free_shadow (const struct vm_struct *vm) {} -#endif /* CONFIG_KASAN && !CONFIG_KASAN_VMALLOC */ +#endif /* (CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS) && !CONFIG_KASAN_VMALLOC */ #ifdef CONFIG_KASAN_INLINE void kasan_non_canonical_hook (unsigned long addr);
include/linux/moduleloader.h +2 -1
@@ -96,7 +96,8 @@ void module_arch_cleanup(struct module *mod);/* Any cleanup before freeing mod->module_init */ void module_arch_freeing_init (struct module *mod); -#if defined(CONFIG_KASAN ) && !defined(CONFIG_KASAN_VMALLOC ) +#if (defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS )) && \ + !defined(CONFIG_KASAN_VMALLOC )#include <linux/kasan.h> #define MODULE_ALIGN (PAGE_SIZE << KASAN_SHADOW_SCALE_SHIFT)#else
include/linux/string.h +1 -1
@@ -273,7 +273,7 @@ void __write_overflow(void) __compiletime_error("detected write beyond size of o#if !defined(__NO_FORTIFY) && defined(__OPTIMIZE__) && defined(CONFIG_FORTIFY_SOURCE ) -#ifdef CONFIG_KASAN +#if defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS )extern void *__underlying_memchr (const void *p,int c,__kernel_size_t size)__RENAME (memchr); extern int __underlying_memcmp(const void *p, const void *q, __kernel_size_t size) __RENAME(memcmp);extern void *__underlying_memcpy (void *p,const void *q,__kernel_size_t size)__RENAME (memcpy);
mm/ptdump.c +8 -5
@@ -4,7 +4,7 @@#include <linux/ptdump.h> #include <linux/kasan.h> -#ifdef CONFIG_KASAN +#if defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS )/* * This is an optimization for KASAN=y case. Since all kasan page tables * eventually point to the kasan_early_shadow_page we could call note_page()
@@ -31,7 +31,8 @@ static int ptdump_pgd_entry(pgd_t *pgd, unsigned long addr,struct ptdump_state *st = walk->private;pgd_t val =READ_ONCE (*pgd); -#if CONFIG_PGTABLE_LEVELS >4 && defined(CONFIG_KASAN ) +#if CONFIG_PGTABLE_LEVELS >4 && \ + (defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS ))if (pgd_page (val) ==virt_to_page (lm_alias (kasan_early_shadow_p4d)))return note_kasan_page_table (walk, addr);#endif
@@ -51,7 +52,8 @@ static int ptdump_p4d_entry(p4d_t *p4d, unsigned long addr,struct ptdump_state *st = walk->private;p4d_t val =READ_ONCE (*p4d); -#if CONFIG_PGTABLE_LEVELS >3 && defined(CONFIG_KASAN ) +#if CONFIG_PGTABLE_LEVELS >3 && \ + (defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS ))if (p4d_page (val) ==virt_to_page (lm_alias (kasan_early_shadow_pud)))return note_kasan_page_table (walk, addr);#endif
@@ -71,7 +73,8 @@ static int ptdump_pud_entry(pud_t *pud, unsigned long addr,struct ptdump_state *st = walk->private;pud_t val =READ_ONCE (*pud); -#if CONFIG_PGTABLE_LEVELS >2 && defined(CONFIG_KASAN ) +#if CONFIG_PGTABLE_LEVELS >2 && \ + (defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS ))if (pud_page (val) ==virt_to_page (lm_alias (kasan_early_shadow_pmd)))return note_kasan_page_table (walk, addr);#endif
@@ -91,7 +94,7 @@ static int ptdump_pmd_entry(pmd_t *pmd, unsigned long addr,struct ptdump_state *st = walk->private;pmd_t val =READ_ONCE (*pmd); -#if defined(CONFIG_KASAN ) +#if defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS )if (pmd_page (val) ==virt_to_page (lm_alias (kasan_early_shadow_pte)))return note_kasan_page_table (walk, addr);#endif
scripts/Makefile.lib +2 -0
@@ -148,10 +148,12 @@ endif # we don't want to check (depends on variables KASAN_SANITIZE_obj.o, KASAN_SANITIZE) # ifeq ($(CONFIG_KASAN),y) +ifneq ($(CONFIG_KASAN_HW_TAGS),y) _c_flags += $(if $(patsubst n%,, \ $(KASAN_SANITIZE_$(basetarget).o)$(KASAN_SANITIZE)y), \ $(CFLAGS_KASAN), $(CFLAGS_KASAN_NOSANITIZE)) endif +endif ifeq ($(CONFIG_UBSAN),y) _c_flags += $(if $(patsubst n%,, \
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
PATCH v3 35/39 kasan, arm64: implement HW_TAGS runtime
In reply to Andrey KonovalovProvide implementation of KASAN functions required for the hardware tag-based mode. Those include core functions for memory and pointer tagging (tags_hw.c) and bug reporting (report_tags_hw.c). Also adapt common KASAN code to support the new mode.
---
Change-Id: I8a8689ba098174a4d0ef3f1d008178387c80ee1c
--- arch/arm64/include/asm/memory.h | 4 +- arch/arm64/kernel/setup.c | 5 ++- include/linux/kasan.h | 6 +-- include/linux/mm.h | 2 +- include/linux/page-flags-layout.h | 2 +- mm/kasan/Makefile | 5 +++ mm/kasan/common.c | 15 ++++--- mm/kasan/hw_tags.c | 70 +++++++++++++++++++++++++++++++ mm/kasan/kasan.h | 17 ++++++-- mm/kasan/report_hw_tags.c | 42 +++++++++++++++++++ mm/kasan/report_sw_tags.c | 2 +- mm/kasan/shadow.c | 2 +- mm/kasan/sw_tags.c | 2 +- 13 files changed, 152 insertions(+), 22 deletions(-) create mode 100644 mm/kasan/hw_tags.c create mode 100644 mm/kasan/report_hw_tags.c
arch/arm64/include/asm/memory.h +2 -2
@@ -215,7 +215,7 @@ static inline unsigned long kaslr_offset(void) (__force __typeof__(addr))__addr; \ }) -#ifdef CONFIG_KASAN_SW_TAGS +#if defined(CONFIG_KASAN_SW_TAGS ) || defined(CONFIG_KASAN_HW_TAGS )#define __tag_shifted (tag) ((u64)(tag) << 56)#define __tag_reset (addr) __untagged_addr(addr)#define __tag_get (addr) (__u8)((u64)(addr) >> 56)
@@ -223,7 +223,7 @@ static inline unsigned long kaslr_offset(void)#define __tag_shifted (tag) 0UL#define __tag_reset (addr) (addr)#define __tag_get (addr) 0 -#endif /* CONFIG_KASAN_SW_TAGS */ +#endif /* CONFIG_KASAN_SW_TAGS || CONFIG_KASAN_HW_TAGS */ static inline const void *__tag_set (const void *addr,u8 tag) {
arch/arm64/kernel/setup.c +4 -1
@@ -358,7 +358,10 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p)smp_init_cpus ();smp_build_mpidr_hash (); -/* Init percpu seeds for random tags after cpus are set up. */ +/* +* For CONFIG_KASAN_SW_TAGS this initializes percpu seeds and must +* come after cpus are set up. +*/ kasan_init_tags ();#ifdef CONFIG_ARM64_SW_TTBR0_PAN
include/linux/kasan.h +3 -3
@@ -178,7 +178,7 @@ static inline void kasan_record_aux_stack(void *ptr) {}#endif /* CONFIG_KASAN_GENERIC */ -#ifdef CONFIG_KASAN_SW_TAGS +#if defined(CONFIG_KASAN_SW_TAGS ) || defined(CONFIG_KASAN_HW_TAGS )void kasan_init_tags (void );
@@ -187,7 +187,7 @@ void *kasan_reset_tag(const void *addr);bool kasan_report (unsigned long addr,size_t size,bool is_write,unsigned long ip); -#else /* CONFIG_KASAN_SW_TAGS */ +#else /* CONFIG_KASAN_SW_TAGS || CONFIG_KASAN_HW_TAGS */ static inline void kasan_init_tags (void ) { }
@@ -196,7 +196,7 @@ static inline void *kasan_reset_tag(const void *addr) return (void *)addr; } -#endif /* CONFIG_KASAN_SW_TAGS */ +#endif /* CONFIG_KASAN_SW_TAGS || CONFIG_KASAN_HW_TAGS*/ #ifdef CONFIG_KASAN_VMALLOC
include/linux/mm.h +1 -1
@@ -1411,7 +1411,7 @@ static inline bool cpupid_match_pid(struct task_struct *task, int cpupid) }#endif /* CONFIG_NUMA_BALANCING */ -#ifdef CONFIG_KASAN_SW_TAGS +#if defined(CONFIG_KASAN_SW_TAGS ) || defined(CONFIG_KASAN_HW_TAGS )static inline u8 page_kasan_tag (const struct page *page) {return (page->flags >>KASAN_TAG_PGSHIFT ) &KASAN_TAG_MASK ;
include/linux/page-flags-layout.h +1 -1
@@ -77,7 +77,7 @@#define LAST_CPUPID_SHIFT 0#endif -#ifdef CONFIG_KASAN_SW_TAGS +#if defined(CONFIG_KASAN_SW_TAGS ) || defined(CONFIG_KASAN_HW_TAGS )#define KASAN_TAG_WIDTH 8#else #define KASAN_TAG_WIDTH 0
mm/kasan/Makefile +5 -0
@@ -10,8 +10,10 @@ CFLAGS_REMOVE_init.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_quarantine.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_report.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_report_generic.o = $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_report_hw_tags.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_report_sw_tags.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_shadow.o = $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_hw_tags.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_sw_tags.o = $(CC_FLAGS_FTRACE) # Function splitter causes unnecessary splits in __asan_load1/__asan_store1
@@ -27,10 +29,13 @@ CFLAGS_init.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_quarantine.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_report.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_report_generic.o := $(CC_FLAGS_KASAN_RUNTIME) +CFLAGS_report_hw_tags.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_report_sw_tags.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_shadow.o := $(CC_FLAGS_KASAN_RUNTIME) +CFLAGS_hw_tags.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_sw_tags.o := $(CC_FLAGS_KASAN_RUNTIME) obj-$(CONFIG_KASAN) := common.o report.o obj-$(CONFIG_KASAN_GENERIC) += init.o generic.o report_generic.o shadow.o quarantine.o +obj-$(CONFIG_KASAN_HW_TAGS) += hw_tags.o report_hw_tags.o obj-$(CONFIG_KASAN_SW_TAGS) += init.o report_sw_tags.o shadow.o sw_tags.o
mm/kasan/common.c +7 -8
@@ -113,7 +113,7 @@ void kasan_free_pages(struct page *page, unsigned int order)*/ static inline unsigned int optimal_redzone (unsigned int object_size) { -if (IS_ENABLED (CONFIG_KASAN_SW_TAGS )) +if (!IS_ENABLED (CONFIG_KASAN_GENERIC ))return 0 ;return
@@ -178,14 +178,14 @@ size_t kasan_metadata_size(struct kmem_cache *cache)struct kasan_alloc_meta *get_alloc_info (struct kmem_cache *cache,const void *object) { -return (void *)object + cache->kasan_info.alloc_meta_offset; +return (void *)reset_tag (object) + cache->kasan_info.alloc_meta_offset; }struct kasan_free_meta *get_free_info (struct kmem_cache *cache,const void *object) {BUILD_BUG_ON (sizeof (struct kasan_free_meta ) >32 ); -return (void *)object + cache->kasan_info.free_meta_offset; +return (void *)reset_tag (object) + cache->kasan_info.free_meta_offset; }void kasan_poison_slab (struct page *page)
@@ -267,9 +267,8 @@ void * __must_check kasan_init_slab_obj(struct kmem_cache *cache, alloc_info =get_alloc_info (cache, object);__memset (alloc_info,0 ,sizeof (*alloc_info)); -if (IS_ENABLED (CONFIG_KASAN_SW_TAGS )) - object =set_tag (object, -assign_tag (cache, object, true, false)); +if (IS_ENABLED (CONFIG_KASAN_SW_TAGS ) ||IS_ENABLED (CONFIG_KASAN_HW_TAGS )) + object =set_tag (object,assign_tag (cache, object, true, false));return (void *)object; }
@@ -337,10 +336,10 @@ static void *__kasan_kmalloc(struct kmem_cache *cache, const void *object, redzone_end =round_up ((unsigned long )object + cache->object_size,KASAN_GRANULE_SIZE ); -if (IS_ENABLED (CONFIG_KASAN_SW_TAGS )) +if (IS_ENABLED (CONFIG_KASAN_SW_TAGS ) ||IS_ENABLED (CONFIG_KASAN_HW_TAGS )) tag =assign_tag (cache, object, false, keep_tag); -/* Tag is ignored in set_tag without CONFIG_KASAN_SW_TAGS */ +/* Tag is ignored in set_tag without CONFIG_KASAN_SW/HW_TAGS */ kasan_unpoison_memory (set_tag (object, tag), size);kasan_poison_memory ((void *)redzone_start, redzone_end - redzone_start,KASAN_KMALLOC_REDZONE );
mm/kasan/hw_tags.c new file +70 -0
70 lines not on this page · raw message
mm/kasan/kasan.h +14 -3
@@ -153,6 +153,10 @@ struct kasan_alloc_meta *get_alloc_info(struct kmem_cache *cache,struct kasan_free_meta *get_free_info (struct kmem_cache *cache,const void *object); +void kasan_poison_memory (const void *address,size_t size,u8 value); + +#if defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS ) +static inline const void *kasan_shadow_to_mem (const void *shadow_addr) { return (void *)(((unsigned long)shadow_addr - KASAN_SHADOW_OFFSET)
@@ -164,8 +168,6 @@ static inline bool addr_has_metadata(const void *addr)return (addr >=kasan_shadow_to_mem ((void *)KASAN_SHADOW_START )); } -void kasan_poison_memory (const void *address,size_t size,u8 value); -/** * check_memory_region - Check memory region, and report if invalid access. * @addr: the accessed address
@@ -177,6 +179,15 @@ void kasan_poison_memory(const void *address, size_t size, u8 value);bool check_memory_region (unsigned long addr,size_t size,bool write,unsigned long ret_ip); +#else /* CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS */ + +static inline bool addr_has_metadata (const void *addr) +{ +return true; +} + +#endif /* CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS */ +bool check_invalid_free (void *addr);void *find_first_bad_addr (void *addr,size_t size);
@@ -213,7 +224,7 @@ static inline void quarantine_reduce(void) { }static inline void quarantine_remove_cache (struct kmem_cache *cache) { }#endif -#ifdef CONFIG_KASAN_SW_TAGS +#if defined(CONFIG_KASAN_SW_TAGS ) || defined(CONFIG_KASAN_HW_TAGS )void print_tags (u8 addr_tag,const void *addr);
mm/kasan/report_hw_tags.c new file +42 -0
42 lines not on this page · raw message
mm/kasan/report_sw_tags.c +1 -1
@@ -1,6 +1,6 @@// SPDX-License-Identifier: GPL-2.0 /* -* This file contains tag-based KASAN specific error reporting code. +* This file contains software tag-based KASAN specific error reporting code. * * Copyright (c) 2014 Samsung Electronics Co., Ltd. * Author: Andrey Ryabinin <[email protected]>
mm/kasan/shadow.c +1 -1
@@ -107,7 +107,7 @@ void kasan_unpoison_memory(const void *address, size_t size)if (IS_ENABLED (CONFIG_KASAN_SW_TAGS )) *shadow = tag; -else +else /* CONFIG_KASAN_GENERIC */ *shadow = size &KASAN_GRANULE_MASK ; } }
mm/kasan/sw_tags.c +1 -1
@@ -1,6 +1,6 @@// SPDX-License-Identifier: GPL-2.0 /* -* This file contains core tag-based KASAN code. +* This file contains core software tag-based KASAN code. * * Copyright (c) 2018 Google, Inc. * Author: Andrey Konovalov <[email protected]>
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 35/39] kasan, arm64: implement HW_TAGS runtime
Quoted 8 lines · Andrey Konovalov
Provide implementation of KASAN functions required for the hardware tag-based mode. Those include core functions for memory and pointer tagging (
tags_hw.c) and bug reporting (report_tags_hw.c). Also adapt common KASAN code to support the new mode.Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>Acked-by Catalin Marinas <[email protected]>
Quoted 412 lines
---
Change-Id: I8a8689ba098174a4d0ef3f1d008178387c80ee1c--- arch/arm64/include/asm/memory.h | 4 +- arch/arm64/kernel/setup.c | 5 ++- include/linux/kasan.h | 6 +-- include/linux/mm.h | 2 +- include/linux/page-flags-layout.h | 2 +- mm/kasan/Makefile | 5 +++ mm/kasan/common.c | 15 ++++--- mm/kasan/hw_tags.c | 70 +++++++++++++++++++++++++++++++ mm/kasan/kasan.h | 17 ++++++-- mm/kasan/report_hw_tags.c | 42 +++++++++++++++++++ mm/kasan/report_sw_tags.c | 2 +- mm/kasan/shadow.c | 2 +- mm/kasan/sw_tags.c | 2 +- 13 files changed, 152 insertions(+), 22 deletions(-) create mode 100644 mm/kasan/hw_tags.c create mode 100644 mm/kasan/report_hw_tags.carch/arm64/include/asm/memory.h +2
-2@@ -215,7 +215,7 @@ static inline unsigned long kaslr_offset(void) (__force __typeof__(addr))__addr; \ }) -#ifdef CONFIG_KASAN_SW_TAGS +#if defined(CONFIG_KASAN_SW_TAGS ) || defined(CONFIG_KASAN_HW_TAGS )#define __tag_shifted (tag) ((u64)(tag) << 56)#define __tag_reset (addr) __untagged_addr(addr)#define __tag_get (addr) (__u8)((u64)(addr) >> 56)@@ -223,7 +223,7 @@ static inline unsigned long kaslr_offset(void)#define __tag_shifted (tag) 0UL#define __tag_reset (addr) (addr)#define __tag_get (addr) 0 -#endif /* CONFIG_KASAN_SW_TAGS */ +#endif /* CONFIG_KASAN_SW_TAGS || CONFIG_KASAN_HW_TAGS */ static inline const void *__tag_set (const void *addr,u8 tag) {arch/arm64/kernel/setup.c +4
-1@@ -358,7 +358,10 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p)smp_init_cpus ();smp_build_mpidr_hash (); -/* Init percpu seeds for random tags after cpus are set up. */ +/* +* For CONFIG_KASAN_SW_TAGS this initializes percpu seeds and must +* come after cpus are set up. +*/ kasan_init_tags ();#ifdef CONFIG_ARM64_SW_TTBR0_PAN include/linux/kasan.h +3
-3@@ -178,7 +178,7 @@ static inline void kasan_record_aux_stack(void *ptr) {}#endif /* CONFIG_KASAN_GENERIC */ -#ifdef CONFIG_KASAN_SW_TAGS +#if defined(CONFIG_KASAN_SW_TAGS ) || defined(CONFIG_KASAN_HW_TAGS )void kasan_init_tags (void );@@ -187,7 +187,7 @@ void *kasan_reset_tag(const void *addr);bool kasan_report (unsigned long addr,size_t size,bool is_write,unsigned long ip); -#else /* CONFIG_KASAN_SW_TAGS */ +#else /* CONFIG_KASAN_SW_TAGS || CONFIG_KASAN_HW_TAGS */ static inline void kasan_init_tags (void ) { }@@ -196,7 +196,7 @@ static inline void *kasan_reset_tag(const void *addr) return (void *)addr; } -#endif /* CONFIG_KASAN_SW_TAGS */ +#endif /* CONFIG_KASAN_SW_TAGS || CONFIG_KASAN_HW_TAGS*/ #ifdef CONFIG_KASAN_VMALLOC include/linux/mm.h +1
-1@@ -1411,7 +1411,7 @@ static inline bool cpupid_match_pid(struct task_struct *task, int cpupid) }#endif /* CONFIG_NUMA_BALANCING */ -#ifdef CONFIG_KASAN_SW_TAGS +#if defined(CONFIG_KASAN_SW_TAGS ) || defined(CONFIG_KASAN_HW_TAGS )static inline u8 page_kasan_tag (const struct page *page) {return (page->flags >>KASAN_TAG_PGSHIFT ) &KASAN_TAG_MASK ;include/linux/page-flags-layout.h +1
-1@@ -77,7 +77,7 @@#define LAST_CPUPID_SHIFT 0#endif -#ifdef CONFIG_KASAN_SW_TAGS +#if defined(CONFIG_KASAN_SW_TAGS ) || defined(CONFIG_KASAN_HW_TAGS )#define KASAN_TAG_WIDTH 8#else #define KASAN_TAG_WIDTH 0mm/kasan/Makefile +5
-0@@ -10,8 +10,10 @@ CFLAGS_REMOVE_init.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_quarantine.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_report.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_report_generic.o = $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_report_hw_tags.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_report_sw_tags.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_shadow.o = $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_hw_tags.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_sw_tags.o = $(CC_FLAGS_FTRACE) # Function splitter causes unnecessary splits in __asan_load1/__asan_store1@@ -27,10 +29,13 @@ CFLAGS_init.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_quarantine.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_report.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_report_generic.o := $(CC_FLAGS_KASAN_RUNTIME) +CFLAGS_report_hw_tags.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_report_sw_tags.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_shadow.o := $(CC_FLAGS_KASAN_RUNTIME) +CFLAGS_hw_tags.o := $(CC_FLAGS_KASAN_RUNTIME) CFLAGS_sw_tags.o := $(CC_FLAGS_KASAN_RUNTIME) obj-$(CONFIG_KASAN) := common.o report.o obj-$(CONFIG_KASAN_GENERIC) += init.o generic.o report_generic.o shadow.o quarantine.o +obj-$(CONFIG_KASAN_HW_TAGS) += hw_tags.o report_hw_tags.o obj-$(CONFIG_KASAN_SW_TAGS) += init.o report_sw_tags.o shadow.o sw_tags.omm/kasan/common.c +7
-8@@ -113,7 +113,7 @@ void kasan_free_pages(struct page *page, unsigned int order)*/ static inline unsigned int optimal_redzone (unsigned int object_size) { -if (IS_ENABLED (CONFIG_KASAN_SW_TAGS )) +if (!IS_ENABLED (CONFIG_KASAN_GENERIC ))return 0 ;return @@ -178,14 +178,14 @@ size_t kasan_metadata_size(struct kmem_cache *cache)struct kasan_alloc_meta *get_alloc_info (struct kmem_cache *cache,const void *object) { -return (void *)object + cache->kasan_info.alloc_meta_offset; +return (void *)reset_tag (object) + cache->kasan_info.alloc_meta_offset; }struct kasan_free_meta *get_free_info (struct kmem_cache *cache,const void *object) {BUILD_BUG_ON (sizeof (struct kasan_free_meta ) >32 ); -return (void *)object + cache->kasan_info.free_meta_offset; +return (void *)reset_tag (object) + cache->kasan_info.free_meta_offset; }void kasan_poison_slab (struct page *page)@@ -267,9 +267,8 @@ void * __must_check kasan_init_slab_obj(struct kmem_cache *cache, alloc_info =get_alloc_info (cache, object);__memset (alloc_info,0 ,sizeof (*alloc_info)); -if (IS_ENABLED (CONFIG_KASAN_SW_TAGS )) - object =set_tag (object, -assign_tag (cache, object, true, false)); +if (IS_ENABLED (CONFIG_KASAN_SW_TAGS ) ||IS_ENABLED (CONFIG_KASAN_HW_TAGS )) + object =set_tag (object,assign_tag (cache, object, true, false));return (void *)object; }@@ -337,10 +336,10 @@ static void *__kasan_kmalloc(struct kmem_cache *cache, const void *object, redzone_end =round_up ((unsigned long )object + cache->object_size,KASAN_GRANULE_SIZE ); -if (IS_ENABLED (CONFIG_KASAN_SW_TAGS )) +if (IS_ENABLED (CONFIG_KASAN_SW_TAGS ) ||IS_ENABLED (CONFIG_KASAN_HW_TAGS )) tag =assign_tag (cache, object, false, keep_tag); -/* Tag is ignored in set_tag without CONFIG_KASAN_SW_TAGS */ +/* Tag is ignored in set_tag without CONFIG_KASAN_SW/HW_TAGS */ kasan_unpoison_memory (set_tag (object, tag), size);kasan_poison_memory ((void *)redzone_start, redzone_end - redzone_start,KASAN_KMALLOC_REDZONE );mm/kasan/hw_tags.c new file +70
-0@@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* This file contains core hardware tag-based KASAN code. +* +* Copyright (c) 2020 Google, Inc. +* Author: Andrey Konovalov <[email protected]> +*/ + +#include <linux/kasan.h> +#include <linux/kernel.h> +#include <linux/memory.h> +#include <linux/mm.h> +#include <linux/string.h> +#include <linux/types.h> + +#include "kasan.h" + +void kasan_init_tags (void ) +{ +init_tags (KASAN_TAG_MAX ); +} + +void *kasan_reset_tag (const void *addr) +{ +return reset_tag (addr); +} + +void kasan_poison_memory (const void *address,size_t size,u8 value) +{ +set_mem_tag_range (reset_tag (address), +round_up (size,KASAN_GRANULE_SIZE ), value); +} + +void kasan_unpoison_memory (const void *address,size_t size) +{ +set_mem_tag_range (reset_tag (address), +round_up (size,KASAN_GRANULE_SIZE ),get_tag (address)); +} + +u8 random_tag (void ) +{ +return get_random_tag (); +} + +bool check_invalid_free (void *addr) +{ +u8 ptr_tag =get_tag (addr); +u8 mem_tag =get_mem_tag (addr); + +return (mem_tag ==KASAN_TAG_INVALID ) || + (ptr_tag !=KASAN_TAG_KERNEL && ptr_tag != mem_tag); +} + +void kasan_set_free_info (struct kmem_cache *cache, +void *object,u8 tag) +{ +struct kasan_alloc_meta *alloc_meta; + + alloc_meta =get_alloc_info (cache, object); +kasan_set_track (&alloc_meta->free_track[0 ],GFP_NOWAIT ); +} + +struct kasan_track *kasan_get_free_track (struct kmem_cache *cache, +void *object,u8 tag) +{ +struct kasan_alloc_meta *alloc_meta; + + alloc_meta =get_alloc_info (cache, object); +return &alloc_meta->free_track[0 ]; +}mm/kasan/kasan.h +14
-3@@ -153,6 +153,10 @@ struct kasan_alloc_meta *get_alloc_info(struct kmem_cache *cache,struct kasan_free_meta *get_free_info (struct kmem_cache *cache,const void *object); +void kasan_poison_memory (const void *address,size_t size,u8 value); + +#if defined(CONFIG_KASAN_GENERIC ) || defined(CONFIG_KASAN_SW_TAGS ) +static inline const void *kasan_shadow_to_mem (const void *shadow_addr) { return (void *)(((unsigned long)shadow_addr - KASAN_SHADOW_OFFSET)@@ -164,8 +168,6 @@ static inline bool addr_has_metadata(const void *addr)return (addr >=kasan_shadow_to_mem ((void *)KASAN_SHADOW_START )); } -void kasan_poison_memory (const void *address,size_t size,u8 value); -/** * check_memory_region - Check memory region, and report if invalid access. * @addr: the accessed address @@ -177,6 +179,15 @@ void kasan_poison_memory(const void *address, size_t size, u8 value);bool check_memory_region (unsigned long addr,size_t size,bool write,unsigned long ret_ip); +#else /* CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS */ + +static inline bool addr_has_metadata (const void *addr) +{ +return true; +} + +#endif /* CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS */ +bool check_invalid_free (void *addr);void *find_first_bad_addr (void *addr,size_t size);@@ -213,7 +224,7 @@ static inline void quarantine_reduce(void) { }static inline void quarantine_remove_cache (struct kmem_cache *cache) { }#endif -#ifdef CONFIG_KASAN_SW_TAGS +#if defined(CONFIG_KASAN_SW_TAGS ) || defined(CONFIG_KASAN_HW_TAGS )void print_tags (u8 addr_tag,const void *addr);mm/kasan/report_hw_tags.c new file +42
-0@@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* This file contains hardware tag-based KASAN specific error reporting code. +* +* Copyright (c) 2020 Google, Inc. +* Author: Andrey Konovalov <[email protected]> +*/ + +#include <linux/kasan.h> +#include <linux/kernel.h> +#include <linux/memory.h> +#include <linux/mm.h> +#include <linux/string.h> +#include <linux/types.h> + +#include "kasan.h" + +const char *get_bug_type (struct kasan_access_info *info) +{ +return "invalid-access" ; +} + +void *find_first_bad_addr (void *addr,size_t size) +{ +return reset_tag (addr); +} + +void metadata_fetch_row (char *buffer,void *row) +{ +int i; + +for (i =0 ; i <META_BYTES_PER_ROW ; i++) + buffer[i] =mte_get_mem_tag (row + i *KASAN_GRANULE_SIZE ); +} + +void print_tags (u8 addr_tag,const void *addr) +{ +u8 memory_tag =mte_get_mem_tag ((void *)addr); + +pr_err ("Pointer tag: [%02x], memory tag: [%02x]\n" , + addr_tag, memory_tag); +}mm/kasan/report_sw_tags.c +1
-1@@ -1,6 +1,6 @@// SPDX-License-Identifier: GPL-2.0 /* -* This file contains tag-based KASAN specific error reporting code. +* This file contains software tag-based KASAN specific error reporting code. * * Copyright (c) 2014 Samsung Electronics Co., Ltd. * Author: Andrey Ryabinin <[email protected]> mm/kasan/shadow.c +1
-1@@ -107,7 +107,7 @@ void kasan_unpoison_memory(const void *address, size_t size)if (IS_ENABLED (CONFIG_KASAN_SW_TAGS )) *shadow = tag; -else +else /* CONFIG_KASAN_GENERIC */ *shadow = size &KASAN_GRANULE_MASK ; } }mm/kasan/sw_tags.c +1
-1@@ -1,6 +1,6 @@// SPDX-License-Identifier: GPL-2.0 /* -* This file contains core tag-based KASAN code. +* This file contains core software tag-based KASAN code. * * Copyright (c) 2018 Google, Inc. * Author: Andrey Konovalov <[email protected]> Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
PATCH v3 36/39 kasan, arm64: print report from tag fault handler
In reply to Andrey KonovalovAdd error reporting for hardware tag-based KASAN. When CONFIG_KASAN_HW_TAGS is enabled, print KASAN report from the arm64 tag fault handler.
SAS bits aren't set in ESR for all faults reported in EL1, so it's impossible to find out the size of the access the caused the fault. Adapt KASAN reporting code to handle this case.
---
Change-Id: I3780fe7db6e075dff2937d3d8508f55c9322b095
--- arch/arm64/mm/fault.c | 14 ++++++++++++++ mm/kasan/report.c | 11 ++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-)
arch/arm64/mm/fault.c +14 -0
@@ -14,6 +14,7 @@#include <linux/mm.h> #include <linux/hardirq.h> #include <linux/init.h> +#include <linux/kasan.h> #include <linux/kprobes.h> #include <linux/uaccess.h> #include <linux/page-flags.h>
@@ -295,10 +296,23 @@ static void die_kernel_fault(const char *msg, unsigned long addr,do_exit (SIGKILL ); } +#ifdef CONFIG_KASAN_HW_TAGS static void report_tag_fault (unsigned long addr,unsigned int esr,struct pt_regs *regs) { +bool is_write = ((esr & ESR_ELx_WNR) >> ESR_ELx_WNR_SHIFT) !=0 ; + +/* +* SAS bits aren't set for all faults reported in EL1, so we can't +* find out access size. +*/ +kasan_report (addr,0 , is_write, regs->pc); } +#else +/* Tag faults aren't enabled without CONFIG_KASAN_HW_TAGS. */ +static inline void report_tag_fault (unsigned long addr,unsigned int esr, +struct pt_regs *regs) { } +#endif static void __do_kernel_fault (unsigned long addr,unsigned int esr,struct pt_regs *regs)
mm/kasan/report.c +8 -3
@@ -60,9 +60,14 @@ 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 by task %s/%d\n" , - info->is_write ?"Write" :"Read" , info->access_size, - info->access_addr, current->comm,task_pid_nr (current)); +if (info->access_size) +pr_err ("%s of size %zu at addr %px by task %s/%d\n" , + info->is_write ?"Write" :"Read" , info->access_size, + info->access_addr, current->comm,task_pid_nr (current)); +else +pr_err ("%s at addr %px by task %s/%d\n" , + info->is_write ?"Write" :"Read" , + info->access_addr, current->comm,task_pid_nr (current)); }static DEFINE_SPINLOCK (report_lock);
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 36/39] kasan, arm64: print report from tag fault handler
Quoted 10 lines · Andrey Konovalov
Add error reporting for hardware tag-based KASAN. When
CONFIG_KASAN_HW_TAGSis enabled, print KASAN report from the arm64 tag fault handler.SAS bits aren't set in ESR for all faults reported in EL1, so it's impossible to find out the size of the access the caused the fault. Adapt KASAN reporting code to handle this case.
Signed-off-by Andrey Konovalov <[email protected]>Co-developed-by Vincenzo Frascino <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>
PATCH v3 37/39 kasan, slub: reset tags when accessing metadata
In reply to Andrey KonovalovSLUB allocator accesses metadata for slab objects, that may lie out-of-bounds of the object itself, or be accessed when an object is freed. Such accesses trigger tag faults and lead to false-positive reports with hardware tag-based KASAN.
Software KASAN modes disable instrumentation for allocator code via KASAN_SANITIZE Makefile macro, and rely on kasan_enable/disable_current() annotations which are used to ignore KASAN reports.
With hardware tag-based KASAN neither of those options are available, as it doesn't use compiler instrumetation, no tag faults are ignored, and MTE is disabled after the first one.
Instead, reset tags when accessing metadata.
---
Change-Id: I39f3c4d4f29299d4fbbda039bedf230db1c746fb
--- mm/page_poison.c | 2 +- mm/slub.c | 25 ++++++++++++++----------- 2 files changed, 15 insertions(+), 12 deletions(-)
mm/page_poison.c +1 -1
@@ -43,7 +43,7 @@ static void poison_page(struct page *page)/* KASAN still think the page is in-use, so skip it. */ kasan_disable_current (); -memset (addr,PAGE_POISON ,PAGE_SIZE ); +memset (kasan_reset_tag (addr),PAGE_POISON ,PAGE_SIZE );kasan_enable_current ();kunmap_atomic (addr); }
mm/slub.c +14 -11
@@ -249,7 +249,7 @@ static inline void *freelist_ptr(const struct kmem_cache *s, void *ptr, {#ifdef CONFIG_SLAB_FREELIST_HARDENED /* -* When CONFIG_KASAN_SW_TAGS is enabled, ptr_addr might be tagged. +* When CONFIG_KASAN_SW/HW_TAGS is enabled, ptr_addr might be tagged. * Normally, this doesn't cause any issues, as both set_freepointer() * and get_freepointer() are called with a pointer with the same tag. * However, there are some issues with CONFIG_SLUB_DEBUG code. For
@@ -275,6 +275,7 @@ static inline void *freelist_dereference(const struct kmem_cache *s,static inline void *get_freepointer (struct kmem_cache *s,void *object) { + object =kasan_reset_tag (object);return freelist_dereference (s, object + s->offset); }
@@ -304,6 +305,7 @@ static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp)BUG_ON (object == fp);/* naive detection of double free or corruption */ #endif + freeptr_addr = (unsigned long )kasan_reset_tag ((void *)freeptr_addr); *(void **)freeptr_addr =freelist_ptr (s, fp, freeptr_addr); }
@@ -538,8 +540,8 @@ static void print_section(char *level, char *text, u8 *addr, unsigned int length) {metadata_access_enable (); -print_hex_dump (level, text,DUMP_PREFIX_ADDRESS ,16 ,1 , addr, - length,1 ); +print_hex_dump (level,kasan_reset_tag (text),DUMP_PREFIX_ADDRESS , +16 ,1 , addr, length,1 );metadata_access_disable (); }
@@ -570,7 +572,7 @@ static struct track *get_track(struct kmem_cache *s, void *object, p = object +get_info_end (s); -return p + alloc; +return kasan_reset_tag (p + alloc); } static void set_track(struct kmem_cache *s, void *object,
@@ -583,7 +585,8 @@ static void set_track(struct kmem_cache *s, void *object,unsigned int nr_entries;metadata_access_enable (); - nr_entries =stack_trace_save (p->addrs,TRACK_ADDRS_COUNT ,3 ); + nr_entries =stack_trace_save (kasan_reset_tag (p->addrs), +TRACK_ADDRS_COUNT ,3 );metadata_access_disable ();if (nr_entries <TRACK_ADDRS_COUNT )
@@ -747,7 +750,7 @@ static __printf(3, 4) void slab_err(struct kmem_cache *s, struct page *page,static void init_object (struct kmem_cache *s,void *object,u8 val) { -u8 *p = object; +u8 *p =kasan_reset_tag (object);if (s->flags &SLAB_RED_ZONE )memset (p - s->red_left_pad, val, s->red_left_pad);
@@ -777,7 +780,7 @@ static int check_bytes_and_report(struct kmem_cache *s, struct page *page,u8 *addr =page_address (page);metadata_access_enable (); - fault =memchr_inv (start, value, bytes); + fault =memchr_inv (kasan_reset_tag (start), value, bytes);metadata_access_disable ();if (!fault)return 1 ;
@@ -873,7 +876,7 @@ static int slab_pad_check(struct kmem_cache *s, struct page *page) pad = end - remainder;metadata_access_enable (); - fault =memchr_inv (pad,POISON_INUSE , remainder); + fault =memchr_inv (kasan_reset_tag (pad),POISON_INUSE , remainder);metadata_access_disable ();if (!fault)return 1 ;
@@ -1118,7 +1121,7 @@ void setup_page_debug(struct kmem_cache *s, struct page *page, void *addr)return ;metadata_access_enable (); -memset (addr,POISON_INUSE ,page_size (page)); +memset (kasan_reset_tag (addr),POISON_INUSE ,page_size (page));metadata_access_disable (); }
@@ -2884,10 +2887,10 @@ static __always_inline void *slab_alloc_node(struct kmem_cache *s,stat (s,ALLOC_FASTPATH ); } -maybe_wipe_obj_freeptr (s, object); +maybe_wipe_obj_freeptr (s,kasan_reset_tag (object));if (unlikely (slab_want_init_on_alloc (gfpflags, s)) && object) -memset (object,0 , s->object_size); +memset (kasan_reset_tag (object),0 , s->object_size);slab_post_alloc_hook (s, objcg, gfpflags,1 , &object);
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 37/39] kasan, slub: reset tags when accessing metadata
Quoted 9 lines · Andrey Konovalov
SLUB allocator accesses metadata for slab objects, that may lie out-of-bounds of the object itself, or be accessed when an object is freed. Such accesses trigger tag faults and lead to false-positive reports with hardware tag-based KASAN.
Software KASAN modes disable instrumentation for allocator code via
KASAN_SANITIZEMakefilemacro, and rely on kasan_enable/disable_current() annotations which are used to ignore KASAN reports.
Quoted 8 lines
With hardware tag-based KASAN neither of those options are available, as it doesn't use compiler instrumetation, no tag faults are ignored, and MTE is disabled after the first one.
Instead, reset tags when accessing metadata.
Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>
I assume you have tested with the various SLUB debug options, as well as things like memory initialization etc?
Quoted 131 lines
---
Change-Id: I39f3c4d4f29299d4fbbda039bedf230db1c746fb--- mm/page_poison.c | 2 +- mm/slub.c | 25 ++++++++++++++----------- 2 files changed, 15 insertions(+), 12 deletions(-)mm/page_poison.c +1
-1@@ -43,7 +43,7 @@ static void poison_page(struct page *page)/* KASAN still think the page is in-use, so skip it. */ kasan_disable_current (); -memset (addr,PAGE_POISON ,PAGE_SIZE ); +memset (kasan_reset_tag (addr),PAGE_POISON ,PAGE_SIZE );kasan_enable_current ();kunmap_atomic (addr); }mm/slub.c +14
-11@@ -249,7 +249,7 @@ static inline void *freelist_ptr(const struct kmem_cache *s, void *ptr, {#ifdef CONFIG_SLAB_FREELIST_HARDENED /* -* When CONFIG_KASAN_SW_TAGS is enabled, ptr_addr might be tagged. +* When CONFIG_KASAN_SW/HW_TAGS is enabled, ptr_addr might be tagged. * Normally, this doesn't cause any issues, as both set_freepointer() * and get_freepointer() are called with a pointer with the same tag. * However, there are some issues with CONFIG_SLUB_DEBUG code. For @@ -275,6 +275,7 @@ static inline void *freelist_dereference(const struct kmem_cache *s,static inline void *get_freepointer (struct kmem_cache *s,void *object) { + object =kasan_reset_tag (object);return freelist_dereference (s, object + s->offset); }@@ -304,6 +305,7 @@ static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp)BUG_ON (object == fp);/* naive detection of double free or corruption */ #endif + freeptr_addr = (unsigned long )kasan_reset_tag ((void *)freeptr_addr); *(void **)freeptr_addr =freelist_ptr (s, fp, freeptr_addr); }@@ -538,8 +540,8 @@ static void print_section(char *level, char *text, u8 *addr, unsigned int length) {metadata_access_enable (); -print_hex_dump (level, text,DUMP_PREFIX_ADDRESS ,16 ,1 , addr, - length,1 ); +print_hex_dump (level,kasan_reset_tag (text),DUMP_PREFIX_ADDRESS , +16 ,1 , addr, length,1 );metadata_access_disable (); }@@ -570,7 +572,7 @@ static struct track *get_track(struct kmem_cache *s, void *object, p = object +get_info_end (s); -return p + alloc; +return kasan_reset_tag (p + alloc); } static void set_track(struct kmem_cache *s, void *object,@@ -583,7 +585,8 @@ static void set_track(struct kmem_cache *s, void *object,unsigned int nr_entries;metadata_access_enable (); - nr_entries =stack_trace_save (p->addrs,TRACK_ADDRS_COUNT ,3 ); + nr_entries =stack_trace_save (kasan_reset_tag (p->addrs), +TRACK_ADDRS_COUNT ,3 );metadata_access_disable ();if (nr_entries <TRACK_ADDRS_COUNT )@@ -747,7 +750,7 @@ static __printf(3, 4) void slab_err(struct kmem_cache *s, struct page *page,static void init_object (struct kmem_cache *s,void *object,u8 val) { -u8 *p = object; +u8 *p =kasan_reset_tag (object);if (s->flags &SLAB_RED_ZONE )memset (p - s->red_left_pad, val, s->red_left_pad);@@ -777,7 +780,7 @@ static int check_bytes_and_report(struct kmem_cache *s, struct page *page,u8 *addr =page_address (page);metadata_access_enable (); - fault =memchr_inv (start, value, bytes); + fault =memchr_inv (kasan_reset_tag (start), value, bytes);metadata_access_disable ();if (!fault)return 1 ;@@ -873,7 +876,7 @@ static int slab_pad_check(struct kmem_cache *s, struct page *page) pad = end - remainder;metadata_access_enable (); - fault =memchr_inv (pad,POISON_INUSE , remainder); + fault =memchr_inv (kasan_reset_tag (pad),POISON_INUSE , remainder);metadata_access_disable ();if (!fault)return 1 ;@@ -1118,7 +1121,7 @@ void setup_page_debug(struct kmem_cache *s, struct page *page, void *addr)return ;metadata_access_enable (); -memset (addr,POISON_INUSE ,page_size (page)); +memset (kasan_reset_tag (addr),POISON_INUSE ,page_size (page));metadata_access_disable (); }@@ -2884,10 +2887,10 @@ static __always_inline void *slab_alloc_node(struct kmem_cache *s,stat (s,ALLOC_FASTPATH ); } -maybe_wipe_obj_freeptr (s, object); +maybe_wipe_obj_freeptr (s,kasan_reset_tag (object));if (unlikely (slab_want_init_on_alloc (gfpflags, s)) && object) -memset (object,0 , s->object_size); +memset (kasan_reset_tag (object),0 , s->object_size);slab_post_alloc_hook (s, objcg, gfpflags,1 , &object);Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 37/39] kasan, slub: reset tags when accessing metadata
Quoted 15 lines · On Thu, Oct 1, 2020 at 8:03 PM <[email protected]> wrote:
Quoted 13 lines · Andrey Konovalov
SLUB allocator accesses metadata for slab objects, that may lie out-of-bounds of the object itself, or be accessed when an object is freed. Such accesses trigger tag faults and lead to false-positive reports with hardware tag-based KASAN.
Software KASAN modes disable instrumentation for allocator code via
KASAN_SANITIZEMakefilemacro, and rely on kasan_enable/disable_current() annotations which are used to ignore KASAN reports.With hardware tag-based KASAN neither of those options are available, as it doesn't use compiler instrumetation, no tag faults are ignored, and MTE is disabled after the first one.
Quoted 8 lines
Quoted 4 lines
Instead, reset tags when accessing metadata.
Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>Acked-by Marco Elver <[email protected]>I assume you have tested with the various SLUB debug options,
Yes.
Quoted 2 lines
as well as
things like memory initialization etc?
Will test before sending v4.
Thanks!
Quoted 132 lines
Quoted 132 lines
---
Change-Id: I39f3c4d4f29299d4fbbda039bedf230db1c746fb--- mm/page_poison.c | 2 +- mm/slub.c | 25 ++++++++++++++----------- 2 files changed, 15 insertions(+), 12 deletions(-)mm/page_poison.c +1
-1@@ -43,7 +43,7 @@ static void poison_page(struct page *page)/* KASAN still think the page is in-use, so skip it. */ kasan_disable_current (); -memset (addr,PAGE_POISON ,PAGE_SIZE ); +memset (kasan_reset_tag (addr),PAGE_POISON ,PAGE_SIZE );kasan_enable_current ();kunmap_atomic (addr); }mm/slub.c +14
-12@@ -249,7 +249,7 @@ static inline void *freelist_ptr(const struct kmem_cache *s, void *ptr, {#ifdef CONFIG_SLAB_FREELIST_HARDENED /* -* When CONFIG_KASAN_SW_TAGS is enabled, ptr_addr might be tagged. +* When CONFIG_KASAN_SW/HW_TAGS is enabled, ptr_addr might be tagged. * Normally, this doesn't cause any issues, as both set_freepointer() * and get_freepointer() are called with a pointer with the same tag. * However, there are some issues with CONFIG_SLUB_DEBUG code. For @@ -275,6 +275,7 @@ static inline void *freelist_dereference(const struct kmem_cache *s,static inline void *get_freepointer (struct kmem_cache *s,void *object) { + object =kasan_reset_tag (object);return freelist_dereference (s, object + s->offset); }@@ -304,6 +305,7 @@ static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp)BUG_ON (object == fp);/* naive detection of double free or corruption */ #endif + freeptr_addr = (unsigned long )kasan_reset_tag ((void *)freeptr_addr); *(void **)freeptr_addr =freelist_ptr (s, fp, freeptr_addr); }@@ -538,8 +540,8 @@ static void print_section(char *level, char *text, u8 *addr, unsigned int length) {metadata_access_enable (); -print_hex_dump (level, text,DUMP_PREFIX_ADDRESS ,16 ,1 , addr, - length,1 ); +print_hex_dump (level,kasan_reset_tag (text),DUMP_PREFIX_ADDRESS , +16 ,1 , addr, length,1 );metadata_access_disable (); }@@ -570,7 +572,7 @@ static struct track *get_track(struct kmem_cache *s, void *object, p = object +get_info_end (s); -return p + alloc; +return kasan_reset_tag (p + alloc); } static void set_track(struct kmem_cache *s, void *object,@@ -583,7 +585,8 @@ static void set_track(struct kmem_cache *s, void *object,unsigned int nr_entries;metadata_access_enable (); - nr_entries =stack_trace_save (p->addrs,TRACK_ADDRS_COUNT ,3 ); + nr_entries =stack_trace_save (kasan_reset_tag (p->addrs), +TRACK_ADDRS_COUNT ,3 );metadata_access_disable ();if (nr_entries <TRACK_ADDRS_COUNT )@@ -747,7 +750,7 @@ static __printf(3, 4) void slab_err(struct kmem_cache *s, struct page *page,static void init_object (struct kmem_cache *s,void *object,u8 val) { -u8 *p = object; +u8 *p =kasan_reset_tag (object);if (s->flags &SLAB_RED_ZONE )memset (p - s->red_left_pad, val, s->red_left_pad);@@ -777,7 +780,7 @@ static int check_bytes_and_report(struct kmem_cache *s, struct page *page,u8 *addr =page_address (page);metadata_access_enable (); - fault =memchr_inv (start, value, bytes); + fault =memchr_inv (kasan_reset_tag (start), value, bytes);metadata_access_disable ();if (!fault)return 1 ;@@ -873,7 +876,7 @@ static int slab_pad_check(struct kmem_cache *s, struct page *page) pad = end - remainder;metadata_access_enable (); - fault =memchr_inv (pad,POISON_INUSE , remainder); + fault =memchr_inv (kasan_reset_tag (pad),POISON_INUSE , remainder);metadata_access_disable ();if (!fault)return 1 ;@@ -1118,7 +1121,7 @@ void setup_page_debug(struct kmem_cache *s, struct page *page, void *addr)return ;metadata_access_enable (); -memset (addr,POISON_INUSE ,page_size (page)); +memset (kasan_reset_tag (addr),POISON_INUSE ,page_size (page));metadata_access_disable (); }@@ -2884,10 +2887,10 @@ static __always_inline void *slab_alloc_node(struct kmem_cache *s,stat (s,ALLOC_FASTPATH ); } -maybe_wipe_obj_freeptr (s, object); +maybe_wipe_obj_freeptr (s,kasan_reset_tag (object));if (unlikely (slab_want_init_on_alloc (gfpflags, s)) && object) -memset (object,0 , s->object_size); +memset (kasan_reset_tag (object),0 , s->object_size);slab_post_alloc_hook (s, objcg, gfpflags,1 , &object); --2.28.0.681.g6f77f65b4e-goog
PATCH v3 38/39 kasan, arm64: enable CONFIG_KASAN_HW_TAGS
In reply to Andrey KonovalovHardware tag-based KASAN is now ready, enable the configuration option.
---
Change-Id: I6eb1eea770e6b61ad71c701231b8d815a7ccc853
--- arch/arm64/Kconfig | 1 + 1 file changed, 1 insertion(+)
arch/arm64/Kconfig +1 -0
@@ -132,6 +132,7 @@ config ARM64 select HAVE_ARCH_JUMP_LABEL_RELATIVE select HAVE_ARCH_KASAN if !(ARM64_16K_PAGES && ARM64_VA_BITS_48) select HAVE_ARCH_KASAN_SW_TAGS if (HAVE_ARCH_KASAN && !ARM64_MTE) + select HAVE_ARCH_KASAN_HW_TAGS if (HAVE_ARCH_KASAN && ARM64_MTE) select HAVE_ARCH_KGDB select HAVE_ARCH_MMAP_RND_BITS select HAVE_ARCH_MMAP_RND_COMPAT_BITS if COMPAT
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
PATCH v3 39/39 kasan: add documentation for hardware tag-based mode
In reply to Andrey KonovalovAdd documentation for hardware tag-based KASAN mode and also add some clarifications for software tag-based mode.
---
Change-Id: Ib46cb444cfdee44054628940a82f5139e10d0258
--- Documentation/dev-tools/kasan.rst | 78 ++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 21 deletions(-)
Documentation/dev-tools/kasan.rst +57 -21
@@ -5,12 +5,14 @@ Overview -------- KernelAddressSANitizer (KASAN) is a dynamic memory error detector designed to -find out-of-bound and use-after-free bugs. KASAN has two modes: generic KASAN -(similar to userspace ASan) and software tag-based KASAN (similar to userspace -HWASan). +find out-of-bound and use-after-free bugs. KASAN has three modes: +1. generic KASAN (similar to userspace ASan), +2. software tag-based KASAN (similar to userspace HWASan), +3. hardware tag-based KASAN (based on hardware memory tagging). -KASAN uses compile-time instrumentation to insert validity checks before every -memory access, and therefore requires a compiler version that supports that. +Software KASAN modes (1 and 2) use compile-time instrumentation to insert +validity checks before every memory access, and therefore require a compiler +version that supports that. Generic KASAN is supported in both GCC and Clang. With GCC it requires version 8.3.0 or later. With Clang it requires version 7.0.0 or later, but detection of
@@ -19,7 +21,7 @@ out-of-bounds accesses for global variables is only supported since Clang 11. Tag-based KASAN is only supported in Clang and requires version 7.0.0 or later. Currently generic KASAN is supported for the x86_64, arm64, xtensa, s390 and -riscv architectures, and tag-based KASAN is supported only for arm64. +riscv architectures, and tag-based KASAN modes are supported only for arm64. Usage -----
@@ -28,14 +30,16 @@ To enable KASAN configure kernel with:: CONFIG_KASAN = y -and choose between CONFIG_KASAN_GENERIC (to enable generic KASAN) and -CONFIG_KASAN_SW_TAGS (to enable software tag-based KASAN). +and choose between CONFIG_KASAN_GENERIC (to enable generic KASAN), +CONFIG_KASAN_SW_TAGS (to enable software tag-based KASAN), and +CONFIG_KASAN_HW_TAGS (to enable hardware tag-based KASAN). -You also need to choose between CONFIG_KASAN_OUTLINE and CONFIG_KASAN_INLINE. -Outline and inline are compiler instrumentation types. The former produces -smaller binary while the latter is 1.1 - 2 times faster. +For software modes, you also need to choose between CONFIG_KASAN_OUTLINE and +CONFIG_KASAN_INLINE. Outline and inline are compiler instrumentation types. +The former produces smaller binary while the latter is 1.1 - 2 times faster. -Both KASAN modes work with both SLUB and SLAB memory allocators. +Both software KASAN modes work with both SLUB and SLAB memory allocators, +hardware tag-based KASAN currently only support SLUB. For better bug detection and nicer reporting, enable CONFIG_STACKTRACE. To augment reports with last allocation and freeing stack of the physical page,
@@ -196,17 +200,24 @@ and the second to last. Software tag-based KASAN ~~~~~~~~~~~~~~~~~~~~~~~~ -Tag-based KASAN uses the Top Byte Ignore (TBI) feature of modern arm64 CPUs to -store a pointer tag in the top byte of kernel pointers. Like generic KASAN it -uses shadow memory to store memory tags associated with each 16-byte memory +Software tag-based KASAN requires software memory tagging support in the form +of HWASan-like compiler instrumentation (see HWASan documentation for details). + +Software tag-based KASAN is currently only implemented for arm64 architecture. + +Software tag-based KASAN uses the Top Byte Ignore (TBI) feature of arm64 CPUs +to store a pointer tag in the top byte of kernel pointers. Like generic KASAN +it uses shadow memory to store memory tags associated with each 16-byte memory cell (therefore it dedicates 1/16th of the kernel memory for shadow memory). -On each memory allocation tag-based KASAN generates a random tag, tags the -allocated memory with this tag, and embeds this tag into the returned pointer. +On each memory allocation software tag-based KASAN generates a random tag, tags +the allocated memory with this tag, and embeds this tag into the returned +pointer. + Software tag-based KASAN uses compile-time instrumentation to insert checks before each memory access. These checks make sure that tag of the memory that is being accessed is equal to tag of the pointer that is used to access this -memory. In case of a tag mismatch tag-based KASAN prints a bug report. +memory. In case of a tag mismatch software tag-based KASAN prints a bug report. Software tag-based KASAN also has two instrumentation modes (outline, that emits callbacks to check memory accesses; and inline, that performs the shadow
@@ -215,9 +226,34 @@ simply printed from the function that performs the access check. With inline instrumentation a brk instruction is emitted by the compiler, and a dedicated brk handler is used to print bug reports. -A potential expansion of this mode is a hardware tag-based mode, which would -use hardware memory tagging support instead of compiler instrumentation and -manual shadow memory manipulation. +Software tag-based KASAN uses 0xFF as a match-all pointer tag (accesses through +pointers with 0xFF pointer tag aren't checked). The value 0xFE is currently +reserved to tag freed memory regions. + +Software tag-based KASAN currently only supports tagging of slab memory. + +Hardware tag-based KASAN +~~~~~~~~~~~~~~~~~~~~~~~~ + +Hardware tag-based KASAN is similar to the software mode in concept, but uses +hardware memory tagging support instead of compiler instrumentation and +shadow memory. + +Hardware tag-based KASAN is currently only implemented for arm64 architecture +and based on both arm64 Memory Tagging Extension (MTE) introduced in ARMv8.5 +Instruction Set Architecture, and Top Byte Ignore (TBI). + +Special arm64 instructions are used to assign memory tags for each allocation. +Same tags are assigned to pointers to those allocations. On every memory +access, hardware makes sure that tag of the memory that is being accessed is +equal to tag of the pointer that is used to access this memory. In case of a +tag mismatch a fault is generated and a report is printed. + +Hardware tag-based KASAN uses 0xFF as a match-all pointer tag (accesses through +pointers with 0xFF pointer tag aren't checked). The value 0xFE is currently +reserved to tag freed memory regions. + +Hardware tag-based KASAN currently only supports tagging of slab memory. What memory accesses are sanitised by KASAN? --------------------------------------------
Signature · 1 line
2.28.0.681.g6f77f65b4e-goog
Re: [PATCH v3 39/39] kasan: add documentation for hardware tag-based mode
Quoted 5 lines · Andrey Konovalov
Add documentation for hardware tag-based KASAN mode and also add some clarifications for software tag-based mode.
Signed-off-by Andrey Konovalov <[email protected]>Signed-off-by Vincenzo Frascino <[email protected]>
Quoted 134 lines
---
Change-Id: Ib46cb444cfdee44054628940a82f5139e10d0258--- Documentation/dev-tools/kasan.rst | 78 ++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 21 deletions(-)Documentation/dev-tools/kasan.rst +57
-21@@ -5,12 +5,14 @@ Overview -------- KernelAddressSANitizer (KASAN) is a dynamic memory error detector designed to -find out-of-bound and use-after-free bugs. KASAN has two modes: generic KASAN -(similar to userspace ASan) and software tag-based KASAN (similar to userspace -HWASan). +find out-of-bound and use-after-free bugs. KASAN has three modes: +1. generic KASAN (similar to userspace ASan), +2. software tag-based KASAN (similar to userspace HWASan), +3. hardware tag-based KASAN (based on hardware memory tagging). -KASAN uses compile-time instrumentation to insert validity checks before every -memory access, and therefore requires a compiler version that supports that. +Software KASAN modes (1 and 2) use compile-time instrumentation to insert +validity checks before every memory access, and therefore require a compiler +version that supports that. Generic KASAN is supported in both GCC and Clang. With GCC it requires version 8.3.0 or later. With Clang it requires version 7.0.0 or later, but detection of@@ -19,7 +21,7 @@ out-of-bounds accesses for global variables is only supported since Clang 11. Tag-based KASAN is only supported in Clang and requires version 7.0.0 or later. Currently generic KASAN is supported for the x86_64, arm64, xtensa, s390 and -riscv architectures, and tag-based KASAN is supported only for arm64. +riscv architectures, and tag-based KASAN modes are supported only for arm64. Usage -----@@ -28,14 +30,16 @@ To enable KASAN configure kernel with:: CONFIG_KASAN = y -and choose between CONFIG_KASAN_GENERIC (to enable generic KASAN) and -CONFIG_KASAN_SW_TAGS (to enable software tag-based KASAN). +and choose between CONFIG_KASAN_GENERIC (to enable generic KASAN), +CONFIG_KASAN_SW_TAGS (to enable software tag-based KASAN), and +CONFIG_KASAN_HW_TAGS (to enable hardware tag-based KASAN). -You also need to choose between CONFIG_KASAN_OUTLINE and CONFIG_KASAN_INLINE. -Outline and inline are compiler instrumentation types. The former produces -smaller binary while the latter is 1.1 - 2 times faster. +For software modes, you also need to choose between CONFIG_KASAN_OUTLINE and +CONFIG_KASAN_INLINE. Outline and inline are compiler instrumentation types. +The former produces smaller binary while the latter is 1.1 - 2 times faster. -Both KASAN modes work with both SLUB and SLAB memory allocators. +Both software KASAN modes work with both SLUB and SLAB memory allocators, +hardware tag-based KASAN currently only support SLUB. For better bug detection and nicer reporting, enable CONFIG_STACKTRACE. To augment reports with last allocation and freeing stack of the physical page,@@ -196,17 +200,24 @@ and the second to last. Software tag-based KASAN ~~~~~~~~~~~~~~~~~~~~~~~~ -Tag-based KASAN uses the Top Byte Ignore (TBI) feature of modern arm64 CPUs to -store a pointer tag in the top byte of kernel pointers. Like generic KASAN it -uses shadow memory to store memory tags associated with each 16-byte memory +Software tag-based KASAN requires software memory tagging support in the form +of HWASan-like compiler instrumentation (see HWASan documentation for details). + +Software tag-based KASAN is currently only implemented for arm64 architecture. + +Software tag-based KASAN uses the Top Byte Ignore (TBI) feature of arm64 CPUs +to store a pointer tag in the top byte of kernel pointers. Like generic KASAN +it uses shadow memory to store memory tags associated with each 16-byte memory cell (therefore it dedicates 1/16th of the kernel memory for shadow memory). -On each memory allocation tag-based KASAN generates a random tag, tags the -allocated memory with this tag, and embeds this tag into the returned pointer. +On each memory allocation software tag-based KASAN generates a random tag, tags +the allocated memory with this tag, and embeds this tag into the returned +pointer. + Software tag-based KASAN uses compile-time instrumentation to insert checks before each memory access. These checks make sure that tag of the memory that is being accessed is equal to tag of the pointer that is used to access this -memory. In case of a tag mismatch tag-based KASAN prints a bug report. +memory. In case of a tag mismatch software tag-based KASAN prints a bug report. Software tag-based KASAN also has two instrumentation modes (outline, that emits callbacks to check memory accesses; and inline, that performs the shadow@@ -215,9 +226,34 @@ simply printed from the function that performs the access check. With inline instrumentation a brk instruction is emitted by the compiler, and a dedicated brk handler is used to print bug reports. -A potential expansion of this mode is a hardware tag-based mode, which would -use hardware memory tagging support instead of compiler instrumentation and -manual shadow memory manipulation. +Software tag-based KASAN uses 0xFF as a match-all pointer tag (accesses through +pointers with 0xFF pointer tag aren't checked). The value 0xFE is currently +reserved to tag freed memory regions. + +Software tag-based KASAN currently only supports tagging of slab memory. + +Hardware tag-based KASAN +~~~~~~~~~~~~~~~~~~~~~~~~ + +Hardware tag-based KASAN is similar to the software mode in concept, but uses +hardware memory tagging support instead of compiler instrumentation and +shadow memory. + +Hardware tag-based KASAN is currently only implemented for arm64 architecture +and based on both arm64 Memory Tagging Extension (MTE) introduced in ARMv8.5 +Instruction Set Architecture, and Top Byte Ignore (TBI). + +Special arm64 instructions are used to assign memory tags for each allocation. +Same tags are assigned to pointers to those allocations. On every memory +access, hardware makes sure that tag of the memory that is being accessed is +equal to tag of the pointer that is used to access this memory. In case of a +tag mismatch a fault is generated and a report is printed. + +Hardware tag-based KASAN uses 0xFF as a match-all pointer tag (accesses through +pointers with 0xFF pointer tag aren't checked). The value 0xFE is currently +reserved to tag freed memory regions. + +Hardware tag-based KASAN currently only supports tagging of slab memory. What memory accesses are sanitised by KASAN? --------------------------------------------Signature · 1 line
2.28.0.681.g6f77f65b4e-goog