lkml.org 
[lkml]   [2019]   [Mar]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH AUTOSEL 4.19 092/192] Bluetooth: hci_ldisc: Initialize hci_dev before open()
    Date
    From: Jeremy Cline <jcline@redhat.com>

    [ Upstream commit 32a7b4cbe93b0a0ef7e63d31ca69ce54736c4412 ]

    The hci_dev struct hdev is referenced in work queues and timers started
    by open() in some protocols. This creates a race between the
    initialization function and the work or timer which can result hdev
    being dereferenced while it is still null.

    The syzbot report contains a reliable reproducer which causes a null
    pointer dereference of hdev in hci_uart_write_work() by making the
    memory allocation for hdev fail.

    To fix this, ensure hdev is valid from before calling a protocol's
    open() until after calling a protocol's close().

    Reported-by: syzbot+257790c15bcdef6fe00c@syzkaller.appspotmail.com
    Signed-off-by: Jeremy Cline <jcline@redhat.com>
    Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/bluetooth/hci_ldisc.c | 21 ++++++++++++++-------
    1 file changed, 14 insertions(+), 7 deletions(-)

    diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
    index ea6238ed5c0e..8776906cafca 100644
    --- a/drivers/bluetooth/hci_ldisc.c
    +++ b/drivers/bluetooth/hci_ldisc.c
    @@ -207,11 +207,11 @@ void hci_uart_init_work(struct work_struct *work)
    err = hci_register_dev(hu->hdev);
    if (err < 0) {
    BT_ERR("Can't register HCI device");
    + clear_bit(HCI_UART_PROTO_READY, &hu->flags);
    + hu->proto->close(hu);
    hdev = hu->hdev;
    hu->hdev = NULL;
    hci_free_dev(hdev);
    - clear_bit(HCI_UART_PROTO_READY, &hu->flags);
    - hu->proto->close(hu);
    return;
    }

    @@ -616,6 +616,7 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data,
    static int hci_uart_register_dev(struct hci_uart *hu)
    {
    struct hci_dev *hdev;
    + int err;

    BT_DBG("");

    @@ -659,11 +660,22 @@ static int hci_uart_register_dev(struct hci_uart *hu)
    else
    hdev->dev_type = HCI_PRIMARY;

    + /* Only call open() for the protocol after hdev is fully initialized as
    + * open() (or a timer/workqueue it starts) may attempt to reference it.
    + */
    + err = hu->proto->open(hu);
    + if (err) {
    + hu->hdev = NULL;
    + hci_free_dev(hdev);
    + return err;
    + }
    +
    if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags))
    return 0;

    if (hci_register_dev(hdev) < 0) {
    BT_ERR("Can't register HCI device");
    + hu->proto->close(hu);
    hu->hdev = NULL;
    hci_free_dev(hdev);
    return -ENODEV;
    @@ -683,17 +695,12 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id)
    if (!p)
    return -EPROTONOSUPPORT;

    - err = p->open(hu);
    - if (err)
    - return err;
    -
    hu->proto = p;
    set_bit(HCI_UART_PROTO_READY, &hu->flags);

    err = hci_uart_register_dev(hu);
    if (err) {
    clear_bit(HCI_UART_PROTO_READY, &hu->flags);
    - p->close(hu);
    return err;
    }

    --
    2.19.1
    \
     
     \ /
      Last update: 2019-03-27 20:05    [W:4.061 / U:0.096 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site