From: Huacai Chen chenhuacai@loongson.cn
[ Upstream commit d5be446948b379f1d1a8e7bc6656d13f44c5c7b1 ]
For 32BIT platform _PAGE_PROTNONE is 0, so set a VMA to be VM_NONE or VM_SHARED will make pages non-present, then cause Oops with kernel page fault.
Fix it by set correct protection_map[] for VM_NONE/VM_SHARED, replacing _PAGE_PROTNONE with _PAGE_PRESENT.
Signed-off-by: Huacai Chen chenhuacai@loongson.cn Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
## Analysis of LoongArch protection_map[] Fix
### 1. COMMIT MESSAGE ANALYSIS
The commit message clearly describes: - **Problem:** On 32-bit LoongArch platforms, `_PAGE_PROTNONE` is 0 - **Symptom:** Setting a VMA to VM_NONE or VM_SHARED makes pages non- present - **Impact:** **Oops with kernel page fault** - this is a crash
Keywords present: "Oops", "page fault" - these are strong indicators of a crash-level bug.
### 2. CODE CHANGE ANALYSIS
The fix modifies the `protection_map[16]` array in `arch/loongarch/mm/cache.c`:
**For `[VM_NONE]` and `[VM_SHARED]` entries:** ```c // Before: _PAGE_PROTNONE | _PAGE_NO_EXEC | _PAGE_NO_READ
// After: _PAGE_NO_EXEC | _PAGE_NO_READ | (_PAGE_PROTNONE ? : _PAGE_PRESENT) ```
**Technical mechanism of the bug:** - `_PAGE_PROTNONE` is a page table bit meant to mark pages that should fault on userspace access but remain valid to the kernel - On LoongArch 32-bit, `_PAGE_PROTNONE` is defined as 0 - When `_PAGE_PROTNONE` is 0, ORing it into the protection flags contributes nothing - Without any "present" bit set, pages are completely non-present - Any access (even from kernel) triggers a page fault → kernel Oops
**The fix logic:** Using GNU C extension: `(_PAGE_PROTNONE ? : _PAGE_PRESENT)` means: - If `_PAGE_PROTNONE` is non-zero → use `_PAGE_PROTNONE` - If `_PAGE_PROTNONE` is 0 → use `_PAGE_PRESENT` as fallback
This ensures pages always have a valid presence indication regardless of platform configuration.
### 3. CLASSIFICATION
- **Bug Fix:** Yes - fixes a kernel crash - **Feature Addition:** No - **Exception Category:** N/A - this is a straightforward crash fix
### 4. SCOPE AND RISK ASSESSMENT
| Metric | Assessment | |--------|------------| | Lines changed | ~4 lines (minimal) | | Files touched | 1 file | | Complexity | Very low - simple conditional | | Subsystem | LoongArch MM (architecture-specific) | | Blast radius | Limited to LoongArch 32-bit only |
**Risk:** Very low. The change is: - Architecture-specific (won't affect x86, ARM, etc.) - Surgical and contained - Uses well-understood pattern
### 5. USER IMPACT
- **Affected users:** LoongArch 32-bit platform users - **Severity:** High - kernel Oops/crash - **Trigger condition:** Basic VM operations with VM_NONE or VM_SHARED - This affects fundamental memory protection functionality
### 6. STABILITY INDICATORS
- Signed-off by Huacai Chen (LoongArch architecture maintainer) - The fix is straightforward and obviously correct
### 7. DEPENDENCY CHECK
- Self-contained fix - No dependencies on other commits - LoongArch has been in mainline since kernel 5.19
### STABLE TREE CRITERIA EVALUATION
| Criterion | Met? | |-----------|------| | Obviously correct and tested | ✅ Yes - logic is clear | | Fixes a real bug | ✅ Yes - kernel Oops | | Fixes important issue | ✅ Yes - crash | | Small and contained | ✅ Yes - 4 lines, 1 file | | No new features | ✅ Yes | | Applies cleanly | ✅ Likely (straightforward) |
### CONCLUSION
This is a textbook stable-worthy commit: - **Fixes a kernel Oops/crash** on LoongArch 32-bit platforms - **Minimal change** - only 4 lines modified in a single architecture- specific file - **Obviously correct** - the conditional expression correctly handles both 32-bit and 64-bit cases - **Zero risk to other architectures** - completely LoongArch-specific - **Low risk even within LoongArch** - the fix is surgical and well- understood
The benefit (preventing kernel crashes) clearly outweighs the minimal risk. This should be backported to any stable tree containing LoongArch support (5.19+).
**YES**
arch/loongarch/mm/cache.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/arch/loongarch/mm/cache.c b/arch/loongarch/mm/cache.c index 6be04d36ca07..496916845ff7 100644 --- a/arch/loongarch/mm/cache.c +++ b/arch/loongarch/mm/cache.c @@ -160,8 +160,8 @@ void cpu_cache_init(void)
static const pgprot_t protection_map[16] = { [VM_NONE] = __pgprot(_CACHE_CC | _PAGE_USER | - _PAGE_PROTNONE | _PAGE_NO_EXEC | - _PAGE_NO_READ), + _PAGE_NO_EXEC | _PAGE_NO_READ | + (_PAGE_PROTNONE ? : _PAGE_PRESENT)), [VM_READ] = __pgprot(_CACHE_CC | _PAGE_VALID | _PAGE_USER | _PAGE_PRESENT | _PAGE_NO_EXEC), @@ -180,8 +180,8 @@ static const pgprot_t protection_map[16] = { [VM_EXEC | VM_WRITE | VM_READ] = __pgprot(_CACHE_CC | _PAGE_VALID | _PAGE_USER | _PAGE_PRESENT), [VM_SHARED] = __pgprot(_CACHE_CC | _PAGE_USER | - _PAGE_PROTNONE | _PAGE_NO_EXEC | - _PAGE_NO_READ), + _PAGE_NO_EXEC | _PAGE_NO_READ | + (_PAGE_PROTNONE ? : _PAGE_PRESENT)), [VM_SHARED | VM_READ] = __pgprot(_CACHE_CC | _PAGE_VALID | _PAGE_USER | _PAGE_PRESENT | _PAGE_NO_EXEC),