mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 17:25:35 +03:00
platform: dce: fix ipc_client_unregister race cond
This patch fixes a race condition between tegra_dce_unregister_ipc_client and dce_client_ipc_wakeup. If dce_client_ipc_wakeup is called just after unregistering it'll result in accessing already freed data structures and kernel crash. This patch adds a check to validate if the client_ipc struct is valid before accessing its members. Bug 4913921 Change-Id: Ie7f25379d7254d1f1ad4fb17baafee353f6d9eca Signed-off-by: Mahesh Kumar <mahkumar@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3239873 GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com> Reviewed-by: Vinod Gopalakrishnakurup <vinodg@nvidia.com> (cherry picked from commit 91a3402525e79bc59c7367743740c17a91e8752e) Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3256954 (cherry picked from commit 6bce903d9e8c8de4c2017abc33191a983343a0c2) Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3261855 Reviewed-by: svcacv <svcacv@nvidia.com>
This commit is contained in:
committed by
mobile promotions
parent
322d0bafa1
commit
472d0dfdf3
@@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-only
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
* SPDX-FileCopyrightText: Copyright (c) 2019-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <dce.h>
|
#include <dce.h>
|
||||||
@@ -89,22 +89,17 @@ static int dce_client_ipc_handle_alloc(u32 *handle)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dce_client_ipc_handle_free(u32 handle)
|
static int dce_client_ipc_handle_free(struct tegra_dce_client_ipc *cl)
|
||||||
{
|
{
|
||||||
struct tegra_dce *d;
|
struct tegra_dce *d;
|
||||||
struct tegra_dce_client_ipc *cl;
|
|
||||||
|
|
||||||
if (!is_client_handle_valid(handle))
|
if ((cl == NULL) || (cl->valid == false))
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
cl = &client_handles[client_handle_to_index(handle)];
|
|
||||||
|
|
||||||
if (cl->valid == false)
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
d = cl->d;
|
d = cl->d;
|
||||||
d->d_clients[cl->type] = NULL;
|
d->d_clients[cl->type] = NULL;
|
||||||
memset(cl, 0, sizeof(struct tegra_dce_client_ipc));
|
memset(cl, 0, sizeof(struct tegra_dce_client_ipc));
|
||||||
|
cl->valid = false;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -129,7 +124,7 @@ int tegra_dce_register_ipc_client(u32 type,
|
|||||||
int ret;
|
int ret;
|
||||||
uint32_t int_type;
|
uint32_t int_type;
|
||||||
struct tegra_dce *d = NULL;
|
struct tegra_dce *d = NULL;
|
||||||
struct tegra_dce_client_ipc *cl;
|
struct tegra_dce_client_ipc *cl = NULL;
|
||||||
u32 handle = DCE_CLIENT_IPC_HANDLE_INVALID;
|
u32 handle = DCE_CLIENT_IPC_HANDLE_INVALID;
|
||||||
|
|
||||||
if (handlep == NULL) {
|
if (handlep == NULL) {
|
||||||
@@ -185,11 +180,12 @@ int tegra_dce_register_ipc_client(u32 type,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cl->valid = true;
|
||||||
d->d_clients[type] = cl;
|
d->d_clients[type] = cl;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
dce_client_ipc_handle_free(handle);
|
(void)dce_client_ipc_handle_free(cl);
|
||||||
handle = DCE_CLIENT_IPC_HANDLE_INVALID;
|
handle = DCE_CLIENT_IPC_HANDLE_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,8 +205,9 @@ int tegra_dce_unregister_ipc_client(u32 handle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
dce_cond_destroy(&cl->recv_wait);
|
dce_cond_destroy(&cl->recv_wait);
|
||||||
|
atomic_set(&cl->complete, 0);
|
||||||
|
|
||||||
return dce_client_ipc_handle_free(handle);
|
return dce_client_ipc_handle_free(cl);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(tegra_dce_unregister_ipc_client);
|
EXPORT_SYMBOL(tegra_dce_unregister_ipc_client);
|
||||||
|
|
||||||
@@ -368,7 +365,7 @@ void dce_client_ipc_wakeup(struct tegra_dce *d, u32 ch_type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
cl = d->d_clients[type];
|
cl = d->d_clients[type];
|
||||||
if ((cl == NULL) || (cl->int_type != ch_type)) {
|
if ((cl == NULL) || (cl->valid == false) || (cl->int_type != ch_type)) {
|
||||||
dce_err(d, "Failed to retrieve client info for ch_type: [%d]",
|
dce_err(d, "Failed to retrieve client info for ch_type: [%d]",
|
||||||
ch_type);
|
ch_type);
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user