lkml.org 
[lkml]   [2022]   [Aug]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.10 466/545] firmware: arm_scpi: Ensure scpi_info is not assigned if the probe fails
    Date
    From: Sudeep Holla <sudeep.holla@arm.com>

    [ Upstream commit 689640efc0a2c4e07e6f88affe6d42cd40cc3f85 ]

    When scpi probe fails, at any point, we need to ensure that the scpi_info
    is not set and will remain NULL until the probe succeeds. If it is not
    taken care, then it could result use-after-free as the value is exported
    via get_scpi_ops() and could refer to a memory allocated via devm_kzalloc()
    but freed when the probe fails.

    Link: https://lore.kernel.org/r/20220701160310.148344-1-sudeep.holla@arm.com
    Cc: stable@vger.kernel.org # 4.19+
    Reported-by: huhai <huhai@kylinos.cn>
    Reviewed-by: Jackie Liu <liuyun01@kylinos.cn>
    Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/firmware/arm_scpi.c | 61 +++++++++++++++++++++----------------
    1 file changed, 35 insertions(+), 26 deletions(-)

    diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c
    index 4ceba5ef7895..36391cb5130e 100644
    --- a/drivers/firmware/arm_scpi.c
    +++ b/drivers/firmware/arm_scpi.c
    @@ -815,7 +815,7 @@ static int scpi_init_versions(struct scpi_drvinfo *info)
    info->firmware_version = le32_to_cpu(caps.platform_version);
    }
    /* Ignore error if not implemented */
    - if (scpi_info->is_legacy && ret == -EOPNOTSUPP)
    + if (info->is_legacy && ret == -EOPNOTSUPP)
    return 0;

    return ret;
    @@ -905,13 +905,14 @@ static int scpi_probe(struct platform_device *pdev)
    struct resource res;
    struct device *dev = &pdev->dev;
    struct device_node *np = dev->of_node;
    + struct scpi_drvinfo *scpi_drvinfo;

    - scpi_info = devm_kzalloc(dev, sizeof(*scpi_info), GFP_KERNEL);
    - if (!scpi_info)
    + scpi_drvinfo = devm_kzalloc(dev, sizeof(*scpi_drvinfo), GFP_KERNEL);
    + if (!scpi_drvinfo)
    return -ENOMEM;

    if (of_match_device(legacy_scpi_of_match, &pdev->dev))
    - scpi_info->is_legacy = true;
    + scpi_drvinfo->is_legacy = true;

    count = of_count_phandle_with_args(np, "mboxes", "#mbox-cells");
    if (count < 0) {
    @@ -919,19 +920,19 @@ static int scpi_probe(struct platform_device *pdev)
    return -ENODEV;
    }

    - scpi_info->channels = devm_kcalloc(dev, count, sizeof(struct scpi_chan),
    - GFP_KERNEL);
    - if (!scpi_info->channels)
    + scpi_drvinfo->channels =
    + devm_kcalloc(dev, count, sizeof(struct scpi_chan), GFP_KERNEL);
    + if (!scpi_drvinfo->channels)
    return -ENOMEM;

    - ret = devm_add_action(dev, scpi_free_channels, scpi_info);
    + ret = devm_add_action(dev, scpi_free_channels, scpi_drvinfo);
    if (ret)
    return ret;

    - for (; scpi_info->num_chans < count; scpi_info->num_chans++) {
    + for (; scpi_drvinfo->num_chans < count; scpi_drvinfo->num_chans++) {
    resource_size_t size;
    - int idx = scpi_info->num_chans;
    - struct scpi_chan *pchan = scpi_info->channels + idx;
    + int idx = scpi_drvinfo->num_chans;
    + struct scpi_chan *pchan = scpi_drvinfo->channels + idx;
    struct mbox_client *cl = &pchan->cl;
    struct device_node *shmem = of_parse_phandle(np, "shmem", idx);

    @@ -975,45 +976,53 @@ static int scpi_probe(struct platform_device *pdev)
    return ret;
    }

    - scpi_info->commands = scpi_std_commands;
    + scpi_drvinfo->commands = scpi_std_commands;

    - platform_set_drvdata(pdev, scpi_info);
    + platform_set_drvdata(pdev, scpi_drvinfo);

    - if (scpi_info->is_legacy) {
    + if (scpi_drvinfo->is_legacy) {
    /* Replace with legacy variants */
    scpi_ops.clk_set_val = legacy_scpi_clk_set_val;
    - scpi_info->commands = scpi_legacy_commands;
    + scpi_drvinfo->commands = scpi_legacy_commands;

    /* Fill priority bitmap */
    for (idx = 0; idx < ARRAY_SIZE(legacy_hpriority_cmds); idx++)
    set_bit(legacy_hpriority_cmds[idx],
    - scpi_info->cmd_priority);
    + scpi_drvinfo->cmd_priority);
    }

    - ret = scpi_init_versions(scpi_info);
    + scpi_info = scpi_drvinfo;
    +
    + ret = scpi_init_versions(scpi_drvinfo);
    if (ret) {
    dev_err(dev, "incorrect or no SCP firmware found\n");
    + scpi_info = NULL;
    return ret;
    }

    - if (scpi_info->is_legacy && !scpi_info->protocol_version &&
    - !scpi_info->firmware_version)
    + if (scpi_drvinfo->is_legacy && !scpi_drvinfo->protocol_version &&
    + !scpi_drvinfo->firmware_version)
    dev_info(dev, "SCP Protocol legacy pre-1.0 firmware\n");
    else
    dev_info(dev, "SCP Protocol %lu.%lu Firmware %lu.%lu.%lu version\n",
    FIELD_GET(PROTO_REV_MAJOR_MASK,
    - scpi_info->protocol_version),
    + scpi_drvinfo->protocol_version),
    FIELD_GET(PROTO_REV_MINOR_MASK,
    - scpi_info->protocol_version),
    + scpi_drvinfo->protocol_version),
    FIELD_GET(FW_REV_MAJOR_MASK,
    - scpi_info->firmware_version),
    + scpi_drvinfo->firmware_version),
    FIELD_GET(FW_REV_MINOR_MASK,
    - scpi_info->firmware_version),
    + scpi_drvinfo->firmware_version),
    FIELD_GET(FW_REV_PATCH_MASK,
    - scpi_info->firmware_version));
    - scpi_info->scpi_ops = &scpi_ops;
    + scpi_drvinfo->firmware_version));
    +
    + scpi_drvinfo->scpi_ops = &scpi_ops;

    - return devm_of_platform_populate(dev);
    + ret = devm_of_platform_populate(dev);
    + if (ret)
    + scpi_info = NULL;
    +
    + return ret;
    }

    static const struct of_device_id scpi_of_match[] = {
    --
    2.35.1


    \
     
     \ /
      Last update: 2022-08-19 18:44    [W:4.037 / U:0.008 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site