mbox series

[v9,00/20] kasan: add software tag-based mode for arm64

Message ID cover.1537542735.git.andreyknvl@google.com
Headers show
Series kasan: add software tag-based mode for arm64 | expand

Message

Andrey Konovalov Sept. 21, 2018, 3:13 p.m. UTC
This patchset adds a new software tag-based mode to KASAN [1].
(Initially this mode was called KHWASAN, but it got renamed,
 see the naming rationale at the end of this section).

The plan is to implement HWASan [2] for the kernel with the incentive,
that it's going to have comparable to KASAN performance, but in the same
time consume much less memory, trading that off for somewhat imprecise
bug detection and being supported only for arm64.

The underlying ideas of the approach used by software tag-based KASAN are:

1. By using the Top Byte Ignore (TBI) arm64 CPU feature, we can store
   pointer tags in the top byte of each kernel pointer.

2. Using shadow memory, we can store memory tags for each chunk of kernel
   memory.

3. On each memory allocation, we can generate a random tag, embed it into
   the returned pointer and set the memory tags that correspond to this
   chunk of memory to the same value.

4. By using compiler instrumentation, before each memory access we can add
   a check that the pointer tag matches the tag of the memory that is being
   accessed.

5. On a tag mismatch we report an error.

With this patchset the existing KASAN mode gets renamed to generic KASAN,
with the word "generic" meaning that the implementation can be supported
by any architecture as it is purely software.

The new mode this patchset adds is called software tag-based KASAN. The
word "tag-based" refers to the fact that this mode uses tags embedded into
the top byte of kernel pointers and the TBI arm64 CPU feature that allows
to dereference such pointers. The word "software" here means that shadow
memory manipulation and tag checking on pointer dereference is done in
software. As it is the only tag-based implementation right now, "software
tag-based" KASAN is sometimes referred to as simply "tag-based" in this
patchset.

A potential expansion of this mode is a hardware tag-based mode, which would
use hardware memory tagging support (announced by Arm [3]) instead of
compiler instrumentation and manual shadow memory manipulation.

Same as generic KASAN, software tag-based KASAN is strictly a debugging
feature.

[1] https://www.kernel.org/doc/html/latest/dev-tools/kasan.html

[2] http://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html

[3] https://community.arm.com/processors/b/blog/posts/arm-a-profile-architecture-2018-developments-armv85a


====== Rationale

On mobile devices generic KASAN's memory usage is significant problem. One
of the main reasons to have tag-based KASAN is to be able to perform a
similar set of checks as the generic one does, but with lower memory
requirements.

Comment from Vishwath Mohan <vishwath@google.com>:

I don't have data on-hand, but anecdotally both ASAN and KASAN have proven
problematic to enable for environments that don't tolerate the increased
memory pressure well. This includes,
(a) Low-memory form factors - Wear, TV, Things, lower-tier phones like Go,
(c) Connected components like Pixel's visual core [1].

These are both places I'd love to have a low(er) memory footprint option at
my disposal.

Comment from Evgenii Stepanov <eugenis@google.com>:

Looking at a live Android device under load, slab (according to
/proc/meminfo) + kernel stack take 8-10% available RAM (~350MB). KASAN's
overhead of 2x - 3x on top of it is not insignificant.

Not having this overhead enables near-production use - ex. running
KASAN/KHWASAN kernel on a personal, daily-use device to catch bugs that do
not reproduce in test configuration. These are the ones that often cost
the most engineering time to track down.

CPU overhead is bad, but generally tolerable. RAM is critical, in our
experience. Once it gets low enough, OOM-killer makes your life miserable.

[1] https://www.blog.google/products/pixel/pixel-visual-core-image-processing-and-machine-learning-pixel-2/


====== Technical details

Software tag-based KASAN mode is implemented in a very similar way to the
generic one. This patchset essentially does the following:

1. TCR_TBI1 is set to enable Top Byte Ignore.

2. Shadow memory is used (with a different scale, 1:16, so each shadow
   byte corresponds to 16 bytes of kernel memory) to store memory tags.

3. All slab objects are aligned to shadow scale, which is 16 bytes.

4. All pointers returned from the slab allocator are tagged with a random
   tag and the corresponding shadow memory is poisoned with the same value.

5. Compiler instrumentation is used to insert tag checks. Either by
   calling callbacks or by inlining them (CONFIG_KASAN_OUTLINE and
   CONFIG_KASAN_INLINE flags are reused).

6. When a tag mismatch is detected in callback instrumentation mode
   KASAN simply prints a bug report. In case of inline instrumentation,
   clang inserts a brk instruction, and KASAN has it's own brk handler,
   which reports the bug.

7. The memory in between slab objects is marked with a reserved tag, and
   acts as a redzone.

8. When a slab object is freed it's marked with a reserved tag.

Bug detection is imprecise for two reasons:

1. We won't catch some small out-of-bounds accesses, that fall into the
   same shadow cell, as the last byte of a slab object.

2. We only have 1 byte to store tags, which means we have a 1/256
   probability of a tag match for an incorrect access (actually even
   slightly less due to reserved tag values).

Despite that there's a particular type of bugs that tag-based KASAN can
detect compared to generic KASAN: use-after-free after the object has been
allocated by someone else.


====== Testing

Some kernel developers voiced a concern that changing the top byte of
kernel pointers may lead to subtle bugs that are difficult to discover.
To address this concern deliberate testing has been performed.

It doesn't seem feasible to do some kind of static checking to find
potential issues with pointer tagging, so a dynamic approach was taken.
All pointer comparisons/subtractions have been instrumented in an LLVM
compiler pass and a kernel module that would print a bug report whenever
two pointers with different tags are being compared/subtracted (ignoring
comparisons with NULL pointers and with pointers obtained by casting an
error code to a pointer type) has been used. Then the kernel has been
booted in QEMU and on an Odroid C2 board and syzkaller has been run.

This yielded the following results.

The two places that look interesting are:

is_vmalloc_addr in include/linux/mm.h
is_kernel_rodata in mm/util.c

Here we compare a pointer with some fixed untagged values to make sure
that the pointer lies in a particular part of the kernel address space.
Since tag-based KASAN doesn't add tags to pointers that belong to rodata
or vmalloc regions, this should work as is. To make sure debug checks to
those two functions that check that the result doesn't change whether
we operate on pointers with or without untagging has been added.

A few other cases that don't look that interesting:

Comparing pointers to achieve unique sorting order of pointee objects
(e.g. sorting locks addresses before performing a double lock):

tty_ldisc_lock_pair_timeout in drivers/tty/tty_ldisc.c
pipe_double_lock in fs/pipe.c
unix_state_double_lock in net/unix/af_unix.c
lock_two_nondirectories in fs/inode.c
mutex_lock_double in kernel/events/core.c

ep_cmp_ffd in fs/eventpoll.c
fsnotify_compare_groups fs/notify/mark.c

Nothing needs to be done here, since the tags embedded into pointers
don't change, so the sorting order would still be unique.

Checks that a pointer belongs to some particular allocation:

is_sibling_entry in lib/radix-tree.c
object_is_on_stack in include/linux/sched/task_stack.h

