mbox series

[v4,0/8] CFI for ARM32 using LLVM

Message ID 20240328-arm32-cfi-v4-0-a11046139125@linaro.org (mailing list archive)
Headers show
Series CFI for ARM32 using LLVM | expand

Message

Linus Walleij March 28, 2024, 8:19 a.m. UTC
This is a first patch set to support CLANG CFI (Control Flow
Integrity) on ARM32.

For information about what CFI is, see:
https://clang.llvm.org/docs/ControlFlowIntegrity.html

For the kernel KCFI flavor, see:
https://lwn.net/Articles/898040/

The base changes required to bring up KCFI on ARM32 was mostly
related to the use of custom vtables in the kernel, combined
with defines to call into these vtable members directly from
sites where they are used.

We annotate all assembly calls that are called directly from
C with SYM_TYPED_FUNC_START()/SYM_FUNC_END() so it is easy
to see while reading the assembly that these functions are
called from C and can have CFI prototype information prefixed
to them.

As protype prefix information is just some random bytes, it is
not possible to "fall through" into an assembly function that
is tagged with SYM_TYPED_FUNC_START(): there will be some
binary noise in front of the function so this design pattern
needs to be explicitly avoided at each site where it occurred.

The approach to binding the calls to C is two-fold:

- Either convert the affected vtable struct to C and provide
  per-CPU prototypes for all the calls (done for TLB, cache)
  or:

- Provide prototypes in a special files just for CFI and tag
  all these functions addressable.

The permissive mode handles the new breakpoint type (0x03) that
LLVM CLANG is emitting.

To runtime-test the patches:
- Enable CONFIG_LKDTM
- echo CFI_FORWARD_PROTO > /sys/kernel/debug/provoke-crash/DIRECT

The patch set has been booted to userspace on the following
test platforms:

- Arm Versatile (QEMU)
- Arm Versatile Express (QEMU)
- multi_v7 booted on Versatile Express (QEMU)
- Footbridge Netwinder (SA110 ARMv4)
- Ux500 (ARMv7 SMP)
- Gemini (FA526)

I am not saying there will not be corner cases that we need
to fix in addition to this, but it is enough to get started.
Looking at what was fixed for arm64 I am a bit weary that
e.g. BPF might need something to trampoline properly.

But hopefullt people can get to testing it and help me fix
remaining issues before the final version, or we can fix it
in-tree.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
Changes in v4:
- Rebase on v6.9-rc1
- Use Ard's patch for converting TLB operation vtables to C
- Rewrite the cache vtables in C and use SYM_SYM_TYPED_FUNC in the
  assembly to make CFI work all the way down.
- Instead of tagging all the delay functions as __nocfi get to the
  root cause and annotate the loop delay code with SYM_TYPED_FUNC_START()
  and rewrite it using explicit branches so we get CFI all the way
  down.
- Drop the patch turning highmem page accesses into static inlines:
  this was probably a development artifact since this code does
  a lot of cache and TLB flusing, and that assembly is now properly
  annotated.
- Do not define static inlines tagged __nocfi for all the proc functions,
  instead provide proper C prototypes in a separate CFI-only file
  and make these explicitly addressable.
- Link to v3: https://lore.kernel.org/r/20240311-arm32-cfi-v3-0-224a0f0a45c2@linaro.org

Changes in v3:
- Use report_cfi_failure() like everyone else in the breakpoint
  handler.
- I think we cannot implement target and type for the report callback
  without operand bundling compiler extensions, so just leaving these as zero.
- Link to v2: https://lore.kernel.org/r/20240307-arm32-cfi-v2-0-cc74ea0306b3@linaro.org

Changes in v2:
- Add the missing ftrace graph tracer stub.
- Enable permissive mode using a breakpoint handler.
- Link to v1: https://lore.kernel.org/r/20240225-arm32-cfi-v1-0-6943306f065b@linaro.org

---
Ard Biesheuvel (1):
      ARM: mm: Make tlbflush routines CFI safe

