The pcie_link_speed[] array is indexed by PCIe generation numbers
(1 = 2.5 GT/s, 2 = 5 GT/s, ...). Several drivers use it directly,
which can lead to out-of-bounds accesses if an invalid generation
number is used.
Introduce a helper function pcie_get_link_speed() that returns the
corresponding enum pci_bus_speed value for a given generation number,
or PCI_SPEED_UNKNOWN if the generation is out of range. This will
allow us to safely handle invalid values after the range check is
removed from of_pci_get_max_link_speed().
Signed-off-by: Hans Zhang <18255117159@163.com>
---
drivers/pci/pci.h | 2 ++
drivers/pci/probe.c | 16 ++++++++++++++++
2 files changed, 18 insertions(+)
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 13d998fbacce..409aca7d737a 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -108,6 +108,8 @@ struct pcie_tlp_log;
PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE)
extern const unsigned char pcie_link_speed[];
+unsigned char pcie_get_link_speed(unsigned int speed);
+
extern bool pci_early_dump;
extern struct mutex pci_rescan_remove_lock;
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index bccc7a4bdd79..d6592898330c 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -783,6 +783,22 @@ const unsigned char pcie_link_speed[] = {
};
EXPORT_SYMBOL_GPL(pcie_link_speed);
+/**
+ * pcie_link_speed_value - Get speed value from PCIe generation number
+ * @speed: PCIe speed (1-based: 1 = 2.5GT, 2 = 5GT, ...)
+ *
+ * Returns the speed value (e.g., PCIE_SPEED_2_5GT) if @speed is valid,
+ * otherwise returns PCI_SPEED_UNKNOWN.
+ */
+unsigned char pcie_get_link_speed(unsigned int speed)
+{
+ if (speed >= ARRAY_SIZE(pcie_link_speed))
+ return PCI_SPEED_UNKNOWN;
+
+ return pcie_link_speed[speed];
+}
+EXPORT_SYMBOL_GPL(pcie_get_link_speed);
+
const char *pci_speed_string(enum pci_bus_speed speed)
{
/* Indexed by the pci_bus_speed enum */
--
2.34.1
On Sat, Mar 14, 2026 at 12:55:18AM +0800, Hans Zhang wrote:
> The pcie_link_speed[] array is indexed by PCIe generation numbers
> (1 = 2.5 GT/s, 2 = 5 GT/s, ...). Several drivers use it directly,
> which can lead to out-of-bounds accesses if an invalid generation
> number is used.
>
> Introduce a helper function pcie_get_link_speed() that returns the
> corresponding enum pci_bus_speed value for a given generation number,
> or PCI_SPEED_UNKNOWN if the generation is out of range. This will
> allow us to safely handle invalid values after the range check is
> removed from of_pci_get_max_link_speed().
>
> Signed-off-by: Hans Zhang <18255117159@163.com>
> ---
> drivers/pci/pci.h | 2 ++
> drivers/pci/probe.c | 16 ++++++++++++++++
> 2 files changed, 18 insertions(+)
>
> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> index 13d998fbacce..409aca7d737a 100644
> --- a/drivers/pci/pci.h
> +++ b/drivers/pci/pci.h
> @@ -108,6 +108,8 @@ struct pcie_tlp_log;
> PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE)
>
> extern const unsigned char pcie_link_speed[];
> +unsigned char pcie_get_link_speed(unsigned int speed);
> +
> extern bool pci_early_dump;
>
> extern struct mutex pci_rescan_remove_lock;
> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> index bccc7a4bdd79..d6592898330c 100644
> --- a/drivers/pci/probe.c
> +++ b/drivers/pci/probe.c
> @@ -783,6 +783,22 @@ const unsigned char pcie_link_speed[] = {
> };
> EXPORT_SYMBOL_GPL(pcie_link_speed);
>
> +/**
> + * pcie_link_speed_value - Get speed value from PCIe generation number
Wrong name here (pcie_link_speed_value vs pcie_get_link_speed)
(pointed out by Sashiko).
> + * @speed: PCIe speed (1-based: 1 = 2.5GT, 2 = 5GT, ...)
> + *
> + * Returns the speed value (e.g., PCIE_SPEED_2_5GT) if @speed is valid,
> + * otherwise returns PCI_SPEED_UNKNOWN.
> + */
> +unsigned char pcie_get_link_speed(unsigned int speed)
Sashiko also pointed out that the commit log says this returns "enum
pci_bus_speed", while here we return unsigned char (which is also the
type of pcie_link_speed[x]).
https://sashiko.dev/#/patchset/20260313165522.123518-1-18255117159%40163.com
> +{
> + if (speed >= ARRAY_SIZE(pcie_link_speed))
> + return PCI_SPEED_UNKNOWN;
> +
> + return pcie_link_speed[speed];
> +}
> +EXPORT_SYMBOL_GPL(pcie_get_link_speed);
> +
> const char *pci_speed_string(enum pci_bus_speed speed)
> {
> /* Indexed by the pci_bus_speed enum */
> --
> 2.34.1
>
On Thu, Mar 26, 2026 at 01:16:24PM -0500, Bjorn Helgaas wrote:
> On Sat, Mar 14, 2026 at 12:55:18AM +0800, Hans Zhang wrote:
> > The pcie_link_speed[] array is indexed by PCIe generation numbers
> > (1 = 2.5 GT/s, 2 = 5 GT/s, ...). Several drivers use it directly,
> > which can lead to out-of-bounds accesses if an invalid generation
> > number is used.
> >
> > Introduce a helper function pcie_get_link_speed() that returns the
> > corresponding enum pci_bus_speed value for a given generation number,
> > or PCI_SPEED_UNKNOWN if the generation is out of range. This will
> > allow us to safely handle invalid values after the range check is
> > removed from of_pci_get_max_link_speed().
> >
> > Signed-off-by: Hans Zhang <18255117159@163.com>
> > ---
> > drivers/pci/pci.h | 2 ++
> > drivers/pci/probe.c | 16 ++++++++++++++++
> > 2 files changed, 18 insertions(+)
> >
> > diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> > index 13d998fbacce..409aca7d737a 100644
> > --- a/drivers/pci/pci.h
> > +++ b/drivers/pci/pci.h
> > @@ -108,6 +108,8 @@ struct pcie_tlp_log;
> > PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE)
> >
> > extern const unsigned char pcie_link_speed[];
> > +unsigned char pcie_get_link_speed(unsigned int speed);
> > +
> > extern bool pci_early_dump;
> >
> > extern struct mutex pci_rescan_remove_lock;
> > diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> > index bccc7a4bdd79..d6592898330c 100644
> > --- a/drivers/pci/probe.c
> > +++ b/drivers/pci/probe.c
> > @@ -783,6 +783,22 @@ const unsigned char pcie_link_speed[] = {
> > };
> > EXPORT_SYMBOL_GPL(pcie_link_speed);
> >
> > +/**
> > + * pcie_link_speed_value - Get speed value from PCIe generation number
>
> Wrong name here (pcie_link_speed_value vs pcie_get_link_speed)
> (pointed out by Sashiko).
>
Noticed this one while applying.
> > + * @speed: PCIe speed (1-based: 1 = 2.5GT, 2 = 5GT, ...)
> > + *
> > + * Returns the speed value (e.g., PCIE_SPEED_2_5GT) if @speed is valid,
> > + * otherwise returns PCI_SPEED_UNKNOWN.
> > + */
> > +unsigned char pcie_get_link_speed(unsigned int speed)
>
> Sashiko also pointed out that the commit log says this returns "enum
> pci_bus_speed", while here we return unsigned char (which is also the
> type of pcie_link_speed[x]).
>
> https://sashiko.dev/#/patchset/20260313165522.123518-1-18255117159%40163.com
>
This one I didn't, but fixed now, thanks!
- Mani
--
மணிவண்ணன் சதாசிவம்
On Sat, Mar 14, 2026 at 12:55:18AM +0800, Hans Zhang wrote:
> The pcie_link_speed[] array is indexed by PCIe generation numbers
> (1 = 2.5 GT/s, 2 = 5 GT/s, ...). Several drivers use it directly,
> which can lead to out-of-bounds accesses if an invalid generation
> number is used.
>
> Introduce a helper function pcie_get_link_speed() that returns the
> corresponding enum pci_bus_speed value for a given generation number,
> or PCI_SPEED_UNKNOWN if the generation is out of range. This will
> allow us to safely handle invalid values after the range check is
> removed from of_pci_get_max_link_speed().
>
> Signed-off-by: Hans Zhang <18255117159@163.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
> ---
> drivers/pci/pci.h | 2 ++
> drivers/pci/probe.c | 16 ++++++++++++++++
> 2 files changed, 18 insertions(+)
>
> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> index 13d998fbacce..409aca7d737a 100644
> --- a/drivers/pci/pci.h
> +++ b/drivers/pci/pci.h
> @@ -108,6 +108,8 @@ struct pcie_tlp_log;
> PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE)
>
> extern const unsigned char pcie_link_speed[];
> +unsigned char pcie_get_link_speed(unsigned int speed);
> +
> extern bool pci_early_dump;
>
> extern struct mutex pci_rescan_remove_lock;
> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> index bccc7a4bdd79..d6592898330c 100644
> --- a/drivers/pci/probe.c
> +++ b/drivers/pci/probe.c
> @@ -783,6 +783,22 @@ const unsigned char pcie_link_speed[] = {
> };
> EXPORT_SYMBOL_GPL(pcie_link_speed);
>
> +/**
> + * pcie_link_speed_value - Get speed value from PCIe generation number
> + * @speed: PCIe speed (1-based: 1 = 2.5GT, 2 = 5GT, ...)
> + *
> + * Returns the speed value (e.g., PCIE_SPEED_2_5GT) if @speed is valid,
> + * otherwise returns PCI_SPEED_UNKNOWN.
> + */
> +unsigned char pcie_get_link_speed(unsigned int speed)
> +{
> + if (speed >= ARRAY_SIZE(pcie_link_speed))
> + return PCI_SPEED_UNKNOWN;
> +
> + return pcie_link_speed[speed];
> +}
> +EXPORT_SYMBOL_GPL(pcie_get_link_speed);
> +
> const char *pci_speed_string(enum pci_bus_speed speed)
> {
> /* Indexed by the pci_bus_speed enum */
> --
> 2.34.1
>
On Sat, Mar 14, 2026 at 12:55:18AM +0800, Hans Zhang wrote:
> The pcie_link_speed[] array is indexed by PCIe generation numbers
> (1 = 2.5 GT/s, 2 = 5 GT/s, ...). Several drivers use it directly,
> which can lead to out-of-bounds accesses if an invalid generation
> number is used.
>
> Introduce a helper function pcie_get_link_speed() that returns the
> corresponding enum pci_bus_speed value for a given generation number,
> or PCI_SPEED_UNKNOWN if the generation is out of range. This will
> allow us to safely handle invalid values after the range check is
> removed from of_pci_get_max_link_speed().
>
Bjorn: Could you please take a look at this patch and ack if looks good? Rest of
the patches look good to me (I might squash patch 5 with 4 while applying).
- Mani
> Signed-off-by: Hans Zhang <18255117159@163.com>
> ---
> drivers/pci/pci.h | 2 ++
> drivers/pci/probe.c | 16 ++++++++++++++++
> 2 files changed, 18 insertions(+)
>
> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> index 13d998fbacce..409aca7d737a 100644
> --- a/drivers/pci/pci.h
> +++ b/drivers/pci/pci.h
> @@ -108,6 +108,8 @@ struct pcie_tlp_log;
> PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE)
>
> extern const unsigned char pcie_link_speed[];
> +unsigned char pcie_get_link_speed(unsigned int speed);
> +
> extern bool pci_early_dump;
>
> extern struct mutex pci_rescan_remove_lock;
> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> index bccc7a4bdd79..d6592898330c 100644
> --- a/drivers/pci/probe.c
> +++ b/drivers/pci/probe.c
> @@ -783,6 +783,22 @@ const unsigned char pcie_link_speed[] = {
> };
> EXPORT_SYMBOL_GPL(pcie_link_speed);
>
> +/**
> + * pcie_link_speed_value - Get speed value from PCIe generation number
> + * @speed: PCIe speed (1-based: 1 = 2.5GT, 2 = 5GT, ...)
> + *
> + * Returns the speed value (e.g., PCIE_SPEED_2_5GT) if @speed is valid,
> + * otherwise returns PCI_SPEED_UNKNOWN.
> + */
> +unsigned char pcie_get_link_speed(unsigned int speed)
> +{
> + if (speed >= ARRAY_SIZE(pcie_link_speed))
> + return PCI_SPEED_UNKNOWN;
> +
> + return pcie_link_speed[speed];
> +}
> +EXPORT_SYMBOL_GPL(pcie_get_link_speed);
> +
> const char *pci_speed_string(enum pci_bus_speed speed)
> {
> /* Indexed by the pci_bus_speed enum */
> --
> 2.34.1
>
--
மணிவண்ணன் சதாசிவம்
© 2016 - 2026 Red Hat, Inc.