Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mmc: dw_mmc: Fix out-of-bounds access for slot's caps

Add num_caps field for dw_mci_drv_data to validate the controller
id from DT alias and non-DT ways.

Reported-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
Fixes: 800d78bfccb3 ("mmc: dw_mmc: add support for implementation specific callbacks")
Cc: <stable@vger.kernel.org>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

Shawn Lin and committed by
Ulf Hansson
0d84b9e5 a4faa492

+14 -1
+1
drivers/mmc/host/dw_mmc-exynos.c
··· 487 487 488 488 static const struct dw_mci_drv_data exynos_drv_data = { 489 489 .caps = exynos_dwmmc_caps, 490 + .num_caps = ARRAY_SIZE(exynos_dwmmc_caps), 490 491 .init = dw_mci_exynos_priv_init, 491 492 .set_ios = dw_mci_exynos_set_ios, 492 493 .parse_dt = dw_mci_exynos_parse_dt,
+1
drivers/mmc/host/dw_mmc-k3.c
··· 210 210 211 211 static const struct dw_mci_drv_data hi6220_data = { 212 212 .caps = dw_mci_hi6220_caps, 213 + .num_caps = ARRAY_SIZE(dw_mci_hi6220_caps), 213 214 .switch_voltage = dw_mci_hi6220_switch_voltage, 214 215 .set_ios = dw_mci_hi6220_set_ios, 215 216 .parse_dt = dw_mci_hi6220_parse_dt,
+1
drivers/mmc/host/dw_mmc-rockchip.c
··· 319 319 320 320 static const struct dw_mci_drv_data rk3288_drv_data = { 321 321 .caps = dw_mci_rk3288_dwmmc_caps, 322 + .num_caps = ARRAY_SIZE(dw_mci_rk3288_dwmmc_caps), 322 323 .set_ios = dw_mci_rk3288_set_ios, 323 324 .execute_tuning = dw_mci_rk3288_execute_tuning, 324 325 .parse_dt = dw_mci_rk3288_parse_dt,
+1
drivers/mmc/host/dw_mmc-zx.c
··· 195 195 196 196 static const struct dw_mci_drv_data zx_drv_data = { 197 197 .caps = zx_dwmmc_caps, 198 + .num_caps = ARRAY_SIZE(zx_dwmmc_caps), 198 199 .execute_tuning = dw_mci_zx_execute_tuning, 199 200 .prepare_hs400_tuning = dw_mci_zx_prepare_hs400_tuning, 200 201 .parse_dt = dw_mci_zx_parse_dt,
+8 -1
drivers/mmc/host/dw_mmc.c
··· 2804 2804 } else { 2805 2805 ctrl_id = to_platform_device(host->dev)->id; 2806 2806 } 2807 - if (drv_data && drv_data->caps) 2807 + 2808 + if (drv_data && drv_data->caps) { 2809 + if (ctrl_id >= drv_data->num_caps) { 2810 + dev_err(host->dev, "invalid controller id %d\n", 2811 + ctrl_id); 2812 + return -EINVAL; 2813 + } 2808 2814 mmc->caps |= drv_data->caps[ctrl_id]; 2815 + } 2809 2816 2810 2817 if (host->pdata->caps2) 2811 2818 mmc->caps2 = host->pdata->caps2;
+2
drivers/mmc/host/dw_mmc.h
··· 543 543 /** 544 544 * dw_mci driver data - dw-mshc implementation specific driver data. 545 545 * @caps: mmc subsystem specified capabilities of the controller(s). 546 + * @num_caps: number of capabilities specified by @caps. 546 547 * @init: early implementation specific initialization. 547 548 * @set_ios: handle bus specific extensions. 548 549 * @parse_dt: parse implementation specific device tree properties. ··· 555 554 */ 556 555 struct dw_mci_drv_data { 557 556 unsigned long *caps; 557 + u32 num_caps; 558 558 int (*init)(struct dw_mci *host); 559 559 void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios); 560 560 int (*parse_dt)(struct dw_mci *host);