lkml.org 
[lkml]   [2021]   [Jul]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.13 669/800] mfd: Remove software node conditionally and locate at right place
    Date
    From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

    [ Upstream commit 5a23e8b0fd6010e25ae58362292235cc9213ca57 ]

    Currently the software node is removed in error case and at ->remove()
    stage unconditionally, that ruins the symmetry. Besides, in some cases,
    when mfd_add_device() fails, the device_remove_software_node() call
    may lead to NULL pointer dereference:

    BUG: kernel NULL pointer dereference, address: 00000000
    ...
    EIP: strlen+0x12/0x20
    ...
    kernfs_name_hash+0x13/0x70
    kernfs_find_ns+0x32/0xc0
    kernfs_remove_by_name_ns+0x2a/0x90
    sysfs_remove_link+0x16/0x30
    software_node_notify.cold+0x34/0x6b
    device_remove_software_node+0x5a/0x90
    mfd_add_device.cold+0x30a/0x427

    Fix all these by guarding device_remove_software_node() with a conditional
    and locating it at the right place.

    Fixes: 42e59982917a ("mfd: core: Add support for software nodes")
    Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
    Signed-off-by: Lee Jones <lee.jones@linaro.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/mfd/mfd-core.c | 15 +++++++++------
    1 file changed, 9 insertions(+), 6 deletions(-)

    diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
    index 6f02b8022c6d..79f5c6a18815 100644
    --- a/drivers/mfd/mfd-core.c
    +++ b/drivers/mfd/mfd-core.c
    @@ -266,18 +266,18 @@ static int mfd_add_device(struct device *parent, int id,
    if (has_acpi_companion(&pdev->dev)) {
    ret = acpi_check_resource_conflict(&res[r]);
    if (ret)
    - goto fail_of_entry;
    + goto fail_res_conflict;
    }
    }
    }

    ret = platform_device_add_resources(pdev, res, cell->num_resources);
    if (ret)
    - goto fail_of_entry;
    + goto fail_res_conflict;

    ret = platform_device_add(pdev);
    if (ret)
    - goto fail_of_entry;
    + goto fail_res_conflict;

    if (cell->pm_runtime_no_callbacks)
    pm_runtime_no_callbacks(&pdev->dev);
    @@ -286,13 +286,15 @@ static int mfd_add_device(struct device *parent, int id,

    return 0;

    +fail_res_conflict:
    + if (cell->swnode)
    + device_remove_software_node(&pdev->dev);
    fail_of_entry:
    list_for_each_entry_safe(of_entry, tmp, &mfd_of_node_list, list)
    if (of_entry->dev == &pdev->dev) {
    list_del(&of_entry->list);
    kfree(of_entry);
    }
    - device_remove_software_node(&pdev->dev);
    fail_alias:
    regulator_bulk_unregister_supply_alias(&pdev->dev,
    cell->parent_supplies,
    @@ -358,11 +360,12 @@ static int mfd_remove_devices_fn(struct device *dev, void *data)
    if (level && cell->level > *level)
    return 0;

    + if (cell->swnode)
    + device_remove_software_node(&pdev->dev);
    +
    regulator_bulk_unregister_supply_alias(dev, cell->parent_supplies,
    cell->num_parent_supplies);

    - device_remove_software_node(&pdev->dev);
    -
    platform_device_unregister(pdev);
    return 0;
    }
    --
    2.30.2


    \
     
     \ /
      Last update: 2021-07-12 11:10    [W:2.826 / U:0.352 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site