mbox series

[RFC,0/7] kasan: RISC-V support for KASAN_SW_TAGS using pointer masking

Message ID 20240814085618.968833-1-samuel.holland@sifive.com (mailing list archive)
Headers show
Series kasan: RISC-V support for KASAN_SW_TAGS using pointer masking | expand

Message

Samuel Holland Aug. 14, 2024, 8:55 a.m. UTC
This series implements support for software tag-based KASAN using the
RISC-V pointer masking extension[1], which supports 7 and/or 16-bit
tags. This implementation uses 7-bit tags, so it is compatible with
either hardware mode. Patch 3 adds supports for KASAN_SW_TAGS with tag
widths other than 8 bits.

Pointer masking is an optional ISA extension, and it must be enabled
using an SBI call to firmware on each CPU. If the SBI call fails on the
boot CPU, KASAN is globally disabled. Patch 2 adds support for boot-time
disabling of KASAN_SW_TAGS.

The SBI call is part of the upcoming SBI Firmware Features (FWFT)
extension[2][3]. Since generic FWFT support is not yet merged to Linux,
I open-coded the sbi_ecall() in this RFC to keep this series focused.

With my RISC-V KASAN fixes series[4] applied, this implementation passes
all but one of the KASAN KUnit tests. It fails vmalloc_percpu(), which
also fails on arm64:

      ...
      ok 65 vmalloc_oob
      ok 66 vmap_tags
      ok 67 vm_map_ram_tags
      # vmalloc_percpu: EXPECTATION FAILED at mm/kasan/kasan_test.c:1785
      Expected (u8)((u8)((u64)(c_ptr) >> 57)) < (u8)0x7f, but
          (u8)((u8)((u64)(c_ptr) >> 57)) == 127 (0x7f)
          (u8)0x7f == 127 (0x7f)
      # vmalloc_percpu: EXPECTATION FAILED at mm/kasan/kasan_test.c:1785
      Expected (u8)((u8)((u64)(c_ptr) >> 57)) < (u8)0x7f, but
          (u8)((u8)((u64)(c_ptr) >> 57)) == 127 (0x7f)
          (u8)0x7f == 127 (0x7f)
      # vmalloc_percpu: EXPECTATION FAILED at mm/kasan/kasan_test.c:1785
      Expected (u8)((u8)((u64)(c_ptr) >> 57)) < (u8)0x7f, but
          (u8)((u8)((u64)(c_ptr) >> 57)) == 127 (0x7f)
          (u8)0x7f == 127 (0x7f)
      # vmalloc_percpu: EXPECTATION FAILED at mm/kasan/kasan_test.c:1785
      Expected (u8)((u8)((u64)(c_ptr) >> 57)) < (u8)0x7f, but
          (u8)((u8)((u64)(c_ptr) >> 57)) == 127 (0x7f)
          (u8)0x7f == 127 (0x7f)
      not ok 68 vmalloc_percpu
      ok 69 match_all_not_assigned
      ok 70 match_all_ptr_tag
      ...
  # kasan: pass:62 fail:1 skip:8 total:71
  # Totals: pass:62 fail:1 skip:8 total:71

I'm not sure how I'm supposed to hook in to the percpu allocator.

When running with hardware or firmware that doesn't support pointer
masking, the kernel still boots successfully:

  kasan: test: Can't run KASAN tests with KASAN disabled
      # kasan:     # failed to initialize (-1)
  not ok 1 kasan

If stack tagging is enabled but pointer masking is unsupported, an extra
change (patch 7) is required so all pointers to stack variables are
tagged with KASAN_TAG_KERENL and can be dereferenced. I'm not sure if
this change should be RISC-V specific or made more generic.

This series can be tested by applying patch series to LLVM[5], QEMU[6],
and OpenSBI[7].

[1]: https://github.com/riscv/riscv-j-extension/releases/download/pointer-masking-v1.0.0-rc2/pointer-masking-v1.0.0-rc2.pdf
[2]: https://github.com/riscv-non-isa/riscv-sbi-doc/blob/master/src/ext-firmware-features.adoc
[3]: https://github.com/riscv-non-isa/riscv-sbi-doc/pull/161
[4]: https://lore.kernel.org/linux-riscv/20240801033725.28816-1-samuel.holland@sifive.com/
[5]: https://github.com/SiFiveHolland/llvm-project/commits/up/riscv64-kernel-hwasan
[6]: https://lore.kernel.org/qemu-devel/20240511101053.1875596-1-me@deliversmonkey.space/
[7]: https://lists.infradead.org/pipermail/opensbi/2024-August/007244.html


