usb: f_gsi: Fix the error path in gsi_update_function_bind_params

Currently if usb_ep_autoconfig fails, we go ahead and free the
requests and buffers even before allocation this. This can lead
to potential kernel panics. Prevent this by fixing the failure
path in gsi_update_function_bind_params().

While at it, introduce a new function gsi_assign_string_ids()
to reduce the cyclomatic complexity.

Change-Id: I545be5db3d3bec0e13e29a7854ba6dff210936e2
Signed-off-by: Prashanth K <quic_prashk@quicinc.com>
Signed-off-by: Udipto Goswami <quic_ugoswami@quicinc.com>
This commit is contained in:
Prashanth K 2023-07-17 16:34:41 +05:30 committed by Udipto Goswami
parent 49626d70d0
commit c62967c152

View file

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2022,2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/module.h>
@ -2652,13 +2652,11 @@ static int gsi_func_suspend(struct usb_function *f, u8 options)
return 0;
}
static int gsi_update_function_bind_params(struct f_gsi *gsi,
static int gsi_assign_string_ids(struct f_gsi *gsi,
struct usb_composite_dev *cdev,
struct gsi_function_bind_info *info)
{
struct usb_ep *ep;
struct usb_cdc_notification *event;
struct usb_function *f = &gsi->function;
int status;
if (info->ctrl_str_idx >= 0 && info->ctrl_desc) {
@ -2714,6 +2712,23 @@ static int gsi_update_function_bind_params(struct f_gsi *gsi,
if (info->data_nop_desc)
info->data_nop_desc->bInterfaceNumber = gsi->data_id;
return 0;
}
static int gsi_update_function_bind_params(struct f_gsi *gsi,
struct usb_composite_dev *cdev,
struct gsi_function_bind_info *info)
{
struct usb_ep *ep;
struct usb_cdc_notification *event;
struct usb_function *f = &gsi->function;
int status;
status = gsi_assign_string_ids(gsi, cdev, info);
if (status < 0)
return status;
/* allocate instance-specific endpoints */
if (info->fs_in_desc) {
ep = usb_ep_autoconfig(cdev->gadget, info->fs_in_desc);
@ -2748,7 +2763,7 @@ static int gsi_update_function_bind_params(struct f_gsi *gsi,
gsi->c_port.notify_req->buf =
kmalloc(info->notify_buf_len, GFP_KERNEL);
if (!gsi->c_port.notify_req->buf)
goto fail;
goto free_req;
gsi->c_port.notify_req->length = info->notify_buf_len;
gsi->c_port.notify_req->context = gsi;
@ -2801,15 +2816,17 @@ static int gsi_update_function_bind_params(struct f_gsi *gsi,
status = usb_assign_descriptors(f, info->fs_desc_hdr, info->hs_desc_hdr,
info->ss_desc_hdr, info->ss_desc_hdr);
if (status)
goto fail;
goto free_req_buf;
return 0;
fail:
if (gsi->c_port.notify_req) {
free_req_buf:
if (gsi->c_port.notify_req && gsi->c_port.notify_req->buf)
kfree(gsi->c_port.notify_req->buf);
free_req:
if (gsi->c_port.notify_req)
usb_ep_free_request(gsi->c_port.notify, gsi->c_port.notify_req);
}
fail:
/* we might as well release our claims on endpoints */
if (gsi->c_port.notify)
gsi->c_port.notify->driver_data = NULL;