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 inline versions respectively. 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 | 14 ++++++++++++-- 2 files changed, 43 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); +} + 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..3d2bcb7682eb 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -2447,16 +2447,26 @@ 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(); + __inline_memcpy(dst, src, len); + lass_clac(); } static void text_poke_memset(void *dst, const void *src, size_t len) { int c = *(const int *)src; - memset(dst, c, len); + lass_stac(); + __inline_memset(dst, c, len); + lass_clac(); } typedef void text_poke_f(void *dst, const void *src, size_t len); -- 2.47.2