VYPR
Unrated severityNVD Advisory· Published Jun 3, 2026

CVE-2026-46250

CVE-2026-46250

Description

Linux kernel MIPS architecture is vulnerable to a crash due to an LLVM bug affecting global register variable handling.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Linux kernel MIPS architecture is vulnerable to a crash due to an LLVM bug affecting global register variable handling.

Vulnerability

On the MIPS architecture within the Linux kernel, a vulnerability exists where the __current_thread_info structure, defined as a global register variable in $gp, is not correctly updated during kernel relocation when using the LLVM compiler. LLVM incorrectly restores $gp even when it's intentionally modified, contrary to GCC behavior, causing it to point to the unrelocated kernel after relocate_kernel() completes. This affects MIPS systems using the Linux kernel, particularly during early boot stages.

Exploitation

An attacker would need to trigger a kernel relocation process on a vulnerable MIPS system compiled with LLVM. The vulnerability is triggered automatically during the kernel boot sequence after the relocate_kernel() function, specifically when the init_idle() function is called, leading to a crash without requiring specific user interaction or elevated privileges.

Impact

Successful exploitation of this vulnerability results in an immediate kernel crash during the boot process, characterized by a "Unable to handle kernel paging request" error. This effectively leads to a denial of service, preventing the system from booting successfully. The scope of the compromise is limited to the kernel itself, causing a system-wide crash.

Mitigation

This vulnerability has been resolved in the Linux kernel. The fix involves a workaround for the LLVM bug related to the use of $gp as a global register variable on MIPS. Users should update to a patched version of the Linux kernel. Specific fixed version details are not provided in the available references, but the issue is addressed in the provided git commit [1].

AI Insight generated on Jun 3, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

2

Patches

16
9bc3b0ae5203

MIPS: Work around LLVM bug when gp is used as global register variable

1 file changed · +13 1
  • arch/mips/kernel/relocate.c+13 1 modified
    diff --git a/arch/mips/kernel/relocate.c b/arch/mips/kernel/relocate.c
    index 7f1c136ad8506..59833210542ff 100644
    --- a/arch/mips/kernel/relocate.c
    +++ b/arch/mips/kernel/relocate.c
    @@ -420,7 +420,20 @@ void *__init relocate_kernel(void)
     			goto out;
     
     		/* The current thread is now within the relocated image */
    +#ifndef CONFIG_CC_IS_CLANG
     		__current_thread_info = RELOCATED(&init_thread_union);
    +#else
    +		/*
    +		 * LLVM may wrongly restore $gp ($28) in epilog even if it's
    +		 * intentionally modified. Work around this by using inline
    +		 * assembly to assign $gp. $gp couldn't be listed as output or
    +		 * clobber, or LLVM will still restore its original value.
    +		 * See also LLVM upstream issue
    +		 * https://github.com/llvm/llvm-project/issues/176546
    +		 */
    +		asm volatile("move $28, %0" : :
    +			     "r" (RELOCATED(&init_thread_union)));
    +#endif
     
     		/* Return the new kernel's entry point */
     		kernel_entry = RELOCATED(start_kernel);
    -- 
    cgit 1.3-korg
    
    
    
30bfc2d6a113

MIPS: Work around LLVM bug when gp is used as global register variable

1 file changed · +13 1
  • arch/mips/kernel/relocate.c+13 1 modified
    diff --git a/arch/mips/kernel/relocate.c b/arch/mips/kernel/relocate.c
    index 7f1c136ad8506..59833210542ff 100644
    --- a/arch/mips/kernel/relocate.c
    +++ b/arch/mips/kernel/relocate.c
    @@ -420,7 +420,20 @@ void *__init relocate_kernel(void)
     			goto out;
     
     		/* The current thread is now within the relocated image */
    +#ifndef CONFIG_CC_IS_CLANG
     		__current_thread_info = RELOCATED(&init_thread_union);
    +#else
    +		/*
    +		 * LLVM may wrongly restore $gp ($28) in epilog even if it's
    +		 * intentionally modified. Work around this by using inline
    +		 * assembly to assign $gp. $gp couldn't be listed as output or
    +		 * clobber, or LLVM will still restore its original value.
    +		 * See also LLVM upstream issue
    +		 * https://github.com/llvm/llvm-project/issues/176546
    +		 */
    +		asm volatile("move $28, %0" : :
    +			     "r" (RELOCATED(&init_thread_union)));
    +#endif
     
     		/* Return the new kernel's entry point */
     		kernel_entry = RELOCATED(start_kernel);
    -- 
    cgit 1.3-korg
    
    
    
