Commit 75a74bd3 authored by Niklas Cassel's avatar Niklas Cassel Committed by Xiongfeng Wang
Browse files

PCI: dwc: ep: Prevent changing BAR size/flags in pci_epc_set_bar()

mainline inclusion
from mainline-v6.14-rc1
commit 3708acbd5f169ebafe1faa519cb28adc56295546
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBPC3J
CVE: CVE-2024-58006

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3708acbd5f169ebafe1faa519cb28adc56295546

--------------------------------

In commit 4284c88f ("PCI: designware-ep: Allow pci_epc_set_bar() update
inbound map address") set_bar() was modified to support dynamically
changing the backing physical address of a BAR that was already configured.

This means that set_bar() can be called twice, without ever calling
clear_bar() (as calling clear_bar() would clear the BAR's PCI address
assigned by the host).

This can only be done if the new BAR size/flags does not differ from the
existing BAR configuration. Add these missing checks.

If we allow set_bar() to set e.g. a new BAR size that differs from the
existing BAR size, the new address translation range will be smaller than
the BAR size already determined by the host, which would mean that a read
past the new BAR size would pass the iATU untranslated, which could allow
the host to read memory not belonging to the new struct pci_epf_bar.

While at it, add comments which clarifies the support for dynamically
changing the physical address of a BAR. (Which was also missing.)

Fixes: 4284c88f ("PCI: designware-ep: Allow pci_epc_set_bar() update inbound map address")
Link: https://lore.kernel.org/r/20241213143301.4158431-10-cassel@kernel.org


Signed-off-by: default avatarNiklas Cassel <cassel@kernel.org>
Signed-off-by: default avatarKrzysztof Wilczyński <kwilczynski@kernel.org>
Reviewed-by: default avatarManivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Cc: stable@vger.kernel.org

Conflicts:
	drivers/pci/controller/dwc/pcie-designware-ep.c
[wxf: fix conflicts because of the following commit is not merged.
commit 33a6938e0c337 "PCI: dwc: ep: Write BAR_MASK before iATU registers
in pci_epc_set_bar()"]
Signed-off-by: default avatarXiongfeng Wang <wangxiongfeng2@huawei.com>
parent cc10030e
Loading
Loading
Loading
Loading
+21 −1
Original line number Diff line number Diff line
@@ -256,8 +256,28 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
	if (ret)
		return ret;

	if (ep->epf_bar[bar])
	/*
	 * Certain EPF drivers dynamically change the physical address of a BAR
	 * (i.e. they call set_bar() twice, without ever calling clear_bar(), as
	 * calling clear_bar() would clear the BAR's PCI address assigned by the
	 * host).
	 */
	if (ep->epf_bar[bar]) {
		/*
		 * We can only dynamically change a BAR if the new BAR size and
		 * BAR flags do not differ from the existing configuration.
		 */
		if (ep->epf_bar[bar]->barno != bar ||
		    ep->epf_bar[bar]->size != size ||
		    ep->epf_bar[bar]->flags != flags)
			return -EINVAL;

		/*
		 * When dynamically changing a BAR, skip writing the BAR reg, as
		 * that would clear the BAR's PCI address assigned by the host.
		 */
		return 0;
	}

	dw_pcie_dbi_ro_wr_en(pci);