Nothing needs to be done here either, since two pointers can only belong
to the same allocation if they have the same tag.

Overall, since the kernel boots and works, there are no critical bugs.
As for the rest, the traditional kernel testing way (use until fails) is
the only one that looks feasible.

Another point here is that tag-based KASAN is available under a separate
config option that needs to be deliberately enabled. Even though it might
be used in a "near-production" environment to find bugs that are not found
during fuzzing or running tests, it is still a debug tool.


====== Benchmarks

The following numbers were collected on Odroid C2 board. Both generic and
tag-based KASAN were used in inline instrumentation mode.

Boot time [1]:
* ~1.7 sec for clean kernel
* ~5.0 sec for generic KASAN
* ~5.0 sec for tag-based KASAN

Network performance [2]:
* 8.33 Gbits/sec for clean kernel
* 3.17 Gbits/sec for generic KASAN
* 2.85 Gbits/sec for tag-based KASAN

Slab memory usage after boot [3]:
* ~40 kb for clean kernel
* ~105 kb (~260% overhead) for generic KASAN
* ~47 kb (~20% overhead) for tag-based KASAN

KASAN memory overhead consists of three main parts:
1. Increased slab memory usage due to redzones.
2. Shadow memory (the whole reserved once during boot).
3. Quaratine (grows gradually until some preset limit; the more the limit,
   the more the chance to detect a use-after-free).

Comparing tag-based vs generic KASAN for each of these points:
1. 20% vs 260% overhead.
2. 1/16th vs 1/8th of physical memory.
3. Tag-based KASAN doesn't require quarantine.

[1] Time before the ext4 driver is initialized.
[2] Measured as `iperf -s & iperf -c 127.0.0.1 -t 30`.
[3] Measured as `cat /proc/meminfo | grep Slab`.


====== Some notes

A few notes:

1. The patchset can be found here:
   https://github.com/xairy/kasan-prototype/tree/khwasan

2. Building requires a recent Clang version (7.0.0 or later).

3. Stack instrumentation is not supported yet and will be added later.


====== Changes

Changes in v9:
- Fixed kasan_init_slab_obj() hook when KASAN is disabled.
- Added assign_tag() function that preassigns tags for caches with
  constructors.
- Fixed KASAN_TAG_MASK redefinition in include/linux/mm.h vs
  mm/kasan/kasan.h.

Changes in v8:
- Rebased onto 7876320f (4.19-rc4).
- Renamed KHWASAN to software tag-based KASAN (see the top of the cover
  letter for details).
- Explicitly called tag-based KASAN a debug tool.
- Reused kasan_init_slab_obj() callback to preassign tags to caches
  without constructors, remove khwasan_preset_sl(u/a)b_tag().
- Moved move obj_to_index to include/linux/slab_def.h from mm/slab.c.
- Moved cache->s_mem untagging to alloc_slabmgmt() for SLAB.
- Fixed check_memory_region() to correctly handle user memory accesses and
  size == 0 case.
- Merged __no_sanitize_hwaddress into __no_sanitize_address.
- Defined KASAN_SET_TAG and KASAN_RESET_TAG macros for non KASAN builds to
  avoid duplication of __kimg_to_phys, _virt_addr_is_linear and
  page_to_virt macros.
- Fixed and simplified find_first_bad_addr for generic KASAN.
- Use non symbolized example KASAN report in documentation.
- Mention clang version requirements for both KASAN modes in the Kconfig
  options and in the documentation.
- Various small fixes.

Version v7 got accidentally skipped.

Changes in v6:
- Rebased onto 050cdc6c (4.19-rc1+).
- Added notes regarding patchset testing into the cover letter.

Changes in v5:
- Rebased onto 1ffaddd029 (4.18-rc8).
- Preassign tags for objects from caches with constructors and
  SLAB_TYPESAFE_BY_RCU caches.
- Fix SLAB allocator support by untagging page->s_mem in
  kasan_poison_slab().
- Performed dynamic testing to find potential places where pointer tagging
  might result in bugs [1].
- Clarified and fixed memory usage benchmarks in the cover letter.
- Added a rationale for having KHWASAN to the cover letter.

Changes in v4:
- Fixed SPDX comment style in mm/kasan/kasan.h.
- Fixed mm/kasan/kasan.h changes being included in a wrong patch.
- Swapped "khwasan, arm64: fix up fault handling logic" and "khwasan: add
  tag related helper functions" patches order.
- Rebased onto 6f0d349d (4.18-rc2+).

Changes in v3:
- Minor documentation fixes.
- Fixed CFLAGS variable name in KASAN makefile.
- Added a "SPDX-License-Identifier: GPL-2.0" line to all source files
  under mm/kasan.
- Rebased onto 81e97f013 (4.18-rc1+).

Changes in v2:
- Changed kmalloc_large_node_hook to return tagged pointer instead of
  using an output argument.
- Fix checking whether -fsanitize=hwaddress is supported by the compiler.
- Removed duplication of -fno-builtin for KASAN and KHWASAN.
- Removed {} block for one line for_each_possible_cpu loop.
- Made set_track() static inline as it is used only in common.c.
- Moved optimal_redzone() to common.c.
- Fixed using tagged pointer for shadow calculation in
  kasan_unpoison_shadow().
- Restored setting cache->align in kasan_cache_create(), which was
  accidentally lost.
- Simplified __kasan_slab_free(), kasan_alloc_pages() and kasan_kmalloc().
- Removed tagging from kasan_kmalloc_large().
- Added page_kasan_tag_reset() to kasan_poison_slab() and removed
  !PageSlab() check from page_to_virt.
- Reset pointer tag in _virt_addr_is_linear.
- Set page tag for each page when multiple pages are allocated or freed.
- Added a comment as to why we ignore cma allocated pages.

Changes in v1:
- Rebased onto 4.17-rc4.
- Updated benchmarking stats.
- Documented compiler version requirements, memory usage and slowdown.
- Dropped kvm patches, as clang + arm64 + kvm is completely broken [1].

Changes in RFC v3:
- Renamed CONFIG_KASAN_CLASSIC and CONFIG_KASAN_TAGS to
  CONFIG_KASAN_GENERIC and CONFIG_KASAN_HW respectively.
- Switch to -fsanitize=kernel-hwaddress instead of -fsanitize=hwaddress.
- Removed unnecessary excessive shadow initialization.
- Removed khwasan_enabled flag (it’s not needed since KHWASAN is
  initialized before any slab caches are used).
- Split out kasan_report.c and khwasan_report.c from report.c.
- Moved more common KASAN and KHWASAN functions to common.c.
- Added tagging to pagealloc.
- Rebased onto 4.17-rc1.
- Temporarily dropped patch that adds kvm support (arm64 + kvm + clang
  combo is broken right now [2]).

Changes in RFC v2:
- Removed explicit casts to u8 * for kasan_mem_to_shadow() calls.
- Introduced KASAN_TCR_FLAGS for setting the TCR_TBI1 flag.
- Added a comment regarding the non-atomic RMW sequence in
  khwasan_random_tag().
