lkml.org 
[lkml]   [2019]   [Dec]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH AUTOSEL 5.4 021/187] regulator: core: fix regulator_register() error paths to properly release rdev
    Date
    From: Wen Yang <wenyang@linux.alibaba.com>

    [ Upstream commit a3cde9534ebdafe18a9bbab208df724c57e6c8e8 ]

    There are several issues with the error handling code of
    the regulator_register() function:
    ret = device_register(&rdev->dev);
    if (ret != 0) {
    put_device(&rdev->dev); --> rdev released
    goto unset_supplies;
    }
    ...
    unset_supplies:
    ...
    unset_regulator_supplies(rdev); --> use-after-free
    ...
    clean:
    if (dangling_of_gpiod)
    gpiod_put(config->ena_gpiod);
    kfree(rdev); --> double free

    We add a variable to record the failure of device_register() and
    move put_device() down a bit to avoid the above issues.

    Fixes: c438b9d01736 ("regulator: core: Move registration of regulator device")
    Signed-off-by: Wen Yang <wenyang@linux.alibaba.com>
    Cc: Liam Girdwood <lgirdwood@gmail.com>
    Cc: Mark Brown <broonie@kernel.org>
    Cc: linux-kernel@vger.kernel.org
    Link: https://lore.kernel.org/r/20191201030250.38074-1-wenyang@linux.alibaba.com
    Signed-off-by: Mark Brown <broonie@kernel.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/regulator/core.c | 8 ++++++--
    1 file changed, 6 insertions(+), 2 deletions(-)

    diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
    index 71c1467e1e2e..8f5c028090e9 100644
    --- a/drivers/regulator/core.c
    +++ b/drivers/regulator/core.c
    @@ -4990,6 +4990,7 @@ regulator_register(const struct regulator_desc *regulator_desc,
    struct regulator_dev *rdev;
    bool dangling_cfg_gpiod = false;
    bool dangling_of_gpiod = false;
    + bool reg_device_fail = false;
    struct device *dev;
    int ret, i;

    @@ -5175,7 +5176,7 @@ regulator_register(const struct regulator_desc *regulator_desc,
    dev_set_drvdata(&rdev->dev, rdev);
    ret = device_register(&rdev->dev);
    if (ret != 0) {
    - put_device(&rdev->dev);
    + reg_device_fail = true;
    goto unset_supplies;
    }

    @@ -5205,7 +5206,10 @@ regulator_register(const struct regulator_desc *regulator_desc,
    clean:
    if (dangling_of_gpiod)
    gpiod_put(config->ena_gpiod);
    - kfree(rdev);
    + if (reg_device_fail)
    + put_device(&rdev->dev);
    + else
    + kfree(rdev);
    kfree(config);
    rinse:
    if (dangling_cfg_gpiod)
    --
    2.20.1
    \
     
     \ /
      Last update: 2019-12-27 18:42    [W:4.036 / U:0.484 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site