05bff9b0ae09

MIPS: Work around LLVM bug when gp is used as global register variable

1 file changed · +13 1
  • arch/mips/kernel/relocate.c+13 1 modified
    diff --git a/arch/mips/kernel/relocate.c b/arch/mips/kernel/relocate.c
    index dab8febb57419..5e014a457ad80 100644
    --- a/arch/mips/kernel/relocate.c
    +++ b/arch/mips/kernel/relocate.c
    @@ -399,7 +399,20 @@ void *__init relocate_kernel(void)
     			goto out;
     
     		/* The current thread is now within the relocated image */
    +#ifndef CONFIG_CC_IS_CLANG
     		__current_thread_info = RELOCATED(&init_thread_union);
    +#else
    +		/*
    +		 * LLVM may wrongly restore $gp ($28) in epilog even if it's
    +		 * intentionally modified. Work around this by using inline
    +		 * assembly to assign $gp. $gp couldn't be listed as output or
    +		 * clobber, or LLVM will still restore its original value.
    +		 * See also LLVM upstream issue
    +		 * https://github.com/llvm/llvm-project/issues/176546
    +		 */
    +		asm volatile("move $28, %0" : :
    +			     "r" (RELOCATED(&init_thread_union)));
    +#endif
     
     		/* Return the new kernel's entry point */
     		kernel_entry = RELOCATED(start_kernel);
    -- 
    cgit 1.3-korg
    
    
    
1fe3b402b1e9

MIPS: Work around LLVM bug when gp is used as global register variable

1 file changed · +13 1
  • arch/mips/kernel/relocate.c+13 1 modified
    diff --git a/arch/mips/kernel/relocate.c b/arch/mips/kernel/relocate.c
    index 56b51de2dc51b..8ca4d1f226854 100644
    --- a/arch/mips/kernel/relocate.c
    +++ b/arch/mips/kernel/relocate.c
    @@ -420,7 +420,20 @@ void *__init relocate_kernel(void)
     			goto out;
     
     		/* The current thread is now within the relocated image */
    +#ifndef CONFIG_CC_IS_CLANG
     		__current_thread_info = RELOCATED(&init_thread_union);
    +#else
    +		/*
    +		 * LLVM may wrongly restore $gp ($28) in epilog even if it's
    +		 * intentionally modified. Work around this by using inline
    +		 * assembly to assign $gp. $gp couldn't be listed as output or
    +		 * clobber, or LLVM will still restore its original value.
    +		 * See also LLVM upstream issue
    +		 * https://github.com/llvm/llvm-project/issues/176546
    +		 */
    +		asm volatile("move $28, %0" : :
    +			     "r" (RELOCATED(&init_thread_union)));
    +#endif
     
     		/* Return the new kernel's entry point */
     		kernel_entry = RELOCATED(start_kernel);
    -- 
    cgit 1.3-korg
    
    
    
4dc65b40fb80

MIPS: Work around LLVM bug when gp is used as global register variable

1 file changed · +13 1
  • arch/mips/kernel/relocate.c+13 1 modified
    diff --git a/arch/mips/kernel/relocate.c b/arch/mips/kernel/relocate.c
    index 58fc8d089402b..dcc2763b39d6e 100644
    --- a/arch/mips/kernel/relocate.c
    +++ b/arch/mips/kernel/relocate.c
    @@ -420,7 +420,20 @@ void *__init relocate_kernel(void)
     			goto out;
     
     		/* The current thread is now within the relocated image */
    +#ifndef CONFIG_CC_IS_CLANG
     		__current_thread_info = RELOCATED(&init_thread_union);
    +#else
    +		/*
    +		 * LLVM may wrongly restore $gp ($28) in epilog even if it's
    +		 * intentionally modified. Work around this by using inline
    +		 * assembly to assign $gp. $gp couldn't be listed as output or
    +		 * clobber, or LLVM will still restore its original value.
    +		 * See also LLVM upstream issue
    +		 * https://github.com/llvm/llvm-project/issues/176546
    +		 */
    +		asm volatile("move $28, %0" : :
    +			     "r" (RELOCATED(&init_thread_union)));
    +#endif
     
     		/* Return the new kernel's entry point */
     		kernel_entry = RELOCATED(start_kernel);
    -- 
    cgit 1.3-korg
    
    
    
