mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-09 21:59:12 -04:00
i2c-msm-geni: KASAN: use-after-free in __list_add_valid+0x2c/0xc4
This UAF issue is seen when driver is removed and inserted. During driver removal, pm runtime resume callback invoked in which as part of clock, ab/ib nodes are added in common struct geni_se_dev. As part of driver exit, we are not removing the ab/ib list from common structure list due to which the issue is seen when driver is loaded. As part of driver removal, checking the status of runtime suspend if it is not suspended, invoke geni suspend call otherwise ignore. So by suspend call ensured that ab/ib are removed from lists, so that UAF will not be encountered when next load of driver. Change-Id: I1f0c7a29c5e268a1ab5c017e271ad0484dcab24f Signed-off-by: Praveen Talari <quic_ptalari@quicinc.com> Signed-off-by: Vaishnavi AVS <quic_vavs@quicinc.com>
This commit is contained in:
parent
0b52a8030f
commit
ed404b2b80
1 changed files with 51 additions and 4 deletions
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
|
|
@ -136,10 +137,12 @@ struct geni_i2c_dev {
|
|||
bool disable_dma_mode;
|
||||
bool prev_cancel_pending; //Halt cancel till IOS in good state
|
||||
bool is_i2c_rtl_based; /* doing pending cancel only for rtl based SE's */
|
||||
atomic_t is_xfer_in_progress; /* Used to maintain xfer inprogress status */
|
||||
};
|
||||
|
||||
static struct geni_i2c_dev *gi2c_dev_dbg[MAX_SE];
|
||||
static int arr_idx;
|
||||
static int geni_i2c_runtime_suspend(struct device *dev);
|
||||
|
||||
struct geni_i2c_err_log {
|
||||
int err;
|
||||
|
|
@ -1052,11 +1055,13 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
|
|||
int i, ret = 0, timeout = 0;
|
||||
|
||||
gi2c->err = 0;
|
||||
atomic_set(&gi2c->is_xfer_in_progress, 1);
|
||||
|
||||
/* Client to respect system suspend */
|
||||
if (!pm_runtime_enabled(gi2c->dev)) {
|
||||
GENI_SE_ERR(gi2c->ipcl, false, gi2c->dev,
|
||||
"%s: System suspended\n", __func__);
|
||||
atomic_set(&gi2c->is_xfer_in_progress, 0);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
|
|
@ -1068,6 +1073,7 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
|
|||
pm_runtime_put_noidle(gi2c->dev);
|
||||
/* Set device in suspended since resume failed */
|
||||
pm_runtime_set_suspended(gi2c->dev);
|
||||
atomic_set(&gi2c->is_xfer_in_progress, 0);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
|
@ -1078,12 +1084,13 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
|
|||
if (ret) {
|
||||
pm_runtime_mark_last_busy(gi2c->dev);
|
||||
pm_runtime_put_autosuspend(gi2c->dev);
|
||||
atomic_set(&gi2c->is_xfer_in_progress, 0);
|
||||
return ret; //Don't perform xfer is cancel failed
|
||||
}
|
||||
}
|
||||
|
||||
GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
|
||||
"n:%d addr:0x%x\n", num, msgs[0].addr);
|
||||
"n:%d addr:0x%x\n", num, msgs[0].addr);
|
||||
|
||||
gi2c->dbg_num = num;
|
||||
kfree(gi2c->dbg_buf_ptr);
|
||||
|
|
@ -1268,7 +1275,7 @@ geni_i2c_txn_ret:
|
|||
pm_runtime_mark_last_busy(gi2c->dev);
|
||||
pm_runtime_put_autosuspend(gi2c->dev);
|
||||
}
|
||||
|
||||
atomic_set(&gi2c->is_xfer_in_progress, 0);
|
||||
gi2c->cur = NULL;
|
||||
GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
|
||||
"i2c txn ret:%d, num:%d, err:%d\n", ret, num, gi2c->err);
|
||||
|
|
@ -1476,10 +1483,10 @@ static int geni_i2c_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
atomic_set(&gi2c->is_xfer_in_progress, 0);
|
||||
snprintf(boot_marker, sizeof(boot_marker),
|
||||
"M - DRIVER GENI_I2C_%d Ready", gi2c->adap.nr);
|
||||
"M - DRIVER GENI_I2C_%d Ready", gi2c->adap.nr);
|
||||
place_marker(boot_marker);
|
||||
|
||||
dev_info(gi2c->dev, "I2C probed\n");
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1489,6 +1496,33 @@ static int geni_i2c_remove(struct platform_device *pdev)
|
|||
struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
|
||||
if (atomic_read(&gi2c->is_xfer_in_progress)) {
|
||||
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
|
||||
"%s: Xfer is in progress\n", __func__);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (!pm_runtime_status_suspended(gi2c->dev)) {
|
||||
if (geni_i2c_runtime_suspend(gi2c->dev))
|
||||
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
|
||||
"%s: runtime suspend failed\n", __func__);
|
||||
}
|
||||
|
||||
if (gi2c->se_mode == GSI_ONLY) {
|
||||
if (gi2c->tx_c) {
|
||||
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
|
||||
"%s: clearing tx dma resource\n", __func__);
|
||||
dma_release_channel(gi2c->tx_c);
|
||||
}
|
||||
if (gi2c->rx_c) {
|
||||
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
|
||||
"%s: clearing rx dma resource\n", __func__);
|
||||
dma_release_channel(gi2c->rx_c);
|
||||
}
|
||||
}
|
||||
|
||||
pm_runtime_put_noidle(gi2c->dev);
|
||||
pm_runtime_set_suspended(gi2c->dev);
|
||||
pm_runtime_disable(gi2c->dev);
|
||||
i2c_del_adapter(&gi2c->adap);
|
||||
|
||||
|
|
@ -1594,6 +1628,19 @@ static int geni_i2c_suspend_late(struct device *device)
|
|||
int ret;
|
||||
|
||||
GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", __func__);
|
||||
|
||||
if (atomic_read(&gi2c->is_xfer_in_progress)) {
|
||||
if (!pm_runtime_status_suspended(gi2c->dev)) {
|
||||
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
|
||||
":%s: runtime PM is active\n", __func__);
|
||||
return -EBUSY;
|
||||
}
|
||||
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
|
||||
"%s System suspend not allowed while xfer in progress\n",
|
||||
__func__);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* Make sure no transactions are pending */
|
||||
ret = i2c_trylock_bus(&gi2c->adap, I2C_LOCK_SEGMENT);
|
||||
if (!ret) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue