https://github.com/zyedidia updated https://github.com/llvm/llvm-project/pull/167061
>From 9ca2065bc60b13f54504251dbb32e3b0784feb85 Mon Sep 17 00:00:00 2001 From: Zachary Yedidia <[email protected]> Date: Mon, 20 Oct 2025 13:19:32 -0700 Subject: [PATCH 1/7] [LFI] Add aarch64_lfi subtarget --- llvm/include/llvm/TargetParser/Triple.h | 7 +++++++ llvm/lib/TargetParser/Triple.cpp | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/llvm/include/llvm/TargetParser/Triple.h b/llvm/include/llvm/TargetParser/Triple.h index 0e82dd212f34d..91f095091308d 100644 --- a/llvm/include/llvm/TargetParser/Triple.h +++ b/llvm/include/llvm/TargetParser/Triple.h @@ -153,6 +153,7 @@ class Triple { AArch64SubArch_arm64e, AArch64SubArch_arm64ec, + AArch64SubArch_lfi, KalimbaSubArch_v3, KalimbaSubArch_v4, @@ -924,6 +925,12 @@ class Triple { return getArch() == Triple::arm || getArch() == Triple::armeb; } + /// Tests whether the target is LFI. + bool isLFI() const { + return getArch() == Triple::aarch64 && + getSubArch() == Triple::AArch64SubArch_lfi; + } + /// Tests whether the target supports the EHABI exception /// handling standard. bool isTargetEHABICompatible() const { diff --git a/llvm/lib/TargetParser/Triple.cpp b/llvm/lib/TargetParser/Triple.cpp index 11ba9ee32f66a..2577b15b19992 100644 --- a/llvm/lib/TargetParser/Triple.cpp +++ b/llvm/lib/TargetParser/Triple.cpp @@ -116,6 +116,8 @@ StringRef Triple::getArchName(ArchType Kind, SubArchType SubArch) { return "arm64ec"; if (SubArch == AArch64SubArch_arm64e) return "arm64e"; + if (SubArch == AArch64SubArch_lfi) + return "aarch64_lfi"; break; case Triple::spirv: switch (SubArch) { @@ -594,6 +596,7 @@ static Triple::ArchType parseArch(StringRef ArchName) { .Case("aarch64", Triple::aarch64) .Case("aarch64_be", Triple::aarch64_be) .Case("aarch64_32", Triple::aarch64_32) + .Case("aarch64_lfi", Triple::aarch64) .Case("arc", Triple::arc) .Case("arm64", Triple::aarch64) .Case("arm64_32", Triple::aarch64_32) @@ -832,6 +835,9 @@ static Triple::SubArchType parseSubArch(StringRef SubArchName) { if (SubArchName == "arm64ec") return Triple::AArch64SubArch_arm64ec; + if (SubArchName == "aarch64_lfi") + return Triple::AArch64SubArch_lfi; + if (SubArchName.starts_with("spirv")) return StringSwitch<Triple::SubArchType>(SubArchName) .EndsWith("v1.0", Triple::SPIRVSubArch_v10) >From 2b46bc05742d63b918593ac445979b752502fb93 Mon Sep 17 00:00:00 2001 From: Zachary Yedidia <[email protected]> Date: Mon, 20 Oct 2025 13:48:50 -0700 Subject: [PATCH 2/7] [LFI] Reserve LFI registers --- llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp | 11 +++++++++++ llvm/lib/Target/AArch64/AArch64Subtarget.h | 1 + 2 files changed, 12 insertions(+) diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp index a5048b9c9e61d..7b72c052fba36 100644 --- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp +++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp @@ -461,6 +461,17 @@ AArch64RegisterInfo::getStrictlyReservedRegs(const MachineFunction &MF) const { markSuperRegs(Reserved, i); } + if (MF.getSubtarget<AArch64Subtarget>().isLFI()) { + markSuperRegs(Reserved, AArch64::W28); + markSuperRegs(Reserved, AArch64::W27); + markSuperRegs(Reserved, AArch64::W26); + markSuperRegs(Reserved, AArch64::W25); + if (!MF.getProperties().hasNoVRegs()) { + markSuperRegs(Reserved, AArch64::LR); + markSuperRegs(Reserved, AArch64::W30); + } + } + for (size_t i = 0; i < AArch64::GPR32commonRegClass.getNumRegs(); ++i) { if (MF.getSubtarget<AArch64Subtarget>().isXRegisterReserved(i)) markSuperRegs(Reserved, AArch64::GPR32commonRegClass.getRegister(i)); diff --git a/llvm/lib/Target/AArch64/AArch64Subtarget.h b/llvm/lib/Target/AArch64/AArch64Subtarget.h index 8974965c41fe3..dbab11a5628af 100644 --- a/llvm/lib/Target/AArch64/AArch64Subtarget.h +++ b/llvm/lib/Target/AArch64/AArch64Subtarget.h @@ -293,6 +293,7 @@ class AArch64Subtarget final : public AArch64GenSubtargetInfo { bool isTargetAndroid() const { return TargetTriple.isAndroid(); } bool isTargetFuchsia() const { return TargetTriple.isOSFuchsia(); } bool isWindowsArm64EC() const { return TargetTriple.isWindowsArm64EC(); } + bool isLFI() const { return TargetTriple.isLFI(); } bool isTargetCOFF() const { return TargetTriple.isOSBinFormatCOFF(); } bool isTargetELF() const { return TargetTriple.isOSBinFormatELF(); } >From 7a771ec23d79ab79a9efa080151cc9b3a94fa425 Mon Sep 17 00:00:00 2001 From: Zachary Yedidia <[email protected]> Date: Mon, 20 Oct 2025 13:54:17 -0700 Subject: [PATCH 3/7] [LFI] Add Clang driver toolchain for LFI --- clang/lib/Basic/Targets/AArch64.cpp | 3 ++ clang/lib/Driver/CMakeLists.txt | 1 + clang/lib/Driver/Driver.cpp | 3 ++ clang/lib/Driver/ToolChains/LFILinux.cpp | 29 ++++++++++++++++++++ clang/lib/Driver/ToolChains/LFILinux.h | 35 ++++++++++++++++++++++++ 5 files changed, 71 insertions(+) create mode 100644 clang/lib/Driver/ToolChains/LFILinux.cpp create mode 100644 clang/lib/Driver/ToolChains/LFILinux.h diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index a97e93470987c..0cc4db1e637ce 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -412,6 +412,9 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__aarch64__"); } + if (getTriple().isLFI()) + Builder.defineMacro("__LFI__"); + // Inline assembly supports AArch64 flag outputs. Builder.defineMacro("__GCC_ASM_FLAG_OUTPUTS__"); diff --git a/clang/lib/Driver/CMakeLists.txt b/clang/lib/Driver/CMakeLists.txt index 7c4f70b966c48..9060b63d75d6e 100644 --- a/clang/lib/Driver/CMakeLists.txt +++ b/clang/lib/Driver/CMakeLists.txt @@ -65,6 +65,7 @@ add_clang_library(clangDriver ToolChains/Hexagon.cpp ToolChains/HLSL.cpp ToolChains/Hurd.cpp + ToolChains/LFILinux.cpp ToolChains/Linux.cpp ToolChains/Managarm.cpp ToolChains/MipsLinux.cpp diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index a0b82cec9a372..e0323cf631fca 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -29,6 +29,7 @@ #include "ToolChains/Haiku.h" #include "ToolChains/Hexagon.h" #include "ToolChains/Hurd.h" +#include "ToolChains/LFILinux.h" #include "ToolChains/Lanai.h" #include "ToolChains/Linux.h" #include "ToolChains/MSP430.h" @@ -6864,6 +6865,8 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, TC = std::make_unique<toolchains::OHOS>(*this, Target, Args); else if (Target.isWALI()) TC = std::make_unique<toolchains::WebAssembly>(*this, Target, Args); + else if (Target.isLFI()) + TC = std::make_unique<toolchains::LFILinuxToolChain>(*this, Target, Args); else TC = std::make_unique<toolchains::Linux>(*this, Target, Args); break; diff --git a/clang/lib/Driver/ToolChains/LFILinux.cpp b/clang/lib/Driver/ToolChains/LFILinux.cpp new file mode 100644 index 0000000000000..7ab2372756af9 --- /dev/null +++ b/clang/lib/Driver/ToolChains/LFILinux.cpp @@ -0,0 +1,29 @@ +//===-- LFILinux.cpp - LFI ToolChain Implementations ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "LFILinux.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Options.h" + +using namespace clang::driver::toolchains; +using namespace llvm::opt; + +void LFILinuxToolChain::AddCXXStdlibLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + switch (GetCXXStdlibType(Args)) { + case ToolChain::CST_Libcxx: + CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); + CmdArgs.push_back("-lc++abi"); + break; + case ToolChain::CST_Libstdcxx: + CmdArgs.push_back("-lstdc++"); + break; + } +} diff --git a/clang/lib/Driver/ToolChains/LFILinux.h b/clang/lib/Driver/ToolChains/LFILinux.h new file mode 100644 index 0000000000000..e85f74803c1ce --- /dev/null +++ b/clang/lib/Driver/ToolChains/LFILinux.h @@ -0,0 +1,35 @@ +//===--- LFILinux.h - LFI ToolChain Implementations -------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LFI_LINUX_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LFI_LINUX_H + +#include "Linux.h" + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY LFILinuxToolChain : public Linux { +public: + LFILinuxToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) + : Linux(D, Triple, Args) { + ExtraOpts.push_back("-z"); + ExtraOpts.push_back("separate-code"); + } + + void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LFI_LINUX_H >From c07a2ce127b67ec379e4c7cf0da61da4aed58ec4 Mon Sep 17 00:00:00 2001 From: Zachary Yedidia <[email protected]> Date: Mon, 20 Oct 2025 13:58:34 -0700 Subject: [PATCH 4/7] [LFI] Update compiler-rt cmake for LFI --- compiler-rt/cmake/builtin-config-ix.cmake | 2 +- compiler-rt/lib/builtins/CMakeLists.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler-rt/cmake/builtin-config-ix.cmake b/compiler-rt/cmake/builtin-config-ix.cmake index eaff8135cff45..3298fe96cd236 100644 --- a/compiler-rt/cmake/builtin-config-ix.cmake +++ b/compiler-rt/cmake/builtin-config-ix.cmake @@ -78,7 +78,7 @@ else() endif() set(AMDGPU amdgcn) -set(ARM64 aarch64 arm64ec) +set(ARM64 aarch64 arm64ec aarch64_lfi) set(ARM32 arm armhf armv4t armv5te armv6 armv6m armv7m armv7em armv7 armv7s armv7k armv8m.base armv8m.main armv8.1m.main) set(AVR avr) set(HEXAGON hexagon) diff --git a/compiler-rt/lib/builtins/CMakeLists.txt b/compiler-rt/lib/builtins/CMakeLists.txt index 6c226aa7d2d48..29c5a08b828cb 100644 --- a/compiler-rt/lib/builtins/CMakeLists.txt +++ b/compiler-rt/lib/builtins/CMakeLists.txt @@ -692,6 +692,7 @@ set(arm64_SOURCES ${aarch64_SOURCES}) set(arm64e_SOURCES ${aarch64_SOURCES}) set(arm64_32_SOURCES ${aarch64_SOURCES}) set(arm64ec_SOURCES ${aarch64_SOURCES}) +set(aarch64_lfi_SOURCES ${aarch64_SOURCES}) # macho_embedded archs set(armv6m_SOURCES ${thumb1_SOURCES}) >From 60de70003eb4e2149c98e592293c1c218549d2c7 Mon Sep 17 00:00:00 2001 From: Zachary Yedidia <[email protected]> Date: Fri, 7 Nov 2025 16:18:27 -0800 Subject: [PATCH 5/7] [LFI] Add LFI.rst documentation --- llvm/docs/LFI.rst | 387 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 387 insertions(+) create mode 100644 llvm/docs/LFI.rst diff --git a/llvm/docs/LFI.rst b/llvm/docs/LFI.rst new file mode 100644 index 0000000000000..22af7b1174e86 --- /dev/null +++ b/llvm/docs/LFI.rst @@ -0,0 +1,387 @@ +========================================= +Lightweight Fault Isolation (LFI) in LLVM +========================================= + +.. contents:: + :local: + +Introduction +++++++++++++ + +Lightweight Fault Isolation (LFI) is a compiler-based sandboxing technology for +native code. Like WebAssembly and Native Client, LFI isolates sandboxed code in-process +(i.e., in the same address space as a host application). + +LFI is designed from the ground up to sandbox existing code, such as C/C++ +libraries (including assembly code) and device drivers. + +LFI aims for the following goals: + +* Compatibility: LFI can be used to sandbox nearly all existing C/C++/assembly + libraries unmodified (they just need to be recompiled). Sandboxed libraries + work with existing system call interfaces, and are compatible with existing + development tools such as profilers, debuggers, and sanitizers. +* Performance: LFI aims for minimal overhead vs. unsandboxed code. +* Security: The LFI runtime and compiler elements aim to be simple and + verifiable when possible. +* Usability: LFI aims to make it easy as possible to used retrofit sandboxing, + i.e., to migrate from unsandboxed to sandboxed libraries with minimal effort. + +When building a program for the LFI target the compiler is designed to ensure +that the program will only be able to access memory within a limited region of +the virtual address space, starting from where the program is loaded (the +current design sets this region to a size of 4GiB of virtual memory). Programs +built for the LFI target are restricted to using a subset of the instruction +set, designed so that the programs can be soundly confined to their sandbox +region. LFI programs must run inside of an "emulator" (usually called the LFI +runtime), responsible for initializing the sandbox region, loading the program, +and servicing system call requests, or other forms of runtime calls. + +LFI uses an architecture-specific sandboxing scheme based on the general +technique of Software-Based Fault Isolation (SFI). Initial support for LFI in +LLVM is focused on the AArch64 platform, with x86-64 support planned for the +future. The initial version of LFI for AArch64 is designed to support the +Armv8.1 AArch64 architecture. + +See `https://github.com/lfi-project <https://github.com/lfi-project/>`__ for +details about the LFI project and additional software needed to run LFI +programs. + +Compiler Requirements ++++++++++++++++++++++ + +When building for the ``aarch64_lfi`` target, the compiler must restrict use of +the instruction set to a subset of instructions, which are known to be safe +from a sandboxing perspective. To do this, we apply a set of simple rewrites at +the assembly language level to transform standard native AArch64 assembly into +LFI-compatible AArch64 assembly. + +These rewrites (also called "expansions") are applied at the very end of the +LLVM compilation pipeline (during the assembler step). This allows the rewrites +to be applied to hand-written assembly, including inline assembly. + +Compiler Options +================ + +The LFI target has several configuration options. + +* ``+lfi-stores``: create a "stores-only" sandbox, where rewrites are not applied to loads. +* ``+lfi-jumps``: create a "jumps-only" sandbox, where rewrites are not applied to loads/stores. + +Reserved Registers +================== + +The LFI target uses a custom ABI that reserves additional registers for the +platform. The registers are listed below, along with the security invariant +that must be maintained. + +* ``x27``: always holds the sandbox base address. +* ``x28``: always holds an address within the sandbox. +* ``sp``: always holds an address within the sandbox. +* ``x30``: always holds an address within the sandbox. +* ``x26``: scratch register. +* ``x25``: points to a thread-local virtual register file for storing runtime context information. + +Linker Support +============== + +In the initial version, LFI only supports static linking, and only supports +creating ``static-pie`` binaries. There is nothing that fundamentally precludes +support for dynamic linking on the LFI target, but such support would require +that the code generated by the linker for PLT entries be slightly modified in +order to conform to the LFI architecture subset. + +Assembly Rewrites +================= + +Terminology +~~~~~~~~~~~ + +In the following assembly rewrites, some shorthand is used. + +* ``xN`` or ``wN``: refers to any general-purpose non-reserved register. +* ``{a,b,c}``: matches any of ``a``, ``b``, or ``c``. +* ``LDSTr``: a load/store instruction that supports register-register addressing modes, with one source/destination register. +* ``LDSTx``: a load/store instruction not matched by ``LDSTr``. + +Control flow +~~~~~~~~~~~~ + +Indirect branches get rewritten to branch through register ``x28``, which must +always contain an address within the sandbox. An ``add`` is used to safely load +``x28`` with the destination address. Since ``ret`` uses ``x30`` by default, +which already must contain an address within the sandbox, it does not require +any rewrite. + ++--------------------+---------------------------+ +| Original | Rewritten | ++--------------------+---------------------------+ +| .. code-block:: | .. code-block:: | +| | | +| {br,blr,ret} xN | add x28, x27, wN, uxtw | +| | {br,blr,ret} x28 | +| | | ++--------------------+---------------------------+ +| .. code-block:: | .. code-block:: | +| | | +| ret | ret | +| | | ++--------------------+---------------------------+ + +Memory accesses +~~~~~~~~~~~~~~~ + +Memory accesses are rewritten to use the ``[x27, wM, uxtw]`` addressing mode if +it is available, which is automatically safe. Otherwise, rewrites fall back to +using ``x28`` along with an instruction to safely load it with the target +address. + ++---------------------------------+-------------------------------+ +| Original | Rewritten | ++---------------------------------+-------------------------------+ +| .. code-block:: | .. code-block:: | +| | | +| LDSTr xN, [xM] | LDSTr xN, [x27, wM, uxtw] | +| | | ++---------------------------------+-------------------------------+ +| .. code-block:: | .. code-block:: | +| | | +| LDSTr xN, [xM, #I] | add x28, x27, wM, uxtw | +| | LDSTr xN, [x28, #I] | +| | | ++---------------------------------+-------------------------------+ +| .. code-block:: | .. code-block:: | +| | | +| LDSTr xN, [xM, #I]! | add xM, xM, #I | +| | LDSTr xN, [x27, wM, uxtw] | +| | | ++---------------------------------+-------------------------------+ +| .. code-block:: | .. code-block:: | +| | | +| LDSTr xN, [xM], #I | LDSTr xN, [x27, wM, uxtw] | +| | add xM, xM, #I | +| | | ++---------------------------------+-------------------------------+ +| .. code-block:: | .. code-block:: | +| | | +| LDSTr xN, [xM1, xM2] | add x26, xM1, xM2 | +| | LDSTr xN, [x27, w26, uxtw] | +| | | ++---------------------------------+-------------------------------+ +| .. code-block:: | .. code-block:: | +| | | +| LDSTr xN, [xM1, xM2, MOD #I] | add x26, xM1, xM2, MOD #I | +| | LDSTr xN, [x27, w26, uxtw] | +| | | ++---------------------------------+-------------------------------+ +| .. code-block:: | .. code-block:: | +| | | +| LDSTx ..., [xM] | add x28, x27, wM, uxtw | +| | LDSTx ..., [x28] | +| | | ++---------------------------------+-------------------------------+ +| .. code-block:: | .. code-block:: | +| | | +| LDSTx ..., [xM, #I] | add x28, x27, wM, uxtw | +| | LDSTx ..., [x28, #I] | +| | | ++---------------------------------+-------------------------------+ +| .. code-block:: | .. code-block:: | +| | | +| LDSTx ..., [xM, #I]! | add x28, x27, wM, uxtw | +| | LDSTx ..., [x28, #I] | +| | add xM, xM, #I | +| | | ++---------------------------------+-------------------------------+ +| .. code-block:: | .. code-block:: | +| | | +| LDSTx ..., [xM], #I | add x28, x27, wM, uxtw | +| | LDSTx ..., [x28] | +| | add xM, xM, #I | +| | | ++---------------------------------+-------------------------------+ +| .. code-block:: | .. code-block:: | +| | | +| LDSTx ..., [xM1], xM2 | add x28, x27, wM1, uxtw | +| | LDSTx ..., [x28] | +| | add xM1, xM1, xM2 | +| | | ++---------------------------------+-------------------------------+ + +Stack pointer modification +~~~~~~~~~~~~~~~~~~ + +When the stack pointer is modified, we write the modified value to a temporary, +before loading it back into ``sp`` with a safe ``add``. + ++------------------------------+-------------------------------+ +| Original | Rewritten | ++------------------------------+-------------------------------+ +| .. code-block:: | .. code-block:: | +| | | +| mov sp, xN | add sp, x27, wN, uxtw | +| | | ++------------------------------+-------------------------------+ +| .. code-block:: | .. code-block:: | +| | | +| {add,sub} sp, sp, {#I,xN} | {add,sub} x26, sp, {#I,xN} | +| | add sp, x27, w26, uxtw | +| | | ++------------------------------+-------------------------------+ + +Link register modification +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When the link register is modified, we write the modified value to a +temporary, before loading it back into ``x30`` with a safe ``add``. + ++-----------------------+----------------------------+ +| Original | Rewritten | ++-----------------------+----------------------------+ +| .. code-block:: | .. code-block:: | +| | | +| ldr x30, [...] | ldr x26, [...] | +| | add x30, x27, w26, uxtw | +| | | ++-----------------------+----------------------------+ +| .. code-block:: | .. code-block:: | +| | | +| ldp xN, x30, [...] | ldp xN, x26, [...] | +| | add x30, x27, w26, uxtw | +| | | ++-----------------------+----------------------------+ +| .. code-block:: | .. code-block:: | +| | | +| ldp x30, xN, [...] | ldp x26, xN, [...] | +| | add x30, x27, w26, uxtw | +| | | ++-----------------------+----------------------------+ + +System instructions +~~~~~~~~~~~~~~~~~~~ + +System calls are rewritten into a sequence that loads the address of the first +runtime call entrypoint and jumps to it. The runtime call entrypoint table is +stored at the start of the sandbox, so it can be referenced by ``x27``. The +rewrite also saves and restores the link register, since it is used for +branching into the runtime. + ++-----------------+----------------------------+ +| Original | Rewritten | ++-----------------+----------------------------+ +| .. code-block:: | .. code-block:: | +| | | +| svc #0 | mov w26, w30 | +| | ldr x30, [x27] | +| | blr x30 | +| | add x30, x27, w26, uxtw | +| | | ++-----------------+----------------------------+ + +Thread-local storage +~~~~~~~~~~~~~~~~~~~~ + +TLS accesses are rewritten into accesses offset from ``x25``, which is a +reserved register that points to a virtual register file, with a location for +storing the sandbox's thread pointer. ``TP`` is the offset into that virtual +register file where the thread pointer is stored. + ++----------------------+-----------------------+ +| Original | Rewritten | ++----------------------+-----------------------+ +| .. code-block:: | .. code-block:: | +| | | +| mrs xN, tpidr_el0 | ldr xN, [x25, #TP] | +| | | ++----------------------+-----------------------+ +| .. code-block:: | .. code-block:: | +| | | +| mrs tpidr_el0, xN | str xN, [x25, #TP] | +| | | ++----------------------+-----------------------+ + +Optimizations +============= + +Basic guard elimination +~~~~~~~~~~~~~~~~~~~~~~~ + +If a register is guarded multiple times in the same basic block without any +modifications to it during the intervening instructions, then subsequent guards +can be removed. + ++---------------------------+---------------------------+ +| Original | Rewritten | ++---------------------------+---------------------------+ +| .. code-block:: | .. code-block:: | +| | | +| add x28, x27, wN, uxtw | add x28, x27, wN, uxtw | +| ldur xN, [x28] | ldur xN, [x28] | +| add x28, x27, wN, uxtw | ldur xN, [x28, #8] | +| ldur xN, [x28, #8] | ldur xN, [x28, #16] | +| add x28, x27, wN, uxtw | | +| ldur xN, [x28, #16] | | +| | | ++---------------------------+---------------------------+ + +Stack guard elimination +~~~~~~~~~~~~~~~~~~~~~~~ + +**Note**: this optimization has not been implemented. + +If the stack pointer is modified by adding/subtracting a small immediate, and +then later used to perform a memory access without any intervening jumps, then +the guard on the stack pointer modification can be removed. This is because the +load/store is guaranteed to trap if the stack pointer has been moved outside of +the sandbox region. + ++---------------------------+---------------------------+ +| Original | Rewritten | ++---------------------------+---------------------------+ +| .. code-block:: | .. code-block:: | +| | | +| add x26, sp, #8 | add sp, sp, #8 | +| add sp, x27, w26, uxtw | ... (same basic block) | +| ... (same basic block) | ldr xN, [sp] | +| ldr xN, [sp] | | +| | | ++---------------------------+---------------------------+ + +Guard hoisting +~~~~~~~~~~~~~~ + +**Note**: this optimization has not been implemented. + +In certain cases, guards may be hoisted outside of loops. + ++-----------------------+-------------------------------+ +| Original | Rewritten | ++-----------------------+-------------------------------+ +| .. code-block:: | .. code-block:: | +| | | +| mov w8, #10 | mov w8, #10 | +| mov w9, #0 | mov w9, #0 | +| .loop: | add x28, x27, wM, uxtw | +| add w9, w9, #1 | .loop: | +| ldr xN, [xM] | add w9, w9, #1 | +| cmp w9, w8 | ldr xN, [x28] | +| b.lt .loop | cmp w9, w8 | +| .end: | b.lt .loop | +| | .end: | +| | | ++-----------------------+-------------------------------+ + +References +++++++++++ + +For more information, please see the following resources: + +* `LFI project page <https://github.com/lfi-project/>`__ +* `LFI RFC <https://discourse.llvm.org/t/rfc-lightweight-fault-isolation-lfi-efficient-native-code-sandboxing-upstream-lfi-target-and-compiler-changes/88380>`__ +* `LFI paper <https://zyedidia.github.io/papers/lfi_asplos24.pdf>`__ + +Contact info: + +* Zachary Yedidia - [email protected] +* Tal Garfinkel - [email protected] +* Sharjeel Khan - [email protected] >From cb99f0a8517ffa2e369a8fab9477eb248db5715c Mon Sep 17 00:00:00 2001 From: Zachary Yedidia <[email protected]> Date: Fri, 7 Nov 2025 16:38:31 -0800 Subject: [PATCH 6/7] [LFI] Apply clang-format to Driver.cpp --- clang/lib/Driver/Driver.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index e0323cf631fca..ba0aae9ebba14 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -6866,7 +6866,8 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, else if (Target.isWALI()) TC = std::make_unique<toolchains::WebAssembly>(*this, Target, Args); else if (Target.isLFI()) - TC = std::make_unique<toolchains::LFILinuxToolChain>(*this, Target, Args); + TC = std::make_unique<toolchains::LFILinuxToolChain>(*this, Target, + Args); else TC = std::make_unique<toolchains::Linux>(*this, Target, Args); break; >From facd934e3a08c03884c2c4fe4bad47f6e928016e Mon Sep 17 00:00:00 2001 From: Zachary Yedidia <[email protected]> Date: Mon, 10 Nov 2025 11:46:11 -0800 Subject: [PATCH 7/7] [LFI] Fix title underline in docs/LFI.rst --- llvm/docs/LFI.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/docs/LFI.rst b/llvm/docs/LFI.rst index 22af7b1174e86..613a8a80b6984 100644 --- a/llvm/docs/LFI.rst +++ b/llvm/docs/LFI.rst @@ -209,7 +209,7 @@ address. +---------------------------------+-------------------------------+ Stack pointer modification -~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~ When the stack pointer is modified, we write the modified value to a temporary, before loading it back into ``sp`` with a safe ``add``. _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
