Re: [PATCH] phy: exynos5-usbdrd: Use dynamic phy_cfg size to prevent OOB access

From: Peter Griffin

Date: Tue Sep 15 2026 - 12:52:40 EST


On Mon, 31 Aug 2026 at 08:03, Selvarasu Ganesan <selvarasu.g@xxxxxxxxxxx> wrote:
>
> The probe loop currently iterates using EXYNOS5_DRDPHYS_NUM (2),
> creating both UTMI and PIPE3 PHY instances regardless of the SoC
> capability. Several SoCs (Exynos2200, Exynos7870, Exynos850, Exynos990,
> and ExynosAutoV920) provide phy_cfg arrays containing only a single
> element.
>
> On these SoCs, when the loop reaches index 1, the driver reads past the
> end of the rodata array, populating the second PHY instance with garbage
> data. Since the configuration structure contains critical function
> pointers (phy_isol, phy_init, set_refclk), any subsequent access to this
> PHY instance via exynos5_usbdrd_phy_xlate could result in a kernel oops.
>
> Fix this by adding 'n_phy_cfg' to struct exynos5_usbdrd_phy_drvdata to
> store the actual size of the phy_cfg array for each SoC. Update the
> probe loop and the xlate function to bound their access against this
> value instead of the hardcoded EXYNOS5_DRDPHYS_NUM.
>
> Assisted-by: Claude:claude-sonnet-5
> Signed-off-by: Selvarasu Ganesan <selvarasu.g@xxxxxxxxxxx>
> ---

Reviewed-by: Peter Griffin <peter.griffin@xxxxxxxxxx>