c0155dee51b9

MIPS: Work around LLVM bug when gp is used as global register variable

1 file changed · +13 1
  • arch/mips/kernel/relocate.c+13 1 modified
    diff --git a/arch/mips/kernel/relocate.c b/arch/mips/kernel/relocate.c
    index 6d35d4f7ebe19..55fe0e8295494 100644
    --- a/arch/mips/kernel/relocate.c
    +++ b/arch/mips/kernel/relocate.c
    @@ -420,7 +420,20 @@ void *__init relocate_kernel(void)
     			goto out;
     
     		/* The current thread is now within the relocated image */
    +#ifndef CONFIG_CC_IS_CLANG
     		__current_thread_info = RELOCATED(&init_thread_union);
    +#else
    +		/*
    +		 * LLVM may wrongly restore $gp ($28) in epilog even if it's
    +		 * intentionally modified. Work around this by using inline
    +		 * assembly to assign $gp. $gp couldn't be listed as output or
    +		 * clobber, or LLVM will still restore its original value.
    +		 * See also LLVM upstream issue
    +		 * https://github.com/llvm/llvm-project/issues/176546
    +		 */
    +		asm volatile("move $28, %0" : :
    +			     "r" (RELOCATED(&init_thread_union)));
    +#endif
     
     		/* Return the new kernel's entry point */
     		kernel_entry = RELOCATED(start_kernel);
    -- 
    cgit 1.3-korg
    
    
    
e3a6498a6339

MIPS: Work around LLVM bug when gp is used as global register variable

1 file changed · +13 1
  • arch/mips/kernel/relocate.c+13 1 modified
    diff --git a/arch/mips/kernel/relocate.c b/arch/mips/kernel/relocate.c
    index cda7983e7c18d..ba3b82f0341a9 100644
    --- a/arch/mips/kernel/relocate.c
    +++ b/arch/mips/kernel/relocate.c
    @@ -420,7 +420,20 @@ void *__init relocate_kernel(void)
     			goto out;
     
     		/* The current thread is now within the relocated image */
    +#ifndef CONFIG_CC_IS_CLANG
     		__current_thread_info = RELOCATED(&init_thread_union);
    +#else
    +		/*
    +		 * LLVM may wrongly restore $gp ($28) in epilog even if it's
    +		 * intentionally modified. Work around this by using inline
    +		 * assembly to assign $gp. $gp couldn't be listed as output or
    +		 * clobber, or LLVM will still restore its original value.
    +		 * See also LLVM upstream issue
    +		 * https://github.com/llvm/llvm-project/issues/176546
    +		 */
    +		asm volatile("move $28, %0" : :
    +			     "r" (RELOCATED(&init_thread_union)));
    +#endif
     
     		/* Return the new kernel's entry point */
     		kernel_entry = RELOCATED(start_kernel);
    -- 
    cgit 1.3-korg
    
    
    
561834f6d6f5

MIPS: Work around LLVM bug when gp is used as global register variable

