This is the first series for an implementation of ARM's DEN 0113
v1.4b Dynamic Root of Trust for Measurement (DRTM) launch protocol.
It is built on some generic changes to the EFI stubs that provide for
a simple, direct DRTM launch directly into vmlinux.

DRTM is a boot security technique that jumps into some platform trusted
environment prior to launching the OS. The trusted environment will
sanitize the CPU, block DMA, measure (SHA hash) the OS to a TPM, and then
jump into the OS. The security goal is to prevent tampering across the
launch: if the measurement says X, it should be impossible to tamper with
the boot such that the CPU is actually running Y. DRTM is a reaction to
the historically bad boot security in the UEFI world. It aims to make bugs
in UEFI/etc unimportant for OS security.

When I spoke to Catalin about this, he was interested in making the flow
cross arch. After looking at what AMD and Intel do, and how different the
kernel EFI flow is on x86, I have opted to do that from the perspective of
building some generic DRTM infrastructure for the arches using EFI_ZBOOT
and FDT. I've sketched out applying the same general ideas to x86 and it
works there too, but x86 is so different that not much is directly
re-used. I would argue the security/hardening work listed below is a more
important place to get commonality.

Several people have asked me about Trenchboot, which is the x86
out-of-tree DRTM implementation. In my view, ARM and Trenchboot have
converged on the same basic design. Both offer high-level functions to the
OS that don't leak out any platform-specific details. Trenchboot offers
these through an EFI mechanism from Grub, while ARM offers it through a
standardized FW based SMC API. Effectively Trenchboot is a reaction to x86
having primitives that are far too low level and far too complicated to
implement inside the EFI stub.

ARM does not suffer the same issues as x86. The EFI stub implementation
for ARM DRTM is only 400 lines in patch 16. This is because the standard
already offers a sufficient abstraction to the OS. There is no technical
reason to bounce back to Grub to hide complexity that doesn't even exist.

Further, due to how ARM has abstracted DRTM, we cannot hide the ARM
details from the post-launch Linux. The kernel must understand it is
inside an ARM-specific DLME, it must do the ARM specific ations, and it
must process the ARM-specific post-launch data structures that the FW
writes. All of the work in this series, and its followups would still be
needed if Grub was involved. There is also a sneaky ABI here, the choices
the stub makes during launch have to be matched by the vmlinux
accomodating them. Keeping this all in one source tree and one link with
no ABI is the right answer.

My hope is that this series will encourage other platforms, like RISCV, to
follow ARM's approach and not x86's. Further, I strongly suggest that the
x86 world standardize some EFI calls so the UEFI itself can provide the
platform specific DRTM implementation instead of involving Grub.

Broadly, ARM's abstraction does several key things for Linux:
 1) No TPM is required until after some ACPI is parsed. ARM has many
    different kinds of TPMs, so TPM without ACPI is hard.

 2) The launch uses a contiguous chunk of memory that can be
    perfectly overlaid on vmlinux, with space for the headers,
    measured section, unmeasured data, bss and trusted post-launch
    information. It is trivial to insert Linux into this scheme.

 3) The launch protocol is trivial. The launch directly measures a
    portion of vmlinux. About 50% of the stub code is just inspecting
    features and doing FW call compatibility work, not tricky DRTM
    things. Zero platform-specific code.

 4) The post-launch world isn't special. We don't need unique kernel
    patches to undo things that DRTM did. The normal drivers work in
    the normal way just fine.

This series is enough to perform the launch and get a working kernel
inside a Dynamic Launch Measured Environment (DLME). There are several
following security-focused topics/series that aim to further prevent
attackers in the unmeasured world from compromising the measured
kernel. Much of this list comes from internal security research at NVIDIA
on securing Linux post-DRTM.

 - The kernel command line needs to be measured, without any "early tpm"
   for Linux.

 - ARM's DRTM protocol for verifying the address map needs to be implemented

 - ARM's protocol for checking the "TCB" ACPI needs to be implemented

 - Non-TCB ACPI needs to be deferred until the TPM is discovered and
   then the tables are measured into the TPM

 - Initrd/Initramfs measurement by Linux before using it

 - Exposing the DRTM launches TCG audit log to userspace

 - TPM locality handling

 - Non-EFI boot, particularly kexec

 - FDT security

 - KASLR RNG security

These topics all largely require different maintainers and different
cross-arch solutions. Post-launch kernel defense against an adversarial
boot is a complicated topic with several different threat models people
are interested in. It has alot of overlap with the Confidential Computing
need to deal with an adversarial host.