- Made all tag related functions accept const void *.
- Untagged pointers in __kimg_to_phys, which is used by virt_to_phys.
- Untagged pointers in show_ptr in fault handling logic.
- Untagged pointers passed to KVM.
- Added two reserved tag values: 0xFF and 0xFE.
- Used the reserved tag 0xFF to disable validity checking (to resolve the
  issue with pointer tag being lost after page_address + kmap usage).
- Used the reserved tag 0xFE to mark redzones and freed objects.
- Added mnemonics for esr manipulation in KHWASAN brk handler.
- Added a comment about the -recover flag.
- Some minor cleanups and fixes.
- Rebased onto 3215b9d5 (4.16-rc6+).
- Tested on real hardware (Odroid C2 board).
- Added better benchmarks.

[1] https://lkml.org/lkml/2018/7/18/765
[2] https://lkml.org/lkml/2018/4/19/775

Andrey Konovalov (20):
  kasan, mm: change hooks signatures
  kasan: move common generic and tag-based code to common.c
  kasan: rename source files to reflect the new naming scheme
  kasan: add CONFIG_KASAN_GENERIC and CONFIG_KASAN_SW_TAGS
  kasan, arm64: adjust shadow size for tag-based mode
  kasan: initialize shadow to 0xff for tag-based mode
  kasan, arm64: untag address in __kimg_to_phys and _virt_addr_is_linear
  kasan: add tag related helper functions
  kasan: preassign tags to objects with ctors or SLAB_TYPESAFE_BY_RCU
  mm: move obj_to_index to include/linux/slab_def.h
  kasan, arm64: fix up fault handling logic
  kasan, arm64: enable top byte ignore for the kernel
  kasan, mm: perform untagged pointers comparison in krealloc
  kasan: split out generic_report.c from report.c
  kasan: add bug reporting routines for tag-based mode
  kasan: add hooks implementation for tag-based mode
  kasan, arm64: add brk handler for inline instrumentation
  kasan, mm, arm64: tag non slab memory allocated via pagealloc
  kasan: update documentation
  kasan: add SPDX-License-Identifier mark to source files

 Documentation/dev-tools/kasan.rst      | 232 +++++----
 arch/arm64/Kconfig                     |   1 +
 arch/arm64/Makefile                    |   2 +-
 arch/arm64/include/asm/brk-imm.h       |   2 +
 arch/arm64/include/asm/memory.h        |  36 +-
 arch/arm64/include/asm/pgtable-hwdef.h |   1 +
 arch/arm64/kernel/traps.c              |  68 ++-
 arch/arm64/mm/fault.c                  |   3 +
 arch/arm64/mm/kasan_init.c             |  18 +-
 arch/arm64/mm/proc.S                   |   8 +-
 include/linux/compiler-clang.h         |   5 +-
 include/linux/kasan.h                  |  83 +++-
 include/linux/mm.h                     |  29 ++
 include/linux/page-flags-layout.h      |  10 +
 include/linux/slab_def.h               |  13 +
 lib/Kconfig.kasan                      |  87 +++-
 mm/cma.c                               |  11 +
 mm/kasan/Makefile                      |  15 +-
 mm/kasan/{kasan.c => common.c}         | 651 +++++++++----------------
 mm/kasan/generic.c                     | 344 +++++++++++++
 mm/kasan/generic_report.c              | 153 ++++++
 mm/kasan/{kasan_init.c => init.c}      |   1 +
 mm/kasan/kasan.h                       |  83 +++-
 mm/kasan/quarantine.c                  |   1 +
 mm/kasan/report.c                      | 272 +++--------
 mm/kasan/tags.c                        | 161 ++++++
 mm/kasan/tags_report.c                 |  58 +++
 mm/page_alloc.c                        |   1 +
 mm/slab.c                              |  29 +-
 mm/slab.h                              |   2 +-
 mm/slab_common.c                       |   6 +-
 mm/slub.c                              |  41 +-
 scripts/Makefile.kasan                 |  27 +-
 33 files changed, 1629 insertions(+), 825 deletions(-)
 rename mm/kasan/{kasan.c => common.c} (59%)
 create mode 100644 mm/kasan/generic.c
 create mode 100644 mm/kasan/generic_report.c
 rename mm/kasan/{kasan_init.c => init.c} (99%)
 create mode 100644 mm/kasan/tags.c
 create mode 100644 mm/kasan/tags_report.c

Comments

Dmitry Vyukov Sept. 24, 2018, 3:14 p.m. UTC | #1
On Fri, Sep 21, 2018 at 5:13 PM, Andrey Konovalov <andreyknvl@google.com> wrote:
> This patchset adds a new software tag-based mode to KASAN [1].
> (Initially this mode was called KHWASAN, but it got renamed,
>  see the naming rationale at the end of this section).

Reviewed-by: Dmitry Vyukov <dvyukov@google.com>

