mirror of https://gitee.com/openkylin/linux.git
gpio: brcmstb: fix null ptr dereference in driver remove
If a failure occurs during probe, brcmstb_gpio_remove() is called. In remove, we call platform_get_drvdata(), but at the time of failure in the probe the driver data hadn't yet been set which leads to a NULL ptr dereference in the remove's list_for_each. Call platform_set_drvdata() and set up list head right after allocating the priv struct to both avoid the null pointer dereference that could occur today. To guard against potential future changes, check for null pointer in remove. Reported-by: Tim Ross <tross@broadcom.com> Signed-off-by: Gregory Fong <gregory.0xf0@gmail.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
parent
30bb6fb39e
commit
2252607d32
|
@ -87,6 +87,15 @@ static int brcmstb_gpio_remove(struct platform_device *pdev)
|
||||||
struct brcmstb_gpio_bank *bank;
|
struct brcmstb_gpio_bank *bank;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!priv) {
|
||||||
|
dev_err(&pdev->dev, "called %s without drvdata!\n", __func__);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* You can lose return values below, but we report all errors, and it's
|
||||||
|
* more important to actually perform all of the steps.
|
||||||
|
*/
|
||||||
list_for_each(pos, &priv->bank_list) {
|
list_for_each(pos, &priv->bank_list) {
|
||||||
bank = list_entry(pos, struct brcmstb_gpio_bank, node);
|
bank = list_entry(pos, struct brcmstb_gpio_bank, node);
|
||||||
ret = bgpio_remove(&bank->bgc);
|
ret = bgpio_remove(&bank->bgc);
|
||||||
|
@ -143,6 +152,8 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
|
||||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||||
if (!priv)
|
if (!priv)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
platform_set_drvdata(pdev, priv);
|
||||||
|
INIT_LIST_HEAD(&priv->bank_list);
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
reg_base = devm_ioremap_resource(dev, res);
|
reg_base = devm_ioremap_resource(dev, res);
|
||||||
|
@ -153,7 +164,6 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
|
||||||
priv->reg_base = reg_base;
|
priv->reg_base = reg_base;
|
||||||
priv->pdev = pdev;
|
priv->pdev = pdev;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&priv->bank_list);
|
|
||||||
if (brcmstb_gpio_sanity_check_banks(dev, np, res))
|
if (brcmstb_gpio_sanity_check_banks(dev, np, res))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -221,8 +231,6 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
|
||||||
dev_info(dev, "Registered %d banks (GPIO(s): %d-%d)\n",
|
dev_info(dev, "Registered %d banks (GPIO(s): %d-%d)\n",
|
||||||
priv->num_banks, priv->gpio_base, gpio_base - 1);
|
priv->num_banks, priv->gpio_base, gpio_base - 1);
|
||||||
|
|
||||||
platform_set_drvdata(pdev, priv);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
|
Loading…
Reference in New Issue