* [PATCH RFC v2 00/29] Address Space Isolation (ASI)
@ 2025-01-10 18:40 Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 01/29] mm: asi: Make some utility functions noinstr compatible Brendan Jackman
` (28 more replies)
0 siblings, 29 replies; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman, Junaid Shahid, Ofir Weisse, Yosry Ahmed,
Kevin Cheng, Reiji Watanabe
ASI is a technique to mitigate a broad class of CPU vulnerabilities
by unmapping sensitive data from the kernel address space. If no data
is mapped that needs protecting, this class of exploits cannot leak
that data and so the kernel can skip expensive mitigation actions.
For a more detailed overview, see the v1 RFC (which was wrongly
labeled as a PATCH) [0].
This new iteration adds support for protecting against bare-metal
processes as well as KVM guests. The basic principle is unchanged.
.:: Multi-class ASI
So far ASI has been a KVM-only solution, although I've been claiming
that in principle it can be extended to also sandbox userspace.
Dave Hansen's most important feedback at LPC [1] was that he wanted
some evidence to support this claim. If it can be shown that ASI is
just as powerful for bare-metal as for KVM, it's much more likely to
actually offer an escape path from maintaining and reactively
developing per-exploit mitigations.
v1 already supported a notion of "ASI classes", with the only class
being KVM. This RFC introduces a second class for userspace. Each
process has a separate restricted address space ("domain") for each
class.
In v1, the only possible ASI transitions were between the KVM
restricted address space, and the unrestricted address space. Now
that there are multiple classes, it's possible to transition directly
between two restricted address spaces.
(Could we dodge this complexity by just transitioning via the
unrestricted address space? Yes, but experience from Google's
internal deployment suggests there's a significant benefit in
avoiding an asi_exit() when switching between userspace and KVM,
despite all the optimizations that exist to avoid that switching).
Compared to v1, this version has a new mechanism to determine
what mitigation actions are required when switching between address
spaces. ASI classes provide a "taint policy" which describes what
uarch state their sandboxee might leave behind, and what uarch state
needs to be purged before their sandboxee can safely be run. The ASI
core takes care of doing the actual flushes.
This enables a reasonably advanced model of what flushes are needed
when; for example the kernel is now able to model "when transitioning
from a VMM to its KVM guest there is no point in flushing speculative
control flow state, but if we _later_ exit to the unrestricted
address space we do need to flush it". It's quite possible this is
actually more advanced than what is needed so suggestions are
welcome.
.:: Performance issues: bogus mitigation costs
Although this implementation of ASI is pretty generous in what it
considers "nonsensitive", there remain unnecessary performance costs
that need to be addressed. For example:
- The entire page cache is removed from the direct map. Traditional
file operations will hit an asi_exit(), paying a pointless cost to
protect data from a process that obviously has the right to read
that data.
- Anything that accesses guest or user memory via the direct map
instead of the user address space will hit an asi_exit().
- Pages being zeroed in the page allocator
Most of these issues existed in v1 too, but now that ASI sandboxes
userspace processes, the page-cache issue becomes very significant.
For FIO 4k read (I suppose this workload is maximally sensitive to
this issue) I saw a 70% degradation in throughput, with a Sapphire
Rapids machine hard-coded to perform IBPB and RSB-stuffing on
asi_exit().
Given a result like that I haven't gone into more detailed analysis.
Note also that I ran with an unrealistic mitigation policy, results
would be much different if ran with platform-appropriate flushes, but
it would presumably lead to the same conclusion.
There are some interesting discussions to be had about tackling that
problem (e.g. reintroducing "local-nonsensitivity" from Junaid's 2022
ASI implementation [2], or creating ephemeral CPU-local mappings),
but for this RFC I prefer to focus on deciding if the overall
framework makes sense.
.:: Next steps
Aside from lack of userspace support, all the other issues listed in
RFCv1 remain. I'll also need a proof-of-concept solution for the
page-cache issue before we can credibly claim to be reaching a
[PATCH], but before that I want to develop a more complete page_alloc
integration. I plan to propose a topic about that at LSF/MM/BPF.
Anyway, despite the further research needed on my side I think
there's still useful stuff to discuss here. For example:
- Does the "tainting" model make intuitive sense? Is there a simpler
way to achieve something similar?
- The taints offer a model for different parts of the kernel to
communicate with each other about what mitigations they've taken
care of. For example, KVM could clear ASI taints if it existing
conditional-L1D-flush logic fires. Does it make sense to take
advantage of this? (I think yes). How does this influence the
design of the bugs.c kernel arguments?
- Suggestions on how to map file pages into processes that can read
them, while minimizing TLB management pain.
Finally, a more extensive branch can be found at [3]. It has some tests
and some of the lower-hanging fruit for optimising performance of KVM
guests.
[0] RFC v1:
https://lore.kernel.org/linux-mm/20240712-asi-rfc-24-v1-0-144b319a40d8@google.com/
[1] LPC session: https://lpc.events/event/18/contributions/1761/
[2] Junaid’s RFC:
https://lore.kernel.org/all/20220223052223.1202152-1-junaids@google.com/
[3] GitHub branch:
https://github.com/googleprodkernel/linux-kvm/tree/asi-rfcv2-preview
Signed-off-by: Brendan Jackman <jackmanb@google.com>
Ingo Molnar <mingo@redhat.com>, Borislav Petkov <bp@alien8.de>,
Dave Hansen <dave.hansen@linux.intel.com>,
"H. Peter Anvin" <hpa@zytor.com>,
Andy Lutomirski <luto@kernel.org>,
Peter Zijlstra <peterz@infradead.org>,
Sean Christopherson <seanjc@google.com>,
Paolo Bonzini <pbonzini@redhat.com>,
Alexandre Chartre <alexandre.chartre@oracle.com>,
Liran Alon <liran.alon@oracle.com>,
Jan Setje-Eilers <jan.setjeeilers@oracle.com>,
Catalin Marinas <catalin.marinas@arm.com>,
Will Deacon <will@kernel.org>,
Mark Rutland <mark.rutland@arm.com>,
Andrew Morton <akpm@linux-foundation.org>,
Mel Gorman <mgorman@suse.de>,
Lorenzo Stoakes <lstoakes@gmail.com>,
David Hildenbrand <david@redhat.com>,
Vlastimil Babka <vbabka@suse.cz>,
Michal Hocko <mhocko@kernel.org>,
Khalid Aziz <khalid.aziz@oracle.com>,
Juri Lelli <juri.lelli@redhat.com>,
Vincent Guittot <vincent.guittot@linaro.org>,
Dietmar Eggemann <dietmar.eggemann@arm.com>,
Steven Rostedt <rostedt@goodmis.org>,
Valentin Schneider <vschneid@redhat.com>,
Paul Turner <pjt@google.com>, Reiji Watanabe <reijiw@google.com>,
Junaid Shahid <junaids@google.com>,
Ofir Weisse <oweisse@google.com>,
Yosry Ahmed <yosryahmed@google.com>,
Patrick Bellasi <derkling@google.com>,
KP Singh <kpsingh@google.com>,
Alexandra Sandulescu <aesa@google.com>,
Matteo Rizzo <matteorizzo@google.com>,
Jann Horn <jannh@google.com>
kvm@vger.kernel.org, Brendan Jackman <jackmanb@google.com>,
Dennis Zhou <dennis@kernel.org>
---
Changes in v2:
- Added support for sandboxing userspace processes.
- Link to v1: https://lore.kernel.org/r/20240712-asi-rfc-24-v1-0-144b319a40d8@google.com
---
Brendan Jackman (21):
mm: asi: Make some utility functions noinstr compatible
x86: Create CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
mm: asi: Introduce ASI core API
mm: asi: Add infrastructure for boot-time enablement
mm: asi: ASI support in interrupts/exceptions
mm: asi: Avoid warning from NMI userspace accesses in ASI context
mm: Add __PAGEFLAG_FALSE
mm: asi: Map non-user buddy allocations as nonsensitive
[TEMP WORKAROUND] mm: asi: Workaround missing partial-unmap support
mm: asi: Map kernel text and static data as nonsensitive
mm: asi: Map vmalloc/vmap data as nonsensitive
mm: asi: Stabilize CR3 in switch_mm_irqs_off()
mm: asi: Make TLB flushing correct under ASI
KVM: x86: asi: Restricted address space for VM execution
mm: asi: exit ASI before accessing CR3 from C code where appropriate
mm: asi: Add infrastructure for mapping userspace addresses
mm: asi: Restricted execution fore bare-metal processes
x86: Create library for flushing L1D for L1TF
mm: asi: Add some mitigations on address space transitions
x86/pti: Disable PTI when ASI is on
mm: asi: Stop ignoring asi=on cmdline flag
Junaid Shahid (4):
mm: asi: Make __get_current_cr3_fast() ASI-aware
mm: asi: ASI page table allocation functions
mm: asi: Functions to map/unmap a memory range into ASI page tables
mm: asi: Add basic infrastructure for global non-sensitive mappings
Ofir Weisse (1):
mm: asi: asi_exit() on PF, skip handling if address is accessible
Reiji Watanabe (1):
mm: asi: Map dynamic percpu memory as nonsensitive
Yosry Ahmed (2):
mm: asi: Use separate PCIDs for restricted address spaces
mm: asi: exit ASI before suspend-like operations
arch/alpha/include/asm/Kbuild | 1 +
arch/arc/include/asm/Kbuild | 1 +
arch/arm/include/asm/Kbuild | 1 +
arch/arm64/include/asm/Kbuild | 1 +
arch/csky/include/asm/Kbuild | 1 +
arch/hexagon/include/asm/Kbuild | 1 +
arch/loongarch/include/asm/Kbuild | 3 +
arch/m68k/include/asm/Kbuild | 1 +
arch/microblaze/include/asm/Kbuild | 1 +
arch/mips/include/asm/Kbuild | 1 +
arch/nios2/include/asm/Kbuild | 1 +
arch/openrisc/include/asm/Kbuild | 1 +
arch/parisc/include/asm/Kbuild | 1 +
arch/powerpc/include/asm/Kbuild | 1 +
arch/riscv/include/asm/Kbuild | 1 +
arch/s390/include/asm/Kbuild | 1 +
arch/sh/include/asm/Kbuild | 1 +
arch/sparc/include/asm/Kbuild | 1 +
arch/um/include/asm/Kbuild | 2 +-
arch/x86/Kconfig | 27 +
arch/x86/boot/compressed/ident_map_64.c | 10 +
arch/x86/boot/compressed/pgtable_64.c | 11 +
arch/x86/include/asm/asi.h | 306 +++++++++
arch/x86/include/asm/cpufeatures.h | 1 +
arch/x86/include/asm/disabled-features.h | 8 +-
arch/x86/include/asm/idtentry.h | 50 +-
arch/x86/include/asm/kvm_host.h | 3 +
arch/x86/include/asm/l1tf.h | 11 +
arch/x86/include/asm/nospec-branch.h | 2 +
arch/x86/include/asm/pgalloc.h | 6 +
arch/x86/include/asm/pgtable_64.h | 4 +
arch/x86/include/asm/processor-flags.h | 24 +
arch/x86/include/asm/processor.h | 20 +-
arch/x86/include/asm/pti.h | 6 +-
arch/x86/include/asm/special_insns.h | 45 +-
arch/x86/include/asm/tlbflush.h | 6 +
arch/x86/kernel/process.c | 2 +
arch/x86/kernel/process_32.c | 2 +-
arch/x86/kernel/process_64.c | 2 +-
arch/x86/kernel/traps.c | 22 +
arch/x86/kvm/Kconfig | 1 +
arch/x86/kvm/svm/svm.c | 2 +
arch/x86/kvm/vmx/nested.c | 6 +
arch/x86/kvm/vmx/vmx.c | 113 ++--
arch/x86/kvm/x86.c | 81 ++-
arch/x86/lib/Makefile | 1 +
arch/x86/lib/l1tf.c | 96 +++
arch/x86/lib/retpoline.S | 10 +
arch/x86/mm/Makefile | 1 +
arch/x86/mm/asi.c | 1039 ++++++++++++++++++++++++++++++
arch/x86/mm/fault.c | 124 +++-
arch/x86/mm/init.c | 7 +-
arch/x86/mm/init_64.c | 25 +-
arch/x86/mm/mm_internal.h | 3 +
arch/x86/mm/pti.c | 14 +-
arch/x86/mm/tlb.c | 167 ++++-
arch/x86/virt/svm/sev.c | 2 +-
arch/xtensa/include/asm/Kbuild | 1 +
drivers/firmware/efi/libstub/x86-5lvl.c | 2 +-
include/asm-generic/asi.h | 113 ++++
include/asm-generic/vmlinux.lds.h | 11 +
include/linux/entry-common.h | 11 +
include/linux/gfp.h | 5 +
include/linux/gfp_types.h | 15 +-
include/linux/mm_types.h | 7 +
include/linux/page-flags.h | 18 +
include/linux/pgtable.h | 3 +
include/trace/events/mmflags.h | 12 +-
init/main.c | 2 +
kernel/entry/common.c | 1 +
kernel/fork.c | 5 +
kernel/sched/core.c | 9 +
mm/init-mm.c | 4 +
mm/internal.h | 2 +
mm/mm_init.c | 1 +
mm/page_alloc.c | 160 ++++-
mm/percpu-vm.c | 50 +-
mm/percpu.c | 4 +-
mm/vmalloc.c | 53 +-
tools/perf/builtin-kmem.c | 1 +
80 files changed, 2582 insertions(+), 190 deletions(-)
---
base-commit: ebd6ea9c6976c64ed5af3e6dce672616447e8e62
change-id: 20241115-asi-rfc-v2-5d9bbb441186
Best regards,
--
Brendan Jackman <jackmanb@google.com>
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply [flat|nested] 45+ messages in thread
* [PATCH RFC v2 01/29] mm: asi: Make some utility functions noinstr compatible
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
2025-01-16 0:18 ` Borislav Petkov
2025-01-10 18:40 ` [PATCH RFC v2 02/29] x86: Create CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION Brendan Jackman
` (27 subsequent siblings)
28 siblings, 1 reply; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman
Some existing utility functions would need to be called from a noinstr
context in the later patches. So mark these as either noinstr or
__always_inline.
An earlier version of this by Junaid had a macro that was intended to
tell the compiler "either inline this function, or call it in the
noinstr section", which basically boiled down to:
#define inline_or_noinstr noinline __section(".noinstr.text")
Unfortunately Thomas pointed out this will prevent the function from
being inlined at call sites in .text.
So far I haven't been able[1] to find a formulation that lets us :
1. avoid calls from .noinstr.text -> .text,
2. while also letting the compiler freely decide what to inline.
1 is a functional requirement so here I'm just giving up on 2. Existing
callsites of this code are just forced inline. For the incoming code
that needs to call it from noinstr, they will be out-of-line calls.
[1] https://lore.kernel.org/lkml/CA+i-1C1z35M8wA_4AwMq7--c1OgjNoLGTkn4+Td5gKg7QQAzWw@mail.gmail.com/
Checkpatch-args: --ignore=COMMIT_LOG_LONG_LINE
Signed-off-by: Brendan Jackman <jackmanb@google.com>
---
arch/x86/include/asm/processor.h | 2 +-
arch/x86/include/asm/special_insns.h | 8 ++++----
arch/x86/include/asm/tlbflush.h | 3 +++
arch/x86/mm/tlb.c | 13 +++++++++----
4 files changed, 17 insertions(+), 9 deletions(-)
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 4a686f0e5dbf6d906ed38276148b186e920927b3..1a1b7ea5d7d32a47d783d9d62cd2a53672addd6f 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -220,7 +220,7 @@ void print_cpu_msr(struct cpuinfo_x86 *);
/*
* Friendlier CR3 helpers.
*/
-static inline unsigned long read_cr3_pa(void)
+static __always_inline unsigned long read_cr3_pa(void)
{
return __read_cr3() & CR3_ADDR_MASK;
}
diff --git a/arch/x86/include/asm/special_insns.h b/arch/x86/include/asm/special_insns.h
index aec6e2d3aa1d52e5c8f513e188015a45e9eeaeb2..6e103358966f6f1333aa07be97aec5f8af794120 100644
--- a/arch/x86/include/asm/special_insns.h
+++ b/arch/x86/include/asm/special_insns.h
@@ -42,14 +42,14 @@ static __always_inline void native_write_cr2(unsigned long val)
asm volatile("mov %0,%%cr2": : "r" (val) : "memory");
}
-static inline unsigned long __native_read_cr3(void)
+static __always_inline unsigned long __native_read_cr3(void)
{
unsigned long val;
asm volatile("mov %%cr3,%0\n\t" : "=r" (val) : __FORCE_ORDER);
return val;
}
-static inline void native_write_cr3(unsigned long val)
+static __always_inline void native_write_cr3(unsigned long val)
{
asm volatile("mov %0,%%cr3": : "r" (val) : "memory");
}
@@ -153,12 +153,12 @@ static __always_inline void write_cr2(unsigned long x)
* Careful! CR3 contains more than just an address. You probably want
* read_cr3_pa() instead.
*/
-static inline unsigned long __read_cr3(void)
+static __always_inline unsigned long __read_cr3(void)
{
return __native_read_cr3();
}
-static inline void write_cr3(unsigned long x)
+static __always_inline void write_cr3(unsigned long x)
{
native_write_cr3(x);
}
diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h
index 69e79fff41b800a0a138bcbf548dde9d72993105..c884174a44e119a3c027c44ada6c5cdba14d1282 100644
--- a/arch/x86/include/asm/tlbflush.h
+++ b/arch/x86/include/asm/tlbflush.h
@@ -423,4 +423,7 @@ static inline void __native_tlb_flush_global(unsigned long cr4)
native_write_cr4(cr4 ^ X86_CR4_PGE);
native_write_cr4(cr4);
}
+
+unsigned long build_cr3_noinstr(pgd_t *pgd, u16 asid, unsigned long lam);
+
#endif /* _ASM_X86_TLBFLUSH_H */
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index 86593d1b787d8a5b9fa4bd492356898ec8870938..f0428e5e1f1947903ee87c4c6444844ee11b45c3 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -108,7 +108,7 @@
/*
* Given @asid, compute kPCID
*/
-static inline u16 kern_pcid(u16 asid)
+static __always_inline u16 kern_pcid(u16 asid)
{
VM_WARN_ON_ONCE(asid > MAX_ASID_AVAILABLE);
@@ -153,9 +153,9 @@ static inline u16 user_pcid(u16 asid)
return ret;
}
-static inline unsigned long build_cr3(pgd_t *pgd, u16 asid, unsigned long lam)
+static __always_inline unsigned long build_cr3(pgd_t *pgd, u16 asid, unsigned long lam)
{
- unsigned long cr3 = __sme_pa(pgd) | lam;
+ unsigned long cr3 = __sme_pa_nodebug(pgd) | lam;
if (static_cpu_has(X86_FEATURE_PCID)) {
cr3 |= kern_pcid(asid);
@@ -166,6 +166,11 @@ static inline unsigned long build_cr3(pgd_t *pgd, u16 asid, unsigned long lam)
return cr3;
}
+noinstr unsigned long build_cr3_noinstr(pgd_t *pgd, u16 asid, unsigned long lam)
+{
+ return build_cr3(pgd, asid, lam);
+}
+
static inline unsigned long build_cr3_noflush(pgd_t *pgd, u16 asid,
unsigned long lam)
{
@@ -1084,7 +1089,7 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end)
* It's intended to be used for code like KVM that sneakily changes CR3
* and needs to restore it. It needs to be used very carefully.
*/
-unsigned long __get_current_cr3_fast(void)
+noinstr unsigned long __get_current_cr3_fast(void)
{
unsigned long cr3 =
build_cr3(this_cpu_read(cpu_tlbstate.loaded_mm)->pgd,
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH RFC v2 02/29] x86: Create CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 01/29] mm: asi: Make some utility functions noinstr compatible Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
2025-01-16 16:43 ` Borislav Petkov
2025-03-01 7:23 ` Mike Rapoport
2025-01-10 18:40 ` [PATCH RFC v2 03/29] mm: asi: Introduce ASI core API Brendan Jackman
` (26 subsequent siblings)
28 siblings, 2 replies; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman, Junaid Shahid
Currently a nop config. Keeping as a separate commit for easy review of
the boring bits. Later commits will use and enable this new config.
This config is only added for non-UML x86_64 as other architectures do
not yet have pending implementations. It also has somewhat artificial
dependencies on !PARAVIRT and !KASAN which are explained in the Kconfig
file.
Co-developed-by: Junaid Shahid <junaids@google.com>
Signed-off-by: Junaid Shahid <junaids@google.com>
Signed-off-by: Brendan Jackman <jackmanb@google.com>
---
arch/alpha/include/asm/Kbuild | 1 +
arch/arc/include/asm/Kbuild | 1 +
arch/arm/include/asm/Kbuild | 1 +
arch/arm64/include/asm/Kbuild | 1 +
arch/csky/include/asm/Kbuild | 1 +
arch/hexagon/include/asm/Kbuild | 1 +
arch/loongarch/include/asm/Kbuild | 3 +++
arch/m68k/include/asm/Kbuild | 1 +
arch/microblaze/include/asm/Kbuild | 1 +
arch/mips/include/asm/Kbuild | 1 +
arch/nios2/include/asm/Kbuild | 1 +
arch/openrisc/include/asm/Kbuild | 1 +
arch/parisc/include/asm/Kbuild | 1 +
arch/powerpc/include/asm/Kbuild | 1 +
arch/riscv/include/asm/Kbuild | 1 +
arch/s390/include/asm/Kbuild | 1 +
arch/sh/include/asm/Kbuild | 1 +
arch/sparc/include/asm/Kbuild | 1 +
arch/um/include/asm/Kbuild | 2 +-
arch/x86/Kconfig | 14 ++++++++++++++
arch/xtensa/include/asm/Kbuild | 1 +
include/asm-generic/asi.h | 5 +++++
22 files changed, 41 insertions(+), 1 deletion(-)
diff --git a/arch/alpha/include/asm/Kbuild b/arch/alpha/include/asm/Kbuild
index 396caece6d6d99c7a428f439322a0a18452e1a42..ca72ce3baca13a32913ac9e01a8f86ef42180b1c 100644
--- a/arch/alpha/include/asm/Kbuild
+++ b/arch/alpha/include/asm/Kbuild
@@ -5,3 +5,4 @@ generic-y += agp.h
generic-y += asm-offsets.h
generic-y += kvm_para.h
generic-y += mcs_spinlock.h
+generic-y += asi.h
diff --git a/arch/arc/include/asm/Kbuild b/arch/arc/include/asm/Kbuild
index 49285a3ce2398cc7442bc44172de76367dc33dda..68604480864bbcb58d896da6bdf71591006ab2f6 100644
--- a/arch/arc/include/asm/Kbuild
+++ b/arch/arc/include/asm/Kbuild
@@ -6,3 +6,4 @@ generic-y += kvm_para.h
generic-y += mcs_spinlock.h
generic-y += parport.h
generic-y += user.h
+generic-y += asi.h
diff --git a/arch/arm/include/asm/Kbuild b/arch/arm/include/asm/Kbuild
index 03657ff8fbe3d202563184b8902aa181e7474a5e..1e2c3d8dbbd99bdf95dbc6b47c2c78092c68b808 100644
--- a/arch/arm/include/asm/Kbuild
+++ b/arch/arm/include/asm/Kbuild
@@ -6,3 +6,4 @@ generic-y += parport.h
generated-y += mach-types.h
generated-y += unistd-nr.h
+generic-y += asi.h
diff --git a/arch/arm64/include/asm/Kbuild b/arch/arm64/include/asm/Kbuild
index 4e350df9a02dd8de387b912740af69035da93e34..15f8aaaa96b80b5657b789ecf3529b1f18d16d80 100644
--- a/arch/arm64/include/asm/Kbuild
+++ b/arch/arm64/include/asm/Kbuild
@@ -14,6 +14,7 @@ generic-y += qrwlock.h
generic-y += qspinlock.h
generic-y += parport.h
generic-y += user.h
+generic-y += asi.h
generated-y += cpucap-defs.h
generated-y += sysreg-defs.h
diff --git a/arch/csky/include/asm/Kbuild b/arch/csky/include/asm/Kbuild
index 9a9bc65b57a9d73dadc9d597700d7229f8554ddf..4f497118fb172d1f2bf0f9e472479f24227f42f4 100644
--- a/arch/csky/include/asm/Kbuild
+++ b/arch/csky/include/asm/Kbuild
@@ -11,3 +11,4 @@ generic-y += qspinlock.h
generic-y += parport.h
generic-y += user.h
generic-y += vmlinux.lds.h
+generic-y += asi.h
diff --git a/arch/hexagon/include/asm/Kbuild b/arch/hexagon/include/asm/Kbuild
index 8c1a78c8f5271ebd47f1baad7b85e87220d1bbe8..b26f186bc03c2e135f8d125a4805b95a41513655 100644
--- a/arch/hexagon/include/asm/Kbuild
+++ b/arch/hexagon/include/asm/Kbuild
@@ -5,3 +5,4 @@ generic-y += extable.h
generic-y += iomap.h
generic-y += kvm_para.h
generic-y += mcs_spinlock.h
+generic-y += asi.h
diff --git a/arch/loongarch/include/asm/Kbuild b/arch/loongarch/include/asm/Kbuild
index 5b5a6c90e6e20771b1074a6262230861cc51bcb4..dd3d0c6891369a9dfa35ccfb8b81c8697c2a3e90 100644
--- a/arch/loongarch/include/asm/Kbuild
+++ b/arch/loongarch/include/asm/Kbuild
@@ -11,3 +11,6 @@ generic-y += ioctl.h
generic-y += mmzone.h
generic-y += statfs.h
generic-y += param.h
+generic-y += asi.h
+generic-y += posix_types.h
+generic-y += resource.h
diff --git a/arch/m68k/include/asm/Kbuild b/arch/m68k/include/asm/Kbuild
index 0dbf9c5c6faeb30eeb38bea52ab7fade99bbd44a..faf0f135df4ab946ef115f3a2fc363f370fc7491 100644
--- a/arch/m68k/include/asm/Kbuild
+++ b/arch/m68k/include/asm/Kbuild
@@ -4,3 +4,4 @@ generic-y += extable.h
generic-y += kvm_para.h
generic-y += mcs_spinlock.h
generic-y += spinlock.h
+generic-y += asi.h
diff --git a/arch/microblaze/include/asm/Kbuild b/arch/microblaze/include/asm/Kbuild
index a055f5dbe00a31616592c3a848b49bbf9ead5d17..012e4bf83c13497dc296b66cd5e0fd519274306b 100644
--- a/arch/microblaze/include/asm/Kbuild
+++ b/arch/microblaze/include/asm/Kbuild
@@ -8,3 +8,4 @@ generic-y += parport.h
generic-y += syscalls.h
generic-y += tlb.h
generic-y += user.h
+generic-y += asi.h
diff --git a/arch/mips/include/asm/Kbuild b/arch/mips/include/asm/Kbuild
index 7ba67a0d6c97b2879fb710aca05ae1e2d47c8ce2..3191699298d80735920481eecc64dd2d1dbd2e54 100644
--- a/arch/mips/include/asm/Kbuild
+++ b/arch/mips/include/asm/Kbuild
@@ -13,3 +13,4 @@ generic-y += parport.h
generic-y += qrwlock.h
generic-y += qspinlock.h
generic-y += user.h
+generic-y += asi.h
diff --git a/arch/nios2/include/asm/Kbuild b/arch/nios2/include/asm/Kbuild
index 0d09829ed14454f2f15a32bf713fa1eb213e85ea..03a5ec74e28b3679a5ef7271606af3c07bb7a198 100644
--- a/arch/nios2/include/asm/Kbuild
+++ b/arch/nios2/include/asm/Kbuild
@@ -7,3 +7,4 @@ generic-y += kvm_para.h
generic-y += mcs_spinlock.h
generic-y += spinlock.h
generic-y += user.h
+generic-y += asi.h
diff --git a/arch/openrisc/include/asm/Kbuild b/arch/openrisc/include/asm/Kbuild
index cef49d60d74c0f46f01cf46cc35e1e52404185f3..6a81a58bf59e20cafa563c422df4dfa6f9f791ec 100644
--- a/arch/openrisc/include/asm/Kbuild
+++ b/arch/openrisc/include/asm/Kbuild
@@ -9,3 +9,4 @@ generic-y += spinlock.h
generic-y += qrwlock_types.h
generic-y += qrwlock.h
generic-y += user.h
+generic-y += asi.h
diff --git a/arch/parisc/include/asm/Kbuild b/arch/parisc/include/asm/Kbuild
index 4fb596d94c8932dd1e12a765a21af5b5099fbafd..3cbb4eb14712c7bd6c248dd26ab91cc41da01825 100644
--- a/arch/parisc/include/asm/Kbuild
+++ b/arch/parisc/include/asm/Kbuild
@@ -5,3 +5,4 @@ generic-y += agp.h
generic-y += kvm_para.h
generic-y += mcs_spinlock.h
generic-y += user.h
+generic-y += asi.h
diff --git a/arch/powerpc/include/asm/Kbuild b/arch/powerpc/include/asm/Kbuild
index e5fdc336c9b22527f824ed30d06b5e8c0fa8a1ef..e86cc027f35564c7b301c283043bde0e5d2d3b6a 100644
--- a/arch/powerpc/include/asm/Kbuild
+++ b/arch/powerpc/include/asm/Kbuild
@@ -7,3 +7,4 @@ generic-y += kvm_types.h
generic-y += mcs_spinlock.h
generic-y += qrwlock.h
generic-y += early_ioremap.h
+generic-y += asi.h
diff --git a/arch/riscv/include/asm/Kbuild b/arch/riscv/include/asm/Kbuild
index 1461af12da6e2bbbff6cf737a7babf33bd298cdd..82060ed50d9beb1ea72d3570ad236d1e08d9d8c6 100644
--- a/arch/riscv/include/asm/Kbuild
+++ b/arch/riscv/include/asm/Kbuild
@@ -13,3 +13,4 @@ generic-y += qrwlock.h
generic-y += qrwlock_types.h
generic-y += user.h
generic-y += vmlinux.lds.h
+generic-y += asi.h
diff --git a/arch/s390/include/asm/Kbuild b/arch/s390/include/asm/Kbuild
index 297bf7157968907d6e4c4ff8b65deeef02dbd630..e15c2a138392b57b186633738ddda913474aa8c4 100644
--- a/arch/s390/include/asm/Kbuild
+++ b/arch/s390/include/asm/Kbuild
@@ -8,3 +8,4 @@ generic-y += asm-offsets.h
generic-y += kvm_types.h
generic-y += mcs_spinlock.h
generic-y += mmzone.h
+generic-y += asi.h
diff --git a/arch/sh/include/asm/Kbuild b/arch/sh/include/asm/Kbuild
index fc44d9c88b41915a7021042eb8b462517cfdbd2c..ea19e4515828552f436d67f764607dd5d15cb19f 100644
--- a/arch/sh/include/asm/Kbuild
+++ b/arch/sh/include/asm/Kbuild
@@ -3,3 +3,4 @@ generated-y += syscall_table.h
generic-y += kvm_para.h
generic-y += mcs_spinlock.h
generic-y += parport.h
+generic-y += asi.h
diff --git a/arch/sparc/include/asm/Kbuild b/arch/sparc/include/asm/Kbuild
index 43b0ae4c2c2112d4d4d3cb3c60e787b175172dea..cb9062c9be17fe276cc92d2ac99d8b165f6297bf 100644
--- a/arch/sparc/include/asm/Kbuild
+++ b/arch/sparc/include/asm/Kbuild
@@ -4,3 +4,4 @@ generated-y += syscall_table_64.h
generic-y += agp.h
generic-y += kvm_para.h
generic-y += mcs_spinlock.h
+generic-y += asi.h
diff --git a/arch/um/include/asm/Kbuild b/arch/um/include/asm/Kbuild
index 18f902da8e99769da857d34af43141ea97a0ca63..6054972f1babdaebae64040b05ab48893915cb04 100644
--- a/arch/um/include/asm/Kbuild
+++ b/arch/um/include/asm/Kbuild
@@ -27,4 +27,4 @@ generic-y += trace_clock.h
generic-y += kprobes.h
generic-y += mm_hooks.h
generic-y += vga.h
-generic-y += video.h
+generic-y += asi.h
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 7b9a7e8f39acc8e9aeb7d4213e87d71047865f5c..5a50582eb210e9d1309856a737d32b76fa1bfc85 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2519,6 +2519,20 @@ config MITIGATION_PAGE_TABLE_ISOLATION
See Documentation/arch/x86/pti.rst for more details.
+config MITIGATION_ADDRESS_SPACE_ISOLATION
+ bool "Allow code to run with a reduced kernel address space"
+ default n
+ depends on X86_64 && !PARAVIRT && !UML
+ help
+ This feature provides the ability to run some kernel code
+ with a reduced kernel address space. This can be used to
+ mitigate some speculative execution attacks.
+
+ The !PARAVIRT dependency is only because of lack of testing; in theory
+ the code is written to work under paravirtualization. In practice
+ there are likely to be unhandled cases, in particular concerning TLB
+ flushes.
+
config MITIGATION_RETPOLINE
bool "Avoid speculative indirect branches in kernel"
select OBJTOOL if HAVE_OBJTOOL
diff --git a/arch/xtensa/include/asm/Kbuild b/arch/xtensa/include/asm/Kbuild
index fa07c686cbcc2153776a478ac4093846f01eddab..07cea6902f98053be244d026ed594fe7246755a6 100644
--- a/arch/xtensa/include/asm/Kbuild
+++ b/arch/xtensa/include/asm/Kbuild
@@ -8,3 +8,4 @@ generic-y += parport.h
generic-y += qrwlock.h
generic-y += qspinlock.h
generic-y += user.h
+generic-y += asi.h
diff --git a/include/asm-generic/asi.h b/include/asm-generic/asi.h
new file mode 100644
index 0000000000000000000000000000000000000000..c4d9a5ff860a96428422a15000c622aeecc2d664
--- /dev/null
+++ b/include/asm-generic/asi.h
@@ -0,0 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_GENERIC_ASI_H
+#define __ASM_GENERIC_ASI_H
+
+#endif
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH RFC v2 03/29] mm: asi: Introduce ASI core API
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 01/29] mm: asi: Make some utility functions noinstr compatible Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 02/29] x86: Create CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
2025-02-19 10:55 ` Borislav Petkov
2025-01-10 18:40 ` [PATCH RFC v2 04/29] mm: asi: Add infrastructure for boot-time enablement Brendan Jackman
` (25 subsequent siblings)
28 siblings, 1 reply; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman, Ofir Weisse, Junaid Shahid
Introduce core API for Address Space Isolation (ASI). Kernel address
space isolation provides the ability to run some kernel
code with a restricted kernel address space.
There can be multiple classes of such restricted kernel address spaces
(e.g. KPTI, KVM-PTI etc.). Each ASI class is identified by an index.
The ASI class can register some hooks to be called when
entering/exiting the restricted address space.
Currently, there is a fixed maximum number of ASI classes supported.
In addition, each process can have at most one restricted address space
from each ASI class. Neither of these are inherent limitations and
are merely simplifying assumptions for the time being.
To keep things simpler for the time being, we disallow context switches
within the restricted address space. In the future, we would be able to
relax this limitation for the case of context switches to different
threads within the same process (or to the idle thread and back).
Note that this doesn't really support protecting sibling VM guests
within the same VMM process from one another. From first principles
it seems unlikely that anyone who cares about VM isolation would do
that, but there could be a use-case to think about. In that case need
something like the OTHER_MM logic might be needed, but specific to
intra-process guest separation.
[0]:
https://lore.kernel.org/kvm/1562855138-19507-1-git-send-email-alexandre.chartre@oracle.com
Notes about RFC-quality implementation details:
- Ignoring checkpatch.pl AVOID_BUG.
- The dynamic registration of classes might be pointless complexity.
This was kept from RFCv1 without much thought.
- The other-mm logic is also perhaps overly complex, suggestions are
welcome for how best to tackle this (or we could just forget about
it for the moment, and rely on asi_exit() happening in process
switch).
- The taint flag definitions would probably be clearer with an enum or
something.
Checkpatch-args: --ignore=AVOID_BUG,COMMIT_LOG_LONG_LINE,EXPORT_SYMBOL
Co-developed-by: Ofir Weisse <oweisse@google.com>
Signed-off-by: Ofir Weisse <oweisse@google.com>
Co-developed-by: Junaid Shahid <junaids@google.com>
Signed-off-by: Junaid Shahid <junaids@google.com>
Signed-off-by: Brendan Jackman <jackmanb@google.com>
---
arch/x86/include/asm/asi.h | 208 +++++++++++++++++++++++
arch/x86/include/asm/processor.h | 8 +
arch/x86/mm/Makefile | 1 +
arch/x86/mm/asi.c | 350 +++++++++++++++++++++++++++++++++++++++
arch/x86/mm/init.c | 3 +-
arch/x86/mm/tlb.c | 1 +
include/asm-generic/asi.h | 67 ++++++++
include/linux/mm_types.h | 7 +
kernel/fork.c | 3 +
kernel/sched/core.c | 9 +
mm/init-mm.c | 4 +
11 files changed, 660 insertions(+), 1 deletion(-)
diff --git a/arch/x86/include/asm/asi.h b/arch/x86/include/asm/asi.h
new file mode 100644
index 0000000000000000000000000000000000000000..7cc635b6653a3970ba9dbfdc9c828a470e27bd44
--- /dev/null
+++ b/arch/x86/include/asm/asi.h
@@ -0,0 +1,208 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_ASI_H
+#define _ASM_X86_ASI_H
+
+#include <linux/sched.h>
+
+#include <asm-generic/asi.h>
+
+#include <asm/pgtable_types.h>
+#include <asm/percpu.h>
+#include <asm/processor.h>
+
+#ifdef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
+
+/*
+ * Overview of API usage by ASI clients:
+ *
+ * Setup: First call asi_init() to create a domain. At present only one domain
+ * can be created per mm per class, but it's safe to asi_init() this domain
+ * multiple times. For each asi_init() call you must call asi_destroy() AFTER
+ * you are certain all CPUs have exited the restricted address space (by
+ * calling asi_exit()).
+ *
+ * Runtime usage:
+ *
+ * 1. Call asi_enter() to switch to the restricted address space. This can't be
+ * from an interrupt or exception handler and preemption must be disabled.
+ *
+ * 2. Execute untrusted code.
+ *
+ * 3. Call asi_relax() to inform the ASI subsystem that untrusted code execution
+ * is finished. This doesn't cause any address space change. This can't be
+ * from an interrupt or exception handler and preemption must be disabled.
+ *
+ * 4. Either:
+ *
+ * a. Go back to 1.
+ *
+ * b. Call asi_exit() before returning to userspace. This immediately
+ * switches to the unrestricted address space.
+ *
+ * The region between 1 and 3 is called the "ASI critical section". During the
+ * critical section, it is a bug to access any sensitive data, and you mustn't
+ * sleep.
+ *
+ * The restriction on sleeping is not really a fundamental property of ASI.
+ * However for performance reasons it's important that the critical section is
+ * absolutely as short as possible. So the ability to do sleepy things like
+ * taking mutexes oughtn't to confer any convenience on API users.
+ *
+ * Similarly to the issue of sleeping, the need to asi_exit in case 4b is not a
+ * fundamental property of the system but a limitation of the current
+ * implementation. With further work it is possible to context switch
+ * from and/or to the restricted address space, and to return to userspace
+ * directly from the restricted address space, or _in_ it.
+ *
+ * Note that the critical section only refers to the direct execution path from
+ * asi_enter to asi_relax: it's fine to access sensitive data from exceptions
+ * and interrupt handlers that occur during that time. ASI will re-enter the
+ * restricted address space before returning from the outermost
+ * exception/interrupt.
+ *
+ * Note: ASI does not modify KPTI behaviour; when ASI and KPTI run together
+ * there are 2+N address spaces per task: the unrestricted kernel address space,
+ * the user address space, and one restricted (kernel) address space for each of
+ * the N ASI classes.
+ */
+
+/*
+ * ASI uses a per-CPU tainting model to track what mitigation actions are
+ * required on domain transitions. Taints exist along two dimensions:
+ *
+ * - Who touched the CPU (guest, unprotected kernel, userspace).
+ *
+ * - What kind of state might remain: "data" means there might be data owned by
+ * a victim domain left behind in a sidechannel. "Control" means there might
+ * be state controlled by an attacker domain left behind in the branch
+ * predictor.
+ *
+ * In principle the same domain can be both attacker and victim, thus we have
+ * both data and control taints for userspace, although there's no point in
+ * trying to protect against attacks from the kernel itself, so there's no
+ * ASI_TAINT_KERNEL_CONTROL.
+ */
+#define ASI_TAINT_KERNEL_DATA ((asi_taints_t)BIT(0))
+#define ASI_TAINT_USER_DATA ((asi_taints_t)BIT(1))
+#define ASI_TAINT_GUEST_DATA ((asi_taints_t)BIT(2))
+#define ASI_TAINT_OTHER_MM_DATA ((asi_taints_t)BIT(3))
+#define ASI_TAINT_USER_CONTROL ((asi_taints_t)BIT(4))
+#define ASI_TAINT_GUEST_CONTROL ((asi_taints_t)BIT(5))
+#define ASI_TAINT_OTHER_MM_CONTROL ((asi_taints_t)BIT(6))
+#define ASI_NUM_TAINTS 6
+static_assert(BITS_PER_BYTE * sizeof(asi_taints_t) >= ASI_NUM_TAINTS);
+
+#define ASI_TAINTS_CONTROL_MASK \
+ (ASI_TAINT_USER_CONTROL | ASI_TAINT_GUEST_CONTROL | ASI_TAINT_OTHER_MM_CONTROL)
+
+#define ASI_TAINTS_DATA_MASK \
+ (ASI_TAINT_KERNEL_DATA | ASI_TAINT_USER_DATA | ASI_TAINT_OTHER_MM_DATA)
+
+#define ASI_TAINTS_GUEST_MASK (ASI_TAINT_GUEST_DATA | ASI_TAINT_GUEST_CONTROL)
+#define ASI_TAINTS_USER_MASK (ASI_TAINT_USER_DATA | ASI_TAINT_USER_CONTROL)
+
+/* The taint policy tells ASI how a class interacts with the CPU taints */
+struct asi_taint_policy {
+ /*
+ * What taints would necessitate a flush when entering the domain, to
+ * protect it from attack by prior domains?
+ */
+ asi_taints_t prevent_control;
+ /*
+ * What taints would necessetate a flush when entering the domain, to
+ * protect former domains from attack by this domain?
+ */
+ asi_taints_t protect_data;
+ /* What taints should be set when entering the domain? */
+ asi_taints_t set;
+};
+
+/*
+ * An ASI domain (struct asi) represents a restricted address space. The
+ * unrestricted address space (and user address space under PTI) are not
+ * represented as a domain.
+ */
+struct asi {
+ pgd_t *pgd;
+ struct mm_struct *mm;
+ int64_t ref_count;
+ enum asi_class_id class_id;
+};
+
+DECLARE_PER_CPU_ALIGNED(struct asi *, curr_asi);
+
+void asi_init_mm_state(struct mm_struct *mm);
+
+int asi_init_class(enum asi_class_id class_id, struct asi_taint_policy *taint_policy);
+void asi_uninit_class(enum asi_class_id class_id);
+const char *asi_class_name(enum asi_class_id class_id);
+
+int asi_init(struct mm_struct *mm, enum asi_class_id class_id, struct asi **out_asi);
+void asi_destroy(struct asi *asi);
+
+/* Enter an ASI domain (restricted address space) and begin the critical section. */
+void asi_enter(struct asi *asi);
+
+/*
+ * Leave the "tense" state if we are in it, i.e. end the critical section. We
+ * will stay relaxed until the next asi_enter.
+ */
+void asi_relax(void);
+
+/* Immediately exit the restricted address space if in it */
+void asi_exit(void);
+
+/* The target is the domain we'll enter when returning to process context. */
+static __always_inline struct asi *asi_get_target(struct task_struct *p)
+{
+ return p->thread.asi_state.target;
+}
+
+static __always_inline void asi_set_target(struct task_struct *p,
+ struct asi *target)
+{
+ p->thread.asi_state.target = target;
+}
+
+static __always_inline struct asi *asi_get_current(void)
+{
+ return this_cpu_read(curr_asi);
+}
+
+/* Are we currently in a restricted address space? */
+static __always_inline bool asi_is_restricted(void)
+{
+ return (bool)asi_get_current();
+}
+
+/* If we exit/have exited, can we stay that way until the next asi_enter? */
+static __always_inline bool asi_is_relaxed(void)
+{
+ return !asi_get_target(current);
+}
+
+/*
+ * Is the current task in the critical section?
+ *
+ * This is just the inverse of !asi_is_relaxed(). We have both functions in order to
+ * help write intuitive client code. In particular, asi_is_tense returns false
+ * when ASI is disabled, which is judged to make user code more obvious.
+ */
+static __always_inline bool asi_is_tense(void)
+{
+ return !asi_is_relaxed();
+}
+
+static __always_inline pgd_t *asi_pgd(struct asi *asi)
+{
+ return asi ? asi->pgd : NULL;
+}
+
+#define INIT_MM_ASI(init_mm) \
+ .asi_init_lock = __MUTEX_INITIALIZER(init_mm.asi_init_lock),
+
+void asi_handle_switch_mm(void);
+
+#endif /* CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION */
+
+#endif
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 1a1b7ea5d7d32a47d783d9d62cd2a53672addd6f..f02220e6b4df911d87e2fee4b497eade61a27161 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -5,6 +5,7 @@
#include <asm/processor-flags.h>
/* Forward declaration, a strange C thing */
+struct asi;
struct task_struct;
struct mm_struct;
struct io_bitmap;
@@ -503,6 +504,13 @@ struct thread_struct {
struct thread_shstk shstk;
#endif
+#ifdef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
+ struct {
+ /* Domain to enter when returning to process context. */
+ struct asi *target;
+ } asi_state;
+#endif
+
/* Floating point and extended processor state */
struct fpu fpu;
/*
diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile
index 690fbf48e8538b62a176ce838820e363575b7897..89ade7363798cc20d5e5643526eba7378174baa0 100644
--- a/arch/x86/mm/Makefile
+++ b/arch/x86/mm/Makefile
@@ -61,6 +61,7 @@ obj-$(CONFIG_ACPI_NUMA) += srat.o
obj-$(CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS) += pkeys.o
obj-$(CONFIG_RANDOMIZE_MEMORY) += kaslr.o
obj-$(CONFIG_MITIGATION_PAGE_TABLE_ISOLATION) += pti.o
+obj-$(CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION) += asi.o
obj-$(CONFIG_X86_MEM_ENCRYPT) += mem_encrypt.o
obj-$(CONFIG_AMD_MEM_ENCRYPT) += mem_encrypt_amd.o
diff --git a/arch/x86/mm/asi.c b/arch/x86/mm/asi.c
new file mode 100644
index 0000000000000000000000000000000000000000..105cd8b43eaf5c20acc80d4916b761559fb95d74
--- /dev/null
+++ b/arch/x86/mm/asi.c
@@ -0,0 +1,350 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/compiler_types.h>
+#include <linux/export.h>
+#include <linux/percpu.h>
+#include <linux/spinlock.h>
+
+#include <asm/asi.h>
+#include <asm/cmdline.h>
+#include <asm/cpufeature.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+#include <asm/mmu_context.h>
+
+static struct asi_taint_policy *taint_policies[ASI_MAX_NUM_CLASSES];
+
+const char *asi_class_names[] = {
+#if IS_ENABLED(CONFIG_KVM)
+ [ASI_CLASS_KVM] = "KVM",
+#endif
+};
+
+DEFINE_PER_CPU_ALIGNED(struct asi *, curr_asi);
+EXPORT_SYMBOL(curr_asi);
+
+static inline bool asi_class_id_valid(enum asi_class_id class_id)
+{
+ return class_id >= 0 && class_id < ASI_MAX_NUM_CLASSES;
+}
+
+static inline bool asi_class_initialized(enum asi_class_id class_id)
+{
+ if (WARN_ON(!asi_class_id_valid(class_id)))
+ return false;
+
+ return !!(taint_policies[class_id]);
+}
+
+int asi_init_class(enum asi_class_id class_id, struct asi_taint_policy *taint_policy)
+{
+ if (asi_class_initialized(class_id))
+ return -EEXIST;
+
+ WARN_ON(!(taint_policy->prevent_control & ASI_TAINTS_CONTROL_MASK));
+ WARN_ON(!(taint_policy->protect_data & ASI_TAINTS_DATA_MASK));
+
+ taint_policies[class_id] = taint_policy;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(asi_init_class);
+
+void asi_uninit_class(enum asi_class_id class_id)
+{
+ if (!asi_class_initialized(class_id))
+ return;
+
+ taint_policies[class_id] = NULL;
+}
+EXPORT_SYMBOL_GPL(asi_uninit_class);
+
+const char *asi_class_name(enum asi_class_id class_id)
+{
+ if (WARN_ON_ONCE(!asi_class_id_valid(class_id)))
+ return "<invalid>";
+
+ return asi_class_names[class_id];
+}
+
+static void __asi_destroy(struct asi *asi)
+{
+ lockdep_assert_held(&asi->mm->asi_init_lock);
+
+}
+
+int asi_init(struct mm_struct *mm, enum asi_class_id class_id, struct asi **out_asi)
+{
+ struct asi *asi;
+ int err = 0;
+
+ *out_asi = NULL;
+
+ if (WARN_ON(!asi_class_initialized(class_id)))
+ return -EINVAL;
+
+ asi = &mm->asi[class_id];
+
+ mutex_lock(&mm->asi_init_lock);
+
+ if (asi->ref_count++ > 0)
+ goto exit_unlock; /* err is 0 */
+
+ BUG_ON(asi->pgd != NULL);
+
+ /*
+ * For now, we allocate 2 pages to avoid any potential problems with
+ * KPTI code. This won't be needed once KPTI is folded into the ASI
+ * framework.
+ */
+ asi->pgd = (pgd_t *)__get_free_pages(
+ GFP_KERNEL_ACCOUNT | __GFP_ZERO, PGD_ALLOCATION_ORDER);
+ if (!asi->pgd) {
+ err = -ENOMEM;
+ goto exit_unlock;
+ }
+
+ asi->mm = mm;
+ asi->class_id = class_id;
+
+exit_unlock:
+ if (err)
+ __asi_destroy(asi);
+ else
+ *out_asi = asi;
+
+ mutex_unlock(&mm->asi_init_lock);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(asi_init);
+
+void asi_destroy(struct asi *asi)
+{
+ struct mm_struct *mm;
+
+ if (!asi)
+ return;
+
+ if (WARN_ON(!asi_class_initialized(asi->class_id)))
+ return;
+
+ mm = asi->mm;
+ /*
+ * We would need this mutex even if the refcount was atomic as we need
+ * to block concurrent asi_init calls.
+ */
+ mutex_lock(&mm->asi_init_lock);
+ WARN_ON_ONCE(asi->ref_count <= 0);
+ if (--(asi->ref_count) == 0) {
+ free_pages((ulong)asi->pgd, PGD_ALLOCATION_ORDER);
+ memset(asi, 0, sizeof(struct asi));
+ }
+ mutex_unlock(&mm->asi_init_lock);
+}
+EXPORT_SYMBOL_GPL(asi_destroy);
+
+DEFINE_PER_CPU_ALIGNED(asi_taints_t, asi_taints);
+
+/*
+ * Flush out any potentially malicious speculative control flow (e.g. branch
+ * predictor) state if necessary when we are entering a new domain (which may be
+ * NULL when we are exiting to the restricted address space).
+ *
+ * This is "backwards-looking" mitigation, the attacker is in the past: we want
+ * then when logically transitioning from A to B and B doesn't trust A.
+ *
+ * This function must tolerate reentrancy.
+ */
+static __always_inline void maybe_flush_control(struct asi *next_asi)
+{
+ asi_taints_t taints = this_cpu_read(asi_taints);
+
+ if (next_asi) {
+ taints &= taint_policies[next_asi->class_id]->prevent_control;
+ } else {
+ /*
+ * Going to the unrestricted address space, this has an implicit
+ * policy of flushing all taints.
+ */
+ taints &= ASI_TAINTS_CONTROL_MASK;
+ }
+
+ if (!taints)
+ return;
+
+ /*
+ * This is where we'll do the actual dirty work of clearing uarch state.
+ * For now we just pretend, clear the taints.
+ */
+ this_cpu_and(asi_taints, ~ASI_TAINTS_CONTROL_MASK);
+}
+
+/*
+ * Flush out any data that might be hanging around in uarch state that can be
+ * leaked through sidechannels if necessary when we are entering a new domain.
+ *
+ * This is "forwards-looking" mitigation, the attacker is in the future: we want
+ * this when logically transitioning from A to B and A doesn't trust B.
+ *
+ * This function must tolerate reentrancy.
+ */
+static __always_inline void maybe_flush_data(struct asi *next_asi)
+{
+ asi_taints_t taints = this_cpu_read(asi_taints)
+ & taint_policies[next_asi->class_id]->protect_data;
+
+ if (!taints)
+ return;
+
+ /*
+ * This is where we'll do the actual dirty work of clearing uarch state.
+ * For now we just pretend, clear the taints.
+ */
+ this_cpu_and(asi_taints, ~ASI_TAINTS_DATA_MASK);
+}
+
+static noinstr void __asi_enter(void)
+{
+ u64 asi_cr3;
+ struct asi *target = asi_get_target(current);
+
+ /*
+ * This is actually false restriction, it should be fine to be
+ * preemptible during the critical section. But we haven't tested it. We
+ * will also need to disable preemption during this function itself and
+ * perhaps elsewhere. This false restriction shouldn't create any
+ * additional burden for ASI clients anyway: the critical section has
+ * to be as short as possible to avoid unnecessary ASI transitions so
+ * disabling preemption should be fine.
+ */
+ VM_BUG_ON(preemptible());
+
+ if (!target || target == this_cpu_read(curr_asi))
+ return;
+
+ VM_BUG_ON(this_cpu_read(cpu_tlbstate.loaded_mm) ==
+ LOADED_MM_SWITCHING);
+
+ /*
+ * Must update curr_asi before writing CR3 to ensure an interrupting
+ * asi_exit sees that it may need to switch address spaces.
+ * This is the real beginning of the ASI critical section.
+ */
+ this_cpu_write(curr_asi, target);
+ maybe_flush_control(target);
+
+ asi_cr3 = build_cr3_noinstr(target->pgd,
+ this_cpu_read(cpu_tlbstate.loaded_mm_asid),
+ tlbstate_lam_cr3_mask());
+ write_cr3(asi_cr3);
+
+ maybe_flush_data(target);
+ /*
+ * It's fine to set the control taints late like this, since we haven't
+ * actually got to the untrusted code yet. Waiting until now to set the
+ * data taints is less obviously correct: we've mapped in the incoming
+ * domain's secrets now so we can't guarantee they haven't already got
+ * into a sidechannel. However, preemption is off so the only way we can
+ * reach another asi_enter() is in the return from an interrupt - in
+ * that case the reentrant asi_enter() call is entering the same domain
+ * that we're entering at the moment, it doesn't need to flush those
+ * secrets.
+ */
+ this_cpu_or(asi_taints, taint_policies[target->class_id]->set);
+}
+
+noinstr void asi_enter(struct asi *asi)
+{
+ VM_WARN_ON_ONCE(!asi);
+
+ /* Should not have an asi_enter() without a prior asi_relax(). */
+ VM_WARN_ON_ONCE(asi_get_target(current));
+
+ asi_set_target(current, asi);
+ barrier();
+
+ __asi_enter();
+}
+EXPORT_SYMBOL_GPL(asi_enter);
+
+noinstr void asi_relax(void)
+{
+ barrier();
+ asi_set_target(current, NULL);
+}
+EXPORT_SYMBOL_GPL(asi_relax);
+
+noinstr void asi_exit(void)
+{
+ u64 unrestricted_cr3;
+ struct asi *asi;
+
+ preempt_disable_notrace();
+
+ VM_BUG_ON(this_cpu_read(cpu_tlbstate.loaded_mm) ==
+ LOADED_MM_SWITCHING);
+
+ asi = this_cpu_read(curr_asi);
+ if (asi) {
+ maybe_flush_control(NULL);
+
+ unrestricted_cr3 =
+ build_cr3_noinstr(this_cpu_read(cpu_tlbstate.loaded_mm)->pgd,
+ this_cpu_read(cpu_tlbstate.loaded_mm_asid),
+ tlbstate_lam_cr3_mask());
+
+ /* Tainting first makes reentrancy easier to reason about. */
+ this_cpu_or(asi_taints, ASI_TAINT_KERNEL_DATA);
+ write_cr3(unrestricted_cr3);
+ /*
+ * Must not update curr_asi until after CR3 write, otherwise a
+ * re-entrant call might not enter this branch. (This means we
+ * might do unnecessary CR3 writes).
+ */
+ this_cpu_write(curr_asi, NULL);
+ }
+
+ preempt_enable_notrace();
+}
+EXPORT_SYMBOL_GPL(asi_exit);
+
+void asi_init_mm_state(struct mm_struct *mm)
+{
+ memset(mm->asi, 0, sizeof(mm->asi));
+ mutex_init(&mm->asi_init_lock);
+}
+
+void asi_handle_switch_mm(void)
+{
+ /*
+ * We can't handle context switching in the restricted address space yet
+ * so this is pointless in practice (we asi_exit() in this path, which
+ * doesn't care about the fine details of who exactly got at the branch
+ * predictor), but just to illustrate how the tainting model is supposed
+ * to work, here we squash the per-domain (guest/userspace) taints into
+ * a general "other MM" taint. Other processes don't care if their peers
+ * are attacking them from a guest or from bare metal.
+ */
+ asi_taints_t taints = this_cpu_read(asi_taints);
+ asi_taints_t new_taints = 0;
+
+ if (taints & ASI_TAINTS_CONTROL_MASK)
+ new_taints |= ASI_TAINT_OTHER_MM_CONTROL;
+ if (taints & ASI_TAINTS_DATA_MASK)
+ new_taints |= ASI_TAINT_OTHER_MM_DATA;
+
+ /*
+ * We can't race with asi_enter() or we'd clobber the taint it sets.
+ * Would be odd given this function says context_switch in the name but
+ * just be to sure...
+ */
+ lockdep_assert_preemption_disabled();
+
+ /*
+ * Can'tt just this_cpu_write here as we could be racing with asi_exit()
+ * (at least, in the future where this function is actually necessary),
+ * we mustn't clobber ASI_TAINT_KERNEL_DATA.
+ */
+ this_cpu_or(asi_taints, new_taints);
+ this_cpu_and(asi_taints, ~(ASI_TAINTS_GUEST_MASK | ASI_TAINTS_USER_MASK));
+}
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index eb503f53c3195ca4f299593c0112dab0fb09e7dd..de4227ed5169ff84d0ce80b677caffc475198fa6 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -250,7 +250,8 @@ static void __init probe_page_size_mask(void)
/* By the default is everything supported: */
__default_kernel_pte_mask = __supported_pte_mask;
/* Except when with PTI where the kernel is mostly non-Global: */
- if (cpu_feature_enabled(X86_FEATURE_PTI))
+ if (cpu_feature_enabled(X86_FEATURE_PTI) ||
+ IS_ENABLED(CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION))
__default_kernel_pte_mask &= ~_PAGE_GLOBAL;
/* Enable 1 GB linear kernel mappings if available: */
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index f0428e5e1f1947903ee87c4c6444844ee11b45c3..7c2309996d1d5a7cac23bd122f7b56a869d67d6a 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -608,6 +608,7 @@ void switch_mm_irqs_off(struct mm_struct *unused, struct mm_struct *next,
* Apply process to process speculation vulnerability
* mitigations if applicable.
*/
+ asi_handle_switch_mm();
cond_mitigation(tsk);
/*
diff --git a/include/asm-generic/asi.h b/include/asm-generic/asi.h
index c4d9a5ff860a96428422a15000c622aeecc2d664..6b84202837605fa57e4a910318c8353b3f816f06 100644
--- a/include/asm-generic/asi.h
+++ b/include/asm-generic/asi.h
@@ -2,4 +2,71 @@
#ifndef __ASM_GENERIC_ASI_H
#define __ASM_GENERIC_ASI_H
+#include <linux/types.h>
+
+#ifndef _ASSEMBLY_
+
+/*
+ * An ASI class is a type of isolation that can be applied to a process. A
+ * process may have a domain for each class.
+ */
+enum asi_class_id {
+#if IS_ENABLED(CONFIG_KVM)
+ ASI_CLASS_KVM,
+#endif
+ ASI_MAX_NUM_CLASSES,
+};
+
+typedef u8 asi_taints_t;
+
+#ifndef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
+
+struct asi_hooks {};
+struct asi {};
+
+static inline
+int asi_init_class(enum asi_class_id class_id,
+ asi_taints_t control_taints, asi_taints_t data_taints)
+{
+ return 0;
+}
+
+static inline void asi_uninit_class(enum asi_class_id class_id) { }
+
+struct mm_struct;
+static inline void asi_init_mm_state(struct mm_struct *mm) { }
+
+static inline int asi_init(struct mm_struct *mm, enum asi_class_id class_id,
+ struct asi **out_asi)
+{
+ return 0;
+}
+
+static inline void asi_destroy(struct asi *asi) { }
+
+static inline void asi_enter(struct asi *asi) { }
+
+static inline void asi_relax(void) { }
+
+static inline bool asi_is_relaxed(void) { return true; }
+
+static inline bool asi_is_tense(void) { return false; }
+
+static inline void asi_exit(void) { }
+
+static inline bool asi_is_restricted(void) { return false; }
+
+static inline struct asi *asi_get_current(void) { return NULL; }
+
+struct task_struct;
+static inline struct asi *asi_get_target(struct task_struct *p) { return NULL; }
+
+static inline pgd_t *asi_pgd(struct asi *asi) { return NULL; }
+
+static inline void asi_handle_switch_mm(void) { }
+
+#endif /* !CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION */
+
+#endif /* !_ASSEMBLY_ */
+
#endif
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 6e3bdf8e38bcaee66a71f5566ac7debb94c0ee78..391e32a41ca3df84a619f3ee8ea45d3729a43023 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -19,8 +19,10 @@
#include <linux/workqueue.h>
#include <linux/seqlock.h>
#include <linux/percpu_counter.h>
+#include <linux/mutex.h>
#include <asm/mmu.h>
+#include <asm/asi.h>
#ifndef AT_VECTOR_SIZE_ARCH
#define AT_VECTOR_SIZE_ARCH 0
@@ -826,6 +828,11 @@ struct mm_struct {
atomic_t membarrier_state;
#endif
+#ifdef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
+ struct asi asi[ASI_MAX_NUM_CLASSES];
+ struct mutex asi_init_lock;
+#endif
+
/**
* @mm_users: The number of users including userspace.
*
diff --git a/kernel/fork.c b/kernel/fork.c
index 22f43721d031d48fd5be2606e86642334be9735f..bb73758790d08112265d398b16902ff9a4c2b8fe 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -112,6 +112,7 @@
#include <asm/mmu_context.h>
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
+#include <asm/asi.h>
#include <trace/events/sched.h>
@@ -1296,6 +1297,8 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p,
if (mm_alloc_pgd(mm))
goto fail_nopgd;
+ asi_init_mm_state(mm);
+
if (init_new_context(p, mm))
goto fail_nocontext;
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index a1c353a62c5684e3e773dd100afbddb818c480be..b1f7f73730c1e56f700cd3611a8093f177184842 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -78,6 +78,7 @@
#include <asm/irq_regs.h>
#include <asm/switch_to.h>
#include <asm/tlb.h>
+#include <asm/asi.h>
#define CREATE_TRACE_POINTS
#include <linux/sched/rseq_api.h>
@@ -5272,6 +5273,14 @@ static __always_inline struct rq *
context_switch(struct rq *rq, struct task_struct *prev,
struct task_struct *next, struct rq_flags *rf)
{
+ /*
+ * It's possible to avoid this by tweaking ASI's domain management code
+ * and updating code that modifies CR3 to be ASI-aware. Even without
+ * that, it's probably possible to get rid of this in certain cases just
+ * by fiddling with the context switch path itself.
+ */
+ asi_exit();
+
prepare_task_switch(rq, prev, next);
/*
diff --git a/mm/init-mm.c b/mm/init-mm.c
index 24c809379274503ac4f261fe7cfdbab3cb1ed1e7..e820e1c6edd48836a0ebe58e777046498d6a89ee 100644
--- a/mm/init-mm.c
+++ b/mm/init-mm.c
@@ -12,6 +12,7 @@
#include <linux/user_namespace.h>
#include <linux/iommu.h>
#include <asm/mmu.h>
+#include <asm/asi.h>
#ifndef INIT_MM_CONTEXT
#define INIT_MM_CONTEXT(name)
@@ -44,6 +45,9 @@ struct mm_struct init_mm = {
#endif
.user_ns = &init_user_ns,
.cpu_bitmap = CPU_BITS_NONE,
+#ifdef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
+ INIT_MM_ASI(init_mm)
+#endif
INIT_MM_CONTEXT(init_mm)
};
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH RFC v2 04/29] mm: asi: Add infrastructure for boot-time enablement
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
` (2 preceding siblings ...)
2025-01-10 18:40 ` [PATCH RFC v2 03/29] mm: asi: Introduce ASI core API Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
2025-03-19 17:29 ` Borislav Petkov
2025-01-10 18:40 ` [PATCH RFC v2 05/29] mm: asi: ASI support in interrupts/exceptions Brendan Jackman
` (24 subsequent siblings)
28 siblings, 1 reply; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman, Junaid Shahid, Yosry Ahmed
Add a boot time parameter to control the newly added X86_FEATURE_ASI.
"asi=on" or "asi=off" can be used in the kernel command line to enable
or disable ASI at boot time. If not specified, ASI enablement depends
on CONFIG_ADDRESS_SPACE_ISOLATION_DEFAULT_ON, which is off by default.
asi_check_boottime_disable() is modeled after
pti_check_boottime_disable().
The boot parameter is currently ignored until ASI is fully functional.
Once we have a set of ASI features checked in that we have actually
tested, we will stop ignoring the flag. But for now let's just add the
infrastructure so we can implement the usage code.
Ignoring checkpatch.pl CONFIG_DESCRIPTION because the _DEFAULT_ON
Kconfig is trivial to explain.
Checkpatch-args: --ignore CONFIG_DESCRIPTION
Co-developed-by: Junaid Shahid <junaids@google.com>
Signed-off-by: Junaid Shahid <junaids@google.com>
Co-developed-by: Yosry Ahmed <yosryahmed@google.com>
Signed-off-by: Yosry Ahmed <yosryahmed@google.com>
Signed-off-by: Brendan Jackman <jackmanb@google.com>
---
arch/x86/Kconfig | 9 +++++
arch/x86/include/asm/asi.h | 19 ++++++++--
arch/x86/include/asm/cpufeatures.h | 1 +
arch/x86/include/asm/disabled-features.h | 8 ++++-
arch/x86/mm/asi.c | 61 +++++++++++++++++++++++++++-----
arch/x86/mm/init.c | 4 ++-
include/asm-generic/asi.h | 4 +++
7 files changed, 92 insertions(+), 14 deletions(-)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 5a50582eb210e9d1309856a737d32b76fa1bfc85..1fcb52cb8cd5084ac3cef04af61b7d1653162bdb 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2533,6 +2533,15 @@ config MITIGATION_ADDRESS_SPACE_ISOLATION
there are likely to be unhandled cases, in particular concerning TLB
flushes.
+
+config ADDRESS_SPACE_ISOLATION_DEFAULT_ON
+ bool "Enable address space isolation by default"
+ default n
+ depends on MITIGATION_ADDRESS_SPACE_ISOLATION
+ help
+ If selected, ASI is enabled by default at boot if the asi=on or
+ asi=off are not specified.
+
config MITIGATION_RETPOLINE
bool "Avoid speculative indirect branches in kernel"
select OBJTOOL if HAVE_OBJTOOL
diff --git a/arch/x86/include/asm/asi.h b/arch/x86/include/asm/asi.h
index 7cc635b6653a3970ba9dbfdc9c828a470e27bd44..b9671ef2dd3278adceed18507fd260e21954d574 100644
--- a/arch/x86/include/asm/asi.h
+++ b/arch/x86/include/asm/asi.h
@@ -8,6 +8,7 @@
#include <asm/pgtable_types.h>
#include <asm/percpu.h>
+#include <asm/cpufeature.h>
#include <asm/processor.h>
#ifdef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
@@ -66,6 +67,8 @@
* the N ASI classes.
*/
+#define static_asi_enabled() cpu_feature_enabled(X86_FEATURE_ASI)
+
/*
* ASI uses a per-CPU tainting model to track what mitigation actions are
* required on domain transitions. Taints exist along two dimensions:
@@ -131,6 +134,8 @@ struct asi {
DECLARE_PER_CPU_ALIGNED(struct asi *, curr_asi);
+void asi_check_boottime_disable(void);
+
void asi_init_mm_state(struct mm_struct *mm);
int asi_init_class(enum asi_class_id class_id, struct asi_taint_policy *taint_policy);
@@ -155,7 +160,9 @@ void asi_exit(void);
/* The target is the domain we'll enter when returning to process context. */
static __always_inline struct asi *asi_get_target(struct task_struct *p)
{
- return p->thread.asi_state.target;
+ return static_asi_enabled()
+ ? p->thread.asi_state.target
+ : NULL;
}
static __always_inline void asi_set_target(struct task_struct *p,
@@ -166,7 +173,9 @@ static __always_inline void asi_set_target(struct task_struct *p,
static __always_inline struct asi *asi_get_current(void)
{
- return this_cpu_read(curr_asi);
+ return static_asi_enabled()
+ ? this_cpu_read(curr_asi)
+ : NULL;
}
/* Are we currently in a restricted address space? */
@@ -175,7 +184,11 @@ static __always_inline bool asi_is_restricted(void)
return (bool)asi_get_current();
}
-/* If we exit/have exited, can we stay that way until the next asi_enter? */
+/*
+ * If we exit/have exited, can we stay that way until the next asi_enter?
+ *
+ * When ASI is disabled, this returns true.
+ */
static __always_inline bool asi_is_relaxed(void)
{
return !asi_get_target(current);
diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
index 913fd3a7bac6506141de65f33b9ee61c615c7d7d..d6a808d10c3b8900d190ea01c66fc248863f05e2 100644
--- a/arch/x86/include/asm/cpufeatures.h
+++ b/arch/x86/include/asm/cpufeatures.h
@@ -474,6 +474,7 @@
#define X86_FEATURE_CLEAR_BHB_HW (21*32+ 3) /* BHI_DIS_S HW control enabled */
#define X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT (21*32+ 4) /* Clear branch history at vmexit using SW loop */
#define X86_FEATURE_FAST_CPPC (21*32 + 5) /* AMD Fast CPPC */
+#define X86_FEATURE_ASI (21*32+6) /* Kernel Address Space Isolation */
/*
* BUG word(s)
diff --git a/arch/x86/include/asm/disabled-features.h b/arch/x86/include/asm/disabled-features.h
index c492bdc97b0595ec77f89dc9b0cefe5e3e64be41..c7964ed4fef8b9441e1c0453da587787d8008d9d 100644
--- a/arch/x86/include/asm/disabled-features.h
+++ b/arch/x86/include/asm/disabled-features.h
@@ -50,6 +50,12 @@
# define DISABLE_PTI (1 << (X86_FEATURE_PTI & 31))
#endif
+#ifdef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
+# define DISABLE_ASI 0
+#else
+# define DISABLE_ASI (1 << (X86_FEATURE_ASI & 31))
+#endif
+
#ifdef CONFIG_MITIGATION_RETPOLINE
# define DISABLE_RETPOLINE 0
#else
@@ -154,7 +160,7 @@
#define DISABLED_MASK17 0
#define DISABLED_MASK18 (DISABLE_IBT)
#define DISABLED_MASK19 (DISABLE_SEV_SNP)
-#define DISABLED_MASK20 0
+#define DISABLED_MASK20 (DISABLE_ASI)
#define DISABLED_MASK21 0
#define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 22)
diff --git a/arch/x86/mm/asi.c b/arch/x86/mm/asi.c
index 105cd8b43eaf5c20acc80d4916b761559fb95d74..5baf563a078f5b3a6cd4b9f5e92baaf81b0774c4 100644
--- a/arch/x86/mm/asi.c
+++ b/arch/x86/mm/asi.c
@@ -4,6 +4,7 @@
#include <linux/percpu.h>
#include <linux/spinlock.h>
+#include <linux/init.h>
#include <asm/asi.h>
#include <asm/cmdline.h>
#include <asm/cpufeature.h>
@@ -29,6 +30,9 @@ static inline bool asi_class_id_valid(enum asi_class_id class_id)
static inline bool asi_class_initialized(enum asi_class_id class_id)
{
+ if (!boot_cpu_has(X86_FEATURE_ASI))
+ return 0;
+
if (WARN_ON(!asi_class_id_valid(class_id)))
return false;
@@ -51,6 +55,9 @@ EXPORT_SYMBOL_GPL(asi_init_class);
void asi_uninit_class(enum asi_class_id class_id)
{
+ if (!boot_cpu_has(X86_FEATURE_ASI))
+ return;
+
if (!asi_class_initialized(class_id))
return;
@@ -66,10 +73,36 @@ const char *asi_class_name(enum asi_class_id class_id)
return asi_class_names[class_id];
}
+void __init asi_check_boottime_disable(void)
+{
+ bool enabled = IS_ENABLED(CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION_DEFAULT_ON);
+ char arg[4];
+ int ret;
+
+ ret = cmdline_find_option(boot_command_line, "asi", arg, sizeof(arg));
+ if (ret == 3 && !strncmp(arg, "off", 3)) {
+ enabled = false;
+ pr_info("ASI disabled through kernel command line.\n");
+ } else if (ret == 2 && !strncmp(arg, "on", 2)) {
+ enabled = true;
+ pr_info("Ignoring asi=on param while ASI implementation is incomplete.\n");
+ } else {
+ pr_info("ASI %s by default.\n",
+ enabled ? "enabled" : "disabled");
+ }
+
+ if (enabled)
+ pr_info("ASI enablement ignored due to incomplete implementation.\n");
+}
+
static void __asi_destroy(struct asi *asi)
{
- lockdep_assert_held(&asi->mm->asi_init_lock);
+ WARN_ON_ONCE(asi->ref_count <= 0);
+ if (--(asi->ref_count) > 0)
+ return;
+ free_pages((ulong)asi->pgd, PGD_ALLOCATION_ORDER);
+ memset(asi, 0, sizeof(struct asi));
}
int asi_init(struct mm_struct *mm, enum asi_class_id class_id, struct asi **out_asi)
@@ -79,6 +112,9 @@ int asi_init(struct mm_struct *mm, enum asi_class_id class_id, struct asi **out_
*out_asi = NULL;
+ if (!boot_cpu_has(X86_FEATURE_ASI))
+ return 0;
+
if (WARN_ON(!asi_class_initialized(class_id)))
return -EINVAL;
@@ -122,7 +158,7 @@ void asi_destroy(struct asi *asi)
{
struct mm_struct *mm;
- if (!asi)
+ if (!boot_cpu_has(X86_FEATURE_ASI) || !asi)
return;
if (WARN_ON(!asi_class_initialized(asi->class_id)))
@@ -134,11 +170,7 @@ void asi_destroy(struct asi *asi)
* to block concurrent asi_init calls.
*/
mutex_lock(&mm->asi_init_lock);
- WARN_ON_ONCE(asi->ref_count <= 0);
- if (--(asi->ref_count) == 0) {
- free_pages((ulong)asi->pgd, PGD_ALLOCATION_ORDER);
- memset(asi, 0, sizeof(struct asi));
- }
+ __asi_destroy(asi);
mutex_unlock(&mm->asi_init_lock);
}
EXPORT_SYMBOL_GPL(asi_destroy);
@@ -255,6 +287,9 @@ static noinstr void __asi_enter(void)
noinstr void asi_enter(struct asi *asi)
{
+ if (!static_asi_enabled())
+ return;
+
VM_WARN_ON_ONCE(!asi);
/* Should not have an asi_enter() without a prior asi_relax(). */
@@ -269,8 +304,10 @@ EXPORT_SYMBOL_GPL(asi_enter);
noinstr void asi_relax(void)
{
- barrier();
- asi_set_target(current, NULL);
+ if (static_asi_enabled()) {
+ barrier();
+ asi_set_target(current, NULL);
+ }
}
EXPORT_SYMBOL_GPL(asi_relax);
@@ -279,6 +316,9 @@ noinstr void asi_exit(void)
u64 unrestricted_cr3;
struct asi *asi;
+ if (!static_asi_enabled())
+ return;
+
preempt_disable_notrace();
VM_BUG_ON(this_cpu_read(cpu_tlbstate.loaded_mm) ==
@@ -310,6 +350,9 @@ EXPORT_SYMBOL_GPL(asi_exit);
void asi_init_mm_state(struct mm_struct *mm)
{
+ if (!boot_cpu_has(X86_FEATURE_ASI))
+ return;
+
memset(mm->asi, 0, sizeof(mm->asi));
mutex_init(&mm->asi_init_lock);
}
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index de4227ed5169ff84d0ce80b677caffc475198fa6..ded3a47f2a9c1f554824d4ad19f3b48bce271274 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -28,6 +28,7 @@
#include <asm/text-patching.h>
#include <asm/memtype.h>
#include <asm/paravirt.h>
+#include <asm/asi.h>
/*
* We need to define the tracepoints somewhere, and tlb.c
@@ -251,7 +252,7 @@ static void __init probe_page_size_mask(void)
__default_kernel_pte_mask = __supported_pte_mask;
/* Except when with PTI where the kernel is mostly non-Global: */
if (cpu_feature_enabled(X86_FEATURE_PTI) ||
- IS_ENABLED(CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION))
+ cpu_feature_enabled(X86_FEATURE_ASI))
__default_kernel_pte_mask &= ~_PAGE_GLOBAL;
/* Enable 1 GB linear kernel mappings if available: */
@@ -754,6 +755,7 @@ void __init init_mem_mapping(void)
unsigned long end;
pti_check_boottime_disable();
+ asi_check_boottime_disable();
probe_page_size_mask();
setup_pcid();
diff --git a/include/asm-generic/asi.h b/include/asm-generic/asi.h
index 6b84202837605fa57e4a910318c8353b3f816f06..eedc961ee916a9e1da631ca489ea4a7bc9e6089f 100644
--- a/include/asm-generic/asi.h
+++ b/include/asm-generic/asi.h
@@ -65,6 +65,10 @@ static inline pgd_t *asi_pgd(struct asi *asi) { return NULL; }
static inline void asi_handle_switch_mm(void) { }
+#define static_asi_enabled() false
+
+static inline void asi_check_boottime_disable(void) { }
+
#endif /* !CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION */
#endif /* !_ASSEMBLY_ */
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH RFC v2 05/29] mm: asi: ASI support in interrupts/exceptions
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
` (3 preceding siblings ...)
2025-01-10 18:40 ` [PATCH RFC v2 04/29] mm: asi: Add infrastructure for boot-time enablement Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 06/29] mm: asi: Use separate PCIDs for restricted address spaces Brendan Jackman
` (23 subsequent siblings)
28 siblings, 0 replies; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman, Junaid Shahid
Add support for potentially switching address spaces from within
interrupts/exceptions/NMIs etc. An interrupt does not automatically
switch to the unrestricted address space. It can switch if needed to
access some memory not available in the restricted address space, using
the normal asi_exit call.
On return from the outermost interrupt, if the target address space was
the restricted address space (e.g. we were in the critical code path
between ASI Enter and VM Enter), the restricted address space will be
automatically restored. Otherwise, execution will continue in the
unrestricted address space until the next explicit ASI Enter.
In order to keep track of when to restore the restricted address space,
an interrupt/exception nesting depth counter is maintained per-task.
An alternative implementation without needing this counter is also
possible, but the counter unlocks an additional nice-to-have benefit by
allowing detection of whether or not we are currently executing inside
an exception context, which would be useful in a later patch.
Note that for KVM on SVM, this is not actually necessary as NMIs are in
fact maskable via CLGI. It's not clear to me if VMX has something
equivalent but we will need this infrastructure in place for userspace
support anyway.
RFC: Once userspace ASI is implemented, this idtentry integration
looks a bit heavy-handed. For example, we don't need this logic
for INT 80 emulation, so having it in DEFINE_IDTENTRY_RAW is
confusing. It could lead to a bug if the order of interrupter counter
modifications and ASI transition logic gets flipped around somehow.
checkpatch.pl SPACING is false positive. AVOID_BUG ignored for RFC.
Checkpatch-args: --ignore=SPACING,AVOID_BUG
Signed-off-by: Junaid Shahid <junaids@google.com>
Signed-off-by: Brendan Jackman <jackmanb@google.com>
---
arch/x86/include/asm/asi.h | 68 ++++++++++++++++++++++++++++++++++++++--
arch/x86/include/asm/idtentry.h | 50 ++++++++++++++++++++++++-----
arch/x86/include/asm/processor.h | 5 +++
arch/x86/kernel/process.c | 2 ++
arch/x86/kernel/traps.c | 22 +++++++++++++
arch/x86/mm/asi.c | 7 ++++-
include/asm-generic/asi.h | 10 ++++++
7 files changed, 153 insertions(+), 11 deletions(-)
diff --git a/arch/x86/include/asm/asi.h b/arch/x86/include/asm/asi.h
index b9671ef2dd3278adceed18507fd260e21954d574..9a9a139518289fc65f26a4d1cd311aa52cc5357f 100644
--- a/arch/x86/include/asm/asi.h
+++ b/arch/x86/include/asm/asi.h
@@ -157,6 +157,11 @@ void asi_relax(void);
/* Immediately exit the restricted address space if in it */
void asi_exit(void);
+static inline void asi_init_thread_state(struct thread_struct *thread)
+{
+ thread->asi_state.intr_nest_depth = 0;
+}
+
/* The target is the domain we'll enter when returning to process context. */
static __always_inline struct asi *asi_get_target(struct task_struct *p)
{
@@ -197,9 +202,10 @@ static __always_inline bool asi_is_relaxed(void)
/*
* Is the current task in the critical section?
*
- * This is just the inverse of !asi_is_relaxed(). We have both functions in order to
- * help write intuitive client code. In particular, asi_is_tense returns false
- * when ASI is disabled, which is judged to make user code more obvious.
+ * This is just the inverse of !asi_is_relaxed(). We have both functions in
+ * order to help write intuitive client code. In particular, asi_is_tense
+ * returns false when ASI is disabled, which is judged to make user code more
+ * obvious.
*/
static __always_inline bool asi_is_tense(void)
{
@@ -211,6 +217,62 @@ static __always_inline pgd_t *asi_pgd(struct asi *asi)
return asi ? asi->pgd : NULL;
}
+static __always_inline void asi_intr_enter(void)
+{
+ if (static_asi_enabled() && asi_is_tense()) {
+ current->thread.asi_state.intr_nest_depth++;
+ barrier();
+ }
+}
+
+void __asi_enter(void);
+
+static __always_inline void asi_intr_exit(void)
+{
+ if (static_asi_enabled() && asi_is_tense()) {
+ /*
+ * If an access to sensitive memory got reordered after the
+ * decrement, the #PF handler for that access would see a value
+ * of 0 for the counter and re-__asi_enter before returning to
+ * the faulting access, triggering an infinite PF loop.
+ */
+ barrier();
+
+ if (--current->thread.asi_state.intr_nest_depth == 0) {
+ /*
+ * If the decrement got reordered after __asi_enter, an
+ * interrupt that came between __asi_enter and the
+ * decrement would always see a nonzero value for the
+ * counter so it wouldn't call __asi_enter again and we
+ * would return to process context in the wrong address
+ * space.
+ */
+ barrier();
+ __asi_enter();
+ }
+ }
+}
+
+/*
+ * Returns the nesting depth of interrupts/exceptions that have interrupted the
+ * ongoing critical section. If the current task is not in a critical section
+ * this is 0.
+ */
+static __always_inline int asi_intr_nest_depth(void)
+{
+ return current->thread.asi_state.intr_nest_depth;
+}
+
+/*
+ * Remember that interrupts/exception don't count as the critical section. If
+ * you want to know if the current task is in the critical section use
+ * asi_is_tense().
+ */
+static __always_inline bool asi_in_critical_section(void)
+{
+ return asi_is_tense() && !asi_intr_nest_depth();
+}
+
#define INIT_MM_ASI(init_mm) \
.asi_init_lock = __MUTEX_INITIALIZER(init_mm.asi_init_lock),
diff --git a/arch/x86/include/asm/idtentry.h b/arch/x86/include/asm/idtentry.h
index ad5c68f0509d4dfd0834303c0f9dabc93ef73aa4..9e00da0a3b08f83ca5e603dc2abbfd5fa3059811 100644
--- a/arch/x86/include/asm/idtentry.h
+++ b/arch/x86/include/asm/idtentry.h
@@ -12,6 +12,7 @@
#include <linux/hardirq.h>
#include <asm/irq_stack.h>
+#include <asm/asi.h>
typedef void (*idtentry_t)(struct pt_regs *regs);
@@ -55,12 +56,15 @@ static __always_inline void __##func(struct pt_regs *regs); \
\
__visible noinstr void func(struct pt_regs *regs) \
{ \
- irqentry_state_t state = irqentry_enter(regs); \
+ irqentry_state_t state; \
\
+ asi_intr_enter(); \
+ state = irqentry_enter(regs); \
instrumentation_begin(); \
__##func (regs); \
instrumentation_end(); \
irqentry_exit(regs, state); \
+ asi_intr_exit(); \
} \
\
static __always_inline void __##func(struct pt_regs *regs)
@@ -102,12 +106,15 @@ static __always_inline void __##func(struct pt_regs *regs, \
__visible noinstr void func(struct pt_regs *regs, \
unsigned long error_code) \
{ \
- irqentry_state_t state = irqentry_enter(regs); \
+ irqentry_state_t state; \
\
+ asi_intr_enter(); \
+ state = irqentry_enter(regs); \
instrumentation_begin(); \
__##func (regs, error_code); \
instrumentation_end(); \
irqentry_exit(regs, state); \
+ asi_intr_exit(); \
} \
\
static __always_inline void __##func(struct pt_regs *regs, \
@@ -139,7 +146,16 @@ static __always_inline void __##func(struct pt_regs *regs, \
* is required before the enter/exit() helpers are invoked.
*/
#define DEFINE_IDTENTRY_RAW(func) \
-__visible noinstr void func(struct pt_regs *regs)
+static __always_inline void __##func(struct pt_regs *regs); \
+ \
+__visible noinstr void func(struct pt_regs *regs) \
+{ \
+ asi_intr_enter(); \
+ __##func (regs); \
+ asi_intr_exit(); \
+} \
+ \
+static __always_inline void __##func(struct pt_regs *regs)
/**
* DEFINE_FREDENTRY_RAW - Emit code for raw FRED entry points
@@ -178,7 +194,18 @@ noinstr void fred_##func(struct pt_regs *regs)
* is required before the enter/exit() helpers are invoked.
*/
#define DEFINE_IDTENTRY_RAW_ERRORCODE(func) \
-__visible noinstr void func(struct pt_regs *regs, unsigned long error_code)
+static __always_inline void __##func(struct pt_regs *regs, \
+ unsigned long error_code); \
+ \
+__visible noinstr void func(struct pt_regs *regs, unsigned long error_code)\
+{ \
+ asi_intr_enter(); \
+ __##func (regs, error_code); \
+ asi_intr_exit(); \
+} \
+ \
+static __always_inline void __##func(struct pt_regs *regs, \
+ unsigned long error_code)
/**
* DECLARE_IDTENTRY_IRQ - Declare functions for device interrupt IDT entry
@@ -209,14 +236,17 @@ static void __##func(struct pt_regs *regs, u32 vector); \
__visible noinstr void func(struct pt_regs *regs, \
unsigned long error_code) \
{ \
- irqentry_state_t state = irqentry_enter(regs); \
+ irqentry_state_t state; \
u32 vector = (u32)(u8)error_code; \
\
+ asi_intr_enter(); \
+ state = irqentry_enter(regs); \
kvm_set_cpu_l1tf_flush_l1d(); \
instrumentation_begin(); \
run_irq_on_irqstack_cond(__##func, regs, vector); \
instrumentation_end(); \
irqentry_exit(regs, state); \
+ asi_intr_exit(); \
} \
\
static noinline void __##func(struct pt_regs *regs, u32 vector)
@@ -255,13 +285,16 @@ static __always_inline void instr_##func(struct pt_regs *regs) \
\
__visible noinstr void func(struct pt_regs *regs) \
{ \
- irqentry_state_t state = irqentry_enter(regs); \
+ irqentry_state_t state; \
\
+ asi_intr_enter(); \
+ state = irqentry_enter(regs); \
kvm_set_cpu_l1tf_flush_l1d(); \
instrumentation_begin(); \
instr_##func (regs); \
instrumentation_end(); \
irqentry_exit(regs, state); \
+ asi_intr_exit(); \
} \
\
void fred_##func(struct pt_regs *regs) \
@@ -294,13 +327,16 @@ static __always_inline void instr_##func(struct pt_regs *regs) \
\
__visible noinstr void func(struct pt_regs *regs) \
{ \
- irqentry_state_t state = irqentry_enter(regs); \
+ irqentry_state_t state; \
\
+ asi_intr_enter(); \
+ state = irqentry_enter(regs); \
kvm_set_cpu_l1tf_flush_l1d(); \
instrumentation_begin(); \
instr_##func (regs); \
instrumentation_end(); \
irqentry_exit(regs, state); \
+ asi_intr_exit(); \
} \
\
void fred_##func(struct pt_regs *regs) \
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index f02220e6b4df911d87e2fee4b497eade61a27161..a32a53405f45e4c0473fe081e216029cf5bd0cdd 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -508,6 +508,11 @@ struct thread_struct {
struct {
/* Domain to enter when returning to process context. */
struct asi *target;
+ /*
+ * The depth of interrupt/exceptions interrupting an ASI
+ * critical section
+ */
+ int intr_nest_depth;
} asi_state;
#endif
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index f63f8fd00a91f3d1171f307b92179556ba2d716d..44abc161820153b7f68664b97267658b8e011101 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -96,6 +96,8 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
#ifdef CONFIG_VM86
dst->thread.vm86 = NULL;
#endif
+ asi_init_thread_state(&dst->thread);
+
/* Drop the copied pointer to current's fpstate */
dst->thread.fpu.fpstate = NULL;
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 2dbadf347b5f4f66625c4f49b76c41b412270d57..beea861da8d3e9a4e2afb3a92ed5f66f11d67bd6 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -65,6 +65,7 @@
#include <asm/umip.h>
#include <asm/insn.h>
#include <asm/insn-eval.h>
+#include <asm/asi.h>
#include <asm/vdso.h>
#include <asm/tdx.h>
#include <asm/cfi.h>
@@ -463,6 +464,27 @@ DEFINE_IDTENTRY_DF(exc_double_fault)
}
#endif
+ /*
+ * Do an asi_exit() only here because a #DF usually indicates
+ * the system is in a really bad state, and we don't want to
+ * cause any additional issue that would prevent us from
+ * printing a correct stack trace.
+ *
+ * The additional issues are not related to a possible triple
+ * fault, which can only occurs if a fault is encountered while
+ * invoking this handler, but here we are already executing it.
+ * Instead, an ASI-induced #PF here could potentially end up
+ * getting another #DF. For example, if there was some issue in
+ * invoking the #PF handler. The handler for the second #DF
+ * could then again cause an ASI-induced #PF leading back to the
+ * same recursion.
+ *
+ * This is not needed in the espfix64 case above, since that
+ * code is about turning a #DF into a #GP which is okay to
+ * handle in the restricted domain. That's also why we don't
+ * asi_exit() in the #GP handler.
+ */
+ asi_exit();
irqentry_nmi_enter(regs);
instrumentation_begin();
notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_DF, SIGSEGV);
diff --git a/arch/x86/mm/asi.c b/arch/x86/mm/asi.c
index 5baf563a078f5b3a6cd4b9f5e92baaf81b0774c4..054315d566c082c0925a00ce3a0877624c8b9957 100644
--- a/arch/x86/mm/asi.c
+++ b/arch/x86/mm/asi.c
@@ -235,7 +235,7 @@ static __always_inline void maybe_flush_data(struct asi *next_asi)
this_cpu_and(asi_taints, ~ASI_TAINTS_DATA_MASK);
}
-static noinstr void __asi_enter(void)
+noinstr void __asi_enter(void)
{
u64 asi_cr3;
struct asi *target = asi_get_target(current);
@@ -250,6 +250,7 @@ static noinstr void __asi_enter(void)
* disabling preemption should be fine.
*/
VM_BUG_ON(preemptible());
+ VM_BUG_ON(current->thread.asi_state.intr_nest_depth != 0);
if (!target || target == this_cpu_read(curr_asi))
return;
@@ -290,6 +291,7 @@ noinstr void asi_enter(struct asi *asi)
if (!static_asi_enabled())
return;
+ VM_WARN_ON_ONCE(asi_intr_nest_depth());
VM_WARN_ON_ONCE(!asi);
/* Should not have an asi_enter() without a prior asi_relax(). */
@@ -305,6 +307,7 @@ EXPORT_SYMBOL_GPL(asi_enter);
noinstr void asi_relax(void)
{
if (static_asi_enabled()) {
+ VM_WARN_ON_ONCE(asi_intr_nest_depth());
barrier();
asi_set_target(current, NULL);
}
@@ -326,6 +329,8 @@ noinstr void asi_exit(void)
asi = this_cpu_read(curr_asi);
if (asi) {
+ WARN_ON_ONCE(asi_in_critical_section());
+
maybe_flush_control(NULL);
unrestricted_cr3 =
diff --git a/include/asm-generic/asi.h b/include/asm-generic/asi.h
index eedc961ee916a9e1da631ca489ea4a7bc9e6089f..7f542c59c2b8a2b74432e4edb7199f9171db8a84 100644
--- a/include/asm-generic/asi.h
+++ b/include/asm-generic/asi.h
@@ -52,6 +52,8 @@ static inline bool asi_is_relaxed(void) { return true; }
static inline bool asi_is_tense(void) { return false; }
+static inline bool asi_in_critical_section(void) { return false; }
+
static inline void asi_exit(void) { }
static inline bool asi_is_restricted(void) { return false; }
@@ -65,6 +67,14 @@ static inline pgd_t *asi_pgd(struct asi *asi) { return NULL; }
static inline void asi_handle_switch_mm(void) { }
+static inline void asi_init_thread_state(struct thread_struct *thread) { }
+
+static inline void asi_intr_enter(void) { }
+
+static inline int asi_intr_nest_depth(void) { return 0; }
+
+static inline void asi_intr_exit(void) { }
+
#define static_asi_enabled() false
static inline void asi_check_boottime_disable(void) { }
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH RFC v2 06/29] mm: asi: Use separate PCIDs for restricted address spaces
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
` (4 preceding siblings ...)
2025-01-10 18:40 ` [PATCH RFC v2 05/29] mm: asi: ASI support in interrupts/exceptions Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 07/29] mm: asi: Make __get_current_cr3_fast() ASI-aware Brendan Jackman
` (22 subsequent siblings)
28 siblings, 0 replies; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman, Yosry Ahmed, Junaid Shahid
From: Yosry Ahmed <yosryahmed@google.com>
Each restricted address space is assigned a separate PCID. Since
currently only one ASI instance per-class exists for a given process,
the PCID is just derived from the class index.
This commit only sets the appropriate PCID when switching CR3, but does
not actually use the NOFLUSH bit. That will be done by later patches.
Co-developed-by: Junaid Shahid <junaids@google.com>
Signed-off-by: Junaid Shahid <junaids@google.com>
Signed-off-by: Yosry Ahmed <yosryahmed@google.com>
Signed-off-by: Brendan Jackman <jackmanb@google.com>
---
arch/x86/include/asm/asi.h | 4 +--
arch/x86/include/asm/processor-flags.h | 24 +++++++++++++++++
arch/x86/include/asm/tlbflush.h | 3 +++
arch/x86/mm/asi.c | 10 +++----
arch/x86/mm/tlb.c | 49 +++++++++++++++++++++++++++++++---
include/asm-generic/asi.h | 2 ++
6 files changed, 81 insertions(+), 11 deletions(-)
diff --git a/arch/x86/include/asm/asi.h b/arch/x86/include/asm/asi.h
index 9a9a139518289fc65f26a4d1cd311aa52cc5357f..a55e73f1b2bc84c41b9ab25f642a4d5f1aa6ba90 100644
--- a/arch/x86/include/asm/asi.h
+++ b/arch/x86/include/asm/asi.h
@@ -4,13 +4,13 @@
#include <linux/sched.h>
-#include <asm-generic/asi.h>
-
#include <asm/pgtable_types.h>
#include <asm/percpu.h>
#include <asm/cpufeature.h>
#include <asm/processor.h>
+#include <asm-generic/asi.h>
+
#ifdef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
/*
diff --git a/arch/x86/include/asm/processor-flags.h b/arch/x86/include/asm/processor-flags.h
index e5f204b9b33dfaa92ed1b05faa6b604e50d5f2f3..42c5acb67c2d2a6b03deb548fe3dd088baa88842 100644
--- a/arch/x86/include/asm/processor-flags.h
+++ b/arch/x86/include/asm/processor-flags.h
@@ -55,4 +55,28 @@
# define X86_CR3_PTI_PCID_USER_BIT 11
#endif
+/*
+ * An ASI identifier is included in the higher bits of PCID to use a different
+ * PCID for each restricted address space, different from the PCID of the
+ * unrestricted address space (see asi_pcid()). We use the bits directly after
+ * the bit used by PTI (if any).
+ */
+#ifdef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
+
+#define X86_CR3_ASI_PCID_BITS 2
+
+/* Use the highest available PCID bits after the PTI bit (if any) */
+#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
+#define X86_CR3_ASI_PCID_END_BIT (X86_CR3_PTI_PCID_USER_BIT - 1)
+#else
+#define X86_CR3_ASI_PCID_END_BIT (X86_CR3_PCID_BITS - 1)
+#endif
+
+#define X86_CR3_ASI_PCID_BITS_SHIFT (X86_CR3_ASI_PCID_END_BIT - X86_CR3_ASI_PCID_BITS + 1)
+#define X86_CR3_ASI_PCID_MASK (((1UL << X86_CR3_ASI_PCID_BITS) - 1) << X86_CR3_ASI_PCID_BITS_SHIFT)
+
+#else
+#define X86_CR3_ASI_PCID_BITS 0
+#endif
+
#endif /* _ASM_X86_PROCESSOR_FLAGS_H */
diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h
index c884174a44e119a3c027c44ada6c5cdba14d1282..f167feb5ebdfc7faba26b8b18ac65888cd9b0494 100644
--- a/arch/x86/include/asm/tlbflush.h
+++ b/arch/x86/include/asm/tlbflush.h
@@ -425,5 +425,8 @@ static inline void __native_tlb_flush_global(unsigned long cr4)
}
unsigned long build_cr3_noinstr(pgd_t *pgd, u16 asid, unsigned long lam);
+unsigned long build_cr3_pcid_noinstr(pgd_t *pgd, u16 pcid, unsigned long lam, bool noflush);
+
+u16 asi_pcid(struct asi *asi, u16 asid);
#endif /* _ASM_X86_TLBFLUSH_H */
diff --git a/arch/x86/mm/asi.c b/arch/x86/mm/asi.c
index 054315d566c082c0925a00ce3a0877624c8b9957..8d060c633be68b508847e2c1c111761df1da92af 100644
--- a/arch/x86/mm/asi.c
+++ b/arch/x86/mm/asi.c
@@ -238,6 +238,7 @@ static __always_inline void maybe_flush_data(struct asi *next_asi)
noinstr void __asi_enter(void)
{
u64 asi_cr3;
+ u16 pcid;
struct asi *target = asi_get_target(current);
/*
@@ -266,9 +267,8 @@ noinstr void __asi_enter(void)
this_cpu_write(curr_asi, target);
maybe_flush_control(target);
- asi_cr3 = build_cr3_noinstr(target->pgd,
- this_cpu_read(cpu_tlbstate.loaded_mm_asid),
- tlbstate_lam_cr3_mask());
+ pcid = asi_pcid(target, this_cpu_read(cpu_tlbstate.loaded_mm_asid));
+ asi_cr3 = build_cr3_pcid_noinstr(target->pgd, pcid, tlbstate_lam_cr3_mask(), false);
write_cr3(asi_cr3);
maybe_flush_data(target);
@@ -335,8 +335,8 @@ noinstr void asi_exit(void)
unrestricted_cr3 =
build_cr3_noinstr(this_cpu_read(cpu_tlbstate.loaded_mm)->pgd,
- this_cpu_read(cpu_tlbstate.loaded_mm_asid),
- tlbstate_lam_cr3_mask());
+ this_cpu_read(cpu_tlbstate.loaded_mm_asid),
+ tlbstate_lam_cr3_mask());
/* Tainting first makes reentrancy easier to reason about. */
this_cpu_or(asi_taints, ASI_TAINT_KERNEL_DATA);
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index 7c2309996d1d5a7cac23bd122f7b56a869d67d6a..2601beed83aef182d88800c09d70e4c5e95e7ed0 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -13,6 +13,7 @@
#include <linux/mmu_notifier.h>
#include <linux/mmu_context.h>
+#include <asm/processor-flags.h>
#include <asm/tlbflush.h>
#include <asm/mmu_context.h>
#include <asm/nospec-branch.h>
@@ -96,7 +97,10 @@
# define PTI_CONSUMED_PCID_BITS 0
#endif
-#define CR3_AVAIL_PCID_BITS (X86_CR3_PCID_BITS - PTI_CONSUMED_PCID_BITS)
+#define CR3_AVAIL_PCID_BITS (X86_CR3_PCID_BITS - PTI_CONSUMED_PCID_BITS - \
+ X86_CR3_ASI_PCID_BITS)
+
+static_assert(BIT(CR3_AVAIL_PCID_BITS) > TLB_NR_DYN_ASIDS);
/*
* ASIDs are zero-based: 0->MAX_AVAIL_ASID are valid. -1 below to account
@@ -125,6 +129,11 @@ static __always_inline u16 kern_pcid(u16 asid)
*/
VM_WARN_ON_ONCE(asid & (1 << X86_CR3_PTI_PCID_USER_BIT));
#endif
+
+#ifdef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
+ BUILD_BUG_ON(TLB_NR_DYN_ASIDS >= (1 << X86_CR3_ASI_PCID_BITS_SHIFT));
+ VM_WARN_ON_ONCE(asid & X86_CR3_ASI_PCID_MASK);
+#endif
/*
* The dynamically-assigned ASIDs that get passed in are small
* (<TLB_NR_DYN_ASIDS). They never have the high switch bit set,
@@ -153,17 +162,22 @@ static inline u16 user_pcid(u16 asid)
return ret;
}
+static __always_inline unsigned long __build_cr3(pgd_t *pgd, u16 pcid, unsigned long lam)
+{
+ return __sme_pa_nodebug(pgd) | pcid | lam;
+}
+
static __always_inline unsigned long build_cr3(pgd_t *pgd, u16 asid, unsigned long lam)
{
- unsigned long cr3 = __sme_pa_nodebug(pgd) | lam;
+ u16 pcid = 0;
if (static_cpu_has(X86_FEATURE_PCID)) {
- cr3 |= kern_pcid(asid);
+ pcid = kern_pcid(asid);
} else {
VM_WARN_ON_ONCE(asid != 0);
}
- return cr3;
+ return __build_cr3(pgd, pcid, lam);
}
noinstr unsigned long build_cr3_noinstr(pgd_t *pgd, u16 asid, unsigned long lam)
@@ -183,6 +197,19 @@ static inline unsigned long build_cr3_noflush(pgd_t *pgd, u16 asid,
return build_cr3(pgd, asid, lam) | CR3_NOFLUSH;
}
+noinstr unsigned long build_cr3_pcid_noinstr(pgd_t *pgd, u16 pcid,
+ unsigned long lam, bool noflush)
+{
+ u64 noflush_bit = 0;
+
+ if (!static_cpu_has(X86_FEATURE_PCID))
+ pcid = 0;
+ else if (noflush)
+ noflush_bit = CR3_NOFLUSH;
+
+ return __build_cr3(pgd, pcid, lam) | noflush_bit;
+}
+
/*
* We get here when we do something requiring a TLB invalidation
* but could not go invalidate all of the contexts. We do the
@@ -998,6 +1025,20 @@ static void put_flush_tlb_info(void)
#endif
}
+#ifdef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
+
+noinstr u16 asi_pcid(struct asi *asi, u16 asid)
+{
+ return kern_pcid(asid) | ((asi->class_id + 1) << X86_CR3_ASI_PCID_BITS_SHIFT);
+ // return kern_pcid(asid) | ((asi->index + 1) << X86_CR3_ASI_PCID_BITS_SHIFT);
+}
+
+#else /* CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION */
+
+u16 asi_pcid(struct asi *asi, u16 asid) { return kern_pcid(asid); }
+
+#endif /* CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION */
+
void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,
unsigned long end, unsigned int stride_shift,
bool freed_tables)
diff --git a/include/asm-generic/asi.h b/include/asm-generic/asi.h
index 7f542c59c2b8a2b74432e4edb7199f9171db8a84..f777a6cf604b0656fb39087f6eba08f980b2cb6f 100644
--- a/include/asm-generic/asi.h
+++ b/include/asm-generic/asi.h
@@ -2,6 +2,7 @@
#ifndef __ASM_GENERIC_ASI_H
#define __ASM_GENERIC_ASI_H
+#include <linux/log2.h>
#include <linux/types.h>
#ifndef _ASSEMBLY_
@@ -16,6 +17,7 @@ enum asi_class_id {
#endif
ASI_MAX_NUM_CLASSES,
};
+static_assert(order_base_2(X86_CR3_ASI_PCID_BITS) <= ASI_MAX_NUM_CLASSES);
typedef u8 asi_taints_t;
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH RFC v2 07/29] mm: asi: Make __get_current_cr3_fast() ASI-aware
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
` (5 preceding siblings ...)
2025-01-10 18:40 ` [PATCH RFC v2 06/29] mm: asi: Use separate PCIDs for restricted address spaces Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 08/29] mm: asi: Avoid warning from NMI userspace accesses in ASI context Brendan Jackman
` (21 subsequent siblings)
28 siblings, 0 replies; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman, Junaid Shahid
From: Junaid Shahid <junaids@google.com>
When ASI is active, __get_current_cr3_fast() adjusts the returned CR3
value accordingly to reflect the actual ASI CR3.
Signed-off-by: Junaid Shahid <junaids@google.com>
Signed-off-by: Brendan Jackman <jackmanb@google.com>
---
arch/x86/mm/tlb.c | 37 +++++++++++++++++++++++++++++++------
1 file changed, 31 insertions(+), 6 deletions(-)
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index 2601beed83aef182d88800c09d70e4c5e95e7ed0..b2a13fdab0c6454c1d9d4e3338801f3402da4191 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -20,6 +20,7 @@
#include <asm/cache.h>
#include <asm/cacheflush.h>
#include <asm/apic.h>
+#include <asm/asi.h>
#include <asm/perf_event.h>
#include "mm_internal.h"
@@ -197,8 +198,8 @@ static inline unsigned long build_cr3_noflush(pgd_t *pgd, u16 asid,
return build_cr3(pgd, asid, lam) | CR3_NOFLUSH;
}
-noinstr unsigned long build_cr3_pcid_noinstr(pgd_t *pgd, u16 pcid,
- unsigned long lam, bool noflush)
+static __always_inline unsigned long build_cr3_pcid(pgd_t *pgd, u16 pcid,
+ unsigned long lam, bool noflush)
{
u64 noflush_bit = 0;
@@ -210,6 +211,12 @@ noinstr unsigned long build_cr3_pcid_noinstr(pgd_t *pgd, u16 pcid,
return __build_cr3(pgd, pcid, lam) | noflush_bit;
}
+noinstr unsigned long build_cr3_pcid_noinstr(pgd_t *pgd, u16 pcid,
+ unsigned long lam, bool noflush)
+{
+ return build_cr3_pcid(pgd, pcid, lam, noflush);
+}
+
/*
* We get here when we do something requiring a TLB invalidation
* but could not go invalidate all of the contexts. We do the
@@ -1133,14 +1140,32 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end)
*/
noinstr unsigned long __get_current_cr3_fast(void)
{
- unsigned long cr3 =
- build_cr3(this_cpu_read(cpu_tlbstate.loaded_mm)->pgd,
- this_cpu_read(cpu_tlbstate.loaded_mm_asid),
- tlbstate_lam_cr3_mask());
+ unsigned long cr3;
+ pgd_t *pgd;
+ u16 asid = this_cpu_read(cpu_tlbstate.loaded_mm_asid);
+ struct asi *asi = asi_get_current();
+ u16 pcid;
+
+ if (asi) {
+ pgd = asi_pgd(asi);
+ pcid = asi_pcid(asi, asid);
+ } else {
+ pgd = this_cpu_read(cpu_tlbstate.loaded_mm)->pgd;
+ pcid = kern_pcid(asid);
+ }
+
+ cr3 = build_cr3_pcid(pgd, pcid, tlbstate_lam_cr3_mask(), false);
/* For now, be very restrictive about when this can be called. */
VM_WARN_ON(in_nmi() || preemptible());
+ /*
+ * Outside of the ASI critical section, an ASI-restricted CR3 is
+ * unstable because an interrupt (including an inner interrupt, if we're
+ * already in one) could cause a persistent asi_exit.
+ */
+ VM_WARN_ON_ONCE(asi && asi_in_critical_section());
+
VM_BUG_ON(cr3 != __read_cr3());
return cr3;
}
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH RFC v2 08/29] mm: asi: Avoid warning from NMI userspace accesses in ASI context
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
` (6 preceding siblings ...)
2025-01-10 18:40 ` [PATCH RFC v2 07/29] mm: asi: Make __get_current_cr3_fast() ASI-aware Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 09/29] mm: asi: ASI page table allocation functions Brendan Jackman
` (20 subsequent siblings)
28 siblings, 0 replies; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman, Junaid Shahid, Yosry Ahmed
nmi_uaccess_okay() emits a warning if current CR3 != mm->pgd.
Limit the warning to only when ASI is not active.
Co-developed-by: Junaid Shahid <junaids@google.com>
Signed-off-by: Junaid Shahid <junaids@google.com>
Co-developed-by: Yosry Ahmed <yosryahmed@google.com>
Signed-off-by: Yosry Ahmed <yosryahmed@google.com>
Signed-off-by: Brendan Jackman <jackmanb@google.com>
---
arch/x86/mm/tlb.c | 26 +++++++++++++++++++++-----
1 file changed, 21 insertions(+), 5 deletions(-)
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index b2a13fdab0c6454c1d9d4e3338801f3402da4191..c41e083c5b5281684be79ad0391c1a5fc7b0c493 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -1340,6 +1340,22 @@ void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch)
put_cpu();
}
+static inline bool cr3_matches_current_mm(void)
+{
+ struct asi *asi = asi_get_current();
+ pgd_t *pgd_asi = asi_pgd(asi);
+ pgd_t *pgd_cr3;
+
+ /*
+ * Prevent read_cr3_pa -> [NMI, asi_exit] -> asi_get_current,
+ * otherwise we might find CR3 pointing to the ASI PGD but not
+ * find a current ASI domain.
+ */
+ barrier();
+ pgd_cr3 = __va(read_cr3_pa());
+ return pgd_cr3 == current->mm->pgd || pgd_cr3 == pgd_asi;
+}
+
/*
* Blindly accessing user memory from NMI context can be dangerous
* if we're in the middle of switching the current user task or
@@ -1355,10 +1371,10 @@ bool nmi_uaccess_okay(void)
VM_WARN_ON_ONCE(!loaded_mm);
/*
- * The condition we want to check is
- * current_mm->pgd == __va(read_cr3_pa()). This may be slow, though,
- * if we're running in a VM with shadow paging, and nmi_uaccess_okay()
- * is supposed to be reasonably fast.
+ * The condition we want to check that CR3 points to either
+ * current_mm->pgd or an appropriate ASI PGD. Reading CR3 may be slow,
+ * though, if we're running in a VM with shadow paging, and
+ * nmi_uaccess_okay() is supposed to be reasonably fast.
*
* Instead, we check the almost equivalent but somewhat conservative
* condition below, and we rely on the fact that switch_mm_irqs_off()
@@ -1367,7 +1383,7 @@ bool nmi_uaccess_okay(void)
if (loaded_mm != current_mm)
return false;
- VM_WARN_ON_ONCE(current_mm->pgd != __va(read_cr3_pa()));
+ VM_WARN_ON_ONCE(!cr3_matches_current_mm());
return true;
}
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH RFC v2 09/29] mm: asi: ASI page table allocation functions
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
` (7 preceding siblings ...)
2025-01-10 18:40 ` [PATCH RFC v2 08/29] mm: asi: Avoid warning from NMI userspace accesses in ASI context Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 10/29] mm: asi: asi_exit() on PF, skip handling if address is accessible Brendan Jackman
` (19 subsequent siblings)
28 siblings, 0 replies; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman, Junaid Shahid
From: Junaid Shahid <junaids@google.com>
This adds custom allocation and free functions for ASI page tables.
The alloc functions support allocating memory using different GFP
reclaim flags, in order to be able to support non-sensitive allocations
from both standard and atomic contexts. They also install the page
tables locklessly, which makes it slightly simpler to handle
non-sensitive allocations from interrupts/exceptions.
checkpatch.pl MACRO_ARG_UNUSED,SPACING is false positive. COMPLEX_MACRO - I
dunno, suggestions welcome.
Checkpatch-args: --ignore=MACRO_ARG_UNUSED,SPACING,COMPLEX_MACRO
Signed-off-by: Junaid Shahid <junaids@google.com>
Signed-off-by: Brendan Jackman <jackmanb@google.com>
---
arch/x86/mm/asi.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)
diff --git a/arch/x86/mm/asi.c b/arch/x86/mm/asi.c
index 8d060c633be68b508847e2c1c111761df1da92af..b15d043acedc9f459f17e86564a15061650afc3a 100644
--- a/arch/x86/mm/asi.c
+++ b/arch/x86/mm/asi.c
@@ -73,6 +73,65 @@ const char *asi_class_name(enum asi_class_id class_id)
return asi_class_names[class_id];
}
+#ifndef mm_inc_nr_p4ds
+#define mm_inc_nr_p4ds(mm) do {} while (false)
+#endif
+
+#ifndef mm_dec_nr_p4ds
+#define mm_dec_nr_p4ds(mm) do {} while (false)
+#endif
+
+#define pte_offset pte_offset_kernel
+
+/*
+ * asi_p4d_alloc, asi_pud_alloc, asi_pmd_alloc, asi_pte_alloc.
+ *
+ * These are like the normal xxx_alloc functions, but:
+ *
+ * - They use atomic operations instead of taking a spinlock; this allows them
+ * to be used from interrupts. This is necessary because we use the page
+ * allocator from interrupts and the page allocator ultimately calls this
+ * code.
+ * - They support customizing the allocation flags.
+ *
+ * On the other hand, they do not use the normal page allocation infrastructure,
+ * that means that PTE pages do not have the PageTable type nor the PagePgtable
+ * flag and we don't increment the meminfo stat (NR_PAGETABLE) as they do.
+ */
+static_assert(!IS_ENABLED(CONFIG_PARAVIRT));
+#define DEFINE_ASI_PGTBL_ALLOC(base, level) \
+__maybe_unused \
+static level##_t * asi_##level##_alloc(struct asi *asi, \
+ base##_t *base, ulong addr, \
+ gfp_t flags) \
+{ \
+ if (unlikely(base##_none(*base))) { \
+ ulong pgtbl = get_zeroed_page(flags); \
+ phys_addr_t pgtbl_pa; \
+ \
+ if (!pgtbl) \
+ return NULL; \
+ \
+ pgtbl_pa = __pa(pgtbl); \
+ \
+ if (cmpxchg((ulong *)base, 0, \
+ pgtbl_pa | _PAGE_TABLE) != 0) { \
+ free_page(pgtbl); \
+ goto out; \
+ } \
+ \
+ mm_inc_nr_##level##s(asi->mm); \
+ } \
+out: \
+ VM_BUG_ON(base##_leaf(*base)); \
+ return level##_offset(base, addr); \
+}
+
+DEFINE_ASI_PGTBL_ALLOC(pgd, p4d)
+DEFINE_ASI_PGTBL_ALLOC(p4d, pud)
+DEFINE_ASI_PGTBL_ALLOC(pud, pmd)
+DEFINE_ASI_PGTBL_ALLOC(pmd, pte)
+
void __init asi_check_boottime_disable(void)
{
bool enabled = IS_ENABLED(CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION_DEFAULT_ON);
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH RFC v2 10/29] mm: asi: asi_exit() on PF, skip handling if address is accessible
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
` (8 preceding siblings ...)
2025-01-10 18:40 ` [PATCH RFC v2 09/29] mm: asi: ASI page table allocation functions Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 11/29] mm: asi: Functions to map/unmap a memory range into ASI page tables Brendan Jackman
` (18 subsequent siblings)
28 siblings, 0 replies; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman, Ofir Weisse
From: Ofir Weisse <oweisse@google.com>
On a page-fault - do asi_exit(). Then check if now after the exit the
address is accessible. We do this by refactoring spurious_kernel_fault()
into two parts:
1. Verify that the error code value is something that could arise from a
lazy TLB update.
2. Walk the page table and verify permissions, which is now called
is_address_accessible(). We also define PTE_PRESENT() and PMD_PRESENT()
which are suitable for checking userspace pages. For the sake of
spurious faults, pte_present() and pmd_present() are only good for
kernelspace pages. This is because these macros might return true even
if the present bit is 0 (only relevant for userspace).
checkpatch.pl VSPRINTF_SPECIFIER_PX - it's in a WARN that only fires in
a debug build of the kernel when we hit a disastrous bug, seems OK to
leak addresses.
RFC note: A separate refactoring/prep commit should be split out of this
patch.
Checkpatch-args: --ignore=VSPRINTF_SPECIFIER_PX
Signed-off-by: Ofir Weisse <oweisse@google.com>
Signed-off-by: Brendan Jackman <jackmanb@google.com>
---
arch/x86/mm/fault.c | 118 +++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 103 insertions(+), 15 deletions(-)
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index e6c469b323ccb748de22adc7d9f0a16dd195edad..ee8f5417174e2956391d538f41e2475553ca4972 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -948,7 +948,7 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address,
force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *)address);
}
-static int spurious_kernel_fault_check(unsigned long error_code, pte_t *pte)
+static __always_inline int kernel_protection_ok(unsigned long error_code, pte_t *pte)
{
if ((error_code & X86_PF_WRITE) && !pte_write(*pte))
return 0;
@@ -959,6 +959,8 @@ static int spurious_kernel_fault_check(unsigned long error_code, pte_t *pte)
return 1;
}
+static int kernel_access_ok(unsigned long error_code, unsigned long address, pgd_t *pgd);
+
/*
* Handle a spurious fault caused by a stale TLB entry.
*
@@ -984,11 +986,6 @@ static noinline int
spurious_kernel_fault(unsigned long error_code, unsigned long address)
{
pgd_t *pgd;
- p4d_t *p4d;
- pud_t *pud;
- pmd_t *pmd;
- pte_t *pte;
- int ret;
/*
* Only writes to RO or instruction fetches from NX may cause
@@ -1004,6 +1001,50 @@ spurious_kernel_fault(unsigned long error_code, unsigned long address)
return 0;
pgd = init_mm.pgd + pgd_index(address);
+ return kernel_access_ok(error_code, address, pgd);
+}
+NOKPROBE_SYMBOL(spurious_kernel_fault);
+
+/*
+ * For kernel addresses, pte_present and pmd_present are sufficient for
+ * is_address_accessible. For user addresses these functions will return true
+ * even though the pte is not actually accessible by hardware (i.e _PAGE_PRESENT
+ * is not set). This happens in cases where the pages are physically present in
+ * memory, but they are not made accessible to hardware as they need software
+ * handling first:
+ *
+ * - ptes/pmds with _PAGE_PROTNONE need autonuma balancing (see pte_protnone(),
+ * change_prot_numa(), and do_numa_page()).
+ *
+ * - pmds with _PAGE_PSE & !_PAGE_PRESENT are undergoing splitting (see
+ * split_huge_page()).
+ *
+ * Here, we care about whether the hardware can actually access the page right
+ * now.
+ *
+ * These issues aren't currently present for PUD but we also have a custom
+ * PUD_PRESENT for a layer of future-proofing.
+ */
+#define PUD_PRESENT(pud) (pud_flags(pud) & _PAGE_PRESENT)
+#define PMD_PRESENT(pmd) (pmd_flags(pmd) & _PAGE_PRESENT)
+#define PTE_PRESENT(pte) (pte_flags(pte) & _PAGE_PRESENT)
+
+/*
+ * Check if an access by the kernel would cause a page fault. The access is
+ * described by a page fault error code (whether it was a write/instruction
+ * fetch) and address. This doesn't check for types of faults that are not
+ * expected to affect the kernel, e.g. PKU. The address can be user or kernel
+ * space, if user then we assume the access would happen via the uaccess API.
+ */
+static noinstr int
+kernel_access_ok(unsigned long error_code, unsigned long address, pgd_t *pgd)
+{
+ p4d_t *p4d;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ int ret;
+
if (!pgd_present(*pgd))
return 0;
@@ -1012,27 +1053,27 @@ spurious_kernel_fault(unsigned long error_code, unsigned long address)
return 0;
if (p4d_leaf(*p4d))
- return spurious_kernel_fault_check(error_code, (pte_t *) p4d);
+ return kernel_protection_ok(error_code, (pte_t *) p4d);
pud = pud_offset(p4d, address);
- if (!pud_present(*pud))
+ if (!PUD_PRESENT(*pud))
return 0;
if (pud_leaf(*pud))
- return spurious_kernel_fault_check(error_code, (pte_t *) pud);
+ return kernel_protection_ok(error_code, (pte_t *) pud);
pmd = pmd_offset(pud, address);
- if (!pmd_present(*pmd))
+ if (!PMD_PRESENT(*pmd))
return 0;
if (pmd_leaf(*pmd))
- return spurious_kernel_fault_check(error_code, (pte_t *) pmd);
+ return kernel_protection_ok(error_code, (pte_t *) pmd);
pte = pte_offset_kernel(pmd, address);
- if (!pte_present(*pte))
+ if (!PTE_PRESENT(*pte))
return 0;
- ret = spurious_kernel_fault_check(error_code, pte);
+ ret = kernel_protection_ok(error_code, pte);
if (!ret)
return 0;
@@ -1040,12 +1081,11 @@ spurious_kernel_fault(unsigned long error_code, unsigned long address)
* Make sure we have permissions in PMD.
* If not, then there's a bug in the page tables:
*/
- ret = spurious_kernel_fault_check(error_code, (pte_t *) pmd);
+ ret = kernel_protection_ok(error_code, (pte_t *) pmd);
WARN_ONCE(!ret, "PMD has incorrect permission bits\n");
return ret;
}
-NOKPROBE_SYMBOL(spurious_kernel_fault);
int show_unhandled_signals = 1;
@@ -1490,6 +1530,29 @@ handle_page_fault(struct pt_regs *regs, unsigned long error_code,
}
}
+static __always_inline void warn_if_bad_asi_pf(
+ unsigned long error_code, unsigned long address)
+{
+#ifdef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
+ struct asi *target;
+
+ /*
+ * It's a bug to access sensitive data from the "critical section", i.e.
+ * on the path between asi_enter and asi_relax, where untrusted code
+ * gets run. #PF in this state sees asi_intr_nest_depth() as 1 because
+ * #PF increments it. We can't think of a better way to determine if
+ * this has happened than to check the ASI pagetables, hence we can't
+ * really have this check in non-debug builds unfortunately.
+ */
+ VM_WARN_ONCE(
+ (target = asi_get_target(current)) != NULL &&
+ asi_intr_nest_depth() == 1 &&
+ !kernel_access_ok(error_code, address, asi_pgd(target)),
+ "ASI-sensitive data access from critical section, addr=%px error_code=%lx class=%s",
+ (void *) address, error_code, asi_class_name(target->class_id));
+#endif
+}
+
DEFINE_IDTENTRY_RAW_ERRORCODE(exc_page_fault)
{
irqentry_state_t state;
@@ -1497,6 +1560,31 @@ DEFINE_IDTENTRY_RAW_ERRORCODE(exc_page_fault)
address = cpu_feature_enabled(X86_FEATURE_FRED) ? fred_event_data(regs) : read_cr2();
+ if (static_asi_enabled() && !user_mode(regs)) {
+ pgd_t *pgd;
+
+ /* Can be a NOP even for ASI faults, because of NMIs */
+ asi_exit();
+
+ /*
+ * handle_page_fault() might oops if we run it for a kernel
+ * address in kernel mode. This might be the case if we got here
+ * due to an ASI fault. We avoid this case by checking whether
+ * the address is now, after asi_exit(), accessible by hardware.
+ * If it is - there's nothing to do. Note that this is a bit of
+ * a shotgun; we can also bail early from user-address faults
+ * here that weren't actually caused by ASI. So we might wanna
+ * move this logic later in the handler. In particular, we might
+ * be losing some stats here. However for now this keeps ASI
+ * page faults nice and fast.
+ */
+ pgd = (pgd_t *)__va(read_cr3_pa()) + pgd_index(address);
+ if (!user_mode(regs) && kernel_access_ok(error_code, address, pgd)) {
+ warn_if_bad_asi_pf(error_code, address);
+ return;
+ }
+ }
+
prefetchw(¤t->mm->mmap_lock);
/*
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH RFC v2 11/29] mm: asi: Functions to map/unmap a memory range into ASI page tables
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
` (9 preceding siblings ...)
2025-01-10 18:40 ` [PATCH RFC v2 10/29] mm: asi: asi_exit() on PF, skip handling if address is accessible Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 12/29] mm: asi: Add basic infrastructure for global non-sensitive mappings Brendan Jackman
` (17 subsequent siblings)
28 siblings, 0 replies; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman, Junaid Shahid, Kevin Cheng
From: Junaid Shahid <junaids@google.com>
Two functions, asi_map() and asi_map_gfp(), are added to allow mapping
memory into ASI page tables. The mapping will be identical to the one
for the same virtual address in the unrestricted page tables. This is
necessary to allow switching between the page tables at any arbitrary
point in the kernel.
Another function, asi_unmap() is added to allow unmapping memory mapped
via asi_map*
RFC Notes: Don't read too much into the implementation of this, lots of
it should probably be rewritten. It also needs to gain support for
partial unmappings.
Checkpatch-args: --ignore=MACRO_ARG_UNUSED
Signed-off-by: Junaid Shahid <junaids@google.com>
Signed-off-by: Brendan Jackman <jackmanb@google.com>
Signed-off-by: Kevin Cheng <chengkev@google.com>
---
arch/x86/include/asm/asi.h | 5 +
arch/x86/mm/asi.c | 236 ++++++++++++++++++++++++++++++++++++++++++++-
arch/x86/mm/tlb.c | 5 +
include/asm-generic/asi.h | 11 +++
include/linux/pgtable.h | 3 +
mm/internal.h | 2 +
mm/vmalloc.c | 32 +++---
7 files changed, 280 insertions(+), 14 deletions(-)
diff --git a/arch/x86/include/asm/asi.h b/arch/x86/include/asm/asi.h
index a55e73f1b2bc84c41b9ab25f642a4d5f1aa6ba90..33f18be0e268b3a6725196619cbb8d847c21e197 100644
--- a/arch/x86/include/asm/asi.h
+++ b/arch/x86/include/asm/asi.h
@@ -157,6 +157,11 @@ void asi_relax(void);
/* Immediately exit the restricted address space if in it */
void asi_exit(void);
+int asi_map_gfp(struct asi *asi, void *addr, size_t len, gfp_t gfp_flags);
+int asi_map(struct asi *asi, void *addr, size_t len);
+void asi_unmap(struct asi *asi, void *addr, size_t len);
+void asi_flush_tlb_range(struct asi *asi, void *addr, size_t len);
+
static inline void asi_init_thread_state(struct thread_struct *thread)
{
thread->asi_state.intr_nest_depth = 0;
diff --git a/arch/x86/mm/asi.c b/arch/x86/mm/asi.c
index b15d043acedc9f459f17e86564a15061650afc3a..f2d8fbc0366c289891903e1c2ac6c59b9476d95f 100644
--- a/arch/x86/mm/asi.c
+++ b/arch/x86/mm/asi.c
@@ -11,6 +11,9 @@
#include <asm/page.h>
#include <asm/pgalloc.h>
#include <asm/mmu_context.h>
+#include <asm/traps.h>
+
+#include "../../../mm/internal.h"
static struct asi_taint_policy *taint_policies[ASI_MAX_NUM_CLASSES];
@@ -100,7 +103,6 @@ const char *asi_class_name(enum asi_class_id class_id)
*/
static_assert(!IS_ENABLED(CONFIG_PARAVIRT));
#define DEFINE_ASI_PGTBL_ALLOC(base, level) \
-__maybe_unused \
static level##_t * asi_##level##_alloc(struct asi *asi, \
base##_t *base, ulong addr, \
gfp_t flags) \
@@ -455,3 +457,235 @@ void asi_handle_switch_mm(void)
this_cpu_or(asi_taints, new_taints);
this_cpu_and(asi_taints, ~(ASI_TAINTS_GUEST_MASK | ASI_TAINTS_USER_MASK));
}
+
+static bool is_page_within_range(unsigned long addr, unsigned long page_size,
+ unsigned long range_start, unsigned long range_end)
+{
+ unsigned long page_start = ALIGN_DOWN(addr, page_size);
+ unsigned long page_end = page_start + page_size;
+
+ return page_start >= range_start && page_end <= range_end;
+}
+
+static bool follow_physaddr(
+ pgd_t *pgd_table, unsigned long virt,
+ phys_addr_t *phys, unsigned long *page_size, ulong *flags)
+{
+ pgd_t *pgd;
+ p4d_t *p4d;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ /* RFC: This should be rewritten with lookup_address_in_*. */
+
+ *page_size = PGDIR_SIZE;
+ pgd = pgd_offset_pgd(pgd_table, virt);
+ if (!pgd_present(*pgd))
+ return false;
+ if (pgd_leaf(*pgd)) {
+ *phys = PFN_PHYS(pgd_pfn(*pgd)) | (virt & ~PGDIR_MASK);
+ *flags = pgd_flags(*pgd);
+ return true;
+ }
+
+ *page_size = P4D_SIZE;
+ p4d = p4d_offset(pgd, virt);
+ if (!p4d_present(*p4d))
+ return false;
+ if (p4d_leaf(*p4d)) {
+ *phys = PFN_PHYS(p4d_pfn(*p4d)) | (virt & ~P4D_MASK);
+ *flags = p4d_flags(*p4d);
+ return true;
+ }
+
+ *page_size = PUD_SIZE;
+ pud = pud_offset(p4d, virt);
+ if (!pud_present(*pud))
+ return false;
+ if (pud_leaf(*pud)) {
+ *phys = PFN_PHYS(pud_pfn(*pud)) | (virt & ~PUD_MASK);
+ *flags = pud_flags(*pud);
+ return true;
+ }
+
+ *page_size = PMD_SIZE;
+ pmd = pmd_offset(pud, virt);
+ if (!pmd_present(*pmd))
+ return false;
+ if (pmd_leaf(*pmd)) {
+ *phys = PFN_PHYS(pmd_pfn(*pmd)) | (virt & ~PMD_MASK);
+ *flags = pmd_flags(*pmd);
+ return true;
+ }
+
+ *page_size = PAGE_SIZE;
+ pte = pte_offset_map(pmd, virt);
+ if (!pte)
+ return false;
+
+ if (!pte_present(*pte)) {
+ pte_unmap(pte);
+ return false;
+ }
+
+ *phys = PFN_PHYS(pte_pfn(*pte)) | (virt & ~PAGE_MASK);
+ *flags = pte_flags(*pte);
+
+ pte_unmap(pte);
+ return true;
+}
+
+/*
+ * Map the given range into the ASI page tables. The source of the mapping is
+ * the regular unrestricted page tables. Can be used to map any kernel memory.
+ *
+ * The caller MUST ensure that the source mapping will not change during this
+ * function. For dynamic kernel memory, this is generally ensured by mapping the
+ * memory within the allocator.
+ *
+ * If this fails, it may leave partial mappings behind. You must asi_unmap them,
+ * bearing in mind asi_unmap's requirements on the calling context. Part of the
+ * reason for this is that we don't want to unexpectedly undo mappings that
+ * weren't created by the present caller.
+ *
+ * If the source mapping is a large page and the range being mapped spans the
+ * entire large page, then it will be mapped as a large page in the ASI page
+ * tables too. If the range does not span the entire huge page, then it will be
+ * mapped as smaller pages. In that case, the implementation is slightly
+ * inefficient, as it will walk the source page tables again for each small
+ * destination page, but that should be ok for now, as usually in such cases,
+ * the range would consist of a small-ish number of pages.
+ *
+ * RFC: * vmap_p4d_range supports huge mappings, we can probably use that now.
+ */
+int __must_check asi_map_gfp(struct asi *asi, void *addr, unsigned long len, gfp_t gfp_flags)
+{
+ unsigned long virt;
+ unsigned long start = (size_t)addr;
+ unsigned long end = start + len;
+ unsigned long page_size;
+
+ if (!static_asi_enabled())
+ return 0;
+
+ VM_BUG_ON(!IS_ALIGNED(start, PAGE_SIZE));
+ VM_BUG_ON(!IS_ALIGNED(len, PAGE_SIZE));
+ /* RFC: fault_in_kernel_space should be renamed. */
+ VM_BUG_ON(!fault_in_kernel_space(start));
+
+ gfp_flags &= GFP_RECLAIM_MASK;
+
+ if (asi->mm != &init_mm)
+ gfp_flags |= __GFP_ACCOUNT;
+
+ for (virt = start; virt < end; virt = ALIGN(virt + 1, page_size)) {
+ pgd_t *pgd;
+ p4d_t *p4d;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ phys_addr_t phys;
+ ulong flags;
+
+ if (!follow_physaddr(asi->mm->pgd, virt, &phys, &page_size, &flags))
+ continue;
+
+#define MAP_AT_LEVEL(base, BASE, level, LEVEL) { \
+ if (base##_leaf(*base)) { \
+ if (WARN_ON_ONCE(PHYS_PFN(phys & BASE##_MASK) !=\
+ base##_pfn(*base))) \
+ return -EBUSY; \
+ continue; \
+ } \
+ \
+ level = asi_##level##_alloc(asi, base, virt, gfp_flags);\
+ if (!level) \
+ return -ENOMEM; \
+ \
+ if (page_size >= LEVEL##_SIZE && \
+ (level##_none(*level) || level##_leaf(*level)) && \
+ is_page_within_range(virt, LEVEL##_SIZE, \
+ start, end)) { \
+ page_size = LEVEL##_SIZE; \
+ phys &= LEVEL##_MASK; \
+ \
+ if (!level##_none(*level)) { \
+ if (WARN_ON_ONCE(level##_pfn(*level) != \
+ PHYS_PFN(phys))) { \
+ return -EBUSY; \
+ } \
+ } else { \
+ set_##level(level, \
+ __##level(phys | flags)); \
+ } \
+ continue; \
+ } \
+ }
+
+ pgd = pgd_offset_pgd(asi->pgd, virt);
+
+ MAP_AT_LEVEL(pgd, PGDIR, p4d, P4D);
+ MAP_AT_LEVEL(p4d, P4D, pud, PUD);
+ MAP_AT_LEVEL(pud, PUD, pmd, PMD);
+ /*
+ * If a large page is going to be partially mapped
+ * in 4k pages, convert the PSE/PAT bits.
+ */
+ if (page_size >= PMD_SIZE)
+ flags = protval_large_2_4k(flags);
+ MAP_AT_LEVEL(pmd, PMD, pte, PAGE);
+
+ VM_BUG_ON(true); /* Should never reach here. */
+ }
+
+ return 0;
+#undef MAP_AT_LEVEL
+}
+
+int __must_check asi_map(struct asi *asi, void *addr, unsigned long len)
+{
+ return asi_map_gfp(asi, addr, len, GFP_KERNEL);
+}
+
+/*
+ * Unmap a kernel address range previously mapped into the ASI page tables.
+ *
+ * The area being unmapped must be a whole previously mapped region (or regions)
+ * Unmapping a partial subset of a previously mapped region is not supported.
+ * That will work, but may end up unmapping more than what was asked for, if
+ * the mapping contained huge pages. A later patch will remove this limitation
+ * by splitting the huge mapping in the ASI page table in such a case. For now,
+ * vunmap_pgd_range() will just emit a warning if this situation is detected.
+ *
+ * This might sleep, and cannot be called with interrupts disabled.
+ */
+void asi_unmap(struct asi *asi, void *addr, size_t len)
+{
+ size_t start = (size_t)addr;
+ size_t end = start + len;
+ pgtbl_mod_mask mask = 0;
+
+ if (!static_asi_enabled() || !len)
+ return;
+
+ VM_BUG_ON(start & ~PAGE_MASK);
+ VM_BUG_ON(len & ~PAGE_MASK);
+ VM_BUG_ON(!fault_in_kernel_space(start)); /* Misnamed, ignore "fault_" */
+
+ vunmap_pgd_range(asi->pgd, start, end, &mask);
+
+ /* We don't support partial unmappings. */
+ if (mask & PGTBL_P4D_MODIFIED) {
+ VM_WARN_ON(!IS_ALIGNED((ulong)addr, P4D_SIZE));
+ VM_WARN_ON(!IS_ALIGNED((ulong)len, P4D_SIZE));
+ } else if (mask & PGTBL_PUD_MODIFIED) {
+ VM_WARN_ON(!IS_ALIGNED((ulong)addr, PUD_SIZE));
+ VM_WARN_ON(!IS_ALIGNED((ulong)len, PUD_SIZE));
+ } else if (mask & PGTBL_PMD_MODIFIED) {
+ VM_WARN_ON(!IS_ALIGNED((ulong)addr, PMD_SIZE));
+ VM_WARN_ON(!IS_ALIGNED((ulong)len, PMD_SIZE));
+ }
+
+ asi_flush_tlb_range(asi, addr, len);
+}
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index c41e083c5b5281684be79ad0391c1a5fc7b0c493..c55733e144c7538ce7f97b74ea2b1b9c22497c32 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -1040,6 +1040,11 @@ noinstr u16 asi_pcid(struct asi *asi, u16 asid)
// return kern_pcid(asid) | ((asi->index + 1) << X86_CR3_ASI_PCID_BITS_SHIFT);
}
+void asi_flush_tlb_range(struct asi *asi, void *addr, size_t len)
+{
+ flush_tlb_kernel_range((ulong)addr, (ulong)addr + len);
+}
+
#else /* CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION */
u16 asi_pcid(struct asi *asi, u16 asid) { return kern_pcid(asid); }
diff --git a/include/asm-generic/asi.h b/include/asm-generic/asi.h
index f777a6cf604b0656fb39087f6eba08f980b2cb6f..5be8f7d657ba0bc2196e333f62b084d0c9eef7b6 100644
--- a/include/asm-generic/asi.h
+++ b/include/asm-generic/asi.h
@@ -77,6 +77,17 @@ static inline int asi_intr_nest_depth(void) { return 0; }
static inline void asi_intr_exit(void) { }
+static inline int asi_map(struct asi *asi, void *addr, size_t len)
+{
+ return 0;
+}
+
+static inline
+void asi_unmap(struct asi *asi, void *addr, size_t len) { }
+
+static inline
+void asi_flush_tlb_range(struct asi *asi, void *addr, size_t len) { }
+
#define static_asi_enabled() false
static inline void asi_check_boottime_disable(void) { }
diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
index e8b2ac6bd2ae3b0a768734c8411f45a7d162e12d..492a9cdee7ff3d4e562c4bf508dc14fd7fa67e36 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -1900,6 +1900,9 @@ typedef unsigned int pgtbl_mod_mask;
#ifndef pmd_leaf
#define pmd_leaf(x) false
#endif
+#ifndef pte_leaf
+#define pte_leaf(x) 1
+#endif
#ifndef pgd_leaf_size
#define pgd_leaf_size(x) (1ULL << PGDIR_SHIFT)
diff --git a/mm/internal.h b/mm/internal.h
index 64c2eb0b160e169ab9134e3ab618d8a1d552d92c..c0454fe019b9078a963b1ab3685bf31ccfd768b7 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -395,6 +395,8 @@ void unmap_page_range(struct mmu_gather *tlb,
void page_cache_ra_order(struct readahead_control *, struct file_ra_state *,
unsigned int order);
void force_page_cache_ra(struct readahead_control *, unsigned long nr);
+void vunmap_pgd_range(pgd_t *pgd_table, unsigned long addr, unsigned long end,
+ pgtbl_mod_mask *mask);
static inline void force_page_cache_readahead(struct address_space *mapping,
struct file *file, pgoff_t index, unsigned long nr_to_read)
{
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 634162271c0045965eabd9bfe8b64f4a1135576c..8d260f2174fe664b54dcda054cb9759ae282bf03 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -427,6 +427,24 @@ static void vunmap_p4d_range(pgd_t *pgd, unsigned long addr, unsigned long end,
} while (p4d++, addr = next, addr != end);
}
+void vunmap_pgd_range(pgd_t *pgd_table, unsigned long addr, unsigned long end,
+ pgtbl_mod_mask *mask)
+{
+ unsigned long next;
+ pgd_t *pgd = pgd_offset_pgd(pgd_table, addr);
+
+ BUG_ON(addr >= end);
+
+ do {
+ next = pgd_addr_end(addr, end);
+ if (pgd_bad(*pgd))
+ *mask |= PGTBL_PGD_MODIFIED;
+ if (pgd_none_or_clear_bad(pgd))
+ continue;
+ vunmap_p4d_range(pgd, addr, next, mask);
+ } while (pgd++, addr = next, addr != end);
+}
+
/*
* vunmap_range_noflush is similar to vunmap_range, but does not
* flush caches or TLBs.
@@ -441,21 +459,9 @@ static void vunmap_p4d_range(pgd_t *pgd, unsigned long addr, unsigned long end,
*/
void __vunmap_range_noflush(unsigned long start, unsigned long end)
{
- unsigned long next;
- pgd_t *pgd;
- unsigned long addr = start;
pgtbl_mod_mask mask = 0;
- BUG_ON(addr >= end);
- pgd = pgd_offset_k(addr);
- do {
- next = pgd_addr_end(addr, end);
- if (pgd_bad(*pgd))
- mask |= PGTBL_PGD_MODIFIED;
- if (pgd_none_or_clear_bad(pgd))
- continue;
- vunmap_p4d_range(pgd, addr, next, &mask);
- } while (pgd++, addr = next, addr != end);
+ vunmap_pgd_range(init_mm.pgd, start, end, &mask);
if (mask & ARCH_PAGE_TABLE_SYNC_MASK)
arch_sync_kernel_mappings(start, end);
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH RFC v2 12/29] mm: asi: Add basic infrastructure for global non-sensitive mappings
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
` (10 preceding siblings ...)
2025-01-10 18:40 ` [PATCH RFC v2 11/29] mm: asi: Functions to map/unmap a memory range into ASI page tables Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 13/29] mm: Add __PAGEFLAG_FALSE Brendan Jackman
` (16 subsequent siblings)
28 siblings, 0 replies; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman, Junaid Shahid
From: Junaid Shahid <junaids@google.com>
A pseudo-PGD is added to store global non-sensitive ASI mappings.
Actual ASI PGDs copy entries from this pseudo-PGD during asi_init().
Memory can be mapped as globally non-sensitive by calling asi_map()
with ASI_GLOBAL_NONSENSITIVE.
Page tables allocated for global non-sensitive mappings are never
freed.
These page tables are shared between all domains and init_mm, so they
don't need special synchronization.
RFC note: A refactoring/prep commit should be split out of this patch.
Signed-off-by: Junaid Shahid <junaids@google.com>
Signed-off-by: Brendan Jackman <jackmanb@google.com>
---
arch/x86/include/asm/asi.h | 3 +++
arch/x86/mm/asi.c | 37 +++++++++++++++++++++++++++++++++++++
arch/x86/mm/init_64.c | 25 ++++++++++++++++---------
arch/x86/mm/mm_internal.h | 3 +++
include/asm-generic/asi.h | 2 ++
5 files changed, 61 insertions(+), 9 deletions(-)
diff --git a/arch/x86/include/asm/asi.h b/arch/x86/include/asm/asi.h
index 33f18be0e268b3a6725196619cbb8d847c21e197..555edb5f292e4d6baba782f51d014aa48dc850b6 100644
--- a/arch/x86/include/asm/asi.h
+++ b/arch/x86/include/asm/asi.h
@@ -120,6 +120,9 @@ struct asi_taint_policy {
asi_taints_t set;
};
+extern struct asi __asi_global_nonsensitive;
+#define ASI_GLOBAL_NONSENSITIVE (&__asi_global_nonsensitive)
+
/*
* An ASI domain (struct asi) represents a restricted address space. The
* unrestricted address space (and user address space under PTI) are not
diff --git a/arch/x86/mm/asi.c b/arch/x86/mm/asi.c
index f2d8fbc0366c289891903e1c2ac6c59b9476d95f..17391ec8b22e3c0903cd5ca29cbb03fcc4cbacce 100644
--- a/arch/x86/mm/asi.c
+++ b/arch/x86/mm/asi.c
@@ -13,6 +13,7 @@
#include <asm/mmu_context.h>
#include <asm/traps.h>
+#include "mm_internal.h"
#include "../../../mm/internal.h"
static struct asi_taint_policy *taint_policies[ASI_MAX_NUM_CLASSES];
@@ -26,6 +27,13 @@ const char *asi_class_names[] = {
DEFINE_PER_CPU_ALIGNED(struct asi *, curr_asi);
EXPORT_SYMBOL(curr_asi);
+static __aligned(PAGE_SIZE) pgd_t asi_global_nonsensitive_pgd[PTRS_PER_PGD];
+
+struct asi __asi_global_nonsensitive = {
+ .pgd = asi_global_nonsensitive_pgd,
+ .mm = &init_mm,
+};
+
static inline bool asi_class_id_valid(enum asi_class_id class_id)
{
return class_id >= 0 && class_id < ASI_MAX_NUM_CLASSES;
@@ -156,6 +164,31 @@ void __init asi_check_boottime_disable(void)
pr_info("ASI enablement ignored due to incomplete implementation.\n");
}
+static int __init asi_global_init(void)
+{
+ if (!boot_cpu_has(X86_FEATURE_ASI))
+ return 0;
+
+ /*
+ * Lower-level pagetables for global nonsensitive mappings are shared,
+ * but the PGD has to be copied into each domain during asi_init. To
+ * avoid needing to synchronize new mappings into pre-existing domains
+ * we just pre-allocate all of the relevant level N-1 entries so that
+ * the global nonsensitive PGD already has pointers that can be copied
+ * when new domains get asi_init()ed.
+ */
+ preallocate_sub_pgd_pages(asi_global_nonsensitive_pgd,
+ PAGE_OFFSET,
+ PAGE_OFFSET + PFN_PHYS(max_pfn) - 1,
+ "ASI Global Non-sensitive direct map");
+ preallocate_sub_pgd_pages(asi_global_nonsensitive_pgd,
+ VMALLOC_START, VMALLOC_END,
+ "ASI Global Non-sensitive vmalloc");
+
+ return 0;
+}
+subsys_initcall(asi_global_init)
+
static void __asi_destroy(struct asi *asi)
{
WARN_ON_ONCE(asi->ref_count <= 0);
@@ -170,6 +203,7 @@ int asi_init(struct mm_struct *mm, enum asi_class_id class_id, struct asi **out_
{
struct asi *asi;
int err = 0;
+ uint i;
*out_asi = NULL;
@@ -203,6 +237,9 @@ int asi_init(struct mm_struct *mm, enum asi_class_id class_id, struct asi **out_
asi->mm = mm;
asi->class_id = class_id;
+ for (i = KERNEL_PGD_BOUNDARY; i < PTRS_PER_PGD; i++)
+ set_pgd(asi->pgd + i, asi_global_nonsensitive_pgd[i]);
+
exit_unlock:
if (err)
__asi_destroy(asi);
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index ff253648706fa9cd49169a54882014a72ad540cf..9d358a05c4e18ac6d5e115de111758ea6cdd37f2 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -1288,18 +1288,15 @@ static void __init register_page_bootmem_info(void)
#endif
}
-/*
- * Pre-allocates page-table pages for the vmalloc area in the kernel page-table.
- * Only the level which needs to be synchronized between all page-tables is
- * allocated because the synchronization can be expensive.
- */
-static void __init preallocate_vmalloc_pages(void)
+/* Initialize empty pagetables at the level below PGD. */
+void __init preallocate_sub_pgd_pages(pgd_t *pgd_table, ulong start,
+ ulong end, const char *name)
{
unsigned long addr;
const char *lvl;
- for (addr = VMALLOC_START; addr <= VMEMORY_END; addr = ALIGN(addr + 1, PGDIR_SIZE)) {
- pgd_t *pgd = pgd_offset_k(addr);
+ for (addr = start; addr <= end; addr = ALIGN(addr + 1, PGDIR_SIZE)) {
+ pgd_t *pgd = pgd_offset_pgd(pgd_table, addr);
p4d_t *p4d;
pud_t *pud;
@@ -1335,7 +1332,17 @@ static void __init preallocate_vmalloc_pages(void)
* The pages have to be there now or they will be missing in
* process page-tables later.
*/
- panic("Failed to pre-allocate %s pages for vmalloc area\n", lvl);
+ panic("Failed to pre-allocate %s pages for %s area\n", lvl, name);
+}
+
+/*
+ * Pre-allocates page-table pages for the vmalloc area in the kernel page-table.
+ * Only the level which needs to be synchronized between all page-tables is
+ * allocated because the synchronization can be expensive.
+ */
+static void __init preallocate_vmalloc_pages(void)
+{
+ preallocate_sub_pgd_pages(init_mm.pgd, VMALLOC_START, VMEMORY_END, "vmalloc");
}
void __init mem_init(void)
diff --git a/arch/x86/mm/mm_internal.h b/arch/x86/mm/mm_internal.h
index 3f37b5c80bb32ff34656a20789449da92e853eb6..1203a977edcd523589ad88a37aab01398a10a129 100644
--- a/arch/x86/mm/mm_internal.h
+++ b/arch/x86/mm/mm_internal.h
@@ -25,4 +25,7 @@ void update_cache_mode_entry(unsigned entry, enum page_cache_mode cache);
extern unsigned long tlb_single_page_flush_ceiling;
+extern void preallocate_sub_pgd_pages(pgd_t *pgd_table, ulong start,
+ ulong end, const char *name);
+
#endif /* __X86_MM_INTERNAL_H */
diff --git a/include/asm-generic/asi.h b/include/asm-generic/asi.h
index 5be8f7d657ba0bc2196e333f62b084d0c9eef7b6..7867b8c23449058a1dd06308ab5351e0d210a489 100644
--- a/include/asm-generic/asi.h
+++ b/include/asm-generic/asi.h
@@ -23,6 +23,8 @@ typedef u8 asi_taints_t;
#ifndef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
+#define ASI_GLOBAL_NONSENSITIVE NULL
+
struct asi_hooks {};
struct asi {};
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH RFC v2 13/29] mm: Add __PAGEFLAG_FALSE
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
` (11 preceding siblings ...)
2025-01-10 18:40 ` [PATCH RFC v2 12/29] mm: asi: Add basic infrastructure for global non-sensitive mappings Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 14/29] mm: asi: Map non-user buddy allocations as nonsensitive Brendan Jackman
` (15 subsequent siblings)
28 siblings, 0 replies; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman
__PAGEFLAG_FALSE is a non-atomic equivalent of PAGEFLAG_FALSE.
Checkpatch-args: --ignore=COMPLEX_MACRO
Signed-off-by: Brendan Jackman <jackmanb@google.com>
---
include/linux/page-flags.h | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index cc839e4365c18223e68c35efd0f67e7650708e8b..7ee9a0edc6d21708fc93dfa8913dc1ae9478dee3 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -484,6 +484,10 @@ static inline int Page##uname(const struct page *page) { return 0; }
FOLIO_SET_FLAG_NOOP(lname) \
static inline void SetPage##uname(struct page *page) { }
+#define __SETPAGEFLAG_NOOP(uname, lname) \
+static inline void __folio_set_##lname(struct folio *folio) { } \
+static inline void __SetPage##uname(struct page *page) { }
+
#define CLEARPAGEFLAG_NOOP(uname, lname) \
FOLIO_CLEAR_FLAG_NOOP(lname) \
static inline void ClearPage##uname(struct page *page) { }
@@ -506,6 +510,9 @@ static inline int TestClearPage##uname(struct page *page) { return 0; }
#define TESTSCFLAG_FALSE(uname, lname) \
TESTSETFLAG_FALSE(uname, lname) TESTCLEARFLAG_FALSE(uname, lname)
+#define __PAGEFLAG_FALSE(uname, lname) TESTPAGEFLAG_FALSE(uname, lname) \
+ __SETPAGEFLAG_NOOP(uname, lname) __CLEARPAGEFLAG_NOOP(uname, lname)
+
__PAGEFLAG(Locked, locked, PF_NO_TAIL)
FOLIO_FLAG(waiters, FOLIO_HEAD_PAGE)
FOLIO_FLAG(referenced, FOLIO_HEAD_PAGE)
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH RFC v2 14/29] mm: asi: Map non-user buddy allocations as nonsensitive
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
` (12 preceding siblings ...)
2025-01-10 18:40 ` [PATCH RFC v2 13/29] mm: Add __PAGEFLAG_FALSE Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
2025-01-10 18:40 ` [PATCH TEMP WORKAROUND RFC v2 15/29] mm: asi: Workaround missing partial-unmap support Brendan Jackman
` (14 subsequent siblings)
28 siblings, 0 replies; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman
This is just simplest possible page_alloc patch I could come up with to
demonstrate ASI working in a "denylist" mode: we map the direct map into
the restricted address space, except pages allocated with GFP_USER.
Pages must be asi_unmap()'d before they can be re-allocated. This
requires a TLB flush, which can't generally be done from the free path
(requires IRQs on), so pages that need unmapping are freed via a
workqueue.
This solution is not ideal:
- If the async queue gets long, we'll run out of allocatable memory.
- We don't batch the TLB flushing or worker wakeups at all.
- We drop FPI flags and skip the pcplists.
Internally at Google we've so far found with extra complexity we're able
to make this solution work for the workloads we've tested so far. It
seems likely this won't keep working forever. So instead for the [PATCH]
version I hope to come up with an implementation that instead just makes
the allocator more deeply aware of sensitivity, most likely this will
look a bit like an extra "dimension" like movability etc. This was
discussed at LSF/MM/BPF [1], I plan to research this right after RFCv2.
However, once that research is done we might want to consider merging a
sub-optimal solution to unblock iteration and development.
[1] https://youtu.be/WD9-ey8LeiI
The main thing in here that is "real" and may warrant discussion is
__GFP_SENSITIVE (or at least, some sort of allocator switch to determine
sensitivity, in an "allowlist" model we would probably have the
opposite, and in future iterations we might want additional options for
different "types" of sensitivity). I think we need this as an extension
to the allocation API; the main alternative would be to infer from
context of the allocation whether the data should be treated as
sensitive; however I think we will have contexts where both sensitive
and nonsensitive data needs to be allocatable.
If there are concerns about __GFP flags specifically, rather than just
the general problem of expanding the allocator API, we could always just
provide an API like __alloc_pages_sensitive or something, implemented
with ALLOC_ flags internally.
Checkpatch-args: --ignore=SPACING,MACRO_ARG_UNUSED,COMPLEX_MACRO
Signed-off-by: Brendan Jackman <jackmanb@google.com>
---
arch/x86/mm/asi.c | 33 +++++++++-
include/linux/gfp.h | 5 ++
include/linux/gfp_types.h | 15 ++++-
include/linux/page-flags.h | 11 ++++
include/trace/events/mmflags.h | 12 +++-
mm/mm_init.c | 1 +
mm/page_alloc.c | 134 ++++++++++++++++++++++++++++++++++++++++-
tools/perf/builtin-kmem.c | 1 +
8 files changed, 205 insertions(+), 7 deletions(-)
diff --git a/arch/x86/mm/asi.c b/arch/x86/mm/asi.c
index 17391ec8b22e3c0903cd5ca29cbb03fcc4cbacce..b951f2100b8bdea5738ded16166255deb29faf57 100644
--- a/arch/x86/mm/asi.c
+++ b/arch/x86/mm/asi.c
@@ -5,6 +5,8 @@
#include <linux/spinlock.h>
#include <linux/init.h>
+#include <linux/pgtable.h>
+
#include <asm/asi.h>
#include <asm/cmdline.h>
#include <asm/cpufeature.h>
@@ -104,10 +106,17 @@ const char *asi_class_name(enum asi_class_id class_id)
* allocator from interrupts and the page allocator ultimately calls this
* code.
* - They support customizing the allocation flags.
+ * - They avoid infinite recursion when the page allocator calls back to
+ * asi_map
*
* On the other hand, they do not use the normal page allocation infrastructure,
* that means that PTE pages do not have the PageTable type nor the PagePgtable
* flag and we don't increment the meminfo stat (NR_PAGETABLE) as they do.
+ *
+ * As an optimisation we attempt to map the pagetables in
+ * ASI_GLOBAL_NONSENSITIVE, but this can fail, and for simplicity we don't do
+ * anything about that. This means it's invalid to access ASI pagetables from a
+ * critical section.
*/
static_assert(!IS_ENABLED(CONFIG_PARAVIRT));
#define DEFINE_ASI_PGTBL_ALLOC(base, level) \
@@ -116,8 +125,11 @@ static level##_t * asi_##level##_alloc(struct asi *asi, \
gfp_t flags) \
{ \
if (unlikely(base##_none(*base))) { \
- ulong pgtbl = get_zeroed_page(flags); \
+ /* Stop asi_map calls causing recursive allocation */ \
+ gfp_t pgtbl_gfp = flags | __GFP_SENSITIVE; \
+ ulong pgtbl = get_zeroed_page(pgtbl_gfp); \
phys_addr_t pgtbl_pa; \
+ int err; \
\
if (!pgtbl) \
return NULL; \
@@ -131,6 +143,16 @@ static level##_t * asi_##level##_alloc(struct asi *asi, \
} \
\
mm_inc_nr_##level##s(asi->mm); \
+ \
+ err = asi_map_gfp(ASI_GLOBAL_NONSENSITIVE, \
+ (void *)pgtbl, PAGE_SIZE, flags); \
+ if (err) \
+ /* Should be rare. Spooky. */ \
+ pr_warn_ratelimited("Created sensitive ASI %s (%pK, maps %luK).\n",\
+ #level, (void *)pgtbl, addr); \
+ else \
+ __SetPageGlobalNonSensitive(virt_to_page(pgtbl));\
+ \
} \
out: \
VM_BUG_ON(base##_leaf(*base)); \
@@ -586,6 +608,9 @@ static bool follow_physaddr(
* reason for this is that we don't want to unexpectedly undo mappings that
* weren't created by the present caller.
*
+ * This must not be called from the critical section, as ASI's pagetables are
+ * not guaranteed to be mapped in the restricted address space.
+ *
* If the source mapping is a large page and the range being mapped spans the
* entire large page, then it will be mapped as a large page in the ASI page
* tables too. If the range does not span the entire huge page, then it will be
@@ -606,6 +631,9 @@ int __must_check asi_map_gfp(struct asi *asi, void *addr, unsigned long len, gfp
if (!static_asi_enabled())
return 0;
+ /* ASI pagetables might be sensitive. */
+ WARN_ON_ONCE(asi_in_critical_section());
+
VM_BUG_ON(!IS_ALIGNED(start, PAGE_SIZE));
VM_BUG_ON(!IS_ALIGNED(len, PAGE_SIZE));
/* RFC: fault_in_kernel_space should be renamed. */
@@ -706,6 +734,9 @@ void asi_unmap(struct asi *asi, void *addr, size_t len)
if (!static_asi_enabled() || !len)
return;
+ /* ASI pagetables might be sensitive. */
+ WARN_ON_ONCE(asi_in_critical_section());
+
VM_BUG_ON(start & ~PAGE_MASK);
VM_BUG_ON(len & ~PAGE_MASK);
VM_BUG_ON(!fault_in_kernel_space(start)); /* Misnamed, ignore "fault_" */
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index a951de920e208991b37fb2d878d9a0e9c550548c..dd3678b5b08016ceaee2d8e1932bf4aefbc7efb0 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -396,6 +396,11 @@ extern void page_frag_free(void *addr);
#define __free_page(page) __free_pages((page), 0)
#define free_page(addr) free_pages((addr), 0)
+#ifdef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
+void page_alloc_init_asi(void);
+#else
+static inline void page_alloc_init_asi(void) { }
+#endif
void page_alloc_init_cpuhp(void);
int decay_pcp_high(struct zone *zone, struct per_cpu_pages *pcp);
void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp);
diff --git a/include/linux/gfp_types.h b/include/linux/gfp_types.h
index 65db9349f9053c701e24bdcf1dfe6afbf1278a2d..5147dbd53eafdccc32cfd506569b04d5c082d1b2 100644
--- a/include/linux/gfp_types.h
+++ b/include/linux/gfp_types.h
@@ -58,6 +58,7 @@ enum {
#ifdef CONFIG_SLAB_OBJ_EXT
___GFP_NO_OBJ_EXT_BIT,
#endif
+ ___GFP_SENSITIVE_BIT,
___GFP_LAST_BIT
};
@@ -103,6 +104,11 @@ enum {
#else
#define ___GFP_NO_OBJ_EXT 0
#endif
+#ifdef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
+#define ___GFP_SENSITIVE BIT(___GFP_SENSITIVE_BIT)
+#else
+#define ___GFP_SENSITIVE 0
+#endif
/*
* Physical address zone modifiers (see linux/mmzone.h - low four bits)
@@ -299,6 +305,12 @@ enum {
/* Disable lockdep for GFP context tracking */
#define __GFP_NOLOCKDEP ((__force gfp_t)___GFP_NOLOCKDEP)
+/*
+ * Allocate sensitive memory, i.e. do not map it into ASI's restricted address
+ * space.
+ */
+#define __GFP_SENSITIVE ((__force gfp_t)___GFP_SENSITIVE)
+
/* Room for N __GFP_FOO bits */
#define __GFP_BITS_SHIFT ___GFP_LAST_BIT
#define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1))
@@ -380,7 +392,8 @@ enum {
#define GFP_NOWAIT (__GFP_KSWAPD_RECLAIM | __GFP_NOWARN)
#define GFP_NOIO (__GFP_RECLAIM)
#define GFP_NOFS (__GFP_RECLAIM | __GFP_IO)
-#define GFP_USER (__GFP_RECLAIM | __GFP_IO | __GFP_FS | __GFP_HARDWALL)
+#define GFP_USER (__GFP_RECLAIM | __GFP_IO | __GFP_FS | \
+ __GFP_HARDWALL | __GFP_SENSITIVE)
#define GFP_DMA __GFP_DMA
#define GFP_DMA32 __GFP_DMA32
#define GFP_HIGHUSER (GFP_USER | __GFP_HIGHMEM)
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 7ee9a0edc6d21708fc93dfa8913dc1ae9478dee3..761b082f1885976b860196d8e69044276e8fa9ca 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -125,6 +125,9 @@ enum pageflags {
#endif
#ifdef CONFIG_ARCH_USES_PG_ARCH_3
PG_arch_3,
+#endif
+#ifdef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
+ PG_global_nonsensitive,
#endif
__NR_PAGEFLAGS,
@@ -632,6 +635,14 @@ FOLIO_TEST_CLEAR_FLAG_FALSE(young)
FOLIO_FLAG_FALSE(idle)
#endif
+#ifdef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
+__PAGEFLAG(GlobalNonSensitive, global_nonsensitive, PF_ANY);
+#define __PG_GLOBAL_NONSENSITIVE (1UL << PG_global_nonsensitive)
+#else
+__PAGEFLAG_FALSE(GlobalNonSensitive, global_nonsensitive);
+#define __PG_GLOBAL_NONSENSITIVE 0
+#endif
+
/*
* PageReported() is used to track reported free pages within the Buddy
* allocator. We can use the non-atomic version of the test and set
diff --git a/include/trace/events/mmflags.h b/include/trace/events/mmflags.h
index bb8a59c6caa21971862b6f200263c74cedff3882..a511a76b4310e949fd5b40b01253cf7d262f0177 100644
--- a/include/trace/events/mmflags.h
+++ b/include/trace/events/mmflags.h
@@ -50,7 +50,8 @@
gfpflag_string(__GFP_RECLAIM), \
gfpflag_string(__GFP_DIRECT_RECLAIM), \
gfpflag_string(__GFP_KSWAPD_RECLAIM), \
- gfpflag_string(__GFP_ZEROTAGS)
+ gfpflag_string(__GFP_ZEROTAGS), \
+ gfpflag_string(__GFP_SENSITIVE)
#ifdef CONFIG_KASAN_HW_TAGS
#define __def_gfpflag_names_kasan , \
@@ -95,6 +96,12 @@
#define IF_HAVE_PG_ARCH_3(_name)
#endif
+#ifdef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
+#define IF_HAVE_ASI(_name) ,{1UL << PG_##_name, __stringify(_name)}
+#else
+#define IF_HAVE_ASI(_name)
+#endif
+
#define DEF_PAGEFLAG_NAME(_name) { 1UL << PG_##_name, __stringify(_name) }
#define __def_pageflag_names \
@@ -122,7 +129,8 @@ IF_HAVE_PG_HWPOISON(hwpoison) \
IF_HAVE_PG_IDLE(idle) \
IF_HAVE_PG_IDLE(young) \
IF_HAVE_PG_ARCH_2(arch_2) \
-IF_HAVE_PG_ARCH_3(arch_3)
+IF_HAVE_PG_ARCH_3(arch_3) \
+IF_HAVE_ASI(global_nonsensitive)
#define show_page_flags(flags) \
(flags) ? __print_flags(flags, "|", \
diff --git a/mm/mm_init.c b/mm/mm_init.c
index 4ba5607aaf1943214c7f79f2a52e17eefac2ad79..30b84c0dd8b764e91fb64b116805ebb46526dd7e 100644
--- a/mm/mm_init.c
+++ b/mm/mm_init.c
@@ -2639,6 +2639,7 @@ void __init mm_core_init(void)
BUILD_BUG_ON(MAX_ZONELISTS > 2);
build_all_zonelists(NULL);
page_alloc_init_cpuhp();
+ page_alloc_init_asi();
/*
* page_ext requires contiguous pages,
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index b6958333054d06ed910f8fef863d83a7312eca9e..3e98fdfbadddb1f7d71e9e050b63255b2008d167 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1041,6 +1041,8 @@ static void kernel_init_pages(struct page *page, int numpages)
kasan_enable_current();
}
+static bool asi_async_free_enqueue(struct page *page, unsigned int order);
+
__always_inline bool free_pages_prepare(struct page *page,
unsigned int order)
{
@@ -1049,6 +1051,11 @@ __always_inline bool free_pages_prepare(struct page *page,
bool init = want_init_on_free();
bool compound = PageCompound(page);
struct folio *folio = page_folio(page);
+ /*
+ * __PG_GLOBAL_NONSENSITIVE needs to be kept around for the ASI async
+ * free logic.
+ */
+ unsigned long flags_mask = ~PAGE_FLAGS_CHECK_AT_PREP | __PG_GLOBAL_NONSENSITIVE;
VM_BUG_ON_PAGE(PageTail(page), page);
@@ -1107,7 +1114,7 @@ __always_inline bool free_pages_prepare(struct page *page,
continue;
}
}
- (page + i)->flags &= ~PAGE_FLAGS_CHECK_AT_PREP;
+ (page + i)->flags &= flags_mask;
}
}
if (PageMappingFlags(page)) {
@@ -1123,7 +1130,7 @@ __always_inline bool free_pages_prepare(struct page *page,
}
page_cpupid_reset_last(page);
- page->flags &= ~PAGE_FLAGS_CHECK_AT_PREP;
+ page->flags &= flags_mask;
reset_page_owner(page, order);
page_table_check_free(page, order);
pgalloc_tag_sub(page, 1 << order);
@@ -1164,7 +1171,7 @@ __always_inline bool free_pages_prepare(struct page *page,
debug_pagealloc_unmap_pages(page, 1 << order);
- return true;
+ return !asi_async_free_enqueue(page, order);
}
/*
@@ -4528,6 +4535,118 @@ static inline bool prepare_alloc_pages(gfp_t gfp_mask, unsigned int order,
return true;
}
+#ifdef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
+
+struct asi_async_free_cpu_state {
+ struct work_struct work;
+ struct list_head to_free;
+};
+static DEFINE_PER_CPU(struct asi_async_free_cpu_state, asi_async_free_cpu_state);
+
+static void asi_async_free_work_fn(struct work_struct *work)
+{
+ struct asi_async_free_cpu_state *cpu_state =
+ container_of(work, struct asi_async_free_cpu_state, work);
+ struct page *page, *tmp;
+ struct list_head to_free = LIST_HEAD_INIT(to_free);
+
+ local_irq_disable();
+ list_splice_init(&cpu_state->to_free, &to_free);
+ local_irq_enable(); /* IRQs must be on for asi_unmap. */
+
+ /* Use _safe because __free_the_page uses .lru */
+ list_for_each_entry_safe(page, tmp, &to_free, lru) {
+ unsigned long order = page_private(page);
+
+ asi_unmap(ASI_GLOBAL_NONSENSITIVE, page_to_virt(page),
+ PAGE_SIZE << order);
+ for (int i = 0; i < (1 << order); i++)
+ __ClearPageGlobalNonSensitive(page + i);
+
+ free_one_page(page_zone(page), page, page_to_pfn(page), order, FPI_NONE);
+ cond_resched();
+ }
+}
+
+/* Returns true if the page was queued for asynchronous freeing. */
+static bool asi_async_free_enqueue(struct page *page, unsigned int order)
+{
+ struct asi_async_free_cpu_state *cpu_state;
+ unsigned long flags;
+
+ if (!PageGlobalNonSensitive(page))
+ return false;
+
+ local_irq_save(flags);
+ cpu_state = this_cpu_ptr(&asi_async_free_cpu_state);
+ set_page_private(page, order);
+ list_add(&page->lru, &cpu_state->to_free);
+ if (mm_percpu_wq)
+ queue_work_on(smp_processor_id(), mm_percpu_wq, &cpu_state->work);
+ local_irq_restore(flags);
+
+ return true;
+}
+
+void __init page_alloc_init_asi(void)
+{
+ int cpu;
+
+ if (!static_asi_enabled())
+ return;
+
+ for_each_possible_cpu(cpu) {
+ struct asi_async_free_cpu_state *cpu_state
+ = &per_cpu(asi_async_free_cpu_state, cpu);
+
+ INIT_WORK(&cpu_state->work, asi_async_free_work_fn);
+ INIT_LIST_HEAD(&cpu_state->to_free);
+ }
+}
+
+static int asi_map_alloced_pages(struct page *page, uint order, gfp_t gfp_mask)
+{
+
+ if (!static_asi_enabled())
+ return 0;
+
+ if (!(gfp_mask & __GFP_SENSITIVE)) {
+ int err = asi_map_gfp(
+ ASI_GLOBAL_NONSENSITIVE, page_to_virt(page),
+ PAGE_SIZE * (1 << order), gfp_mask);
+ uint i;
+
+ if (err)
+ return err;
+
+ for (i = 0; i < (1 << order); i++)
+ __SetPageGlobalNonSensitive(page + i);
+ }
+
+ return 0;
+}
+
+#else /* CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION */
+
+static inline
+int asi_map_alloced_pages(struct page *pages, uint order, gfp_t gfp_mask)
+{
+ return 0;
+}
+
+static inline
+bool asi_unmap_freed_pages(struct page *page, unsigned int order)
+{
+ return true;
+}
+
+static bool asi_async_free_enqueue(struct page *page, unsigned int order)
+{
+ return false;
+}
+
+#endif
+
/*
* __alloc_pages_bulk - Allocate a number of order-0 pages to a list or array
* @gfp: GFP flags for the allocation
@@ -4727,6 +4846,10 @@ struct page *__alloc_pages_noprof(gfp_t gfp, unsigned int order,
if (WARN_ON_ONCE_GFP(order > MAX_PAGE_ORDER, gfp))
return NULL;
+ /* Clear out old (maybe sensitive) data before reallocating as nonsensitive. */
+ if (!static_asi_enabled() && !(gfp & __GFP_SENSITIVE))
+ gfp |= __GFP_ZERO;
+
gfp &= gfp_allowed_mask;
/*
* Apply scoped allocation constraints. This is mainly about GFP_NOFS
@@ -4773,6 +4896,11 @@ struct page *__alloc_pages_noprof(gfp_t gfp, unsigned int order,
trace_mm_page_alloc(page, order, alloc_gfp, ac.migratetype);
kmsan_alloc_page(page, order, alloc_gfp);
+ if (page && unlikely(asi_map_alloced_pages(page, order, gfp))) {
+ __free_pages(page, order);
+ page = NULL;
+ }
+
return page;
}
EXPORT_SYMBOL(__alloc_pages_noprof);
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index a756147e2eec7a3820e1953db346fafa8fe687ba..99f4c6632155d2573f1370af131c15c3d8baa655 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -682,6 +682,7 @@ static const struct {
{ "__GFP_RECLAIM", "R" },
{ "__GFP_DIRECT_RECLAIM", "DR" },
{ "__GFP_KSWAPD_RECLAIM", "KR" },
+ { "__GFP_SENSITIVE", "S" },
};
static size_t max_gfp_len;
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH TEMP WORKAROUND RFC v2 15/29] mm: asi: Workaround missing partial-unmap support
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
` (13 preceding siblings ...)
2025-01-10 18:40 ` [PATCH RFC v2 14/29] mm: asi: Map non-user buddy allocations as nonsensitive Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 16/29] mm: asi: Map kernel text and static data as nonsensitive Brendan Jackman
` (13 subsequent siblings)
28 siblings, 0 replies; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman
This is a hack, no need to review it carefully. asi_unmap() doesn't
currently work unless it corresponds exactly to an asi_map() of the
exact same region.
This is mostly harmless (it's only a functional problem if you wanna
touch those pages from the ASI critical section) but it's messy. For
now, working around the only practical case that appears by moving the
asi_map call up the call stack in the page allocator, to the place where
we know the actual size the mapping is supposed to end up at.
This just removes the main case where that happens. Later, a proper
solution for partial unmaps will be needed.
Signed-off-by: Brendan Jackman <jackmanb@google.com>
---
mm/page_alloc.c | 40 ++++++++++++++++++++++++++--------------
1 file changed, 26 insertions(+), 14 deletions(-)
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 3e98fdfbadddb1f7d71e9e050b63255b2008d167..f96e95032450be90b6567f67915b0b941fc431d8 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -4604,22 +4604,20 @@ void __init page_alloc_init_asi(void)
}
}
-static int asi_map_alloced_pages(struct page *page, uint order, gfp_t gfp_mask)
+static int asi_map_alloced_pages(struct page *page, size_t size, gfp_t gfp_mask)
{
if (!static_asi_enabled())
return 0;
if (!(gfp_mask & __GFP_SENSITIVE)) {
- int err = asi_map_gfp(
- ASI_GLOBAL_NONSENSITIVE, page_to_virt(page),
- PAGE_SIZE * (1 << order), gfp_mask);
+ int err = asi_map_gfp(ASI_GLOBAL_NONSENSITIVE, page_to_virt(page), size, gfp_mask);
uint i;
if (err)
return err;
- for (i = 0; i < (1 << order); i++)
+ for (i = 0; i < (size >> PAGE_SHIFT); i++)
__SetPageGlobalNonSensitive(page + i);
}
@@ -4629,7 +4627,7 @@ static int asi_map_alloced_pages(struct page *page, uint order, gfp_t gfp_mask)
#else /* CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION */
static inline
-int asi_map_alloced_pages(struct page *pages, uint order, gfp_t gfp_mask)
+int asi_map_alloced_pages(struct page *pages, size_t size, gfp_t gfp_mask)
{
return 0;
}
@@ -4896,7 +4894,7 @@ struct page *__alloc_pages_noprof(gfp_t gfp, unsigned int order,
trace_mm_page_alloc(page, order, alloc_gfp, ac.migratetype);
kmsan_alloc_page(page, order, alloc_gfp);
- if (page && unlikely(asi_map_alloced_pages(page, order, gfp))) {
+ if (page && unlikely(asi_map_alloced_pages(page, PAGE_SIZE << order, gfp))) {
__free_pages(page, order);
page = NULL;
}
@@ -5118,12 +5116,13 @@ void page_frag_free(void *addr)
}
EXPORT_SYMBOL(page_frag_free);
-static void *make_alloc_exact(unsigned long addr, unsigned int order,
- size_t size)
+static void *finish_exact_alloc(unsigned long addr, unsigned int order,
+ size_t size, gfp_t gfp_mask)
{
if (addr) {
unsigned long nr = DIV_ROUND_UP(size, PAGE_SIZE);
struct page *page = virt_to_page((void *)addr);
+ struct page *first = page;
struct page *last = page + nr;
split_page_owner(page, order, 0);
@@ -5132,9 +5131,22 @@ static void *make_alloc_exact(unsigned long addr, unsigned int order,
while (page < --last)
set_page_refcounted(last);
- last = page + (1UL << order);
+ last = page + (1 << order);
for (page += nr; page < last; page++)
__free_pages_ok(page, 0, FPI_TO_TAIL);
+
+ /*
+ * ASI doesn't support partially undoing calls to asi_map, so
+ * we can only safely free sub-allocations if they were made
+ * with __GFP_SENSITIVE in the first place. Users of this need
+ * to map with forced __GFP_SENSITIVE and then here we'll make a
+ * second asi_map_alloced_pages() call to do any mapping that's
+ * necessary, but with the exact size.
+ */
+ if (unlikely(asi_map_alloced_pages(first, nr << PAGE_SHIFT, gfp_mask))) {
+ free_pages_exact(first, size);
+ return NULL;
+ }
}
return (void *)addr;
}
@@ -5162,8 +5174,8 @@ void *alloc_pages_exact_noprof(size_t size, gfp_t gfp_mask)
if (WARN_ON_ONCE(gfp_mask & (__GFP_COMP | __GFP_HIGHMEM)))
gfp_mask &= ~(__GFP_COMP | __GFP_HIGHMEM);
- addr = get_free_pages_noprof(gfp_mask, order);
- return make_alloc_exact(addr, order, size);
+ addr = get_free_pages_noprof(gfp_mask | __GFP_SENSITIVE, order);
+ return finish_exact_alloc(addr, order, size, gfp_mask);
}
EXPORT_SYMBOL(alloc_pages_exact_noprof);
@@ -5187,10 +5199,10 @@ void * __meminit alloc_pages_exact_nid_noprof(int nid, size_t size, gfp_t gfp_ma
if (WARN_ON_ONCE(gfp_mask & (__GFP_COMP | __GFP_HIGHMEM)))
gfp_mask &= ~(__GFP_COMP | __GFP_HIGHMEM);
- p = alloc_pages_node_noprof(nid, gfp_mask, order);
+ p = alloc_pages_node_noprof(nid, gfp_mask | __GFP_SENSITIVE, order);
if (!p)
return NULL;
- return make_alloc_exact((unsigned long)page_address(p), order, size);
+ return finish_exact_alloc((unsigned long)page_address(p), order, size, gfp_mask);
}
/**
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH RFC v2 16/29] mm: asi: Map kernel text and static data as nonsensitive
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
` (14 preceding siblings ...)
2025-01-10 18:40 ` [PATCH TEMP WORKAROUND RFC v2 15/29] mm: asi: Workaround missing partial-unmap support Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
2025-01-17 11:23 ` Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 17/29] mm: asi: Map vmalloc/vmap " Brendan Jackman
` (12 subsequent siblings)
28 siblings, 1 reply; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman
Basically we need to map the kernel code and all its static variables.
Per-CPU variables need to be treated specially as described in the
comments. The cpu_entry_area is similar - this needs to be
nonsensitive so that the CPU can access the GDT etc when handling
a page fault.
Under 5-level paging, most of the kernel memory comes under a single PGD
entry (see Documentation/x86/x86_64/mm.rst. Basically, the mapping is
for this big region is the same as under 4-level, just wrapped in an
outer PGD entry). For that region, the "clone" logic is moved down one
step of the paging hierarchy.
Note that the p4d_alloc in asi_clone_p4d won't actually be used in
practice; the relevant PGD entry will always have been populated by
prior asi_map calls so this code would "work" if we just wrote
p4d_offset (but asi_clone_p4d would be broken if viewed in isolation).
The vmemmap area is not under this single PGD, it has its own 2-PGD
area, so we still use asi_clone_pgd for that one.
Signed-off-by: Brendan Jackman <jackmanb@google.com>
---
arch/x86/mm/asi.c | 105 +++++++++++++++++++++++++++++++++++++-
include/asm-generic/vmlinux.lds.h | 11 ++++
2 files changed, 115 insertions(+), 1 deletion(-)
diff --git a/arch/x86/mm/asi.c b/arch/x86/mm/asi.c
index b951f2100b8bdea5738ded16166255deb29faf57..bc2cf0475a0e7344a66d81453f55034b2fc77eef 100644
--- a/arch/x86/mm/asi.c
+++ b/arch/x86/mm/asi.c
@@ -7,7 +7,6 @@
#include <linux/init.h>
#include <linux/pgtable.h>
-#include <asm/asi.h>
#include <asm/cmdline.h>
#include <asm/cpufeature.h>
#include <asm/page.h>
@@ -186,8 +185,68 @@ void __init asi_check_boottime_disable(void)
pr_info("ASI enablement ignored due to incomplete implementation.\n");
}
+/*
+ * Map data by sharing sub-PGD pagetables with the unrestricted mapping. This is
+ * more efficient than asi_map, but only works when you know the whole top-level
+ * page needs to be mapped in the restricted tables. Note that the size of the
+ * mappings this creates differs between 4 and 5-level paging.
+ */
+static void asi_clone_pgd(pgd_t *dst_table, pgd_t *src_table, size_t addr)
+{
+ pgd_t *src = pgd_offset_pgd(src_table, addr);
+ pgd_t *dst = pgd_offset_pgd(dst_table, addr);
+
+ if (!pgd_val(*dst))
+ set_pgd(dst, *src);
+ else
+ WARN_ON_ONCE(pgd_val(*dst) != pgd_val(*src));
+}
+
+/*
+ * For 4-level paging this is exactly the same as asi_clone_pgd. For 5-level
+ * paging it clones one level lower. So this always creates a mapping of the
+ * same size.
+ */
+static void asi_clone_p4d(pgd_t *dst_table, pgd_t *src_table, size_t addr)
+{
+ pgd_t *src_pgd = pgd_offset_pgd(src_table, addr);
+ pgd_t *dst_pgd = pgd_offset_pgd(dst_table, addr);
+ p4d_t *src_p4d = p4d_alloc(&init_mm, src_pgd, addr);
+ p4d_t *dst_p4d = p4d_alloc(&init_mm, dst_pgd, addr);
+
+ if (!p4d_val(*dst_p4d))
+ set_p4d(dst_p4d, *src_p4d);
+ else
+ WARN_ON_ONCE(p4d_val(*dst_p4d) != p4d_val(*src_p4d));
+}
+
+/*
+ * percpu_addr is where the linker put the percpu variable. asi_map_percpu finds
+ * the place where the percpu allocator copied the data during boot.
+ *
+ * This is necessary even when the page allocator defaults to
+ * global-nonsensitive, because the percpu allocator uses the memblock allocator
+ * for early allocations.
+ */
+static int asi_map_percpu(struct asi *asi, void *percpu_addr, size_t len)
+{
+ int cpu, err;
+ void *ptr;
+
+ for_each_possible_cpu(cpu) {
+ ptr = per_cpu_ptr(percpu_addr, cpu);
+ err = asi_map(asi, ptr, len);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
static int __init asi_global_init(void)
{
+ int err;
+
if (!boot_cpu_has(X86_FEATURE_ASI))
return 0;
@@ -207,6 +266,46 @@ static int __init asi_global_init(void)
VMALLOC_START, VMALLOC_END,
"ASI Global Non-sensitive vmalloc");
+ /* Map all kernel text and static data */
+ err = asi_map(ASI_GLOBAL_NONSENSITIVE, (void *)__START_KERNEL,
+ (size_t)_end - __START_KERNEL);
+ if (WARN_ON(err))
+ return err;
+ err = asi_map(ASI_GLOBAL_NONSENSITIVE, (void *)FIXADDR_START,
+ FIXADDR_SIZE);
+ if (WARN_ON(err))
+ return err;
+ /* Map all static percpu data */
+ err = asi_map_percpu(
+ ASI_GLOBAL_NONSENSITIVE,
+ __per_cpu_start, __per_cpu_end - __per_cpu_start);
+ if (WARN_ON(err))
+ return err;
+
+ /*
+ * The next areas are mapped using shared sub-P4D paging structures
+ * (asi_clone_p4d instead of asi_map), since we know the whole P4D will
+ * be mapped.
+ */
+ asi_clone_p4d(asi_global_nonsensitive_pgd, init_mm.pgd,
+ CPU_ENTRY_AREA_BASE);
+#ifdef CONFIG_X86_ESPFIX64
+ asi_clone_p4d(asi_global_nonsensitive_pgd, init_mm.pgd,
+ ESPFIX_BASE_ADDR);
+#endif
+ /*
+ * The vmemmap area actually _must_ be cloned via shared paging
+ * structures, since mappings can potentially change dynamically when
+ * hugetlbfs pages are created or broken down.
+ *
+ * We always clone 2 PGDs, this is a corrolary of the sizes of struct
+ * page, a page, and the physical address space.
+ */
+ WARN_ON(sizeof(struct page) * MAXMEM / PAGE_SIZE != 2 * (1UL << PGDIR_SHIFT));
+ asi_clone_pgd(asi_global_nonsensitive_pgd, init_mm.pgd, VMEMMAP_START);
+ asi_clone_pgd(asi_global_nonsensitive_pgd, init_mm.pgd,
+ VMEMMAP_START + (1UL << PGDIR_SHIFT));
+
return 0;
}
subsys_initcall(asi_global_init)
@@ -599,6 +698,10 @@ static bool follow_physaddr(
* Map the given range into the ASI page tables. The source of the mapping is
* the regular unrestricted page tables. Can be used to map any kernel memory.
*
+ * In contrast to some internal ASI logic (asi_clone_pgd and asi_clone_p4d) this
+ * never shares pagetables between restricted and unrestricted address spaces,
+ * instead it creates wholly new equivalent mappings.
+ *
* The caller MUST ensure that the source mapping will not change during this
* function. For dynamic kernel memory, this is generally ensured by mapping the
* memory within the allocator.
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index eeadbaeccf88b73af40efe5221760a7cb37058d2..18f6c0448baf5dfbd0721ba9a6d89000fa86f061 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -1022,6 +1022,16 @@
COMMON_DISCARDS \
}
+/*
+ * ASI maps certain sections with certain sensitivity levels, so they need to
+ * have a page-aligned size.
+ */
+#ifdef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
+#define ASI_ALIGN() ALIGN(PAGE_SIZE)
+#else
+#define ASI_ALIGN() .
+#endif
+
/**
* PERCPU_INPUT - the percpu input sections
* @cacheline: cacheline size
@@ -1043,6 +1053,7 @@
*(.data..percpu) \
*(.data..percpu..shared_aligned) \
PERCPU_DECRYPTED_SECTION \
+ . = ASI_ALIGN(); \
__per_cpu_end = .;
/**
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH RFC v2 17/29] mm: asi: Map vmalloc/vmap data as nonsensitive
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
` (15 preceding siblings ...)
2025-01-10 18:40 ` [PATCH RFC v2 16/29] mm: asi: Map kernel text and static data as nonsensitive Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 18/29] mm: asi: Map dynamic percpu memory " Brendan Jackman
` (11 subsequent siblings)
28 siblings, 0 replies; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman
We add new VM flags for sensitive and global-nonsensitive, parallel to
the corresponding GFP flags.
__get_vm_area_node and friends will default to creating
global-nonsensitive VM areas, and vmap then calls asi_map as necessary.
__vmalloc_node_range has additional logic to check and set defaults for
the sensitivity of the underlying page allocation. It does this via an
initial __set_asi_flags call - note that it then calls
__get_vm_area_node which also calls __set_asi_flags. This second call
is a NOP.
By default, we mark the underlying page allocation as sensitive, even
if the VM area is global-nonsensitive. This is just an optimization to
avoid unnecessary asi_map etc, since presumably most code has no reason
to access vmalloc'd data through the direct map.
There are some details of the GFP-flag/VM-flag interaction that are not
really obvious, for example: what should happen when callers of
__vmalloc explicitly set GFP sensitivity flags? (That function has no VM
flags argument). For the moment let's just not block on that and focus
on adding the infrastructure, though.
At the moment, the high-level vmalloc APIs doesn't actually provide a
way to configure sensitivity, this commit just adds the infrastructure.
We'll have to decide how to expose this to allocation sites as we
implement more denylist logic. vmap does already allow configuring vm
flags.
Signed-off-by: Brendan Jackman <jackmanb@google.com>
---
mm/vmalloc.c | 21 +++++++++++++++++----
1 file changed, 17 insertions(+), 4 deletions(-)
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 8d260f2174fe664b54dcda054cb9759ae282bf03..00745edf0b2c5f4c769a46bdcf0872223de5299d 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -3210,6 +3210,7 @@ struct vm_struct *remove_vm_area(const void *addr)
{
struct vmap_area *va;
struct vm_struct *vm;
+ unsigned long vm_addr;
might_sleep();
@@ -3221,6 +3222,7 @@ struct vm_struct *remove_vm_area(const void *addr)
if (!va || !va->vm)
return NULL;
vm = va->vm;
+ vm_addr = (unsigned long) READ_ONCE(vm->addr);
debug_check_no_locks_freed(vm->addr, get_vm_area_size(vm));
debug_check_no_obj_freed(vm->addr, get_vm_area_size(vm));
@@ -3352,6 +3354,7 @@ void vfree(const void *addr)
addr);
return;
}
+ asi_unmap(ASI_GLOBAL_NONSENSITIVE, vm->addr, get_vm_area_size(vm));
if (unlikely(vm->flags & VM_FLUSH_RESET_PERMS))
vm_reset_perms(vm);
@@ -3397,6 +3400,7 @@ void vunmap(const void *addr)
addr);
return;
}
+ asi_unmap(ASI_GLOBAL_NONSENSITIVE, vm->addr, get_vm_area_size(vm));
kfree(vm);
}
EXPORT_SYMBOL(vunmap);
@@ -3445,16 +3449,21 @@ void *vmap(struct page **pages, unsigned int count,
addr = (unsigned long)area->addr;
if (vmap_pages_range(addr, addr + size, pgprot_nx(prot),
- pages, PAGE_SHIFT) < 0) {
- vunmap(area->addr);
- return NULL;
- }
+ pages, PAGE_SHIFT) < 0)
+ goto err;
+
+ if (asi_map(ASI_GLOBAL_NONSENSITIVE, area->addr,
+ get_vm_area_size(area)))
+ goto err; /* The necessary asi_unmap() is in vunmap. */
if (flags & VM_MAP_PUT_PAGES) {
area->pages = pages;
area->nr_pages = count;
}
return area->addr;
+err:
+ vunmap(area->addr);
+ return NULL;
}
EXPORT_SYMBOL(vmap);
@@ -3711,6 +3720,10 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
goto fail;
}
+ if (asi_map(ASI_GLOBAL_NONSENSITIVE, area->addr,
+ get_vm_area_size(area)))
+ goto fail; /* The necessary asi_unmap() is in vfree. */
+
return area->addr;
fail:
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH RFC v2 18/29] mm: asi: Map dynamic percpu memory as nonsensitive
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
` (16 preceding siblings ...)
2025-01-10 18:40 ` [PATCH RFC v2 17/29] mm: asi: Map vmalloc/vmap " Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 19/29] mm: asi: Stabilize CR3 in switch_mm_irqs_off() Brendan Jackman
` (10 subsequent siblings)
28 siblings, 0 replies; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman, Reiji Watanabe, Junaid Shahid
From: Reiji Watanabe <reijiw@google.com>
Currently, all dynamic percpu memory is implicitly (and
unintentionally) treated as sensitive memory.
Unconditionally map pages for dynamically allocated percpu
memory as global nonsensitive memory, other than pages that
are allocated for pcpu_{first,reserved}_chunk during early
boot via memblock allocator (these will be taken care by the
following patch).
We don't support sensitive percpu memory allocation yet.
Co-developed-by: Junaid Shahid <junaids@google.com>
Signed-off-by: Junaid Shahid <junaids@google.com>
Signed-off-by: Reiji Watanabe <reijiw@google.com>
Signed-off-by: Brendan Jackman <jackmanb@google.com>
WIP: Drop VM_SENSITIVE checks from percpu code
---
mm/percpu-vm.c | 50 ++++++++++++++++++++++++++++++++++++++++++++------
mm/percpu.c | 4 ++--
2 files changed, 46 insertions(+), 8 deletions(-)
diff --git a/mm/percpu-vm.c b/mm/percpu-vm.c
index cd69caf6aa8d8eded2395eb4bc4051b78ec6aa33..2935d7fbac41548819a94dcc60566bd18cde819a 100644
--- a/mm/percpu-vm.c
+++ b/mm/percpu-vm.c
@@ -132,11 +132,20 @@ static void pcpu_pre_unmap_flush(struct pcpu_chunk *chunk,
pcpu_chunk_addr(chunk, pcpu_high_unit_cpu, page_end));
}
-static void __pcpu_unmap_pages(unsigned long addr, int nr_pages)
+static void ___pcpu_unmap_pages(unsigned long addr, int nr_pages)
{
vunmap_range_noflush(addr, addr + (nr_pages << PAGE_SHIFT));
}
+static void __pcpu_unmap_pages(unsigned long addr, int nr_pages,
+ unsigned long vm_flags)
+{
+ unsigned long size = nr_pages << PAGE_SHIFT;
+
+ asi_unmap(ASI_GLOBAL_NONSENSITIVE, (void *)addr, size);
+ ___pcpu_unmap_pages(addr, nr_pages);
+}
+
/**
* pcpu_unmap_pages - unmap pages out of a pcpu_chunk
* @chunk: chunk of interest
@@ -153,6 +162,8 @@ static void __pcpu_unmap_pages(unsigned long addr, int nr_pages)
static void pcpu_unmap_pages(struct pcpu_chunk *chunk,
struct page **pages, int page_start, int page_end)
{
+ struct vm_struct **vms = (struct vm_struct **)chunk->data;
+ unsigned long vm_flags = vms ? vms[0]->flags : VM_ALLOC;
unsigned int cpu;
int i;
@@ -165,7 +176,7 @@ static void pcpu_unmap_pages(struct pcpu_chunk *chunk,
pages[pcpu_page_idx(cpu, i)] = page;
}
__pcpu_unmap_pages(pcpu_chunk_addr(chunk, cpu, page_start),
- page_end - page_start);
+ page_end - page_start, vm_flags);
}
}
@@ -190,13 +201,38 @@ static void pcpu_post_unmap_tlb_flush(struct pcpu_chunk *chunk,
pcpu_chunk_addr(chunk, pcpu_high_unit_cpu, page_end));
}
-static int __pcpu_map_pages(unsigned long addr, struct page **pages,
- int nr_pages)
+/*
+ * __pcpu_map_pages() should not be called during the percpu initialization,
+ * as asi_map() depends on the page allocator (which isn't available yet
+ * during percpu initialization). Instead, ___pcpu_map_pages() can be used
+ * during the percpu initialization. But, any pages that are mapped with
+ * ___pcpu_map_pages() will be treated as sensitive memory, unless
+ * they are explicitly mapped with asi_map() later.
+ */
+static int ___pcpu_map_pages(unsigned long addr, struct page **pages,
+ int nr_pages)
{
return vmap_pages_range_noflush(addr, addr + (nr_pages << PAGE_SHIFT),
PAGE_KERNEL, pages, PAGE_SHIFT);
}
+static int __pcpu_map_pages(unsigned long addr, struct page **pages,
+ int nr_pages, unsigned long vm_flags)
+{
+ unsigned long size = nr_pages << PAGE_SHIFT;
+ int err;
+
+ err = ___pcpu_map_pages(addr, pages, nr_pages);
+ if (err)
+ return err;
+
+ /*
+ * If this fails, pcpu_map_pages()->__pcpu_unmap_pages() will call
+ * asi_unmap() and clean up any partial mappings.
+ */
+ return asi_map(ASI_GLOBAL_NONSENSITIVE, (void *)addr, size);
+}
+
/**
* pcpu_map_pages - map pages into a pcpu_chunk
* @chunk: chunk of interest
@@ -214,13 +250,15 @@ static int __pcpu_map_pages(unsigned long addr, struct page **pages,
static int pcpu_map_pages(struct pcpu_chunk *chunk,
struct page **pages, int page_start, int page_end)
{
+ struct vm_struct **vms = (struct vm_struct **)chunk->data;
+ unsigned long vm_flags = vms ? vms[0]->flags : VM_ALLOC;
unsigned int cpu, tcpu;
int i, err;
for_each_possible_cpu(cpu) {
err = __pcpu_map_pages(pcpu_chunk_addr(chunk, cpu, page_start),
&pages[pcpu_page_idx(cpu, page_start)],
- page_end - page_start);
+ page_end - page_start, vm_flags);
if (err < 0)
goto err;
@@ -232,7 +270,7 @@ static int pcpu_map_pages(struct pcpu_chunk *chunk,
err:
for_each_possible_cpu(tcpu) {
__pcpu_unmap_pages(pcpu_chunk_addr(chunk, tcpu, page_start),
- page_end - page_start);
+ page_end - page_start, vm_flags);
if (tcpu == cpu)
break;
}
diff --git a/mm/percpu.c b/mm/percpu.c
index da21680ff294cb53dfb42bf0d3b3bbd2654d2cfa..c2d913c579bf07892957ac7f601a6a71defadc4b 100644
--- a/mm/percpu.c
+++ b/mm/percpu.c
@@ -3273,8 +3273,8 @@ int __init pcpu_page_first_chunk(size_t reserved_size, pcpu_fc_cpu_to_node_fn_t
pcpu_populate_pte(unit_addr + (i << PAGE_SHIFT));
/* pte already populated, the following shouldn't fail */
- rc = __pcpu_map_pages(unit_addr, &pages[unit * unit_pages],
- unit_pages);
+ rc = ___pcpu_map_pages(unit_addr, &pages[unit * unit_pages],
+ unit_pages);
if (rc < 0)
panic("failed to map percpu area, err=%d\n", rc);
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH RFC v2 19/29] mm: asi: Stabilize CR3 in switch_mm_irqs_off()
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
` (17 preceding siblings ...)
2025-01-10 18:40 ` [PATCH RFC v2 18/29] mm: asi: Map dynamic percpu memory " Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 20/29] mm: asi: Make TLB flushing correct under ASI Brendan Jackman
` (9 subsequent siblings)
28 siblings, 0 replies; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman
An ASI-restricted CR3 is unstable as interrupts can cause ASI-exits.
Although we already unconditionally ASI-exit during context-switch, and
before returning from the VM-run path, it's still possible to reach
switch_mm_irqs_off() in a restricted context, because KVM code updates
static keys, which requires using a temporary mm.
Signed-off-by: Brendan Jackman <jackmanb@google.com>
---
arch/x86/mm/tlb.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index c55733e144c7538ce7f97b74ea2b1b9c22497c32..ce5598f96ea7a84dc0e8623022ab5bfbba401b48 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -546,6 +546,9 @@ void switch_mm_irqs_off(struct mm_struct *unused, struct mm_struct *next,
bool need_flush;
u16 new_asid;
+ /* Stabilize CR3, before reading or writing CR3 */
+ asi_exit();
+
/* We don't want flush_tlb_func() to run concurrently with us. */
if (IS_ENABLED(CONFIG_PROVE_LOCKING))
WARN_ON_ONCE(!irqs_disabled());
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH RFC v2 20/29] mm: asi: Make TLB flushing correct under ASI
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
` (18 preceding siblings ...)
2025-01-10 18:40 ` [PATCH RFC v2 19/29] mm: asi: Stabilize CR3 in switch_mm_irqs_off() Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 21/29] KVM: x86: asi: Restricted address space for VM execution Brendan Jackman
` (8 subsequent siblings)
28 siblings, 0 replies; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman
This is the absolute minimum change for TLB flushing to be correct under
ASI. There are two arguably orthogonal changes in here but they feel
small enough for a single commit.
.:: CR3 stabilization
As noted in the comment ASI can destabilize CR3, but we can stabilize it
again by calling asi_exit, this makes it safe to read CR3 and write it
back.
This is enough to be correct - we don't have to worry about invalidating
the other ASI address space (i.e. we don't need to invalidate the
restricted address space if we are currently unrestricted / vice versa)
because we currently never set the noflush bit in CR3 for ASI
transitions.
Even without using CR3's noflush bit there are trivial optimizations
still on the table here: on where invpcid_flush_single_context is
available (i.e. with the INVPCID_SINGLE feature) we can use that in lieu
of the CR3 read/write, and avoid the extremely costly asi_exit.
.:: Invalidating kernel mappings
Before ASI, with KPTI off we always either disable PCID or use global
mappings for kernel memory. However ASI disables global kernel mappings
regardless of factors. So we need to invalidate other address spaces to
trigger a flush when we switch into them.
Note that there is currently a pointless write of
cpu_tlbstate.invalidate_other in the case of KPTI and !PCID. We've added
another case of that (ASI, !KPTI and !PCID). I think that's preferable
to expanding the conditional in flush_tlb_one_kernel.
Signed-off-by: Brendan Jackman <jackmanb@google.com>
---
arch/x86/mm/tlb.c | 27 ++++++++++++++++++++-------
1 file changed, 20 insertions(+), 7 deletions(-)
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index ce5598f96ea7a84dc0e8623022ab5bfbba401b48..07b1657bee8e4cf17452ea57c838823e76f482c0 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -231,7 +231,7 @@ static void clear_asid_other(void)
* This is only expected to be set if we have disabled
* kernel _PAGE_GLOBAL pages.
*/
- if (!static_cpu_has(X86_FEATURE_PTI)) {
+ if (!static_cpu_has(X86_FEATURE_PTI) && !static_asi_enabled()) {
WARN_ON_ONCE(1);
return;
}
@@ -1040,7 +1040,6 @@ static void put_flush_tlb_info(void)
noinstr u16 asi_pcid(struct asi *asi, u16 asid)
{
return kern_pcid(asid) | ((asi->class_id + 1) << X86_CR3_ASI_PCID_BITS_SHIFT);
- // return kern_pcid(asid) | ((asi->index + 1) << X86_CR3_ASI_PCID_BITS_SHIFT);
}
void asi_flush_tlb_range(struct asi *asi, void *addr, size_t len)
@@ -1192,15 +1191,19 @@ void flush_tlb_one_kernel(unsigned long addr)
* use PCID if we also use global PTEs for the kernel mapping, and
* INVLPG flushes global translations across all address spaces.
*
- * If PTI is on, then the kernel is mapped with non-global PTEs, and
- * __flush_tlb_one_user() will flush the given address for the current
- * kernel address space and for its usermode counterpart, but it does
- * not flush it for other address spaces.
+ * If PTI or ASI is on, then the kernel is mapped with non-global PTEs,
+ * and __flush_tlb_one_user() will flush the given address for the
+ * current kernel address space and, if PTI is on, for its usermode
+ * counterpart, but it does not flush it for other address spaces.
*/
flush_tlb_one_user(addr);
- if (!static_cpu_has(X86_FEATURE_PTI))
+ /* Nothing more to do if PTI and ASI are completely off. */
+ if (!static_cpu_has(X86_FEATURE_PTI) && !static_asi_enabled()) {
+ VM_WARN_ON_ONCE(static_cpu_has(X86_FEATURE_PCID) &&
+ !(__default_kernel_pte_mask & _PAGE_GLOBAL));
return;
+ }
/*
* See above. We need to propagate the flush to all other address
@@ -1289,6 +1292,16 @@ STATIC_NOPV void native_flush_tlb_local(void)
invalidate_user_asid(this_cpu_read(cpu_tlbstate.loaded_mm_asid));
+ /*
+ * Restricted ASI CR3 is unstable outside of critical section, so we
+ * couldn't flush via a CR3 read/write. asi_exit() stabilizes it.
+ * We don't expect any flushes in a critical section.
+ */
+ if (WARN_ON(asi_in_critical_section()))
+ native_flush_tlb_global();
+ else
+ asi_exit();
+
/* If current->mm == NULL then the read_cr3() "borrows" an mm */
native_write_cr3(__native_read_cr3());
}
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH RFC v2 21/29] KVM: x86: asi: Restricted address space for VM execution
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
` (19 preceding siblings ...)
2025-01-10 18:40 ` [PATCH RFC v2 20/29] mm: asi: Make TLB flushing correct under ASI Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 22/29] mm: asi: exit ASI before accessing CR3 from C code where appropriate Brendan Jackman
` (7 subsequent siblings)
28 siblings, 0 replies; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman
An ASI restricted address space is added for KVM. This protects the
userspace from attack by the guest, and the guest from attack by other
processes. It doesn't attempt to prevent the guest from attack by the
current process.
This change incorporates an extra asi_exit at the end of vcpu_run. We
expect later iterations of ASI to drop that call as we gain the
ability to context switch within the ASI domain.
Signed-off-by: Brendan Jackman <jackmanb@google.com>
---
arch/x86/include/asm/kvm_host.h | 3 ++
arch/x86/kvm/svm/svm.c | 2 ++
arch/x86/kvm/vmx/vmx.c | 38 ++++++++++++--------
arch/x86/kvm/x86.c | 77 ++++++++++++++++++++++++++++++++++++++++-
4 files changed, 105 insertions(+), 15 deletions(-)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 6d9f763a7bb9d5db422ea5625b2c28420bd14f26..00cda452dd6ca6ec57ff85ca194ee4aeb6af3be7 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -37,6 +37,7 @@
#include <asm/kvm_vcpu_regs.h>
#include <asm/hyperv-tlfs.h>
#include <asm/reboot.h>
+#include <asm/asi.h>
#define __KVM_HAVE_ARCH_VCPU_DEBUGFS
@@ -1535,6 +1536,8 @@ struct kvm_arch {
*/
#define SPLIT_DESC_CACHE_MIN_NR_OBJECTS (SPTE_ENT_PER_PAGE + 1)
struct kvm_mmu_memory_cache split_desc_cache;
+
+ struct asi *asi;
};
struct kvm_vm_stat {
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 9df3e1e5ae81a1346409632edd693cb7e0740f72..f2c3154292b4f6c960b490b0773f53bea43897bb 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -4186,6 +4186,7 @@ static noinstr void svm_vcpu_enter_exit(struct kvm_vcpu *vcpu, bool spec_ctrl_in
guest_state_enter_irqoff();
amd_clear_divider();
+ asi_enter(vcpu->kvm->arch.asi);
if (sev_es_guest(vcpu->kvm))
__svm_sev_es_vcpu_run(svm, spec_ctrl_intercepted,
@@ -4193,6 +4194,7 @@ static noinstr void svm_vcpu_enter_exit(struct kvm_vcpu *vcpu, bool spec_ctrl_in
else
__svm_vcpu_run(svm, spec_ctrl_intercepted);
+ asi_relax();
guest_state_exit_irqoff();
}
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index d28618e9277ede83ad2edc1b1778ea44123aa797..181d230b1c057fed33f7b29b7b0e378dbdfeb174 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -49,6 +49,7 @@
#include <asm/mwait.h>
#include <asm/spec-ctrl.h>
#include <asm/vmx.h>
+#include <asm/asi.h>
#include <trace/events/ipi.h>
@@ -7282,14 +7283,34 @@ static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu,
unsigned int flags)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
+ unsigned long cr3;
guest_state_enter_irqoff();
+ asi_enter(vcpu->kvm->arch.asi);
+
+ /*
+ * Refresh vmcs.HOST_CR3 if necessary. This must be done immediately
+ * prior to VM-Enter, as the kernel may load a new ASID (PCID) any time
+ * it switches back to the current->mm, which can occur in KVM context
+ * when switching to a temporary mm to patch kernel code, e.g. if KVM
+ * toggles a static key while handling a VM-Exit.
+ * Also, this must be done after asi_enter(), as it changes CR3
+ * when switching address spaces.
+ */
+ cr3 = __get_current_cr3_fast();
+ if (unlikely(cr3 != vmx->loaded_vmcs->host_state.cr3)) {
+ vmcs_writel(HOST_CR3, cr3);
+ vmx->loaded_vmcs->host_state.cr3 = cr3;
+ }
/*
* L1D Flush includes CPU buffer clear to mitigate MDS, but VERW
* mitigation for MDS is done late in VMentry and is still
* executed in spite of L1D Flush. This is because an extra VERW
* should not matter much after the big hammer L1D Flush.
+ *
+ * This is only after asi_enter() for performance reasons.
+ * RFC: This also needs to be integrated with ASI's tainting model.
*/
if (static_branch_unlikely(&vmx_l1d_should_flush))
vmx_l1d_flush(vcpu);
@@ -7310,6 +7331,8 @@ static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu,
vmx->idt_vectoring_info = 0;
+ asi_relax();
+
vmx_enable_fb_clear(vmx);
if (unlikely(vmx->fail)) {
@@ -7338,7 +7361,7 @@ static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu,
fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu, bool force_immediate_exit)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
- unsigned long cr3, cr4;
+ unsigned long cr4;
/* Record the guest's net vcpu time for enforced NMI injections. */
if (unlikely(!enable_vnmi &&
@@ -7381,19 +7404,6 @@ fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu, bool force_immediate_exit)
vmcs_writel(GUEST_RIP, vcpu->arch.regs[VCPU_REGS_RIP]);
vcpu->arch.regs_dirty = 0;
- /*
- * Refresh vmcs.HOST_CR3 if necessary. This must be done immediately
- * prior to VM-Enter, as the kernel may load a new ASID (PCID) any time
- * it switches back to the current->mm, which can occur in KVM context
- * when switching to a temporary mm to patch kernel code, e.g. if KVM
- * toggles a static key while handling a VM-Exit.
- */
- cr3 = __get_current_cr3_fast();
- if (unlikely(cr3 != vmx->loaded_vmcs->host_state.cr3)) {
- vmcs_writel(HOST_CR3, cr3);
- vmx->loaded_vmcs->host_state.cr3 = cr3;
- }
-
cr4 = cr4_read_shadow();
if (unlikely(cr4 != vmx->loaded_vmcs->host_state.cr4)) {
vmcs_writel(HOST_CR4, cr4);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 83fe0a78146fc198115aba0e76ba57ecfb1dd8d9..3e0811eb510650abc601e4adce1ce4189835a730 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -85,6 +85,7 @@
#include <asm/emulate_prefix.h>
#include <asm/sgx.h>
#include <clocksource/hyperv_timer.h>
+#include <asm/asi.h>
#define CREATE_TRACE_POINTS
#include "trace.h"
@@ -9674,6 +9675,55 @@ static void kvm_x86_check_cpu_compat(void *ret)
*(int *)ret = kvm_x86_check_processor_compatibility();
}
+#ifdef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
+static inline int kvm_x86_init_asi_class(void)
+{
+ static struct asi_taint_policy policy = {
+ /*
+ * Prevent going to the guest with sensitive data potentially
+ * left in sidechannels by code running in the unrestricted
+ * address space, or another MM.
+ */
+ .protect_data = ASI_TAINT_KERNEL_DATA | ASI_TAINT_OTHER_MM_DATA,
+ /*
+ * Prevent going to the guest with branch predictor state
+ * influenced by other processes. Note this bit is about
+ * protecting the guest from other parts of the system, while
+ * data_taints is about protecting other parts of the system
+ * from the guest.
+ */
+ .prevent_control = ASI_TAINT_OTHER_MM_CONTROL,
+ .set = ASI_TAINT_GUEST_DATA,
+ };
+
+ /*
+ * Inform ASI that the guest will gain control of the branch predictor,
+ * unless we're just unconditionally blasting it after VM Exit.
+ *
+ * RFC: This is a bit simplified - on some configurations we could avoid
+ * a duplicated RSB-fill if we had a separate taint specifically for the
+ * RSB.
+ */
+ if (!cpu_feature_enabled(X86_FEATURE_IBPB_ON_VMEXIT) ||
+ !IS_ENABLED(CONFIG_MITIGATION_RETPOLINE) ||
+ !cpu_feature_enabled(X86_FEATURE_RSB_VMEXIT))
+ policy.set = ASI_TAINT_GUEST_CONTROL;
+
+ /*
+ * And the same for data left behind by code in the userspace domain
+ * (i.e. the VMM itself, plus kernel code serving its syscalls etc).
+ * This should eventually be configurable: users whose VMMs contain
+ * no secrets can disable it to avoid paying a mitigation cost on
+ * transition between their guest and userspace.
+ */
+ policy.protect_data |= ASI_TAINT_USER_DATA;
+
+ return asi_init_class(ASI_CLASS_KVM, &policy);
+}
+#else /* CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION */
+static inline int kvm_x86_init_asi_class(void) { return 0; }
+#endif /* CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION */
+
int kvm_x86_vendor_init(struct kvm_x86_init_ops *ops)
{
u64 host_pat;
@@ -9737,6 +9787,10 @@ int kvm_x86_vendor_init(struct kvm_x86_init_ops *ops)
kvm_caps.supported_vm_types = BIT(KVM_X86_DEFAULT_VM);
kvm_caps.supported_mce_cap = MCG_CTL_P | MCG_SER_P;
+ r = kvm_x86_init_asi_class();
+ if (r < 0)
+ goto out_mmu_exit;
+
if (boot_cpu_has(X86_FEATURE_XSAVE)) {
kvm_host.xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
kvm_caps.supported_xcr0 = kvm_host.xcr0 & KVM_SUPPORTED_XCR0;
@@ -9754,7 +9808,7 @@ int kvm_x86_vendor_init(struct kvm_x86_init_ops *ops)
r = ops->hardware_setup();
if (r != 0)
- goto out_mmu_exit;
+ goto out_asi_uninit;
kvm_ops_update(ops);
@@ -9810,6 +9864,8 @@ int kvm_x86_vendor_init(struct kvm_x86_init_ops *ops)
out_unwind_ops:
kvm_x86_ops.enable_virtualization_cpu = NULL;
kvm_x86_call(hardware_unsetup)();
+out_asi_uninit:
+ asi_uninit_class(ASI_CLASS_KVM);
out_mmu_exit:
kvm_mmu_vendor_module_exit();
out_free_percpu:
@@ -9841,6 +9897,7 @@ void kvm_x86_vendor_exit(void)
cancel_work_sync(&pvclock_gtod_work);
#endif
kvm_x86_call(hardware_unsetup)();
+ asi_uninit_class(ASI_CLASS_KVM);
kvm_mmu_vendor_module_exit();
free_percpu(user_return_msrs);
kmem_cache_destroy(x86_emulator_cache);
@@ -11574,6 +11631,13 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
r = vcpu_run(vcpu);
+ /*
+ * At present ASI doesn't have the capability to transition directly
+ * from the restricted address space to the user address space. So we
+ * just return to the unrestricted address space in between.
+ */
+ asi_exit();
+
out:
kvm_put_guest_fpu(vcpu);
if (kvm_run->kvm_valid_regs)
@@ -12705,6 +12769,14 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
if (ret)
goto out_uninit_mmu;
+ ret = asi_init(kvm->mm, ASI_CLASS_KVM, &kvm->arch.asi);
+ if (ret)
+ goto out_uninit_mmu;
+
+ ret = static_call(kvm_x86_vm_init)(kvm);
+ if (ret)
+ goto out_asi_destroy;
+
INIT_HLIST_HEAD(&kvm->arch.mask_notifier_list);
atomic_set(&kvm->arch.noncoherent_dma_count, 0);
@@ -12742,6 +12814,8 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
return 0;
+out_asi_destroy:
+ asi_destroy(kvm->arch.asi);
out_uninit_mmu:
kvm_mmu_uninit_vm(kvm);
kvm_page_track_cleanup(kvm);
@@ -12883,6 +12957,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
kvm_destroy_vcpus(kvm);
kvfree(rcu_dereference_check(kvm->arch.apic_map, 1));
kfree(srcu_dereference_check(kvm->arch.pmu_event_filter, &kvm->srcu, 1));
+ asi_destroy(kvm->arch.asi);
kvm_mmu_uninit_vm(kvm);
kvm_page_track_cleanup(kvm);
kvm_xen_destroy_vm(kvm);
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH RFC v2 22/29] mm: asi: exit ASI before accessing CR3 from C code where appropriate
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
` (20 preceding siblings ...)
2025-01-10 18:40 ` [PATCH RFC v2 21/29] KVM: x86: asi: Restricted address space for VM execution Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 23/29] mm: asi: exit ASI before suspend-like operations Brendan Jackman
` (6 subsequent siblings)
28 siblings, 0 replies; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman, Yosry Ahmed
Because asi_exit()s can be triggered by NMIs, CR3 is unstable when in
the ASI restricted address space. (Exception: code in the ASI critical
section can treat it as stable, because if an asi_exit() occurs during
an exception it will be undone before the critical section resumes).
Code that accesses CR3 needs to become aware of this. Most importantly:
if code reads CR3 and then writes a derived value back, if concurrent
asi_exit() occurred in between then the address space switch would be
undone, which would totally break ASI.
So, make sure that an asi_exit() is performed before accessing CR3.
Exceptions are made for cases that need to access the current CR3 value,
restricted or not, without exiting ASI.
(An alternative approach would be to enter an ASI critical section when
a stable CR3 is needed. This would be worth exploring if the ASI exits
introduced by this patch turned out to cause performance issues).
Add calls to asi_exit() to __native_read_cr3() and native_write_cr3(),
and introduce 'raw' variants that do not perform an ASI exit. Introduce
similar variants for wrappers: __read_cr3(), read_cr3_pa(), and
write_cr3(). A forward declaration of asi_exit(), because the one in
asm-generic/asi.h is only declared when !CONFIG_ADDRESS_SPACE_ISOLATION,
and arch/x86/asm/asi.h cannot be included either as it would cause a
circular dependency.
The 'raw' variants are used in the following cases:
- In __show_regs() where the actual values of registers are dumped for
debugging.
- In dump_pagetable() and show_fault_oops() where the active page tables
during a page fault are dumped for debugging.
- In switch_mm_verify_cr3() and cr3_matches_current_mm() where the
actual value of CR3 is needed for a debug check, and the code
explicitly checks for ASI-restricted CR3.
- In exc_page_fault() for ASI faults. The code is ASI-aware and
explicitly performs an ASI exit before reading CR3.
- In load_new_mm_cr3() where a new CR3 is loaded during context
switching. At this point, it is guaranteed that ASI already exited.
Calling asi_exit() at that point, where loaded_mm ==
LOADED_MM_SWITCHING, will cause VM_BUG_ON in asi_exit() to fire
mistakenly even though loaded_mm is never accessed.
- In __get_current_cr3_fast(), as it is called from an ASI critical
section and the value is only used for debug checking.
In nested_vmx_check_vmentry_hw(), do an explicit asi_exit() before
calling __get_current_cr3_fast(), since in that case we are not in a
critical section and do need a stable CR3 value.
- In __asi_enter() and asi_exit() for obvious reasons.
- In vmx_set_constant_host_state() when CR3 is initialized in the VMCS
with the most likely value. Preemption is enabled, so once ASI
supports context switching exiting ASI will not be reliable as
rescheduling may cause re-entering ASI. It doesn't matter if the wrong
value of CR3 is used in this context, before entering the guest, ASI
is either explicitly entered or exited, and CR3 is updated again in
the VMCS if needed.
- In efi_5level_switch(), as it is called from startup_64_mixed_mode()
during boot before ASI can be entered. startup_64_mixed_mode() is
under arch/x86/boot/compressed/* and it cannot call asi_exit() anyway
(see below).
Finally, code in arch/x86/boot/compressed/ident_map_64.c and
arch/x86/boot/compressed/pgtable_64.c extensively accesses CR3 during
boot. This code under arch/x86/boot/compressed/* cannot call asi_exit()
due to restriction on its compilation (it cannot use functions defined
in .c files outside the directory).
Instead of changing all CR3 accesses to use 'raw' variants, undefine
CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION in these files. This will make
the asi_exit() calls in CR3 helpers use the noop variant defined in
include/asm-generic/asi.h. This is fine because the code is executed
early in boot where asi_exit() would be noop anyway.
With this change, the number of existing *_cr3() calls are 44, and the
number of *_cr3_raw() are 22. The choice was made to make the existing
functions exit ASI by default and adding new variants that do not exit
ASI, because most call sites that use the new *_cr3_raw() variants are
either ASI-aware code or debugging code.
On the contrary, code that uses the existing variants is usually in
important code paths (e.g. TLB flushes) and is ignorant of ASI. Hence,
new code is most likely to be correct and less risky by using the
variants that exit ASI by default.
Signed-off-by: Yosry Ahmed <yosryahmed@google.com>
Signed-off-by: Brendan Jackman <jackmanb@google.com>
---
arch/x86/Kconfig | 2 +-
arch/x86/boot/compressed/ident_map_64.c | 10 ++++++++
arch/x86/boot/compressed/pgtable_64.c | 11 +++++++++
arch/x86/include/asm/processor.h | 5 ++++
arch/x86/include/asm/special_insns.h | 41 +++++++++++++++++++++++++++++++--
arch/x86/kernel/process_32.c | 2 +-
arch/x86/kernel/process_64.c | 2 +-
arch/x86/kvm/vmx/nested.c | 6 +++++
arch/x86/kvm/vmx/vmx.c | 8 ++++++-
arch/x86/mm/asi.c | 4 ++--
arch/x86/mm/fault.c | 8 +++----
arch/x86/mm/tlb.c | 16 +++++++++----
arch/x86/virt/svm/sev.c | 2 +-
drivers/firmware/efi/libstub/x86-5lvl.c | 2 +-
include/asm-generic/asi.h | 1 +
15 files changed, 101 insertions(+), 19 deletions(-)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 1fcb52cb8cd5084ac3cef04af61b7d1653162bdb..ae31f36ce23d7c29d1e90b726c5a2e6ea5a63c8d 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2531,7 +2531,7 @@ config MITIGATION_ADDRESS_SPACE_ISOLATION
The !PARAVIRT dependency is only because of lack of testing; in theory
the code is written to work under paravirtualization. In practice
there are likely to be unhandled cases, in particular concerning TLB
- flushes.
+ flushes and CR3 manipulation.
config ADDRESS_SPACE_ISOLATION_DEFAULT_ON
diff --git a/arch/x86/boot/compressed/ident_map_64.c b/arch/x86/boot/compressed/ident_map_64.c
index dfb9c2deb77cfc4e9986976bf2fd1652666f8f15..957b6f818aec361191432b420b61ba6ae017cf6c 100644
--- a/arch/x86/boot/compressed/ident_map_64.c
+++ b/arch/x86/boot/compressed/ident_map_64.c
@@ -11,6 +11,16 @@
/* No MITIGATION_PAGE_TABLE_ISOLATION support needed either: */
#undef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
+/*
+ * CR3 access helpers (e.g. write_cr3()) will call asi_exit() to exit the
+ * restricted address space first. We cannot call the version defined in
+ * arch/x86/mm/asi.c here, so make sure we always call the noop version in
+ * asm-generic/asi.h. It does not matter because early during boot asi_exit()
+ * would be a noop anyway. The alternative is spamming the code with *_raw()
+ * variants of the CR3 helpers.
+ */
+#undef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
+
#include "error.h"
#include "misc.h"
diff --git a/arch/x86/boot/compressed/pgtable_64.c b/arch/x86/boot/compressed/pgtable_64.c
index c882e1f67af01c50a20bfe00a32138dc771ee88c..034ad7101126c19864cfacc7c363fd31fedecd2b 100644
--- a/arch/x86/boot/compressed/pgtable_64.c
+++ b/arch/x86/boot/compressed/pgtable_64.c
@@ -1,4 +1,15 @@
// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * CR3 access helpers (e.g. write_cr3()) will call asi_exit() to exit the
+ * restricted address space first. We cannot call the version defined in
+ * arch/x86/mm/asi.c here, so make sure we always call the noop version in
+ * asm-generic/asi.h. It does not matter because early during boot asi_exit()
+ * would be a noop anyway. The alternative is spamming the code with *_raw()
+ * variants of the CR3 helpers.
+ */
+#undef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
+
#include "misc.h"
#include <asm/bootparam.h>
#include <asm/e820/types.h>
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index a32a53405f45e4c0473fe081e216029cf5bd0cdd..9375a7f877d60e8f556dedefbe74593c1a5a6e10 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -226,6 +226,11 @@ static __always_inline unsigned long read_cr3_pa(void)
return __read_cr3() & CR3_ADDR_MASK;
}
+static __always_inline unsigned long read_cr3_pa_raw(void)
+{
+ return __read_cr3_raw() & CR3_ADDR_MASK;
+}
+
static inline unsigned long native_read_cr3_pa(void)
{
return __native_read_cr3() & CR3_ADDR_MASK;
diff --git a/arch/x86/include/asm/special_insns.h b/arch/x86/include/asm/special_insns.h
index 6e103358966f6f1333aa07be97aec5f8af794120..1c886b3f04a56893b7408466a2c94d23f5d11857 100644
--- a/arch/x86/include/asm/special_insns.h
+++ b/arch/x86/include/asm/special_insns.h
@@ -5,6 +5,7 @@
#ifdef __KERNEL__
#include <asm/nops.h>
#include <asm/processor-flags.h>
+#include <asm-generic/asi.h>
#include <linux/errno.h>
#include <linux/irqflags.h>
@@ -42,18 +43,32 @@ static __always_inline void native_write_cr2(unsigned long val)
asm volatile("mov %0,%%cr2": : "r" (val) : "memory");
}
-static __always_inline unsigned long __native_read_cr3(void)
+void asi_exit(void);
+
+static __always_inline unsigned long __native_read_cr3_raw(void)
{
unsigned long val;
asm volatile("mov %%cr3,%0\n\t" : "=r" (val) : __FORCE_ORDER);
return val;
}
-static __always_inline void native_write_cr3(unsigned long val)
+static __always_inline unsigned long __native_read_cr3(void)
+{
+ asi_exit();
+ return __native_read_cr3_raw();
+}
+
+static __always_inline void native_write_cr3_raw(unsigned long val)
{
asm volatile("mov %0,%%cr3": : "r" (val) : "memory");
}
+static __always_inline void native_write_cr3(unsigned long val)
+{
+ asi_exit();
+ native_write_cr3_raw(val);
+}
+
static inline unsigned long native_read_cr4(void)
{
unsigned long val;
@@ -152,17 +167,39 @@ static __always_inline void write_cr2(unsigned long x)
/*
* Careful! CR3 contains more than just an address. You probably want
* read_cr3_pa() instead.
+ *
+ * The implementation interacts with ASI to ensure that the returned value is
+ * stable as long as preemption is disabled.
*/
static __always_inline unsigned long __read_cr3(void)
{
return __native_read_cr3();
}
+/*
+ * The return value of this is unstable under ASI, even with preemption off.
+ * Call __read_cr3 instead unless you have a good reason not to.
+ */
+static __always_inline unsigned long __read_cr3_raw(void)
+{
+ return __native_read_cr3_raw();
+}
+
+/* This interacts with ASI like __read_cr3. */
static __always_inline void write_cr3(unsigned long x)
{
native_write_cr3(x);
}
+/*
+ * Like __read_cr3_raw, this doesn't interact with ASI. It's very unlikely that
+ * this should be called from outside ASI-specific code.
+ */
+static __always_inline void write_cr3_raw(unsigned long x)
+{
+ native_write_cr3_raw(x);
+}
+
static inline void __write_cr4(unsigned long x)
{
native_write_cr4(x);
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 0917c7f25720be91372bacddb1a3032323b8996f..14828a867b713a50297953c5a0ccfd03d83debc0 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -79,7 +79,7 @@ void __show_regs(struct pt_regs *regs, enum show_regs_mode mode,
cr0 = read_cr0();
cr2 = read_cr2();
- cr3 = __read_cr3();
+ cr3 = __read_cr3_raw();
cr4 = __read_cr4();
printk("%sCR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n",
log_lvl, cr0, cr2, cr3, cr4);
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 226472332a70dd02902f81c21207d770e698aeed..ca135731b54b7f5f1123c2b8b27afdca7b868bcc 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -113,7 +113,7 @@ void __show_regs(struct pt_regs *regs, enum show_regs_mode mode,
cr0 = read_cr0();
cr2 = read_cr2();
- cr3 = __read_cr3();
+ cr3 = __read_cr3_raw();
cr4 = __read_cr4();
printk("%sFS: %016lx(%04x) GS:%016lx(%04x) knlGS:%016lx\n",
diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index 931a7361c30f2da28073eb832efce0b378e3b325..7eb033dabe4a606947c4d7e5b96be2e42d8f2478 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -3214,6 +3214,12 @@ static int nested_vmx_check_vmentry_hw(struct kvm_vcpu *vcpu)
*/
vmcs_writel(GUEST_RFLAGS, 0);
+ /*
+ * Stabilize CR3 to ensure the VM Exit returns to the correct address
+ * space. This is costly, we wouldn't do this in hot-path code.
+ */
+ asi_exit();
+
cr3 = __get_current_cr3_fast();
if (unlikely(cr3 != vmx->loaded_vmcs->host_state.cr3)) {
vmcs_writel(HOST_CR3, cr3);
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 181d230b1c057fed33f7b29b7b0e378dbdfeb174..0e90463f1f2183b8d716f85d5c8a8af8958fef0b 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -4323,8 +4323,14 @@ void vmx_set_constant_host_state(struct vcpu_vmx *vmx)
/*
* Save the most likely value for this task's CR3 in the VMCS.
* We can't use __get_current_cr3_fast() because we're not atomic.
+ *
+ * Use __read_cr3_raw() to avoid exiting ASI if we are in the restrict
+ * address space. Preemption is enabled, so rescheduling could make us
+ * re-enter ASI anyway. It's okay to avoid exiting ASI here because
+ * vmx_vcpu_enter_exit() and nested_vmx_check_vmentry_hw() will
+ * explicitly enter or exit ASI and update CR3 in the VMCS if needed.
*/
- cr3 = __read_cr3();
+ cr3 = __read_cr3_raw();
vmcs_writel(HOST_CR3, cr3); /* 22.2.3 FIXME: shadow tables */
vmx->loaded_vmcs->host_state.cr3 = cr3;
diff --git a/arch/x86/mm/asi.c b/arch/x86/mm/asi.c
index bc2cf0475a0e7344a66d81453f55034b2fc77eef..a9f9bfbf85eb47d16ef8d0bfbc7713f07052d3ed 100644
--- a/arch/x86/mm/asi.c
+++ b/arch/x86/mm/asi.c
@@ -488,7 +488,7 @@ noinstr void __asi_enter(void)
pcid = asi_pcid(target, this_cpu_read(cpu_tlbstate.loaded_mm_asid));
asi_cr3 = build_cr3_pcid_noinstr(target->pgd, pcid, tlbstate_lam_cr3_mask(), false);
- write_cr3(asi_cr3);
+ write_cr3_raw(asi_cr3);
maybe_flush_data(target);
/*
@@ -559,7 +559,7 @@ noinstr void asi_exit(void)
/* Tainting first makes reentrancy easier to reason about. */
this_cpu_or(asi_taints, ASI_TAINT_KERNEL_DATA);
- write_cr3(unrestricted_cr3);
+ write_cr3_raw(unrestricted_cr3);
/*
* Must not update curr_asi until after CR3 write, otherwise a
* re-entrant call might not enter this branch. (This means we
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index ee8f5417174e2956391d538f41e2475553ca4972..ca48e4f5a27be30ff93d1c3d194aad23d99ae43c 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -295,7 +295,7 @@ static bool low_pfn(unsigned long pfn)
static void dump_pagetable(unsigned long address)
{
- pgd_t *base = __va(read_cr3_pa());
+ pgd_t *base = __va(read_cr3_pa_raw());
pgd_t *pgd = &base[pgd_index(address)];
p4d_t *p4d;
pud_t *pud;
@@ -351,7 +351,7 @@ static int bad_address(void *p)
static void dump_pagetable(unsigned long address)
{
- pgd_t *base = __va(read_cr3_pa());
+ pgd_t *base = __va(read_cr3_pa_raw());
pgd_t *pgd = base + pgd_index(address);
p4d_t *p4d;
pud_t *pud;
@@ -519,7 +519,7 @@ show_fault_oops(struct pt_regs *regs, unsigned long error_code, unsigned long ad
pgd_t *pgd;
pte_t *pte;
- pgd = __va(read_cr3_pa());
+ pgd = __va(read_cr3_pa_raw());
pgd += pgd_index(address);
pte = lookup_address_in_pgd_attr(pgd, address, &level, &nx, &rw);
@@ -1578,7 +1578,7 @@ DEFINE_IDTENTRY_RAW_ERRORCODE(exc_page_fault)
* be losing some stats here. However for now this keeps ASI
* page faults nice and fast.
*/
- pgd = (pgd_t *)__va(read_cr3_pa()) + pgd_index(address);
+ pgd = (pgd_t *)__va(read_cr3_pa_raw()) + pgd_index(address);
if (!user_mode(regs) && kernel_access_ok(error_code, address, pgd)) {
warn_if_bad_asi_pf(error_code, address);
return;
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index 07b1657bee8e4cf17452ea57c838823e76f482c0..0c9f477a44a4da971cb7744d01d9101900ead1a5 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -331,8 +331,14 @@ static void load_new_mm_cr3(pgd_t *pgdir, u16 new_asid, unsigned long lam,
* Caution: many callers of this function expect
* that load_cr3() is serializing and orders TLB
* fills with respect to the mm_cpumask writes.
+ *
+ * The context switching code will explicitly exit ASI when needed, do
+ * not use write_cr3() as it has an implicit ASI exit. Calling
+ * asi_exit() here, where loaded_mm == LOADED_MM_SWITCHING, will cause
+ * the VM_BUG_ON() in asi_exit() to fire mistakenly even though
+ * loaded_mm is never accessed.
*/
- write_cr3(new_mm_cr3);
+ write_cr3_raw(new_mm_cr3);
}
void leave_mm(void)
@@ -559,11 +565,11 @@ void switch_mm_irqs_off(struct mm_struct *unused, struct mm_struct *next,
* without going through leave_mm() / switch_mm_irqs_off() or that
* does something like write_cr3(read_cr3_pa()).
*
- * Only do this check if CONFIG_DEBUG_VM=y because __read_cr3()
+ * Only do this check if CONFIG_DEBUG_VM=y because __read_cr3_raw()
* isn't free.
*/
#ifdef CONFIG_DEBUG_VM
- if (WARN_ON_ONCE(__read_cr3() != build_cr3(prev->pgd, prev_asid,
+ if (WARN_ON_ONCE(__read_cr3_raw() != build_cr3(prev->pgd, prev_asid,
tlbstate_lam_cr3_mask()))) {
/*
* If we were to BUG here, we'd be very likely to kill
@@ -1173,7 +1179,7 @@ noinstr unsigned long __get_current_cr3_fast(void)
*/
VM_WARN_ON_ONCE(asi && asi_in_critical_section());
- VM_BUG_ON(cr3 != __read_cr3());
+ VM_BUG_ON(cr3 != __read_cr3_raw());
return cr3;
}
EXPORT_SYMBOL_GPL(__get_current_cr3_fast);
@@ -1373,7 +1379,7 @@ static inline bool cr3_matches_current_mm(void)
* find a current ASI domain.
*/
barrier();
- pgd_cr3 = __va(read_cr3_pa());
+ pgd_cr3 = __va(read_cr3_pa_raw());
return pgd_cr3 == current->mm->pgd || pgd_cr3 == pgd_asi;
}
diff --git a/arch/x86/virt/svm/sev.c b/arch/x86/virt/svm/sev.c
index 9a6a943d8e410c0289200adb9deafe8e45d33a4b..63d391395a5c7f4ddec28116814ccd6c52bbb428 100644
--- a/arch/x86/virt/svm/sev.c
+++ b/arch/x86/virt/svm/sev.c
@@ -379,7 +379,7 @@ void snp_dump_hva_rmpentry(unsigned long hva)
pgd_t *pgd;
pte_t *pte;
- pgd = __va(read_cr3_pa());
+ pgd = __va(read_cr3_pa_raw());
pgd += pgd_index(hva);
pte = lookup_address_in_pgd(pgd, hva, &level);
diff --git a/drivers/firmware/efi/libstub/x86-5lvl.c b/drivers/firmware/efi/libstub/x86-5lvl.c
index 77359e802181fd82b6a624cf74183e6a318cec9b..3b97a5aea983a109fbdc6d23a219e4a04024c512 100644
--- a/drivers/firmware/efi/libstub/x86-5lvl.c
+++ b/drivers/firmware/efi/libstub/x86-5lvl.c
@@ -66,7 +66,7 @@ void efi_5level_switch(void)
bool have_la57 = native_read_cr4() & X86_CR4_LA57;
bool need_toggle = want_la57 ^ have_la57;
u64 *pgt = (void *)la57_toggle + PAGE_SIZE;
- u64 *cr3 = (u64 *)__native_read_cr3();
+ u64 *cr3 = (u64 *)__native_read_cr3_raw();
u64 *new_cr3;
if (!la57_toggle || !need_toggle)
diff --git a/include/asm-generic/asi.h b/include/asm-generic/asi.h
index 7867b8c23449058a1dd06308ab5351e0d210a489..4f033d3ef5929707fd280f74fc800193e45143c1 100644
--- a/include/asm-generic/asi.h
+++ b/include/asm-generic/asi.h
@@ -71,6 +71,7 @@ static inline pgd_t *asi_pgd(struct asi *asi) { return NULL; }
static inline void asi_handle_switch_mm(void) { }
+struct thread_struct;
static inline void asi_init_thread_state(struct thread_struct *thread) { }
static inline void asi_intr_enter(void) { }
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH RFC v2 23/29] mm: asi: exit ASI before suspend-like operations
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
` (21 preceding siblings ...)
2025-01-10 18:40 ` [PATCH RFC v2 22/29] mm: asi: exit ASI before accessing CR3 from C code where appropriate Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 24/29] mm: asi: Add infrastructure for mapping userspace addresses Brendan Jackman
` (5 subsequent siblings)
28 siblings, 0 replies; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman, Yosry Ahmed
From: Yosry Ahmed <yosryahmed@google.com>
During suspend-like operations (suspend, hibernate, kexec w/
preserve_context), the processor state (including CR3) is usually saved
and restored later.
In the kexec case, this only happens when KEXEC_PRESERVE_CONTEXT is
used to jump back to the original kernel. In relocate_kernel(), some
registers including CR3 are stored in VA_CONTROL_PAGE. If
preserve_context is set (passed into relocate_kernel() in RCX), after
running the new kernel the code under 'virtual_mapped' restores these
registers. This is similar to what happens in suspend and hibernate.
Note that even when KEXEC_PRESERVE_CONTEXT is not set, relocate_kernel()
still accesses CR3. It mainly reads and writes it to flush the TLB. This
could be problematic and cause improper ASI enters (see below), but it
is assumed to be safe because the kernel will essentially reboot in this
case anyway.
Saving and restoring CR3 in this fashion can cause a problem if the
suspend/hibernate/kexec is performed within an ASI domain. A restricted
CR3 will be saved, and later restored after ASI had potentially already
exited (e.g. from an NMI after CR3 is stored). This will cause an
_improper_ ASI enter, where code starts executing in a restricted
address space, yet ASI metadata (especially curr_asi) says otherwise.
Exit ASI early in all these paths by registering a syscore_suspend()
callback. syscore_suspend() is called in all the above paths (for kexec,
only with KEXEC_PRESERVE_CONTEXT) after IRQs are finally disabled before
the operation. This is not currently strictly required but is convenient
because when ASI gains the ability to persist across context switching,
there will be additional synchronization requirements simplified by
this.
Note: If the CR3 accesses in relocate_kernel() when
KEXEC_PRESERVE_CONTEXT is not set are concerning, they could be handled
by registering a syscore_shutdown() callback to exit ASI.
syscore_shutdown() is called in the kexec path where
KEXEC_PRESERVE_CONTEXT is not set starting commit 7bb943806ff6 ("kexec:
do syscore_shutdown() in kernel_kexec").
Signed-off-by: Yosry Ahmed <yosryahmed@google.com>
Signed-off-by: Brendan Jackman <jackmanb@google.com>
---
arch/x86/mm/asi.c | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/arch/x86/mm/asi.c b/arch/x86/mm/asi.c
index a9f9bfbf85eb47d16ef8d0bfbc7713f07052d3ed..c5073af1a82ded1c6fc467cd7a5d29a39d676bb4 100644
--- a/arch/x86/mm/asi.c
+++ b/arch/x86/mm/asi.c
@@ -6,6 +6,7 @@
#include <linux/init.h>
#include <linux/pgtable.h>
+#include <linux/syscore_ops.h>
#include <asm/cmdline.h>
#include <asm/cpufeature.h>
@@ -243,6 +244,32 @@ static int asi_map_percpu(struct asi *asi, void *percpu_addr, size_t len)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int asi_suspend(void)
+{
+ /*
+ * Must be called after IRQs are disabled and rescheduling is no longer
+ * possible (so that we cannot re-enter ASI before suspending.
+ */
+ lockdep_assert_irqs_disabled();
+
+ /*
+ * Suspend operations sometimes save CR3 as part of the saved state,
+ * which is restored later (e.g. do_suspend_lowlevel() in the suspend
+ * path, swsusp_arch_suspend() in the hibernate path, relocate_kernel()
+ * in the kexec path). Saving a restricted CR3 and restoring it later
+ * could leave to improperly entering ASI. Exit ASI before such
+ * operations.
+ */
+ asi_exit();
+ return 0;
+}
+
+static struct syscore_ops asi_syscore_ops = {
+ .suspend = asi_suspend,
+};
+#endif /* CONFIG_PM_SLEEP */
+
static int __init asi_global_init(void)
{
int err;
@@ -306,6 +333,10 @@ static int __init asi_global_init(void)
asi_clone_pgd(asi_global_nonsensitive_pgd, init_mm.pgd,
VMEMMAP_START + (1UL << PGDIR_SHIFT));
+#ifdef CONFIG_PM_SLEEP
+ register_syscore_ops(&asi_syscore_ops);
+#endif
+
return 0;
}
subsys_initcall(asi_global_init)
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH RFC v2 24/29] mm: asi: Add infrastructure for mapping userspace addresses
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
` (22 preceding siblings ...)
2025-01-10 18:40 ` [PATCH RFC v2 23/29] mm: asi: exit ASI before suspend-like operations Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 25/29] mm: asi: Restricted execution fore bare-metal processes Brendan Jackman
` (4 subsequent siblings)
28 siblings, 0 replies; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman, Junaid Shahid, Reiji Watanabe
In preparation for sandboxing bare-metal processes, teach ASI to map
userspace addresses into the restricted address space.
Add a new policy helper to determine based on the class whether to do
this. If the helper returns true, mirror userspace mappings into the ASI
pagetables.
Later, it will be possible for users who do not have a significant
security boundary between KVM guests and their VMM process, to take
advantage of this to reduce mitigation costs when switching between
those two domains - to illustrate this idea, it's now reflected in the
KVM taint policy, although the KVM class is still hard-coded not to map
userspace addresses.
Co-developed-by: Junaid Shahid <junaids@google.com>
Signed-off-by: Junaid Shahid <junaids@google.com>
Co-developed-by: Reiji Watanabe <reijiw@google.com>
Signed-off-by: Reiji Watanabe <reijiw@google.com>
Signed-off-by: Brendan Jackman <jackmanb@google.com>
---
arch/x86/include/asm/asi.h | 11 +++++
arch/x86/include/asm/pgalloc.h | 6 +++
arch/x86/include/asm/pgtable_64.h | 4 ++
arch/x86/kvm/x86.c | 12 +++--
arch/x86/mm/asi.c | 92 +++++++++++++++++++++++++++++++++++++++
include/asm-generic/asi.h | 4 ++
6 files changed, 125 insertions(+), 4 deletions(-)
diff --git a/arch/x86/include/asm/asi.h b/arch/x86/include/asm/asi.h
index 555edb5f292e4d6baba782f51d014aa48dc850b6..e925d7d2cfc85bca8480c837548654e7a5a7009e 100644
--- a/arch/x86/include/asm/asi.h
+++ b/arch/x86/include/asm/asi.h
@@ -133,6 +133,7 @@ struct asi {
struct mm_struct *mm;
int64_t ref_count;
enum asi_class_id class_id;
+ spinlock_t pgd_lock;
};
DECLARE_PER_CPU_ALIGNED(struct asi *, curr_asi);
@@ -147,6 +148,7 @@ const char *asi_class_name(enum asi_class_id class_id);
int asi_init(struct mm_struct *mm, enum asi_class_id class_id, struct asi **out_asi);
void asi_destroy(struct asi *asi);
+void asi_clone_user_pgtbl(struct mm_struct *mm, pgd_t *pgdp);
/* Enter an ASI domain (restricted address space) and begin the critical section. */
void asi_enter(struct asi *asi);
@@ -286,6 +288,15 @@ static __always_inline bool asi_in_critical_section(void)
void asi_handle_switch_mm(void);
+/*
+ * This function returns true when we would like to map userspace addresses
+ * in the restricted address space.
+ */
+static inline bool asi_maps_user_addr(enum asi_class_id class_id)
+{
+ return false;
+}
+
#endif /* CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION */
#endif
diff --git a/arch/x86/include/asm/pgalloc.h b/arch/x86/include/asm/pgalloc.h
index dcd836b59bebd329c3d265b98e48ef6eb4c9e6fc..edf9fe76c53369eefcd5bf14a09cbf802cf1ea21 100644
--- a/arch/x86/include/asm/pgalloc.h
+++ b/arch/x86/include/asm/pgalloc.h
@@ -114,12 +114,16 @@ static inline void p4d_populate(struct mm_struct *mm, p4d_t *p4d, pud_t *pud)
{
paravirt_alloc_pud(mm, __pa(pud) >> PAGE_SHIFT);
set_p4d(p4d, __p4d(_PAGE_TABLE | __pa(pud)));
+ if (!pgtable_l5_enabled())
+ asi_clone_user_pgtbl(mm, (pgd_t *)p4d);
}
static inline void p4d_populate_safe(struct mm_struct *mm, p4d_t *p4d, pud_t *pud)
{
paravirt_alloc_pud(mm, __pa(pud) >> PAGE_SHIFT);
set_p4d_safe(p4d, __p4d(_PAGE_TABLE | __pa(pud)));
+ if (!pgtable_l5_enabled())
+ asi_clone_user_pgtbl(mm, (pgd_t *)p4d);
}
extern void ___pud_free_tlb(struct mmu_gather *tlb, pud_t *pud);
@@ -137,6 +141,7 @@ static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, p4d_t *p4d)
return;
paravirt_alloc_p4d(mm, __pa(p4d) >> PAGE_SHIFT);
set_pgd(pgd, __pgd(_PAGE_TABLE | __pa(p4d)));
+ asi_clone_user_pgtbl(mm, pgd);
}
static inline void pgd_populate_safe(struct mm_struct *mm, pgd_t *pgd, p4d_t *p4d)
@@ -145,6 +150,7 @@ static inline void pgd_populate_safe(struct mm_struct *mm, pgd_t *pgd, p4d_t *p4
return;
paravirt_alloc_p4d(mm, __pa(p4d) >> PAGE_SHIFT);
set_pgd_safe(pgd, __pgd(_PAGE_TABLE | __pa(p4d)));
+ asi_clone_user_pgtbl(mm, pgd);
}
static inline p4d_t *p4d_alloc_one(struct mm_struct *mm, unsigned long addr)
diff --git a/arch/x86/include/asm/pgtable_64.h b/arch/x86/include/asm/pgtable_64.h
index d1426b64c1b9715cd9e4d1d7451ae4feadd8b2f5..fe6d83ec632a6894527784f2ebdbd013161c6f09 100644
--- a/arch/x86/include/asm/pgtable_64.h
+++ b/arch/x86/include/asm/pgtable_64.h
@@ -157,6 +157,8 @@ static inline void native_set_p4d(p4d_t *p4dp, p4d_t p4d)
static inline void native_p4d_clear(p4d_t *p4d)
{
native_set_p4d(p4d, native_make_p4d(0));
+ if (!pgtable_l5_enabled())
+ asi_clone_user_pgtbl(NULL, (pgd_t *)p4d);
}
static inline void native_set_pgd(pgd_t *pgdp, pgd_t pgd)
@@ -167,6 +169,8 @@ static inline void native_set_pgd(pgd_t *pgdp, pgd_t pgd)
static inline void native_pgd_clear(pgd_t *pgd)
{
native_set_pgd(pgd, native_make_pgd(0));
+ if (pgtable_l5_enabled())
+ asi_clone_user_pgtbl(NULL, pgd);
}
/*
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 3e0811eb510650abc601e4adce1ce4189835a730..920475fe014f6503dd88c7bbdb6b2707c084a689 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -9712,11 +9712,15 @@ static inline int kvm_x86_init_asi_class(void)
/*
* And the same for data left behind by code in the userspace domain
* (i.e. the VMM itself, plus kernel code serving its syscalls etc).
- * This should eventually be configurable: users whose VMMs contain
- * no secrets can disable it to avoid paying a mitigation cost on
- * transition between their guest and userspace.
+ *
+ *
+ * If we decided to map userspace into the guest's restricted address
+ * space then we don't bother with this since we assume either no bugs
+ * allow the guest to leak that data, or the user doesn't care about
+ * that security boundary.
*/
- policy.protect_data |= ASI_TAINT_USER_DATA;
+ if (!asi_maps_user_addr(ASI_CLASS_KVM))
+ policy.protect_data |= ASI_TAINT_USER_DATA;
return asi_init_class(ASI_CLASS_KVM, &policy);
}
diff --git a/arch/x86/mm/asi.c b/arch/x86/mm/asi.c
index c5073af1a82ded1c6fc467cd7a5d29a39d676bb4..093103c1bc2677c81d68008aca064fab53b73a62 100644
--- a/arch/x86/mm/asi.c
+++ b/arch/x86/mm/asi.c
@@ -14,6 +14,7 @@
#include <asm/pgalloc.h>
#include <asm/mmu_context.h>
#include <asm/traps.h>
+#include <asm/pgtable.h>
#include "mm_internal.h"
#include "../../../mm/internal.h"
@@ -351,6 +352,33 @@ static void __asi_destroy(struct asi *asi)
memset(asi, 0, sizeof(struct asi));
}
+static void __asi_init_user_pgds(struct mm_struct *mm, struct asi *asi)
+{
+ int i;
+
+ if (!asi_maps_user_addr(asi->class_id))
+ return;
+
+ /*
+ * The code below must be executed only after the given asi is
+ * available in mm->asi[index] to ensure at least either this
+ * function or __asi_clone_user_pgd() will copy entries in the
+ * unrestricted pgd to the restricted pgd.
+ */
+ if (WARN_ON_ONCE(&mm->asi[asi->class_id] != asi))
+ return;
+
+ /*
+ * See the comment for __asi_clone_user_pgd() why we hold the lock here.
+ */
+ spin_lock(&asi->pgd_lock);
+
+ for (i = 0; i < KERNEL_PGD_BOUNDARY; i++)
+ set_pgd(asi->pgd + i, READ_ONCE(*(mm->pgd + i)));
+
+ spin_unlock(&asi->pgd_lock);
+}
+
int asi_init(struct mm_struct *mm, enum asi_class_id class_id, struct asi **out_asi)
{
struct asi *asi;
@@ -388,6 +416,7 @@ int asi_init(struct mm_struct *mm, enum asi_class_id class_id, struct asi **out_
asi->mm = mm;
asi->class_id = class_id;
+ spin_lock_init(&asi->pgd_lock);
for (i = KERNEL_PGD_BOUNDARY; i < PTRS_PER_PGD; i++)
set_pgd(asi->pgd + i, asi_global_nonsensitive_pgd[i]);
@@ -398,6 +427,7 @@ int asi_init(struct mm_struct *mm, enum asi_class_id class_id, struct asi **out_
else
*out_asi = asi;
+ __asi_init_user_pgds(mm, asi);
mutex_unlock(&mm->asi_init_lock);
return err;
@@ -891,3 +921,65 @@ void asi_unmap(struct asi *asi, void *addr, size_t len)
asi_flush_tlb_range(asi, addr, len);
}
+
+/*
+ * This function is to copy the given unrestricted pgd entry for
+ * userspace addresses to the corresponding restricted pgd entries.
+ * It means that the unrestricted pgd entry must be updated before
+ * this function is called.
+ * We map entire userspace addresses to the restricted address spaces
+ * by copying unrestricted pgd entries to the restricted page tables
+ * so that we don't need to maintain consistency of lower level PTEs
+ * between the unrestricted page table and the restricted page tables.
+ */
+void asi_clone_user_pgtbl(struct mm_struct *mm, pgd_t *pgdp)
+{
+ unsigned long pgd_idx;
+ struct asi *asi;
+ int i;
+
+ if (!static_asi_enabled())
+ return;
+
+ /* We shouldn't need to take care non-userspace mapping. */
+ if (!pgdp_maps_userspace(pgdp))
+ return;
+
+ /*
+ * The mm will be NULL for p{4,g}d_clear(). We need to get
+ * the owner mm for this pgd in this case. The pgd page has
+ * a valid pt_mm only when SHARED_KERNEL_PMD == 0.
+ */
+ BUILD_BUG_ON(SHARED_KERNEL_PMD);
+ if (!mm) {
+ mm = pgd_page_get_mm(virt_to_page(pgdp));
+ if (WARN_ON_ONCE(!mm))
+ return;
+ }
+
+ /*
+ * Compute a PGD index of the given pgd entry. This will be the
+ * index of the ASI PGD entry to be updated.
+ */
+ pgd_idx = pgdp - PTR_ALIGN_DOWN(pgdp, PAGE_SIZE);
+
+ for (i = 0; i < ARRAY_SIZE(mm->asi); i++) {
+ asi = mm->asi + i;
+
+ if (!asi_pgd(asi) || !asi_maps_user_addr(asi->class_id))
+ continue;
+
+ /*
+ * We need to synchronize concurrent callers of
+ * __asi_clone_user_pgd() among themselves, as well as
+ * __asi_init_user_pgds(). The lock makes sure that reading
+ * the unrestricted pgd and updating the corresponding
+ * ASI pgd are not interleaved by concurrent calls.
+ * We cannot rely on mm->page_table_lock here because it
+ * is not always held when pgd/p4d_clear_bad() is called.
+ */
+ spin_lock(&asi->pgd_lock);
+ set_pgd(asi_pgd(asi) + pgd_idx, READ_ONCE(*pgdp));
+ spin_unlock(&asi->pgd_lock);
+ }
+}
diff --git a/include/asm-generic/asi.h b/include/asm-generic/asi.h
index 4f033d3ef5929707fd280f74fc800193e45143c1..d103343292fad567dcd73e45e986fb3974e59898 100644
--- a/include/asm-generic/asi.h
+++ b/include/asm-generic/asi.h
@@ -95,6 +95,10 @@ void asi_flush_tlb_range(struct asi *asi, void *addr, size_t len) { }
static inline void asi_check_boottime_disable(void) { }
+static inline void asi_clone_user_pgtbl(struct mm_struct *mm, pgd_t *pgdp) { };
+
+static inline bool asi_maps_user_addr(enum asi_class_id class_id) { return false; }
+
#endif /* !CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION */
#endif /* !_ASSEMBLY_ */
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH RFC v2 25/29] mm: asi: Restricted execution fore bare-metal processes
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
` (23 preceding siblings ...)
2025-01-10 18:40 ` [PATCH RFC v2 24/29] mm: asi: Add infrastructure for mapping userspace addresses Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
2025-02-28 15:32 ` Yosry Ahmed
2025-01-10 18:40 ` [PATCH RFC v2 26/29] x86: Create library for flushing L1D for L1TF Brendan Jackman
` (3 subsequent siblings)
28 siblings, 1 reply; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman
Now userspace gets a restricted address space too. The critical section
begins on exit to userspace and ends when it makes a system call.
Other entries from userspace just interrupt the critical section via
asi_intr_enter().
The reason why system calls have to actually asi_relax() (i.e. fully
terminate the critical section instead of just interrupting it) is that
system calls are the type of kernel entry that can lead to transition
into a _different_ ASI domain, namely the KVM one: it is not supported
to transition into a different domain while a critical section exists
(i.e. while asi_state.target is not NULL), even if it has been paused by
asi_intr_enter() (i.e. even if asi_state.intr_nest_depth is nonzero) -
there must be an asi_relax() between any two asi_enter()s.
The restricted address space for bare-metal tasks naturally contains the
entire userspace address region, although the task's own memory is still
missing from the direct map.
This implementation creates new userspace-specific APIs for asi_init(),
asi_destroy() and asi_enter(), which seems a little ugly, maybe this
suggest a general rework of these APIs given that the "generic" version
only has one caller. For RFC code this seems good enough though.
Signed-off-by: Brendan Jackman <jackmanb@google.com>
---
arch/x86/include/asm/asi.h | 8 ++++++--
arch/x86/mm/asi.c | 49 ++++++++++++++++++++++++++++++++++++++++----
include/asm-generic/asi.h | 9 +++++++-
include/linux/entry-common.h | 11 ++++++++++
init/main.c | 2 ++
kernel/entry/common.c | 1 +
kernel/fork.c | 4 +++-
7 files changed, 76 insertions(+), 8 deletions(-)
diff --git a/arch/x86/include/asm/asi.h b/arch/x86/include/asm/asi.h
index e925d7d2cfc85bca8480c837548654e7a5a7009e..c3c1a57f0147ae9bd11d89c8bf7c8a4477728f51 100644
--- a/arch/x86/include/asm/asi.h
+++ b/arch/x86/include/asm/asi.h
@@ -140,19 +140,23 @@ DECLARE_PER_CPU_ALIGNED(struct asi *, curr_asi);
void asi_check_boottime_disable(void);
-void asi_init_mm_state(struct mm_struct *mm);
+int asi_init_mm_state(struct mm_struct *mm);
int asi_init_class(enum asi_class_id class_id, struct asi_taint_policy *taint_policy);
+void asi_init_userspace_class(void);
void asi_uninit_class(enum asi_class_id class_id);
const char *asi_class_name(enum asi_class_id class_id);
int asi_init(struct mm_struct *mm, enum asi_class_id class_id, struct asi **out_asi);
void asi_destroy(struct asi *asi);
+void asi_destroy_userspace(struct mm_struct *mm);
void asi_clone_user_pgtbl(struct mm_struct *mm, pgd_t *pgdp);
/* Enter an ASI domain (restricted address space) and begin the critical section. */
void asi_enter(struct asi *asi);
+void asi_enter_userspace(void);
+
/*
* Leave the "tense" state if we are in it, i.e. end the critical section. We
* will stay relaxed until the next asi_enter.
@@ -294,7 +298,7 @@ void asi_handle_switch_mm(void);
*/
static inline bool asi_maps_user_addr(enum asi_class_id class_id)
{
- return false;
+ return class_id == ASI_CLASS_USERSPACE;
}
#endif /* CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION */
diff --git a/arch/x86/mm/asi.c b/arch/x86/mm/asi.c
index 093103c1bc2677c81d68008aca064fab53b73a62..1e9dc568e79e8686a4dbf47f765f2c2535d025ec 100644
--- a/arch/x86/mm/asi.c
+++ b/arch/x86/mm/asi.c
@@ -25,6 +25,7 @@ const char *asi_class_names[] = {
#if IS_ENABLED(CONFIG_KVM)
[ASI_CLASS_KVM] = "KVM",
#endif
+ [ASI_CLASS_USERSPACE] = "userspace",
};
DEFINE_PER_CPU_ALIGNED(struct asi *, curr_asi);
@@ -67,6 +68,32 @@ int asi_init_class(enum asi_class_id class_id, struct asi_taint_policy *taint_po
}
EXPORT_SYMBOL_GPL(asi_init_class);
+void __init asi_init_userspace_class(void)
+{
+ static struct asi_taint_policy policy = {
+ /*
+ * Prevent going to userspace with sensitive data potentially
+ * left in sidechannels by code running in the unrestricted
+ * address space, or another MM. Note we don't check for guest
+ * data here. This reflects the assumption that the guest trusts
+ * its VMM (absent fancy HW features, which are orthogonal).
+ */
+ .protect_data = ASI_TAINT_KERNEL_DATA | ASI_TAINT_OTHER_MM_DATA,
+ /*
+ * Don't go into userspace with control flow state controlled by
+ * other processes, or any KVM guest the process is running.
+ * Note this bit is about protecting userspace from other parts
+ * of the system, while data_taints is about protecting other
+ * parts of the system from the guest.
+ */
+ .prevent_control = ASI_TAINT_GUEST_CONTROL | ASI_TAINT_OTHER_MM_CONTROL,
+ .set = ASI_TAINT_USER_CONTROL | ASI_TAINT_USER_DATA,
+ };
+ int err = asi_init_class(ASI_CLASS_USERSPACE, &policy);
+
+ WARN_ON(err);
+}
+
void asi_uninit_class(enum asi_class_id class_id)
{
if (!boot_cpu_has(X86_FEATURE_ASI))
@@ -385,7 +412,8 @@ int asi_init(struct mm_struct *mm, enum asi_class_id class_id, struct asi **out_
int err = 0;
uint i;
- *out_asi = NULL;
+ if (out_asi)
+ *out_asi = NULL;
if (!boot_cpu_has(X86_FEATURE_ASI))
return 0;
@@ -424,7 +452,7 @@ int asi_init(struct mm_struct *mm, enum asi_class_id class_id, struct asi **out_
exit_unlock:
if (err)
__asi_destroy(asi);
- else
+ else if (out_asi)
*out_asi = asi;
__asi_init_user_pgds(mm, asi);
@@ -515,6 +543,12 @@ static __always_inline void maybe_flush_data(struct asi *next_asi)
this_cpu_and(asi_taints, ~ASI_TAINTS_DATA_MASK);
}
+void asi_destroy_userspace(struct mm_struct *mm)
+{
+ VM_BUG_ON(!asi_class_initialized(ASI_CLASS_USERSPACE));
+ asi_destroy(&mm->asi[ASI_CLASS_USERSPACE]);
+}
+
noinstr void __asi_enter(void)
{
u64 asi_cr3;
@@ -584,6 +618,11 @@ noinstr void asi_enter(struct asi *asi)
}
EXPORT_SYMBOL_GPL(asi_enter);
+noinstr void asi_enter_userspace(void)
+{
+ asi_enter(¤t->mm->asi[ASI_CLASS_USERSPACE]);
+}
+
noinstr void asi_relax(void)
{
if (static_asi_enabled()) {
@@ -633,13 +672,15 @@ noinstr void asi_exit(void)
}
EXPORT_SYMBOL_GPL(asi_exit);
-void asi_init_mm_state(struct mm_struct *mm)
+int asi_init_mm_state(struct mm_struct *mm)
{
if (!boot_cpu_has(X86_FEATURE_ASI))
- return;
+ return 0;
memset(mm->asi, 0, sizeof(mm->asi));
mutex_init(&mm->asi_init_lock);
+
+ return asi_init(mm, ASI_CLASS_USERSPACE, NULL);
}
void asi_handle_switch_mm(void)
diff --git a/include/asm-generic/asi.h b/include/asm-generic/asi.h
index d103343292fad567dcd73e45e986fb3974e59898..c93f9e779ce1fa61e3df7835f5ab744cce7d667b 100644
--- a/include/asm-generic/asi.h
+++ b/include/asm-generic/asi.h
@@ -15,6 +15,7 @@ enum asi_class_id {
#if IS_ENABLED(CONFIG_KVM)
ASI_CLASS_KVM,
#endif
+ ASI_CLASS_USERSPACE,
ASI_MAX_NUM_CLASSES,
};
static_assert(order_base_2(X86_CR3_ASI_PCID_BITS) <= ASI_MAX_NUM_CLASSES);
@@ -37,8 +38,10 @@ int asi_init_class(enum asi_class_id class_id,
static inline void asi_uninit_class(enum asi_class_id class_id) { }
+static inline void asi_init_userspace_class(void) { }
+
struct mm_struct;
-static inline void asi_init_mm_state(struct mm_struct *mm) { }
+static inline int asi_init_mm_state(struct mm_struct *mm) { return 0; }
static inline int asi_init(struct mm_struct *mm, enum asi_class_id class_id,
struct asi **out_asi)
@@ -48,8 +51,12 @@ static inline int asi_init(struct mm_struct *mm, enum asi_class_id class_id,
static inline void asi_destroy(struct asi *asi) { }
+static inline void asi_destroy_userspace(struct mm_struct *mm) { }
+
static inline void asi_enter(struct asi *asi) { }
+static inline void asi_enter_userspace(void) { }
+
static inline void asi_relax(void) { }
static inline bool asi_is_relaxed(void) { return true; }
diff --git a/include/linux/entry-common.h b/include/linux/entry-common.h
index 1e50cdb83ae501467ecc30ee52f1379d409f962e..f04c4c038556f84ddf3bc09b6c1dd22a9dbd2f6b 100644
--- a/include/linux/entry-common.h
+++ b/include/linux/entry-common.h
@@ -191,6 +191,16 @@ static __always_inline long syscall_enter_from_user_mode(struct pt_regs *regs, l
{
long ret;
+ /*
+ * End the ASI critical section for userspace. Syscalls are the only
+ * place this happens - all other entry from userspace is handled via
+ * ASI's interrupt-tracking. The reason syscalls are special is that's
+ * where it's possible to switch to another ASI domain within the same
+ * task (i.e. KVM_RUN), an asi_relax() is required here in case of an
+ * upcoming asi_enter().
+ */
+ asi_relax();
+
enter_from_user_mode(regs);
instrumentation_begin();
@@ -355,6 +365,7 @@ static __always_inline void exit_to_user_mode_prepare(struct pt_regs *regs)
*/
static __always_inline void exit_to_user_mode(void)
{
+
instrumentation_begin();
trace_hardirqs_on_prepare();
lockdep_hardirqs_on_prepare();
diff --git a/init/main.c b/init/main.c
index c4778edae7972f512d5eefe8400075ac35a70d1c..d19e149d385e8321d2f3e7c28aa75802af62d09c 100644
--- a/init/main.c
+++ b/init/main.c
@@ -953,6 +953,8 @@ void start_kernel(void)
/* Architectural and non-timekeeping rng init, before allocator init */
random_init_early(command_line);
+ asi_init_userspace_class();
+
/*
* These use large bootmem allocations and must precede
* initalization of page allocator
diff --git a/kernel/entry/common.c b/kernel/entry/common.c
index 5b6934e23c21d36a3238dc03e391eb9e3beb4cfb..874254ed5958d62eaeaef4fe3e8c02e56deaf5ed 100644
--- a/kernel/entry/common.c
+++ b/kernel/entry/common.c
@@ -218,6 +218,7 @@ __visible noinstr void syscall_exit_to_user_mode(struct pt_regs *regs)
__syscall_exit_to_user_mode_work(regs);
instrumentation_end();
exit_to_user_mode();
+ asi_enter_userspace();
}
noinstr void irqentry_enter_from_user_mode(struct pt_regs *regs)
diff --git a/kernel/fork.c b/kernel/fork.c
index bb73758790d08112265d398b16902ff9a4c2b8fe..54068d2415939b92409ca8a45111176783c6acbd 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -917,6 +917,7 @@ void __mmdrop(struct mm_struct *mm)
/* Ensure no CPUs are using this as their lazy tlb mm */
cleanup_lazy_tlbs(mm);
+ asi_destroy_userspace(mm);
WARN_ON_ONCE(mm == current->active_mm);
mm_free_pgd(mm);
destroy_context(mm);
@@ -1297,7 +1298,8 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p,
if (mm_alloc_pgd(mm))
goto fail_nopgd;
- asi_init_mm_state(mm);
+ if (asi_init_mm_state(mm))
+ goto fail_nocontext;
if (init_new_context(p, mm))
goto fail_nocontext;
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH RFC v2 26/29] x86: Create library for flushing L1D for L1TF
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
` (24 preceding siblings ...)
2025-01-10 18:40 ` [PATCH RFC v2 25/29] mm: asi: Restricted execution fore bare-metal processes Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 27/29] mm: asi: Add some mitigations on address space transitions Brendan Jackman
` (2 subsequent siblings)
28 siblings, 0 replies; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman
ASI will need to use this L1D flushing logic so put it in a library
where it can be used independently of KVM.
Since we're creating this library, it starts to look messy if we don't
also use it in the double-opt-in (both kernel cmdline and prctl)
mm-switching flush logic which is there for mitigating Snoop-Assisted L1
Data Sampling ("SAL1DS"). However, that logic doesn't use any
software-based fallback for flushing on CPUs without the L1D_FLUSH
command. In that case the prctl opt-in will fail.
One option would be to just start using the software fallback sequence
currently done by VMX code, but Linus didn't seem happy with a similar
sequence being used here [1]. CPUs affected by SAL1DS are a subset of
those affected by L1TF, so it wouldn't be completely insane to assume
that the same sequence works for both cases, but I'll err on the side of
caution and avoid risk of giving users a false impression that the
kernel has really flushed L1D for them.
[1] https://lore.kernel.org/linux-kernel/CAHk-=whC4PUhErcoDhCbTOdmPPy-Pj8j9ytsdcyz9TorOb4KUw@mail.gmail.com/
Instead, create this awkward library that is scoped specifically to L1TF,
which will be used only by VMX and ASI, and has an annoying "only
sometimes works" doc-comment. Users of the library can then infer from
that comment whether they have flushed L1D.
No functional change intended.
Checkpatch-args: --ignore=COMMIT_LOG_LONG_LINE
Signed-off-by: Brendan Jackman <jackmanb@google.com>
---
arch/x86/Kconfig | 4 ++
arch/x86/include/asm/l1tf.h | 11 ++++++
arch/x86/kvm/Kconfig | 1 +
arch/x86/kvm/vmx/vmx.c | 66 +++----------------------------
arch/x86/lib/Makefile | 1 +
arch/x86/lib/l1tf.c | 94 +++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 117 insertions(+), 60 deletions(-)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index ae31f36ce23d7c29d1e90b726c5a2e6ea5a63c8d..ca984dc7ee2f2b68c3ce1bcb5055047ca4f2a65d 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2523,6 +2523,7 @@ config MITIGATION_ADDRESS_SPACE_ISOLATION
bool "Allow code to run with a reduced kernel address space"
default n
depends on X86_64 && !PARAVIRT && !UML
+ select X86_L1TF_FLUSH_LIB
help
This feature provides the ability to run some kernel code
with a reduced kernel address space. This can be used to
@@ -3201,6 +3202,9 @@ config HAVE_ATOMIC_IOMAP
def_bool y
depends on X86_32
+config X86_L1TF_FLUSH_LIB
+ def_bool n
+
source "arch/x86/kvm/Kconfig"
source "arch/x86/Kconfig.assembler"
diff --git a/arch/x86/include/asm/l1tf.h b/arch/x86/include/asm/l1tf.h
new file mode 100644
index 0000000000000000000000000000000000000000..e0be19c588bb5ec5c76a1861492e48b88615b4b8
--- /dev/null
+++ b/arch/x86/include/asm/l1tf.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_L1TF_FLUSH_H
+#define _ASM_L1TF_FLUSH_H
+
+#ifdef CONFIG_X86_L1TF_FLUSH_LIB
+int l1tf_flush_setup(void);
+void l1tf_flush(void);
+#endif /* CONFIG_X86_L1TF_FLUSH_LIB */
+
+#endif
+
diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig
index f09f13c01c6bbd28fa37fdf50547abf4403658c9..81c71510e33e52447882ab7b22682199c57b492e 100644
--- a/arch/x86/kvm/Kconfig
+++ b/arch/x86/kvm/Kconfig
@@ -92,6 +92,7 @@ config KVM_SW_PROTECTED_VM
config KVM_INTEL
tristate "KVM for Intel (and compatible) processors support"
depends on KVM && IA32_FEAT_CTL
+ select X86_L1TF_FLUSH_LIB
help
Provides support for KVM on processors equipped with Intel's VT
extensions, a.k.a. Virtual Machine Extensions (VMX).
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 0e90463f1f2183b8d716f85d5c8a8af8958fef0b..b1a02f27b3abce0ef6ac448b66bef2c653a52eef 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -42,6 +42,7 @@
#include <asm/idtentry.h>
#include <asm/io.h>
#include <asm/irq_remapping.h>
+#include <asm/l1tf.h>
#include <asm/reboot.h>
#include <asm/perf_event.h>
#include <asm/mmu_context.h>
@@ -250,9 +251,6 @@ static void *vmx_l1d_flush_pages;
static int vmx_setup_l1d_flush(enum vmx_l1d_flush_state l1tf)
{
- struct page *page;
- unsigned int i;
-
if (!boot_cpu_has_bug(X86_BUG_L1TF)) {
l1tf_vmx_mitigation = VMENTER_L1D_FLUSH_NOT_REQUIRED;
return 0;
@@ -288,26 +286,11 @@ static int vmx_setup_l1d_flush(enum vmx_l1d_flush_state l1tf)
l1tf = VMENTER_L1D_FLUSH_ALWAYS;
}
- if (l1tf != VMENTER_L1D_FLUSH_NEVER && !vmx_l1d_flush_pages &&
- !boot_cpu_has(X86_FEATURE_FLUSH_L1D)) {
- /*
- * This allocation for vmx_l1d_flush_pages is not tied to a VM
- * lifetime and so should not be charged to a memcg.
- */
- page = alloc_pages(GFP_KERNEL, L1D_CACHE_ORDER);
- if (!page)
- return -ENOMEM;
- vmx_l1d_flush_pages = page_address(page);
+ if (l1tf != VMENTER_L1D_FLUSH_NEVER) {
+ int err = l1tf_flush_setup();
- /*
- * Initialize each page with a different pattern in
- * order to protect against KSM in the nested
- * virtualization case.
- */
- for (i = 0; i < 1u << L1D_CACHE_ORDER; ++i) {
- memset(vmx_l1d_flush_pages + i * PAGE_SIZE, i + 1,
- PAGE_SIZE);
- }
+ if (err)
+ return err;
}
l1tf_vmx_mitigation = l1tf;
@@ -6652,20 +6635,8 @@ int vmx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
return ret;
}
-/*
- * Software based L1D cache flush which is used when microcode providing
- * the cache control MSR is not loaded.
- *
- * The L1D cache is 32 KiB on Nehalem and later microarchitectures, but to
- * flush it is required to read in 64 KiB because the replacement algorithm
- * is not exactly LRU. This could be sized at runtime via topology
- * information but as all relevant affected CPUs have 32KiB L1D cache size
- * there is no point in doing so.
- */
static noinstr void vmx_l1d_flush(struct kvm_vcpu *vcpu)
{
- int size = PAGE_SIZE << L1D_CACHE_ORDER;
-
/*
* This code is only executed when the flush mode is 'cond' or
* 'always'
@@ -6695,32 +6666,7 @@ static noinstr void vmx_l1d_flush(struct kvm_vcpu *vcpu)
vcpu->stat.l1d_flush++;
- if (static_cpu_has(X86_FEATURE_FLUSH_L1D)) {
- native_wrmsrl(MSR_IA32_FLUSH_CMD, L1D_FLUSH);
- return;
- }
-
- asm volatile(
- /* First ensure the pages are in the TLB */
- "xorl %%eax, %%eax\n"
- ".Lpopulate_tlb:\n\t"
- "movzbl (%[flush_pages], %%" _ASM_AX "), %%ecx\n\t"
- "addl $4096, %%eax\n\t"
- "cmpl %%eax, %[size]\n\t"
- "jne .Lpopulate_tlb\n\t"
- "xorl %%eax, %%eax\n\t"
- "cpuid\n\t"
- /* Now fill the cache */
- "xorl %%eax, %%eax\n"
- ".Lfill_cache:\n"
- "movzbl (%[flush_pages], %%" _ASM_AX "), %%ecx\n\t"
- "addl $64, %%eax\n\t"
- "cmpl %%eax, %[size]\n\t"
- "jne .Lfill_cache\n\t"
- "lfence\n"
- :: [flush_pages] "r" (vmx_l1d_flush_pages),
- [size] "r" (size)
- : "eax", "ebx", "ecx", "edx");
+ l1tf_flush();
}
void vmx_update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index 98583a9dbab337e09a2e58905e5200499a496a07..b0a45bd70b40743a3fccb352b9641caacac83275 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -37,6 +37,7 @@ lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o insn-eval.o
lib-$(CONFIG_RANDOMIZE_BASE) += kaslr.o
lib-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
lib-$(CONFIG_MITIGATION_RETPOLINE) += retpoline.o
+lib-$(CONFIG_X86_L1TF_FLUSH_LIB) += l1tf.o
obj-y += msr.o msr-reg.o msr-reg-export.o hweight.o
obj-y += iomem.o
diff --git a/arch/x86/lib/l1tf.c b/arch/x86/lib/l1tf.c
new file mode 100644
index 0000000000000000000000000000000000000000..c474f18ae331c8dfa7a029c457dd3cf75bebf808
--- /dev/null
+++ b/arch/x86/lib/l1tf.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/gfp.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+
+#include <asm/cpufeature.h>
+#include <asm/l1tf.h>
+#include <asm/msr.h>
+
+#define L1D_CACHE_ORDER 4
+static void *l1tf_flush_pages;
+
+int l1tf_flush_setup(void)
+{
+ struct page *page;
+ unsigned int i;
+
+ if (l1tf_flush_pages || boot_cpu_has(X86_FEATURE_FLUSH_L1D))
+ return 0;
+
+ page = alloc_pages(GFP_KERNEL, L1D_CACHE_ORDER);
+ if (!page)
+ return -ENOMEM;
+ l1tf_flush_pages = page_address(page);
+
+ /*
+ * Initialize each page with a different pattern in
+ * order to protect against KSM in the nested
+ * virtualization case.
+ */
+ for (i = 0; i < 1u << L1D_CACHE_ORDER; ++i) {
+ memset(l1tf_flush_pages + i * PAGE_SIZE, i + 1,
+ PAGE_SIZE);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(l1tf_flush_setup);
+
+/*
+ * Flush L1D in a way that:
+ *
+ * - definitely works on CPUs X86_FEATURE_FLUSH_L1D (because the SDM says so).
+ * - almost definitely works on other CPUs with L1TF (because someone on LKML
+ * said someone from Intel said so).
+ * - may or may not work on other CPUs.
+ *
+ * Don't call unless l1tf_flush_setup() has returned successfully.
+ */
+noinstr void l1tf_flush(void)
+{
+ int size = PAGE_SIZE << L1D_CACHE_ORDER;
+
+ if (static_cpu_has(X86_FEATURE_FLUSH_L1D)) {
+ native_wrmsrl(MSR_IA32_FLUSH_CMD, L1D_FLUSH);
+ return;
+ }
+
+ if (WARN_ON(!l1tf_flush_pages))
+ return;
+
+ /*
+ * This sequence was provided by Intel for the purpose of mitigating
+ * L1TF on VMX.
+ *
+ * The L1D cache is 32 KiB on Nehalem and some later microarchitectures,
+ * but to flush it is required to read in 64 KiB because the replacement
+ * algorithm is not exactly LRU. This could be sized at runtime via
+ * topology information but as all relevant affected CPUs have 32KiB L1D
+ * cache size there is no point in doing so.
+ */
+ asm volatile(
+ /* First ensure the pages are in the TLB */
+ "xorl %%eax, %%eax\n"
+ ".Lpopulate_tlb:\n\t"
+ "movzbl (%[flush_pages], %%" _ASM_AX "), %%ecx\n\t"
+ "addl $4096, %%eax\n\t"
+ "cmpl %%eax, %[size]\n\t"
+ "jne .Lpopulate_tlb\n\t"
+ "xorl %%eax, %%eax\n\t"
+ "cpuid\n\t"
+ /* Now fill the cache */
+ "xorl %%eax, %%eax\n"
+ ".Lfill_cache:\n"
+ "movzbl (%[flush_pages], %%" _ASM_AX "), %%ecx\n\t"
+ "addl $64, %%eax\n\t"
+ "cmpl %%eax, %[size]\n\t"
+ "jne .Lfill_cache\n\t"
+ "lfence\n"
+ :: [flush_pages] "r" (l1tf_flush_pages),
+ [size] "r" (size)
+ : "eax", "ebx", "ecx", "edx");
+}
+EXPORT_SYMBOL(l1tf_flush);
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH RFC v2 27/29] mm: asi: Add some mitigations on address space transitions
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
` (25 preceding siblings ...)
2025-01-10 18:40 ` [PATCH RFC v2 26/29] x86: Create library for flushing L1D for L1TF Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 28/29] x86/pti: Disable PTI when ASI is on Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 29/29] mm: asi: Stop ignoring asi=on cmdline flag Brendan Jackman
28 siblings, 0 replies; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman
Here we ASI actually starts becoming a real exploit mitigation,
On CPUs with L1TF, flush L1D when the ASI data taints say so.
On all CPUs, do some general branch predictor clearing
whenever the control taints say so.
This policy is very much just a starting point for discussion.
Primarily it's a vague gesture at the fact that there is leeway
in how ASI is used: it can be used to target CPU-specific issues (as
is the case for L1TF here), or it can be used as a fairly broad
mitigation (asi_maybe_flush_control() mitigates several known
Spectre-style attacks and very likely also some unknown ones).
Signed-off-by: Brendan Jackman <jackmanb@google.com>
---
arch/x86/include/asm/nospec-branch.h | 2 ++
arch/x86/kvm/vmx/vmx.c | 1 +
arch/x86/lib/l1tf.c | 2 ++
arch/x86/lib/retpoline.S | 10 ++++++++++
arch/x86/mm/asi.c | 29 +++++++++++++++++++++--------
5 files changed, 36 insertions(+), 8 deletions(-)
diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h
index 96b410b1d4e841eb02f53a4691ee794ceee4ad2c..4582fb1fb42f6fd226534012d969ed13085e943a 100644
--- a/arch/x86/include/asm/nospec-branch.h
+++ b/arch/x86/include/asm/nospec-branch.h
@@ -614,6 +614,8 @@ static __always_inline void mds_idle_clear_cpu_buffers(void)
mds_clear_cpu_buffers();
}
+extern void fill_return_buffer(void);
+
#endif /* __ASSEMBLY__ */
#endif /* _ASM_X86_NOSPEC_BRANCH_H_ */
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index b1a02f27b3abce0ef6ac448b66bef2c653a52eef..a532783caaea97291cd92a2e2cac617f74f76c7e 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -6635,6 +6635,7 @@ int vmx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
return ret;
}
+/* Must be reentrant, for use by vmx_post_asi_enter. */
static noinstr void vmx_l1d_flush(struct kvm_vcpu *vcpu)
{
/*
diff --git a/arch/x86/lib/l1tf.c b/arch/x86/lib/l1tf.c
index c474f18ae331c8dfa7a029c457dd3cf75bebf808..ffe1c3d0ef43ff8f1781f2e446aed041f4ce3179 100644
--- a/arch/x86/lib/l1tf.c
+++ b/arch/x86/lib/l1tf.c
@@ -46,6 +46,8 @@ EXPORT_SYMBOL(l1tf_flush_setup);
* - may or may not work on other CPUs.
*
* Don't call unless l1tf_flush_setup() has returned successfully.
+ *
+ * Must be reentrant, for use by ASI.
*/
noinstr void l1tf_flush(void)
{
diff --git a/arch/x86/lib/retpoline.S b/arch/x86/lib/retpoline.S
index 391059b2c6fbc4a571f0582c7c4654147a930cef..6d126fff6bf839889086fe21464d8af07316d7e5 100644
--- a/arch/x86/lib/retpoline.S
+++ b/arch/x86/lib/retpoline.S
@@ -396,3 +396,13 @@ SYM_CODE_END(__x86_return_thunk)
EXPORT_SYMBOL(__x86_return_thunk)
#endif /* CONFIG_MITIGATION_RETHUNK */
+
+.pushsection .noinstr.text, "ax"
+SYM_CODE_START(fill_return_buffer)
+ UNWIND_HINT_FUNC
+ ENDBR
+ __FILL_RETURN_BUFFER(%_ASM_AX,RSB_CLEAR_LOOPS)
+ RET
+SYM_CODE_END(fill_return_buffer)
+__EXPORT_THUNK(fill_return_buffer)
+.popsection
diff --git a/arch/x86/mm/asi.c b/arch/x86/mm/asi.c
index 1e9dc568e79e8686a4dbf47f765f2c2535d025ec..f10f6614b26148e5ba423d8a44f640674573ee40 100644
--- a/arch/x86/mm/asi.c
+++ b/arch/x86/mm/asi.c
@@ -10,6 +10,7 @@
#include <asm/cmdline.h>
#include <asm/cpufeature.h>
+#include <asm/l1tf.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
#include <asm/mmu_context.h>
@@ -38,6 +39,8 @@ struct asi __asi_global_nonsensitive = {
.mm = &init_mm,
};
+static bool do_l1tf_flush __ro_after_init;
+
static inline bool asi_class_id_valid(enum asi_class_id class_id)
{
return class_id >= 0 && class_id < ASI_MAX_NUM_CLASSES;
@@ -361,6 +364,15 @@ static int __init asi_global_init(void)
asi_clone_pgd(asi_global_nonsensitive_pgd, init_mm.pgd,
VMEMMAP_START + (1UL << PGDIR_SHIFT));
+ if (boot_cpu_has_bug(X86_BUG_L1TF)) {
+ int err = l1tf_flush_setup();
+
+ if (err)
+ pr_warn("Failed to setup L1TF flushing for ASI (%pe)", ERR_PTR(err));
+ else
+ do_l1tf_flush = true;
+ }
+
#ifdef CONFIG_PM_SLEEP
register_syscore_ops(&asi_syscore_ops);
#endif
@@ -512,10 +524,12 @@ static __always_inline void maybe_flush_control(struct asi *next_asi)
if (!taints)
return;
- /*
- * This is where we'll do the actual dirty work of clearing uarch state.
- * For now we just pretend, clear the taints.
- */
+ /* Clear normal indirect branch predictions, if we haven't */
+ if (cpu_feature_enabled(X86_FEATURE_IBPB))
+ __wrmsr(MSR_IA32_PRED_CMD, PRED_CMD_IBPB, 0);
+
+ fill_return_buffer();
+
this_cpu_and(asi_taints, ~ASI_TAINTS_CONTROL_MASK);
}
@@ -536,10 +550,9 @@ static __always_inline void maybe_flush_data(struct asi *next_asi)
if (!taints)
return;
- /*
- * This is where we'll do the actual dirty work of clearing uarch state.
- * For now we just pretend, clear the taints.
- */
+ if (do_l1tf_flush)
+ l1tf_flush();
+
this_cpu_and(asi_taints, ~ASI_TAINTS_DATA_MASK);
}
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH RFC v2 28/29] x86/pti: Disable PTI when ASI is on
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
` (26 preceding siblings ...)
2025-01-10 18:40 ` [PATCH RFC v2 27/29] mm: asi: Add some mitigations on address space transitions Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 29/29] mm: asi: Stop ignoring asi=on cmdline flag Brendan Jackman
28 siblings, 0 replies; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman
Now that ASI has support for sandboxing userspace, although userspace
now has much more mapped than it would under KPTI, in theory none of
that data is important to protect.
Note that one particular impact of this is it makes locally defeating
KASLR easier. I don't think this is a great loss given [1] etc.
Why do we pass in an argument instead of just having
pti_check_boottime_disable() check boot_cpu_has(X86_FEATURE_ASI)? Just
for clarity: I wanted it to be at least _sort of_ visible that it would
break if you reordered asi_check_boottime_disable() afterwards.
[1]: https://gruss.cc/files/prefetch.pdf
and https://dl.acm.org/doi/pdf/10.1145/3623652.3623669
Signed-off-by: Brendan Jackman <jackmanb@google.com>
---
arch/x86/include/asm/pti.h | 6 ++++--
arch/x86/mm/init.c | 2 +-
arch/x86/mm/pti.c | 14 +++++++++++++-
3 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/arch/x86/include/asm/pti.h b/arch/x86/include/asm/pti.h
index ab167c96b9ab474b33d778453db0bb550f42b0ac..79b9ba927db9b76ac3cc72cdda6f8b5fc413d352 100644
--- a/arch/x86/include/asm/pti.h
+++ b/arch/x86/include/asm/pti.h
@@ -3,12 +3,14 @@
#define _ASM_X86_PTI_H
#ifndef __ASSEMBLY__
+#include <linux/types.h>
+
#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
extern void pti_init(void);
-extern void pti_check_boottime_disable(void);
+extern void pti_check_boottime_disable(bool asi_enabled);
extern void pti_finalize(void);
#else
-static inline void pti_check_boottime_disable(void) { }
+static inline void pti_check_boottime_disable(bool asi_enabled) { }
#endif
#endif /* __ASSEMBLY__ */
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index ded3a47f2a9c1f554824d4ad19f3b48bce271274..4ccf6d60705652805342abefc5e71cd00c563207 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -754,8 +754,8 @@ void __init init_mem_mapping(void)
{
unsigned long end;
- pti_check_boottime_disable();
asi_check_boottime_disable();
+ pti_check_boottime_disable(boot_cpu_has(X86_FEATURE_ASI));
probe_page_size_mask();
setup_pcid();
diff --git a/arch/x86/mm/pti.c b/arch/x86/mm/pti.c
index 851ec8f1363a8b389ea4579cc68bf3300a4df27c..b7132080d3c9b6962a0252383190335e171bafa6 100644
--- a/arch/x86/mm/pti.c
+++ b/arch/x86/mm/pti.c
@@ -76,7 +76,7 @@ static enum pti_mode {
PTI_FORCE_ON
} pti_mode;
-void __init pti_check_boottime_disable(void)
+void __init pti_check_boottime_disable(bool asi_enabled)
{
if (hypervisor_is_type(X86_HYPER_XEN_PV)) {
pti_mode = PTI_FORCE_OFF;
@@ -91,6 +91,18 @@ void __init pti_check_boottime_disable(void)
return;
}
+ if (asi_enabled) {
+ /*
+ * Having both ASI and PTI enabled is not a totally ridiculous
+ * thing to do; if you want ASI but you are not confident in the
+ * sensitivity annotations then it provides useful
+ * defence-in-depth. But, the implementation doesn't support it.
+ */
+ if (pti_mode != PTI_FORCE_OFF)
+ pti_print_if_insecure("disabled by ASI");
+ return;
+ }
+
if (pti_mode == PTI_FORCE_ON)
pti_print_if_secure("force enabled on command line.");
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH RFC v2 29/29] mm: asi: Stop ignoring asi=on cmdline flag
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
` (27 preceding siblings ...)
2025-01-10 18:40 ` [PATCH RFC v2 28/29] x86/pti: Disable PTI when ASI is on Brendan Jackman
@ 2025-01-10 18:40 ` Brendan Jackman
28 siblings, 0 replies; 45+ messages in thread
From: Brendan Jackman @ 2025-01-10 18:40 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Brendan Jackman
At this point the minimum requirements are in place for the kernel to
operate correctly with ASI enabled.
Signed-off-by: Brendan Jackman <jackmanb@google.com>
---
arch/x86/mm/asi.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/x86/mm/asi.c b/arch/x86/mm/asi.c
index f10f6614b26148e5ba423d8a44f640674573ee40..3e3956326936ea8550308ad004dbbb3738546f9f 100644
--- a/arch/x86/mm/asi.c
+++ b/arch/x86/mm/asi.c
@@ -207,14 +207,14 @@ void __init asi_check_boottime_disable(void)
pr_info("ASI disabled through kernel command line.\n");
} else if (ret == 2 && !strncmp(arg, "on", 2)) {
enabled = true;
- pr_info("Ignoring asi=on param while ASI implementation is incomplete.\n");
+ pr_info("ASI enabled through kernel command line.\n");
} else {
pr_info("ASI %s by default.\n",
enabled ? "enabled" : "disabled");
}
if (enabled)
- pr_info("ASI enablement ignored due to incomplete implementation.\n");
+ setup_force_cpu_cap(X86_FEATURE_ASI);
}
/*
--
2.47.1.613.gc27f4b7a9f-goog
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* Re: [PATCH RFC v2 01/29] mm: asi: Make some utility functions noinstr compatible
2025-01-10 18:40 ` [PATCH RFC v2 01/29] mm: asi: Make some utility functions noinstr compatible Brendan Jackman
@ 2025-01-16 0:18 ` Borislav Petkov
2025-01-16 10:27 ` Borislav Petkov
0 siblings, 1 reply; 45+ messages in thread
From: Borislav Petkov @ 2025-01-16 0:18 UTC (permalink / raw)
To: Brendan Jackman
Cc: Thomas Gleixner, Ingo Molnar, Dave Hansen, H. Peter Anvin,
Andy Lutomirski, Peter Zijlstra, Richard Henderson, Matt Turner,
Vineet Gupta, Russell King, Catalin Marinas, Will Deacon, Guo Ren,
Brian Cain, Huacai Chen, WANG Xuerui, Geert Uytterhoeven,
Michal Simek, Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn,
Stefan Kristiansson, Stafford Horne, James E.J. Bottomley,
Helge Deller, Michael Ellerman, Nicholas Piggin, Christophe Leroy,
Naveen N Rao, Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta, x86, linux-kernel, linux-alpha,
linux-snps-arc, linux-arm-kernel, linux-csky, linux-hexagon,
loongarch, linux-m68k, linux-mips, linux-openrisc, linux-parisc,
linuxppc-dev, linux-riscv, linux-s390, linux-sh, sparclinux,
linux-um, linux-arch, linux-mm, linux-trace-kernel,
linux-perf-users, kvm, linux-efi
On Fri, Jan 10, 2025 at 06:40:27PM +0000, Brendan Jackman wrote:
> Subject: Re: [PATCH RFC v2 01/29] mm: asi: Make some utility functions noinstr compatible
The tip tree preferred format for patch subject prefixes is
'subsys/component:', e.g. 'x86/apic:', 'x86/mm/fault:', 'sched/fair:',
'genirq/core:'. Please do not use file names or complete file paths as
prefix. 'git log path/to/file' should give you a reasonable hint in most
cases.
So I guess "x86/asm:" or so.
> Some existing utility functions would need to be called from a noinstr
> context in the later patches. So mark these as either noinstr or
> __always_inline.
>
> An earlier version of this by Junaid had a macro that was intended to
> tell the compiler "either inline this function, or call it in the
> noinstr section", which basically boiled down to:
>
> #define inline_or_noinstr noinline __section(".noinstr.text")
>
> Unfortunately Thomas pointed out this will prevent the function from
> being inlined at call sites in .text.
>
> So far I haven't been able[1] to find a formulation that lets us :
> 1. avoid calls from .noinstr.text -> .text,
> 2. while also letting the compiler freely decide what to inline.
>
> 1 is a functional requirement so here I'm just giving up on 2. Existing
> callsites of this code are just forced inline. For the incoming code
> that needs to call it from noinstr, they will be out-of-line calls.
I'm not sure some of that belongs in the commit message - if you want to have
it in the submission, you should put it under the --- line below, right above
the diffstat.
> [1] https://lore.kernel.org/lkml/CA+i-1C1z35M8wA_4AwMq7--c1OgjNoLGTkn4+Td5gKg7QQAzWw@mail.gmail.com/
>
> Checkpatch-args: --ignore=COMMIT_LOG_LONG_LINE
Yeah, you can drop those. People should not turn off brain, use checkpatch and
point at all the silly errors it spits anyway.
> Signed-off-by: Brendan Jackman <jackmanb@google.com>
> ---
> arch/x86/include/asm/processor.h | 2 +-
> arch/x86/include/asm/special_insns.h | 8 ++++----
> arch/x86/include/asm/tlbflush.h | 3 +++
> arch/x86/mm/tlb.c | 13 +++++++++----
> 4 files changed, 17 insertions(+), 9 deletions(-)
So I was just about to look at the below diff but then booting the patch in my
guest causes it to stop at:
[ 1.110988] sr 2:0:0:0: Attached scsi generic sg1 type 5
[ 1.114210] PM: Image not found (code -22)
[ 1.114903] clk: Disabling unused clocks
[ 1.119397] EXT4-fs (sda2): mounted filesystem 90868bc4-a017-4fa2-ac81-931ba260346f ro with ordered data mode. Quota mode: disabled.
[ 1.121069] VFS: Mounted root (ext4 filesystem) readonly on device 8:2.
<--- EOF
with the below call stack.
Booting it on Linus' master branch is ok but this is tip/master with all that
we've accumulated for the next merge window along with other stuff I'm poking
at...
Long story short, lemme try to poke around tomorrow to try to figure out what
actually happens. It could be caused by the part of Rik's patches and this one
inlining things. We'll see...
native_flush_tlb_one_user (addr=2507219558400) at arch/x86/mm/tlb.c:1177
1177 if (!static_cpu_has(X86_FEATURE_PTI))
(gdb) bt
#0 native_flush_tlb_one_user (addr=2507219558400) at arch/x86/mm/tlb.c:1177
#1 0xffffffff8128206e in flush_tlb_one_user (addr=addr@entry=2507219558400) at arch/x86/mm/tlb.c:1196
#2 flush_tlb_one_kernel (addr=addr@entry=2507219558400) at arch/x86/mm/tlb.c:1151
#3 0xffffffff812820b7 in do_kernel_range_flush (info=0xffff88807dc311c0) at arch/x86/mm/tlb.c:1092
#4 0xffffffff8137beb6 in csd_do_func (csd=0x0 <fixed_percpu_data>, info=0xffff88807dc311c0,
func=0xffffffff81282090 <do_kernel_range_flush>) at kernel/smp.c:134
#5 smp_call_function_many_cond (mask=<optimized out>, func=func@entry=0xffffffff81282090 <do_kernel_range_flush>,
info=0xffff88807dc311c0, scf_flags=scf_flags@entry=3, cond_func=cond_func@entry=0x0 <fixed_percpu_data>)
at kernel/smp.c:876
#6 0xffffffff8137c254 in on_each_cpu_cond_mask (cond_func=cond_func@entry=0x0 <fixed_percpu_data>,
func=func@entry=0xffffffff81282090 <do_kernel_range_flush>, info=<optimized out>, wait=wait@entry=true,
mask=<optimized out>) at kernel/smp.c:1052
#7 0xffffffff81282020 in on_each_cpu (wait=1, info=<optimized out>, func=0xffffffff81282090 <do_kernel_range_flush>)
at ./include/linux/smp.h:71
#8 flush_tlb_kernel_range (start=start@entry=18446683600570097664, end=<optimized out>, end@entry=18446683600579907584)
at arch/x86/mm/tlb.c:1106
#9 0xffffffff81481c3f in __purge_vmap_area_lazy (start=18446683600570097664, start@entry=18446744073709551615,
end=18446683600579907584, end@entry=0, full_pool_decay=full_pool_decay@entry=false) at mm/vmalloc.c:2284
#10 0xffffffff81481fde in _vm_unmap_aliases (start=start@entry=18446744073709551615, end=end@entry=0,
flush=<optimized out>, flush@entry=0) at mm/vmalloc.c:2899
#11 0xffffffff81482049 in vm_unmap_aliases () at mm/vmalloc.c:2922
#12 0xffffffff81284d9f in change_page_attr_set_clr (addr=0xffffc9000001fef0, numpages=<optimized out>, mask_set=...,
mask_clr=..., force_split=<optimized out>, in_flag=0, pages=0x0 <fixed_percpu_data>)
at arch/x86/mm/pat/set_memory.c:1881
#13 0xffffffff81285c52 in change_page_attr_set (array=0, mask=..., numpages=511, addr=0xffffc9000001fef0)
at arch/x86/mm/pat/set_memory.c:1922
#14 set_memory_nx (addr=<optimized out>, addr@entry=18446744071759204352, numpages=numpages@entry=511)
at arch/x86/mm/pat/set_memory.c:2110
#15 0xffffffff8127b729 in free_init_pages (what=what@entry=0xffffffff8226bac0 "unused decrypted",
begin=18446744071759204352, end=18446744071761297408) at arch/x86/mm/init.c:929
#16 0xffffffff898f25aa in mem_encrypt_free_decrypted_mem () at arch/x86/mm/mem_encrypt_amd.c:574
#17 0xffffffff81ca06c3 in free_initmem () at arch/x86/mm/init.c:973
#18 0xffffffff81c9fa48 in kernel_init (unused=<optimized out>) at init/main.c:1475
#19 0xffffffff812398a0 in ret_from_fork (prev=<optimized out>, regs=0xffffc9000001ff58,
fn=0xffffffff81c9fa10 <kernel_init>, fn_arg=0x0 <fixed_percpu_data>) at arch/x86/kernel/process.c:148
#20 0xffffffff81206f7a in ret_from_fork_asm () at arch/x86/entry/entry_64.S:244
#21 0x1f0f2e6600000000 in ?? ()
#22 0x2e66000000000084 in ?? ()
#23 0x0000000000841f0f in ?? ()
#24 0x000000841f0f2e66 in ?? ()
#25 0x00841f0f2e660000 in ?? ()
#26 0x1f0f2e6600000000 in ?? ()
#27 0x2e66000000000084 in ?? ()
#28 0x0000000000841f0f in ?? ()
#29 0x000000841f0f2e66 in ?? ()
#30 0x00841f0f2e660000 in ?? ()
#31 0x0000000000000000 in ?? ()
(gdb)
--
Regards/Gruss,
Boris.
https://people.kernel.org/tglx/notes-about-netiquette
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH RFC v2 01/29] mm: asi: Make some utility functions noinstr compatible
2025-01-16 0:18 ` Borislav Petkov
@ 2025-01-16 10:27 ` Borislav Petkov
2025-01-16 13:22 ` Brendan Jackman
0 siblings, 1 reply; 45+ messages in thread
From: Borislav Petkov @ 2025-01-16 10:27 UTC (permalink / raw)
To: Brendan Jackman
Cc: Thomas Gleixner, Ingo Molnar, Dave Hansen, H. Peter Anvin,
Andy Lutomirski, Peter Zijlstra, Richard Henderson, Matt Turner,
Vineet Gupta, Russell King, Catalin Marinas, Will Deacon, Guo Ren,
Brian Cain, Huacai Chen, WANG Xuerui, Geert Uytterhoeven,
Michal Simek, Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn,
Stefan Kristiansson, Stafford Horne, James E.J. Bottomley,
Helge Deller, Michael Ellerman, Nicholas Piggin, Christophe Leroy,
Naveen N Rao, Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta, x86, linux-kernel, linux-alpha,
linux-snps-arc, linux-arm-kernel, linux-csky, linux-hexagon,
loongarch, linux-m68k, linux-mips, linux-openrisc, linux-parisc,
linuxppc-dev, linux-riscv, linux-s390, linux-sh, sparclinux,
linux-um, linux-arch, linux-mm, linux-trace-kernel,
linux-perf-users, kvm, linux-efi
On Thu, Jan 16, 2025 at 01:18:58AM +0100, Borislav Petkov wrote:
> Long story short, lemme try to poke around tomorrow to try to figure out what
> actually happens. It could be caused by the part of Rik's patches and this one
> inlining things. We'll see...
Looks transient... The very similar guest boots fine on another machine. Let's
watch this...
--
Regards/Gruss,
Boris.
https://people.kernel.org/tglx/notes-about-netiquette
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH RFC v2 01/29] mm: asi: Make some utility functions noinstr compatible
2025-01-16 10:27 ` Borislav Petkov
@ 2025-01-16 13:22 ` Brendan Jackman
2025-01-16 14:02 ` Borislav Petkov
0 siblings, 1 reply; 45+ messages in thread
From: Brendan Jackman @ 2025-01-16 13:22 UTC (permalink / raw)
To: Borislav Petkov
Cc: Thomas Gleixner, Ingo Molnar, Dave Hansen, H. Peter Anvin,
Andy Lutomirski, Peter Zijlstra, Richard Henderson, Matt Turner,
Vineet Gupta, Russell King, Catalin Marinas, Will Deacon, Guo Ren,
Brian Cain, Huacai Chen, WANG Xuerui, Geert Uytterhoeven,
Michal Simek, Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn,
Stefan Kristiansson, Stafford Horne, James E.J. Bottomley,
Helge Deller, Michael Ellerman, Nicholas Piggin, Christophe Leroy,
Naveen N Rao, Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta, x86, linux-kernel, linux-alpha,
linux-snps-arc, linux-arm-kernel, linux-csky, linux-hexagon,
loongarch, linux-m68k, linux-mips, linux-openrisc, linux-parisc,
linuxppc-dev, linux-riscv, linux-s390, linux-sh, sparclinux,
linux-um, linux-arch, linux-mm, linux-trace-kernel,
linux-perf-users, kvm, linux-efi
On Thu, 16 Jan 2025 at 01:21, Borislav Petkov <bp@alien8.de> wrote:
> > Unfortunately Thomas pointed out this will prevent the function from
> > being inlined at call sites in .text.
> >
> > So far I haven't been able[1] to find a formulation that lets us :
> > 1. avoid calls from .noinstr.text -> .text,
> > 2. while also letting the compiler freely decide what to inline.
> >
> > 1 is a functional requirement so here I'm just giving up on 2. Existing
> > callsites of this code are just forced inline. For the incoming code
> > that needs to call it from noinstr, they will be out-of-line calls.
>
> I'm not sure some of that belongs in the commit message - if you want to have
> it in the submission, you should put it under the --- line below, right above
> the diffstat.
Sure. I'm actually not even sure that for a [PATCH]-quality thing this
cross-cutting commit even makes sense - once we've decided on the
general way to solve this problem, perhaps the changes should just be
part of the commit that needs them?
It feels messy to have a patch that "does multiple things", but on the
other hand it might be annoying to review a patch that says "make a
load of random changes across the kernel, which are needed at various
points in various upcoming patches, trust me".
Do you have any opinion on that?
(BTW, since a comment you made on another series (can't find it on
Lore...), I've changed my writing style to avoid stuff like this in
comments & commit messages in general, but this text all predates
that. I'll do my best to sort all that stuff out before I send
anything as a [PATCH].)
On Thu, 16 Jan 2025 at 11:29, Borislav Petkov <bp@alien8.de> wrote:
>
> On Thu, Jan 16, 2025 at 01:18:58AM +0100, Borislav Petkov wrote:
> > Long story short, lemme try to poke around tomorrow to try to figure out what
> > actually happens. It could be caused by the part of Rik's patches and this one
> > inlining things. We'll see...
>
> Looks transient... The very similar guest boots fine on another machine. Let's
> watch this...
Oh, I didn't notice your update until now. But yeah I also couldn't
reproduce it on a Sapphire Rapids machine and on QEMU with this patch
applied on top of tip/master (37bc915c6ad0f).
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH RFC v2 01/29] mm: asi: Make some utility functions noinstr compatible
2025-01-16 13:22 ` Brendan Jackman
@ 2025-01-16 14:02 ` Borislav Petkov
0 siblings, 0 replies; 45+ messages in thread
From: Borislav Petkov @ 2025-01-16 14:02 UTC (permalink / raw)
To: Brendan Jackman
Cc: Thomas Gleixner, Ingo Molnar, Dave Hansen, H. Peter Anvin,
Andy Lutomirski, Peter Zijlstra, Richard Henderson, Matt Turner,
Vineet Gupta, Russell King, Catalin Marinas, Will Deacon, Guo Ren,
Brian Cain, Huacai Chen, WANG Xuerui, Geert Uytterhoeven,
Michal Simek, Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn,
Stefan Kristiansson, Stafford Horne, James E.J. Bottomley,
Helge Deller, Michael Ellerman, Nicholas Piggin, Christophe Leroy,
Naveen N Rao, Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta, x86, linux-kernel, linux-alpha,
linux-snps-arc, linux-arm-kernel, linux-csky, linux-hexagon,
loongarch, linux-m68k, linux-mips, linux-openrisc, linux-parisc,
linuxppc-dev, linux-riscv, linux-s390, linux-sh, sparclinux,
linux-um, linux-arch, linux-mm, linux-trace-kernel,
linux-perf-users, kvm, linux-efi
On Thu, Jan 16, 2025 at 02:22:42PM +0100, Brendan Jackman wrote:
> Sure. I'm actually not even sure that for a [PATCH]-quality thing this
> cross-cutting commit even makes sense - once we've decided on the
> general way to solve this problem, perhaps the changes should just be
> part of the commit that needs them?
Right, that sounds better.
> It feels messy to have a patch that "does multiple things", but on the
> other hand it might be annoying to review a patch that says "make a
> load of random changes across the kernel, which are needed at various
> points in various upcoming patches, trust me".
>
> Do you have any opinion on that?
You're absolutely right - we do things when we need them and not before.
Otherwise, often times things get done preemptively and then forgotten only
for someone to notice way later and undo them again.
> (BTW, since a comment you made on another series (can't find it on
> Lore...), I've changed my writing style to avoid stuff like this in
> comments & commit messages in general, but this text all predates
> that. I'll do my best to sort all that stuff out before I send
> anything as a [PATCH].)
Thanks!
Btw, good and funny way to use "[PATCH]-quality" to mean non-RFC. :-P
> Oh, I didn't notice your update until now. But yeah I also couldn't
> reproduce it on a Sapphire Rapids machine and on QEMU with this patch
> applied on top of tip/master (37bc915c6ad0f).
Yeah, it feels like toolchain-related but I can't put my finger on it yet.
We'll see if and when this thing will re-surface its ugly head...
:-)
Thx.
--
Regards/Gruss,
Boris.
https://people.kernel.org/tglx/notes-about-netiquette
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH RFC v2 02/29] x86: Create CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
2025-01-10 18:40 ` [PATCH RFC v2 02/29] x86: Create CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION Brendan Jackman
@ 2025-01-16 16:43 ` Borislav Petkov
2025-03-01 7:23 ` Mike Rapoport
1 sibling, 0 replies; 45+ messages in thread
From: Borislav Petkov @ 2025-01-16 16:43 UTC (permalink / raw)
To: Brendan Jackman
Cc: Thomas Gleixner, Ingo Molnar, Dave Hansen, H. Peter Anvin,
Andy Lutomirski, Peter Zijlstra, Richard Henderson, Matt Turner,
Vineet Gupta, Russell King, Catalin Marinas, Will Deacon, Guo Ren,
Brian Cain, Huacai Chen, WANG Xuerui, Geert Uytterhoeven,
Michal Simek, Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn,
Stefan Kristiansson, Stafford Horne, James E.J. Bottomley,
Helge Deller, Michael Ellerman, Nicholas Piggin, Christophe Leroy,
Naveen N Rao, Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta, x86, linux-kernel, linux-alpha,
linux-snps-arc, linux-arm-kernel, linux-csky, linux-hexagon,
loongarch, linux-m68k, linux-mips, linux-openrisc, linux-parisc,
linuxppc-dev, linux-riscv, linux-s390, linux-sh, sparclinux,
linux-um, linux-arch, linux-mm, linux-trace-kernel,
linux-perf-users, kvm, linux-efi, Junaid Shahid
On Fri, Jan 10, 2025 at 06:40:28PM +0000, Brendan Jackman wrote:
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index 7b9a7e8f39acc8e9aeb7d4213e87d71047865f5c..5a50582eb210e9d1309856a737d32b76fa1bfc85 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -2519,6 +2519,20 @@ config MITIGATION_PAGE_TABLE_ISOLATION
>
> See Documentation/arch/x86/pti.rst for more details.
>
> +config MITIGATION_ADDRESS_SPACE_ISOLATION
> + bool "Allow code to run with a reduced kernel address space"
> + default n
> + depends on X86_64 && !PARAVIRT && !UML
> + help
> + This feature provides the ability to run some kernel code
s/This feature provide/Provide/
> + with a reduced kernel address space. This can be used to
> + mitigate some speculative execution attacks.
> +
> + The !PARAVIRT dependency is only because of lack of testing; in theory
> + the code is written to work under paravirtualization. In practice
> + there are likely to be unhandled cases, in particular concerning TLB
> + flushes.
Right, this paragraph should be under the "---" line too until PARAVIRT gets
tested, ofc.
Thx.
--
Regards/Gruss,
Boris.
https://people.kernel.org/tglx/notes-about-netiquette
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH RFC v2 16/29] mm: asi: Map kernel text and static data as nonsensitive
2025-01-10 18:40 ` [PATCH RFC v2 16/29] mm: asi: Map kernel text and static data as nonsensitive Brendan Jackman
@ 2025-01-17 11:23 ` Brendan Jackman
0 siblings, 0 replies; 45+ messages in thread
From: Brendan Jackman @ 2025-01-17 11:23 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta
Cc: x86, linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi
On Fri, 10 Jan 2025 at 19:41, Brendan Jackman <jackmanb@google.com> wrote:
> + asi_clone_pgd(asi_global_nonsensitive_pgd, init_mm.pgd, VMEMMAP_START);
> + asi_clone_pgd(asi_global_nonsensitive_pgd, init_mm.pgd,
> + VMEMMAP_START + (1UL << PGDIR_SHIFT));
There's a bug here that Yosry has fixed in our internal version, I
neglected to incorporate that here.
Under KASLR, vmemmap is not necessarily exactly 2 PGDs like this is
assuming. In fact it can share a PGD entry with the vmalloc area. So
to be correct this cloning logic needs to actually look at the
alignment and then navigate the page table hierarchy appropriately.
To be fixed for the next version.
As Yosry noted internally we also need to think about vmmemap getting
updated under memory hotplug.
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH RFC v2 03/29] mm: asi: Introduce ASI core API
2025-01-10 18:40 ` [PATCH RFC v2 03/29] mm: asi: Introduce ASI core API Brendan Jackman
@ 2025-02-19 10:55 ` Borislav Petkov
2025-02-19 13:53 ` Brendan Jackman
0 siblings, 1 reply; 45+ messages in thread
From: Borislav Petkov @ 2025-02-19 10:55 UTC (permalink / raw)
To: Brendan Jackman
Cc: Thomas Gleixner, Ingo Molnar, Dave Hansen, H. Peter Anvin,
Andy Lutomirski, Peter Zijlstra, Richard Henderson, Matt Turner,
Vineet Gupta, Russell King, Catalin Marinas, Will Deacon, Guo Ren,
Brian Cain, Huacai Chen, WANG Xuerui, Geert Uytterhoeven,
Michal Simek, Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn,
Stefan Kristiansson, Stafford Horne, James E.J. Bottomley,
Helge Deller, Michael Ellerman, Nicholas Piggin, Christophe Leroy,
Naveen N Rao, Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta, x86, linux-kernel, linux-alpha,
linux-snps-arc, linux-arm-kernel, linux-csky, linux-hexagon,
loongarch, linux-m68k, linux-mips, linux-openrisc, linux-parisc,
linuxppc-dev, linux-riscv, linux-s390, linux-sh, sparclinux,
linux-um, linux-arch, linux-mm, linux-trace-kernel,
linux-perf-users, kvm, linux-efi, Ofir Weisse, Junaid Shahid
On Fri, Jan 10, 2025 at 06:40:29PM +0000, Brendan Jackman wrote:
> Subject: Re: [PATCH RFC v2 03/29] mm: asi: Introduce ASI core API
x86/asi: ...
> Introduce core API for Address Space Isolation (ASI). Kernel address
> space isolation provides the ability to run some kernel
> code with a restricted kernel address space.
>
> There can be multiple classes of such restricted kernel address spaces
> (e.g. KPTI, KVM-PTI etc.). Each ASI class is identified by an index.
> The ASI class can register some hooks to be called when
> entering/exiting the restricted address space.
>
> Currently, there is a fixed maximum number of ASI classes supported.
> In addition, each process can have at most one restricted address space
> from each ASI class. Neither of these are inherent limitations and
> are merely simplifying assumptions for the time being.
>
> To keep things simpler for the time being, we disallow context switches
Please use passive voice in your commit message: no "we" or "I", etc,
and describe your changes in imperative mood.
Also, see section "Changelog" in
Documentation/process/maintainer-tip.rst
> within the restricted address space. In the future, we would be able to
> relax this limitation for the case of context switches to different
> threads within the same process (or to the idle thread and back).
>
> Note that this doesn't really support protecting sibling VM guests
> within the same VMM process from one another. From first principles
> it seems unlikely that anyone who cares about VM isolation would do
> that, but there could be a use-case to think about. In that case need
> something like the OTHER_MM logic might be needed, but specific to
> intra-process guest separation.
>
> [0]:
> https://lore.kernel.org/kvm/1562855138-19507-1-git-send-email-alexandre.chartre@oracle.com
>
> Notes about RFC-quality implementation details:
>
> - Ignoring checkpatch.pl AVOID_BUG.
> - The dynamic registration of classes might be pointless complexity.
> This was kept from RFCv1 without much thought.
> - The other-mm logic is also perhaps overly complex, suggestions are
> welcome for how best to tackle this (or we could just forget about
> it for the moment, and rely on asi_exit() happening in process
> switch).
> - The taint flag definitions would probably be clearer with an enum or
> something.
>
> Checkpatch-args: --ignore=AVOID_BUG,COMMIT_LOG_LONG_LINE,EXPORT_SYMBOL
> Co-developed-by: Ofir Weisse <oweisse@google.com>
> Signed-off-by: Ofir Weisse <oweisse@google.com>
> Co-developed-by: Junaid Shahid <junaids@google.com>
> Signed-off-by: Junaid Shahid <junaids@google.com>
> Signed-off-by: Brendan Jackman <jackmanb@google.com>
> ---
> arch/x86/include/asm/asi.h | 208 +++++++++++++++++++++++
> arch/x86/include/asm/processor.h | 8 +
> arch/x86/mm/Makefile | 1 +
> arch/x86/mm/asi.c | 350 +++++++++++++++++++++++++++++++++++++++
> arch/x86/mm/init.c | 3 +-
> arch/x86/mm/tlb.c | 1 +
> include/asm-generic/asi.h | 67 ++++++++
> include/linux/mm_types.h | 7 +
> kernel/fork.c | 3 +
> kernel/sched/core.c | 9 +
> mm/init-mm.c | 4 +
> 11 files changed, 660 insertions(+), 1 deletion(-)
>
> diff --git a/arch/x86/include/asm/asi.h b/arch/x86/include/asm/asi.h
> new file mode 100644
> index 0000000000000000000000000000000000000000..7cc635b6653a3970ba9dbfdc9c828a470e27bd44
> --- /dev/null
> +++ b/arch/x86/include/asm/asi.h
> @@ -0,0 +1,208 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _ASM_X86_ASI_H
> +#define _ASM_X86_ASI_H
> +
> +#include <linux/sched.h>
> +
> +#include <asm-generic/asi.h>
> +
> +#include <asm/pgtable_types.h>
> +#include <asm/percpu.h>
> +#include <asm/processor.h>
> +
> +#ifdef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
> +
> +/*
> + * Overview of API usage by ASI clients:
> + *
> + * Setup: First call asi_init() to create a domain. At present only one domain
> + * can be created per mm per class, but it's safe to asi_init() this domain
> + * multiple times. For each asi_init() call you must call asi_destroy() AFTER
> + * you are certain all CPUs have exited the restricted address space (by
> + * calling asi_exit()).
> + *
> + * Runtime usage:
> + *
> + * 1. Call asi_enter() to switch to the restricted address space. This can't be
> + * from an interrupt or exception handler and preemption must be disabled.
> + *
> + * 2. Execute untrusted code.
> + *
> + * 3. Call asi_relax() to inform the ASI subsystem that untrusted code execution
> + * is finished. This doesn't cause any address space change. This can't be
> + * from an interrupt or exception handler and preemption must be disabled.
> + *
> + * 4. Either:
> + *
> + * a. Go back to 1.
> + *
> + * b. Call asi_exit() before returning to userspace. This immediately
> + * switches to the unrestricted address space.
So only from reading this, it does sound weird. Maybe the code does it
differently - I'll see soon - but this basically says:
I asi_enter(), do something, asi_relax() and then I decide to do something
more and to asi_enter() again!? And then I can end it all with a *single*
asi_exit() call?
Hm, definitely weird API. Why?
/*
* Leave the "tense" state if we are in it, i.e. end the critical section. We
* will stay relaxed until the next asi_enter.
*/
void asi_relax(void);
Yeah, so there's no API functions balance between enter() and relax()...
> + *
> + * The region between 1 and 3 is called the "ASI critical section". During the
> + * critical section, it is a bug to access any sensitive data, and you mustn't
> + * sleep.
> + *
> + * The restriction on sleeping is not really a fundamental property of ASI.
> + * However for performance reasons it's important that the critical section is
> + * absolutely as short as possible. So the ability to do sleepy things like
> + * taking mutexes oughtn't to confer any convenience on API users.
> + *
> + * Similarly to the issue of sleeping, the need to asi_exit in case 4b is not a
> + * fundamental property of the system but a limitation of the current
> + * implementation. With further work it is possible to context switch
> + * from and/or to the restricted address space, and to return to userspace
> + * directly from the restricted address space, or _in_ it.
> + *
> + * Note that the critical section only refers to the direct execution path from
> + * asi_enter to asi_relax: it's fine to access sensitive data from exceptions
> + * and interrupt handlers that occur during that time. ASI will re-enter the
> + * restricted address space before returning from the outermost
> + * exception/interrupt.
> + *
> + * Note: ASI does not modify KPTI behaviour; when ASI and KPTI run together
> + * there are 2+N address spaces per task: the unrestricted kernel address space,
> + * the user address space, and one restricted (kernel) address space for each of
> + * the N ASI classes.
> + */
> +
> +/*
> + * ASI uses a per-CPU tainting model to track what mitigation actions are
> + * required on domain transitions. Taints exist along two dimensions:
> + *
> + * - Who touched the CPU (guest, unprotected kernel, userspace).
> + *
> + * - What kind of state might remain: "data" means there might be data owned by
> + * a victim domain left behind in a sidechannel. "Control" means there might
> + * be state controlled by an attacker domain left behind in the branch
> + * predictor.
> + *
> + * In principle the same domain can be both attacker and victim, thus we have
> + * both data and control taints for userspace, although there's no point in
> + * trying to protect against attacks from the kernel itself, so there's no
> + * ASI_TAINT_KERNEL_CONTROL.
> + */
> +#define ASI_TAINT_KERNEL_DATA ((asi_taints_t)BIT(0))
> +#define ASI_TAINT_USER_DATA ((asi_taints_t)BIT(1))
> +#define ASI_TAINT_GUEST_DATA ((asi_taints_t)BIT(2))
> +#define ASI_TAINT_OTHER_MM_DATA ((asi_taints_t)BIT(3))
> +#define ASI_TAINT_USER_CONTROL ((asi_taints_t)BIT(4))
> +#define ASI_TAINT_GUEST_CONTROL ((asi_taints_t)BIT(5))
> +#define ASI_TAINT_OTHER_MM_CONTROL ((asi_taints_t)BIT(6))
> +#define ASI_NUM_TAINTS 6
> +static_assert(BITS_PER_BYTE * sizeof(asi_taints_t) >= ASI_NUM_TAINTS);
Why is this a typedef at all to make the code more unreadable than it needs to
be? Why not a simple unsigned int or char or whatever you need?
> +
> +#define ASI_TAINTS_CONTROL_MASK \
> + (ASI_TAINT_USER_CONTROL | ASI_TAINT_GUEST_CONTROL | ASI_TAINT_OTHER_MM_CONTROL)
> +
> +#define ASI_TAINTS_DATA_MASK \
> + (ASI_TAINT_KERNEL_DATA | ASI_TAINT_USER_DATA | ASI_TAINT_OTHER_MM_DATA)
> +
> +#define ASI_TAINTS_GUEST_MASK (ASI_TAINT_GUEST_DATA | ASI_TAINT_GUEST_CONTROL)
> +#define ASI_TAINTS_USER_MASK (ASI_TAINT_USER_DATA | ASI_TAINT_USER_CONTROL)
> +
> +/* The taint policy tells ASI how a class interacts with the CPU taints */
> +struct asi_taint_policy {
> + /*
> + * What taints would necessitate a flush when entering the domain, to
> + * protect it from attack by prior domains?
> + */
> + asi_taints_t prevent_control;
So if those necessitate a flush, why isn't this var called "taints_to_flush"
or whatever which exactly explains what it is?
> + /*
> + * What taints would necessetate a flush when entering the domain, to
+ * What taints would necessetate a flush when entering the domain, to
Unknown word [necessetate] in comment.
Suggestions: ['necessitate',
Spellchecker please. Go over your whole set.
> + * protect former domains from attack by this domain?
> + */
> + asi_taints_t protect_data;
Same.
> + /* What taints should be set when entering the domain? */
> + asi_taints_t set;
So "required_taints" or so... hm?
> +};
> +
> +/*
> + * An ASI domain (struct asi) represents a restricted address space. The
no need for "(struct asi)" - it is right below :).
> + * unrestricted address space (and user address space under PTI) are not
> + * represented as a domain.
> + */
> +struct asi {
> + pgd_t *pgd;
> + struct mm_struct *mm;
> + int64_t ref_count;
> + enum asi_class_id class_id;
> +};
> +
> +DECLARE_PER_CPU_ALIGNED(struct asi *, curr_asi);
Or simply "asi" - this per-CPU var will be so prominent so that when you do
"per_cpu(asi)" you know what exactly it is
> +
> +void asi_init_mm_state(struct mm_struct *mm);
> +
> +int asi_init_class(enum asi_class_id class_id, struct asi_taint_policy *taint_policy);
> +void asi_uninit_class(enum asi_class_id class_id);
"uninit", meh. "exit" perhaps? or "destroy"?
And you have "asi_destroy" already so I guess you can do:
asi_class_init()
asi_class_destroy()
to have the namespace correct.
> +const char *asi_class_name(enum asi_class_id class_id);
> +
> +int asi_init(struct mm_struct *mm, enum asi_class_id class_id, struct asi **out_asi);
> +void asi_destroy(struct asi *asi);
> +
> +/* Enter an ASI domain (restricted address space) and begin the critical section. */
> +void asi_enter(struct asi *asi);
> +
> +/*
> + * Leave the "tense" state if we are in it, i.e. end the critical section. We
> + * will stay relaxed until the next asi_enter.
> + */
> +void asi_relax(void);
> +
> +/* Immediately exit the restricted address space if in it */
> +void asi_exit(void);
> +
> +/* The target is the domain we'll enter when returning to process context. */
> +static __always_inline struct asi *asi_get_target(struct task_struct *p)
> +{
> + return p->thread.asi_state.target;
> +}
> +
> +static __always_inline void asi_set_target(struct task_struct *p,
> + struct asi *target)
> +{
> + p->thread.asi_state.target = target;
> +}
> +
> +static __always_inline struct asi *asi_get_current(void)
> +{
> + return this_cpu_read(curr_asi);
> +}
> +
> +/* Are we currently in a restricted address space? */
> +static __always_inline bool asi_is_restricted(void)
> +{
> + return (bool)asi_get_current();
> +}
> +
> +/* If we exit/have exited, can we stay that way until the next asi_enter? */
> +static __always_inline bool asi_is_relaxed(void)
> +{
> + return !asi_get_target(current);
> +}
> +
> +/*
> + * Is the current task in the critical section?
> + *
> + * This is just the inverse of !asi_is_relaxed(). We have both functions in order to
> + * help write intuitive client code. In particular, asi_is_tense returns false
> + * when ASI is disabled, which is judged to make user code more obvious.
> + */
> +static __always_inline bool asi_is_tense(void)
> +{
> + return !asi_is_relaxed();
> +}
So can we tone down the silly helpers above? You don't really need
asi_is_tense() for example. It is still very intuitive if I read
if (!asi_is_relaxed())
...
> +
> +static __always_inline pgd_t *asi_pgd(struct asi *asi)
> +{
> + return asi ? asi->pgd : NULL;
> +}
> +
> +#define INIT_MM_ASI(init_mm) \
> + .asi_init_lock = __MUTEX_INITIALIZER(init_mm.asi_init_lock),
> +
> +void asi_handle_switch_mm(void);
> +
> +#endif /* CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION */
> +
> +#endif
Splitting the patch here and will continue with the next one as this one is
kinda big for one mail.
--
Regards/Gruss,
Boris.
https://people.kernel.org/tglx/notes-about-netiquette
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH RFC v2 03/29] mm: asi: Introduce ASI core API
2025-02-19 10:55 ` Borislav Petkov
@ 2025-02-19 13:53 ` Brendan Jackman
2025-02-27 12:06 ` Borislav Petkov
0 siblings, 1 reply; 45+ messages in thread
From: Brendan Jackman @ 2025-02-19 13:53 UTC (permalink / raw)
To: Borislav Petkov
Cc: Thomas Gleixner, Ingo Molnar, Dave Hansen, H. Peter Anvin,
Andy Lutomirski, Peter Zijlstra, Richard Henderson, Matt Turner,
Vineet Gupta, Russell King, Catalin Marinas, Will Deacon, Guo Ren,
Brian Cain, Huacai Chen, WANG Xuerui, Geert Uytterhoeven,
Michal Simek, Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn,
Stefan Kristiansson, Stafford Horne, James E.J. Bottomley,
Helge Deller, Michael Ellerman, Nicholas Piggin, Christophe Leroy,
Naveen N Rao, Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta, x86, linux-kernel, linux-alpha,
linux-snps-arc, linux-arm-kernel, linux-csky, linux-hexagon,
loongarch, linux-m68k, linux-mips, linux-openrisc, linux-parisc,
linuxppc-dev, linux-riscv, linux-s390, linux-sh, sparclinux,
linux-um, linux-arch, linux-mm, linux-trace-kernel,
linux-perf-users, kvm, linux-efi, Ofir Weisse, Junaid Shahid
Argh, sorry, GMail switched back to HTML mode somehow. Maybe I have to
get a proper mail client after all.
Here's the clean version.
On Wed, 19 Feb 2025 at 11:57, Borislav Petkov <bp@alien8.de> wrote:
>
> > + * Runtime usage:
> > + *
> > + * 1. Call asi_enter() to switch to the restricted address space. This can't be
> > + * from an interrupt or exception handler and preemption must be disabled.
> > + *
> > + * 2. Execute untrusted code.
> > + *
> > + * 3. Call asi_relax() to inform the ASI subsystem that untrusted code execution
> > + * is finished. This doesn't cause any address space change. This can't be
> > + * from an interrupt or exception handler and preemption must be disabled.
> > + *
> > + * 4. Either:
> > + *
> > + * a. Go back to 1.
> > + *
> > + * b. Call asi_exit() before returning to userspace. This immediately
> > + * switches to the unrestricted address space.
>
> So only from reading this, it does sound weird. Maybe the code does it
> differently - I'll see soon - but this basically says:
>
> I asi_enter(), do something, asi_relax() and then I decide to do something
> more and to asi_enter() again!? And then I can end it all with a *single*
> asi_exit() call?
>
> Hm, definitely weird API. Why?
OK, sounds like I need to rewrite this explanation! It's only been
read before by people who already knew how this thing worked so this
might take a few attempts to make it clear.
Maybe the best way to make it clear is to explain this with reference
to KVM. At a super high level, That looks like:
ioctl(KVM_RUN) {
enter_from_user_mode()
while !need_userspace_handling() {
asi_enter(); // part 1
vmenter(); // part 2
asi_relax(); // part 3
}
asi _exit(); // part 4b
exit_to_user_mode()
}
So part 4a is just referring to continuation of the loop.
This explanation was written when that was the only user of this API
so it was probably clearer, now we have userspace it seems a bit odd.
With my pseudocode above, does it make more sense? If so I'll try to
think of a better way to explain it.
> /*
> * Leave the "tense" state if we are in it, i.e. end the critical section. We
> * will stay relaxed until the next asi_enter.
> */
> void asi_relax(void);
>
> Yeah, so there's no API functions balance between enter() and relax()...
asi_enter() is actually balanced with asi_relax(). The comment says
"if we are in it" because technically if you call this asi_relax()
outside of the critical section, it's a nop. But, there's no reason to
do that, so we could definitely change the comment and WARN if that
happens.
>
> > +#define ASI_TAINT_OTHER_MM_CONTROL ((asi_taints_t)BIT(6))
> > +#define ASI_NUM_TAINTS 6
> > +static_assert(BITS_PER_BYTE * sizeof(asi_taints_t) >= ASI_NUM_TAINTS);
>
> Why is this a typedef at all to make the code more unreadable than it needs to
> be? Why not a simple unsigned int or char or whatever you need?
My thinking was just that it's nicer to see asi_taints_t and know that
it means "it holds taint flags and it's big enough" instead of having
to remember the space needed for these flags. But yeah I'm fine with
making it a raw integer type.
> > +#define ASI_TAINTS_CONTROL_MASK \
> > + (ASI_TAINT_USER_CONTROL | ASI_TAINT_GUEST_CONTROL | ASI_TAINT_OTHER_MM_CONTROL)
> > +
> > +#define ASI_TAINTS_DATA_MASK \
> > + (ASI_TAINT_KERNEL_DATA | ASI_TAINT_USER_DATA | ASI_TAINT_OTHER_MM_DATA)
> > +
> > +#define ASI_TAINTS_GUEST_MASK (ASI_TAINT_GUEST_DATA | ASI_TAINT_GUEST_CONTROL)
> > +#define ASI_TAINTS_USER_MASK (ASI_TAINT_USER_DATA | ASI_TAINT_USER_CONTROL)
> > +
> > +/* The taint policy tells ASI how a class interacts with the CPU taints */
> > +struct asi_taint_policy {
> > + /*
> > + * What taints would necessitate a flush when entering the domain, to
> > + * protect it from attack by prior domains?
> > + */
> > + asi_taints_t prevent_control;
>
> So if those necessitate a flush, why isn't this var called "taints_to_flush"
> or whatever which exactly explains what it is?
Well it needs to be disambiguated from the field below (currently
protect_data) but it could be control_to_flush (and data_to_flush).
The downside of that is that having one say "prevent" and one say
"protect" is quite meaningful. prevent_control is describing things we
need to do to protect the system from this domain, protect_data is
about protecting the domain from the system. However, while that
difference is meaningful it might not actually be helpful for the
reader of the code so I'm not wed to it.
Also worth noting that we could just combine these fields. At present
they should have disjoint bits set. But, they're used in separate
contexts and have separate (although conceptually very similar)
meanings, so I think that would reduce clarity.
>
> Spellchecker please. Go over your whole set.
Ack, I've set up a local thingy to spellcheck all my commits so
hopefully you should encounter less of that noise in future.
For the pronouns stuff I will do my best but you might still spot
violations in older text, sorry about that.
> > + /* What taints should be set when entering the domain? */
> > + asi_taints_t set;
>
>
> So "required_taints" or so... hm?
What this field is describing is: when we run the untrusted code, what
happens? I don't mean "what does the kernel do" but what physically
happens on the CPU from an exploit point of view.
For example setting ASI_TAINT_USER_DATA in this field means "when we
run the untrusted code (i.e. userspace), userspace data gets left
behind in sidechannels".
"Should be set" in the comment means "this field should be set to
record that a thing has happened" not "this field being set is a
requirement for some API" or something. So I don't think "required" is
right but this is hard to name.
That commentary should also be expanded I think, since "should be set"
is pretty ambiguous. And maybe if we called it "to_set" it would be
more obvious that "set" is a verb? I'm very open to suggestions.
>
> > +
> > +void asi_init_mm_state(struct mm_struct *mm);
> > +
> > +int asi_init_class(enum asi_class_id class_id, struct asi_taint_policy *taint_policy);
> > +void asi_uninit_class(enum asi_class_id class_id);
>
> "uninit", meh. "exit" perhaps? or "destroy"
>
> And you have "asi_destroy" already so I guess you can do:
>
> asi_class_init()
> asi_class_destroy()
>
> to have the namespace correct.
Yeah, not sure what I was thinking here!
>
> > +static __always_inline bool asi_is_tense(void)
> > +{
> > + return !asi_is_relaxed();
> > +}
>
> So can we tone down the silly helpers above? You don't really need
> asi_is_tense() for example. It is still very intuitive if I read
>
> if (!asi_is_relaxed())
>
Yep that sounds good.
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH RFC v2 03/29] mm: asi: Introduce ASI core API
2025-02-19 13:53 ` Brendan Jackman
@ 2025-02-27 12:06 ` Borislav Petkov
0 siblings, 0 replies; 45+ messages in thread
From: Borislav Petkov @ 2025-02-27 12:06 UTC (permalink / raw)
To: Brendan Jackman
Cc: Thomas Gleixner, Ingo Molnar, Dave Hansen, H. Peter Anvin,
Andy Lutomirski, Peter Zijlstra, Richard Henderson, Matt Turner,
Vineet Gupta, Russell King, Catalin Marinas, Will Deacon, Guo Ren,
Brian Cain, Huacai Chen, WANG Xuerui, Geert Uytterhoeven,
Michal Simek, Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn,
Stefan Kristiansson, Stafford Horne, James E.J. Bottomley,
Helge Deller, Michael Ellerman, Nicholas Piggin, Christophe Leroy,
Naveen N Rao, Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta, x86, linux-kernel, linux-alpha,
linux-snps-arc, linux-arm-kernel, linux-csky, linux-hexagon,
loongarch, linux-m68k, linux-mips, linux-openrisc, linux-parisc,
linuxppc-dev, linux-riscv, linux-s390, linux-sh, sparclinux,
linux-um, linux-arch, linux-mm, linux-trace-kernel,
linux-perf-users, kvm, linux-efi, Ofir Weisse, Junaid Shahid
On Wed, Feb 19, 2025 at 02:53:03PM +0100, Brendan Jackman wrote:
> Argh, sorry, GMail switched back to HTML mode somehow. Maybe I have to
> get a proper mail client after all.
Yap, wouldn't be such a bad idea. And yes, it ain't easy - we have a whole doc
about it:
Documentation/process/email-clients.rst
> OK, sounds like I need to rewrite this explanation! It's only been
> read before by people who already knew how this thing worked so this
> might take a few attempts to make it clear.
>
> Maybe the best way to make it clear is to explain this with reference
> to KVM. At a super high level, That looks like:
>
> ioctl(KVM_RUN) {
> enter_from_user_mode()
> while !need_userspace_handling() {
> asi_enter(); // part 1
> vmenter(); // part 2
> asi_relax(); // part 3
> }
> asi _exit(); // part 4b
> exit_to_user_mode()
> }
>
> So part 4a is just referring to continuation of the loop.
>
> This explanation was written when that was the only user of this API
> so it was probably clearer, now we have userspace it seems a bit odd.
>
> With my pseudocode above, does it make more sense? If so I'll try to
> think of a better way to explain it.
Well, it is still confusing. I would expect to see:
ioctl(KVM_RUN) {
enter_from_user_mode()
while !need_userspace_handling() {
asi_enter(); // part 1
vmenter(); // part 2
asi_exit(); // part 3
}
asi_switch(); // part 4b
exit_to_user_mode()
}
Because then it is ballanced: you enter the restricted address space, do stuff
and then you exit it without switching address space. But then you need to
switch address space so you have to do asi_exit or asi_switch or wnatnot. And
that's still unbalanced.
So from *only* looking at the usage, it'd be a lot more balanced if all calls
were paired:
ioctl(KVM_RUN) {
enter_from_user_mode()
asi_switch_to(); <-------+
while !need_userspace_handling() { |
asi_enter(); // part 1 <---+ |
vmenter(); // part 2 | |
asi_exit(); // part 3 <---+ |
} |
asi_switch_back(); // part 4b <-------+
exit_to_user_mode()
}
(look at me doing ascii paintint :-P)
Naming is awful but it should illustrate what I mean:
asi_switch_to
asi_enter
asi_exit
asi_switch_back
Does that make more sense?
> asi_enter() is actually balanced with asi_relax(). The comment says
> "if we are in it" because technically if you call this asi_relax()
> outside of the critical section, it's a nop. But, there's no reason to
> do that, so we could definitely change the comment and WARN if that
> happens.
See above.
>
> >
> > > +#define ASI_TAINT_OTHER_MM_CONTROL ((asi_taints_t)BIT(6))
> > > +#define ASI_NUM_TAINTS 6
> > > +static_assert(BITS_PER_BYTE * sizeof(asi_taints_t) >= ASI_NUM_TAINTS);
> >
> > Why is this a typedef at all to make the code more unreadable than it needs to
> > be? Why not a simple unsigned int or char or whatever you need?
>
>
> My thinking was just that it's nicer to see asi_taints_t and know that
> it means "it holds taint flags and it's big enough" instead of having
> to remember the space needed for these flags. But yeah I'm fine with
> making it a raw integer type.
You're thinking of some of those rules here perhaps?
https://kernel.org/doc/html/latest/process/coding-style.html#typedefs
Probably but then you're using casts (asi_taints_t) to put in integers in it.
Does it matter then?
Might as well use a plain int and avoid the casts, no? Unless there's a real
good reason to have a special type and it is really really good this way...?
> Well it needs to be disambiguated from the field below (currently
> protect_data) but it could be control_to_flush (and data_to_flush).
>
> The downside of that is that having one say "prevent" and one say
> "protect" is quite meaningful. prevent_control is describing things we
> need to do to protect the system from this domain, protect_data is
> about protecting the domain from the system. However, while that
> difference is meaningful it might not actually be helpful for the
> reader of the code so I'm not wed to it.
>
> Also worth noting that we could just combine these fields. At present
> they should have disjoint bits set. But, they're used in separate
> contexts and have separate (although conceptually very similar)
> meanings, so I think that would reduce clarity.
Ok, I guess it'll tell us what is better once we stare at that code more. :)
> Ack, I've set up a local thingy to spellcheck all my commits so
> hopefully you should encounter less of that noise in future.
Yeah, I use the default vim spellchecker and it simply works.
> For the pronouns stuff I will do my best but you might still spot
> violations in older text, sorry about that.
No worries.
> What this field is describing is: when we run the untrusted code, what
> happens? I don't mean "what does the kernel do" but what physically
> happens on the CPU from an exploit point of view.
>
> For example setting ASI_TAINT_USER_DATA in this field means "when we
> run the untrusted code (i.e. userspace), userspace data gets left
> behind in sidechannels".
>
> "Should be set" in the comment means "this field should be set to
> record that a thing has happened" not "this field being set is a
> requirement for some API" or something. So I don't think "required" is
> right but this is hard to name.
>
> That commentary should also be expanded I think, since "should be set"
> is pretty ambiguous. And maybe if we called it "to_set" it would be
> more obvious that "set" is a verb? I'm very open to suggestions.
I think the explanations you give here should be condensed into comments over
those things. They're really helpful.
Thx.
--
Regards/Gruss,
Boris.
https://people.kernel.org/tglx/notes-about-netiquette
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH RFC v2 25/29] mm: asi: Restricted execution fore bare-metal processes
2025-01-10 18:40 ` [PATCH RFC v2 25/29] mm: asi: Restricted execution fore bare-metal processes Brendan Jackman
@ 2025-02-28 15:32 ` Yosry Ahmed
0 siblings, 0 replies; 45+ messages in thread
From: Yosry Ahmed @ 2025-02-28 15:32 UTC (permalink / raw)
To: Brendan Jackman
Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra, Andrew Morton,
Josh Poimboeuf, Pawan Gupta, x86, linux-kernel, linux-alpha,
linux-snps-arc, linux-arm-kernel, linux-csky, linux-hexagon,
loongarch, linux-m68k, linux-mips, linux-openrisc, linux-parisc,
linuxppc-dev, linux-riscv, linux-s390, linux-sh, sparclinux,
linux-um, linux-arch, linux-mm, linux-trace-kernel,
linux-perf-users, kvm, linux-efi
(Trimming the CC list as my email server refuses the number of CCs)
On Fri, Jan 10, 2025 at 06:40:51PM +0000, Brendan Jackman wrote:
> Now userspace gets a restricted address space too. The critical section
> begins on exit to userspace and ends when it makes a system call.
> Other entries from userspace just interrupt the critical section via
> asi_intr_enter().
>
> The reason why system calls have to actually asi_relax() (i.e. fully
> terminate the critical section instead of just interrupting it) is that
> system calls are the type of kernel entry that can lead to transition
> into a _different_ ASI domain, namely the KVM one: it is not supported
> to transition into a different domain while a critical section exists
> (i.e. while asi_state.target is not NULL), even if it has been paused by
> asi_intr_enter() (i.e. even if asi_state.intr_nest_depth is nonzero) -
> there must be an asi_relax() between any two asi_enter()s.
>
> The restricted address space for bare-metal tasks naturally contains the
> entire userspace address region, although the task's own memory is still
> missing from the direct map.
>
> This implementation creates new userspace-specific APIs for asi_init(),
> asi_destroy() and asi_enter(), which seems a little ugly, maybe this
> suggest a general rework of these APIs given that the "generic" version
> only has one caller. For RFC code this seems good enough though.
>
> Signed-off-by: Brendan Jackman <jackmanb@google.com>
> ---
> arch/x86/include/asm/asi.h | 8 ++++++--
> arch/x86/mm/asi.c | 49 ++++++++++++++++++++++++++++++++++++++++----
> include/asm-generic/asi.h | 9 +++++++-
> include/linux/entry-common.h | 11 ++++++++++
> init/main.c | 2 ++
> kernel/entry/common.c | 1 +
> kernel/fork.c | 4 +++-
> 7 files changed, 76 insertions(+), 8 deletions(-)
>
> diff --git a/arch/x86/include/asm/asi.h b/arch/x86/include/asm/asi.h
> index e925d7d2cfc85bca8480c837548654e7a5a7009e..c3c1a57f0147ae9bd11d89c8bf7c8a4477728f51 100644
> --- a/arch/x86/include/asm/asi.h
> +++ b/arch/x86/include/asm/asi.h
> @@ -140,19 +140,23 @@ DECLARE_PER_CPU_ALIGNED(struct asi *, curr_asi);
>
> void asi_check_boottime_disable(void);
>
> -void asi_init_mm_state(struct mm_struct *mm);
> +int asi_init_mm_state(struct mm_struct *mm);
>
> int asi_init_class(enum asi_class_id class_id, struct asi_taint_policy *taint_policy);
> +void asi_init_userspace_class(void);
> void asi_uninit_class(enum asi_class_id class_id);
> const char *asi_class_name(enum asi_class_id class_id);
>
> int asi_init(struct mm_struct *mm, enum asi_class_id class_id, struct asi **out_asi);
> void asi_destroy(struct asi *asi);
> +void asi_destroy_userspace(struct mm_struct *mm);
> void asi_clone_user_pgtbl(struct mm_struct *mm, pgd_t *pgdp);
>
> /* Enter an ASI domain (restricted address space) and begin the critical section. */
> void asi_enter(struct asi *asi);
>
> +void asi_enter_userspace(void);
> +
> /*
> * Leave the "tense" state if we are in it, i.e. end the critical section. We
> * will stay relaxed until the next asi_enter.
> @@ -294,7 +298,7 @@ void asi_handle_switch_mm(void);
> */
> static inline bool asi_maps_user_addr(enum asi_class_id class_id)
> {
> - return false;
> + return class_id == ASI_CLASS_USERSPACE;
> }
>
> #endif /* CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION */
> diff --git a/arch/x86/mm/asi.c b/arch/x86/mm/asi.c
> index 093103c1bc2677c81d68008aca064fab53b73a62..1e9dc568e79e8686a4dbf47f765f2c2535d025ec 100644
> --- a/arch/x86/mm/asi.c
> +++ b/arch/x86/mm/asi.c
> @@ -25,6 +25,7 @@ const char *asi_class_names[] = {
> #if IS_ENABLED(CONFIG_KVM)
> [ASI_CLASS_KVM] = "KVM",
> #endif
> + [ASI_CLASS_USERSPACE] = "userspace",
> };
>
> DEFINE_PER_CPU_ALIGNED(struct asi *, curr_asi);
> @@ -67,6 +68,32 @@ int asi_init_class(enum asi_class_id class_id, struct asi_taint_policy *taint_po
> }
> EXPORT_SYMBOL_GPL(asi_init_class);
>
> +void __init asi_init_userspace_class(void)
> +{
> + static struct asi_taint_policy policy = {
> + /*
> + * Prevent going to userspace with sensitive data potentially
> + * left in sidechannels by code running in the unrestricted
> + * address space, or another MM. Note we don't check for guest
> + * data here. This reflects the assumption that the guest trusts
> + * its VMM (absent fancy HW features, which are orthogonal).
> + */
> + .protect_data = ASI_TAINT_KERNEL_DATA | ASI_TAINT_OTHER_MM_DATA,
> + /*
> + * Don't go into userspace with control flow state controlled by
> + * other processes, or any KVM guest the process is running.
> + * Note this bit is about protecting userspace from other parts
> + * of the system, while data_taints is about protecting other
> + * parts of the system from the guest.
> + */
> + .prevent_control = ASI_TAINT_GUEST_CONTROL | ASI_TAINT_OTHER_MM_CONTROL,
> + .set = ASI_TAINT_USER_CONTROL | ASI_TAINT_USER_DATA,
> + };
> + int err = asi_init_class(ASI_CLASS_USERSPACE, &policy);
> +
> + WARN_ON(err);
> +}
> +
> void asi_uninit_class(enum asi_class_id class_id)
> {
> if (!boot_cpu_has(X86_FEATURE_ASI))
> @@ -385,7 +412,8 @@ int asi_init(struct mm_struct *mm, enum asi_class_id class_id, struct asi **out_
> int err = 0;
> uint i;
>
> - *out_asi = NULL;
> + if (out_asi)
> + *out_asi = NULL;
>
> if (!boot_cpu_has(X86_FEATURE_ASI))
> return 0;
> @@ -424,7 +452,7 @@ int asi_init(struct mm_struct *mm, enum asi_class_id class_id, struct asi **out_
> exit_unlock:
> if (err)
> __asi_destroy(asi);
> - else
> + else if (out_asi)
> *out_asi = asi;
>
> __asi_init_user_pgds(mm, asi);
> @@ -515,6 +543,12 @@ static __always_inline void maybe_flush_data(struct asi *next_asi)
> this_cpu_and(asi_taints, ~ASI_TAINTS_DATA_MASK);
> }
>
> +void asi_destroy_userspace(struct mm_struct *mm)
> +{
> + VM_BUG_ON(!asi_class_initialized(ASI_CLASS_USERSPACE));
> + asi_destroy(&mm->asi[ASI_CLASS_USERSPACE]);
> +}
> +
> noinstr void __asi_enter(void)
> {
> u64 asi_cr3;
> @@ -584,6 +618,11 @@ noinstr void asi_enter(struct asi *asi)
> }
> EXPORT_SYMBOL_GPL(asi_enter);
>
> +noinstr void asi_enter_userspace(void)
> +{
> + asi_enter(¤t->mm->asi[ASI_CLASS_USERSPACE]);
> +}
> +
> noinstr void asi_relax(void)
> {
> if (static_asi_enabled()) {
> @@ -633,13 +672,15 @@ noinstr void asi_exit(void)
> }
> EXPORT_SYMBOL_GPL(asi_exit);
>
> -void asi_init_mm_state(struct mm_struct *mm)
> +int asi_init_mm_state(struct mm_struct *mm)
> {
> if (!boot_cpu_has(X86_FEATURE_ASI))
> - return;
> + return 0;
>
> memset(mm->asi, 0, sizeof(mm->asi));
> mutex_init(&mm->asi_init_lock);
> +
> + return asi_init(mm, ASI_CLASS_USERSPACE, NULL);
I think this call here is problematic. This can be called from
asi_global_init().
An example is:
start_kernel()
poking_init()
mm_alloc()
mm_init()
asi_init_mm_state()
But the same also happen through dup_mm(), for example:
kernel_thread()
kernel_clone()
copy_process()
copy_mm()
dup_mm()
asi_global_init() is called later from do_initcalls() (run in a kthread
by kernel_init()). In this case, asi_init() copies the kernel PGDs from
asi_global_nonsensitive_pgd, but those PGDs won't be initialized yet.
It could be fine for the current code because all these threads created
during init never enter userspace, but I am not sure if that's always
true. It also makes me a bit nervous to have partially initialized ASI
domains hanging around.
I'd rather we either:
- Move asi_global_init() earlier, but we have to be careful not to move
it too early before some of the mappings it clones are created (or
before we can make allocations). In this case, we should also add a
warning in asi_init() in case the code changes and it is ever called
before asi_global_init().
- Explicitly avoid calling asi_init_mm_state() or asi_init() in these
cases. This may be easy-ish in the case of kthreads, but for things
like poking_init() we would need to plump more context through.
Alternatively we can just make asi_init() a noop if asi_global_init()
isn't called yet, but the silent failure makes me a bit worried too.
> }
>
> void asi_handle_switch_mm(void)
> diff --git a/include/asm-generic/asi.h b/include/asm-generic/asi.h
> index d103343292fad567dcd73e45e986fb3974e59898..c93f9e779ce1fa61e3df7835f5ab744cce7d667b 100644
> --- a/include/asm-generic/asi.h
> +++ b/include/asm-generic/asi.h
> @@ -15,6 +15,7 @@ enum asi_class_id {
> #if IS_ENABLED(CONFIG_KVM)
> ASI_CLASS_KVM,
> #endif
> + ASI_CLASS_USERSPACE,
> ASI_MAX_NUM_CLASSES,
> };
> static_assert(order_base_2(X86_CR3_ASI_PCID_BITS) <= ASI_MAX_NUM_CLASSES);
> @@ -37,8 +38,10 @@ int asi_init_class(enum asi_class_id class_id,
>
> static inline void asi_uninit_class(enum asi_class_id class_id) { }
>
> +static inline void asi_init_userspace_class(void) { }
> +
> struct mm_struct;
> -static inline void asi_init_mm_state(struct mm_struct *mm) { }
> +static inline int asi_init_mm_state(struct mm_struct *mm) { return 0; }
>
> static inline int asi_init(struct mm_struct *mm, enum asi_class_id class_id,
> struct asi **out_asi)
> @@ -48,8 +51,12 @@ static inline int asi_init(struct mm_struct *mm, enum asi_class_id class_id,
>
> static inline void asi_destroy(struct asi *asi) { }
>
> +static inline void asi_destroy_userspace(struct mm_struct *mm) { }
> +
> static inline void asi_enter(struct asi *asi) { }
>
> +static inline void asi_enter_userspace(void) { }
> +
> static inline void asi_relax(void) { }
>
> static inline bool asi_is_relaxed(void) { return true; }
> diff --git a/include/linux/entry-common.h b/include/linux/entry-common.h
> index 1e50cdb83ae501467ecc30ee52f1379d409f962e..f04c4c038556f84ddf3bc09b6c1dd22a9dbd2f6b 100644
> --- a/include/linux/entry-common.h
> +++ b/include/linux/entry-common.h
> @@ -191,6 +191,16 @@ static __always_inline long syscall_enter_from_user_mode(struct pt_regs *regs, l
> {
> long ret;
>
> + /*
> + * End the ASI critical section for userspace. Syscalls are the only
> + * place this happens - all other entry from userspace is handled via
> + * ASI's interrupt-tracking. The reason syscalls are special is that's
> + * where it's possible to switch to another ASI domain within the same
> + * task (i.e. KVM_RUN), an asi_relax() is required here in case of an
> + * upcoming asi_enter().
> + */
> + asi_relax();
> +
> enter_from_user_mode(regs);
>
> instrumentation_begin();
> @@ -355,6 +365,7 @@ static __always_inline void exit_to_user_mode_prepare(struct pt_regs *regs)
> */
> static __always_inline void exit_to_user_mode(void)
> {
> +
> instrumentation_begin();
> trace_hardirqs_on_prepare();
> lockdep_hardirqs_on_prepare();
> diff --git a/init/main.c b/init/main.c
> index c4778edae7972f512d5eefe8400075ac35a70d1c..d19e149d385e8321d2f3e7c28aa75802af62d09c 100644
> --- a/init/main.c
> +++ b/init/main.c
> @@ -953,6 +953,8 @@ void start_kernel(void)
> /* Architectural and non-timekeeping rng init, before allocator init */
> random_init_early(command_line);
>
> + asi_init_userspace_class();
> +
> /*
> * These use large bootmem allocations and must precede
> * initalization of page allocator
> diff --git a/kernel/entry/common.c b/kernel/entry/common.c
> index 5b6934e23c21d36a3238dc03e391eb9e3beb4cfb..874254ed5958d62eaeaef4fe3e8c02e56deaf5ed 100644
> --- a/kernel/entry/common.c
> +++ b/kernel/entry/common.c
> @@ -218,6 +218,7 @@ __visible noinstr void syscall_exit_to_user_mode(struct pt_regs *regs)
> __syscall_exit_to_user_mode_work(regs);
> instrumentation_end();
> exit_to_user_mode();
> + asi_enter_userspace();
> }
>
> noinstr void irqentry_enter_from_user_mode(struct pt_regs *regs)
> diff --git a/kernel/fork.c b/kernel/fork.c
> index bb73758790d08112265d398b16902ff9a4c2b8fe..54068d2415939b92409ca8a45111176783c6acbd 100644
> --- a/kernel/fork.c
> +++ b/kernel/fork.c
> @@ -917,6 +917,7 @@ void __mmdrop(struct mm_struct *mm)
> /* Ensure no CPUs are using this as their lazy tlb mm */
> cleanup_lazy_tlbs(mm);
>
> + asi_destroy_userspace(mm);
> WARN_ON_ONCE(mm == current->active_mm);
> mm_free_pgd(mm);
> destroy_context(mm);
> @@ -1297,7 +1298,8 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p,
> if (mm_alloc_pgd(mm))
> goto fail_nopgd;
>
> - asi_init_mm_state(mm);
> + if (asi_init_mm_state(mm))
> + goto fail_nocontext;
>
> if (init_new_context(p, mm))
> goto fail_nocontext;
>
> --
> 2.47.1.613.gc27f4b7a9f-goog
>
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH RFC v2 02/29] x86: Create CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
2025-01-10 18:40 ` [PATCH RFC v2 02/29] x86: Create CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION Brendan Jackman
2025-01-16 16:43 ` Borislav Petkov
@ 2025-03-01 7:23 ` Mike Rapoport
2025-03-05 13:12 ` Brendan Jackman
1 sibling, 1 reply; 45+ messages in thread
From: Mike Rapoport @ 2025-03-01 7:23 UTC (permalink / raw)
To: Brendan Jackman
Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Arnaldo Carvalho de Melo, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
Dennis Zhou, Tejun Heo, Christoph Lameter, Sean Christopherson,
Paolo Bonzini, Ard Biesheuvel, Josh Poimboeuf, Pawan Gupta, x86,
linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Junaid Shahid
Hi Brendan,
On Fri, Jan 10, 2025 at 06:40:28PM +0000, Brendan Jackman wrote:
> Currently a nop config. Keeping as a separate commit for easy review of
> the boring bits. Later commits will use and enable this new config.
>
> This config is only added for non-UML x86_64 as other architectures do
> not yet have pending implementations. It also has somewhat artificial
> dependencies on !PARAVIRT and !KASAN which are explained in the Kconfig
> file.
>
> Co-developed-by: Junaid Shahid <junaids@google.com>
> Signed-off-by: Junaid Shahid <junaids@google.com>
> Signed-off-by: Brendan Jackman <jackmanb@google.com>
> ---
> arch/alpha/include/asm/Kbuild | 1 +
> arch/arc/include/asm/Kbuild | 1 +
> arch/arm/include/asm/Kbuild | 1 +
> arch/arm64/include/asm/Kbuild | 1 +
> arch/csky/include/asm/Kbuild | 1 +
> arch/hexagon/include/asm/Kbuild | 1 +
> arch/loongarch/include/asm/Kbuild | 3 +++
> arch/m68k/include/asm/Kbuild | 1 +
> arch/microblaze/include/asm/Kbuild | 1 +
> arch/mips/include/asm/Kbuild | 1 +
> arch/nios2/include/asm/Kbuild | 1 +
> arch/openrisc/include/asm/Kbuild | 1 +
> arch/parisc/include/asm/Kbuild | 1 +
> arch/powerpc/include/asm/Kbuild | 1 +
> arch/riscv/include/asm/Kbuild | 1 +
> arch/s390/include/asm/Kbuild | 1 +
> arch/sh/include/asm/Kbuild | 1 +
> arch/sparc/include/asm/Kbuild | 1 +
> arch/um/include/asm/Kbuild | 2 +-
> arch/x86/Kconfig | 14 ++++++++++++++
> arch/xtensa/include/asm/Kbuild | 1 +
> include/asm-generic/asi.h | 5 +++++
> 22 files changed, 41 insertions(+), 1 deletion(-)
I don't think this all is needed. You can put asi.h with stubs used outside
of arch/x86 in include/linux and save you the hassle of updating every
architecture.
> diff --git a/arch/sparc/include/asm/Kbuild b/arch/sparc/include/asm/Kbuild
> index 43b0ae4c2c2112d4d4d3cb3c60e787b175172dea..cb9062c9be17fe276cc92d2ac99d8b165f6297bf 100644
> --- a/arch/sparc/include/asm/Kbuild
> +++ b/arch/sparc/include/asm/Kbuild
> @@ -4,3 +4,4 @@ generated-y += syscall_table_64.h
> generic-y += agp.h
> generic-y += kvm_para.h
> generic-y += mcs_spinlock.h
> +generic-y += asi.h
sparc already has include/asm/asi.h, this will break the build
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index 7b9a7e8f39acc8e9aeb7d4213e87d71047865f5c..5a50582eb210e9d1309856a737d32b76fa1bfc85 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -2519,6 +2519,20 @@ config MITIGATION_PAGE_TABLE_ISOLATION
>
> See Documentation/arch/x86/pti.rst for more details.
>
> +config MITIGATION_ADDRESS_SPACE_ISOLATION
> + bool "Allow code to run with a reduced kernel address space"
> + default n
> + depends on X86_64 && !PARAVIRT && !UML
> + help
> + This feature provides the ability to run some kernel code
> + with a reduced kernel address space. This can be used to
> + mitigate some speculative execution attacks.
> +
> + The !PARAVIRT dependency is only because of lack of testing; in theory
> + the code is written to work under paravirtualization. In practice
> + there are likely to be unhandled cases, in particular concerning TLB
> + flushes.
> +
If you expect other architectures might implement ASI the config would better
fit into init/Kconfig or mm/Kconfig and in arch/x86/Kconfig will define
ARCH_HAS_MITIGATION_ADDRESS_SPACE_ISOLATION.
> config MITIGATION_RETPOLINE
> bool "Avoid speculative indirect branches in kernel"
> select OBJTOOL if HAVE_OBJTOOL
> diff --git a/arch/xtensa/include/asm/Kbuild b/arch/xtensa/include/asm/Kbuild
> index fa07c686cbcc2153776a478ac4093846f01eddab..07cea6902f98053be244d026ed594fe7246755a6 100644
> --- a/arch/xtensa/include/asm/Kbuild
> +++ b/arch/xtensa/include/asm/Kbuild
> @@ -8,3 +8,4 @@ generic-y += parport.h
> generic-y += qrwlock.h
> generic-y += qspinlock.h
> generic-y += user.h
> +generic-y += asi.h
> diff --git a/include/asm-generic/asi.h b/include/asm-generic/asi.h
> new file mode 100644
> index 0000000000000000000000000000000000000000..c4d9a5ff860a96428422a15000c622aeecc2d664
> --- /dev/null
> +++ b/include/asm-generic/asi.h
> @@ -0,0 +1,5 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef __ASM_GENERIC_ASI_H
> +#define __ASM_GENERIC_ASI_H
> +
> +#endif
IMHO it should be include/linux/asi.h, with something like
#infdef __LINUX_ASI_H
#define __LINUX_ASI_H
#ifdef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
#include <asm/asi.h>
#else /* CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION */
/* stubs for functions used outside arch/ */
#endif /* CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION */
#endif /* __LINUX_ASI_H */
--
Sincerely yours,
Mike.
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH RFC v2 02/29] x86: Create CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
2025-03-01 7:23 ` Mike Rapoport
@ 2025-03-05 13:12 ` Brendan Jackman
0 siblings, 0 replies; 45+ messages in thread
From: Brendan Jackman @ 2025-03-05 13:12 UTC (permalink / raw)
To: Mike Rapoport
Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Richard Henderson, Matt Turner, Vineet Gupta, Russell King,
Catalin Marinas, Will Deacon, Guo Ren, Brian Cain, Huacai Chen,
WANG Xuerui, Geert Uytterhoeven, Michal Simek,
Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn, Stefan Kristiansson,
Stafford Horne, James E.J. Bottomley, Helge Deller,
Michael Ellerman, Nicholas Piggin, Christophe Leroy, Naveen N Rao,
Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Arnaldo Carvalho de Melo, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
Dennis Zhou, Tejun Heo, Christoph Lameter, Sean Christopherson,
Paolo Bonzini, Ard Biesheuvel, Josh Poimboeuf, Pawan Gupta, x86,
linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Junaid Shahid
On Sat, Mar 01, 2025 at 09:23:51AM +0200, Mike Rapoport wrote:
> Hi Brendan,
>
> On Fri, Jan 10, 2025 at 06:40:28PM +0000, Brendan Jackman wrote:
> > Currently a nop config. Keeping as a separate commit for easy review of
> > the boring bits. Later commits will use and enable this new config.
> >
> > This config is only added for non-UML x86_64 as other architectures do
> > not yet have pending implementations. It also has somewhat artificial
> > dependencies on !PARAVIRT and !KASAN which are explained in the Kconfig
> > file.
> >
> > Co-developed-by: Junaid Shahid <junaids@google.com>
> > Signed-off-by: Junaid Shahid <junaids@google.com>
> > Signed-off-by: Brendan Jackman <jackmanb@google.com>
> > ---
> > arch/alpha/include/asm/Kbuild | 1 +
> > arch/arc/include/asm/Kbuild | 1 +
> > arch/arm/include/asm/Kbuild | 1 +
> > arch/arm64/include/asm/Kbuild | 1 +
> > arch/csky/include/asm/Kbuild | 1 +
> > arch/hexagon/include/asm/Kbuild | 1 +
> > arch/loongarch/include/asm/Kbuild | 3 +++
> > arch/m68k/include/asm/Kbuild | 1 +
> > arch/microblaze/include/asm/Kbuild | 1 +
> > arch/mips/include/asm/Kbuild | 1 +
> > arch/nios2/include/asm/Kbuild | 1 +
> > arch/openrisc/include/asm/Kbuild | 1 +
> > arch/parisc/include/asm/Kbuild | 1 +
> > arch/powerpc/include/asm/Kbuild | 1 +
> > arch/riscv/include/asm/Kbuild | 1 +
> > arch/s390/include/asm/Kbuild | 1 +
> > arch/sh/include/asm/Kbuild | 1 +
> > arch/sparc/include/asm/Kbuild | 1 +
> > arch/um/include/asm/Kbuild | 2 +-
> > arch/x86/Kconfig | 14 ++++++++++++++
> > arch/xtensa/include/asm/Kbuild | 1 +
> > include/asm-generic/asi.h | 5 +++++
> > 22 files changed, 41 insertions(+), 1 deletion(-)
>
> I don't think this all is needed. You can put asi.h with stubs used outside
> of arch/x86 in include/linux and save you the hassle of updating every
> architecture.
...
> If you expect other architectures might implement ASI the config would better
> fit into init/Kconfig or mm/Kconfig and in arch/x86/Kconfig will define
> ARCH_HAS_MITIGATION_ADDRESS_SPACE_ISOLATION.
...
> > +++ b/include/asm-generic/asi.h
> > @@ -0,0 +1,5 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +#ifndef __ASM_GENERIC_ASI_H
> > +#define __ASM_GENERIC_ASI_H
> > +
> > +#endif
>
> IMHO it should be include/linux/asi.h, with something like
>
> #infdef __LINUX_ASI_H
> #define __LINUX_ASI_H
>
> #ifdef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
>
> #include <asm/asi.h>
>
> #else /* CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION */
>
> /* stubs for functions used outside arch/ */
>
> #endif /* CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION */
>
> #endif /* __LINUX_ASI_H */
Thanks Mike! That does indeed look way tidier. I'll try to adopt it.
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH RFC v2 04/29] mm: asi: Add infrastructure for boot-time enablement
2025-01-10 18:40 ` [PATCH RFC v2 04/29] mm: asi: Add infrastructure for boot-time enablement Brendan Jackman
@ 2025-03-19 17:29 ` Borislav Petkov
2025-03-19 18:47 ` Yosry Ahmed
0 siblings, 1 reply; 45+ messages in thread
From: Borislav Petkov @ 2025-03-19 17:29 UTC (permalink / raw)
To: Brendan Jackman
Cc: Thomas Gleixner, Ingo Molnar, Dave Hansen, H. Peter Anvin,
Andy Lutomirski, Peter Zijlstra, Richard Henderson, Matt Turner,
Vineet Gupta, Russell King, Catalin Marinas, Will Deacon, Guo Ren,
Brian Cain, Huacai Chen, WANG Xuerui, Geert Uytterhoeven,
Michal Simek, Thomas Bogendoerfer, Dinh Nguyen, Jonas Bonn,
Stefan Kristiansson, Stafford Horne, James E.J. Bottomley,
Helge Deller, Michael Ellerman, Nicholas Piggin, Christophe Leroy,
Naveen N Rao, Madhavan Srinivasan, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, David S. Miller, Andreas Larsson,
Richard Weinberger, Anton Ivanov, Johannes Berg, Chris Zankel,
Max Filippov, Arnd Bergmann, Andrew Morton, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, Uladzislau Rezki,
Christoph Hellwig, Masami Hiramatsu, Mathieu Desnoyers,
Mike Rapoport, Arnaldo Carvalho de Melo, Namhyung Kim,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Ian Rogers,
Adrian Hunter, Dennis Zhou, Tejun Heo, Christoph Lameter,
Sean Christopherson, Paolo Bonzini, Ard Biesheuvel,
Josh Poimboeuf, Pawan Gupta, x86, linux-kernel, linux-alpha,
linux-snps-arc, linux-arm-kernel, linux-csky, linux-hexagon,
loongarch, linux-m68k, linux-mips, linux-openrisc, linux-parisc,
linuxppc-dev, linux-riscv, linux-s390, linux-sh, sparclinux,
linux-um, linux-arch, linux-mm, linux-trace-kernel,
linux-perf-users, kvm, linux-efi, Junaid Shahid, Yosry Ahmed
On Fri, Jan 10, 2025 at 06:40:30PM +0000, Brendan Jackman wrote:
> Add a boot time parameter to control the newly added X86_FEATURE_ASI.
> "asi=on" or "asi=off" can be used in the kernel command line to enable
> or disable ASI at boot time. If not specified, ASI enablement depends
> on CONFIG_ADDRESS_SPACE_ISOLATION_DEFAULT_ON, which is off by default.
I don't know yet why we need this default-on thing...
> asi_check_boottime_disable() is modeled after
> pti_check_boottime_disable().
>
> The boot parameter is currently ignored until ASI is fully functional.
>
> Once we have a set of ASI features checked in that we have actually
> tested, we will stop ignoring the flag. But for now let's just add the
> infrastructure so we can implement the usage code.
>
> Ignoring checkpatch.pl CONFIG_DESCRIPTION because the _DEFAULT_ON
> Kconfig is trivial to explain.
Those last two paragraphs go...
> Checkpatch-args: --ignore CONFIG_DESCRIPTION
> Co-developed-by: Junaid Shahid <junaids@google.com>
> Signed-off-by: Junaid Shahid <junaids@google.com>
> Co-developed-by: Yosry Ahmed <yosryahmed@google.com>
> Signed-off-by: Yosry Ahmed <yosryahmed@google.com>
> Signed-off-by: Brendan Jackman <jackmanb@google.com>
> ---
... here as that's text not really pertaining to the contents of the patch.
> arch/x86/Kconfig | 9 +++++
> arch/x86/include/asm/asi.h | 19 ++++++++--
> arch/x86/include/asm/cpufeatures.h | 1 +
> arch/x86/include/asm/disabled-features.h | 8 ++++-
> arch/x86/mm/asi.c | 61 +++++++++++++++++++++++++++-----
> arch/x86/mm/init.c | 4 ++-
> include/asm-generic/asi.h | 4 +++
> 7 files changed, 92 insertions(+), 14 deletions(-)
...
> * the N ASI classes.
> */
>
> +#define static_asi_enabled() cpu_feature_enabled(X86_FEATURE_ASI)
Yeah, as already mentioned somewhere else, whack that thing pls.
> +
> /*
> * ASI uses a per-CPU tainting model to track what mitigation actions are
> * required on domain transitions. Taints exist along two dimensions:
> @@ -131,6 +134,8 @@ struct asi {
>
> DECLARE_PER_CPU_ALIGNED(struct asi *, curr_asi);
>
> +void asi_check_boottime_disable(void);
> +
> void asi_init_mm_state(struct mm_struct *mm);
>
> int asi_init_class(enum asi_class_id class_id, struct asi_taint_policy *taint_policy);
> @@ -155,7 +160,9 @@ void asi_exit(void);
> /* The target is the domain we'll enter when returning to process context. */
> static __always_inline struct asi *asi_get_target(struct task_struct *p)
> {
> - return p->thread.asi_state.target;
> + return static_asi_enabled()
> + ? p->thread.asi_state.target
> + : NULL;
Waaay too fancy for old people:
if ()
return...
else
return NULL;
:-)
The others too pls.
> static __always_inline void asi_set_target(struct task_struct *p,
> @@ -166,7 +173,9 @@ static __always_inline void asi_set_target(struct task_struct *p,
>
> static __always_inline struct asi *asi_get_current(void)
> {
> - return this_cpu_read(curr_asi);
> + return static_asi_enabled()
> + ? this_cpu_read(curr_asi)
> + : NULL;
> }
>
> /* Are we currently in a restricted address space? */
> @@ -175,7 +184,11 @@ static __always_inline bool asi_is_restricted(void)
> return (bool)asi_get_current();
> }
>
> -/* If we exit/have exited, can we stay that way until the next asi_enter? */
> +/*
> + * If we exit/have exited, can we stay that way until the next asi_enter?
What is that supposed to mean here?
> + *
> + * When ASI is disabled, this returns true.
> + */
> static __always_inline bool asi_is_relaxed(void)
> {
> return !asi_get_target(current);
> diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
> index 913fd3a7bac6506141de65f33b9ee61c615c7d7d..d6a808d10c3b8900d190ea01c66fc248863f05e2 100644
> --- a/arch/x86/include/asm/cpufeatures.h
> +++ b/arch/x86/include/asm/cpufeatures.h
> @@ -474,6 +474,7 @@
> #define X86_FEATURE_CLEAR_BHB_HW (21*32+ 3) /* BHI_DIS_S HW control enabled */
> #define X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT (21*32+ 4) /* Clear branch history at vmexit using SW loop */
> #define X86_FEATURE_FAST_CPPC (21*32 + 5) /* AMD Fast CPPC */
> +#define X86_FEATURE_ASI (21*32+6) /* Kernel Address Space Isolation */
>
> /*
> * BUG word(s)
> diff --git a/arch/x86/include/asm/disabled-features.h b/arch/x86/include/asm/disabled-features.h
> index c492bdc97b0595ec77f89dc9b0cefe5e3e64be41..c7964ed4fef8b9441e1c0453da587787d8008d9d 100644
> --- a/arch/x86/include/asm/disabled-features.h
> +++ b/arch/x86/include/asm/disabled-features.h
> @@ -50,6 +50,12 @@
> # define DISABLE_PTI (1 << (X86_FEATURE_PTI & 31))
> #endif
>
> +#ifdef CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION
> +# define DISABLE_ASI 0
> +#else
> +# define DISABLE_ASI (1 << (X86_FEATURE_ASI & 31))
> +#endif
> +
> #ifdef CONFIG_MITIGATION_RETPOLINE
> # define DISABLE_RETPOLINE 0
> #else
> @@ -154,7 +160,7 @@
> #define DISABLED_MASK17 0
> #define DISABLED_MASK18 (DISABLE_IBT)
> #define DISABLED_MASK19 (DISABLE_SEV_SNP)
> -#define DISABLED_MASK20 0
> +#define DISABLED_MASK20 (DISABLE_ASI)
> #define DISABLED_MASK21 0
> #define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 22)
>
Right, that hunk is done this way now:
diff --git a/arch/x86/Kconfig.cpufeatures b/arch/x86/Kconfig.cpufeatures
index e12d5b7e39a2..f219eaf664fb 100644
--- a/arch/x86/Kconfig.cpufeatures
+++ b/arch/x86/Kconfig.cpufeatures
@@ -199,3 +199,7 @@ config X86_DISABLED_FEATURE_SEV_SNP
config X86_DISABLED_FEATURE_INVLPGB
def_bool y
depends on !BROADCAST_TLB_FLUSH
+
+config X86_DISABLED_FEATURE_ASI
+ def_bool y
+ depends on !MITIGATION_ADDRESS_SPACE_ISOLATION
> diff --git a/arch/x86/mm/asi.c b/arch/x86/mm/asi.c
> index 105cd8b43eaf5c20acc80d4916b761559fb95d74..5baf563a078f5b3a6cd4b9f5e92baaf81b0774c4 100644
> --- a/arch/x86/mm/asi.c
> +++ b/arch/x86/mm/asi.c
> @@ -4,6 +4,7 @@
> #include <linux/percpu.h>
> #include <linux/spinlock.h>
>
> +#include <linux/init.h>
> #include <asm/asi.h>
> #include <asm/cmdline.h>
> #include <asm/cpufeature.h>
> @@ -29,6 +30,9 @@ static inline bool asi_class_id_valid(enum asi_class_id class_id)
>
> static inline bool asi_class_initialized(enum asi_class_id class_id)
> {
> + if (!boot_cpu_has(X86_FEATURE_ASI))
check_for_deprecated_apis: WARNING: arch/x86/mm/asi.c:33: Do not use boot_cpu_has() - use cpu_feature_enabled() instead.
Check your whole set pls.
> + return 0;
> +
> if (WARN_ON(!asi_class_id_valid(class_id)))
> return false;
>
> @@ -51,6 +55,9 @@ EXPORT_SYMBOL_GPL(asi_init_class);
>
> void asi_uninit_class(enum asi_class_id class_id)
> {
> + if (!boot_cpu_has(X86_FEATURE_ASI))
> + return;
> +
> if (!asi_class_initialized(class_id))
> return;
>
> @@ -66,10 +73,36 @@ const char *asi_class_name(enum asi_class_id class_id)
> return asi_class_names[class_id];
> }
>
> +void __init asi_check_boottime_disable(void)
> +{
> + bool enabled = IS_ENABLED(CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION_DEFAULT_ON);
> + char arg[4];
> + int ret;
> +
> + ret = cmdline_find_option(boot_command_line, "asi", arg, sizeof(arg));
> + if (ret == 3 && !strncmp(arg, "off", 3)) {
> + enabled = false;
> + pr_info("ASI disabled through kernel command line.\n");
> + } else if (ret == 2 && !strncmp(arg, "on", 2)) {
> + enabled = true;
> + pr_info("Ignoring asi=on param while ASI implementation is incomplete.\n");
> + } else {
> + pr_info("ASI %s by default.\n",
> + enabled ? "enabled" : "disabled");
> + }
> +
> + if (enabled)
> + pr_info("ASI enablement ignored due to incomplete implementation.\n");
Incomplete how?
> +}
> +
> static void __asi_destroy(struct asi *asi)
> {
> - lockdep_assert_held(&asi->mm->asi_init_lock);
> + WARN_ON_ONCE(asi->ref_count <= 0);
> + if (--(asi->ref_count) > 0)
Switch that to
include/linux/kref.h
It gives you a sanity-checking functionality too so you don't need the WARN...
> + return;
>
> + free_pages((ulong)asi->pgd, PGD_ALLOCATION_ORDER);
> + memset(asi, 0, sizeof(struct asi));
And then you can do:
if (kref_put())
free_pages...
and so on.
Thx.
--
Regards/Gruss,
Boris.
https://people.kernel.org/tglx/notes-about-netiquette
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply related [flat|nested] 45+ messages in thread
* Re: [PATCH RFC v2 04/29] mm: asi: Add infrastructure for boot-time enablement
2025-03-19 17:29 ` Borislav Petkov
@ 2025-03-19 18:47 ` Yosry Ahmed
2025-03-20 10:44 ` Brendan Jackman
0 siblings, 1 reply; 45+ messages in thread
From: Yosry Ahmed @ 2025-03-19 18:47 UTC (permalink / raw)
To: Borislav Petkov
Cc: Brendan Jackman, Thomas Gleixner, Ingo Molnar, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra, Josh Poimboeuf,
Pawan Gupta, x86, linux-kernel, linux-alpha, linux-snps-arc,
linux-arm-kernel, linux-csky, linux-hexagon, loongarch,
linux-m68k, linux-mips, linux-openrisc, linux-parisc,
linuxppc-dev, linux-riscv, linux-s390, linux-sh, sparclinux,
linux-um, linux-arch, linux-mm, linux-trace-kernel,
linux-perf-users, kvm, linux-efi, Junaid Shahid
On Wed, Mar 19, 2025 at 06:29:35PM +0100, Borislav Petkov wrote:
> On Fri, Jan 10, 2025 at 06:40:30PM +0000, Brendan Jackman wrote:
> > Add a boot time parameter to control the newly added X86_FEATURE_ASI.
> > "asi=on" or "asi=off" can be used in the kernel command line to enable
> > or disable ASI at boot time. If not specified, ASI enablement depends
> > on CONFIG_ADDRESS_SPACE_ISOLATION_DEFAULT_ON, which is off by default.
>
> I don't know yet why we need this default-on thing...
It's a convenience to avoid needing to set asi=on if you want ASI to be
on by default. It's similar to HUGETLB_PAGE_OPTIMIZE_VMEMMAP_DEFAULT_ON
or ZSWAP_DEFAULT_ON.
[..]
> > @@ -175,7 +184,11 @@ static __always_inline bool asi_is_restricted(void)
> > return (bool)asi_get_current();
> > }
> >
> > -/* If we exit/have exited, can we stay that way until the next asi_enter? */
> > +/*
> > + * If we exit/have exited, can we stay that way until the next asi_enter?
>
> What is that supposed to mean here?
asi_is_relaxed() checks if the thread is outside an ASI critical
section.
I say "the thread" because it will also return true if we are executing
an interrupt that arrived during the critical section, even though the
interrupt handler is not technically part of the critical section.
Now the reason it says "if we exit we stay that way" is probably
referring to the fact that an asi_exit() when interrupting a critical
section will be undone in the interrupt epilogue by re-entering ASI.
I agree the wording here is confusing. We should probably describe this
more explicitly and probably rename the function after the API
discussions you had in the previous patch.
>
> > + *
> > + * When ASI is disabled, this returns true.
> > + */
> > static __always_inline bool asi_is_relaxed(void)
> > {
> > return !asi_get_target(current);
[..]
> > @@ -66,10 +73,36 @@ const char *asi_class_name(enum asi_class_id class_id)
> > return asi_class_names[class_id];
> > }
> >
> > +void __init asi_check_boottime_disable(void)
> > +{
> > + bool enabled = IS_ENABLED(CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION_DEFAULT_ON);
> > + char arg[4];
> > + int ret;
> > +
> > + ret = cmdline_find_option(boot_command_line, "asi", arg, sizeof(arg));
> > + if (ret == 3 && !strncmp(arg, "off", 3)) {
> > + enabled = false;
> > + pr_info("ASI disabled through kernel command line.\n");
> > + } else if (ret == 2 && !strncmp(arg, "on", 2)) {
> > + enabled = true;
> > + pr_info("Ignoring asi=on param while ASI implementation is incomplete.\n");
> > + } else {
> > + pr_info("ASI %s by default.\n",
> > + enabled ? "enabled" : "disabled");
> > + }
> > +
> > + if (enabled)
> > + pr_info("ASI enablement ignored due to incomplete implementation.\n");
>
> Incomplete how?
This is referring to the fact that ASI is still not fully/correctly
functional, but it will be after the following patches.
I think it will be clearer if we just add the feature flag here so that
we have something to check for in the following patches, but add the
infrastructure for boot-time enablement at the end of the series when
the impelemntation is complete.
Basically start by a feature flag that has no way of being enabled, use
it in the implmentation, then add means of enabling it.
>
> > +}
> > +
> > static void __asi_destroy(struct asi *asi)
> > {
> > - lockdep_assert_held(&asi->mm->asi_init_lock);
> > + WARN_ON_ONCE(asi->ref_count <= 0);
> > + if (--(asi->ref_count) > 0)
>
> Switch that to
>
> include/linux/kref.h
>
> It gives you a sanity-checking functionality too so you don't need the WARN...
I think we hve internal changes that completely get rid of this
ref_count and simplifies the lifetime handling that we can squash here.
We basically keep ASI objects around until the process is torn down,
which makes this simpler and avoids the need for complex synchronization
when we try to context switch or run userspace without exiting ASI
(spoiler alert :) ).
>
> > + return;
> >
> > + free_pages((ulong)asi->pgd, PGD_ALLOCATION_ORDER);
> > + memset(asi, 0, sizeof(struct asi));
>
> And then you can do:
>
> if (kref_put())
> free_pages...
>
> and so on.
>
> Thx.
>
> --
> Regards/Gruss,
> Boris.
>
> https://people.kernel.org/tglx/notes-about-netiquette
>
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH RFC v2 04/29] mm: asi: Add infrastructure for boot-time enablement
2025-03-19 18:47 ` Yosry Ahmed
@ 2025-03-20 10:44 ` Brendan Jackman
0 siblings, 0 replies; 45+ messages in thread
From: Brendan Jackman @ 2025-03-20 10:44 UTC (permalink / raw)
To: Yosry Ahmed, Borislav Petkov
Cc: Thomas Gleixner, Ingo Molnar, Dave Hansen, H. Peter Anvin,
Andy Lutomirski, Peter Zijlstra, Josh Poimboeuf, Pawan Gupta, x86,
linux-kernel, linux-alpha, linux-snps-arc, linux-arm-kernel,
linux-csky, linux-hexagon, loongarch, linux-m68k, linux-mips,
linux-openrisc, linux-parisc, linuxppc-dev, linux-riscv,
linux-s390, linux-sh, sparclinux, linux-um, linux-arch, linux-mm,
linux-trace-kernel, linux-perf-users, kvm, linux-efi,
Junaid Shahid
On Wed Mar 19, 2025 at 6:47 PM UTC, Yosry Ahmed wrote:
> On Wed, Mar 19, 2025 at 06:29:35PM +0100, Borislav Petkov wrote:
> > On Fri, Jan 10, 2025 at 06:40:30PM +0000, Brendan Jackman wrote:
> > > Add a boot time parameter to control the newly added X86_FEATURE_ASI.
> > > "asi=on" or "asi=off" can be used in the kernel command line to enable
> > > or disable ASI at boot time. If not specified, ASI enablement depends
> > > on CONFIG_ADDRESS_SPACE_ISOLATION_DEFAULT_ON, which is off by default.
> >
> > I don't know yet why we need this default-on thing...
>
> It's a convenience to avoid needing to set asi=on if you want ASI to be
> on by default. It's similar to HUGETLB_PAGE_OPTIMIZE_VMEMMAP_DEFAULT_ON
> or ZSWAP_DEFAULT_ON.
>
> [..]
> > > @@ -175,7 +184,11 @@ static __always_inline bool asi_is_restricted(void)
> > > return (bool)asi_get_current();
> > > }
> > >
> > > -/* If we exit/have exited, can we stay that way until the next asi_enter? */
> > > +/*
> > > + * If we exit/have exited, can we stay that way until the next asi_enter?
> >
> > What is that supposed to mean here?
>
> asi_is_relaxed() checks if the thread is outside an ASI critical
> section.
>
> I say "the thread" because it will also return true if we are executing
> an interrupt that arrived during the critical section, even though the
> interrupt handler is not technically part of the critical section.
>
> Now the reason it says "if we exit we stay that way" is probably
> referring to the fact that an asi_exit() when interrupting a critical
> section will be undone in the interrupt epilogue by re-entering ASI.
>
> I agree the wording here is confusing. We should probably describe this
> more explicitly and probably rename the function after the API
> discussions you had in the previous patch.
Yeah, this is confusing. It's trying to very concisely define the
concept of "relaxed" but now I see it through Boris' eyes I realise
it's really unhelpful to try and do that. And yeah we should probably
just rework the terminology/API.
To re-iterate what Yosry said, aside from my too-clever comment style
the more fundamental thing that's confusing here is that, using the
terminology currently in the code there are two concepts at play:
- The critical section: this is the path from asi_enter() to
asi_relax(). The critical section can be interrupted, and code
running in those interupts is not said to be "in the critical
section".
- Being "tense" vs "relaxed". Being "tense" means the _task_ is in a
critical section, but the current code might not be.
This distinction is theoretically relevant because e.g. it's a bug to
access sensitive data in a critical section, but it's OK to access it
while in the tense state (we will switch to the restricted address
space, but this is OK because we will have a chance to asi_enter()
again before we get back to the untrusted code).
BTW, just to be clear:
1. Both of these are only relevant to code that's pretty deeply aware
of ASI. (TLB flushing code, entry code, stuff like that).
2. To be honest whenever you write:
if (asi_in_critical_section())
You probably mean:
if (WARN_ON(asi_in_critical_section()))
For example if we try to flush the TLB in the critical section,
there's a thing we can do to handle it. But that really shouldn't
be necessary. We want the critical section code to be very small
and straight-line code.
And indeed in the present code we don't use
asi_in_critical_section() for anything bur WARNing.
> asi_is_relaxed() checks if the thread is outside an ASI critical
> section.
Now I see it written this way, this is probably the best way to
conceptualise it. Instead of having two concepts "tense/relaxed" vs
"ASI critical section" we could just say "the task is in a critical
section" vs "the CPU is in a critical section". So we could have
something like:
bool asi_task_critical(void);
bool asi_cpu_critical(void);
(They could also accept an argument for the task/CPU, but I can't see
any reason why you'd peek at another context like that).
--
For everything else, Ack to Boris or +1 to Yosry respectively.
_______________________________________________
linux-snps-arc mailing list
linux-snps-arc@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-snps-arc
^ permalink raw reply [flat|nested] 45+ messages in thread
end of thread, other threads:[~2025-03-20 10:46 UTC | newest]
Thread overview: 45+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-01-10 18:40 [PATCH RFC v2 00/29] Address Space Isolation (ASI) Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 01/29] mm: asi: Make some utility functions noinstr compatible Brendan Jackman
2025-01-16 0:18 ` Borislav Petkov
2025-01-16 10:27 ` Borislav Petkov
2025-01-16 13:22 ` Brendan Jackman
2025-01-16 14:02 ` Borislav Petkov
2025-01-10 18:40 ` [PATCH RFC v2 02/29] x86: Create CONFIG_MITIGATION_ADDRESS_SPACE_ISOLATION Brendan Jackman
2025-01-16 16:43 ` Borislav Petkov
2025-03-01 7:23 ` Mike Rapoport
2025-03-05 13:12 ` Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 03/29] mm: asi: Introduce ASI core API Brendan Jackman
2025-02-19 10:55 ` Borislav Petkov
2025-02-19 13:53 ` Brendan Jackman
2025-02-27 12:06 ` Borislav Petkov
2025-01-10 18:40 ` [PATCH RFC v2 04/29] mm: asi: Add infrastructure for boot-time enablement Brendan Jackman
2025-03-19 17:29 ` Borislav Petkov
2025-03-19 18:47 ` Yosry Ahmed
2025-03-20 10:44 ` Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 05/29] mm: asi: ASI support in interrupts/exceptions Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 06/29] mm: asi: Use separate PCIDs for restricted address spaces Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 07/29] mm: asi: Make __get_current_cr3_fast() ASI-aware Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 08/29] mm: asi: Avoid warning from NMI userspace accesses in ASI context Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 09/29] mm: asi: ASI page table allocation functions Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 10/29] mm: asi: asi_exit() on PF, skip handling if address is accessible Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 11/29] mm: asi: Functions to map/unmap a memory range into ASI page tables Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 12/29] mm: asi: Add basic infrastructure for global non-sensitive mappings Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 13/29] mm: Add __PAGEFLAG_FALSE Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 14/29] mm: asi: Map non-user buddy allocations as nonsensitive Brendan Jackman
2025-01-10 18:40 ` [PATCH TEMP WORKAROUND RFC v2 15/29] mm: asi: Workaround missing partial-unmap support Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 16/29] mm: asi: Map kernel text and static data as nonsensitive Brendan Jackman
2025-01-17 11:23 ` Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 17/29] mm: asi: Map vmalloc/vmap " Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 18/29] mm: asi: Map dynamic percpu memory " Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 19/29] mm: asi: Stabilize CR3 in switch_mm_irqs_off() Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 20/29] mm: asi: Make TLB flushing correct under ASI Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 21/29] KVM: x86: asi: Restricted address space for VM execution Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 22/29] mm: asi: exit ASI before accessing CR3 from C code where appropriate Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 23/29] mm: asi: exit ASI before suspend-like operations Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 24/29] mm: asi: Add infrastructure for mapping userspace addresses Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 25/29] mm: asi: Restricted execution fore bare-metal processes Brendan Jackman
2025-02-28 15:32 ` Yosry Ahmed
2025-01-10 18:40 ` [PATCH RFC v2 26/29] x86: Create library for flushing L1D for L1TF Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 27/29] mm: asi: Add some mitigations on address space transitions Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 28/29] x86/pti: Disable PTI when ASI is on Brendan Jackman
2025-01-10 18:40 ` [PATCH RFC v2 29/29] mm: asi: Stop ignoring asi=on cmdline flag Brendan Jackman
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).