Linus Walleij (7):
      ARM: bugs: Check in the vtable instead of defined aliases
      ARM: ftrace: Define ftrace_stub_graph
      ARM: mm: Rewrite cacheflush vtables in CFI safe C
      ARM: mm: Define prototypes for all per-processor calls
      ARM: lib: Annotate loop delay instructions for CFI
      ARM: hw_breakpoint: Handle CFI breakpoints
      ARM: Support CLANG CFI

 arch/arm/Kconfig                     |   1 +
 arch/arm/include/asm/glue-cache.h    |  28 +-
 arch/arm/include/asm/hw_breakpoint.h |   1 +
 arch/arm/kernel/bugs.c               |   2 +-
 arch/arm/kernel/entry-ftrace.S       |   4 +
 arch/arm/kernel/hw_breakpoint.c      |  30 ++
 arch/arm/lib/delay-loop.S            |  16 +-
 arch/arm/mm/Makefile                 |   3 +
 arch/arm/mm/cache-b15-rac.c          |   1 +
 arch/arm/mm/cache-fa.S               |  47 +--
 arch/arm/mm/cache-nop.S              |  57 +--
 arch/arm/mm/cache-v4.S               |  55 +--
 arch/arm/mm/cache-v4wb.S             |  47 ++-
 arch/arm/mm/cache-v4wt.S             |  55 +--
 arch/arm/mm/cache-v6.S               |  49 ++-
 arch/arm/mm/cache-v7.S               |  74 ++--
 arch/arm/mm/cache-v7m.S              |  53 ++-
 arch/arm/mm/cache.c                  | 663 +++++++++++++++++++++++++++++++++++
 arch/arm/mm/proc-arm1020.S           |  69 ++--
 arch/arm/mm/proc-arm1020e.S          |  70 ++--
 arch/arm/mm/proc-arm1022.S           |  69 ++--
 arch/arm/mm/proc-arm1026.S           |  70 ++--
 arch/arm/mm/proc-arm720.S            |  25 +-
 arch/arm/mm/proc-arm740.S            |  26 +-
 arch/arm/mm/proc-arm7tdmi.S          |  34 +-
 arch/arm/mm/proc-arm920.S            |  76 ++--
 arch/arm/mm/proc-arm922.S            |  69 ++--
 arch/arm/mm/proc-arm925.S            |  66 ++--
 arch/arm/mm/proc-arm926.S            |  75 ++--
 arch/arm/mm/proc-arm940.S            |  69 ++--
 arch/arm/mm/proc-arm946.S            |  65 ++--
 arch/arm/mm/proc-arm9tdmi.S          |  26 +-
 arch/arm/mm/proc-fa526.S             |  24 +-
 arch/arm/mm/proc-feroceon.S          | 105 +++---
 arch/arm/mm/proc-macros.S            |  33 --
 arch/arm/mm/proc-mohawk.S            |  74 ++--
 arch/arm/mm/proc-sa110.S             |  23 +-
 arch/arm/mm/proc-sa1100.S            |  31 +-
 arch/arm/mm/proc-v6.S                |  31 +-
 arch/arm/mm/proc-v7-2level.S         |   8 +-
 arch/arm/mm/proc-v7-3level.S         |   8 +-
 arch/arm/mm/proc-v7-bugs.c           |   4 +-
 arch/arm/mm/proc-v7.S                |  66 ++--
 arch/arm/mm/proc-v7m.S               |  41 +--
 arch/arm/mm/proc-xsc3.S              |  75 ++--
 arch/arm/mm/proc-xscale.S            | 127 +++----
 arch/arm/mm/proc.c                   | 500 ++++++++++++++++++++++++++
 arch/arm/mm/tlb-fa.S                 |  12 +-
 arch/arm/mm/tlb-v4.S                 |  15 +-
 arch/arm/mm/tlb-v4wb.S               |  12 +-
 arch/arm/mm/tlb-v4wbi.S              |  12 +-
 arch/arm/mm/tlb-v6.S                 |  12 +-
 arch/arm/mm/tlb-v7.S                 |  14 +-
 arch/arm/mm/tlb.c                    |  84 +++++
 54 files changed, 2334 insertions(+), 972 deletions(-)
---
base-commit: 4cece764965020c22cff7665b18a012006359095
change-id: 20240115-arm32-cfi-65d60f201108

Best regards,

Comments

