From: Johannes Berg johannes.berg@intel.com
[ Upstream commit 7b5d4416964c07c902163822a30a622111172b01 ]
This is currently done in uml_finishsetup(), but e.g. with KCOV enabled we'll crash because some init code can call into e.g. memparse(), which has coverage annotations, and then the checks in check_kcov_mode() crash because current is NULL.
Simply initialize the cpu_tasks[] array statically, which fixes the crash. For the later SMP work, it seems to have not really caused any problems yet, but initialize all of the entries anyway.
Link: https://patch.msgid.link/20250924113214.c76cd74d0583.I974f691ebb1a2b47915bd2... Signed-off-by: Johannes Berg johannes.berg@intel.com Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
## Analysis Summary
### Bug Mechanism
This commit fixes a **boot crash** in User Mode Linux (UML) when KCOV (kernel code coverage) is enabled:
1. **Root cause**: In UML, `current` is defined as `cpu_tasks[0]` (see `arch/um/include/asm/current.h:15`) 2. **Problem**: `cpu_tasks[]` was uninitialized (NULL) until `uml_finishsetup()` was called late in boot 3. **Trigger**: With KCOV enabled, early init code calls coverage- annotated functions like `memparse()` 4. **Crash path**: KCOV's `__sanitizer_cov_trace_pc` → `check_kcov_mode(current)` → dereferences NULL `current` → crash
### The Fix
The fix is elegantly simple: - **Before**: `struct task_struct *cpu_tasks[NR_CPUS];` (zero- initialized, i.e., NULL) - **After**: `struct task_struct *cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = &init_task };`
This ensures `current` is valid (`&init_task`) from the very start of kernel execution. The runtime initialization in `uml_finishsetup()` is removed since it's now redundant.
### Stable Criteria Assessment
| Criteria | Assessment | |----------|------------| | Fixes a real bug? | **YES** - Boot crash with KCOV enabled | | Obviously correct? | **YES** - Same value (`&init_task`), just initialized earlier | | Small and contained? | **YES** - 2 files, +3/-3 lines, net -1 | | No new features? | **YES** - Pure bug fix | | Low regression risk? | **YES** - Identical initialization, just at compile time | | Self-contained? | **YES** - No dependencies on other patches |
### Risk Assessment
- **Risk**: Very low. The initialization value is exactly what was done before in `uml_finishsetup()`, just done statically at compile time instead of at runtime. - **Scope**: Limited to UML architecture only - **Impact**: Fixes complete boot failure for UML+KCOV users
### Concerns
- No explicit `Cc: stable@vger.kernel.org` tag - No `Fixes:` tag to identify when bug was introduced - Affects only UML users (niche architecture, but important for kernel testing/development)
### Conclusion
This is a textbook stable backport candidate: - Fixes a real, reproducible crash (not theoretical) - The fix is minimal, surgical, and obviously correct - Zero risk of introducing regressions since the same value is used, just initialized earlier - The infrastructure (`init_task`, `cpu_tasks[]`) has existed in stable trees for years
The lack of explicit stable tags appears to be an oversight. The fix is appropriate for any stable tree that has both UML support and KCOV support.
**YES**
arch/um/kernel/process.c | 4 +++- arch/um/kernel/um_arch.c | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 9c9c66dc45f05..13d461712c997 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -43,7 +43,9 @@ * cares about its entry, so it's OK if another processor is modifying its * entry. */ -struct task_struct *cpu_tasks[NR_CPUS]; +struct task_struct *cpu_tasks[NR_CPUS] = { + [0 ... NR_CPUS - 1] = &init_task, +}; EXPORT_SYMBOL(cpu_tasks);
void free_stack(unsigned long stack, int order) diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index cfbbbf8500c34..ed2f67848a50e 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -239,8 +239,6 @@ static struct notifier_block panic_exit_notifier = {
void uml_finishsetup(void) { - cpu_tasks[0] = &init_task; - atomic_notifier_chain_register(&panic_notifier_list, &panic_exit_notifier);