Commit 0d84b9e5 authored by Shawn Lin's avatar Shawn Lin Committed by Ulf Hansson

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: default avatarGeert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: default avatarShawn Lin <shawn.lin@rock-chips.com>
Fixes: 800d78bf ("mmc: dw_mmc: add support for implementation specific callbacks")
Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
parent a4faa492
...@@ -487,6 +487,7 @@ static unsigned long exynos_dwmmc_caps[4] = { ...@@ -487,6 +487,7 @@ static unsigned long exynos_dwmmc_caps[4] = {
static const struct dw_mci_drv_data exynos_drv_data = { static const struct dw_mci_drv_data exynos_drv_data = {
.caps = exynos_dwmmc_caps, .caps = exynos_dwmmc_caps,
.num_caps = ARRAY_SIZE(exynos_dwmmc_caps),
.init = dw_mci_exynos_priv_init, .init = dw_mci_exynos_priv_init,
.set_ios = dw_mci_exynos_set_ios, .set_ios = dw_mci_exynos_set_ios,
.parse_dt = dw_mci_exynos_parse_dt, .parse_dt = dw_mci_exynos_parse_dt,
......
...@@ -210,6 +210,7 @@ static int dw_mci_hi6220_execute_tuning(struct dw_mci_slot *slot, u32 opcode) ...@@ -210,6 +210,7 @@ static int dw_mci_hi6220_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
static const struct dw_mci_drv_data hi6220_data = { static const struct dw_mci_drv_data hi6220_data = {
.caps = dw_mci_hi6220_caps, .caps = dw_mci_hi6220_caps,
.num_caps = ARRAY_SIZE(dw_mci_hi6220_caps),
.switch_voltage = dw_mci_hi6220_switch_voltage, .switch_voltage = dw_mci_hi6220_switch_voltage,
.set_ios = dw_mci_hi6220_set_ios, .set_ios = dw_mci_hi6220_set_ios,
.parse_dt = dw_mci_hi6220_parse_dt, .parse_dt = dw_mci_hi6220_parse_dt,
......
...@@ -319,6 +319,7 @@ static const struct dw_mci_drv_data rk2928_drv_data = { ...@@ -319,6 +319,7 @@ static const struct dw_mci_drv_data rk2928_drv_data = {
static const struct dw_mci_drv_data rk3288_drv_data = { static const struct dw_mci_drv_data rk3288_drv_data = {
.caps = dw_mci_rk3288_dwmmc_caps, .caps = dw_mci_rk3288_dwmmc_caps,
.num_caps = ARRAY_SIZE(dw_mci_rk3288_dwmmc_caps),
.set_ios = dw_mci_rk3288_set_ios, .set_ios = dw_mci_rk3288_set_ios,
.execute_tuning = dw_mci_rk3288_execute_tuning, .execute_tuning = dw_mci_rk3288_execute_tuning,
.parse_dt = dw_mci_rk3288_parse_dt, .parse_dt = dw_mci_rk3288_parse_dt,
......
...@@ -195,6 +195,7 @@ static unsigned long zx_dwmmc_caps[3] = { ...@@ -195,6 +195,7 @@ static unsigned long zx_dwmmc_caps[3] = {
static const struct dw_mci_drv_data zx_drv_data = { static const struct dw_mci_drv_data zx_drv_data = {
.caps = zx_dwmmc_caps, .caps = zx_dwmmc_caps,
.num_caps = ARRAY_SIZE(zx_dwmmc_caps),
.execute_tuning = dw_mci_zx_execute_tuning, .execute_tuning = dw_mci_zx_execute_tuning,
.prepare_hs400_tuning = dw_mci_zx_prepare_hs400_tuning, .prepare_hs400_tuning = dw_mci_zx_prepare_hs400_tuning,
.parse_dt = dw_mci_zx_parse_dt, .parse_dt = dw_mci_zx_parse_dt,
......
...@@ -2804,8 +2804,15 @@ static int dw_mci_init_slot_caps(struct dw_mci_slot *slot) ...@@ -2804,8 +2804,15 @@ static int dw_mci_init_slot_caps(struct dw_mci_slot *slot)
} else { } else {
ctrl_id = to_platform_device(host->dev)->id; ctrl_id = to_platform_device(host->dev)->id;
} }
if (drv_data && drv_data->caps)
if (drv_data && drv_data->caps) {
if (ctrl_id >= drv_data->num_caps) {
dev_err(host->dev, "invalid controller id %d\n",
ctrl_id);
return -EINVAL;
}
mmc->caps |= drv_data->caps[ctrl_id]; mmc->caps |= drv_data->caps[ctrl_id];
}
if (host->pdata->caps2) if (host->pdata->caps2)
mmc->caps2 = host->pdata->caps2; mmc->caps2 = host->pdata->caps2;
......
...@@ -543,6 +543,7 @@ struct dw_mci_slot { ...@@ -543,6 +543,7 @@ struct dw_mci_slot {
/** /**
* dw_mci driver data - dw-mshc implementation specific driver data. * dw_mci driver data - dw-mshc implementation specific driver data.
* @caps: mmc subsystem specified capabilities of the controller(s). * @caps: mmc subsystem specified capabilities of the controller(s).
* @num_caps: number of capabilities specified by @caps.
* @init: early implementation specific initialization. * @init: early implementation specific initialization.
* @set_ios: handle bus specific extensions. * @set_ios: handle bus specific extensions.
* @parse_dt: parse implementation specific device tree properties. * @parse_dt: parse implementation specific device tree properties.
...@@ -554,6 +555,7 @@ struct dw_mci_slot { ...@@ -554,6 +555,7 @@ struct dw_mci_slot {
*/ */
struct dw_mci_drv_data { struct dw_mci_drv_data {
unsigned long *caps; unsigned long *caps;
u32 num_caps;
int (*init)(struct dw_mci *host); int (*init)(struct dw_mci *host);
void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios); void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios);
int (*parse_dt)(struct dw_mci *host); int (*parse_dt)(struct dw_mci *host);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment