Bluetooth: hci_qca: Remove hdev dereference in qca_close().
When flag KASAN is set, we are seeing an following crash while removing hci_uart module. [ 50.589909] Unable to handle kernel paging request at virtual address 6b6b6b6b6b6b73 [ 50.597902] Mem abort info: [ 50.600846] Exception class = DABT (current EL), IL = 32 bits [ 50.606959] SET = 0, FnV = 0 [ 50.610142] EA = 0, S1PTW = 0 [ 50.613396] Data abort info: [ 50.616401] ISV = 0, ISS = 0x00000004 [ 50.620373] CM = 0, WnR = 0 [ 50.623466] [006b6b6b6b6b6b73] address between user and kernel address ranges [ 50.630818] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 50.671670] PC is at qca_power_shutdown+0x28/0x100 [hci_uart] [ 50.677593] LR is at qca_close+0x74/0xb0 [hci_uart] [ 50.775689] Process rmmod (pid: 2144, stack limit = 0xffffff801ba90000) [ 50.782493] Call trace: [ 50.872150] [<ffffff8000c3c81c>] qca_power_shutdown+0x28/0x100 [hci_uart] [ 50.879138] [<ffffff8000c3c968>] qca_close+0x74/0xb0 [hci_uart] [ 50.885238] [<ffffff8000c3a71c>] hci_uart_unregister_device+0x44/0x50 [hci_uart] [ 50.892846] [<ffffff8000c3c9f4>] qca_serdev_remove+0x50/0x5c [hci_uart] [ 50.899654] [<ffffff800844f630>] serdev_drv_remove+0x28/0x38 [ 50.905489] [<ffffff800850fc44>] device_release_driver_internal+0x140/0x1e4 [ 50.912653] [<ffffff800850fd94>] driver_detach+0x78/0x84 [ 50.918121] [<ffffff800850edac>] bus_remove_driver+0x80/0xa8 [ 50.923942] [<ffffff80085107dc>] driver_unregister+0x4c/0x58 [ 50.929768] [<ffffff8000c3ca8c>] qca_deinit+0x24/0x598 [hci_uart] [ 50.936045] [<ffffff8000c3ca10>] hci_uart_exit+0x10/0x48 [hci_uart] [ 50.942495] [<ffffff8008136630>] SyS_delete_module+0x17c/0x224 This crash is due to dereference of hdev, after freeing it. Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
Родитель
ca30ccd219
Коммит
c2d7827338
|
@ -167,7 +167,7 @@ struct qca_serdev {
|
||||||
};
|
};
|
||||||
|
|
||||||
static int qca_power_setup(struct hci_uart *hu, bool on);
|
static int qca_power_setup(struct hci_uart *hu, bool on);
|
||||||
static void qca_power_shutdown(struct hci_dev *hdev);
|
static void qca_power_shutdown(struct hci_uart *hu);
|
||||||
|
|
||||||
static void __serial_clock_on(struct tty_struct *tty)
|
static void __serial_clock_on(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
|
@ -608,7 +608,7 @@ static int qca_close(struct hci_uart *hu)
|
||||||
if (hu->serdev) {
|
if (hu->serdev) {
|
||||||
qcadev = serdev_device_get_drvdata(hu->serdev);
|
qcadev = serdev_device_get_drvdata(hu->serdev);
|
||||||
if (qcadev->btsoc_type == QCA_WCN3990)
|
if (qcadev->btsoc_type == QCA_WCN3990)
|
||||||
qca_power_shutdown(hu->hdev);
|
qca_power_shutdown(hu);
|
||||||
else
|
else
|
||||||
gpiod_set_value_cansleep(qcadev->bt_en, 0);
|
gpiod_set_value_cansleep(qcadev->bt_en, 0);
|
||||||
|
|
||||||
|
@ -1230,12 +1230,15 @@ static const struct qca_vreg_data qca_soc_data = {
|
||||||
.num_vregs = 4,
|
.num_vregs = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void qca_power_shutdown(struct hci_dev *hdev)
|
static void qca_power_shutdown(struct hci_uart *hu)
|
||||||
{
|
{
|
||||||
struct hci_uart *hu = hci_get_drvdata(hdev);
|
struct serdev_device *serdev = hu->serdev;
|
||||||
|
unsigned char cmd = QCA_WCN3990_POWEROFF_PULSE;
|
||||||
|
|
||||||
host_set_baudrate(hu, 2400);
|
host_set_baudrate(hu, 2400);
|
||||||
qca_send_power_pulse(hdev, QCA_WCN3990_POWEROFF_PULSE);
|
hci_uart_set_flow_control(hu, true);
|
||||||
|
serdev_device_write_buf(serdev, &cmd, sizeof(cmd));
|
||||||
|
hci_uart_set_flow_control(hu, false);
|
||||||
qca_power_setup(hu, false);
|
qca_power_setup(hu, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1411,7 +1414,7 @@ static void qca_serdev_remove(struct serdev_device *serdev)
|
||||||
struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
|
struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
|
||||||
|
|
||||||
if (qcadev->btsoc_type == QCA_WCN3990)
|
if (qcadev->btsoc_type == QCA_WCN3990)
|
||||||
qca_power_shutdown(qcadev->serdev_hu.hdev);
|
qca_power_shutdown(&qcadev->serdev_hu);
|
||||||
else
|
else
|
||||||
clk_disable_unprepare(qcadev->susclk);
|
clk_disable_unprepare(qcadev->susclk);
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче