[PATCHv7 03/16] x86/alternatives: Disable LASS when patching kernel alternatives

Kirill A. Shutemov posted 16 patches 3 months, 2 weeks ago
There is a newer version of this series
[PATCHv7 03/16] x86/alternatives: Disable LASS when patching kernel alternatives
Posted by Kirill A. Shutemov 3 months, 2 weeks ago
From: Sohil Mehta <sohil.mehta@intel.com>

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@intel.com>
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
---
 arch/x86/include/asm/smap.h   | 27 +++++++++++++++++++++++++--
 arch/x86/kernel/alternative.c | 14 ++++++++++++--
 2 files changed, 37 insertions(+), 4 deletions(-)

diff --git a/arch/x86/include/asm/smap.h b/arch/x86/include/asm/smap.h
index 4f84d421d1cf..2bb7f3808e51 100644
--- a/arch/x86/include/asm/smap.h
+++ b/arch/x86/include/asm/smap.h
@@ -23,18 +23,41 @@
 
 #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.
+ *
+ * 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_enable_enforcement(void)
+{
+	alternative("", "clac", X86_FEATURE_LASS);
+}
+
+static __always_inline void lass_disable_enforcement(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..ed75892590ee 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_disable_enforcement();
+	__inline_memcpy(dst, src, len);
+	lass_enable_enforcement();
 }
 
 static void text_poke_memset(void *dst, const void *src, size_t len)
 {
 	int c = *(const int *)src;
 
-	memset(dst, c, len);
+	lass_disable_enforcement();
+	__inline_memset(dst, c, len);
+	lass_enable_enforcement();
 }
 
 typedef void text_poke_f(void *dst, const void *src, size_t len);
-- 
2.47.2
Re: [PATCHv7 03/16] x86/alternatives: Disable LASS when patching kernel alternatives
Posted by Peter Zijlstra 3 months, 2 weeks ago
On Wed, Jun 25, 2025 at 03:50:56PM +0300, Kirill A. Shutemov wrote:

> +/*
> + * 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.
> + *
> + * 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_enable_enforcement(void)
> +{
> +	alternative("", "clac", X86_FEATURE_LASS);
> +}
> +
> +static __always_inline void lass_disable_enforcement(void)
> +{
> +	alternative("", "stac", X86_FEATURE_LASS);
> +}

Much hate for this naming. WTH was wrong with lass_{clac,stac}()?

We're not calling those other functions smap_{en,dis}able_enforcement()
either (and please don't take that as a suggestion, its terrible
naming).
Re: [PATCHv7 03/16] x86/alternatives: Disable LASS when patching kernel alternatives
Posted by Dave Hansen 3 months, 2 weeks ago
On 6/26/25 06:49, Peter Zijlstra wrote:
>> +static __always_inline void lass_enable_enforcement(void)
>> +{
>> +	alternative("", "clac", X86_FEATURE_LASS);
>> +}
>> +
>> +static __always_inline void lass_disable_enforcement(void)
>> +{
>> +	alternative("", "stac", X86_FEATURE_LASS);
>> +}
> Much hate for this naming. WTH was wrong with lass_{clac,stac}()?
> 
> We're not calling those other functions smap_{en,dis}able_enforcement()
> either (and please don't take that as a suggestion, its terrible
> naming).

It was a response to a comment from Sohil about the delta between
lass_{cl,st}ac() and plain {cl,st}ac() being subtle. They are subtle,
but I don't think it's fixable with naming.

There are lots of crazy gymnastics we could do. But there are so few
sites where AC is twiddled for LASS that I don't think it's worth it.

Let's just use the lass_{cl,st}ac() and comment both variants. First,
the existing stac()/clac():

/*
 * Use these when accessing userspace (_PAGE_USER)
 * mappings, regardless of location.
 */

and the new ones:

/*
 * Use these when accessing kernel mappings (!_PAGE_USER)
 * in the lower half of the address space.
 */

Any objections to doing that?
Re: [PATCHv7 03/16] x86/alternatives: Disable LASS when patching kernel alternatives
Posted by Kirill A. Shutemov 3 months, 1 week ago
On Thu, Jun 26, 2025 at 07:18:59AM -0700, Dave Hansen wrote:
> On 6/26/25 06:49, Peter Zijlstra wrote:
> >> +static __always_inline void lass_enable_enforcement(void)
> >> +{
> >> +	alternative("", "clac", X86_FEATURE_LASS);
> >> +}
> >> +
> >> +static __always_inline void lass_disable_enforcement(void)
> >> +{
> >> +	alternative("", "stac", X86_FEATURE_LASS);
> >> +}
> > Much hate for this naming. WTH was wrong with lass_{clac,stac}()?
> > 
> > We're not calling those other functions smap_{en,dis}able_enforcement()
> > either (and please don't take that as a suggestion, its terrible
> > naming).
> 
> It was a response to a comment from Sohil about the delta between
> lass_{cl,st}ac() and plain {cl,st}ac() being subtle. They are subtle,
> but I don't think it's fixable with naming.
> 
> There are lots of crazy gymnastics we could do. But there are so few
> sites where AC is twiddled for LASS that I don't think it's worth it.
> 
> Let's just use the lass_{cl,st}ac() and comment both variants. First,
> the existing stac()/clac():
> 
> /*
>  * Use these when accessing userspace (_PAGE_USER)
>  * mappings, regardless of location.
>  */
> 
> and the new ones:
> 
> /*
>  * Use these when accessing kernel mappings (!_PAGE_USER)
>  * in the lower half of the address space.
>  */
> 
> Any objections to doing that?

Looks good. Will update the patch.

-- 
  Kiryl Shutsemau / Kirill A. Shutemov