Kees Cook April 4, 2024, 9:27 p.m. UTC | #1
On Thu, Mar 28, 2024 at 09:19:23AM +0100, Linus Walleij wrote:
> This is a first patch set to support CLANG CFI (Control Flow
> Integrity) on ARM32.
> 
> For information about what CFI is, see:
> https://clang.llvm.org/docs/ControlFlowIntegrity.html
> 
> For the kernel KCFI flavor, see:
> https://lwn.net/Articles/898040/
> 
> The base changes required to bring up KCFI on ARM32 was mostly
> related to the use of custom vtables in the kernel, combined
> with defines to call into these vtable members directly from
> sites where they are used.
> 
> We annotate all assembly calls that are called directly from
> C with SYM_TYPED_FUNC_START()/SYM_FUNC_END() so it is easy
> to see while reading the assembly that these functions are
> called from C and can have CFI prototype information prefixed
> to them.
> 
> As protype prefix information is just some random bytes, it is
> not possible to "fall through" into an assembly function that
> is tagged with SYM_TYPED_FUNC_START(): there will be some
> binary noise in front of the function so this design pattern
> needs to be explicitly avoided at each site where it occurred.
> 
> The approach to binding the calls to C is two-fold:
> 
> - Either convert the affected vtable struct to C and provide
>   per-CPU prototypes for all the calls (done for TLB, cache)
>   or:
> 
> - Provide prototypes in a special files just for CFI and tag
>   all these functions addressable.
> 
> The permissive mode handles the new breakpoint type (0x03) that
> LLVM CLANG is emitting.
> 
> To runtime-test the patches:
> - Enable CONFIG_LKDTM
> - echo CFI_FORWARD_PROTO > /sys/kernel/debug/provoke-crash/DIRECT
> 
> The patch set has been booted to userspace on the following
> test platforms:
> 
> - Arm Versatile (QEMU)
> - Arm Versatile Express (QEMU)
> - multi_v7 booted on Versatile Express (QEMU)
> - Footbridge Netwinder (SA110 ARMv4)
> - Ux500 (ARMv7 SMP)
> - Gemini (FA526)
> 
> I am not saying there will not be corner cases that we need
> to fix in addition to this, but it is enough to get started.
> Looking at what was fixed for arm64 I am a bit weary that
> e.g. BPF might need something to trampoline properly.
> 
> But hopefullt people can get to testing it and help me fix
> remaining issues before the final version, or we can fix it
> in-tree.
> 
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

For the series:

Tested-by: Kees Cook <keescook@chromium.org>

Thanks for making this work!
Linus Walleij April 12, 2024, 7:38 a.m. UTC | #2
On Thu, Mar 28, 2024 at 9:19 AM Linus Walleij <linus.walleij@linaro.org> wrote:

> This is a first patch set to support CLANG CFI (Control Flow
> Integrity) on ARM32.

Not much reaction to this apart from Kees' ACK and I think
most patches are pretty straight-forward so I'll soon put them
in Russell's tracker, I can always update them if there is some
issue.

As mentioned, there will be some rough edges (e.g. eBPF)
but a slew of machines boot fine with it and it should be able
to provide additional hardening on a slew of embedded use
cases.

Yours,
Linus Walleij
Nathan Chancellor April 12, 2024, 10:07 p.m. UTC | #3
On Fri, Apr 12, 2024 at 09:38:24AM +0200, Linus Walleij wrote:
> On Thu, Mar 28, 2024 at 9:19 AM Linus Walleij <linus.walleij@linaro.org> wrote:
> 
> > This is a first patch set to support CLANG CFI (Control Flow
> > Integrity) on ARM32.
> 
> Not much reaction to this apart from Kees' ACK and I think
> most patches are pretty straight-forward so I'll soon put them
> in Russell's tracker, I can always update them if there is some
> issue.

I've given the patches a quick glance and I do not see anything
obviously wrong so consider this a soft LGTM. Given that it is an option
and I am sure there are arm64 and x86_64 configurations that are not
clean, I don't think having all CFI issues patched before the support
lands is necessary or desirable.

> As mentioned, there will be some rough edges (e.g. eBPF)
> but a slew of machines boot fine with it and it should be able
> to provide additional hardening on a slew of embedded use
> cases.

Agreed.

I will try to file an issue for the EFI issue I noticed before so that
it can be investigated and fixed at some point.

Cheers,
Nathan