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
2Patches
169bc3b0ae5203MIPS: Work around LLVM bug when gp is used as global register variable
1 file changed · +13 −1
arch/mips/kernel/relocate.c+13 −1 modifieddiff --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
30bfc2d6a113MIPS: Work around LLVM bug when gp is used as global register variable
1 file changed · +13 −1
arch/mips/kernel/relocate.c+13 −1 modifieddiff --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
05bff9b0ae09MIPS: Work around LLVM bug when gp is used as global register variable
1 file changed · +13 −1
arch/mips/kernel/relocate.c+13 −1 modifieddiff --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
1fe3b402b1e9MIPS: Work around LLVM bug when gp is used as global register variable
1 file changed · +13 −1
arch/mips/kernel/relocate.c+13 −1 modifieddiff --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
4dc65b40fb80MIPS: Work around LLVM bug when gp is used as global register variable
1 file changed · +13 −1
arch/mips/kernel/relocate.c+13 −1 modifieddiff --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
c0155dee51b9MIPS: Work around LLVM bug when gp is used as global register variable
1 file changed · +13 −1
arch/mips/kernel/relocate.c+13 −1 modifieddiff --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
e3a6498a6339MIPS: Work around LLVM bug when gp is used as global register variable
1 file changed · +13 −1
arch/mips/kernel/relocate.c+13 −1 modifieddiff --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
561834f6d6f5MIPS: Work around LLVM bug when gp is used as global register variable
1 file changed · +13 −1
arch/mips/kernel/relocate.c+13 −1 modifieddiff --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
c0155dee51b9MIPS: Work around LLVM bug when gp is used as global register variable
1 file changed · +13 −1
arch/mips/kernel/relocate.c+13 −1 modifieddiff --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
1fe3b402b1e9MIPS: Work around LLVM bug when gp is used as global register variable
1 file changed · +13 −1
arch/mips/kernel/relocate.c+13 −1 modifieddiff --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
30bfc2d6a113MIPS: Work around LLVM bug when gp is used as global register variable
1 file changed · +13 −1
arch/mips/kernel/relocate.c+13 −1 modifieddiff --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
4dc65b40fb80MIPS: Work around LLVM bug when gp is used as global register variable
1 file changed · +13 −1
arch/mips/kernel/relocate.c+13 −1 modifieddiff --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
561834f6d6f5MIPS: Work around LLVM bug when gp is used as global register variable
1 file changed · +13 −1
arch/mips/kernel/relocate.c+13 −1 modifieddiff --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
9bc3b0ae5203MIPS: Work around LLVM bug when gp is used as global register variable
1 file changed · +13 −1
arch/mips/kernel/relocate.c+13 −1 modifieddiff --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
05bff9b0ae09MIPS: Work around LLVM bug when gp is used as global register variable
1 file changed · +13 −1
arch/mips/kernel/relocate.c+13 −1 modifieddiff --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
e3a6498a6339MIPS: Work around LLVM bug when gp is used as global register variable
1 file changed · +13 −1
arch/mips/kernel/relocate.c+13 −1 modifieddiff --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- git.kernel.org/stable/c/05bff9b0ae095b2420cfebb4a96759a09334bec6nvd
- git.kernel.org/stable/c/1fe3b402b1e97a1718df3be0a1d3eee20133e735nvd
- git.kernel.org/stable/c/30bfc2d6a1132a89a5f1c3b96c59cf3e4d076ea3nvd
- git.kernel.org/stable/c/4dc65b40fb80c2020efbf139b9a38d30f9a37b92nvd
- git.kernel.org/stable/c/561834f6d6f52b8a1791331e94b2aac753491d2anvd
- git.kernel.org/stable/c/9bc3b0ae5203aba650297fdf3e1e774125e423f2nvd
- git.kernel.org/stable/c/c0155dee51b9f5f48aaf5c71cae005eb0e36521fnvd
- git.kernel.org/stable/c/e3a6498a63394218561065a9a7a597a204f52f6anvd
News mentions
1- Linux Kernel: 25 Vulnerabilities Disclosed in Single Batch on June 3, 2026Vypr Intelligence · Jun 3, 2026