diff options
| author | TheOfficialFloW <theflow@google.com> | 2020-07-30 11:33:48 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-07-30 11:33:48 +0200 |
| commit | b0947553167615d7bb1b67b22d2d080e5a5ab2cd (patch) | |
| tree | f3f104edb509ef1cf89c1db3119052f4d7d4e7ae | |
| parent | 233283a191b3c32a48c56928985c8e2cfc004aeb (diff) | |
all: initialize vhci in linux
* all: initialize vhci in linux
* executor/common_linux.h: improve vhci initialization
* pkg/repro/repro.go: add missing vhci options
* executor/common_linux.h: fix type and add missing header
* executor, pkg: do it like NetInjection
* pkg/csource/csource.go: do not emit syz_emit_vhci if vhci is not enabled
* executor/common_linux.h: fix format string
* executor/common_linux.h: initialize with memset
For som reason {0} gets complains about missing braces...
* executor/common_linux.h: simplify vhci init
* executor/common_linux.h: try to bring all available hci devices up
* executor/common_linux.h: find which hci device has been registered
* executor/common_linux.h: use HCI_VENDOR_PKT response to retrieve device id
* sys/linux/dev_vhci.txt: fix structs of inquiry and report packets
* executor/common_linux.h: remove unnecessary return statement and check vendor_pkt read size
* executor/common_linux.h: remove unnecessary return statement and check vendor_pkt read size
* sys/linux/dev_vhci.txt: pack extended_inquiry_info_t
* sys/linux/l2cap.txt: add l2cap_conf_opt struct
* executor/common_linux.h: just fill bd addr will 0xaa
* executor/common_linux.h: just fill bd addr will 0xaa
| -rw-r--r-- | executor/common_linux.h | 307 | ||||
| -rw-r--r-- | executor/executor.cc | 2 | ||||
| -rw-r--r-- | pkg/csource/common.go | 1 | ||||
| -rw-r--r-- | pkg/csource/csource.go | 5 | ||||
| -rw-r--r-- | pkg/csource/generated.go | 293 | ||||
| -rw-r--r-- | pkg/csource/options.go | 58 | ||||
| -rw-r--r-- | pkg/csource/options_test.go | 9 | ||||
| -rw-r--r-- | pkg/host/features.go | 2 | ||||
| -rw-r--r-- | pkg/host/features_linux.go | 8 | ||||
| -rw-r--r-- | pkg/host/syscalls_linux.go | 3 | ||||
| -rw-r--r-- | pkg/ipc/ipc.go | 25 | ||||
| -rw-r--r-- | pkg/repro/repro.go | 11 | ||||
| -rw-r--r-- | pkg/runtest/run.go | 6 | ||||
| -rw-r--r-- | sys/linux/dev_vhci.txt | 50 | ||||
| -rw-r--r-- | sys/linux/l2cap.txt | 10 | ||||
| -rw-r--r-- | sys/linux/test/vhci | 1 | ||||
| -rw-r--r-- | syz-fuzzer/fuzzer.go | 37 | ||||
| -rw-r--r-- | tools/syz-execprog/execprog.go | 3 | ||||
| -rw-r--r-- | tools/syz-prog2c/prog2c.go | 47 | ||||
| -rw-r--r-- | tools/syz-reprolist/reprolist.go | 4 | ||||
| -rw-r--r-- | tools/syz-stress/stress.go | 3 |
21 files changed, 790 insertions, 95 deletions
diff --git a/executor/common_linux.h b/executor/common_linux.h index a7dfa2374..b679d1ebb 100644 --- a/executor/common_linux.h +++ b/executor/common_linux.h @@ -557,7 +557,7 @@ static void initialize_tun(void) } #endif -#if SYZ_EXECUTOR || __NR_syz_init_net_socket || SYZ_DEVLINK_PCI +#if SYZ_EXECUTOR || __NR_syz_init_net_socket || SYZ_DEVLINK_PCI || SYZ_VHCI_INJECTION const int kInitNetNsFd = 239; // see kMaxFd #endif @@ -1768,7 +1768,7 @@ static long syz_open_pts(volatile long a0, volatile long a1) } #endif -#if SYZ_EXECUTOR || __NR_syz_init_net_socket +#if SYZ_EXECUTOR || __NR_syz_init_net_socket || SYZ_VHCI_INJECTION #if SYZ_EXECUTOR || SYZ_SANDBOX_NONE || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE || SYZ_SANDBOX_ANDROID #include <fcntl.h> #include <sched.h> @@ -1801,6 +1801,291 @@ static long syz_init_net_socket(volatile long domain, volatile long type, volati #endif #endif +#if SYZ_EXECUTOR || SYZ_VHCI_INJECTION +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <sys/epoll.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/uio.h> + +#define BTPROTO_HCI 1 +#define ACL_LINK 1 +#define SCAN_PAGE 2 + +typedef struct { + uint8 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 opcode; + uint8 plen; +} __attribute__((packed)); + +struct hci_event_hdr { + uint8 evt; + uint8 plen; +} __attribute__((packed)); + +#define HCI_EV_CONN_COMPLETE 0x03 +struct hci_ev_conn_complete { + uint8 status; + uint16 handle; + bdaddr_t bdaddr; + uint8 link_type; + uint8 encr_mode; +} __attribute__((packed)); + +#define HCI_EV_CONN_REQUEST 0x04 +struct hci_ev_conn_request { + bdaddr_t bdaddr; + uint8 dev_class[3]; + uint8 link_type; +} __attribute__((packed)); + +#define HCI_EV_REMOTE_FEATURES 0x0b +struct hci_ev_remote_features { + uint8 status; + uint16 handle; + uint8 features[8]; +} __attribute__((packed)); + +#define HCI_EV_CMD_COMPLETE 0x0e +struct hci_ev_cmd_complete { + uint8 ncmd; + uint16 opcode; +} __attribute__((packed)); + +#define HCI_OP_WRITE_SCAN_ENABLE 0x0c1a + +#define HCI_OP_READ_BUFFER_SIZE 0x1005 +struct hci_rp_read_buffer_size { + uint8 status; + uint16 acl_mtu; + uint8 sco_mtu; + uint16 acl_max_pkt; + uint16 sco_max_pkt; +} __attribute__((packed)); + +#define HCI_OP_READ_BD_ADDR 0x1009 +struct hci_rp_read_bd_addr { + uint8 status; + bdaddr_t bdaddr; +} __attribute__((packed)); + +struct hci_dev_req { + uint16 dev_id; + uint32 dev_opt; +}; + +struct vhci_vendor_pkt { + uint8 type; + uint8 opcode; + uint16 id; +}; + +#define HCIDEVUP _IOW('H', 201, int) +#define HCISETSCAN _IOW('H', 221, int) + +static int vhci_fd = -1; + +static void hci_send_event_packet(int fd, uint8 evt, void* data, size_t data_len) +{ + struct iovec iv[3]; + + struct hci_event_hdr hdr; + hdr.evt = evt; + hdr.plen = data_len; + + uint8 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) + fail("writev failed"); +} + +static void hci_send_event_cmd_complete(int fd, uint16 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 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) + fail("writev failed"); +} + +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)) { + fail("invalid size: %zx\n", buf_size); + } + + switch (hdr->opcode) { + case HCI_OP_WRITE_SCAN_ENABLE: { + uint8 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) + fail("read failed"); + debug_dump_data(buf, buf_size); + if (buf_size > 0 && buf[0] == HCI_COMMAND_PKT) { + if (process_command_pkt(vhci_fd, buf + 1, buf_size - 1)) + break; + } + } + return NULL; +} + +#define ACL_HANDLE 256 + +static void initialize_vhci() +{ +#if SYZ_EXECUTOR + if (!flag_vhci_injection) + return; +#endif + + int hci_sock = syz_init_net_socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); + if (hci_sock < 0) + fail("syz_init_net_socket failed"); + + vhci_fd = open("/dev/vhci", O_RDWR); + if (vhci_fd == -1) + fail("open /dev/vhci failed"); + + // Remap vhci onto higher fd number to hide it from fuzzer and to keep + // fd numbers stable regardless of whether vhci is opened or not (also see kMaxFd). + const int kVhciFd = 241; + if (dup2(vhci_fd, kVhciFd) < 0) + fail("dup2(vhci_fd, kVhciFd) failed"); + 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"); + + if (vendor_pkt.type != HCI_VENDOR_PKT) + fail("wrong response packet"); + + debug("hci dev id: %x\n", vendor_pkt.id); + + pthread_t th; + if (pthread_create(&th, NULL, event_thread, NULL)) + fail("pthread_create failed"); + + // Bring hci device up + if (ioctl(hci_sock, HCIDEVUP, vendor_pkt.id) && errno != EALREADY) + fail("ioctl(HCIDEVUP) failed"); + + // 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_opt = SCAN_PAGE; + if (ioctl(hci_sock, HCISETSCAN, &dr)) + fail("ioctl(HCISETSCAN) failed"); + + // Fake a connection with bd address aa:aa:aa:aa:aa:aa. + // This is a fixed address used in sys/linux/socket_bluetooth.txt. + struct hci_ev_conn_request request; + memset(&request, 0, sizeof(request)); + memset(&request.bdaddr, 0xaa, 6); + 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 = ACL_HANDLE; + memset(&complete.bdaddr, 0xaa, 6); + 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 = ACL_HANDLE; + hci_send_event_packet(vhci_fd, HCI_EV_REMOTE_FEATURES, &features, sizeof(features)); + + pthread_join(th, NULL); + close(hci_sock); +} +#endif + +#if SYZ_EXECUTOR || __NR_syz_emit_vhci && SYZ_VHCI_INJECTION +static long syz_emit_vhci(volatile long a0, volatile long a1) +{ + if (vhci_fd < 0) + return (uintptr_t)-1; + + char* data = (char*)a0; + uint32 length = a1; + + return write(vhci_fd, data, length); +} +#endif + #if SYZ_EXECUTOR || __NR_syz_genetlink_get_family_id #include <errno.h> #include <linux/genetlink.h> @@ -2778,7 +3063,7 @@ static void sandbox_common() setpgrp(); setsid(); -#if SYZ_EXECUTOR || __NR_syz_init_net_socket || SYZ_DEVLINK_PCI +#if SYZ_EXECUTOR || __NR_syz_init_net_socket || SYZ_DEVLINK_PCI || SYZ_VHCI_INJECTION int netns = open("/proc/self/ns/net", O_RDONLY); if (netns == -1) fail("open(/proc/self/ns/net) failed"); @@ -2927,6 +3212,9 @@ static int do_sandbox_none(void) #if SYZ_EXECUTOR || SYZ_NET_DEVICES initialize_netdevices(); #endif +#if SYZ_EXECUTOR || SYZ_VHCI_INJECTION + initialize_vhci(); +#endif loop(); doexit(1); } @@ -2964,6 +3252,9 @@ static int do_sandbox_setuid(void) #if SYZ_EXECUTOR || SYZ_NET_DEVICES initialize_netdevices(); #endif +#if SYZ_EXECUTOR || SYZ_VHCI_INJECTION + initialize_vhci(); +#endif const int nobody = 65534; if (setgroups(0, NULL)) @@ -3024,6 +3315,11 @@ static int namespace_sandbox_proc(void* arg) #if SYZ_EXECUTOR || SYZ_NET_DEVICES initialize_netdevices(); #endif +#if SYZ_EXECUTOR || SYZ_VHCI_INJECTION + // This will fail and we only have it here to avoid complains about the + // function being unused. + initialize_vhci(); +#endif if (mkdir("./syz-tmp", 0777)) fail("mkdir(syz-tmp) failed"); @@ -3240,6 +3536,11 @@ static int do_sandbox_android(void) // and try to reinitialize them as other test processes use them. initialize_netdevices(); #endif +#if SYZ_EXECUTOR || SYZ_VHCI_INJECTION + // This will fail and we only have it here to avoid complains about the + // function being unused. + initialize_vhci(); +#endif if (chown(".", UNTRUSTED_APP_UID, UNTRUSTED_APP_UID) != 0) fail("chmod failed"); diff --git a/executor/executor.cc b/executor/executor.cc index ccbdb1aa0..5b7371b1d 100644 --- a/executor/executor.cc +++ b/executor/executor.cc @@ -128,6 +128,7 @@ static bool flag_net_reset; static bool flag_cgroups; static bool flag_close_fds; static bool flag_devlink_pci; +static bool flag_vhci_injection; static bool flag_collect_cover; static bool flag_dedup_cover; @@ -490,6 +491,7 @@ void parse_env_flags(uint64 flags) flag_cgroups = flags & (1 << 9); flag_close_fds = flags & (1 << 10); flag_devlink_pci = flags & (1 << 11); + flag_vhci_injection = flags & (1 << 12); } #if SYZ_EXECUTOR_USES_FORK_SERVER diff --git a/pkg/csource/common.go b/pkg/csource/common.go index 96d719b67..c767349e2 100644 --- a/pkg/csource/common.go +++ b/pkg/csource/common.go @@ -113,6 +113,7 @@ func commonDefines(p *prog.Prog, opts Options) map[string]bool { "SYZ_KCSAN": opts.KCSAN, "SYZ_DEVLINK_PCI": opts.DevlinkPCI, "SYZ_USB": opts.USB, + "SYZ_VHCI_INJECTION": opts.VhciInjection, "SYZ_USE_TMP_DIR": opts.UseTmpDir, "SYZ_HANDLE_SEGV": opts.HandleSegv, "SYZ_REPRO": opts.Repro, diff --git a/pkg/csource/csource.go b/pkg/csource/csource.go index 9cd456533..134994a13 100644 --- a/pkg/csource/csource.go +++ b/pkg/csource/csource.go @@ -187,9 +187,10 @@ func (ctx *context) generateCalls(p prog.ExecProg, trace bool) ([]string, []uint callName := call.Meta.CallName resCopyout := call.Index != prog.ExecNoCopyout argCopyout := len(call.Copyout) != 0 - emitCall := ctx.opts.NetInjection || + emitCall := (ctx.opts.NetInjection || callName != "syz_emit_ethernet" && - callName != "syz_extract_tcp_res" + callName != "syz_extract_tcp_res") && + (ctx.opts.VhciInjection || callName != "syz_emit_vhci") // TODO: if we don't emit the call we must also not emit copyin, copyout and fault injection. // However, simply skipping whole iteration breaks tests due to unused static functions. if emitCall { diff --git a/pkg/csource/generated.go b/pkg/csource/generated.go index 6234a1262..43d2adb23 100644 --- a/pkg/csource/generated.go +++ b/pkg/csource/generated.go @@ -2793,7 +2793,7 @@ static void initialize_tun(void) } #endif -#if SYZ_EXECUTOR || __NR_syz_init_net_socket || SYZ_DEVLINK_PCI +#if SYZ_EXECUTOR || __NR_syz_init_net_socket || SYZ_DEVLINK_PCI || SYZ_VHCI_INJECTION const int kInitNetNsFd = 239; #endif @@ -5233,7 +5233,7 @@ static long syz_open_pts(volatile long a0, volatile long a1) } #endif -#if SYZ_EXECUTOR || __NR_syz_init_net_socket +#if SYZ_EXECUTOR || __NR_syz_init_net_socket || SYZ_VHCI_INJECTION #if SYZ_EXECUTOR || SYZ_SANDBOX_NONE || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE || SYZ_SANDBOX_ANDROID #include <fcntl.h> #include <sched.h> @@ -5263,6 +5263,281 @@ static long syz_init_net_socket(volatile long domain, volatile long type, volati #endif #endif +#if SYZ_EXECUTOR || SYZ_VHCI_INJECTION +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <sys/epoll.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/uio.h> + +#define BTPROTO_HCI 1 +#define ACL_LINK 1 +#define SCAN_PAGE 2 + +typedef struct { + uint8 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 opcode; + uint8 plen; +} __attribute__((packed)); + +struct hci_event_hdr { + uint8 evt; + uint8 plen; +} __attribute__((packed)); + +#define HCI_EV_CONN_COMPLETE 0x03 +struct hci_ev_conn_complete { + uint8 status; + uint16 handle; + bdaddr_t bdaddr; + uint8 link_type; + uint8 encr_mode; +} __attribute__((packed)); + +#define HCI_EV_CONN_REQUEST 0x04 +struct hci_ev_conn_request { + bdaddr_t bdaddr; + uint8 dev_class[3]; + uint8 link_type; +} __attribute__((packed)); + +#define HCI_EV_REMOTE_FEATURES 0x0b +struct hci_ev_remote_features { + uint8 status; + uint16 handle; + uint8 features[8]; +} __attribute__((packed)); + +#define HCI_EV_CMD_COMPLETE 0x0e +struct hci_ev_cmd_complete { + uint8 ncmd; + uint16 opcode; +} __attribute__((packed)); + +#define HCI_OP_WRITE_SCAN_ENABLE 0x0c1a + +#define HCI_OP_READ_BUFFER_SIZE 0x1005 +struct hci_rp_read_buffer_size { + uint8 status; + uint16 acl_mtu; + uint8 sco_mtu; + uint16 acl_max_pkt; + uint16 sco_max_pkt; +} __attribute__((packed)); + +#define HCI_OP_READ_BD_ADDR 0x1009 +struct hci_rp_read_bd_addr { + uint8 status; + bdaddr_t bdaddr; +} __attribute__((packed)); + +struct hci_dev_req { + uint16 dev_id; + uint32 dev_opt; +}; + +struct vhci_vendor_pkt { + uint8 type; + uint8 opcode; + uint16 id; +}; + +#define HCIDEVUP _IOW('H', 201, int) +#define HCISETSCAN _IOW('H', 221, int) + +static int vhci_fd = -1; + +static void hci_send_event_packet(int fd, uint8 evt, void* data, size_t data_len) +{ + struct iovec iv[3]; + + struct hci_event_hdr hdr; + hdr.evt = evt; + hdr.plen = data_len; + + uint8 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) + fail("writev failed"); +} + +static void hci_send_event_cmd_complete(int fd, uint16 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 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) + fail("writev failed"); +} + +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)) { + fail("invalid size: %zx\n", buf_size); + } + + switch (hdr->opcode) { + case HCI_OP_WRITE_SCAN_ENABLE: { + uint8 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) + fail("read failed"); + debug_dump_data(buf, buf_size); + if (buf_size > 0 && buf[0] == HCI_COMMAND_PKT) { + if (process_command_pkt(vhci_fd, buf + 1, buf_size - 1)) + break; + } + } + return NULL; +} + +#define ACL_HANDLE 256 + +static void initialize_vhci() +{ +#if SYZ_EXECUTOR + if (!flag_vhci_injection) + return; +#endif + + int hci_sock = syz_init_net_socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); + if (hci_sock < 0) + fail("syz_init_net_socket failed"); + + vhci_fd = open("/dev/vhci", O_RDWR); + if (vhci_fd == -1) + fail("open /dev/vhci failed"); + const int kVhciFd = 241; + if (dup2(vhci_fd, kVhciFd) < 0) + fail("dup2(vhci_fd, kVhciFd) failed"); + 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"); + + if (vendor_pkt.type != HCI_VENDOR_PKT) + fail("wrong response packet"); + + debug("hci dev id: %x\n", vendor_pkt.id); + + pthread_t th; + if (pthread_create(&th, NULL, event_thread, NULL)) + fail("pthread_create failed"); + if (ioctl(hci_sock, HCIDEVUP, vendor_pkt.id) && errno != EALREADY) + fail("ioctl(HCIDEVUP) failed"); + struct hci_dev_req dr = {0}; + dr.dev_id = vendor_pkt.id; + dr.dev_opt = SCAN_PAGE; + if (ioctl(hci_sock, HCISETSCAN, &dr)) + fail("ioctl(HCISETSCAN) failed"); + struct hci_ev_conn_request request; + memset(&request, 0, sizeof(request)); + memset(&request.bdaddr, 0xaa, 6); + 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 = ACL_HANDLE; + memset(&complete.bdaddr, 0xaa, 6); + 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 = ACL_HANDLE; + hci_send_event_packet(vhci_fd, HCI_EV_REMOTE_FEATURES, &features, sizeof(features)); + + pthread_join(th, NULL); + close(hci_sock); +} +#endif + +#if SYZ_EXECUTOR || __NR_syz_emit_vhci && SYZ_VHCI_INJECTION +static long syz_emit_vhci(volatile long a0, volatile long a1) +{ + if (vhci_fd < 0) + return (uintptr_t)-1; + + char* data = (char*)a0; + uint32 length = a1; + + return write(vhci_fd, data, length); +} +#endif + #if SYZ_EXECUTOR || __NR_syz_genetlink_get_family_id #include <errno.h> #include <linux/genetlink.h> @@ -7127,7 +7402,7 @@ static void sandbox_common() setpgrp(); setsid(); -#if SYZ_EXECUTOR || __NR_syz_init_net_socket || SYZ_DEVLINK_PCI +#if SYZ_EXECUTOR || __NR_syz_init_net_socket || SYZ_DEVLINK_PCI || SYZ_VHCI_INJECTION int netns = open("/proc/self/ns/net", O_RDONLY); if (netns == -1) fail("open(/proc/self/ns/net) failed"); @@ -7252,6 +7527,9 @@ static int do_sandbox_none(void) #if SYZ_EXECUTOR || SYZ_NET_DEVICES initialize_netdevices(); #endif +#if SYZ_EXECUTOR || SYZ_VHCI_INJECTION + initialize_vhci(); +#endif loop(); doexit(1); } @@ -7289,6 +7567,9 @@ static int do_sandbox_setuid(void) #if SYZ_EXECUTOR || SYZ_NET_DEVICES initialize_netdevices(); #endif +#if SYZ_EXECUTOR || SYZ_VHCI_INJECTION + initialize_vhci(); +#endif const int nobody = 65534; if (setgroups(0, NULL)) @@ -7336,6 +7617,9 @@ static int namespace_sandbox_proc(void* arg) #if SYZ_EXECUTOR || SYZ_NET_DEVICES initialize_netdevices(); #endif +#if SYZ_EXECUTOR || SYZ_VHCI_INJECTION + initialize_vhci(); +#endif if (mkdir("./syz-tmp", 0777)) fail("mkdir(syz-tmp) failed"); @@ -8041,6 +8325,9 @@ static int do_sandbox_android(void) #if SYZ_EXECUTOR || SYZ_NET_DEVICES initialize_netdevices(); #endif +#if SYZ_EXECUTOR || SYZ_VHCI_INJECTION + initialize_vhci(); +#endif if (chown(".", UNTRUSTED_APP_UID, UNTRUSTED_APP_UID) != 0) fail("chmod failed"); diff --git a/pkg/csource/options.go b/pkg/csource/options.go index 00f83157f..cb1a19114 100644 --- a/pkg/csource/options.go +++ b/pkg/csource/options.go @@ -31,15 +31,16 @@ type Options struct { Leak bool `json:"leak,omitempty"` // do leak checking // These options allow for a more fine-tuned control over the generated C code. - NetInjection bool `json:"tun,omitempty"` - NetDevices bool `json:"netdev,omitempty"` - NetReset bool `json:"resetnet,omitempty"` - Cgroups bool `json:"cgroups,omitempty"` - BinfmtMisc bool `json:"binfmt_misc,omitempty"` - CloseFDs bool `json:"close_fds"` - KCSAN bool `json:"kcsan,omitempty"` - DevlinkPCI bool `json:"devlinkpci,omitempty"` - USB bool `json:"usb,omitempty"` + NetInjection bool `json:"tun,omitempty"` + NetDevices bool `json:"netdev,omitempty"` + NetReset bool `json:"resetnet,omitempty"` + Cgroups bool `json:"cgroups,omitempty"` + BinfmtMisc bool `json:"binfmt_misc,omitempty"` + CloseFDs bool `json:"close_fds"` + KCSAN bool `json:"kcsan,omitempty"` + DevlinkPCI bool `json:"devlinkpci,omitempty"` + USB bool `json:"usb,omitempty"` + VhciInjection bool `json:"vhci,omitempty"` UseTmpDir bool `json:"tmpdir,omitempty"` HandleSegv bool `json:"segv,omitempty"` @@ -88,6 +89,9 @@ func (opts Options) Check(OS string) error { if opts.BinfmtMisc { return errors.New("option BinfmtMisc without sandbox") } + if opts.VhciInjection { + return errors.New("option VhciInjection without sandbox") + } } if opts.Sandbox == sandboxNamespace && !opts.UseTmpDir { // This is borken and never worked. @@ -135,6 +139,9 @@ func (opts Options) checkLinuxOnly(OS string) error { if opts.USB { return fmt.Errorf("option USB is not supported on %v", OS) } + if opts.VhciInjection { + return fmt.Errorf("option VHCI is not supported on %v", OS) + } if opts.Sandbox == sandboxNamespace || (opts.Sandbox == sandboxSetuid && !(OS == openbsd || OS == freebsd || OS == netbsd)) || opts.Sandbox == sandboxAndroid { @@ -151,21 +158,22 @@ func (opts Options) checkLinuxOnly(OS string) error { func DefaultOpts(cfg *mgrconfig.Config) Options { opts := Options{ - Threaded: true, - Collide: true, - Repeat: true, - Procs: cfg.Procs, - Sandbox: cfg.Sandbox, - NetInjection: true, - NetDevices: true, - NetReset: true, - Cgroups: true, - BinfmtMisc: true, - CloseFDs: true, - DevlinkPCI: true, - UseTmpDir: true, - HandleSegv: true, - Repro: true, + Threaded: true, + Collide: true, + Repeat: true, + Procs: cfg.Procs, + Sandbox: cfg.Sandbox, + NetInjection: true, + NetDevices: true, + NetReset: true, + Cgroups: true, + BinfmtMisc: true, + CloseFDs: true, + DevlinkPCI: true, + VhciInjection: true, + UseTmpDir: true, + HandleSegv: true, + Repro: true, } if cfg.TargetOS != linux { opts.NetInjection = false @@ -176,6 +184,7 @@ func DefaultOpts(cfg *mgrconfig.Config) Options { opts.CloseFDs = false opts.DevlinkPCI = false opts.USB = false + opts.VhciInjection = false } if cfg.Sandbox == "" || cfg.Sandbox == "setuid" { opts.NetReset = false @@ -256,6 +265,7 @@ func defaultFeatures(value bool) Features { "close_fds": {"close fds after each program", value}, "devlink_pci": {"setup devlink PCI device", value}, "usb": {"setup and use /dev/raw-gadget for USB emulation", value}, + "vhci": {"setup and use /dev/vhci for hci packet injection", value}, } } diff --git a/pkg/csource/options_test.go b/pkg/csource/options_test.go index e1457ea73..0786d6118 100644 --- a/pkg/csource/options_test.go +++ b/pkg/csource/options_test.go @@ -235,6 +235,7 @@ func TestParseFeaturesFlags(t *testing.T) { "close_fds": true, "devlink_pci": true, "usb": true, + "vhci": true, }}, {"none", "none", false, map[string]bool{ "tun": false, @@ -245,6 +246,7 @@ func TestParseFeaturesFlags(t *testing.T) { "close_fds": false, "devlink_pci": false, "usb": false, + "vhci": false, }}, {"all", "none", true, map[string]bool{ "tun": true, @@ -255,6 +257,7 @@ func TestParseFeaturesFlags(t *testing.T) { "close_fds": true, "devlink_pci": true, "usb": true, + "vhci": true, }}, {"", "none", true, map[string]bool{ "tun": false, @@ -265,6 +268,7 @@ func TestParseFeaturesFlags(t *testing.T) { "close_fds": false, "devlink_pci": false, "usb": false, + "vhci": false, }}, {"none", "all", true, map[string]bool{ "tun": false, @@ -275,6 +279,7 @@ func TestParseFeaturesFlags(t *testing.T) { "close_fds": false, "devlink_pci": false, "usb": false, + "vhci": false, }}, {"none", "", true, map[string]bool{ "tun": true, @@ -285,6 +290,7 @@ func TestParseFeaturesFlags(t *testing.T) { "close_fds": true, "devlink_pci": true, "usb": true, + "vhci": true, }}, {"tun,net_dev", "none", true, map[string]bool{ "tun": true, @@ -295,6 +301,7 @@ func TestParseFeaturesFlags(t *testing.T) { "close_fds": false, "devlink_pci": false, "usb": false, + "vhci": false, }}, {"none", "cgroups,net_dev", true, map[string]bool{ "tun": true, @@ -305,6 +312,7 @@ func TestParseFeaturesFlags(t *testing.T) { "close_fds": true, "devlink_pci": true, "usb": true, + "vhci": true, }}, {"close_fds", "none", true, map[string]bool{ "tun": false, @@ -315,6 +323,7 @@ func TestParseFeaturesFlags(t *testing.T) { "close_fds": true, "devlink_pci": false, "usb": false, + "vhci": false, }}, } for i, test := range tests { diff --git a/pkg/host/features.go b/pkg/host/features.go index 800e3ea19..07f6487a8 100644 --- a/pkg/host/features.go +++ b/pkg/host/features.go @@ -27,6 +27,7 @@ const ( FeatureKCSAN FeatureDevlinkPCI FeatureUSBEmulation + FeatureVhciInjection numFeatures ) @@ -65,6 +66,7 @@ func Check(target *prog.Target) (*Features, error) { FeatureKCSAN: {Name: "concurrency sanitizer", Reason: unsupported}, FeatureDevlinkPCI: {Name: "devlink PCI setup", Reason: unsupported}, FeatureUSBEmulation: {Name: "USB emulation", Reason: unsupported}, + FeatureVhciInjection: {Name: "hci packet injection", Reason: unsupported}, } if noHostChecks(target) { return res, nil diff --git a/pkg/host/features_linux.go b/pkg/host/features_linux.go index 8c6f63004..230022c38 100644 --- a/pkg/host/features_linux.go +++ b/pkg/host/features_linux.go @@ -28,6 +28,7 @@ func init() { checkFeature[FeatureKCSAN] = checkKCSAN checkFeature[FeatureDevlinkPCI] = checkDevlinkPCI checkFeature[FeatureUSBEmulation] = checkUSBEmulation + checkFeature[FeatureVhciInjection] = checkVhciInjection } func checkCoverage() string { @@ -191,6 +192,13 @@ func checkUSBEmulation() string { return "" } +func checkVhciInjection() string { + if err := osutil.IsAccessible("/dev/vhci"); err != nil { + return err.Error() + } + return "" +} + func checkDebugFS() string { if err := osutil.IsAccessible("/sys/kernel/debug"); err != nil { return "debugfs is not enabled or not mounted" diff --git a/pkg/host/syscalls_linux.go b/pkg/host/syscalls_linux.go index 715deada4..f0230bb6a 100644 --- a/pkg/host/syscalls_linux.go +++ b/pkg/host/syscalls_linux.go @@ -181,6 +181,9 @@ func isSupportedSyzkall(c *prog.Syscall, target *prog.Target, sandbox string) (b case "syz_emit_ethernet", "syz_extract_tcp_res": reason := checkNetInjection() return reason == "", reason + case "syz_emit_vhci": + reason := checkVhciInjection() + return reason == "", reason case "syz_usb_connect", "syz_usb_connect_ath9k", "syz_usb_disconnect", "syz_usb_control_io", "syz_usb_ep_write", "syz_usb_ep_read": reason := checkUSBEmulation() diff --git a/pkg/ipc/ipc.go b/pkg/ipc/ipc.go index 11e73835b..5ae502e5d 100644 --- a/pkg/ipc/ipc.go +++ b/pkg/ipc/ipc.go @@ -28,18 +28,19 @@ type EnvFlags uint64 // Note: New / changed flags should be added to parse_env_flags in executor.cc. const ( - FlagDebug EnvFlags = 1 << iota // debug output from executor - FlagSignal // collect feedback signals (coverage) - FlagSandboxSetuid // impersonate nobody user - FlagSandboxNamespace // use namespaces for sandboxing - FlagSandboxAndroid // use Android sandboxing for the untrusted_app domain - FlagExtraCover // collect extra coverage - FlagEnableTun // setup and use /dev/tun for packet injection - FlagEnableNetDev // setup more network devices for testing - FlagEnableNetReset // reset network namespace between programs - FlagEnableCgroups // setup cgroups for testing - FlagEnableCloseFds // close fds after each program - FlagEnableDevlinkPCI // setup devlink PCI device + FlagDebug EnvFlags = 1 << iota // debug output from executor + FlagSignal // collect feedback signals (coverage) + FlagSandboxSetuid // impersonate nobody user + FlagSandboxNamespace // use namespaces for sandboxing + FlagSandboxAndroid // use Android sandboxing for the untrusted_app domain + FlagExtraCover // collect extra coverage + FlagEnableTun // setup and use /dev/tun for packet injection + FlagEnableNetDev // setup more network devices for testing + FlagEnableNetReset // reset network namespace between programs + FlagEnableCgroups // setup cgroups for testing + FlagEnableCloseFds // close fds after each program + FlagEnableDevlinkPCI // setup devlink PCI device + FlagEnableVhciInjection // setup and use /dev/vhci for hci packet injection ) // Per-exec flags for ExecOpts.Flags. diff --git a/pkg/repro/repro.go b/pkg/repro/repro.go index 2525198bf..3003d99aa 100644 --- a/pkg/repro/repro.go +++ b/pkg/repro/repro.go @@ -199,6 +199,9 @@ func createStartOptions(cfg *mgrconfig.Config, features *host.Features, crashTyp if !features[host.FeatureUSBEmulation].Enabled { opts.USB = false } + if !features[host.FeatureVhciInjection].Enabled { + opts.VhciInjection = false + } } return opts } @@ -862,6 +865,7 @@ var cSimplifies = append(progSimplifies, []Simplify{ opts.CloseFDs = false opts.DevlinkPCI = false opts.USB = false + opts.VhciInjection = false return true }, func(opts *csource.Options) bool { @@ -923,6 +927,13 @@ var cSimplifies = append(progSimplifies, []Simplify{ return true }, func(opts *csource.Options) bool { + if !opts.VhciInjection { + return false + } + opts.VhciInjection = false + return true + }, + func(opts *csource.Options) bool { if !opts.UseTmpDir || opts.Sandbox == "namespace" || opts.Cgroups { return false } diff --git a/pkg/runtest/run.go b/pkg/runtest/run.go index 2da871fe6..af57e7629 100644 --- a/pkg/runtest/run.go +++ b/pkg/runtest/run.go @@ -394,6 +394,9 @@ func (ctx *Context) createSyzTest(p *prog.Prog, sandbox string, threaded, cov bo if ctx.Features[host.FeatureDevlinkPCI].Enabled { cfg.Flags |= ipc.FlagEnableDevlinkPCI } + if ctx.Features[host.FeatureVhciInjection].Enabled { + cfg.Flags |= ipc.FlagEnableVhciInjection + } if ctx.Debug { cfg.Flags |= ipc.FlagDebug } @@ -426,6 +429,9 @@ func (ctx *Context) createCTest(p *prog.Prog, sandbox string, threaded bool, tim if ctx.Features[host.FeatureNetDevices].Enabled { opts.NetDevices = true } + if ctx.Features[host.FeatureVhciInjection].Enabled { + opts.VhciInjection = true + } } src, err := csource.Write(p, opts) if err != nil { diff --git a/sys/linux/dev_vhci.txt b/sys/linux/dev_vhci.txt index 48ef737d6..040d4e2a1 100644 --- a/sys/linux/dev_vhci.txt +++ b/sys/linux/dev_vhci.txt @@ -6,9 +6,7 @@ include <net/bluetooth/hci_sock.h> include <net/bluetooth/sco.h> include <net/bluetooth/hci.h> -resource fd_vhci[fd] -openat$vhci(fd const[AT_FDCWD], file ptr[in, string["/dev/vhci"]], flags flags[open_flags]) fd_vhci -write$vhci(fd fd_vhci, data ptr[in, vhci_command], size bytesize[data]) +syz_emit_vhci(data ptr[in, vhci_command], size bytesize[data]) vhci_command [ HCI_EVENT_PKT vhci_command_event_pkt @@ -42,14 +40,14 @@ vhci_command_vendor_pkt { vhci_vendor_pkt_opcode = HCI_PRIMARY, HCI_AMP, HCI_EXTERNAL_CONFIG, HCI_RAW_DEVICE type hci_acl_hdr[DATA] { - bc int16:2 + handle const[0x100, int16:12] pb int16:2 - handle int16:12 + bc int16:2 dlen bytesize[DATA, int16] } [packed] hci_event_hdr_un [ - extended_inquiry_info hci_event_hdr_t[HCI_EV_EXTENDED_INQUIRY_RESULT, extended_inquiry_info] + extended_inquiry_info hci_event_hdr_t[HCI_EV_EXTENDED_INQUIRY_RESULT, extended_inquiry_info_t] hci_ev_auth_complete hci_event_hdr_t[HCI_EV_AUTH_COMPLETE, hci_ev_auth_complete] hci_ev_change_link_key_complete hci_event_hdr_t[HCI_EV_CHANGE_LINK_KEY_COMPLETE, hci_ev_change_link_key_complete] hci_ev_channel_selected hci_event_hdr_t[HCI_EV_CHANNEL_SELECTED, hci_ev_channel_selected] @@ -97,9 +95,9 @@ hci_event_hdr_un [ hci_ev_user_confirm_req hci_event_hdr_t[HCI_EV_USER_CONFIRM_REQUEST, hci_ev_user_confirm_req] hci_ev_user_passkey_notify hci_event_hdr_t[HCI_EV_USER_PASSKEY_NOTIFY, hci_ev_user_passkey_notify] hci_ev_user_passkey_req hci_event_hdr_t[HCI_EV_USER_PASSKEY_REQUEST, hci_ev_user_passkey_req] - inquiry_info hci_event_hdr_t[HCI_EV_INQUIRY_RESULT, inquiry_info] - inquiry_info_with_rssi hci_event_hdr_t[HCI_EV_INQUIRY_RESULT_WITH_RSSI, inquiry_info_with_rssi] - inquiry_info_with_rssi_and_pscan_mode hci_event_hdr_t[HCI_EV_INQUIRY_RESULT_WITH_RSSI, inquiry_info_with_rssi_and_pscan_mode] + inquiry_info hci_event_hdr_t[HCI_EV_INQUIRY_RESULT, inquiry_info_t] + inquiry_info_with_rssi hci_event_hdr_t[HCI_EV_INQUIRY_RESULT_WITH_RSSI, inquiry_info_with_rssi_t] + inquiry_info_with_rssi_and_pscan_mode hci_event_hdr_t[HCI_EV_INQUIRY_RESULT_WITH_RSSI, inquiry_info_with_rssi_and_pscan_mode_t] ] [varlen] type hci_event_hdr_t[EVENT, PAYLOAD] { @@ -113,13 +111,13 @@ type hci_event_hdr[EVENT] { } [packed] hci_ev_le_meta_un [ - hci_ev_le_advertising_info hci_ev_le_meta_t[HCI_EV_LE_ADVERTISING_REPORT, hci_ev_le_advertising_info] + hci_ev_le_advertising_info hci_ev_le_meta_t[HCI_EV_LE_ADVERTISING_REPORT, hci_ev_le_advertising_info_t] hci_ev_le_conn_complete hci_ev_le_meta_t[HCI_EV_LE_CONN_COMPLETE, hci_ev_le_conn_complete] hci_ev_le_conn_update_complete hci_ev_le_meta_t[HCI_EV_LE_CONN_UPDATE_COMPLETE, hci_ev_le_conn_update_complete] hci_ev_le_data_len_change hci_ev_le_meta_t[HCI_EV_LE_DATA_LEN_CHANGE, hci_ev_le_data_len_change] hci_ev_le_direct_adv_info hci_ev_le_meta_t[HCI_EV_LE_DIRECT_ADV_REPORT, hci_ev_le_direct_adv_info] hci_ev_le_enh_conn_complete hci_ev_le_meta_t[HCI_EV_LE_ENHANCED_CONN_COMPLETE, hci_ev_le_enh_conn_complete] - hci_ev_le_ext_adv_report hci_ev_le_meta_t[HCI_EV_LE_EXT_ADV_REPORT, hci_ev_le_ext_adv_report] + hci_ev_le_ext_adv_report hci_ev_le_meta_t[HCI_EV_LE_EXT_ADV_REPORT, hci_ev_le_ext_adv_report_t] hci_ev_le_ltk_req hci_ev_le_meta_t[HCI_EV_LE_LTK_REQ, hci_ev_le_ltk_req] hci_ev_le_phy_update_complete hci_ev_le_meta_t[HCI_EV_LE_PHY_UPDATE_COMPLETE, hci_ev_le_phy_update_complete] hci_ev_le_remote_conn_param_req hci_ev_le_meta_t[HCI_EV_LE_REMOTE_CONN_PARAM_REQ, hci_ev_le_remote_conn_param_req] @@ -215,6 +213,11 @@ type hci_ev_cmd_complete[OPCODE] { link_types = SCO_LINK, ACL_LINK, ESCO_LINK bdaddr_types = ADDR_LE_DEV_PUBLIC, ADDR_LE_DEV_RANDOM +extended_inquiry_info_t { + num_rsp len[rsps, int8] + rsps array[extended_inquiry_info] +} [packed] + extended_inquiry_info { bdaddr bdaddr_t pscan_rep_mode int8 @@ -327,6 +330,11 @@ hci_ev_keypress_notify { type int8 } [packed] +hci_ev_le_advertising_info_t { + num_reports len[reports, int8] + reports array[hci_ev_le_advertising_info] +} [packed] + hci_ev_le_advertising_info { evt_type int8 bdaddr_type flags[bdaddr_types, int8] @@ -386,6 +394,11 @@ hci_ev_le_enh_conn_complete { clk_accurancy int8 } [packed] +hci_ev_le_ext_adv_report_t { + num_reports len[reports, int8] + reports array[hci_ev_le_ext_adv_report] +} [packed] + hci_ev_le_ext_adv_report { evt_type int16 bdaddr_type flags[bdaddr_types, int8] @@ -1001,6 +1014,11 @@ hci_qos { delay_variation int32 } [packed] +inquiry_info_t { + num_rsp len[rsps, int8] + rsps array[inquiry_info] +} [packed] + inquiry_info { bdaddr bdaddr_t pscan_rep_mode int8 @@ -1010,6 +1028,11 @@ inquiry_info { clock_offset int16 } [packed] +inquiry_info_with_rssi_t { + num_rsp len[rsps, int8] + rsps array[inquiry_info_with_rssi] +} [packed] + inquiry_info_with_rssi { bdaddr bdaddr_t pscan_rep_mode int8 @@ -1019,6 +1042,11 @@ inquiry_info_with_rssi { rssi int8 } [packed] +inquiry_info_with_rssi_and_pscan_mode_t { + num_rsp len[rsps, int8] + rsps array[inquiry_info_with_rssi_and_pscan_mode] +} [packed] + inquiry_info_with_rssi_and_pscan_mode { bdaddr bdaddr_t pscan_rep_mode int8 diff --git a/sys/linux/l2cap.txt b/sys/linux/l2cap.txt index c9fd6fe29..3bc4e608f 100644 --- a/sys/linux/l2cap.txt +++ b/sys/linux/l2cap.txt @@ -68,17 +68,23 @@ l2cap_cmd_rej_unk { reason int16 } [packed] +l2cap_conf_opt { + type int8 + len bytesize[val, int8] + val array[int8] +} [packed] + l2cap_conf_req { dcid int16 flags int16 - data array[int8] + data array[l2cap_conf_opt] } [packed] l2cap_conf_rsp { scid int16 flags int16 result int16 - data array[int8] + data array[l2cap_conf_opt] } [packed] l2cap_conn_param_update_req { diff --git a/sys/linux/test/vhci b/sys/linux/test/vhci new file mode 100644 index 000000000..575ee5d65 --- /dev/null +++ b/sys/linux/test/vhci @@ -0,0 +1 @@ +syz_emit_vhci(&(0x7f0000000040)=@HCI_EVENT_PKT={0x4, @hci_ev_cmd_status={{0xf, 0x4}, {0x1, 0xfa, 0x41b}}}, 0x7) diff --git a/syz-fuzzer/fuzzer.go b/syz-fuzzer/fuzzer.go index 6791393b2..876bc7c06 100644 --- a/syz-fuzzer/fuzzer.go +++ b/syz-fuzzer/fuzzer.go @@ -102,6 +102,27 @@ const ( OutputFile ) +func createIPCConfig(features *host.Features, config *ipc.Config) { + if features[host.FeatureExtraCoverage].Enabled { + config.Flags |= ipc.FlagExtraCover + } + if features[host.FeatureNetInjection].Enabled { + config.Flags |= ipc.FlagEnableTun + } + if features[host.FeatureNetDevices].Enabled { + config.Flags |= ipc.FlagEnableNetDev + } + config.Flags |= ipc.FlagEnableNetReset + config.Flags |= ipc.FlagEnableCgroups + config.Flags |= ipc.FlagEnableCloseFds + if features[host.FeatureDevlinkPCI].Enabled { + config.Flags |= ipc.FlagEnableDevlinkPCI + } + if features[host.FeatureVhciInjection].Enabled { + config.Flags |= ipc.FlagEnableVhciInjection + } +} + // nolint: funlen func main() { debug.SetGCPercent(50) @@ -204,21 +225,7 @@ func main() { for _, feat := range r.CheckResult.Features.Supported() { log.Logf(0, "%v: %v", feat.Name, feat.Reason) } - if r.CheckResult.Features[host.FeatureExtraCoverage].Enabled { - config.Flags |= ipc.FlagExtraCover - } - if r.CheckResult.Features[host.FeatureNetInjection].Enabled { - config.Flags |= ipc.FlagEnableTun - } - if r.CheckResult.Features[host.FeatureNetDevices].Enabled { - config.Flags |= ipc.FlagEnableNetDev - } - config.Flags |= ipc.FlagEnableNetReset - config.Flags |= ipc.FlagEnableCgroups - config.Flags |= ipc.FlagEnableCloseFds - if r.CheckResult.Features[host.FeatureDevlinkPCI].Enabled { - config.Flags |= ipc.FlagEnableDevlinkPCI - } + createIPCConfig(r.CheckResult.Features, config) if *flagRunTest { runTest(target, manager, *flagName, config.Executor) diff --git a/tools/syz-execprog/execprog.go b/tools/syz-execprog/execprog.go index 38412edd4..a5ef8fbc4 100644 --- a/tools/syz-execprog/execprog.go +++ b/tools/syz-execprog/execprog.go @@ -329,5 +329,8 @@ func createConfig(target *prog.Target, if featuresFlags["devlink_pci"].Enabled && features[host.FeatureDevlinkPCI].Enabled { config.Flags |= ipc.FlagEnableDevlinkPCI } + if featuresFlags["vhci"].Enabled && features[host.FeatureVhciInjection].Enabled { + config.Flags |= ipc.FlagEnableVhciInjection + } return config, execOpts } diff --git a/tools/syz-prog2c/prog2c.go b/tools/syz-prog2c/prog2c.go index 5d161929e..399b5e417 100644 --- a/tools/syz-prog2c/prog2c.go +++ b/tools/syz-prog2c/prog2c.go @@ -71,29 +71,30 @@ func main() { os.Exit(1) } opts := csource.Options{ - Threaded: *flagThreaded, - Collide: *flagCollide, - Repeat: *flagRepeat != 1, - RepeatTimes: *flagRepeat, - Procs: *flagProcs, - Sandbox: *flagSandbox, - Fault: *flagFaultCall >= 0, - FaultCall: *flagFaultCall, - FaultNth: *flagFaultNth, - Leak: *flagLeak, - NetInjection: features["tun"].Enabled, - NetDevices: features["net_dev"].Enabled, - NetReset: features["net_reset"].Enabled, - Cgroups: features["cgroups"].Enabled, - BinfmtMisc: features["binfmt_misc"].Enabled, - CloseFDs: features["close_fds"].Enabled, - KCSAN: features["kcsan"].Enabled, - DevlinkPCI: features["devlink_pci"].Enabled, - USB: features["usb"].Enabled, - UseTmpDir: *flagUseTmpDir, - HandleSegv: *flagHandleSegv, - Repro: false, - Trace: *flagTrace, + Threaded: *flagThreaded, + Collide: *flagCollide, + Repeat: *flagRepeat != 1, + RepeatTimes: *flagRepeat, + Procs: *flagProcs, + Sandbox: *flagSandbox, + Fault: *flagFaultCall >= 0, + FaultCall: *flagFaultCall, + FaultNth: *flagFaultNth, + Leak: *flagLeak, + NetInjection: features["tun"].Enabled, + NetDevices: features["net_dev"].Enabled, + NetReset: features["net_reset"].Enabled, + Cgroups: features["cgroups"].Enabled, + BinfmtMisc: features["binfmt_misc"].Enabled, + CloseFDs: features["close_fds"].Enabled, + KCSAN: features["kcsan"].Enabled, + DevlinkPCI: features["devlink_pci"].Enabled, + USB: features["usb"].Enabled, + VhciInjection: features["vhci"].Enabled, + UseTmpDir: *flagUseTmpDir, + HandleSegv: *flagHandleSegv, + Repro: false, + Trace: *flagTrace, } src, err := csource.Write(p, opts) if err != nil { diff --git a/tools/syz-reprolist/reprolist.go b/tools/syz-reprolist/reprolist.go index f6283f933..e4c26011f 100644 --- a/tools/syz-reprolist/reprolist.go +++ b/tools/syz-reprolist/reprolist.go @@ -228,6 +228,10 @@ func createProg2CArgs(bug *dashapi.LoadBugResp, opts csource.Options, file strin enable = append(enable, "devlink_pci") flags = append(flags, "-devlinkpci") } + if opts.VhciInjection { + enable = append(enable, "vhci") + flags = append(flags, "-vhci") + } if !haveEnableFlag { args = append(args, flags...) } else if len(enable) != 0 { diff --git a/tools/syz-stress/stress.go b/tools/syz-stress/stress.go index b2fa4cb8e..9ec0229f4 100644 --- a/tools/syz-stress/stress.go +++ b/tools/syz-stress/stress.go @@ -162,6 +162,9 @@ func createIPCConfig(target *prog.Target, features *host.Features, featuresFlags if featuresFlags["devlink_pci"].Enabled && features[host.FeatureDevlinkPCI].Enabled { config.Flags |= ipc.FlagEnableDevlinkPCI } + if featuresFlags["vhci"].Enabled && features[host.FeatureVhciInjection].Enabled { + config.Flags |= ipc.FlagEnableVhciInjection + } return config, execOpts, nil } |
