aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTheOfficialFloW <theflow@google.com>2020-07-30 11:33:48 +0200
committerGitHub <noreply@github.com>2020-07-30 11:33:48 +0200
commitb0947553167615d7bb1b67b22d2d080e5a5ab2cd (patch)
treef3f104edb509ef1cf89c1db3119052f4d7d4e7ae
parent233283a191b3c32a48c56928985c8e2cfc004aeb (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.h307
-rw-r--r--executor/executor.cc2
-rw-r--r--pkg/csource/common.go1
-rw-r--r--pkg/csource/csource.go5
-rw-r--r--pkg/csource/generated.go293
-rw-r--r--pkg/csource/options.go58
-rw-r--r--pkg/csource/options_test.go9
-rw-r--r--pkg/host/features.go2
-rw-r--r--pkg/host/features_linux.go8
-rw-r--r--pkg/host/syscalls_linux.go3
-rw-r--r--pkg/ipc/ipc.go25
-rw-r--r--pkg/repro/repro.go11
-rw-r--r--pkg/runtest/run.go6
-rw-r--r--sys/linux/dev_vhci.txt50
-rw-r--r--sys/linux/l2cap.txt10
-rw-r--r--sys/linux/test/vhci1
-rw-r--r--syz-fuzzer/fuzzer.go37
-rw-r--r--tools/syz-execprog/execprog.go3
-rw-r--r--tools/syz-prog2c/prog2c.go47
-rw-r--r--tools/syz-reprolist/reprolist.go4
-rw-r--r--tools/syz-stress/stress.go3
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
}