On 7/7/25 01:03, Kirill A. Shutemov wrote: > From: Sohil Mehta <sohil.mehta@xxxxxxxxx> > > For patching, the kernel initializes a temporary mm area in the lower > half of the address range. See commit 4fc19708b165 ("x86/alternatives: > Initialize temporary mm for patching"). > > Disable LASS enforcement during patching to avoid triggering a #GP > fault. > > The objtool warns due to a call to a non-allowed function that exists > outside of the stac/clac guard, or references to any function with a > dynamic function pointer inside the guard. See the Objtool warnings > section #9 in the document tools/objtool/Documentation/objtool.txt. > > Considering that patching is usually small, replace the memcpy() and > memset() functions in the text poking functions with their open coded > versions. > > Signed-off-by: Sohil Mehta <sohil.mehta@xxxxxxxxx> > Signed-off-by: Alexander Shishkin <alexander.shishkin@xxxxxxxxxxxxxxx> > Signed-off-by: Kirill A. Shutemov <kirill.shutemov@xxxxxxxxxxxxxxx> > --- > arch/x86/include/asm/smap.h | 33 +++++++++++++++++++++++++++++++-- > arch/x86/kernel/alternative.c | 28 ++++++++++++++++++++++++++-- > 2 files changed, 57 insertions(+), 4 deletions(-) > > diff --git a/arch/x86/include/asm/smap.h b/arch/x86/include/asm/smap.h > index 4f84d421d1cf..d0cc24348641 100644 > --- a/arch/x86/include/asm/smap.h > +++ b/arch/x86/include/asm/smap.h > @@ -23,18 +23,47 @@ > > #else /* __ASSEMBLER__ */ > > +/* > + * The CLAC/STAC instructions toggle the enforcement of X86_FEATURE_SMAP and > + * X86_FEATURE_LASS. > + * > + * SMAP enforcement is based on the _PAGE_BIT_USER bit in the page tables: the > + * kernel is not allowed to touch pages with the bit set unless the AC bit is > + * set. > + * > + * LASS enforcement is based on bit 63 of the virtual address. The kernel is > + * not allowed to touch memory in the lower half of the virtual address space > + * unless the AC bit is set. > + * > + * Use stac()/clac() when accessing userspace (_PAGE_USER) mappings, > + * regardless of location. > + * > + * Use lass_stac()/lass_clac() when accessing kernel mappings (!_PAGE_USER) > + * in the lower half of the address space. > + * > + * Note: a barrier is implicit in alternative(). > + */ > + > static __always_inline void clac(void) > { > - /* Note: a barrier is implicit in alternative() */ > alternative("", "clac", X86_FEATURE_SMAP); > } > > static __always_inline void stac(void) > { > - /* Note: a barrier is implicit in alternative() */ > alternative("", "stac", X86_FEATURE_SMAP); > } > > +static __always_inline void lass_clac(void) > +{ > + alternative("", "clac", X86_FEATURE_LASS); > +} > + > +static __always_inline void lass_stac(void) > +{ > + alternative("", "stac", X86_FEATURE_LASS); > +} Could we please move the comments about lass_*() closer to the LASS functions? > static __always_inline unsigned long smap_save(void) > { > unsigned long flags; > diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c > index ea1d984166cd..992ece0e879a 100644 > --- a/arch/x86/kernel/alternative.c > +++ b/arch/x86/kernel/alternative.c > @@ -2447,16 +2447,40 @@ void __init_or_module text_poke_early(void *addr, const void *opcode, > __ro_after_init struct mm_struct *text_poke_mm; > __ro_after_init unsigned long text_poke_mm_addr; > > +/* > + * Text poking creates and uses a mapping in the lower half of the > + * address space. Relax LASS enforcement when accessing the poking > + * address. > + */ > + > static void text_poke_memcpy(void *dst, const void *src, size_t len) > { > - memcpy(dst, src, len); > + lass_stac(); > + > + /* > + * Objtool is picky about what occurs within the STAC/CLAC region > + * because this code runs with protection disabled. Objtool typically > + * does not permit function calls in this area. > + * > + * Avoid using memcpy() here. Instead, open code it. > + */ > + asm volatile("rep movsb" > + : "+D" (dst), "+S" (src), "+c" (len) : : "memory"); > + > + lass_clac(); > } This didn't turn out great. At the _very_ least, we could have a: inline_memcpy_i_really_mean_it() with the rep mov. Or even a #define if we were super paranoid the compiler is out to get us. But _actually_ open-coding inline assembly is far too ugly to live. We can also be a bit more compact about the comments: /* * objtool enforces a strict policy of "no function calls within * AC=1 regions". Adhere to the policy by doing a memcpy() that * will never result in a function call. */