1 file changed · +13 1
  • arch/mips/kernel/relocate.c+13 1 modified
    diff --git a/arch/mips/kernel/relocate.c b/arch/mips/kernel/relocate.c
    index 7f1c136ad8506..59833210542ff 100644
    --- a/arch/mips/kernel/relocate.c
    +++ b/arch/mips/kernel/relocate.c
    @@ -420,7 +420,20 @@ void *__init relocate_kernel(void)
     			goto out;
     
     		/* The current thread is now within the relocated image */
    +#ifndef CONFIG_CC_IS_CLANG
     		__current_thread_info = RELOCATED(&init_thread_union);
    +#else
    +		/*
    +		 * LLVM may wrongly restore $gp ($28) in epilog even if it's
    +		 * intentionally modified. Work around this by using inline
    +		 * assembly to assign $gp. $gp couldn't be listed as output or
    +		 * clobber, or LLVM will still restore its original value.
    +		 * See also LLVM upstream issue
    +		 * https://github.com/llvm/llvm-project/issues/176546
    +		 */
    +		asm volatile("move $28, %0" : :
    +			     "r" (RELOCATED(&init_thread_union)));
    +#endif
     
     		/* Return the new kernel's entry point */
     		kernel_entry = RELOCATED(start_kernel);
    -- 
    cgit 1.3-korg
    
    
    
c0155dee51b9

MIPS: Work around LLVM bug when gp is used as global register variable

1 file changed · +13 1
  • arch/mips/kernel/relocate.c+13 1 modified
    diff --git a/arch/mips/kernel/relocate.c b/arch/mips/kernel/relocate.c
    index 6d35d4f7ebe19..55fe0e8295494 100644
    --- a/arch/mips/kernel/relocate.c
    +++ b/arch/mips/kernel/relocate.c
    @@ -420,7 +420,20 @@ void *__init relocate_kernel(void)
     			goto out;
     
     		/* The current thread is now within the relocated image */
    +#ifndef CONFIG_CC_IS_CLANG
     		__current_thread_info = RELOCATED(&init_thread_union);
    +#else
    +		/*
    +		 * LLVM may wrongly restore $gp ($28) in epilog even if it's
    +		 * intentionally modified. Work around this by using inline
    +		 * assembly to assign $gp. $gp couldn't be listed as output or
    +		 * clobber, or LLVM will still restore its original value.
    +		 * See also LLVM upstream issue
    +		 * https://github.com/llvm/llvm-project/issues/176546
    +		 */
    +		asm volatile("move $28, %0" : :
    +			     "r" (RELOCATED(&init_thread_union)));
    +#endif
     
     		/* Return the new kernel's entry point */
     		kernel_entry = RELOCATED(start_kernel);
    -- 
    cgit 1.3-korg
    
    
    
1fe3b402b1e9

MIPS: Work around LLVM bug when gp is used as global register variable

1 file changed · +13 1
  • arch/mips/kernel/relocate.c+13 1 modified
    diff --git a/arch/mips/kernel/relocate.c b/arch/mips/kernel/relocate.c
    index 56b51de2dc51b..8ca4d1f226854 100644
    --- a/arch/mips/kernel/relocate.c
    +++ b/arch/mips/kernel/relocate.c
    @@ -420,7 +420,20 @@ void *__init relocate_kernel(void)
     			goto out;
     
     		/* The current thread is now within the relocated image */
    +#ifndef CONFIG_CC_IS_CLANG
     		__current_thread_info = RELOCATED(&init_thread_union);
    +#else
    +		/*
    +		 * LLVM may wrongly restore $gp ($28) in epilog even if it's
    +		 * intentionally modified. Work around this by using inline
    +		 * assembly to assign $gp. $gp couldn't be listed as output or
    +		 * clobber, or LLVM will still restore its original value.
    +		 * See also LLVM upstream issue
    +		 * https://github.com/llvm/llvm-project/issues/176546
    +		 */
    +		asm volatile("move $28, %0" : :
    +			     "r" (RELOCATED(&init_thread_union)));
    +#endif
     
     		/* Return the new kernel's entry point */
     		kernel_entry = RELOCATED(start_kernel);
    -- 
    cgit 1.3-korg
    
    
    
30bfc2d6a113

MIPS: Work around LLVM bug when gp is used as global register variable