> drivers/phy/samsung/phy-exynos5-usbdrd.c | 17 +++++++++++++++--
> 1 file changed, 15 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/phy/samsung/phy-exynos5-usbdrd.c b/drivers/phy/samsung/phy-exynos5-usbdrd.c
> index 8711a3b62c8e..311d1c25eb3e 100644
> --- a/drivers/phy/samsung/phy-exynos5-usbdrd.c
> +++ b/drivers/phy/samsung/phy-exynos5-usbdrd.c
> @@ -477,6 +477,7 @@ struct exynos5_usbdrd_phy_config {
>
> struct exynos5_usbdrd_phy_drvdata {
> const struct exynos5_usbdrd_phy_config *phy_cfg;
> + int n_phy_cfg;
> const struct exynos5_usbdrd_phy_tuning **phy_tunes;
> const struct phy_ops *phy_ops;
> const char * const *clk_names;
> @@ -1164,7 +1165,7 @@ static struct phy *exynos5_usbdrd_phy_xlate(struct device *dev,
> {
> struct exynos5_usbdrd_phy *phy_drd = dev_get_drvdata(dev);
>
> - if (WARN_ON(args->args[0] >= EXYNOS5_DRDPHYS_NUM))
> + if (WARN_ON(args->args[0] >= phy_drd->drv_data->n_phy_cfg))
> return ERR_PTR(-ENODEV);
>
> return phy_drd->phys[args->args[0]].phy;
> @@ -1993,6 +1994,7 @@ static const char * const exynos5_regulator_names[] = {
>
> static const struct exynos5_usbdrd_phy_drvdata exynos2200_usb32drd_phy = {
> .phy_cfg = phy_cfg_exynos2200,
> + .n_phy_cfg = ARRAY_SIZE(phy_cfg_exynos2200),
> .phy_ops = &exynos2200_usbdrd_phy_ops,
> .pmu_offset_usbdrd0_phy = EXYNOS2200_PHY_CTRL_USB20,
> .clk_names = exynos5_clk_names,
> @@ -2006,6 +2008,7 @@ static const struct exynos5_usbdrd_phy_drvdata exynos2200_usb32drd_phy = {
>
> static const struct exynos5_usbdrd_phy_drvdata exynos5420_usbdrd_phy = {
> .phy_cfg = phy_cfg_exynos5,
> + .n_phy_cfg = ARRAY_SIZE(phy_cfg_exynos5),
> .phy_ops = &exynos5_usbdrd_phy_ops,
> .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL,
> .pmu_offset_usbdrd1_phy = EXYNOS5420_USBDRD1_PHY_CONTROL,
> @@ -2019,6 +2022,7 @@ static const struct exynos5_usbdrd_phy_drvdata exynos5420_usbdrd_phy = {
>
> static const struct exynos5_usbdrd_phy_drvdata exynos5250_usbdrd_phy = {
> .phy_cfg = phy_cfg_exynos5,
> + .n_phy_cfg = ARRAY_SIZE(phy_cfg_exynos5),
> .phy_ops = &exynos5_usbdrd_phy_ops,
> .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL,
> .clk_names = exynos5_clk_names,
> @@ -2031,6 +2035,7 @@ static const struct exynos5_usbdrd_phy_drvdata exynos5250_usbdrd_phy = {
>
> static const struct exynos5_usbdrd_phy_drvdata exynos5433_usbdrd_phy = {
> .phy_cfg = phy_cfg_exynos5,
> + .n_phy_cfg = ARRAY_SIZE(phy_cfg_exynos5),
> .phy_ops = &exynos5_usbdrd_phy_ops,
> .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL,
> .pmu_offset_usbdrd1_phy = EXYNOS5433_USBHOST30_PHY_CONTROL,
> @@ -2044,6 +2049,7 @@ static const struct exynos5_usbdrd_phy_drvdata exynos5433_usbdrd_phy = {
>
> static const struct exynos5_usbdrd_phy_drvdata exynos7_usbdrd_phy = {
> .phy_cfg = phy_cfg_exynos5,
> + .n_phy_cfg = ARRAY_SIZE(phy_cfg_exynos5),
> .phy_ops = &exynos5_usbdrd_phy_ops,
> .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL,
> .clk_names = exynos5_clk_names,
> @@ -2056,6 +2062,7 @@ static const struct exynos5_usbdrd_phy_drvdata exynos7_usbdrd_phy = {
>
> static const struct exynos5_usbdrd_phy_drvdata exynos7870_usbdrd_phy = {
> .phy_cfg = phy_cfg_exynos7870,
> + .n_phy_cfg = ARRAY_SIZE(phy_cfg_exynos7870),
> .phy_tunes = exynos7870_tunes,
> .phy_ops = &exynos7870_usbdrd_phy_ops,
> .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL,
> @@ -2069,6 +2076,7 @@ static const struct exynos5_usbdrd_phy_drvdata exynos7870_usbdrd_phy = {
>
> static const struct exynos5_usbdrd_phy_drvdata exynos850_usbdrd_phy = {
> .phy_cfg = phy_cfg_exynos850,
> + .n_phy_cfg = ARRAY_SIZE(phy_cfg_exynos850),
> .phy_ops = &exynos850_usbdrd_phy_ops,
> .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL,
> .clk_names = exynos5_clk_names,
> @@ -2097,6 +2105,7 @@ static const struct exynos5_usbdrd_phy_tuning *exynos990_tunes[PTS_MAX] = {
>
> static const struct exynos5_usbdrd_phy_drvdata exynos990_usbdrd_phy = {
> .phy_cfg = phy_cfg_exynos850,
> + .n_phy_cfg = ARRAY_SIZE(phy_cfg_exynos850),
> .phy_ops = &exynos850_usbdrd_phy_ops,
> .phy_tunes = exynos990_tunes,
> .pmu_offset_usbdrd0_phy = EXYNOS990_PHY_CTRL_USB20,
> @@ -2629,6 +2638,7 @@ static const struct phy_ops exynosautov920_usb31drd_combo_ssphy_ops = {
> static const
> struct exynos5_usbdrd_phy_drvdata exynosautov920_usb31drd_combo_ssphy = {
> .phy_cfg = usb31drd_phy_cfg_exynosautov920,
> + .n_phy_cfg = ARRAY_SIZE(usb31drd_phy_cfg_exynosautov920),
> .phy_ops = &exynosautov920_usb31drd_combo_ssphy_ops,
> .pmu_offset_usbdrd0_phy = EXYNOSAUTOV920_PHY_CTRL_USB31,
> .clk_names = exynos5_clk_names,
> @@ -2659,6 +2669,7 @@ exynos5_usbdrd_phy_config usbdrd_hsphy_cfg_exynosautov920[] = {
> static const
> struct exynos5_usbdrd_phy_drvdata exynosautov920_usbdrd_combo_hsphy = {
> .phy_cfg = usbdrd_hsphy_cfg_exynosautov920,
> + .n_phy_cfg = ARRAY_SIZE(usbdrd_hsphy_cfg_exynosautov920),
> .phy_ops = &exynosautov920_usbdrd_combo_hsphy_ops,
> .pmu_offset_usbdrd0_phy = EXYNOSAUTOV920_PHY_CTRL_USB20,
> .clk_names = exynos5_clk_names,
> @@ -2687,6 +2698,7 @@ static const struct exynos5_usbdrd_phy_config phy_cfg_exynosautov920[] = {
>
> static const struct exynos5_usbdrd_phy_drvdata exynosautov920_usbdrd_phy = {
> .phy_cfg = phy_cfg_exynosautov920,
> + .n_phy_cfg = ARRAY_SIZE(phy_cfg_exynosautov920),
> .phy_ops = &exynosautov920_usbdrd_phy_ops,
> .pmu_offset_usbdrd0_phy = EXYNOSAUTOV920_PHY_CTRL_USB20,
> .clk_names = exynos5_clk_names,
> @@ -2863,6 +2875,7 @@ static const char * const gs101_regulator_names[] = {
>
> static const struct exynos5_usbdrd_phy_drvdata gs101_usbd31rd_phy = {
> .phy_cfg = phy_cfg_gs101,
> + .n_phy_cfg = ARRAY_SIZE(phy_cfg_gs101),
> .phy_tunes = gs101_tunes,
> .phy_ops = &gs101_usbdrd_phy_ops,
> .pmu_offset_usbdrd0_phy = GS101_PHY_CTRL_USB20,
> @@ -3020,7 +3033,7 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
>
> dev_vdbg(dev, "Creating usbdrd_phy phy\n");
>
> - for (i = 0; i < EXYNOS5_DRDPHYS_NUM; i++) {
> + for (i = 0; i < drv_data->n_phy_cfg; i++) {
> struct phy *phy = devm_phy_create(dev, NULL, drv_data->phy_ops);
>
> if (IS_ERR(phy))
> --
> 2.17.1
>