This series is arranged to try to build re-usable things that any
arch can use to implement DRTM:
 - A technique to communicate the link layout to the zboot stub based
   on ARM's code_size trick
 - New general linker sections/etc to move mutable data out of the
   measured range
 - Cross-arch symbols __drtm_measured_start/end that allow a user
   tool to compute the measurement hash from the vmlinux itself.
   Because of the mutable values this isn't just all of vmlinux.
 - CONFIG_EFI_DRTM and general EFI stub arch hooks to plug into for
   EFI ZBOOT and FDT arches
 - Shared drtm= kernel command-line processing

For x86, it does set some user-visible expectations like how to compute a
hash for vmlinux and the drtm= parameter. IMHO, these are key areas to get
cross-arch alignment on so the user tooling, like a systemd UKI, can use
DRTM easily.

I have a slop'd up qemu that implements the SMC protocol which is very
useful for testing:
  https://github.com/jgunthorpe/qemu/commits/arm64_drtm

NVIDIA has several real HW platforms this works with, I'll get more HW
testing as the review progresses.

This is on github: https://github.com/jgunthorpe/linux/commits/arm64_drtm

I've fed it to a local Sashiko and am satisfied the remaining remarks are
not applicable, and fixed several of the previously existing bugs it
found.

Jason Gunthorpe (16):
  efi/libstub: Fix error unwind freeing fdt in
    allocate_new_fdt_and_exit_boot()
  efi/riscv: libstub: Don't set image_size in handle_kernel_image()
  efi/libstub: Free cmdline_ptr in efi_pe_entry
  vmlinux.lds: Move DATA_LE32() from arm64 to the common linker script
  efi/libstub: Add a general way to get symbols from the vmlinux into
    zboot
  arm64/efi: Use CONFIG_EFI_STUB_IMAGE_INFO for code_size
  efi/zboot: Lift efi_cache_sync_image() from efi_zboot_decompress()
  efi/libstub: Add generic arch callbacks for DRTM
  efi/libstub: Have efi_kaslr_relocate_kernel() handle extra_size
  efi: Add a __efi_data_handoff section annotation
  efi/libstub: Put the stub's writable data in unique sections for DRTM
  arm64: drtm: Add macro definitions for DEN0113
  arm64: drtm: Update the linker script for EFI_STUB_DRTM
  arm64: drtm: Add drtm_entry point to head.S
  arm64: drtm: Call UNPROTECT_MEMORY
  efi/arm64: Implement ARM64 DRTM in the stub

 .../admin-guide/kernel-parameters.txt         |  12 +
 arch/arm64/Kconfig                            |  17 +
 arch/arm64/boot/Makefile                      |   3 -
 arch/arm64/include/asm/drtm.h                 | 215 +++++++++
 arch/arm64/include/asm/image.h                |  21 +
 arch/arm64/kernel/Makefile                    |   1 +
 arch/arm64/kernel/drtm.c                      |  49 +++
 arch/arm64/kernel/head.S                      |  83 ++++
 arch/arm64/kernel/image-vars.h                |   8 +-
 arch/arm64/kernel/image.h                     |  14 -
 arch/arm64/kernel/vmlinux.lds.S               |  76 +++-
 drivers/firmware/efi/Kconfig                  |  33 ++
 drivers/firmware/efi/efi-init.c               |   2 +-
 drivers/firmware/efi/libstub/Makefile         |  11 +
 drivers/firmware/efi/libstub/Makefile.zboot   |  11 +-
 drivers/firmware/efi/libstub/arm64-drtm.c     | 414 ++++++++++++++++++
 drivers/firmware/efi/libstub/arm64-stub.c     |   6 +-
 drivers/firmware/efi/libstub/arm64.c          |   4 +-
 drivers/firmware/efi/libstub/efi-stub-entry.c |   6 +-
 .../firmware/efi/libstub/efi-stub-helper.c    |  34 ++
 drivers/firmware/efi/libstub/efistub.h        |  65 +++
 drivers/firmware/efi/libstub/fdt.c            |  12 +-
 drivers/firmware/efi/libstub/kaslr.c          |  72 ++-
 drivers/firmware/efi/libstub/riscv-stub.c     |   6 +-
 .../efi/libstub/zboot-decompress-gzip.c       |   2 -
 .../efi/libstub/zboot-decompress-zstd.c       |   2 -
 drivers/firmware/efi/libstub/zboot.c          |  26 +-
 drivers/firmware/efi/libstub/zboot.lds        |  10 +-
 include/asm-generic/vmlinux.lds.h             |  57 +++
 include/linux/efi.h                           |  12 +
 30 files changed, 1221 insertions(+), 63 deletions(-)
 create mode 100644 arch/arm64/include/asm/drtm.h
 create mode 100644 arch/arm64/kernel/drtm.c
 create mode 100644 drivers/firmware/efi/libstub/arm64-drtm.c


base-commit: df2908090cda368b01ff43709f51890076c56157
-- 
2.43.0


Reply via email to