> The plan is to implement HWASan [2] for the kernel with the incentive,
> that it's going to have comparable to KASAN performance, but in the same
> time consume much less memory, trading that off for somewhat imprecise
> bug detection and being supported only for arm64.
>
> The underlying ideas of the approach used by software tag-based KASAN are:
>
> 1. By using the Top Byte Ignore (TBI) arm64 CPU feature, we can store
>    pointer tags in the top byte of each kernel pointer.
>
> 2. Using shadow memory, we can store memory tags for each chunk of kernel
>    memory.
>
> 3. On each memory allocation, we can generate a random tag, embed it into
>    the returned pointer and set the memory tags that correspond to this
>    chunk of memory to the same value.
>
> 4. By using compiler instrumentation, before each memory access we can add
>    a check that the pointer tag matches the tag of the memory that is being
>    accessed.
>
> 5. On a tag mismatch we report an error.
>
> With this patchset the existing KASAN mode gets renamed to generic KASAN,
> with the word "generic" meaning that the implementation can be supported
> by any architecture as it is purely software.
>
> The new mode this patchset adds is called software tag-based KASAN. The
> word "tag-based" refers to the fact that this mode uses tags embedded into
> the top byte of kernel pointers and the TBI arm64 CPU feature that allows
> to dereference such pointers. The word "software" here means that shadow
> memory manipulation and tag checking on pointer dereference is done in
> software. As it is the only tag-based implementation right now, "software
> tag-based" KASAN is sometimes referred to as simply "tag-based" in this
> patchset.
>
> A potential expansion of this mode is a hardware tag-based mode, which would
> use hardware memory tagging support (announced by Arm [3]) instead of
> compiler instrumentation and manual shadow memory manipulation.
>
> Same as generic KASAN, software tag-based KASAN is strictly a debugging
> feature.
>
> [1] https://www.kernel.org/doc/html/latest/dev-tools/kasan.html
>
> [2] http://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
>
> [3] https://community.arm.com/processors/b/blog/posts/arm-a-profile-architecture-2018-developments-armv85a
>
>
> ====== Rationale
>
> On mobile devices generic KASAN's memory usage is significant problem. One
> of the main reasons to have tag-based KASAN is to be able to perform a
> similar set of checks as the generic one does, but with lower memory
> requirements.
>
> Comment from Vishwath Mohan <vishwath@google.com>:
>
> I don't have data on-hand, but anecdotally both ASAN and KASAN have proven
> problematic to enable for environments that don't tolerate the increased
> memory pressure well. This includes,
> (a) Low-memory form factors - Wear, TV, Things, lower-tier phones like Go,
> (c) Connected components like Pixel's visual core [1].
>
> These are both places I'd love to have a low(er) memory footprint option at
> my disposal.
>
> Comment from Evgenii Stepanov <eugenis@google.com>:
>
> Looking at a live Android device under load, slab (according to
> /proc/meminfo) + kernel stack take 8-10% available RAM (~350MB). KASAN's
> overhead of 2x - 3x on top of it is not insignificant.
>
> Not having this overhead enables near-production use - ex. running
> KASAN/KHWASAN kernel on a personal, daily-use device to catch bugs that do
> not reproduce in test configuration. These are the ones that often cost
> the most engineering time to track down.
>
> CPU overhead is bad, but generally tolerable. RAM is critical, in our
> experience. Once it gets low enough, OOM-killer makes your life miserable.
>
> [1] https://www.blog.google/products/pixel/pixel-visual-core-image-processing-and-machine-learning-pixel-2/
>
>
> ====== Technical details
>
> Software tag-based KASAN mode is implemented in a very similar way to the
> generic one. This patchset essentially does the following:
>
> 1. TCR_TBI1 is set to enable Top Byte Ignore.
>
> 2. Shadow memory is used (with a different scale, 1:16, so each shadow
>    byte corresponds to 16 bytes of kernel memory) to store memory tags.
>
> 3. All slab objects are aligned to shadow scale, which is 16 bytes.
>
> 4. All pointers returned from the slab allocator are tagged with a random
>    tag and the corresponding shadow memory is poisoned with the same value.
>
> 5. Compiler instrumentation is used to insert tag checks. Either by
>    calling callbacks or by inlining them (CONFIG_KASAN_OUTLINE and
>    CONFIG_KASAN_INLINE flags are reused).
>
> 6. When a tag mismatch is detected in callback instrumentation mode
>    KASAN simply prints a bug report. In case of inline instrumentation,
>    clang inserts a brk instruction, and KASAN has it's own brk handler,
>    which reports the bug.
>
> 7. The memory in between slab objects is marked with a reserved tag, and
>    acts as a redzone.
>
> 8. When a slab object is freed it's marked with a reserved tag.
>
> Bug detection is imprecise for two reasons:
>
> 1. We won't catch some small out-of-bounds accesses, that fall into the
>    same shadow cell, as the last byte of a slab object.
>
> 2. We only have 1 byte to store tags, which means we have a 1/256
>    probability of a tag match for an incorrect access (actually even
>    slightly less due to reserved tag values).
>
> Despite that there's a particular type of bugs that tag-based KASAN can
> detect compared to generic KASAN: use-after-free after the object has been
> allocated by someone else.
>
>
> ====== Testing
>
> Some kernel developers voiced a concern that changing the top byte of
> kernel pointers may lead to subtle bugs that are difficult to discover.
> To address this concern deliberate testing has been performed.
>
> It doesn't seem feasible to do some kind of static checking to find
> potential issues with pointer tagging, so a dynamic approach was taken.
> All pointer comparisons/subtractions have been instrumented in an LLVM
> compiler pass and a kernel module that would print a bug report whenever
> two pointers with different tags are being compared/subtracted (ignoring
> comparisons with NULL pointers and with pointers obtained by casting an
> error code to a pointer type) has been used. Then the kernel has been
> booted in QEMU and on an Odroid C2 board and syzkaller has been run.
>
> This yielded the following results.
>
> The two places that look interesting are:
>
> is_vmalloc_addr in include/linux/mm.h
> is_kernel_rodata in mm/util.c
>
> Here we compare a pointer with some fixed untagged values to make sure
> that the pointer lies in a particular part of the kernel address space.
> Since tag-based KASAN doesn't add tags to pointers that belong to rodata
> or vmalloc regions, this should work as is. To make sure debug checks to
> those two functions that check that the result doesn't change whether
> we operate on pointers with or without untagging has been added.
>
> A few other cases that don't look that interesting:
>
> Comparing pointers to achieve unique sorting order of pointee objects
> (e.g. sorting locks addresses before performing a double lock):
>
> tty_ldisc_lock_pair_timeout in drivers/tty/tty_ldisc.c
> pipe_double_lock in fs/pipe.c
> unix_state_double_lock in net/unix/af_unix.c
> lock_two_nondirectories in fs/inode.c
> mutex_lock_double in kernel/events/core.c
>
> ep_cmp_ffd in fs/eventpoll.c
> fsnotify_compare_groups fs/notify/mark.c
>
> Nothing needs to be done here, since the tags embedded into pointers
> don't change, so the sorting order would still be unique.
>
> Checks that a pointer belongs to some particular allocation:
>
> is_sibling_entry in lib/radix-tree.c
> object_is_on_stack in include/linux/sched/task_stack.h
>
> Nothing needs to be done here either, since two pointers can only belong
> to the same allocation if they have the same tag.
>
> Overall, since the kernel boots and works, there are no critical bugs.
> As for the rest, the traditional kernel testing way (use until fails) is
> the only one that looks feasible.
>
> Another point here is that tag-based KASAN is available under a separate
> config option that needs to be deliberately enabled. Even though it might
> be used in a "near-production" environment to find bugs that are not found
> during fuzzing or running tests, it is still a debug tool.
>
>
> ====== Benchmarks
>
> The following numbers were collected on Odroid C2 board. Both generic and
> tag-based KASAN were used in inline instrumentation mode.
>
> Boot time [1]:
> * ~1.7 sec for clean kernel
> * ~5.0 sec for generic KASAN
> * ~5.0 sec for tag-based KASAN
>
> Network performance [2]:
> * 8.33 Gbits/sec for clean kernel
> * 3.17 Gbits/sec for generic KASAN
> * 2.85 Gbits/sec for tag-based KASAN
>
> Slab memory usage after boot [3]:
> * ~40 kb for clean kernel
> * ~105 kb (~260% overhead) for generic KASAN
> * ~47 kb (~20% overhead) for tag-based KASAN
>
> KASAN memory overhead consists of three main parts:
> 1. Increased slab memory usage due to redzones.
> 2. Shadow memory (the whole reserved once during boot).
> 3. Quaratine (grows gradually until some preset limit; the more the limit,
>    the more the chance to detect a use-after-free).
>
> Comparing tag-based vs generic KASAN for each of these points:
> 1. 20% vs 260% overhead.
> 2. 1/16th vs 1/8th of physical memory.
> 3. Tag-based KASAN doesn't require quarantine.
>
> [1] Time before the ext4 driver is initialized.
> [2] Measured as `iperf -s & iperf -c 127.0.0.1 -t 30`.
> [3] Measured as `cat /proc/meminfo | grep Slab`.
>
>
> ====== Some notes
>
> A few notes:
>
> 1. The patchset can be found here:
>    https://github.com/xairy/kasan-prototype/tree/khwasan
>
> 2. Building requires a recent Clang version (7.0.0 or later).
>
> 3. Stack instrumentation is not supported yet and will be added later.
>
>
> ====== Changes
>
> Changes in v9:
> - Fixed kasan_init_slab_obj() hook when KASAN is disabled.
> - Added assign_tag() function that preassigns tags for caches with
>   constructors.
> - Fixed KASAN_TAG_MASK redefinition in include/linux/mm.h vs
>   mm/kasan/kasan.h.
>
> Changes in v8:
> - Rebased onto 7876320f (4.19-rc4).
> - Renamed KHWASAN to software tag-based KASAN (see the top of the cover
>   letter for details).
> - Explicitly called tag-based KASAN a debug tool.
> - Reused kasan_init_slab_obj() callback to preassign tags to caches
>   without constructors, remove khwasan_preset_sl(u/a)b_tag().
> - Moved move obj_to_index to include/linux/slab_def.h from mm/slab.c.
> - Moved cache->s_mem untagging to alloc_slabmgmt() for SLAB.
> - Fixed check_memory_region() to correctly handle user memory accesses and
>   size == 0 case.
> - Merged __no_sanitize_hwaddress into __no_sanitize_address.
> - Defined KASAN_SET_TAG and KASAN_RESET_TAG macros for non KASAN builds to
>   avoid duplication of __kimg_to_phys, _virt_addr_is_linear and
>   page_to_virt macros.
> - Fixed and simplified find_first_bad_addr for generic KASAN.
> - Use non symbolized example KASAN report in documentation.
> - Mention clang version requirements for both KASAN modes in the Kconfig
>   options and in the documentation.
> - Various small fixes.
>
> Version v7 got accidentally skipped.
>
> Changes in v6:
> - Rebased onto 050cdc6c (4.19-rc1+).
> - Added notes regarding patchset testing into the cover letter.
>
> Changes in v5:
> - Rebased onto 1ffaddd029 (4.18-rc8).
> - Preassign tags for objects from caches with constructors and
>   SLAB_TYPESAFE_BY_RCU caches.
> - Fix SLAB allocator support by untagging page->s_mem in
>   kasan_poison_slab().
> - Performed dynamic testing to find potential places where pointer tagging
>   might result in bugs [1].
> - Clarified and fixed memory usage benchmarks in the cover letter.
> - Added a rationale for having KHWASAN to the cover letter.
>
> Changes in v4:
> - Fixed SPDX comment style in mm/kasan/kasan.h.
> - Fixed mm/kasan/kasan.h changes being included in a wrong patch.
> - Swapped "khwasan, arm64: fix up fault handling logic" and "khwasan: add
>   tag related helper functions" patches order.
> - Rebased onto 6f0d349d (4.18-rc2+).
>
> Changes in v3:
> - Minor documentation fixes.
> - Fixed CFLAGS variable name in KASAN makefile.
> - Added a "SPDX-License-Identifier: GPL-2.0" line to all source files
>   under mm/kasan.
> - Rebased onto 81e97f013 (4.18-rc1+).
>
> Changes in v2:
> - Changed kmalloc_large_node_hook to return tagged pointer instead of
>   using an output argument.
> - Fix checking whether -fsanitize=hwaddress is supported by the compiler.
> - Removed duplication of -fno-builtin for KASAN and KHWASAN.
> - Removed {} block for one line for_each_possible_cpu loop.
> - Made set_track() static inline as it is used only in common.c.
> - Moved optimal_redzone() to common.c.
> - Fixed using tagged pointer for shadow calculation in
>   kasan_unpoison_shadow().
> - Restored setting cache->align in kasan_cache_create(), which was
>   accidentally lost.
> - Simplified __kasan_slab_free(), kasan_alloc_pages() and kasan_kmalloc().
> - Removed tagging from kasan_kmalloc_large().
> - Added page_kasan_tag_reset() to kasan_poison_slab() and removed
>   !PageSlab() check from page_to_virt.
> - Reset pointer tag in _virt_addr_is_linear.
> - Set page tag for each page when multiple pages are allocated or freed.
> - Added a comment as to why we ignore cma allocated pages.
>
> Changes in v1:
> - Rebased onto 4.17-rc4.
> - Updated benchmarking stats.
> - Documented compiler version requirements, memory usage and slowdown.
> - Dropped kvm patches, as clang + arm64 + kvm is completely broken [1].
>
> Changes in RFC v3:
> - Renamed CONFIG_KASAN_CLASSIC and CONFIG_KASAN_TAGS to
>   CONFIG_KASAN_GENERIC and CONFIG_KASAN_HW respectively.
> - Switch to -fsanitize=kernel-hwaddress instead of -fsanitize=hwaddress.
> - Removed unnecessary excessive shadow initialization.
> - Removed khwasan_enabled flag (it’s not needed since KHWASAN is
>   initialized before any slab caches are used).
> - Split out kasan_report.c and khwasan_report.c from report.c.
> - Moved more common KASAN and KHWASAN functions to common.c.
> - Added tagging to pagealloc.
> - Rebased onto 4.17-rc1.
> - Temporarily dropped patch that adds kvm support (arm64 + kvm + clang
>   combo is broken right now [2]).
>
> Changes in RFC v2:
> - Removed explicit casts to u8 * for kasan_mem_to_shadow() calls.
> - Introduced KASAN_TCR_FLAGS for setting the TCR_TBI1 flag.
> - Added a comment regarding the non-atomic RMW sequence in
>   khwasan_random_tag().
> - Made all tag related functions accept const void *.
> - Untagged pointers in __kimg_to_phys, which is used by virt_to_phys.
> - Untagged pointers in show_ptr in fault handling logic.
> - Untagged pointers passed to KVM.
> - Added two reserved tag values: 0xFF and 0xFE.
> - Used the reserved tag 0xFF to disable validity checking (to resolve the
>   issue with pointer tag being lost after page_address + kmap usage).
> - Used the reserved tag 0xFE to mark redzones and freed objects.
> - Added mnemonics for esr manipulation in KHWASAN brk handler.
> - Added a comment about the -recover flag.
> - Some minor cleanups and fixes.
> - Rebased onto 3215b9d5 (4.16-rc6+).
> - Tested on real hardware (Odroid C2 board).
> - Added better benchmarks.
>
> [1] https://lkml.org/lkml/2018/7/18/765
> [2] https://lkml.org/lkml/2018/4/19/775
>
> Andrey Konovalov (20):
>   kasan, mm: change hooks signatures
>   kasan: move common generic and tag-based code to common.c
>   kasan: rename source files to reflect the new naming scheme
>   kasan: add CONFIG_KASAN_GENERIC and CONFIG_KASAN_SW_TAGS
>   kasan, arm64: adjust shadow size for tag-based mode
>   kasan: initialize shadow to 0xff for tag-based mode
>   kasan, arm64: untag address in __kimg_to_phys and _virt_addr_is_linear
>   kasan: add tag related helper functions
>   kasan: preassign tags to objects with ctors or SLAB_TYPESAFE_BY_RCU
>   mm: move obj_to_index to include/linux/slab_def.h
>   kasan, arm64: fix up fault handling logic
>   kasan, arm64: enable top byte ignore for the kernel
>   kasan, mm: perform untagged pointers comparison in krealloc
>   kasan: split out generic_report.c from report.c
>   kasan: add bug reporting routines for tag-based mode
>   kasan: add hooks implementation for tag-based mode
>   kasan, arm64: add brk handler for inline instrumentation
>   kasan, mm, arm64: tag non slab memory allocated via pagealloc
>   kasan: update documentation
>   kasan: add SPDX-License-Identifier mark to source files
>
>  Documentation/dev-tools/kasan.rst      | 232 +++++----
>  arch/arm64/Kconfig                     |   1 +
>  arch/arm64/Makefile                    |   2 +-
>  arch/arm64/include/asm/brk-imm.h       |   2 +
>  arch/arm64/include/asm/memory.h        |  36 +-
>  arch/arm64/include/asm/pgtable-hwdef.h |   1 +
>  arch/arm64/kernel/traps.c              |  68 ++-
>  arch/arm64/mm/fault.c                  |   3 +
>  arch/arm64/mm/kasan_init.c             |  18 +-
>  arch/arm64/mm/proc.S                   |   8 +-
>  include/linux/compiler-clang.h         |   5 +-
>  include/linux/kasan.h                  |  83 +++-
>  include/linux/mm.h                     |  29 ++
>  include/linux/page-flags-layout.h      |  10 +
>  include/linux/slab_def.h               |  13 +
>  lib/Kconfig.kasan                      |  87 +++-
>  mm/cma.c                               |  11 +
>  mm/kasan/Makefile                      |  15 +-
>  mm/kasan/{kasan.c => common.c}         | 651 +++++++++----------------
>  mm/kasan/generic.c                     | 344 +++++++++++++
>  mm/kasan/generic_report.c              | 153 ++++++
>  mm/kasan/{kasan_init.c => init.c}      |   1 +
>  mm/kasan/kasan.h                       |  83 +++-
>  mm/kasan/quarantine.c                  |   1 +
>  mm/kasan/report.c                      | 272 +++--------
>  mm/kasan/tags.c                        | 161 ++++++
>  mm/kasan/tags_report.c                 |  58 +++
>  mm/page_alloc.c                        |   1 +
>  mm/slab.c                              |  29 +-
>  mm/slab.h                              |   2 +-
>  mm/slab_common.c                       |   6 +-
>  mm/slub.c                              |  41 +-
>  scripts/Makefile.kasan                 |  27 +-
>  33 files changed, 1629 insertions(+), 825 deletions(-)
>  rename mm/kasan/{kasan.c => common.c} (59%)
>  create mode 100644 mm/kasan/generic.c
>  create mode 100644 mm/kasan/generic_report.c
>  rename mm/kasan/{kasan_init.c => init.c} (99%)
>  create mode 100644 mm/kasan/tags.c
>  create mode 100644 mm/kasan/tags_report.c
>
> --
> 2.19.0.444.g18242da7ef-goog
>
Andrey Konovalov Oct. 2, 2018, 1:42 p.m. UTC | #2
On Fri, Sep 21, 2018 at 5:13 PM, Andrey Konovalov <andreyknvl@google.com> wrote:
> This patch updates KASAN documentation to reflect the addition of the new
> tag-based mode.
>
> Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
> ---
>  Documentation/dev-tools/kasan.rst | 232 ++++++++++++++++++------------
>  1 file changed, 138 insertions(+), 94 deletions(-)
>
> diff --git a/Documentation/dev-tools/kasan.rst b/Documentation/dev-tools/kasan.rst
> index aabc8738b3d8..a407e18afd32 100644
> --- a/Documentation/dev-tools/kasan.rst
> +++ b/Documentation/dev-tools/kasan.rst
> @@ -4,15 +4,25 @@ The Kernel Address Sanitizer (KASAN)
>  Overview
>  --------
>
> -KernelAddressSANitizer (KASAN) is a dynamic memory error detector. It provides
> -a fast and comprehensive solution for finding use-after-free and out-of-bounds
> -bugs.
> +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).
>
> -KASAN uses compile-time instrumentation for checking every memory access,
> -therefore you will need a GCC version 4.9.2 or later. GCC 5.0 or later is
> -required for detection of out-of-bounds accesses to stack or global variables.
> +KASAN uses compile-time instrumentation to insert validity checks before every
> +memory access, and therefore requires a compiler version that supports that.
>
> -Currently KASAN is supported only for the x86_64 and arm64 architectures.
> +Generic KASAN is supported in both GCC and Clang. With GCC it requires version
> +4.9.2 or later for basic support and version 5.0 or later for detection of
> +out-of-bounds accesses for stack and global variables and for inline
> +instrumentation mode (see the Usage section). With Clang it requires version
> +3.7.0 or later and it doesn't support detection of out-of-bounds accesses for

