From: Vasiliy Kovalev kovalev@altlinux.org
There is no need to drop the connection of some functions in which the conn->state in BT_CONNECTED is marked, since in the future the same check takes place (for example, in the hci_encrypt_change_evt() function) and the hci_conn_drop() is called.
Otherwise, the conn->refcnt will become below zero, which will trigger a warning and may cause a crash on kernels with the panic_on_warn parameter enabled.
Syzkaller hit 'WARNING in hci_conn_timeout' bug.
[ 23.485892] Bluetooth: Core ver 2.22 [ 23.485916] NET: Registered PF_BLUETOOTH protocol family [ 23.485917] Bluetooth: HCI device and connection manager initialized [ 23.486407] Bluetooth: HCI socket layer initialized [ 23.486410] Bluetooth: L2CAP socket layer initialized [ 23.486413] Bluetooth: SCO socket layer initialized [ 24.507112] Bluetooth: hci0: unexpected cc 0x0c03 length: 249 > 1 [ 24.507142] Bluetooth: hci0: unexpected cc 0x1003 length: 249 > 9 [ 24.507165] Bluetooth: hci0: unexpected cc 0x1001 length: 249 > 9 [ 24.508091] Bluetooth: hci0: unexpected cc 0x0c23 length: 249 > 4 [ 24.508109] Bluetooth: hci0: unexpected cc 0x0c25 length: 249 > 3 [ 24.508117] Bluetooth: hci0: unexpected cc 0x0c38 length: 249 > 2 [ 24.545962] Bluetooth: BNEP (Ethernet Emulation) ver 1.3 [ 24.545969] Bluetooth: BNEP filters: protocol multicast [ 24.545973] Bluetooth: BNEP socket layer initialized [ 24.547521] Bluetooth: MGMT ver 1.22 [ 26.553008] Bluetooth: hci0: command tx timeout [ 26.561518] Bluetooth: RFCOMM TTY layer initialized [ 26.561526] Bluetooth: RFCOMM socket layer initialized [ 26.561532] Bluetooth: RFCOMM ver 1.11 [ 28.602024] Bluetooth: hci0: Opcode 0x0c13 failed: -110 [ 28.602054] Bluetooth: hci0: command tx timeout [ 30.650011] Bluetooth: hci0: Opcode 0x0c24 failed: -110 [ 30.650021] Bluetooth: hci0: command tx timeout [ 32.696973] Bluetooth: hci0: command tx timeout [ 32.696985] Bluetooth: hci0: Opcode 0x0c24 failed: -110 [ 34.744973] Bluetooth: hci0: command 0x0406 tx timeout [ 34.745008] Bluetooth: hci0: Opcode 0x0c24 failed: -110 [ 36.792966] Bluetooth: hci0: Opcode 0x0c24 failed: -110 [ 36.792980] Bluetooth: hci0: command 0x0406 tx timeout [ 38.841027] Bluetooth: hci0: command 0x0406 tx timeout [ 38.841035] Bluetooth: hci0: Opcode 0x0c24 failed: -110 [ 40.889026] Bluetooth: hci0: Opcode 0x0c24 failed: -110 [ 40.889999] Bluetooth: hci0: command 0x0406 tx timeout [ 40.890012] Bluetooth: hci0: Opcode 0x0c24 failed: -110 [ 40.893629] NET: Registered PF_ALG protocol family [ 42.937008] Bluetooth: hci0: Opcode 0x0c24 failed: -110 [ 42.937023] Bluetooth: hci0: command 0x0406 tx timeout [ 44.984984] Bluetooth: hci0: Opcode 0x0c24 failed: -110 [ 44.985008] Bluetooth: hci0: command 0x0406 tx timeout [ 47.033023] Bluetooth: hci0: Opcode 0x0c1a failed: -110 [ 47.033044] Bluetooth: hci0: command 0x0406 tx timeout [ 49.080976] Bluetooth: hci0: command 0x0406 tx timeout [ 49.080985] Bluetooth: hci0: Opcode 0x0c24 failed: -110 [ 51.129140] Bluetooth: hci0: Opcode 0x0c24 failed: -110 [ 51.130051] Bluetooth: hci0: command 0x0406 tx timeout [ 53.177011] Bluetooth: hci0: command 0x0406 tx timeout [ 55.225969] Bluetooth: hci0: command 0x0406 tx timeout [ 57.272968] Bluetooth: hci0: command 0x0406 tx timeout [ 59.320982] Bluetooth: hci0: command 0x0406 tx timeout [ 61.368989] Bluetooth: hci0: command 0x0406 tx timeout [ 148.474066] ------------[ cut here ]------------ [ 148.474072] WARNING: CPU: 0 PID: 3835 at net/bluetooth/hci_conn.c:612 hci_conn_timeout+0x16/0x60 [bluetooth] [ 148.474115] Modules linked in: cmac algif_hash algif_skcipher af_alg rfcomm bnep hci_vhci bluetooth ecdh_generic uinput af_packet rfkill joydev hid_generic usbhid hid qrtr intel_rapl_msr intel_rapl_common intel_pmc_core kvm_intel nls_utf8 iTCO_wdt intel_pmc_bxt iTCO_vendor_support nls_cp866 vfat fat kvm irqbypass crct10dif_pclmul crc32_pclmul snd_hda_codec_generic crc32c_intel ghash_clmulni_intel ledtrig_audio sha512_ssse3 snd_hda_intel sha256_ssse3 sha1_ssse3 snd_intel_dspcfg snd_intel_sdw_acpi snd_hda_codec aesni_intel crypto_simd cryptd i2c_i801 snd_hda_core psmouse snd_hwdep i2c_smbus xhci_pci pcspkr snd_pcm lpc_ich xhci_pci_renesas xhci_hcd tiny_power_button qemu_fw_cfg button sch_fq_codel vboxvideo drm_vram_helper drm_ttm_helper ttm vboxsf vboxguest snd_seq_midi snd_seq_midi_event snd_seq snd_rawmidi snd_seq_device snd_timer snd soundcore msr fuse efi_pstore dm_mod ip_tables x_tables autofs4 virtio_gpu virtio_net virtio_dma_buf drm_shmem_helper net_failover drm_kms_helper [ 148.474210] virtio_rng drm virtio_scsi rng_core virtio_console virtio_balloon virtio_blk failover ahci libahci libata evdev input_leds serio_raw scsi_mod scsi_common virtio_pci virtio_pci_legacy_dev virtio_pci_modern_dev virtio_ring virtio intel_agp intel_gtt [ 148.474234] CPU: 0 PID: 3835 Comm: kworker/u5:2 Not tainted 6.1.85-un-def-alt1 #1 [ 148.474238] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.0-alt1 04/01/2014 [ 148.474241] Workqueue: hci0 hci_conn_timeout [bluetooth] [ 148.474265] RIP: 0010:hci_conn_timeout+0x16/0x60 [bluetooth] [ 148.474288] Code: 00 00 66 89 44 24 06 e8 58 a7 ff ff eb a8 e8 41 7b ee c1 90 0f 1f 44 00 00 8b 87 20 fd ff ff 85 c0 78 07 74 07 c3 cc cc cc cc <0f> 0b 55 0f b6 87 49 fd ff ff 48 8d af 10 fd ff ff 3c 01 74 12 be [ 148.474291] RSP: 0018:ffffa7fd80b53e90 EFLAGS: 00010286 [ 148.474295] RAX: 00000000fffe728b RBX: ffff8959c46ab180 RCX: ffff8959c3b70028 [ 148.474297] RDX: 0000000000000001 RSI: ffff8959c86ce0b0 RDI: ffff895a105aeaf0 [ 148.474299] RBP: ffff895a105aeaf0 R08: ffff8959c86ce0b0 R09: ffff8959c46ab1f4 [ 148.474301] R10: 0000000000000005 R11: 0000000000000005 R12: ffff8959c3b70000 [ 148.474302] R13: ffff8959ec495400 R14: 0000000000000000 R15: ffff8959ec495405 [ 148.474305] FS: 0000000000000000(0000) GS:ffff895a3dc00000(0000) knlGS:0000000000000000 [ 148.474308] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 148.474310] CR2: 00007f2a1b7baa48 CR3: 0000000034b98000 CR4: 0000000000750ef0 [ 148.474317] PKRU: 55555554 [ 148.474319] Call Trace: [ 148.474323] <TASK> [ 148.474327] ? __warn+0x79/0xc0 [ 148.474343] ? hci_conn_timeout+0x16/0x60 [bluetooth] [ 148.474364] ? report_bug+0xff/0x150 [ 148.474375] ? handle_bug+0x49/0xa0 [ 148.474398] ? exc_invalid_op+0x14/0x70 [ 148.474402] ? asm_exc_invalid_op+0x16/0x20 [ 148.474408] ? hci_conn_timeout+0x16/0x60 [bluetooth] [ 148.474441] process_one_work+0x217/0x3e0 [ 148.474467] worker_thread+0x4d/0x3c0 [ 148.474473] ? process_one_work+0x3e0/0x3e0 [ 148.474478] kthread+0xd6/0x100 [ 148.474482] ? kthread_complete_and_exit+0x20/0x20 [ 148.474486] ret_from_fork+0x1f/0x30 [ 148.474500] </TASK> [ 148.474502] ---[ end trace 0000000000000000 ]---
Fixes: 0fe29fd1cd77 ("Bluetooth: Read LE remote features during connection establishment") Fixes: 769be974d0c7 ("[Bluetooth] Use ACL config stage to retrieve remote features") Fixes: f8558555f31e ("[Bluetooth] Initiate authentication during connection establishment") Cc: stable@vger.kernel.org Signed-off-by: Vasiliy Kovalev kovalev@altlinux.org --- net/bluetooth/hci_event.c | 4 ---- 1 file changed, 4 deletions(-)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index a8b8cfebe0180c..64477e1bde7cec 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3529,7 +3529,6 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, void *data, } else { conn->state = BT_CONNECTED; hci_connect_cfm(conn, ev->status); - hci_conn_drop(conn); } } else { hci_auth_cfm(conn, ev->status); @@ -3776,7 +3775,6 @@ static void hci_remote_features_evt(struct hci_dev *hdev, void *data, if (!hci_outgoing_auth_needed(hdev, conn)) { conn->state = BT_CONNECTED; hci_connect_cfm(conn, ev->status); - hci_conn_drop(conn); }
unlock: @@ -5030,7 +5028,6 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev, void *data, if (!hci_outgoing_auth_needed(hdev, conn)) { conn->state = BT_CONNECTED; hci_connect_cfm(conn, ev->status); - hci_conn_drop(conn); }
unlock: @@ -6561,7 +6558,6 @@ static void hci_le_remote_feat_complete_evt(struct hci_dev *hdev, void *data,
conn->state = BT_CONNECTED; hci_connect_cfm(conn, status); - hci_conn_drop(conn); } }
11.04.2024 18:18, kovalev@altlinux.org wrote:
From: Vasiliy Kovalev kovalev@altlinux.org
There is no need to drop the connection of some functions in which the conn->state in BT_CONNECTED is marked, since in the future the same check takes place (for example, in the hci_encrypt_change_evt() function) and the hci_conn_drop() is called.
Otherwise, the conn->refcnt will become below zero, which will trigger a warning and may cause a crash on kernels with the panic_on_warn parameter enabled.
repro.c generated by syzkaller:
#define _GNU_SOURCE
#include <dirent.h> #include <endian.h> #include <errno.h> #include <fcntl.h> #include <pthread.h> #include <sched.h> #include <signal.h> #include <stdarg.h> #include <stdbool.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/epoll.h> #include <sys/ioctl.h> #include <sys/mount.h> #include <sys/prctl.h> #include <sys/resource.h> #include <sys/socket.h> #include <sys/stat.h> #include <sys/syscall.h> #include <sys/time.h> #include <sys/types.h> #include <sys/uio.h> #include <sys/wait.h> #include <time.h> #include <unistd.h>
#include <linux/capability.h> #include <linux/rfkill.h>
static void sleep_ms(uint64_t ms) { usleep(ms * 1000); }
static uint64_t current_time_ms(void) { struct timespec ts; if (clock_gettime(CLOCK_MONOTONIC, &ts)) exit(1); return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000; }
static bool write_file(const char* file, const char* what, ...) { char buf[1024]; va_list args; va_start(args, what); vsnprintf(buf, sizeof(buf), what, args); va_end(args); buf[sizeof(buf) - 1] = 0; int len = strlen(buf); int fd = open(file, O_WRONLY | O_CLOEXEC); if (fd == -1) return false; if (write(fd, buf, len) != len) { int err = errno; close(fd); errno = err; return false; } close(fd); return true; }
#define MAX_FDS 30
#define BTPROTO_HCI 1 #define ACL_LINK 1 #define SCAN_PAGE 2
typedef struct { uint8_t b[6]; } __attribute__((packed)) bdaddr_t;
#define HCI_COMMAND_PKT 1 #define HCI_EVENT_PKT 4 #define HCI_VENDOR_PKT 0xff
struct hci_command_hdr { uint16_t opcode; uint8_t plen; } __attribute__((packed));
struct hci_event_hdr { uint8_t evt; uint8_t plen; } __attribute__((packed));
#define HCI_EV_CONN_COMPLETE 0x03 struct hci_ev_conn_complete { uint8_t status; uint16_t handle; bdaddr_t bdaddr; uint8_t link_type; uint8_t encr_mode; } __attribute__((packed));
#define HCI_EV_CONN_REQUEST 0x04 struct hci_ev_conn_request { bdaddr_t bdaddr; uint8_t dev_class[3]; uint8_t link_type; } __attribute__((packed));
#define HCI_EV_REMOTE_FEATURES 0x0b struct hci_ev_remote_features { uint8_t status; uint16_t handle; uint8_t features[8]; } __attribute__((packed));
#define HCI_EV_CMD_COMPLETE 0x0e struct hci_ev_cmd_complete { uint8_t ncmd; uint16_t opcode; } __attribute__((packed));
#define HCI_OP_WRITE_SCAN_ENABLE 0x0c1a
#define HCI_OP_READ_BUFFER_SIZE 0x1005 struct hci_rp_read_buffer_size { uint8_t status; uint16_t acl_mtu; uint8_t sco_mtu; uint16_t acl_max_pkt; uint16_t sco_max_pkt; } __attribute__((packed));
#define HCI_OP_READ_BD_ADDR 0x1009 struct hci_rp_read_bd_addr { uint8_t status; bdaddr_t bdaddr; } __attribute__((packed));
#define HCI_EV_LE_META 0x3e struct hci_ev_le_meta { uint8_t subevent; } __attribute__((packed));
#define HCI_EV_LE_CONN_COMPLETE 0x01 struct hci_ev_le_conn_complete { uint8_t status; uint16_t handle; uint8_t role; uint8_t bdaddr_type; bdaddr_t bdaddr; uint16_t interval; uint16_t latency; uint16_t supervision_timeout; uint8_t clk_accurancy; } __attribute__((packed));
struct hci_dev_req { uint16_t dev_id; uint32_t dev_opt; };
struct vhci_vendor_pkt { uint8_t type; uint8_t opcode; uint16_t id; };
#define HCIDEVUP _IOW('H', 201, int) #define HCISETSCAN _IOW('H', 221, int)
static int vhci_fd = -1;
static void rfkill_unblock_all() { int fd = open("/dev/rfkill", O_WRONLY); if (fd < 0) exit(1); struct rfkill_event event = {0}; event.idx = 0; event.type = RFKILL_TYPE_ALL; event.op = RFKILL_OP_CHANGE_ALL; event.soft = 0; event.hard = 0; if (write(fd, &event, sizeof(event)) < 0) exit(1); close(fd); }
static void hci_send_event_packet(int fd, uint8_t evt, void* data, size_t data_len) { struct iovec iv[3]; struct hci_event_hdr hdr; hdr.evt = evt; hdr.plen = data_len; uint8_t type = HCI_EVENT_PKT; iv[0].iov_base = &type; iv[0].iov_len = sizeof(type); iv[1].iov_base = &hdr; iv[1].iov_len = sizeof(hdr); iv[2].iov_base = data; iv[2].iov_len = data_len; if (writev(fd, iv, sizeof(iv) / sizeof(struct iovec)) < 0) exit(1); }
static void hci_send_event_cmd_complete(int fd, uint16_t opcode, void* data, size_t data_len) { struct iovec iv[4]; struct hci_event_hdr hdr; hdr.evt = HCI_EV_CMD_COMPLETE; hdr.plen = sizeof(struct hci_ev_cmd_complete) + data_len; struct hci_ev_cmd_complete evt_hdr; evt_hdr.ncmd = 1; evt_hdr.opcode = opcode; uint8_t type = HCI_EVENT_PKT; iv[0].iov_base = &type; iv[0].iov_len = sizeof(type); iv[1].iov_base = &hdr; iv[1].iov_len = sizeof(hdr); iv[2].iov_base = &evt_hdr; iv[2].iov_len = sizeof(evt_hdr); iv[3].iov_base = data; iv[3].iov_len = data_len; if (writev(fd, iv, sizeof(iv) / sizeof(struct iovec)) < 0) exit(1); }
static bool process_command_pkt(int fd, char* buf, ssize_t buf_size) { struct hci_command_hdr* hdr = (struct hci_command_hdr*)buf; if (buf_size < (ssize_t)sizeof(struct hci_command_hdr) || hdr->plen != buf_size - sizeof(struct hci_command_hdr)) exit(1); switch (hdr->opcode) { case HCI_OP_WRITE_SCAN_ENABLE: { uint8_t status = 0; hci_send_event_cmd_complete(fd, hdr->opcode, &status, sizeof(status)); return true; } case HCI_OP_READ_BD_ADDR: { struct hci_rp_read_bd_addr rp = {0}; rp.status = 0; memset(&rp.bdaddr, 0xaa, 6); hci_send_event_cmd_complete(fd, hdr->opcode, &rp, sizeof(rp)); return false; } case HCI_OP_READ_BUFFER_SIZE: { struct hci_rp_read_buffer_size rp = {0}; rp.status = 0; rp.acl_mtu = 1021; rp.sco_mtu = 96; rp.acl_max_pkt = 4; rp.sco_max_pkt = 6; hci_send_event_cmd_complete(fd, hdr->opcode, &rp, sizeof(rp)); return false; } } char dummy[0xf9] = {0}; hci_send_event_cmd_complete(fd, hdr->opcode, dummy, sizeof(dummy)); return false; }
static void* event_thread(void* arg) { while (1) { char buf[1024] = {0}; ssize_t buf_size = read(vhci_fd, buf, sizeof(buf)); if (buf_size < 0) exit(1); if (buf_size > 0 && buf[0] == HCI_COMMAND_PKT) { if (process_command_pkt(vhci_fd, buf + 1, buf_size - 1)) break; } } return NULL; } #define HCI_HANDLE_1 200 #define HCI_HANDLE_2 201
static void initialize_vhci() { int hci_sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); if (hci_sock < 0) exit(1); vhci_fd = open("/dev/vhci", O_RDWR); if (vhci_fd == -1) exit(1); const int kVhciFd = 202; if (dup2(vhci_fd, kVhciFd) < 0) exit(1); close(vhci_fd); vhci_fd = kVhciFd; struct vhci_vendor_pkt vendor_pkt; if (read(vhci_fd, &vendor_pkt, sizeof(vendor_pkt)) != sizeof(vendor_pkt)) exit(1); if (vendor_pkt.type != HCI_VENDOR_PKT) exit(1); pthread_t th; if (pthread_create(&th, NULL, event_thread, NULL)) exit(1); int ret = ioctl(hci_sock, HCIDEVUP, vendor_pkt.id); if (ret) { if (errno == ERFKILL) { rfkill_unblock_all(); ret = ioctl(hci_sock, HCIDEVUP, vendor_pkt.id); } if (ret && errno != EALREADY) exit(1); } struct hci_dev_req dr = {0}; dr.dev_id = vendor_pkt.id; dr.dev_opt = SCAN_PAGE; if (ioctl(hci_sock, HCISETSCAN, &dr)) exit(1); struct hci_ev_conn_request request; memset(&request, 0, sizeof(request)); memset(&request.bdaddr, 0xaa, 6); *(uint8_t*)&request.bdaddr.b[5] = 0x10; request.link_type = ACL_LINK; hci_send_event_packet(vhci_fd, HCI_EV_CONN_REQUEST, &request, sizeof(request)); struct hci_ev_conn_complete complete; memset(&complete, 0, sizeof(complete)); complete.status = 0; complete.handle = HCI_HANDLE_1; memset(&complete.bdaddr, 0xaa, 6); *(uint8_t*)&complete.bdaddr.b[5] = 0x10; complete.link_type = ACL_LINK; complete.encr_mode = 0; hci_send_event_packet(vhci_fd, HCI_EV_CONN_COMPLETE, &complete, sizeof(complete)); struct hci_ev_remote_features features; memset(&features, 0, sizeof(features)); features.status = 0; features.handle = HCI_HANDLE_1; hci_send_event_packet(vhci_fd, HCI_EV_REMOTE_FEATURES, &features, sizeof(features)); struct { struct hci_ev_le_meta le_meta; struct hci_ev_le_conn_complete le_conn; } le_conn; memset(&le_conn, 0, sizeof(le_conn)); le_conn.le_meta.subevent = HCI_EV_LE_CONN_COMPLETE; memset(&le_conn.le_conn.bdaddr, 0xaa, 6); *(uint8_t*)&le_conn.le_conn.bdaddr.b[5] = 0x11; le_conn.le_conn.role = 1; le_conn.le_conn.handle = HCI_HANDLE_2; hci_send_event_packet(vhci_fd, HCI_EV_LE_META, &le_conn, sizeof(le_conn)); pthread_join(th, NULL); close(hci_sock); }
static long syz_emit_vhci(volatile long a0, volatile long a1) { if (vhci_fd < 0) return (uintptr_t)-1; char* data = (char*)a0; uint32_t length = a1; return write(vhci_fd, data, length); }
static void setup_common() { if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) { } }
static void setup_binderfs() { if (mkdir("/dev/binderfs", 0777)) { } if (mount("binder", "/dev/binderfs", "binder", 0, NULL)) { } if (symlink("/dev/binderfs", "./binderfs")) { } }
static void loop();
static void sandbox_common() { prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); setsid(); struct rlimit rlim; rlim.rlim_cur = rlim.rlim_max = (200 << 20); setrlimit(RLIMIT_AS, &rlim); rlim.rlim_cur = rlim.rlim_max = 32 << 20; setrlimit(RLIMIT_MEMLOCK, &rlim); rlim.rlim_cur = rlim.rlim_max = 136 << 20; setrlimit(RLIMIT_FSIZE, &rlim); rlim.rlim_cur = rlim.rlim_max = 1 << 20; setrlimit(RLIMIT_STACK, &rlim); rlim.rlim_cur = rlim.rlim_max = 0; setrlimit(RLIMIT_CORE, &rlim); rlim.rlim_cur = rlim.rlim_max = 256; setrlimit(RLIMIT_NOFILE, &rlim); if (unshare(CLONE_NEWNS)) { } if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL)) { } if (unshare(CLONE_NEWIPC)) { } if (unshare(0x02000000)) { } if (unshare(CLONE_NEWUTS)) { } if (unshare(CLONE_SYSVSEM)) { } typedef struct { const char* name; const char* value; } sysctl_t; static const sysctl_t sysctls[] = { {"/proc/sys/kernel/shmmax", "16777216"}, {"/proc/sys/kernel/shmall", "536870912"}, {"/proc/sys/kernel/shmmni", "1024"}, {"/proc/sys/kernel/msgmax", "8192"}, {"/proc/sys/kernel/msgmni", "1024"}, {"/proc/sys/kernel/msgmnb", "1024"}, {"/proc/sys/kernel/sem", "1024 1048576 500 1024"}, }; unsigned i; for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++) write_file(sysctls[i].name, sysctls[i].value); }
static int wait_for_loop(int pid) { if (pid < 0) exit(1); int status = 0; while (waitpid(-1, &status, __WALL) != pid) { } return WEXITSTATUS(status); }
static void drop_caps(void) { struct __user_cap_header_struct cap_hdr = {}; struct __user_cap_data_struct cap_data[2] = {}; cap_hdr.version = _LINUX_CAPABILITY_VERSION_3; cap_hdr.pid = getpid(); if (syscall(SYS_capget, &cap_hdr, &cap_data)) exit(1); const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE); cap_data[0].effective &= ~drop; cap_data[0].permitted &= ~drop; cap_data[0].inheritable &= ~drop; if (syscall(SYS_capset, &cap_hdr, &cap_data)) exit(1); }
static int do_sandbox_none(void) { if (unshare(CLONE_NEWPID)) { } int pid = fork(); if (pid != 0) return wait_for_loop(pid); setup_common(); initialize_vhci(); sandbox_common(); drop_caps(); if (unshare(CLONE_NEWNET)) { } setup_binderfs(); loop(); exit(1); }
static void kill_and_wait(int pid, int* status) { kill(-pid, SIGKILL); kill(pid, SIGKILL); for (int i = 0; i < 100; i++) { if (waitpid(-1, status, WNOHANG | __WALL) == pid) return; usleep(1000); } DIR* dir = opendir("/sys/fs/fuse/connections"); if (dir) { for (;;) { struct dirent* ent = readdir(dir); if (!ent) break; if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) continue; char abort[300]; snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort", ent->d_name); int fd = open(abort, O_WRONLY); if (fd == -1) { continue; } if (write(fd, abort, 1) < 0) { } close(fd); } closedir(dir); } else { } while (waitpid(-1, status, __WALL) != pid) { } }
static void setup_test() { prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); setpgrp(); write_file("/proc/self/oom_score_adj", "1000"); }
static void close_fds() { for (int fd = 3; fd < MAX_FDS; fd++) close(fd); }
static void execute_one(void);
#define WAIT_FLAGS __WALL
static void loop(void) { int iter = 0; for (;; iter++) { int pid = fork(); if (pid < 0) exit(1); if (pid == 0) { setup_test(); execute_one(); close_fds(); exit(0); } int status = 0; uint64_t start = current_time_ms(); for (;;) { if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid) break; sleep_ms(1); if (current_time_ms() - start < 5000) continue; kill_and_wait(pid, &status); break; } } }
void execute_one(void) { *(uint8_t*)0x20000040 = 4; *(uint8_t*)0x20000041 = 8; *(uint8_t*)0x20000042 = 4; *(uint8_t*)0x20000043 = 0xf9; *(uint16_t*)0x20000044 = 0xc8; *(uint8_t*)0x20000046 = 2; syz_emit_vhci(0x20000040, 7);
} int main(void) { syscall(__NR_mmap, 0x1ffff000ul, 0x1000ul, 0ul, 0x32ul, -1, 0ul); syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 7ul, 0x32ul, -1, 0ul); syscall(__NR_mmap, 0x21000000ul, 0x1000ul, 0ul, 0x32ul, -1, 0ul); do_sandbox_none(); return 0; }
Hi,
On Thu, Apr 11, 2024 at 11:18 AM kovalev@altlinux.org wrote:
From: Vasiliy Kovalev kovalev@altlinux.org
There is no need to drop the connection of some functions in which the conn->state in BT_CONNECTED is marked, since in the future the same check takes place (for example, in the hci_encrypt_change_evt() function) and the hci_conn_drop() is called.
Otherwise, the conn->refcnt will become below zero, which will trigger a warning and may cause a crash on kernels with the panic_on_warn parameter enabled.
Syzkaller hit 'WARNING in hci_conn_timeout' bug.
[ 23.485892] Bluetooth: Core ver 2.22 [ 23.485916] NET: Registered PF_BLUETOOTH protocol family [ 23.485917] Bluetooth: HCI device and connection manager initialized [ 23.486407] Bluetooth: HCI socket layer initialized [ 23.486410] Bluetooth: L2CAP socket layer initialized [ 23.486413] Bluetooth: SCO socket layer initialized [ 24.507112] Bluetooth: hci0: unexpected cc 0x0c03 length: 249 > 1 [ 24.507142] Bluetooth: hci0: unexpected cc 0x1003 length: 249 > 9 [ 24.507165] Bluetooth: hci0: unexpected cc 0x1001 length: 249 > 9 [ 24.508091] Bluetooth: hci0: unexpected cc 0x0c23 length: 249 > 4 [ 24.508109] Bluetooth: hci0: unexpected cc 0x0c25 length: 249 > 3 [ 24.508117] Bluetooth: hci0: unexpected cc 0x0c38 length: 249 > 2 [ 24.545962] Bluetooth: BNEP (Ethernet Emulation) ver 1.3 [ 24.545969] Bluetooth: BNEP filters: protocol multicast [ 24.545973] Bluetooth: BNEP socket layer initialized [ 24.547521] Bluetooth: MGMT ver 1.22 [ 26.553008] Bluetooth: hci0: command tx timeout [ 26.561518] Bluetooth: RFCOMM TTY layer initialized [ 26.561526] Bluetooth: RFCOMM socket layer initialized [ 26.561532] Bluetooth: RFCOMM ver 1.11 [ 28.602024] Bluetooth: hci0: Opcode 0x0c13 failed: -110 [ 28.602054] Bluetooth: hci0: command tx timeout [ 30.650011] Bluetooth: hci0: Opcode 0x0c24 failed: -110 [ 30.650021] Bluetooth: hci0: command tx timeout [ 32.696973] Bluetooth: hci0: command tx timeout [ 32.696985] Bluetooth: hci0: Opcode 0x0c24 failed: -110 [ 34.744973] Bluetooth: hci0: command 0x0406 tx timeout [ 34.745008] Bluetooth: hci0: Opcode 0x0c24 failed: -110 [ 36.792966] Bluetooth: hci0: Opcode 0x0c24 failed: -110 [ 36.792980] Bluetooth: hci0: command 0x0406 tx timeout [ 38.841027] Bluetooth: hci0: command 0x0406 tx timeout [ 38.841035] Bluetooth: hci0: Opcode 0x0c24 failed: -110 [ 40.889026] Bluetooth: hci0: Opcode 0x0c24 failed: -110 [ 40.889999] Bluetooth: hci0: command 0x0406 tx timeout [ 40.890012] Bluetooth: hci0: Opcode 0x0c24 failed: -110 [ 40.893629] NET: Registered PF_ALG protocol family [ 42.937008] Bluetooth: hci0: Opcode 0x0c24 failed: -110 [ 42.937023] Bluetooth: hci0: command 0x0406 tx timeout [ 44.984984] Bluetooth: hci0: Opcode 0x0c24 failed: -110 [ 44.985008] Bluetooth: hci0: command 0x0406 tx timeout [ 47.033023] Bluetooth: hci0: Opcode 0x0c1a failed: -110 [ 47.033044] Bluetooth: hci0: command 0x0406 tx timeout [ 49.080976] Bluetooth: hci0: command 0x0406 tx timeout [ 49.080985] Bluetooth: hci0: Opcode 0x0c24 failed: -110 [ 51.129140] Bluetooth: hci0: Opcode 0x0c24 failed: -110 [ 51.130051] Bluetooth: hci0: command 0x0406 tx timeout [ 53.177011] Bluetooth: hci0: command 0x0406 tx timeout [ 55.225969] Bluetooth: hci0: command 0x0406 tx timeout [ 57.272968] Bluetooth: hci0: command 0x0406 tx timeout [ 59.320982] Bluetooth: hci0: command 0x0406 tx timeout [ 61.368989] Bluetooth: hci0: command 0x0406 tx timeout [ 148.474066] ------------[ cut here ]------------ [ 148.474072] WARNING: CPU: 0 PID: 3835 at net/bluetooth/hci_conn.c:612 hci_conn_timeout+0x16/0x60 [bluetooth] [ 148.474115] Modules linked in: cmac algif_hash algif_skcipher af_alg rfcomm bnep hci_vhci bluetooth ecdh_generic uinput af_packet rfkill joydev hid_generic usbhid hid qrtr intel_rapl_msr intel_rapl_common intel_pmc_core kvm_intel nls_utf8 iTCO_wdt intel_pmc_bxt iTCO_vendor_support nls_cp866 vfat fat kvm irqbypass crct10dif_pclmul crc32_pclmul snd_hda_codec_generic crc32c_intel ghash_clmulni_intel ledtrig_audio sha512_ssse3 snd_hda_intel sha256_ssse3 sha1_ssse3 snd_intel_dspcfg snd_intel_sdw_acpi snd_hda_codec aesni_intel crypto_simd cryptd i2c_i801 snd_hda_core psmouse snd_hwdep i2c_smbus xhci_pci pcspkr snd_pcm lpc_ich xhci_pci_renesas xhci_hcd tiny_power_button qemu_fw_cfg button sch_fq_codel vboxvideo drm_vram_helper drm_ttm_helper ttm vboxsf vboxguest snd_seq_midi snd_seq_midi_event snd_seq snd_rawmidi snd_seq_device snd_timer snd soundcore msr fuse efi_pstore dm_mod ip_tables x_tables autofs4 virtio_gpu virtio_net virtio_dma_buf drm_shmem_helper net_failover drm_kms_helper [ 148.474210] virtio_rng drm virtio_scsi rng_core virtio_console virtio_balloon virtio_blk failover ahci libahci libata evdev input_leds serio_raw scsi_mod scsi_common virtio_pci virtio_pci_legacy_dev virtio_pci_modern_dev virtio_ring virtio intel_agp intel_gtt [ 148.474234] CPU: 0 PID: 3835 Comm: kworker/u5:2 Not tainted 6.1.85-un-def-alt1 #1 [ 148.474238] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.0-alt1 04/01/2014 [ 148.474241] Workqueue: hci0 hci_conn_timeout [bluetooth] [ 148.474265] RIP: 0010:hci_conn_timeout+0x16/0x60 [bluetooth] [ 148.474288] Code: 00 00 66 89 44 24 06 e8 58 a7 ff ff eb a8 e8 41 7b ee c1 90 0f 1f 44 00 00 8b 87 20 fd ff ff 85 c0 78 07 74 07 c3 cc cc cc cc <0f> 0b 55 0f b6 87 49 fd ff ff 48 8d af 10 fd ff ff 3c 01 74 12 be [ 148.474291] RSP: 0018:ffffa7fd80b53e90 EFLAGS: 00010286 [ 148.474295] RAX: 00000000fffe728b RBX: ffff8959c46ab180 RCX: ffff8959c3b70028 [ 148.474297] RDX: 0000000000000001 RSI: ffff8959c86ce0b0 RDI: ffff895a105aeaf0 [ 148.474299] RBP: ffff895a105aeaf0 R08: ffff8959c86ce0b0 R09: ffff8959c46ab1f4 [ 148.474301] R10: 0000000000000005 R11: 0000000000000005 R12: ffff8959c3b70000 [ 148.474302] R13: ffff8959ec495400 R14: 0000000000000000 R15: ffff8959ec495405 [ 148.474305] FS: 0000000000000000(0000) GS:ffff895a3dc00000(0000) knlGS:0000000000000000 [ 148.474308] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 148.474310] CR2: 00007f2a1b7baa48 CR3: 0000000034b98000 CR4: 0000000000750ef0 [ 148.474317] PKRU: 55555554 [ 148.474319] Call Trace: [ 148.474323] <TASK> [ 148.474327] ? __warn+0x79/0xc0 [ 148.474343] ? hci_conn_timeout+0x16/0x60 [bluetooth] [ 148.474364] ? report_bug+0xff/0x150 [ 148.474375] ? handle_bug+0x49/0xa0 [ 148.474398] ? exc_invalid_op+0x14/0x70 [ 148.474402] ? asm_exc_invalid_op+0x16/0x20 [ 148.474408] ? hci_conn_timeout+0x16/0x60 [bluetooth] [ 148.474441] process_one_work+0x217/0x3e0 [ 148.474467] worker_thread+0x4d/0x3c0 [ 148.474473] ? process_one_work+0x3e0/0x3e0 [ 148.474478] kthread+0xd6/0x100 [ 148.474482] ? kthread_complete_and_exit+0x20/0x20 [ 148.474486] ret_from_fork+0x1f/0x30 [ 148.474500] </TASK> [ 148.474502] ---[ end trace 0000000000000000 ]---
Fixes: 0fe29fd1cd77 ("Bluetooth: Read LE remote features during connection establishment") Fixes: 769be974d0c7 ("[Bluetooth] Use ACL config stage to retrieve remote features") Fixes: f8558555f31e ("[Bluetooth] Initiate authentication during connection establishment") Cc: stable@vger.kernel.org Signed-off-by: Vasiliy Kovalev kovalev@altlinux.org
net/bluetooth/hci_event.c | 4 ---- 1 file changed, 4 deletions(-)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index a8b8cfebe0180c..64477e1bde7cec 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3529,7 +3529,6 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, void *data, } else { conn->state = BT_CONNECTED; hci_connect_cfm(conn, ev->status);
hci_conn_drop(conn); } } else { hci_auth_cfm(conn, ev->status);
@@ -3776,7 +3775,6 @@ static void hci_remote_features_evt(struct hci_dev *hdev, void *data, if (!hci_outgoing_auth_needed(hdev, conn)) { conn->state = BT_CONNECTED; hci_connect_cfm(conn, ev->status);
hci_conn_drop(conn); }
unlock: @@ -5030,7 +5028,6 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev, void *data, if (!hci_outgoing_auth_needed(hdev, conn)) { conn->state = BT_CONNECTED; hci_connect_cfm(conn, ev->status);
hci_conn_drop(conn); }
unlock: @@ -6561,7 +6558,6 @@ static void hci_le_remote_feat_complete_evt(struct hci_dev *hdev, void *data,
conn->state = BT_CONNECTED; hci_connect_cfm(conn, status);
hci_conn_drop(conn); } }
-- 2.33.8
The instances are called when the connection procedure is considered finished so hci_connect_cfm is called, etc, which is assumed to be done only once per hci_conn, we could in theory even do the state change and hci_conn_drop inside hci_connect_cfm and ignore if there are calls to it after it had move to connected state for example, anyway szykaller probably doesn't really follow the procedures accordingly and just generate events regardless if there are commands being generated or not which would explain why we have never seem this with real controllers, but you can't really remove these calls like this because it would probably result in memory leaks.
linux-stable-mirror@lists.linaro.org