From 6feb842be06bf94e4751c499cd8b4659974c6f03 Mon Sep 17 00:00:00 2001 From: Tamas Koczka Date: Wed, 2 Nov 2022 10:30:06 +0000 Subject: executor: fix "wrong response packet" in BT fuzzing (#3493) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: the BT initialization logic (`initialize_vhci()` in `common_linux.h`) expected `HCI_VENDOR_PKT` to be sent first, but this is not always the case as the kernel sends these two packets almost at the same time (both are sent as the result of the `open("/dev/vhci", …)` call): * syscall thread: `HCI_VENDOR_PKT` (in `__vhci_create_device`) * `power_on` queue thread: `HCI_OP_RESET` (from `hci_reset_sync` <- `hci_init1_sync` <- `hci_init_sync` <- `hci_dev_open_sync` <- `hci_dev_do_open` <- `hci_power_on` <- `hdev->power_on` <- (worker queue) <- `hci_register_dev` <- `__vhci_create_device`) Solution: handle both `HCI_OP_RESET` and `HCI_VENDOR_PKT` packets in `initialize_vhci`. Also instead of waiting for the kernel to send `HCI_VENDOR_PKT` after 1 second, we initiate the setup by sending `HCI_VENDOR_PKT` (request) to the kernel first. --- executor/common_linux.h | 48 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 11 deletions(-) (limited to 'executor') diff --git a/executor/common_linux.h b/executor/common_linux.h index 39a687e36..10f693815 100644 --- a/executor/common_linux.h +++ b/executor/common_linux.h @@ -2586,11 +2586,21 @@ struct hci_dev_req { uint32 dev_opt; }; -struct vhci_vendor_pkt { +struct vhci_vendor_pkt_request { uint8 type; uint8 opcode; - uint16 id; -}; +} __attribute__((packed)); + +struct vhci_pkt { + uint8 type; + union { + struct { + uint8 opcode; + uint16 id; + } __attribute__((packed)) vendor_pkt; + struct hci_command_hdr command_hdr; + }; +} __attribute__((packed)); #define HCIDEVUP _IOW('H', 201, int) #define HCISETSCAN _IOW('H', 221, int) @@ -2718,6 +2728,9 @@ static void* event_thread(void* arg) #define HCI_HANDLE_1 200 #define HCI_HANDLE_2 201 +#define HCI_PRIMARY 0 +#define HCI_OP_RESET 0x0c03 + static void initialize_vhci() { #if SYZ_EXECUTOR @@ -2741,25 +2754,38 @@ static void initialize_vhci() close(vhci_fd); vhci_fd = kVhciFd; - struct vhci_vendor_pkt vendor_pkt; - if (read(vhci_fd, &vendor_pkt, sizeof(vendor_pkt)) != sizeof(vendor_pkt)) - fail("read failed"); + struct vhci_vendor_pkt_request vendor_pkt_req = {HCI_VENDOR_PKT, HCI_PRIMARY}; + if (write(vhci_fd, &vendor_pkt_req, sizeof(vendor_pkt_req)) != sizeof(vendor_pkt_req)) + fail("vendor_pkt_req write failed"); + + struct vhci_pkt vhci_pkt; + if (read(vhci_fd, &vhci_pkt, sizeof(vhci_pkt)) != sizeof(vhci_pkt)) + fail("vhci_pkt read failed"); + + if (vhci_pkt.type == HCI_COMMAND_PKT && vhci_pkt.command_hdr.opcode == HCI_OP_RESET) { + char response[1] = {0}; + hci_send_event_cmd_complete(vhci_fd, HCI_OP_RESET, response, sizeof(response)); + + if (read(vhci_fd, &vhci_pkt, sizeof(vhci_pkt)) != sizeof(vhci_pkt)) + fail("vhci_pkt read failed"); + } - if (vendor_pkt.type != HCI_VENDOR_PKT) + if (vhci_pkt.type != HCI_VENDOR_PKT) fail("wrong response packet"); - debug("hci dev id: %x\n", vendor_pkt.id); + int dev_id = vhci_pkt.vendor_pkt.id; + debug("hci dev id: %x\n", dev_id); pthread_t th; if (pthread_create(&th, NULL, event_thread, NULL)) fail("pthread_create failed"); // Bring hci device up - int ret = ioctl(hci_sock, HCIDEVUP, vendor_pkt.id); + int ret = ioctl(hci_sock, HCIDEVUP, dev_id); if (ret) { if (errno == ERFKILL) { rfkill_unblock_all(); - ret = ioctl(hci_sock, HCIDEVUP, vendor_pkt.id); + ret = ioctl(hci_sock, HCIDEVUP, dev_id); } if (ret && errno != EALREADY) @@ -2768,7 +2794,7 @@ static void initialize_vhci() // Activate page scanning mode which is required to fake a connection. struct hci_dev_req dr = {0}; - dr.dev_id = vendor_pkt.id; + dr.dev_id = dev_id; dr.dev_opt = SCAN_PAGE; if (ioctl(hci_sock, HCISETSCAN, &dr)) fail("ioctl(HCISETSCAN) failed"); -- cgit mrf-deployment