powerpc/pseries: Fix use after free in remove_phb_dynamic()
In remove_phb_dynamic() we use &phb->io_resource, after we've called
device_unregister(&host_bridge->dev). But the unregister may have freed
phb, because pcibios_free_controller_deferred() is the release function
for the host_bridge.
If there are no outstanding references when we call device_unregister()
then phb will be freed out from under us.
This has gone mainly unnoticed, but with slub_debug and page_poison
enabled it can lead to a crash:
PID: 7574 TASK:
c0000000d492cb80 CPU: 13 COMMAND: "drmgr"
#0 [
c0000000e4f075a0] crash_kexec at
c00000000027d7dc
#1 [
c0000000e4f075d0] oops_end at
c000000000029608
#2 [
c0000000e4f07650] __bad_page_fault at
c0000000000904b4
#3 [
c0000000e4f076c0] do_bad_slb_fault at
c00000000009a5a8
#4 [
c0000000e4f076f0] data_access_slb_common_virt at
c000000000008b30
Data SLB Access [380] exception frame:
R0:
c000000000167250 R1:
c0000000e4f07a00 R2:
c000000002a46100
R3:
c000000002b39ce8 R4:
00000000000000c0 R5:
00000000000000a9
R6:
3894674d000000c0 R7:
0000000000000000 R8:
00000000000000ff
R9:
0000000000000100 R10:
6b6b6b6b6b6b6b6b R11:
0000000000008000
R12:
c00000000023da80 R13:
c0000009ffd38b00 R14:
0000000000000000
R15:
000000011c87f0f0 R16:
0000000000000006 R17:
0000000000000003
R18:
0000000000000002 R19:
0000000000000004 R20:
0000000000000005
R21:
000000011c87ede8 R22:
000000011c87c5a8 R23:
000000011c87d3a0
R24:
0000000000000000 R25:
0000000000000001 R26:
c0000000e4f07cc8
R27:
c00000004d1cc400 R28:
c0080000031d00e8 R29:
c00000004d23d800
R30:
c00000004d1d2400 R31:
c00000004d1d2540
NIP:
c000000000167258 MSR:
8000000000009033 OR3:
c000000000e9f474
CTR:
0000000000000000 LR:
c000000000167250 XER:
0000000020040003
CCR:
0000000024088420 MQ:
0000000000000000 DAR:
6b6b6b6b6b6b6ba3
DSISR:
c0000000e4f07920 Syscall Result:
fffffffffffffff2
[NIP : release_resource+56]
[LR : release_resource+48]
#5 [
c0000000e4f07a00] release_resource at
c000000000167258 (unreliable)
#6 [
c0000000e4f07a30] remove_phb_dynamic at
c000000000105648
#7 [
c0000000e4f07ab0] dlpar_remove_slot at
c0080000031a09e8 [rpadlpar_io]
#8 [
c0000000e4f07b50] remove_slot_store at
c0080000031a0b9c [rpadlpar_io]
#9 [
c0000000e4f07be0] kobj_attr_store at
c000000000817d8c
#10 [
c0000000e4f07c00] sysfs_kf_write at
c00000000063e504
#11 [
c0000000e4f07c20] kernfs_fop_write_iter at
c00000000063d868
#12 [
c0000000e4f07c70] new_sync_write at
c00000000054339c
#13 [
c0000000e4f07d10] vfs_write at
c000000000546624
#14 [
c0000000e4f07d60] ksys_write at
c0000000005469f4
#15 [
c0000000e4f07db0] system_call_exception at
c000000000030840
#16 [
c0000000e4f07e10] system_call_vectored_common at
c00000000000c168
To avoid it, we can take a reference to the host_bridge->dev until we're
done using phb. Then when we drop the reference the phb will be freed.
Fixes: 2dd9c11b9d4d ("powerpc/pseries: use pci_host_bridge.release_fn() to kfree(phb)")
Reported-by: David Dai <zdai@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Tested-by: Sachin Sant <sachinp@linux.ibm.com>
Link: https://lore.kernel.org/r/20220318034219.1188008-1-mpe@ellerman.id.au