NULL pointer dereference when configuring multi-function with devfn != 0 before devfn == 0
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
Ubuntu on IBM z Systems |
Fix Released
|
Medium
|
Skipper Bug Screeners | ||
linux (Ubuntu) |
Fix Released
|
Undecided
|
Frank Heimes | ||
Focal |
Fix Released
|
Medium
|
Unassigned | ||
Groovy |
Fix Released
|
Medium
|
Unassigned | ||
Hirsute |
Fix Released
|
Undecided
|
Frank Heimes |
Bug Description
SRU Justification:
==================
[Impact]
* While handling multifunction devices in zPCI the UID of the PCI function with function number 0 (that always exists according to the PCI spec) is taken as domain number.
* Therefore if hot plugging functions with a function number larger than 0 are used before function 0, these need to be held in standby before creating the domain and bus.
* This has been tested during development of this feature using a patched QEMU and in DPM, but unfortunately never in classic/traditional HMC mode.
* On a classic/traditional mode machine with a multi-function device, and hot plug ("Reassign I/O Path") of the FID of the second port of the LPAR, any additional hotplug (and even just deconfiguring a PCI device) will hang - and hotplug now makes the entire Linux instance unresponsive.
* The reason for this is a NULL pointer dereference - inc case configuring multi-function with devfn != 0 before devfn == 0.
* This issue was introduced with the topology-aware PCI enumeration code.
[Fix]
* 0b2ca2c7d0c9e27
[Test Case]
* IBM Z or LinuxONE hardware, equipped with hot-pluggable, multi-functional PCIe cards (like for example RoCE Express 2 adapters) in classic/traditional mode.
* An Ubuntu OS running in LPAR, that comes with a kernel that includes the topology-aware PCI enumeration code (like for example 20.04.1 w/o further updates or 20.10 GA kernel).
* Now on a system that is in classic/traditional mode, hot plug ("Reassign I/O Path") a multi-function device, but using the FID of the second port.
[Regression Potential]
* There is at least some regression risk, but I consider it as low, because:
* Even is the modification is a single if statement (that spans two lines) in 'zpci_event_
* In such a case no enabling / disabling of devices would be possible.
* But the fix is very simple and straight-forward, it checks zdev->zbus->bus for being NULL and in such a case break the function - means breaking instead of calling the PCI common code pci_scan_
* PCIe devices are usually more optional devices on s390x (compared to CCW and OSA devices for network) and this affects the zPCI subsystem only, which is unique to s390x.
[Other]
* The patch got upstream accepted with kernel v5.10-rc3, hence it will land sooner or later in Hirsute.
* It was initially planned to address groovy via 5.8 upstream stable update, and in fact the patch was already marked for this, but it didn't made it because 5.8 reached it's EOL already.
* Hence in addition to the already submitted SRU for focal, this is now a separate SRU for groovy.
__________
Background:
When handling multifunction devices in zPCI we take the
UID of the PCI function with function number 0
(that always exists according to the PCI spec)
as domain number.
Therefore when hot plugging functions with function
number larger than 0 before function 0, we need
to hold these in standby before creating the
domain and bus.
This has been tested during feature development
using a patched QEMU and with DPM but never in Classic
Mode.
Reproduction:
This issue was introduced with the Topology aware PCI
Enumeration code so test with a Linux supporting
that feature. E.g. Upstream, Devel Driver etc.
On a Classic Mode machine with a multi-function device,
hot plug ("Reassign I/O Path") only the FID of the
second port to the LPAR.
Symptom:
After this any additional hotplug and even just
deconfiguring a PCI device will hang. A hotplug
makes the entire Linux instance unresponsive.
Analysis:
The problem occurs in Classic Mode but not with
previous testing as the LPAR hypervisor does
hot plug/Reassign I/O Path as a two step process:
1. zPCI event with PEC 0x0302 to plug the zPCI function in Standby
2. zPCI event with PEC 0x0301 to configure the zPCI function
For the first event we create the zdev in clp_add_
in Standby which is all fine so far.
The problem then occurs in step 2 as we then find
the existing zdev and try to configure it.
This however does not work as the PCI bus
is not yet created (as we still don't know the UID of
function 0 that will become its domain).
The bus pointer zdev->zbus->bus pointer is thus still
NULL but will be accessed by common code which
inevitably results in disaster including
the above mentioned hang and (possibly) the below
RCU stall:
[ 689.724703] rcu: INFO: rcu_sched self-detected stall on CPU
[ 689.724712] rcu: 16-....: (42004 ticks this GP) idle=6ee/
[ 689.724742] (t=42006 jiffies g=89 q=3770)
[ 689.724743] Task dump for CPU 16:
[ 689.724745] task:kmcheck state:R running task stack: 0 pid: 205 ppid: 2 flags:0x00000004
[ 689.724747] Call Trace:
[ 689.724757] [<0000000ccde0b
[ 689.724762] [<0000000ccd0da
[ 689.724764] [<0000000ccde0e
[ 689.724767] [<0000000ccd146
[ 689.724768] [<0000000ccd14a
[ 689.724771] [<0000000ccd15c
[ 689.724775] [<0000000ccd176
[ 689.724777] [<0000000ccd15d
[ 689.724779] [<0000000ccd160
[ 689.724782] [<0000000ccd045
[ 689.724784] [<0000000ccde2b
[ 689.724790] [<0000000ccd9f3
[ 689.724794] [<0000000ccd9dc
[ 689.724797] [<0000000ccd086
[ 689.724800] [<0000000ccdd40
[ 689.724802] [<0000000ccdd4b
[ 689.724804] [<0000000ccd0ca
[ 689.724805] [<0000000ccde2b
The fix is very simple, we check zdev->zbus->bus
for being NULL and in that case bail from the
case 0x0301 before calling the PCI common code
pci_scan_
The only subtlety is that we still need to
do the zpci_enable_
code in arch/s390/
that it can immediately do a scan of
all devfn != 0 PCI functions once
PCI function 0 is found.
It thereby mimics what happens
when we only find the FID for a function with
devfn != 0 in the CLP List PCI Functions.
This is implemented in the following upstream
commit:
0b2ca2c7d0c9e27
It is included in v5.10-rc3 and has been tagged for
stable > v5.8 i.e. all upstream versions with
the PCI enumeration changes.
Also it carries the appropriate Fixes tag.
I have verified that it cherry-picks cleanly
on current focal master-next and expect
it to cleanly cherry-pick on newer Ubuntu
Kernels too.
CVE References
tags: | added: architecture-s39064 bugnameltc-189163 severity-medium targetmilestone-inin2010 |
Changed in ubuntu: | |
assignee: | nobody → Skipper Bug Screeners (skipper-screen-team) |
affects: | ubuntu → linux (Ubuntu) |
Changed in ubuntu-z-systems: | |
importance: | Undecided → Medium |
Changed in ubuntu-z-systems: | |
assignee: | nobody → Skipper Bug Screeners (skipper-screen-team) |
Changed in linux (Ubuntu): | |
assignee: | Skipper Bug Screeners (skipper-screen-team) → Frank Heimes (fheimes) |
Changed in ubuntu-z-systems: | |
status: | New → Triaged |
Changed in linux (Ubuntu Hirsute): | |
assignee: | Frank Heimes (fheimes) → nobody |
Changed in linux (Ubuntu Focal): | |
assignee: | nobody → Frank Heimes (fheimes) |
summary: |
- [UBUNTU 20.10] NULL pointer dereference when configuring multi-function - with devfn != 0 before devfn == 0 + NULL pointer dereference when configuring multi-function with devfn != 0 + before devfn == 0 |
Changed in linux (Ubuntu Focal): | |
importance: | Undecided → Medium |
status: | In Progress → Fix Committed |
Changed in ubuntu-z-systems: | |
status: | Triaged → In Progress |
Changed in linux (Ubuntu Groovy): | |
importance: | Undecided → Medium |
Changed in linux (Ubuntu Groovy): | |
assignee: | Frank Heimes (fheimes) → nobody |
Changed in linux (Ubuntu Groovy): | |
status: | In Progress → Fix Committed |
Changed in ubuntu-z-systems: | |
status: | In Progress → Fix Committed |
Changed in linux (Ubuntu Hirsute): | |
status: | Triaged → Fix Committed |
Changed in ubuntu-z-systems: | |
status: | Fix Committed → Fix Released |
Ok, I can see that the commit got accepted with 5.10-rc3, hence it will land in hirsute.
And because the patch was tagged as stable for 5.8, it will land in groovy's kernel 5.8 (I'll check the 'Groovy update: v5.8.x upstream stable release' kernel team tracking tickets and will align the status).
Remaining todo is to cherry-pick and manually SRU to focal/5.4.