1 file changed · +13 1
  • arch/mips/kernel/relocate.c+13 1 modified
    diff --git a/arch/mips/kernel/relocate.c b/arch/mips/kernel/relocate.c
    index 7f1c136ad8506..59833210542ff 100644
    --- a/arch/mips/kernel/relocate.c
    +++ b/arch/mips/kernel/relocate.c
    @@ -420,7 +420,20 @@ void *__init relocate_kernel(void)
     			goto out;
     
     		/* The current thread is now within the relocated image */
    +#ifndef CONFIG_CC_IS_CLANG
     		__current_thread_info = RELOCATED(&init_thread_union);
    +#else
    +		/*
    +		 * LLVM may wrongly restore $gp ($28) in epilog even if it's
    +		 * intentionally modified. Work around this by using inline
    +		 * assembly to assign $gp. $gp couldn't be listed as output or
    +		 * clobber, or LLVM will still restore its original value.
    +		 * See also LLVM upstream issue
    +		 * https://github.com/llvm/llvm-project/issues/176546
    +		 */
    +		asm volatile("move $28, %0" : :
    +			     "r" (RELOCATED(&init_thread_union)));
    +#endif
     
     		/* Return the new kernel's entry point */
     		kernel_entry = RELOCATED(start_kernel);
    -- 
    cgit 1.3-korg
    
    
    
4dc65b40fb80

MIPS: Work around LLVM bug when gp is used as global register variable

1 file changed · +13 1
  • arch/mips/kernel/relocate.c+13 1 modified
    diff --git a/arch/mips/kernel/relocate.c b/arch/mips/kernel/relocate.c
    index 58fc8d089402b..dcc2763b39d6e 100644
    --- a/arch/mips/kernel/relocate.c
    +++ b/arch/mips/kernel/relocate.c
    @@ -420,7 +420,20 @@ void *__init relocate_kernel(void)
     			goto out;
     
     		/* The current thread is now within the relocated image */
    +#ifndef CONFIG_CC_IS_CLANG
     		__current_thread_info = RELOCATED(&init_thread_union);
    +#else
    +		/*
    +		 * LLVM may wrongly restore $gp ($28) in epilog even if it's
    +		 * intentionally modified. Work around this by using inline
    +		 * assembly to assign $gp. $gp couldn't be listed as output or
    +		 * clobber, or LLVM will still restore its original value.
    +		 * See also LLVM upstream issue
    +		 * https://github.com/llvm/llvm-project/issues/176546
    +		 */
    +		asm volatile("move $28, %0" : :
    +			     "r" (RELOCATED(&init_thread_union)));
    +#endif
     
     		/* Return the new kernel's entry point */
     		kernel_entry = RELOCATED(start_kernel);
    -- 
    cgit 1.3-korg
    
    
    
561834f6d6f5

MIPS: Work around LLVM bug when gp is used as global register variable

1 file changed · +13 1
  • arch/mips/kernel/relocate.c+13 1 modified
    diff --git a/arch/mips/kernel/relocate.c b/arch/mips/kernel/relocate.c
    index 7f1c136ad8506..59833210542ff 100644
    --- a/arch/mips/kernel/relocate.c
    +++ b/arch/mips/kernel/relocate.c
    @@ -420,7 +420,20 @@ void *__init relocate_kernel(void)
     			goto out;
     
     		/* The current thread is now within the relocated image */
    +#ifndef CONFIG_CC_IS_CLANG
     		__current_thread_info = RELOCATED(&init_thread_union);
    +#else
    +		/*
    +		 * LLVM may wrongly restore $gp ($28) in epilog even if it's
    +		 * intentionally modified. Work around this by using inline
    +		 * assembly to assign $gp. $gp couldn't be listed as output or
    +		 * clobber, or LLVM will still restore its original value.
    +		 * See also LLVM upstream issue
    +		 * https://github.com/llvm/llvm-project/issues/176546
    +		 */
    +		asm volatile("move $28, %0" : :
    +			     "r" (RELOCATED(&init_thread_union)));
    +#endif
     
     		/* Return the new kernel's entry point */
     		kernel_entry = RELOCATED(start_kernel);
    -- 
    cgit 1.3-korg
    
    
    
9bc3b0ae5203

MIPS: Work around LLVM bug when gp is used as global register variable

