[PATCH] arm64: mm: Stop using the previous ASID for init_mm

Anshuman Khandual anshuman.khandual at arm.com
Thu Oct 29 23:30:55 PDT 2026


On Tue, Oct 27, 2026 at 06:02:27PM +0800, Lai Jiangshan wrote:
> From: Lai Jiangshan <jiangshan.ljs at antgroup.com>
> 
> Switching to init_mm should prevent further accesses through the
> previous address space's translations.
> 
> Commit e53f21bce4d3 ("arm64: Use the reserved TTBR0 if context switching
> to the init_mm") avoided installing init_mm.pgd as a user page table.
> At the time, the ASID was held in TTBR0, so installing the reserved
> TTBR0 also switched to ASID 0.
> 
> Since commit 7655abb95386 ("arm64: mm: Move ASID from TTBR0 to TTBR1"),
> installing the reserved TTBR0 no longer changes the active ASID.
> Consequently, switching to init_mm leaves the CPU using the previous
> address space's ASID. An empty page table does not prevent TLB hits
> for that ASID.
> 
> This can retain access beyond the lifetime of the backing pages.
> During fullmm teardown, user data pages can be freed before their
> cached translations are invalidated. If those pages are subsequently
> reused for kernel data, an erroneous uaccess that hits a surviving
> translation can read or corrupt that data instead of faulting.
> 
> Fixes: 7655abb95386 ("arm64: mm: Move ASID from TTBR0 to TTBR1")
> Signed-off-by: Lai Jiangshan <jiangshan.ljs at antgroup.com>
> 
> diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h
> index 803b68758152..7e56099c5fbb 100644
> --- a/arch/arm64/include/asm/mmu_context.h
> +++ b/arch/arm64/include/asm/mmu_context.h
> @@ -235,15 +235,6 @@ enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
>  
>  static inline void __switch_mm(struct mm_struct *next)
>  {
> -	/*
> -	 * init_mm.pgd does not contain any user mappings and it is always
> -	 * active for kernel addresses in TTBR1. Just set the reserved TTBR0.
> -	 */
> -	if (next == &init_mm) {
> -		cpu_set_reserved_ttbr0();
> -		return;
> -	}
> -
>  	check_and_switch_context(next);
>  }
>  
> diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c
> index 0f4a28b87469..a96ebe904dd7 100644
> --- a/arch/arm64/mm/context.c
> +++ b/arch/arm64/mm/context.c
> @@ -218,6 +218,16 @@ void check_and_switch_context(struct mm_struct *mm)
>  	unsigned int cpu;
>  	u64 asid, old_active_asid;
>  
> +	/*
> +	 * init_mm.pgd contains kernel mappings, so use the reserved page
> +	 * tables for TTBR0 and switch TTBR1 to ASID 0. Leave active_asids

Just curious - does TTBR1 switch to ASID 0 ? AFAICS TTBR1_EL1 gets
the ASID which is derived from the mm_struct via ASID(mm) earlier.

void cpu_do_switch_mm(phys_addr_t pgd_phys, struct mm_struct *mm)
{
	unsigned long ttbr1 = read_sysreg(ttbr1_el1);
	unsigned long asid = ASID(mm);
	unsigned long ttbr0 = phys_to_ttbr(pgd_phys);

	/* Skip CNP for the reserved ASID */
	if (system_supports_cnp() && asid)
		ttbr0 |= TTBRx_EL1_CnP;

	/* SW PAN needs a copy of the ASID in TTBR0 for entry */
	if (IS_ENABLED(CONFIG_ARM64_SW_TTBR0_PAN))
		ttbr0 |= FIELD_PREP(TTBRx_EL1_ASID_MASK, asid);

	/* Set ASID in TTBR1 since TCR.A1 is set */
	ttbr1 &= ~TTBRx_EL1_ASID_MASK;
	ttbr1 |= FIELD_PREP(TTBRx_EL1_ASID_MASK, asid);

	cpu_set_reserved_ttbr0_nosync();
	write_sysreg(ttbr1, ttbr1_el1);
	write_sysreg(ttbr0, ttbr0_el1);
	isb();
	post_ttbr_update_workaround();
}

> +	 * unchanged to preserve the ASID rollover bookkeeping.
> +	 */
> +	if (mm == &init_mm) {
> +		cpu_do_switch_mm(__pa_symbol(reserved_pg_dir), mm);
> +		return;
> +	}
> +
>  	if (system_supports_cnp())
>  		cpu_set_reserved_ttbr0();
>  
> -- 
> 2.39.5 (Apple Git-154)
> 



More information about the linux-arm-kernel mailing list