Samuel Holland (7):
  kasan: sw_tags: Use arithmetic shift for shadow computation
  kasan: sw_tags: Check kasan_flag_enabled at runtime
  kasan: sw_tags: Support tag widths less than 8 bits
  riscv: Do not rely on KASAN to define the memory layout
  riscv: Align the sv39 linear map to 16 GiB
  riscv: Implement KASAN_SW_TAGS
  kasan: sw_tags: Support runtime stack tagging control for RISC-V

 Documentation/arch/riscv/vm-layout.rst | 10 ++---
 Documentation/dev-tools/kasan.rst      | 14 +++---
 arch/arm64/Kconfig                     | 10 ++---
 arch/arm64/include/asm/kasan.h         |  6 ++-
 arch/arm64/include/asm/memory.h        |  8 ++++
 arch/arm64/include/asm/uaccess.h       |  1 +
 arch/arm64/mm/kasan_init.c             |  7 ++-
 arch/riscv/Kconfig                     |  4 +-
 arch/riscv/include/asm/cache.h         |  4 ++
 arch/riscv/include/asm/kasan.h         | 29 +++++++++++-
 arch/riscv/include/asm/page.h          | 21 +++++++--
 arch/riscv/include/asm/pgtable.h       |  6 +++
 arch/riscv/include/asm/tlbflush.h      |  4 +-
 arch/riscv/kernel/setup.c              |  6 +++
 arch/riscv/kernel/smpboot.c            |  8 +++-
 arch/riscv/lib/Makefile                |  2 +
 arch/riscv/lib/kasan_sw_tags.S         | 61 ++++++++++++++++++++++++++
 arch/riscv/mm/init.c                   |  2 +-
 arch/riscv/mm/kasan_init.c             | 30 ++++++++++++-
 arch/riscv/mm/physaddr.c               |  4 ++
 include/linux/kasan-enabled.h          | 15 +++----
 include/linux/kasan-tags.h             | 13 +++---
 include/linux/kasan.h                  | 10 ++++-
 mm/kasan/hw_tags.c                     | 10 -----
 mm/kasan/kasan.h                       |  2 +
 mm/kasan/sw_tags.c                     |  9 ++++
 mm/kasan/tags.c                        | 10 +++++
 scripts/Makefile.kasan                 |  5 +++
 scripts/gdb/linux/mm.py                |  5 ++-
 29 files changed, 255 insertions(+), 61 deletions(-)
 create mode 100644 arch/riscv/lib/kasan_sw_tags.S

Comments

Andrey Konovalov Aug. 14, 2024, 4:03 p.m. UTC | #1
On Wed, Aug 14, 2024 at 10:56 AM Samuel Holland
<samuel.holland@sifive.com> wrote:
>
> This series implements support for software tag-based KASAN using the
> RISC-V pointer masking extension[1], which supports 7 and/or 16-bit
> tags. This implementation uses 7-bit tags, so it is compatible with
> either hardware mode. Patch 3 adds supports for KASAN_SW_TAGS with tag
> widths other than 8 bits.

This is awesome!

> Pointer masking is an optional ISA extension, and it must be enabled
> using an SBI call to firmware on each CPU. If the SBI call fails on the
> boot CPU, KASAN is globally disabled. Patch 2 adds support for boot-time
> disabling of KASAN_SW_TAGS.
>
> The SBI call is part of the upcoming SBI Firmware Features (FWFT)
> extension[2][3]. Since generic FWFT support is not yet merged to Linux,
> I open-coded the sbi_ecall() in this RFC to keep this series focused.
>
> With my RISC-V KASAN fixes series[4] applied, this implementation passes
> all but one of the KASAN KUnit tests. It fails vmalloc_percpu(), which
> also fails on arm64:

Hm, this test passes on arm64 for me. Could you share the kernel
config that you used?


