From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 01DB9207667; Thu, 3 Apr 2025 19:16:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1743707801; cv=none; b=IuFSZkS364jzw2NRb1+069IZKn67Ggq4f7HFf3yPU+XB6/E6hm3uG/nfCOAhKGsxdpQpyFpCBk27iEP/lGzfMFu8F2XCeEWBBp+keqpO4/TzfSF2ziBewe+mF+czsFAWybtoQ+rDLj/X5zi+PF5gYiGw/fAQCSXBSQL05YTYdGA= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1743707801; c=relaxed/simple; bh=XS4LlfQocr7grcquSdoGOfQ6HYPWb5SYEdmm23R0Go8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=Ce0oaZ/Vi9OLunBw1GomXXbzYIETyZAY33yVRyvPT1oVERPoG2FQZ3GYA3EOEW+lj/2aLslqafX0vSd0c9USa9TmbrjXE2rfQyy+z+FMoyZFnSPafzW57Y61r6fn8EdKgCN0Kc0w2yMc0lY2LHDJUMmcG4XCgEY7ycI+9aq9gsI= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=I/3ah3lK; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="I/3ah3lK" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 915ACC4CEE8; Thu, 3 Apr 2025 19:16:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1743707800; bh=XS4LlfQocr7grcquSdoGOfQ6HYPWb5SYEdmm23R0Go8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=I/3ah3lKKwZdyfExTpL1NMZhjAbSRq5Ml+okm3XLy/V0wnK8Z1221kgLpCvgOW0SU WLoV3EanVqXUb+GVDdsahx4+/usshAtGfJONVe4iBaT0ZPADspNafMC0I2PUa/B0ci w/eyFaJ+lgTj1Y6SeadD8FXQZz6e+hwgwYHG5gYv1CXTqVuQ+aPvgh9GzTlS1LOswZ HOhxyfq/OU3cJJMbCHgmiSVaCRrjsrjD5wprR9lsZbQqK6siAVY2ODtccexflR4hWk IQyzHIT4CJnc0fgSgwdByea44umuw377eBXj2D59X77r+Hi1W6eoWuf1Xe5Y7xv1K9 UbJihKzYrDXHw== From: Sasha Levin To: linux-kernel@vger.kernel.org, stable@vger.kernel.org Cc: Philipp Stanner , Bingbu Cao , =?UTF-8?q?Krzysztof=20Wilczy=C5=84ski?= , Bjorn Helgaas , Sasha Levin , linux-pci@vger.kernel.org Subject: [PATCH AUTOSEL 6.13 30/37] PCI: Check BAR index for validity Date: Thu, 3 Apr 2025 15:15:06 -0400 Message-Id: <20250403191513.2680235-30-sashal@kernel.org> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250403191513.2680235-1-sashal@kernel.org> References: <20250403191513.2680235-1-sashal@kernel.org> Precedence: bulk X-Mailing-List: linux-pci@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 X-stable: review X-Patchwork-Hint: Ignore X-stable-base: Linux 6.13.9 Content-Transfer-Encoding: 8bit From: Philipp Stanner [ Upstream commit b1a7f99967fc0c052db8e65b449c7b32b1e9177f ] Many functions in PCI use accessor macros such as pci_resource_len(), which take a BAR index. That index, however, is never checked for validity, potentially resulting in undefined behavior by overflowing the array pci_dev.resource in the macro pci_resource_n(). Since many users of those macros directly assign the accessed value to an unsigned integer, the macros cannot be changed easily anymore to return -EINVAL for invalid indexes. Consequently, the problem has to be mitigated in higher layers. Add pci_bar_index_valid(). Use it where appropriate. Link: https://lore.kernel.org/r/20250312080634.13731-4-phasta@kernel.org Closes: https://lore.kernel.org/all/adb53b1f-29e1-3d14-0e61-351fd2d3ff0d@linux.intel.com/ Reported-by: Bingbu Cao Signed-off-by: Philipp Stanner [kwilczynski: correct if-statement condition the pci_bar_index_is_valid() helper function uses, tidy up code comments] Signed-off-by: Krzysztof WilczyƄski [bhelgaas: fix typo] Signed-off-by: Bjorn Helgaas Signed-off-by: Sasha Levin --- drivers/pci/devres.c | 16 ++++++++++++++-- drivers/pci/iomap.c | 29 +++++++++++++++++++++-------- drivers/pci/pci.c | 6 ++++++ drivers/pci/pci.h | 16 ++++++++++++++++ 4 files changed, 57 insertions(+), 10 deletions(-) diff --git a/drivers/pci/devres.c b/drivers/pci/devres.c index 1adebcb263bd0..51ef3e591d343 100644 --- a/drivers/pci/devres.c +++ b/drivers/pci/devres.c @@ -577,7 +577,7 @@ static int pcim_add_mapping_to_legacy_table(struct pci_dev *pdev, { void __iomem **legacy_iomap_table; - if (bar >= PCI_STD_NUM_BARS) + if (!pci_bar_index_is_valid(bar)) return -EINVAL; legacy_iomap_table = (void __iomem **)pcim_iomap_table(pdev); @@ -622,7 +622,7 @@ static void pcim_remove_bar_from_legacy_table(struct pci_dev *pdev, int bar) { void __iomem **legacy_iomap_table; - if (bar >= PCI_STD_NUM_BARS) + if (!pci_bar_index_is_valid(bar)) return; legacy_iomap_table = (void __iomem **)pcim_iomap_table(pdev); @@ -655,6 +655,9 @@ void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen) void __iomem *mapping; struct pcim_addr_devres *res; + if (!pci_bar_index_is_valid(bar)) + return NULL; + res = pcim_addr_devres_alloc(pdev); if (!res) return NULL; @@ -722,6 +725,9 @@ void __iomem *pcim_iomap_region(struct pci_dev *pdev, int bar, int ret; struct pcim_addr_devres *res; + if (!pci_bar_index_is_valid(bar)) + return IOMEM_ERR_PTR(-EINVAL); + res = pcim_addr_devres_alloc(pdev); if (!res) return IOMEM_ERR_PTR(-ENOMEM); @@ -823,6 +829,9 @@ static int _pcim_request_region(struct pci_dev *pdev, int bar, const char *name, int ret; struct pcim_addr_devres *res; + if (!pci_bar_index_is_valid(bar)) + return -EINVAL; + res = pcim_addr_devres_alloc(pdev); if (!res) return -ENOMEM; @@ -991,6 +1000,9 @@ void __iomem *pcim_iomap_range(struct pci_dev *pdev, int bar, void __iomem *mapping; struct pcim_addr_devres *res; + if (!pci_bar_index_is_valid(bar)) + return IOMEM_ERR_PTR(-EINVAL); + res = pcim_addr_devres_alloc(pdev); if (!res) return IOMEM_ERR_PTR(-ENOMEM); diff --git a/drivers/pci/iomap.c b/drivers/pci/iomap.c index 9fb7cacc15cde..fe706ed946dfd 100644 --- a/drivers/pci/iomap.c +++ b/drivers/pci/iomap.c @@ -9,6 +9,8 @@ #include +#include "pci.h" /* for pci_bar_index_is_valid() */ + /** * pci_iomap_range - create a virtual mapping cookie for a PCI BAR * @dev: PCI device that owns the BAR @@ -33,12 +35,19 @@ void __iomem *pci_iomap_range(struct pci_dev *dev, unsigned long offset, unsigned long maxlen) { - resource_size_t start = pci_resource_start(dev, bar); - resource_size_t len = pci_resource_len(dev, bar); - unsigned long flags = pci_resource_flags(dev, bar); + resource_size_t start, len; + unsigned long flags; + + if (!pci_bar_index_is_valid(bar)) + return NULL; + + start = pci_resource_start(dev, bar); + len = pci_resource_len(dev, bar); + flags = pci_resource_flags(dev, bar); if (len <= offset || !start) return NULL; + len -= offset; start += offset; if (maxlen && len > maxlen) @@ -77,16 +86,20 @@ void __iomem *pci_iomap_wc_range(struct pci_dev *dev, unsigned long offset, unsigned long maxlen) { - resource_size_t start = pci_resource_start(dev, bar); - resource_size_t len = pci_resource_len(dev, bar); - unsigned long flags = pci_resource_flags(dev, bar); + resource_size_t start, len; + unsigned long flags; - - if (flags & IORESOURCE_IO) + if (!pci_bar_index_is_valid(bar)) return NULL; + start = pci_resource_start(dev, bar); + len = pci_resource_len(dev, bar); + flags = pci_resource_flags(dev, bar); + if (len <= offset || !start) return NULL; + if (flags & IORESOURCE_IO) + return NULL; len -= offset; start += offset; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index b0ae4bc1a1bee..603e51936ed68 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3916,6 +3916,9 @@ EXPORT_SYMBOL(pci_enable_atomic_ops_to_root); */ void pci_release_region(struct pci_dev *pdev, int bar) { + if (!pci_bar_index_is_valid(bar)) + return; + /* * This is done for backwards compatibility, because the old PCI devres * API had a mode in which the function became managed if it had been @@ -3961,6 +3964,9 @@ EXPORT_SYMBOL(pci_release_region); static int __pci_request_region(struct pci_dev *pdev, int bar, const char *res_name, int exclusive) { + if (!pci_bar_index_is_valid(bar)) + return -EINVAL; + if (pci_is_managed(pdev)) { if (exclusive == IORESOURCE_EXCLUSIVE) return pcim_request_region_exclusive(pdev, bar, res_name); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 2e40fc63ba315..21f3743d03b03 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -165,6 +165,22 @@ static inline void pci_wakeup_event(struct pci_dev *dev) pm_wakeup_event(&dev->dev, 100); } +/** + * pci_bar_index_is_valid - Check whether a BAR index is within valid range + * @bar: BAR index + * + * Protects against overflowing &struct pci_dev.resource array. + * + * Return: true for valid index, false otherwise. + */ +static inline bool pci_bar_index_is_valid(int bar) +{ + if (bar >= 0 && bar < PCI_NUM_RESOURCES) + return true; + + return false; +} + static inline bool pci_has_subordinate(struct pci_dev *pci_dev) { return !!(pci_dev->subordinate); -- 2.39.5