CVE-2020-11669: Insufficient Information (NVD-CWE-noinfo)
value: An issue was discovered in the Linux kernel before 5.2 on the powerpc platform. arch/powerpc/kernel/idle_book3s.S does not have save/restore functionality for PNV_POWERSAVE_AMR, PNV_POWERSAVE_UAMOR, and PNV_POWERSAVE_AMOR, aka CID-53a712bae5dd.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
CVSS v3 base score: 5.5
Published: 2020-04-10T15:15Z
Repository: https://github.com/torvalds/linux
Language: Other
Files changed: arch/powerpc/kernel/idle_book3s.S
Commit date: 2019-04-21 23:05:54 +1000
Commit message: powerpc/powernv/idle: Restore AMR/UAMOR/AMOR after idle

In order to implement KUAP (Kernel Userspace Access Protection) on
Power9 we will be using the AMR, and therefore indirectly the
UAMOR/AMOR.

So save/restore these regs in the idle code.

Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>

Diff: diff --git a/arch/powerpc/kernel/idle_book3s.S b/arch/powerpc/kernel/idle_book3s.S
index 36178000a2f2..4a860d3b9229 100644
--- a/arch/powerpc/kernel/idle_book3s.S
+++ b/arch/powerpc/kernel/idle_book3s.S
@@ -168,12 +168,15 @@ core_idle_lock_held:
 	lwarx	r15,0,r14
 	andis.	r9,r15,PNV_CORE_IDLE_LOCK_BIT@h
 	bne-	core_idle_lock_held
 	blr
 
-/* Reuse an unused pt_regs slot for IAMR */
+/* Reuse some unused pt_regs slots for AMR/IAMR/UAMOR/UAMOR */
+#define PNV_POWERSAVE_AMR	_TRAP
 #define PNV_POWERSAVE_IAMR	_DAR
+#define PNV_POWERSAVE_UAMOR	_DSISR
+#define PNV_POWERSAVE_AMOR	RESULT
 
 /*
  * Pass requested state in r3:
  *	r3 - PNV_THREAD_NAP/SLEEP/WINKLE in POWER8
  *	   - Requested PSSCR value in POWER9
@@ -203,12 +206,20 @@ pnv_powersave_common:
 	/* Continue saving state */
 	SAVE_GPR(2, r1)
 	SAVE_NVGPRS(r1)
 
 BEGIN_FTR_SECTION
+	mfspr	r4, SPRN_AMR
 	mfspr	r5, SPRN_IAMR
+	mfspr	r6, SPRN_UAMOR
+	std	r4, PNV_POWERSAVE_AMR(r1)
 	std	r5, PNV_POWERSAVE_IAMR(r1)
+	std	r6, PNV_POWERSAVE_UAMOR(r1)
+BEGIN_FTR_SECTION_NESTED(42)
+	mfspr	r7, SPRN_AMOR
+	std	r7, PNV_POWERSAVE_AMOR(r1)
+END_FTR_SECTION_NESTED_IFSET(CPU_FTR_HVMODE, 42)
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
 
 	mfcr	r5
 	std	r5,_CCR(r1)
 	std	r1,PACAR1(r13)
@@ -933,16 +944,24 @@ BEGIN_FTR_SECTION
 END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
 	REST_NVGPRS(r1)
 	REST_GPR(2, r1)
 
 BEGIN_FTR_SECTION
-	/* IAMR was saved in pnv_powersave_common() */
+	/* These regs were saved in pnv_powersave_common() */
+	ld	r4, PNV_POWERSAVE_AMR(r1)
 	ld	r5, PNV_POWERSAVE_IAMR(r1)
+	ld	r6, PNV_POWERSAVE_UAMOR(r1)
+	mtspr	SPRN_AMR, r4
 	mtspr	SPRN_IAMR, r5
+	mtspr	SPRN_UAMOR, r6
+BEGIN_FTR_SECTION_NESTED(42)
+	ld	r7, PNV_POWERSAVE_AMOR(r1)
+	mtspr	SPRN_AMOR, r7
+END_FTR_SECTION_NESTED_IFSET(CPU_FTR_HVMODE, 42)
 	/*
-	 * We don't need an isync here because the upcoming mtmsrd is
-	 * execution synchronizing.
+	 * We don't need an isync here after restoring IAMR because the upcoming
+	 * mtmsrd is execution synchronizing.
 	 */
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
 
 	ld	r4,PACAKMSR(r13)
 	ld	r5,_LINK(r1)

Vulnerable code: /* Reuse an unused pt_regs slot for IAMR */
	/* IAMR was saved in pnv_powersave_common() */
	 * We don't need an isync here because the upcoming mtmsrd is
	 * execution synchronizing.
Fixed code: /* Reuse some unused pt_regs slots for AMR/IAMR/UAMOR/UAMOR */
#define PNV_POWERSAVE_AMR	_TRAP
#define PNV_POWERSAVE_UAMOR	_DSISR
#define PNV_POWERSAVE_AMOR	RESULT
	mfspr	r4, SPRN_AMR
	mfspr	r6, SPRN_UAMOR
	std	r4, PNV_POWERSAVE_AMR(r1)
	std	r6, PNV_POWERSAVE_UAMOR(r1)
BEGIN_FTR_SECTION_NESTED(42)
	mfspr	r7, SPRN_AMOR
	std	r7, PNV_POWERSAVE_AMOR(r1)
END_FTR_SECTION_NESTED_IFSET(CPU_FTR_HVMODE, 42)
	/* These regs were saved in pnv_powersave_common() */
	ld	r4, PNV_POWERSAVE_AMR(r1)
	ld	r6, PNV_POWERSAVE_UAMOR(r1)
	mtspr	SPRN_AMR, r4
	mtspr	SPRN_UAMOR, r6
BEGIN_FTR_SECTION_NESTED(42)
	ld	r7, PNV_POWERSAVE_AMOR(r1)
	mtspr	SPRN_AMOR, r7
END_FTR_SECTION_NESTED_IFSET(CPU_FTR_HVMODE, 42)
	 * We don't need an isync here after restoring IAMR because the upcoming
	 * mtmsrd is execution synchronizing.