1 file changed · +13 1
  • arch/mips/kernel/relocate.c+13 1 modified
    diff --git a/arch/mips/kernel/relocate.c b/arch/mips/kernel/relocate.c
    index 7f1c136ad8506..59833210542ff 100644
    --- a/arch/mips/kernel/relocate.c
    +++ b/arch/mips/kernel/relocate.c
    @@ -420,7 +420,20 @@ void *__init relocate_kernel(void)
     			goto out;
     
     		/* The current thread is now within the relocated image */
    +#ifndef CONFIG_CC_IS_CLANG
     		__current_thread_info = RELOCATED(&init_thread_union);
    +#else
    +		/*
    +		 * LLVM may wrongly restore $gp ($28) in epilog even if it's
    +		 * intentionally modified. Work around this by using inline
    +		 * assembly to assign $gp. $gp couldn't be listed as output or
    +		 * clobber, or LLVM will still restore its original value.
    +		 * See also LLVM upstream issue
    +		 * https://github.com/llvm/llvm-project/issues/176546
    +		 */
    +		asm volatile("move $28, %0" : :
    +			     "r" (RELOCATED(&init_thread_union)));
    +#endif
     
     		/* Return the new kernel's entry point */
     		kernel_entry = RELOCATED(start_kernel);
    -- 
    cgit 1.3-korg
    
    
    
05bff9b0ae09

MIPS: Work around LLVM bug when gp is used as global register variable

1 file changed · +13 1
  • arch/mips/kernel/relocate.c+13 1 modified
    diff --git a/arch/mips/kernel/relocate.c b/arch/mips/kernel/relocate.c
    index dab8febb57419..5e014a457ad80 100644
    --- a/arch/mips/kernel/relocate.c
    +++ b/arch/mips/kernel/relocate.c
    @@ -399,7 +399,20 @@ void *__init relocate_kernel(void)
     			goto out;
     
     		/* The current thread is now within the relocated image */
    +#ifndef CONFIG_CC_IS_CLANG
     		__current_thread_info = RELOCATED(&init_thread_union);
    +#else
    +		/*
    +		 * LLVM may wrongly restore $gp ($28) in epilog even if it's
    +		 * intentionally modified. Work around this by using inline
    +		 * assembly to assign $gp. $gp couldn't be listed as output or
    +		 * clobber, or LLVM will still restore its original value.
    +		 * See also LLVM upstream issue
    +		 * https://github.com/llvm/llvm-project/issues/176546
    +		 */
    +		asm volatile("move $28, %0" : :
    +			     "r" (RELOCATED(&init_thread_union)));
    +#endif
     
     		/* Return the new kernel's entry point */
     		kernel_entry = RELOCATED(start_kernel);
    -- 
    cgit 1.3-korg
    
    
    
e3a6498a6339

MIPS: Work around LLVM bug when gp is used as global register variable

1 file changed · +13 1
  • arch/mips/kernel/relocate.c+13 1 modified
    diff --git a/arch/mips/kernel/relocate.c b/arch/mips/kernel/relocate.c
    index cda7983e7c18d..ba3b82f0341a9 100644
    --- a/arch/mips/kernel/relocate.c
    +++ b/arch/mips/kernel/relocate.c
    @@ -420,7 +420,20 @@ void *__init relocate_kernel(void)
     			goto out;
     
     		/* The current thread is now within the relocated image */
    +#ifndef CONFIG_CC_IS_CLANG
     		__current_thread_info = RELOCATED(&init_thread_union);
    +#else
    +		/*
    +		 * LLVM may wrongly restore $gp ($28) in epilog even if it's
    +		 * intentionally modified. Work around this by using inline
    +		 * assembly to assign $gp. $gp couldn't be listed as output or
    +		 * clobber, or LLVM will still restore its original value.
    +		 * See also LLVM upstream issue
    +		 * https://github.com/llvm/llvm-project/issues/176546
    +		 */
    +		asm volatile("move $28, %0" : :
    +			     "r" (RELOCATED(&init_thread_union)));
    +#endif
     
     		/* Return the new kernel's entry point */
     		kernel_entry = RELOCATED(start_kernel);
    -- 
    cgit 1.3-korg
    
    
    

Vulnerability mechanics

No source-code context for this CVE — mechanics is only generated when we can read the actual fix diff. Without that, the four sections (root cause, attack vector, affected code, fix) would be speculation rather than analysis.

References

8

News mentions

1