From: Michael Ellerman <mpe@ellerman.id.au> Date: 2020-03-16 15:41:49
From: Daniel Axtens <redacted>
Currently we set up the paca after parsing the device tree for CPU
features. Prior to that, r13 contains random data, which means there
is random data in r13 while we're running the generic dt parsing code.
This random data varies depending on whether we boot through a vmlinux
or a zImage: for the vmlinux case it's usually around zero, but for
zImages we see random values like 912a72603d420015.
This is poor practice, and can also lead to difficult-to-debug
crashes. For example, when kcov is enabled, the kcov instrumentation
attempts to read preempt_count out of the current task, which goes via
the paca. This then crashes in the zImage case.
Similarly stack protector can cause crashes if r13 is bogus, by
reading from the stack canary in the paca.
To resolve this:
- move the paca setup to before the CPU feature parsing.
- because we no longer have access to CPU feature flags in paca
setup, change the HV feature test in the paca setup path to consider
the actual value of the MSR rather than the CPU feature.
Translations get switched on once we leave early_setup, so I think
we'd already catch any other cases where the paca or task aren't set
up.
Boot tested on a P9 guest and host.
Fixes: fb0b0a73b223 ("powerpc: Enable kcov")
Fixes: 06ec27aea9fc ("powerpc/64: add stack protector support")
Cc: stable@vger.kernel.org # v4.20+
Reviewed-by: Andrew Donnellan <redacted>
Suggested-by: Michael Ellerman <mpe@ellerman.id.au>
Signed-off-by: Daniel Axtens <redacted>
[mpe: Reword comments & change log a bit to mention stack protector]
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
---
arch/powerpc/kernel/dt_cpu_ftrs.c | 1 -
arch/powerpc/kernel/paca.c | 10 +++++++---
arch/powerpc/kernel/setup_64.c | 30 ++++++++++++++++++++++++------
3 files changed, 31 insertions(+), 10 deletions(-)
v5: mpe: Reword comments & change log a bit to mention stack protector]
dja:
Regarding moving the comment about printk()-safety:
I am about 75% sure that the thing that makes printk() safe is the PACA,
not the CPU features. That's what commit 24d9649574fb ("[POWERPC] Document
when printk is useable") seems to indicate, but as someone wise recently
told me, "bootstrapping is hard", so I may be totally wrong.
v4: Update commit message and clarify that the mfmsr() approach is not
for general use. Thanks Nick Piggin.
v3: Update comment, thanks Christophe Leroy.
Remove a comment in dt_cpu_ftrs.c that is no longer accurate - thanks
Andrew. I think we want to retain all the code still, but I'm open to
being told otherwise.
@@ -139,7 +139,6 @@ static void __init cpufeatures_setup_cpu(void)/* Initialize the base environment -- clear FSCR/HFSCR. */hv_mode=!!(mfmsr()&MSR_HV);if(hv_mode){-/* CPU_FTR_HVMODE is used early in PACA setup */cur_cpu_spec->cpu_features|=CPU_FTR_HVMODE;mtspr(SPRN_HFSCR,0);}
@@ -214,11 +214,15 @@ void setup_paca(struct paca_struct *new_paca)/* On Book3E, initialize the TLB miss exception frames */mtspr(SPRN_SPRG_TLB_EXFRAME,local_paca->extlb);#else-/* In HV mode, we setup both HPACA and PACA to avoid problems+/*+*InHVmode,wesetupbothHPACAandPACAtoavoidproblems*ifwedoaGET_PACA()beforethefeaturefixupshavebeen-*applied+*applied.+*+*NormallyyoushouldtestagainstCPU_FTR_HVMODE,butCPUfeatures+*arenotyetsetupwhenwefirstreachhere.*/-if(early_cpu_has_feature(CPU_FTR_HVMODE))+if(mfmsr()&MSR_HV)mtspr(SPRN_SPRG_HPACA,local_paca);#endifmtspr(SPRN_SPRG_PACA,local_paca);
@@ -285,18 +285,36 @@ void __init early_setup(unsigned long dt_ptr)/* -------- printk is _NOT_ safe to use here ! ------- */-/* Try new device tree based feature discovery ... */-if(!dt_cpu_ftrs_init(__va(dt_ptr)))-/* Otherwise use the old style CPU table */-identify_cpu(0,mfspr(SPRN_PVR));--/* Assume we're on cpu 0 for now. Don't write to the paca yet! */+/*+*Assumewe'reoncpu0fornow.+*+*WeneedtoloadaPACAveryearlyforafewreasons.+*+*Thestackprotectorcanaryisstoredinthepaca,soassoonaswe+*callanystackprotectedcodeweneedr13pointingsomewherevalid.+*+*Ifweareusingkcovitwillcallin_task()initsinstrumentation,+*whichreliesonthecurrenttaskfromthePACA.+*+*dt_cpu_ftrs_init()callsintogenericOF/fdtcode,aswellas+*printk(),whichcantriggerbothstackprotectorandkcov.+*+*percpuvariablesandspinlocksalsousethepaca.+*+*Sosetupatemporarypaca.Itwillbereplacedbelowonceweknow+*whatCPUweareon.+*/initialise_paca(&boot_paca,0);setup_paca(&boot_paca);fixup_boot_paca();/* -------- printk is now safe to use ------- */+/* Try new device tree based feature discovery ... */+if(!dt_cpu_ftrs_init(__va(dt_ptr)))+/* Otherwise use the old style CPU table */+identify_cpu(0,mfspr(SPRN_PVR));+/* Enable early debugging if any specified (see udbg.h) */udbg_early_init();
From: Michael Ellerman <mpe@ellerman.id.au> Date: 2020-03-16 15:43:34
The previous commit reduced the amount of code that is run before we
setup a paca. However there are still a few remaining functions that
run with no paca, or worse, with an arbitrary value in r13 that will
be used as a paca pointer.
In particular the stack protector canary is stored in the paca, so if
stack protector is activated for any of these functions we will read
the stack canary from wherever r13 points. If r13 happens to point
outside of memory we will get a machine check / checkstop.
For example if we modify initialise_paca() to trigger stack
protection, and then boot in the mambo simulator with r13 poisoned in
skiboot before calling the kernel:
DEBUG: 19952232: (19952232): INSTRUCTION: PC=0xC0000000191FC1E8: [0x3C4C006D]: addis r2,r12,0x6D [fetch]
DEBUG: 19952236: (19952236): INSTRUCTION: PC=0xC00000001807EAD8: [0x7D8802A6]: mflr r12 [fetch]
FATAL ERROR: 19952276: (19952276): Check Stop for 0:0: Machine Check with ME bit of MSR off
DEBUG: 19952276: (19952276): INSTRUCTION: PC=0xC0000000191FCA7C: [0xE90D0CF8]: ld r8,0xCF8(r13) [Instruction Failed]
INFO: 19952276: (19952277): ** Execution stopped: Mambo Error, Machine Check Stop, **
systemsim % bt
pc: 0xC0000000191FCA7C initialise_paca+0x54
lr: 0xC0000000191FC22C early_setup+0x44
stack:0x00000000198CBED0 0x0 +0x0
stack:0x00000000198CBF00 0xC0000000191FC22C early_setup+0x44
stack:0x00000000198CBF90 0x1801C968 +0x1801C968
So annotate the relevant functions to ensure stack protection is never
enabled for them.
Fixes: 06ec27aea9fc ("powerpc/64: add stack protector support")
Cc: stable@vger.kernel.org # v4.20+
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
---
arch/powerpc/kernel/paca.c | 4 ++--
arch/powerpc/kernel/setup.h | 2 ++
arch/powerpc/kernel/setup_64.c | 2 +-
3 files changed, 5 insertions(+), 3 deletions(-)
v5: New.
@@ -205,7 +205,7 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu)}/* Put the paca pointer into r13 and SPRG_PACA */-voidsetup_paca(structpaca_struct*new_paca)+void__nostackprotectorsetup_paca(structpaca_struct*new_paca){/* Setup r13 */local_paca=new_paca;
From: Daniel Axtens <hidden> Date: 2020-03-18 12:51:04
Michael Ellerman [off-list ref] writes:
The previous commit reduced the amount of code that is run before we
setup a paca. However there are still a few remaining functions that
run with no paca, or worse, with an arbitrary value in r13 that will
be used as a paca pointer.
In particular the stack protector canary is stored in the paca, so if
stack protector is activated for any of these functions we will read
the stack canary from wherever r13 points. If r13 happens to point
outside of memory we will get a machine check / checkstop.
For example if we modify initialise_paca() to trigger stack
protection, and then boot in the mambo simulator with r13 poisoned in
skiboot before calling the kernel:
DEBUG: 19952232: (19952232): INSTRUCTION: PC=0xC0000000191FC1E8: [0x3C4C006D]: addis r2,r12,0x6D [fetch]
DEBUG: 19952236: (19952236): INSTRUCTION: PC=0xC00000001807EAD8: [0x7D8802A6]: mflr r12 [fetch]
FATAL ERROR: 19952276: (19952276): Check Stop for 0:0: Machine Check with ME bit of MSR off
DEBUG: 19952276: (19952276): INSTRUCTION: PC=0xC0000000191FCA7C: [0xE90D0CF8]: ld r8,0xCF8(r13) [Instruction Failed]
INFO: 19952276: (19952277): ** Execution stopped: Mambo Error, Machine Check Stop, **
systemsim % bt
pc: 0xC0000000191FCA7C initialise_paca+0x54
lr: 0xC0000000191FC22C early_setup+0x44
stack:0x00000000198CBED0 0x0 +0x0
stack:0x00000000198CBF00 0xC0000000191FC22C early_setup+0x44
stack:0x00000000198CBF90 0x1801C968 +0x1801C968
So annotate the relevant functions to ensure stack protection is never
enabled for them.
This all makes sense to me, although I don't really understand the stack
protector especially well.
I have checked and I can find no other C functions that are called
before early_setup.
Do we need to do add setup_64.c to the part of the Makefile that
disables tracing of early boot?
ifdef CONFIG_FUNCTION_TRACER
# Do not trace early boot code
CFLAGS_REMOVE_cputable.o = $(CC_FLAGS_FTRACE)
CFLAGS_REMOVE_prom_init.o = $(CC_FLAGS_FTRACE)
CFLAGS_REMOVE_btext.o = $(CC_FLAGS_FTRACE)
CFLAGS_REMOVE_prom.o = $(CC_FLAGS_FTRACE)
-> should we add setup_64.c here?
endif
Regards,
Daniel
@@ -205,7 +205,7 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu)}/* Put the paca pointer into r13 and SPRG_PACA */-voidsetup_paca(structpaca_struct*new_paca)+void__nostackprotectorsetup_paca(structpaca_struct*new_paca){/* Setup r13 */local_paca=new_paca;
From: Michael Ellerman <mpe@ellerman.id.au> Date: 2020-03-19 04:37:58
Daniel Axtens [off-list ref] writes:
Michael Ellerman [off-list ref] writes:
quoted
The previous commit reduced the amount of code that is run before we
setup a paca. However there are still a few remaining functions that
run with no paca, or worse, with an arbitrary value in r13 that will
be used as a paca pointer.
In particular the stack protector canary is stored in the paca, so if
stack protector is activated for any of these functions we will read
the stack canary from wherever r13 points. If r13 happens to point
outside of memory we will get a machine check / checkstop.
For example if we modify initialise_paca() to trigger stack
protection, and then boot in the mambo simulator with r13 poisoned in
skiboot before calling the kernel:
DEBUG: 19952232: (19952232): INSTRUCTION: PC=0xC0000000191FC1E8: [0x3C4C006D]: addis r2,r12,0x6D [fetch]
DEBUG: 19952236: (19952236): INSTRUCTION: PC=0xC00000001807EAD8: [0x7D8802A6]: mflr r12 [fetch]
FATAL ERROR: 19952276: (19952276): Check Stop for 0:0: Machine Check with ME bit of MSR off
DEBUG: 19952276: (19952276): INSTRUCTION: PC=0xC0000000191FCA7C: [0xE90D0CF8]: ld r8,0xCF8(r13) [Instruction Failed]
INFO: 19952276: (19952277): ** Execution stopped: Mambo Error, Machine Check Stop, **
systemsim % bt
pc: 0xC0000000191FCA7C initialise_paca+0x54
lr: 0xC0000000191FC22C early_setup+0x44
stack:0x00000000198CBED0 0x0 +0x0
stack:0x00000000198CBF00 0xC0000000191FC22C early_setup+0x44
stack:0x00000000198CBF90 0x1801C968 +0x1801C968
So annotate the relevant functions to ensure stack protection is never
enabled for them.
This all makes sense to me, although I don't really understand the stack
protector especially well.
The key details for this bug are that 1) some functions get stack
protection, if they have on-stack buffers etc. 2) that stack protection
involves reading a canary from the paca.
I have checked and I can find no other C functions that are called
before early_setup.
Thanks.
Except for all of prom_init.c but that's already built with no stack
protector.
Do we need to do add setup_64.c to the part of the Makefile that
disables tracing of early boot?
ifdef CONFIG_FUNCTION_TRACER
# Do not trace early boot code
CFLAGS_REMOVE_cputable.o = $(CC_FLAGS_FTRACE)
CFLAGS_REMOVE_prom_init.o = $(CC_FLAGS_FTRACE)
CFLAGS_REMOVE_btext.o = $(CC_FLAGS_FTRACE)
CFLAGS_REMOVE_prom.o = $(CC_FLAGS_FTRACE)
-> should we add setup_64.c here?
endif
No I don't think so.
Tracing is less of a concern during very early boot because although the
functions may be built to support tracing, you can't actually turn
tracing *on* that early.
Also setup_64.c is not purely early boot code, there are some functions
in there we would like to be able to trace.
As I was saying the other day, we may want to create a specific
directory (or file) for all the really early boot code where we turn off
all special options like tracing, kcov, stack protector etc.
cheers