Note: this should actually be 7.0.0 and not 3.7.0 (as we need rL329612).

> +global variables yet.
> +
> +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 and xtensa
> +architectures, and tag-based KASAN is supported only for arm64.
>
>  Usage
>  -----
> @@ -21,12 +31,14 @@ To enable KASAN configure kernel with::
>
>           CONFIG_KASAN = y
>
> -and choose between CONFIG_KASAN_OUTLINE and CONFIG_KASAN_INLINE. Outline and
> -inline are compiler instrumentation types. The former produces smaller binary
> -the latter is 1.1 - 2 times faster. Inline instrumentation requires a GCC
> -version 5.0 or later.
> +and choose between CONFIG_KASAN_GENERIC (to enable generic KASAN) and
> +CONFIG_KASAN_SW_TAGS (to enable software tag-based KASAN).
>
> -KASAN works with both SLUB and SLAB memory allocators.
> +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.
>  For better bug detection and nicer reporting, enable CONFIG_STACKTRACE.
>
>  To disable instrumentation for specific files or directories, add a line
> @@ -43,85 +55,85 @@ similar to the following to the respective kernel Makefile:
>  Error reports
>  ~~~~~~~~~~~~~
>
> -A typical out of bounds access report looks like this::
> +A typical out-of-bounds access generic KASAN report looks like this::
>
>      ==================================================================
> -    BUG: AddressSanitizer: out of bounds access in kmalloc_oob_right+0x65/0x75 [test_kasan] at addr ffff8800693bc5d3
> -    Write of size 1 by task modprobe/1689
> -    =============================================================================
> -    BUG kmalloc-128 (Not tainted): kasan error
> -    -----------------------------------------------------------------------------
> -
> -    Disabling lock debugging due to kernel taint
> -    INFO: Allocated in kmalloc_oob_right+0x3d/0x75 [test_kasan] age=0 cpu=0 pid=1689
> -     __slab_alloc+0x4b4/0x4f0
> -     kmem_cache_alloc_trace+0x10b/0x190
> -     kmalloc_oob_right+0x3d/0x75 [test_kasan]
> -     init_module+0x9/0x47 [test_kasan]
> -     do_one_initcall+0x99/0x200
> -     load_module+0x2cb3/0x3b20
> -     SyS_finit_module+0x76/0x80
> -     system_call_fastpath+0x12/0x17
> -    INFO: Slab 0xffffea0001a4ef00 objects=17 used=7 fp=0xffff8800693bd728 flags=0x100000000004080
> -    INFO: Object 0xffff8800693bc558 @offset=1368 fp=0xffff8800693bc720
> -
> -    Bytes b4 ffff8800693bc548: 00 00 00 00 00 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a  ........ZZZZZZZZ
> -    Object ffff8800693bc558: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
> -    Object ffff8800693bc568: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
> -    Object ffff8800693bc578: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
> -    Object ffff8800693bc588: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
> -    Object ffff8800693bc598: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
> -    Object ffff8800693bc5a8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
> -    Object ffff8800693bc5b8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
> -    Object ffff8800693bc5c8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5  kkkkkkkkkkkkkkk.
> -    Redzone ffff8800693bc5d8: cc cc cc cc cc cc cc cc                          ........
> -    Padding ffff8800693bc718: 5a 5a 5a 5a 5a 5a 5a 5a                          ZZZZZZZZ
> -    CPU: 0 PID: 1689 Comm: modprobe Tainted: G    B          3.18.0-rc1-mm1+ #98
> -    Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014
> -     ffff8800693bc000 0000000000000000 ffff8800693bc558 ffff88006923bb78
> -     ffffffff81cc68ae 00000000000000f3 ffff88006d407600 ffff88006923bba8
> -     ffffffff811fd848 ffff88006d407600 ffffea0001a4ef00 ffff8800693bc558
> +    BUG: KASAN: slab-out-of-bounds in kmalloc_oob_right+0xa8/0xbc [test_kasan]
> +    Write of size 1 at addr ffff8801f44ec37b by task insmod/2760
> +
> +    CPU: 1 PID: 2760 Comm: insmod Not tainted 4.19.0-rc3+ #698
> +    Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014
>      Call Trace:
> -     [<ffffffff81cc68ae>] dump_stack+0x46/0x58
> -     [<ffffffff811fd848>] print_trailer+0xf8/0x160
> -     [<ffffffffa00026a7>] ? kmem_cache_oob+0xc3/0xc3 [test_kasan]
> -     [<ffffffff811ff0f5>] object_err+0x35/0x40
> -     [<ffffffffa0002065>] ? kmalloc_oob_right+0x65/0x75 [test_kasan]
> -     [<ffffffff8120b9fa>] kasan_report_error+0x38a/0x3f0
> -     [<ffffffff8120a79f>] ? kasan_poison_shadow+0x2f/0x40
> -     [<ffffffff8120b344>] ? kasan_unpoison_shadow+0x14/0x40
> -     [<ffffffff8120a79f>] ? kasan_poison_shadow+0x2f/0x40
> -     [<ffffffffa00026a7>] ? kmem_cache_oob+0xc3/0xc3 [test_kasan]
> -     [<ffffffff8120a995>] __asan_store1+0x75/0xb0
> -     [<ffffffffa0002601>] ? kmem_cache_oob+0x1d/0xc3 [test_kasan]
> -     [<ffffffffa0002065>] ? kmalloc_oob_right+0x65/0x75 [test_kasan]
> -     [<ffffffffa0002065>] kmalloc_oob_right+0x65/0x75 [test_kasan]
> -     [<ffffffffa00026b0>] init_module+0x9/0x47 [test_kasan]
> -     [<ffffffff810002d9>] do_one_initcall+0x99/0x200
> -     [<ffffffff811e4e5c>] ? __vunmap+0xec/0x160
> -     [<ffffffff81114f63>] load_module+0x2cb3/0x3b20
> -     [<ffffffff8110fd70>] ? m_show+0x240/0x240
> -     [<ffffffff81115f06>] SyS_finit_module+0x76/0x80
> -     [<ffffffff81cd3129>] system_call_fastpath+0x12/0x17
> +     dump_stack+0x94/0xd8
> +     print_address_description+0x73/0x280
> +     kasan_report+0x144/0x187
> +     __asan_report_store1_noabort+0x17/0x20
> +     kmalloc_oob_right+0xa8/0xbc [test_kasan]
> +     kmalloc_tests_init+0x16/0x700 [test_kasan]
> +     do_one_initcall+0xa5/0x3ae
> +     do_init_module+0x1b6/0x547
> +     load_module+0x75df/0x8070
> +     __do_sys_init_module+0x1c6/0x200
> +     __x64_sys_init_module+0x6e/0xb0
> +     do_syscall_64+0x9f/0x2c0
> +     entry_SYSCALL_64_after_hwframe+0x44/0xa9
> +    RIP: 0033:0x7f96443109da
> +    RSP: 002b:00007ffcf0b51b08 EFLAGS: 00000202 ORIG_RAX: 00000000000000af
> +    RAX: ffffffffffffffda RBX: 000055dc3ee521a0 RCX: 00007f96443109da
> +    RDX: 00007f96445cff88 RSI: 0000000000057a50 RDI: 00007f9644992000
> +    RBP: 000055dc3ee510b0 R08: 0000000000000003 R09: 0000000000000000
> +    R10: 00007f964430cd0a R11: 0000000000000202 R12: 00007f96445cff88
> +    R13: 000055dc3ee51090 R14: 0000000000000000 R15: 0000000000000000
> +
> +    Allocated by task 2760:
> +     save_stack+0x43/0xd0
> +     kasan_kmalloc+0xa7/0xd0
> +     kmem_cache_alloc_trace+0xe1/0x1b0
> +     kmalloc_oob_right+0x56/0xbc [test_kasan]
> +     kmalloc_tests_init+0x16/0x700 [test_kasan]
> +     do_one_initcall+0xa5/0x3ae
> +     do_init_module+0x1b6/0x547
> +     load_module+0x75df/0x8070
> +     __do_sys_init_module+0x1c6/0x200
> +     __x64_sys_init_module+0x6e/0xb0
> +     do_syscall_64+0x9f/0x2c0
> +     entry_SYSCALL_64_after_hwframe+0x44/0xa9
> +
> +    Freed by task 815:
> +     save_stack+0x43/0xd0
> +     __kasan_slab_free+0x135/0x190
> +     kasan_slab_free+0xe/0x10
> +     kfree+0x93/0x1a0
> +     umh_complete+0x6a/0xa0
> +     call_usermodehelper_exec_async+0x4c3/0x640
> +     ret_from_fork+0x35/0x40
> +
> +    The buggy address belongs to the object at ffff8801f44ec300
> +     which belongs to the cache kmalloc-128 of size 128
> +    The buggy address is located 123 bytes inside of
> +     128-byte region [ffff8801f44ec300, ffff8801f44ec380)
> +    The buggy address belongs to the page:
> +    page:ffffea0007d13b00 count:1 mapcount:0 mapping:ffff8801f7001640 index:0x0
> +    flags: 0x200000000000100(slab)
> +    raw: 0200000000000100 ffffea0007d11dc0 0000001a0000001a ffff8801f7001640
> +    raw: 0000000000000000 0000000080150015 00000001ffffffff 0000000000000000
> +    page dumped because: kasan: bad access detected
> +
>      Memory state around the buggy address:
> -     ffff8800693bc300: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
> -     ffff8800693bc380: fc fc 00 00 00 00 00 00 00 00 00 00 00 00 00 fc
> -     ffff8800693bc400: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
> -     ffff8800693bc480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
> -     ffff8800693bc500: fc fc fc fc fc fc fc fc fc fc fc 00 00 00 00 00
> -    >ffff8800693bc580: 00 00 00 00 00 00 00 00 00 00 03 fc fc fc fc fc
> -                                                 ^
> -     ffff8800693bc600: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
> -     ffff8800693bc680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
> -     ffff8800693bc700: fc fc fc fc fb fb fb fb fb fb fb fb fb fb fb fb
> -     ffff8800693bc780: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> -     ffff8800693bc800: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> +     ffff8801f44ec200: fc fc fc fc fc fc fc fc fb fb fb fb fb fb fb fb
> +     ffff8801f44ec280: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
> +    >ffff8801f44ec300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03
> +                                                                    ^
> +     ffff8801f44ec380: fc fc fc fc fc fc fc fc fb fb fb fb fb fb fb fb
> +     ffff8801f44ec400: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
>      ==================================================================
>
> -The header of the report discribe what kind of bug happened and what kind of
> -access caused it. It's followed by the description of the accessed slub object
> -(see 'SLUB Debug output' section in Documentation/vm/slub.rst for details) and
> -the description of the accessed memory page.
> +The header of the report provides a short summary of what kind of bug happened
> +and what kind of access caused it. It's followed by a stack trace of the bad
> +access, a stack trace of where the accessed memory was allocated (in case bad
> +access happens on a slab object), and a stack trace of where the object was
> +freed (in case of a use-after-free bug report). Next comes a description of
> +the accessed slab object and information about the accessed memory page.
>
>  In the last section the report shows memory state around the accessed address.
>  Reading this part requires some understanding of how KASAN works.
> @@ -138,18 +150,24 @@ inaccessible memory like redzones or freed memory (see mm/kasan/kasan.h).
>  In the report above the arrows point to the shadow byte 03, which means that
>  the accessed address is partially accessible.
>
> +For tag-based KASAN this last report section shows the memory tags around the
> +accessed address (see Implementation details section).
> +
>
>  Implementation details
>  ----------------------
>
> +Generic KASAN
> +~~~~~~~~~~~~~
> +
>  From a high level, our approach to memory error detection is similar to that
>  of kmemcheck: use shadow memory to record whether each byte of memory is safe
> -to access, and use compile-time instrumentation to check shadow memory on each
> -memory access.
> +to access, and use compile-time instrumentation to insert checks of shadow
> +memory on each memory access.
>
> -AddressSanitizer dedicates 1/8 of kernel memory to its shadow memory
> -(e.g. 16TB to cover 128TB on x86_64) and uses direct mapping with a scale and
> -offset to translate a memory address to its corresponding shadow address.
> +Generic KASAN dedicates 1/8th of kernel memory to its shadow memory (e.g. 16TB
> +to cover 128TB on x86_64) and uses direct mapping with a scale and offset to
> +translate a memory address to its corresponding shadow address.
>
>  Here is the function which translates an address to its corresponding shadow
>  address::
> @@ -162,12 +180,38 @@ address::
>
>  where ``KASAN_SHADOW_SCALE_SHIFT = 3``.
>
> -Compile-time instrumentation used for checking memory accesses. Compiler inserts
> -function calls (__asan_load*(addr), __asan_store*(addr)) before each memory
> -access of size 1, 2, 4, 8 or 16. These functions check whether memory access is
> -valid or not by checking corresponding shadow memory.
> +Compile-time instrumentation is used to insert memory access checks. Compiler
> +inserts function calls (__asan_load*(addr), __asan_store*(addr)) before each
> +memory access of size 1, 2, 4, 8 or 16. These functions check whether memory
> +access is valid or not by checking corresponding shadow memory.
>
>  GCC 5.0 has possibility to perform inline instrumentation. Instead of making
>  function calls GCC directly inserts the code to check the shadow memory.
>  This option significantly enlarges kernel but it gives x1.1-x2 performance
>  boost over outline instrumented kernel.
> +
> +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
> +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.
> +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.
> +
> +Software tag-based KASAN also has two instrumentation modes (outline, that
> +emits callbacks to check memory accesses; and inline, that performs the shadow
> +memory checks inline). With outline instrumentation mode, a bug report is
> +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.
> --
> 2.19.0.444.g18242da7ef-goog
>
Andrey Ryabinin Oct. 31, 2018, 4:33 p.m. UTC | #3
On 09/21/2018 06:13 PM, Andrey Konovalov wrote:
> Tag-based KASAN changes the value of the top byte of pointers returned
> from the kernel allocation functions (such as kmalloc). This patch updates
> KASAN hooks signatures and their usage in SLAB and SLUB code to reflect
> that.
> 
> Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
> ---
>  include/linux/kasan.h | 43 +++++++++++++++++++++++++++++--------------
>  mm/kasan/kasan.c      | 30 ++++++++++++++++++------------
>  mm/slab.c             | 12 ++++++------
>  mm/slab.h             |  2 +-
>  mm/slab_common.c      |  4 ++--
>  mm/slub.c             | 15 +++++++--------
>  6 files changed, 63 insertions(+), 43 deletions(-)
> 
> diff --git a/include/linux/kasan.h b/include/linux/kasan.h
> index 46aae129917c..52c86a568a4e 100644
> --- a/include/linux/kasan.h
> +++ b/include/linux/kasan.h
> @@ -51,16 +51,16 @@ void kasan_cache_shutdown(struct kmem_cache *cache);
>  void kasan_poison_slab(struct page *page);
>  void kasan_unpoison_object_data(struct kmem_cache *cache, void *object);
>  void kasan_poison_object_data(struct kmem_cache *cache, void *object);
> -void kasan_init_slab_obj(struct kmem_cache *cache, const void *object);
> +void *kasan_init_slab_obj(struct kmem_cache *cache, const void *object);
>  
> -void kasan_kmalloc_large(const void *ptr, size_t size, gfp_t flags);
> +void *kasan_kmalloc_large(const void *ptr, size_t size, gfp_t flags);
>  void kasan_kfree_large(void *ptr, unsigned long ip);
>  void kasan_poison_kfree(void *ptr, unsigned long ip);
> -void kasan_kmalloc(struct kmem_cache *s, const void *object, size_t size,
> +void *kasan_kmalloc(struct kmem_cache *s, const void *object, size_t size,
>  		  gfp_t flags);

This patch missed couple call-sites, in kmem_cache_alloc_trace() and kmem_cache_alloc_node_trace() in include/linux/slab.h,
the return value of kasan_kmalloc() is ignored. Probably worth adding __must_check to functions like this.

Once that fixed you can add Reviewed-by: Andrey Ryabinin <aryabinin@virtuozzo.com>
here and to the rest of the patches. They look fine me.