>
>       ...
>       ok 65 vmalloc_oob
>       ok 66 vmap_tags
>       ok 67 vm_map_ram_tags
>       # vmalloc_percpu: EXPECTATION FAILED at mm/kasan/kasan_test.c:1785
>       Expected (u8)((u8)((u64)(c_ptr) >> 57)) < (u8)0x7f, but
>           (u8)((u8)((u64)(c_ptr) >> 57)) == 127 (0x7f)
>           (u8)0x7f == 127 (0x7f)
>       # vmalloc_percpu: EXPECTATION FAILED at mm/kasan/kasan_test.c:1785
>       Expected (u8)((u8)((u64)(c_ptr) >> 57)) < (u8)0x7f, but
>           (u8)((u8)((u64)(c_ptr) >> 57)) == 127 (0x7f)
>           (u8)0x7f == 127 (0x7f)
>       # vmalloc_percpu: EXPECTATION FAILED at mm/kasan/kasan_test.c:1785
>       Expected (u8)((u8)((u64)(c_ptr) >> 57)) < (u8)0x7f, but
>           (u8)((u8)((u64)(c_ptr) >> 57)) == 127 (0x7f)
>           (u8)0x7f == 127 (0x7f)
>       # vmalloc_percpu: EXPECTATION FAILED at mm/kasan/kasan_test.c:1785
>       Expected (u8)((u8)((u64)(c_ptr) >> 57)) < (u8)0x7f, but
>           (u8)((u8)((u64)(c_ptr) >> 57)) == 127 (0x7f)
>           (u8)0x7f == 127 (0x7f)
>       not ok 68 vmalloc_percpu
>       ok 69 match_all_not_assigned
>       ok 70 match_all_ptr_tag
>       ...
>   # kasan: pass:62 fail:1 skip:8 total:71
>   # Totals: pass:62 fail:1 skip:8 total:71
>
> I'm not sure how I'm supposed to hook in to the percpu allocator.
>
> When running with hardware or firmware that doesn't support pointer
> masking, the kernel still boots successfully:
>
>   kasan: test: Can't run KASAN tests with KASAN disabled
>       # kasan:     # failed to initialize (-1)
>   not ok 1 kasan
>
> If stack tagging is enabled but pointer masking is unsupported, an extra
> change (patch 7) is required so all pointers to stack variables are
> tagged with KASAN_TAG_KERENL and can be dereferenced. I'm not sure if
> this change should be RISC-V specific or made more generic.
>
> This series can be tested by applying patch series to LLVM[5], QEMU[6],
> and OpenSBI[7].
>
> [1]: https://github.com/riscv/riscv-j-extension/releases/download/pointer-masking-v1.0.0-rc2/pointer-masking-v1.0.0-rc2.pdf
> [2]: https://github.com/riscv-non-isa/riscv-sbi-doc/blob/master/src/ext-firmware-features.adoc
> [3]: https://github.com/riscv-non-isa/riscv-sbi-doc/pull/161
> [4]: https://lore.kernel.org/linux-riscv/20240801033725.28816-1-samuel.holland@sifive.com/
> [5]: https://github.com/SiFiveHolland/llvm-project/commits/up/riscv64-kernel-hwasan
> [6]: https://lore.kernel.org/qemu-devel/20240511101053.1875596-1-me@deliversmonkey.space/
> [7]: https://lists.infradead.org/pipermail/opensbi/2024-August/007244.html
>
>
> Samuel Holland (7):
>   kasan: sw_tags: Use arithmetic shift for shadow computation
>   kasan: sw_tags: Check kasan_flag_enabled at runtime
>   kasan: sw_tags: Support tag widths less than 8 bits
>   riscv: Do not rely on KASAN to define the memory layout
>   riscv: Align the sv39 linear map to 16 GiB
>   riscv: Implement KASAN_SW_TAGS
>   kasan: sw_tags: Support runtime stack tagging control for RISC-V
>
>  Documentation/arch/riscv/vm-layout.rst | 10 ++---
>  Documentation/dev-tools/kasan.rst      | 14 +++---
>  arch/arm64/Kconfig                     | 10 ++---
>  arch/arm64/include/asm/kasan.h         |  6 ++-
>  arch/arm64/include/asm/memory.h        |  8 ++++
>  arch/arm64/include/asm/uaccess.h       |  1 +
>  arch/arm64/mm/kasan_init.c             |  7 ++-
>  arch/riscv/Kconfig                     |  4 +-
>  arch/riscv/include/asm/cache.h         |  4 ++
>  arch/riscv/include/asm/kasan.h         | 29 +++++++++++-
>  arch/riscv/include/asm/page.h          | 21 +++++++--
>  arch/riscv/include/asm/pgtable.h       |  6 +++
>  arch/riscv/include/asm/tlbflush.h      |  4 +-
>  arch/riscv/kernel/setup.c              |  6 +++
>  arch/riscv/kernel/smpboot.c            |  8 +++-
>  arch/riscv/lib/Makefile                |  2 +
>  arch/riscv/lib/kasan_sw_tags.S         | 61 ++++++++++++++++++++++++++
>  arch/riscv/mm/init.c                   |  2 +-
>  arch/riscv/mm/kasan_init.c             | 30 ++++++++++++-
>  arch/riscv/mm/physaddr.c               |  4 ++
>  include/linux/kasan-enabled.h          | 15 +++----
>  include/linux/kasan-tags.h             | 13 +++---
>  include/linux/kasan.h                  | 10 ++++-
>  mm/kasan/hw_tags.c                     | 10 -----
>  mm/kasan/kasan.h                       |  2 +
>  mm/kasan/sw_tags.c                     |  9 ++++
>  mm/kasan/tags.c                        | 10 +++++
>  scripts/Makefile.kasan                 |  5 +++
>  scripts/gdb/linux/mm.py                |  5 ++-
>  29 files changed, 255 insertions(+), 61 deletions(-)
>  create mode 100644 arch/riscv/lib/kasan_sw_tags.S
>
> --
> 2.45.1
>