pcifront_common_process() handles an AER request from the backend by dispatching on aer_op.cmd to the bound driver's PCI error handler. It only checks that err_handler and err_handler->error_detected are present, then for the mmio_enabled, slot_reset and resume commands it calls the corresponding callback unconditionally. Those three callbacks are optional -- the PCI core NULL-checks each of them individually before use -- and many drivers (for example igb, igc, ice and ixgbevf) install error_detected without all of them. aer_op.cmd comes from the shared ring, so a malicious or buggy backend can send XEN_PCI_OP_aer_mmio (or _slotreset/_resume) for a device whose driver leaves that callback NULL and make the frontend call through a NULL pointer, crashing the guest. Check each callback before calling it, as the PCI core already does, and fall through to PCI_ERS_RESULT_NONE when it is absent. Fixes: 956a9202cd12 ("xen-pcifront: Xen PCI frontend driver.") Cc: stable@vger.kernel.org Signed-off-by: Yehyeong Lee --- There is an in-flight fix for a refcount leak in this same function ("xen/pcifront: Fix PCI device reference leak in AER handling"); this change is orthogonal and applies in either order. drivers/pci/xen-pcifront.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index cffc32d660327..490913676f244 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c @@ -599,12 +599,17 @@ static pci_ers_result_t pcifront_common_process(int cmd, case XEN_PCI_OP_aer_detected: return pdrv->err_handler->error_detected(pcidev, state); case XEN_PCI_OP_aer_mmio: - return pdrv->err_handler->mmio_enabled(pcidev); + if (pdrv->err_handler->mmio_enabled) + return pdrv->err_handler->mmio_enabled(pcidev); + break; case XEN_PCI_OP_aer_slotreset: - return pdrv->err_handler->slot_reset(pcidev); + if (pdrv->err_handler->slot_reset) + return pdrv->err_handler->slot_reset(pcidev); + break; case XEN_PCI_OP_aer_resume: - pdrv->err_handler->resume(pcidev); - return PCI_ERS_RESULT_NONE; + if (pdrv->err_handler->resume) + pdrv->err_handler->resume(pcidev); + break; default: dev_err(&pdev->xdev->dev, "bad request in aer recovery operation!\n"); -- 2.43.0