aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--executor/common_linux.h455
-rw-r--r--executor/executor.cc2
-rw-r--r--pkg/csource/common.go1
-rw-r--r--pkg/csource/generated.go417
-rw-r--r--pkg/csource/options.go10
-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.go13
-rw-r--r--pkg/ipc/ipc.go1
-rw-r--r--pkg/repro/repro.go11
-rw-r--r--pkg/runtest/run.go6
-rw-r--r--sys/linux/net_80211.txt51
-rw-r--r--sys/linux/net_80211.txt.const6
-rw-r--r--sys/linux/socket.txt2
-rw-r--r--sys/linux/test/80211_ibss9
-rw-r--r--syz-fuzzer/fuzzer.go3
-rw-r--r--tools/syz-execprog/execprog.go3
-rw-r--r--tools/syz-prog2c/prog2c.go1
-rw-r--r--tools/syz-reprolist/reprolist.go6
-rw-r--r--tools/syz-stress/stress.go3
21 files changed, 1009 insertions, 10 deletions
diff --git a/executor/common_linux.h b/executor/common_linux.h
index 756bd8707..63b769f4c 100644
--- a/executor/common_linux.h
+++ b/executor/common_linux.h
@@ -107,7 +107,8 @@ static bool write_file(const char* file, const char* what, ...)
}
#endif
-#if SYZ_EXECUTOR || SYZ_NET_DEVICES || SYZ_NET_INJECTION || SYZ_DEVLINK_PCI || __NR_syz_genetlink_get_family_id
+#if SYZ_EXECUTOR || SYZ_NET_DEVICES || SYZ_NET_INJECTION || SYZ_DEVLINK_PCI || SYZ_WIFI || \
+ __NR_syz_genetlink_get_family_id || __NR_syz_80211_inject_frame || __NR_syz_80211_join_ibss
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/in.h>
@@ -201,7 +202,8 @@ static int netlink_send_ext(struct nlmsg* nlmsg, int sock,
return ((struct nlmsgerr*)(hdr + 1))->error;
}
-#if SYZ_EXECUTOR || SYZ_NET_DEVICES || SYZ_NET_INJECTION || SYZ_DEVLINK_PCI
+#if SYZ_EXECUTOR || SYZ_NET_DEVICES || SYZ_NET_INJECTION || SYZ_DEVLINK_PCI || SYZ_WIFI || \
+ __NR_syz_80211_join_ibss || __NR_syz_80211_inject_frame
static int netlink_send(struct nlmsg* nlmsg, int sock)
{
return netlink_send_ext(nlmsg, sock, 0, NULL);
@@ -471,7 +473,7 @@ static void netlink_add_neigh(struct nlmsg* nlmsg, int sock, const char* name,
#endif
#endif
-#if SYZ_EXECUTOR || SYZ_NET_DEVICES || SYZ_NET_INJECTION || SYZ_DEVLINK_PCI
+#if SYZ_EXECUTOR || SYZ_NET_DEVICES || SYZ_NET_INJECTION || SYZ_DEVLINK_PCI || SYZ_WIFI
static struct nlmsg nlmsg;
#endif
@@ -728,6 +730,278 @@ static void initialize_devlink_pci(void)
#endif
#endif
+#if SYZ_EXECUTOR || SYZ_WIFI || __NR_syz_80211_inject_frame || __NR_syz_80211_join_ibss
+
+#define WIFI_INITIAL_DEVICE_COUNT 2
+#define WIFI_MAC_BASE \
+ { \
+ 0x08, 0x02, 0x11, 0x00, 0x00, 0x00 \
+ }
+#define WIFI_IBSS_BSSID \
+ { \
+ 0x50, 0x50, 0x50, 0x50, 0x50, 0x50 \
+ }
+#define WIFI_IBSS_SSID \
+ { \
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 \
+ }
+#define WIFI_DEFAULT_FREQUENCY 2412
+#define WIFI_DEFAULT_SIGNAL 0
+#define WIFI_DEFAULT_RX_RATE 1
+
+// consts from drivers/net/wireless/mac80211_hwsim.h
+#define HWSIM_CMD_REGISTER 1
+#define HWSIM_CMD_FRAME 2
+#define HWSIM_CMD_NEW_RADIO 4
+#define HWSIM_ATTR_SUPPORT_P2P_DEVICE 14
+#define HWSIM_ATTR_PERM_ADDR 22
+
+#endif
+
+#if SYZ_EXECUTOR || SYZ_WIFI || __NR_syz_80211_join_ibss
+#include <linux/genetlink.h>
+#include <linux/if_ether.h>
+#include <linux/nl80211.h>
+#include <linux/rtnetlink.h>
+#include <net/if.h>
+#include <stdbool.h>
+#include <sys/ioctl.h>
+
+// From linux/if.h, but we cannot include the file as it conflicts with net/if.h
+#define IF_OPER_UP 6
+
+// IBSS parameters for nl80211_join_ibss
+struct join_ibss_props {
+ int wiphy_freq;
+ bool wiphy_freq_fixed;
+ uint8* mac;
+ uint8* ssid;
+ int ssid_len;
+};
+
+static int set_interface_state(const char* interface_name, int on)
+{
+ struct ifreq ifr;
+ int sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0) {
+ debug("set_interface_state: failed to open socket, errno %d\n", errno);
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ strcpy(ifr.ifr_name, interface_name);
+ int ret = ioctl(sock, SIOCGIFFLAGS, &ifr);
+ if (ret < 0) {
+ debug("set_interface_state: failed to execute SIOCGIFFLAGS, ret %d\n", ret);
+ close(sock);
+ return -1;
+ }
+
+ if (on)
+ ifr.ifr_flags |= IFF_UP;
+ else
+ ifr.ifr_flags &= ~IFF_UP;
+
+ ret = ioctl(sock, SIOCSIFFLAGS, &ifr);
+ close(sock);
+ if (ret < 0) {
+ debug("set_interface_state: failed to execute SIOCSIFFLAGS, ret %d\n", ret);
+ return -1;
+ }
+ return 0;
+}
+
+static int nl80211_set_interface(struct nlmsg* nlmsg, int sock, int nl80211_family, uint32 ifindex, uint32 iftype)
+{
+ struct genlmsghdr genlhdr;
+
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = NL80211_CMD_SET_INTERFACE;
+ netlink_init(nlmsg, nl80211_family, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, NL80211_ATTR_IFINDEX, &ifindex, sizeof(ifindex));
+ netlink_attr(nlmsg, NL80211_ATTR_IFTYPE, &iftype, sizeof(iftype));
+ int err = netlink_send(nlmsg, sock);
+ if (err < 0) {
+ debug("nl80211_set_interface failed: %s\n", strerror(-err));
+ return -1;
+ }
+ return 0;
+}
+
+static int nl80211_join_ibss(struct nlmsg* nlmsg, int sock, int nl80211_family, uint32 ifindex, struct join_ibss_props* props)
+{
+ struct genlmsghdr genlhdr;
+
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = NL80211_CMD_JOIN_IBSS;
+ netlink_init(nlmsg, nl80211_family, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, NL80211_ATTR_IFINDEX, &ifindex, sizeof(ifindex));
+ netlink_attr(nlmsg, NL80211_ATTR_SSID, props->ssid, props->ssid_len);
+ netlink_attr(nlmsg, NL80211_ATTR_WIPHY_FREQ, &(props->wiphy_freq), sizeof(props->wiphy_freq));
+ if (props->mac)
+ netlink_attr(nlmsg, NL80211_ATTR_MAC, props->mac, ETH_ALEN);
+ if (props->wiphy_freq_fixed)
+ netlink_attr(nlmsg, NL80211_ATTR_FREQ_FIXED, NULL, 0);
+ int err = netlink_send(nlmsg, sock);
+ if (err < 0) {
+ debug("nl80211_join_ibss failed: %s\n", strerror(-err));
+ return -1;
+ }
+ return 0;
+}
+
+static int get_ifla_operstate(struct nlmsg* nlmsg, int ifindex)
+{
+ struct ifinfomsg info;
+ memset(&info, 0, sizeof(info));
+ info.ifi_family = AF_UNSPEC;
+ info.ifi_index = ifindex;
+
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1) {
+ debug("get_ifla_operstate: socket failed: %d\n", errno);
+ return -1;
+ }
+
+ netlink_init(nlmsg, RTM_GETLINK, 0, &info, sizeof(info));
+ int n;
+ int err = netlink_send_ext(nlmsg, sock, RTM_NEWLINK, &n);
+ close(sock);
+
+ if (err) {
+ debug("get_ifla_operstate: failed to query: %s\n", strerror(-err));
+ return -1;
+ }
+
+ struct rtattr* attr = IFLA_RTA(NLMSG_DATA(nlmsg->buf));
+ for (; RTA_OK(attr, n); attr = RTA_NEXT(attr, n)) {
+ if (attr->rta_type == IFLA_OPERSTATE)
+ return *((int32_t*)RTA_DATA(attr));
+ }
+
+ return -1;
+}
+
+static int await_ifla_operstate(struct nlmsg* nlmsg, char* interface, int operstate)
+{
+ int ifindex = if_nametoindex(interface);
+ while (true) {
+ usleep(1000); // 1 ms
+ int ret = get_ifla_operstate(nlmsg, ifindex);
+ if (ret < 0)
+ return ret;
+ if (ret == operstate)
+ return 0;
+ }
+ return 0;
+}
+
+static int nl80211_setup_ibss_interface(struct nlmsg* nlmsg, int sock, int nl80211_family_id, char* interface, struct join_ibss_props* ibss_props)
+{
+ int ifindex = if_nametoindex(interface);
+ if (ifindex == 0) {
+ debug("nl80211_setup_ibss_interface: if_nametoindex failed for %.32s, ret 0\n", interface);
+ return -1;
+ }
+
+ int ret = nl80211_set_interface(nlmsg, sock, nl80211_family_id, ifindex, NL80211_IFTYPE_ADHOC);
+ if (ret < 0) {
+ debug("nl80211_setup_ibss_interface: nl80211_set_interface failed for %.32s, ret %d\n", interface, ret);
+ return -1;
+ }
+
+ ret = set_interface_state(interface, 1);
+ if (ret < 0) {
+ debug("nl80211_setup_ibss_interface: set_interface_state failed for %.32s, ret %d\n", interface, ret);
+ return -1;
+ }
+
+ ret = nl80211_join_ibss(nlmsg, sock, nl80211_family_id, ifindex, ibss_props);
+ if (ret < 0) {
+ debug("nl80211_setup_ibss_interface: nl80211_join_ibss failed for %.32s, ret %d\n", interface, ret);
+ return -1;
+ }
+
+ return 0;
+}
+#endif
+
+#if SYZ_EXECUTOR || SYZ_WIFI
+static int hwsim80211_create_device(struct nlmsg* nlmsg, int sock, int hwsim_family, uint8 mac_addr[ETH_ALEN])
+{
+ struct genlmsghdr genlhdr;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = HWSIM_CMD_NEW_RADIO;
+ netlink_init(nlmsg, hwsim_family, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, HWSIM_ATTR_SUPPORT_P2P_DEVICE, NULL, 0);
+ netlink_attr(nlmsg, HWSIM_ATTR_PERM_ADDR, mac_addr, ETH_ALEN);
+ int err = netlink_send(nlmsg, sock);
+ if (err < 0) {
+ debug("hwsim80211_create_device failed: %s\n", strerror(-err));
+ return -1;
+ }
+ return 0;
+}
+
+static void initialize_wifi_devices(void)
+{
+ // Set up virtual wifi devices and join them into an IBSS network.
+ // An IBSS network is created here in order to put these devices in an operable state right from
+ // the beginning. It has the following positive effects.
+ // 1. Frame injection becomes possible from the very start.
+ // 2. A number of nl80211 commands expect their target wireless interface to be in an operable state.
+ // 3. Simplification of reproducer generation - in many cases the reproducer will not have to spend time
+ // selecting system calls that set up the environment.
+ //
+ // IBSS network was chosen as the simplest network type to begin with.
+
+#if SYZ_EXECUTOR
+ if (!flag_wifi)
+ return;
+#endif
+ uint8 mac_addr[6] = WIFI_MAC_BASE;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock < 0) {
+ debug("initialize_wifi_devices: failed to create socket (%d)\n", errno);
+ return;
+ }
+
+ int hwsim_family_id = netlink_query_family_id(&nlmsg, sock, "MAC80211_HWSIM");
+ int nl80211_family_id = netlink_query_family_id(&nlmsg, sock, "nl80211");
+ uint8 ssid[] = WIFI_IBSS_SSID;
+ uint8 bssid[] = WIFI_IBSS_BSSID;
+ struct join_ibss_props ibss_props = {
+ .wiphy_freq = WIFI_DEFAULT_FREQUENCY, .wiphy_freq_fixed = true, .mac = bssid, .ssid = ssid, .ssid_len = sizeof(ssid)};
+
+ for (int device_id = 0; device_id < WIFI_INITIAL_DEVICE_COUNT; device_id++) {
+ // Virtual wifi devices will have consequtive mac addresses
+ mac_addr[5] = device_id;
+ int ret = hwsim80211_create_device(&nlmsg, sock, hwsim_family_id, mac_addr);
+ if (ret < 0)
+ fail("initialize_wifi_devices: failed to create device #%d\n", device_id);
+
+ // For each device, unless HWSIM_ATTR_NO_VIF is passed, a network interface is created
+ // automatically. Such interfaces are named "wlan0", "wlan1" and so on.
+ char interface[6] = "wlan0";
+ interface[4] += device_id;
+
+ if (nl80211_setup_ibss_interface(&nlmsg, sock, nl80211_family_id, interface, &ibss_props) < 0)
+ fail("initialize_wifi_devices: failed set up IBSS network for #%d\n", device_id);
+ }
+
+ // Wait for all devices to join the IBSS network
+ for (int device_id = 0; device_id < WIFI_INITIAL_DEVICE_COUNT; device_id++) {
+ char interface[6] = "wlan0";
+ interface[4] += device_id;
+ int ret = await_ifla_operstate(&nlmsg, interface, IF_OPER_UP);
+ if (ret < 0)
+ fail("initialize_wifi_devices: get_ifla_operstate failed for #%d, ret %d\n", device_id, ret);
+ }
+
+ close(sock);
+}
+#endif
+
#if SYZ_EXECUTOR || SYZ_NET_DEVICES
#include <arpa/inet.h>
#include <errno.h>
@@ -3386,6 +3660,9 @@ static int do_sandbox_none(void)
#if SYZ_EXECUTOR || SYZ_NET_DEVICES
initialize_netdevices();
#endif
+#if SYZ_EXECUTOR || SYZ_WIFI
+ initialize_wifi_devices();
+#endif
loop();
doexit(1);
}
@@ -3426,6 +3703,9 @@ static int do_sandbox_setuid(void)
#if SYZ_EXECUTOR || SYZ_NET_DEVICES
initialize_netdevices();
#endif
+#if SYZ_EXECUTOR || SYZ_WIFI
+ initialize_wifi_devices();
+#endif
const int nobody = 65534;
if (setgroups(0, NULL))
@@ -3486,6 +3766,9 @@ static int namespace_sandbox_proc(void* arg)
#if SYZ_EXECUTOR || SYZ_NET_DEVICES
initialize_netdevices();
#endif
+#if SYZ_EXECUTOR || SYZ_WIFI
+ initialize_wifi_devices();
+#endif
if (mkdir("./syz-tmp", 0777))
fail("mkdir(syz-tmp) failed");
@@ -4507,3 +4790,169 @@ static volatile long syz_fuse_handle_req(volatile long a0, // /dev/fuse fd.
return fuse_send_response(fd, in_hdr, out_hdr);
}
#endif
+
+#if SYZ_EXECUTOR || __NR_syz_80211_inject_frame
+#include <linux/genetlink.h>
+#include <linux/if_ether.h>
+#include <linux/nl80211.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+
+// This pseudo syscall performs 802.11 frame injection.
+//
+// Its current implementation performs the injection by means of mac80211_hwsim.
+// The procedure consists of the following steps:
+// 1. Open a netlink socket
+// 2. Register as an application responsible for wireless medium simulation by executing
+// HWSIM_CMD_REGISTER. This is a preq-requisite for the following step. After HWSIM_CMD_REGISTER
+// is executed, mac80211_hwsim stops simulating a perfect medium.
+// It is also important to note that this command registers a specific socket, not a netlink port.
+// 3. Inject a frame to the required interface by executing HWSIM_CMD_FRAME.
+// 4. Close the socket. mac80211_hwsim will detect this and return to perfect medium simulation.
+//
+// Note that we cannot (should not) open a socket, register it once and then use it for frame injection
+// throughout the lifetime of a proc. When some socket is registered, mac80211_hwsim does not broadcast
+// frames to all interfaces itself. As we do not perform this activity either, a permanently registered
+// socket will disrupt normal network operation.
+
+#define HWSIM_ATTR_RX_RATE 5
+#define HWSIM_ATTR_SIGNAL 6
+#define HWSIM_ATTR_ADDR_RECEIVER 1
+#define HWSIM_ATTR_FRAME 3
+
+#define WIFI_MAX_INJECT_LEN 2048
+
+static int hwsim_register_socket(struct nlmsg* nlmsg, int sock, int hwsim_family)
+{
+ struct genlmsghdr genlhdr;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = HWSIM_CMD_REGISTER;
+ netlink_init(nlmsg, hwsim_family, 0, &genlhdr, sizeof(genlhdr));
+ int err = netlink_send(nlmsg, sock);
+ if (err < 0) {
+ debug("hwsim_register_device failed: %s\n", strerror(-err));
+ return -1;
+ }
+ return 0;
+}
+
+static int hwsim_inject_frame(struct nlmsg* nlmsg, int sock, int hwsim_family, uint8* mac_addr, uint8* data, int len)
+{
+ struct genlmsghdr genlhdr;
+ uint32 rx_rate = WIFI_DEFAULT_RX_RATE;
+ uint32 signal = WIFI_DEFAULT_SIGNAL;
+
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = HWSIM_CMD_FRAME;
+ netlink_init(nlmsg, hwsim_family, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, HWSIM_ATTR_RX_RATE, &rx_rate, sizeof(rx_rate));
+ netlink_attr(nlmsg, HWSIM_ATTR_SIGNAL, &signal, sizeof(signal));
+ netlink_attr(nlmsg, HWSIM_ATTR_ADDR_RECEIVER, mac_addr, ETH_ALEN);
+ netlink_attr(nlmsg, HWSIM_ATTR_FRAME, data, len);
+ int err = netlink_send(nlmsg, sock);
+ if (err < 0) {
+ debug("hwsim_inject_frame failed: %s\n", strerror(-err));
+ return -1;
+ }
+ return 0;
+}
+
+static long syz_80211_inject_frame(volatile long a0, volatile long a1, volatile long a2)
+{
+ uint8* mac_addr = (uint8*)a0;
+ uint8* buf = (uint8*)a1;
+ int buf_len = (int)a2;
+ struct nlmsg tmp_msg;
+
+ if (buf_len < 0 || buf_len > WIFI_MAX_INJECT_LEN) {
+ debug("syz_80211_inject_frame: wrong buffer size %d\n", buf_len);
+ return -1;
+ }
+
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock < 0) {
+ debug("syz_80211_inject_frame: socket creation failed, errno %d\n", errno);
+ return -1;
+ }
+
+ int hwsim_family_id = netlink_query_family_id(&tmp_msg, sock, "MAC80211_HWSIM");
+ int ret = hwsim_register_socket(&tmp_msg, sock, hwsim_family_id);
+ if (ret < 0) {
+ debug("syz_80211_inject_frame: failed to register socket, ret %d\n", ret);
+ close(sock);
+ return -1;
+ }
+
+ ret = hwsim_inject_frame(&tmp_msg, sock, hwsim_family_id, mac_addr, buf, buf_len);
+ close(sock);
+ if (ret < 0) {
+ debug("syz_80211_inject_frame: failed to inject message, ret %d\n", ret);
+ return -1;
+ }
+
+ return 0;
+}
+
+#endif
+
+#if SYZ_EXECUTOR || __NR_syz_80211_join_ibss
+
+#define WIFI_MAX_SSID_LEN 32
+
+#define WIFI_JOIN_IBSS_NO_SCAN 0
+#define WIFI_JOIN_IBSS_BG_SCAN 1
+#define WIFI_JOIN_IBSS_BG_NO_SCAN 2
+
+static long syz_80211_join_ibss(volatile long a0, volatile long a1, volatile long a2, volatile long a3)
+{
+ char* interface = (char*)a0;
+ uint8* ssid = (uint8*)a1;
+ int ssid_len = (int)a2;
+ int mode = (int)a3; // This parameter essentially determines whether it will perform a scan
+
+ struct nlmsg tmp_msg;
+ uint8 bssid[ETH_ALEN] = WIFI_IBSS_BSSID;
+
+ if (ssid_len < 0 || ssid_len > WIFI_MAX_SSID_LEN) {
+ debug("syz_80211_join_ibss: invalid ssid len %d\n", ssid_len);
+ return -1;
+ }
+
+ if (mode < 0 || mode > WIFI_JOIN_IBSS_BG_NO_SCAN) {
+ debug("syz_80211_join_ibss: invalid mode %d\n", mode);
+ return -1;
+ }
+
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock < 0) {
+ debug("syz_80211_join_ibss: socket creation failed, errno %d\n", errno);
+ return -1;
+ }
+
+ int nl80211_family_id = netlink_query_family_id(&tmp_msg, sock, "nl80211");
+ struct join_ibss_props ibss_props = {
+ .wiphy_freq = WIFI_DEFAULT_FREQUENCY,
+ .wiphy_freq_fixed = (mode == WIFI_JOIN_IBSS_NO_SCAN || mode == WIFI_JOIN_IBSS_BG_NO_SCAN),
+ .mac = bssid,
+ .ssid = ssid,
+ .ssid_len = ssid_len};
+
+ int ret = nl80211_setup_ibss_interface(&tmp_msg, sock, nl80211_family_id, interface, &ibss_props);
+ close(sock);
+ if (ret < 0) {
+ debug("syz_80211_join_ibss: failed set up IBSS network for %.32s\n", interface);
+ return -1;
+ }
+
+ if (mode == WIFI_JOIN_IBSS_NO_SCAN) {
+ ret = await_ifla_operstate(&tmp_msg, interface, IF_OPER_UP);
+ if (ret < 0) {
+ debug("syz_80211_join_ibss: await_ifla_operstate failed for %.32s, ret %d\n", interface, ret);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/executor/executor.cc b/executor/executor.cc
index e63f9b224..92d25e318 100644
--- a/executor/executor.cc
+++ b/executor/executor.cc
@@ -129,6 +129,7 @@ static bool flag_cgroups;
static bool flag_close_fds;
static bool flag_devlink_pci;
static bool flag_vhci_injection;
+static bool flag_wifi;
static bool flag_collect_cover;
static bool flag_dedup_cover;
@@ -492,6 +493,7 @@ void parse_env_flags(uint64 flags)
flag_close_fds = flags & (1 << 10);
flag_devlink_pci = flags & (1 << 11);
flag_vhci_injection = flags & (1 << 12);
+ flag_wifi = flags & (1 << 13);
}
#if SYZ_EXECUTOR_USES_FORK_SERVER
diff --git a/pkg/csource/common.go b/pkg/csource/common.go
index f1e8a21b4..242190180 100644
--- a/pkg/csource/common.go
+++ b/pkg/csource/common.go
@@ -125,6 +125,7 @@ func commonDefines(p *prog.Prog, opts Options) map[string]bool {
"SYZ_HANDLE_SEGV": opts.HandleSegv,
"SYZ_REPRO": opts.Repro,
"SYZ_TRACE": opts.Trace,
+ "SYZ_WIFI": opts.Wifi,
"SYZ_EXECUTOR_USES_SHMEM": sysTarget.ExecutorUsesShmem,
"SYZ_EXECUTOR_USES_FORK_SERVER": sysTarget.ExecutorUsesForkServer,
}
diff --git a/pkg/csource/generated.go b/pkg/csource/generated.go
index 729772c8b..d02e2732e 100644
--- a/pkg/csource/generated.go
+++ b/pkg/csource/generated.go
@@ -2338,7 +2338,8 @@ static bool write_file(const char* file, const char* what, ...)
}
#endif
-#if SYZ_EXECUTOR || SYZ_NET_DEVICES || SYZ_NET_INJECTION || SYZ_DEVLINK_PCI || __NR_syz_genetlink_get_family_id
+#if SYZ_EXECUTOR || SYZ_NET_DEVICES || SYZ_NET_INJECTION || SYZ_DEVLINK_PCI || SYZ_WIFI || \
+ __NR_syz_genetlink_get_family_id || __NR_syz_80211_inject_frame || __NR_syz_80211_join_ibss
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/in.h>
@@ -2432,7 +2433,8 @@ static int netlink_send_ext(struct nlmsg* nlmsg, int sock,
return ((struct nlmsgerr*)(hdr + 1))->error;
}
-#if SYZ_EXECUTOR || SYZ_NET_DEVICES || SYZ_NET_INJECTION || SYZ_DEVLINK_PCI
+#if SYZ_EXECUTOR || SYZ_NET_DEVICES || SYZ_NET_INJECTION || SYZ_DEVLINK_PCI || SYZ_WIFI || \
+ __NR_syz_80211_join_ibss || __NR_syz_80211_inject_frame
static int netlink_send(struct nlmsg* nlmsg, int sock)
{
return netlink_send_ext(nlmsg, sock, 0, NULL);
@@ -2702,7 +2704,7 @@ static void netlink_add_neigh(struct nlmsg* nlmsg, int sock, const char* name,
#endif
#endif
-#if SYZ_EXECUTOR || SYZ_NET_DEVICES || SYZ_NET_INJECTION || SYZ_DEVLINK_PCI
+#if SYZ_EXECUTOR || SYZ_NET_DEVICES || SYZ_NET_INJECTION || SYZ_DEVLINK_PCI || SYZ_WIFI
static struct nlmsg nlmsg;
#endif
@@ -2944,6 +2946,257 @@ static void initialize_devlink_pci(void)
#endif
#endif
+#if SYZ_EXECUTOR || SYZ_WIFI || __NR_syz_80211_inject_frame || __NR_syz_80211_join_ibss
+
+#define WIFI_INITIAL_DEVICE_COUNT 2
+#define WIFI_MAC_BASE \
+ { \
+ 0x08, 0x02, 0x11, 0x00, 0x00, 0x00 \
+ }
+#define WIFI_IBSS_BSSID \
+ { \
+ 0x50, 0x50, 0x50, 0x50, 0x50, 0x50 \
+ }
+#define WIFI_IBSS_SSID \
+ { \
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 \
+ }
+#define WIFI_DEFAULT_FREQUENCY 2412
+#define WIFI_DEFAULT_SIGNAL 0
+#define WIFI_DEFAULT_RX_RATE 1
+#define HWSIM_CMD_REGISTER 1
+#define HWSIM_CMD_FRAME 2
+#define HWSIM_CMD_NEW_RADIO 4
+#define HWSIM_ATTR_SUPPORT_P2P_DEVICE 14
+#define HWSIM_ATTR_PERM_ADDR 22
+
+#endif
+
+#if SYZ_EXECUTOR || SYZ_WIFI || __NR_syz_80211_join_ibss
+#include <linux/genetlink.h>
+#include <linux/if_ether.h>
+#include <linux/nl80211.h>
+#include <linux/rtnetlink.h>
+#include <net/if.h>
+#include <stdbool.h>
+#include <sys/ioctl.h>
+#define IF_OPER_UP 6
+struct join_ibss_props {
+ int wiphy_freq;
+ bool wiphy_freq_fixed;
+ uint8* mac;
+ uint8* ssid;
+ int ssid_len;
+};
+
+static int set_interface_state(const char* interface_name, int on)
+{
+ struct ifreq ifr;
+ int sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0) {
+ debug("set_interface_state: failed to open socket, errno %d\n", errno);
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ strcpy(ifr.ifr_name, interface_name);
+ int ret = ioctl(sock, SIOCGIFFLAGS, &ifr);
+ if (ret < 0) {
+ debug("set_interface_state: failed to execute SIOCGIFFLAGS, ret %d\n", ret);
+ close(sock);
+ return -1;
+ }
+
+ if (on)
+ ifr.ifr_flags |= IFF_UP;
+ else
+ ifr.ifr_flags &= ~IFF_UP;
+
+ ret = ioctl(sock, SIOCSIFFLAGS, &ifr);
+ close(sock);
+ if (ret < 0) {
+ debug("set_interface_state: failed to execute SIOCSIFFLAGS, ret %d\n", ret);
+ return -1;
+ }
+ return 0;
+}
+
+static int nl80211_set_interface(struct nlmsg* nlmsg, int sock, int nl80211_family, uint32 ifindex, uint32 iftype)
+{
+ struct genlmsghdr genlhdr;
+
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = NL80211_CMD_SET_INTERFACE;
+ netlink_init(nlmsg, nl80211_family, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, NL80211_ATTR_IFINDEX, &ifindex, sizeof(ifindex));
+ netlink_attr(nlmsg, NL80211_ATTR_IFTYPE, &iftype, sizeof(iftype));
+ int err = netlink_send(nlmsg, sock);
+ if (err < 0) {
+ debug("nl80211_set_interface failed: %s\n", strerror(-err));
+ return -1;
+ }
+ return 0;
+}
+
+static int nl80211_join_ibss(struct nlmsg* nlmsg, int sock, int nl80211_family, uint32 ifindex, struct join_ibss_props* props)
+{
+ struct genlmsghdr genlhdr;
+
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = NL80211_CMD_JOIN_IBSS;
+ netlink_init(nlmsg, nl80211_family, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, NL80211_ATTR_IFINDEX, &ifindex, sizeof(ifindex));
+ netlink_attr(nlmsg, NL80211_ATTR_SSID, props->ssid, props->ssid_len);
+ netlink_attr(nlmsg, NL80211_ATTR_WIPHY_FREQ, &(props->wiphy_freq), sizeof(props->wiphy_freq));
+ if (props->mac)
+ netlink_attr(nlmsg, NL80211_ATTR_MAC, props->mac, ETH_ALEN);
+ if (props->wiphy_freq_fixed)
+ netlink_attr(nlmsg, NL80211_ATTR_FREQ_FIXED, NULL, 0);
+ int err = netlink_send(nlmsg, sock);
+ if (err < 0) {
+ debug("nl80211_join_ibss failed: %s\n", strerror(-err));
+ return -1;
+ }
+ return 0;
+}
+
+static int get_ifla_operstate(struct nlmsg* nlmsg, int ifindex)
+{
+ struct ifinfomsg info;
+ memset(&info, 0, sizeof(info));
+ info.ifi_family = AF_UNSPEC;
+ info.ifi_index = ifindex;
+
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1) {
+ debug("get_ifla_operstate: socket failed: %d\n", errno);
+ return -1;
+ }
+
+ netlink_init(nlmsg, RTM_GETLINK, 0, &info, sizeof(info));
+ int n;
+ int err = netlink_send_ext(nlmsg, sock, RTM_NEWLINK, &n);
+ close(sock);
+
+ if (err) {
+ debug("get_ifla_operstate: failed to query: %s\n", strerror(-err));
+ return -1;
+ }
+
+ struct rtattr* attr = IFLA_RTA(NLMSG_DATA(nlmsg->buf));
+ for (; RTA_OK(attr, n); attr = RTA_NEXT(attr, n)) {
+ if (attr->rta_type == IFLA_OPERSTATE)
+ return *((int32_t*)RTA_DATA(attr));
+ }
+
+ return -1;
+}
+
+static int await_ifla_operstate(struct nlmsg* nlmsg, char* interface, int operstate)
+{
+ int ifindex = if_nametoindex(interface);
+ while (true) {
+ usleep(1000);
+ int ret = get_ifla_operstate(nlmsg, ifindex);
+ if (ret < 0)
+ return ret;
+ if (ret == operstate)
+ return 0;
+ }
+ return 0;
+}
+
+static int nl80211_setup_ibss_interface(struct nlmsg* nlmsg, int sock, int nl80211_family_id, char* interface, struct join_ibss_props* ibss_props)
+{
+ int ifindex = if_nametoindex(interface);
+ if (ifindex == 0) {
+ debug("nl80211_setup_ibss_interface: if_nametoindex failed for %.32s, ret 0\n", interface);
+ return -1;
+ }
+
+ int ret = nl80211_set_interface(nlmsg, sock, nl80211_family_id, ifindex, NL80211_IFTYPE_ADHOC);
+ if (ret < 0) {
+ debug("nl80211_setup_ibss_interface: nl80211_set_interface failed for %.32s, ret %d\n", interface, ret);
+ return -1;
+ }
+
+ ret = set_interface_state(interface, 1);
+ if (ret < 0) {
+ debug("nl80211_setup_ibss_interface: set_interface_state failed for %.32s, ret %d\n", interface, ret);
+ return -1;
+ }
+
+ ret = nl80211_join_ibss(nlmsg, sock, nl80211_family_id, ifindex, ibss_props);
+ if (ret < 0) {
+ debug("nl80211_setup_ibss_interface: nl80211_join_ibss failed for %.32s, ret %d\n", interface, ret);
+ return -1;
+ }
+
+ return 0;
+}
+#endif
+
+#if SYZ_EXECUTOR || SYZ_WIFI
+static int hwsim80211_create_device(struct nlmsg* nlmsg, int sock, int hwsim_family, uint8 mac_addr[ETH_ALEN])
+{
+ struct genlmsghdr genlhdr;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = HWSIM_CMD_NEW_RADIO;
+ netlink_init(nlmsg, hwsim_family, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, HWSIM_ATTR_SUPPORT_P2P_DEVICE, NULL, 0);
+ netlink_attr(nlmsg, HWSIM_ATTR_PERM_ADDR, mac_addr, ETH_ALEN);
+ int err = netlink_send(nlmsg, sock);
+ if (err < 0) {
+ debug("hwsim80211_create_device failed: %s\n", strerror(-err));
+ return -1;
+ }
+ return 0;
+}
+
+static void initialize_wifi_devices(void)
+{
+
+#if SYZ_EXECUTOR
+ if (!flag_wifi)
+ return;
+#endif
+ uint8 mac_addr[6] = WIFI_MAC_BASE;
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock < 0) {
+ debug("initialize_wifi_devices: failed to create socket (%d)\n", errno);
+ return;
+ }
+
+ int hwsim_family_id = netlink_query_family_id(&nlmsg, sock, "MAC80211_HWSIM");
+ int nl80211_family_id = netlink_query_family_id(&nlmsg, sock, "nl80211");
+ uint8 ssid[] = WIFI_IBSS_SSID;
+ uint8 bssid[] = WIFI_IBSS_BSSID;
+ struct join_ibss_props ibss_props = {
+ .wiphy_freq = WIFI_DEFAULT_FREQUENCY, .wiphy_freq_fixed = true, .mac = bssid, .ssid = ssid, .ssid_len = sizeof(ssid)};
+
+ for (int device_id = 0; device_id < WIFI_INITIAL_DEVICE_COUNT; device_id++) {
+ mac_addr[5] = device_id;
+ int ret = hwsim80211_create_device(&nlmsg, sock, hwsim_family_id, mac_addr);
+ if (ret < 0)
+ fail("initialize_wifi_devices: failed to create device #%d\n", device_id);
+ char interface[6] = "wlan0";
+ interface[4] += device_id;
+
+ if (nl80211_setup_ibss_interface(&nlmsg, sock, nl80211_family_id, interface, &ibss_props) < 0)
+ fail("initialize_wifi_devices: failed set up IBSS network for #%d\n", device_id);
+ }
+ for (int device_id = 0; device_id < WIFI_INITIAL_DEVICE_COUNT; device_id++) {
+ char interface[6] = "wlan0";
+ interface[4] += device_id;
+ int ret = await_ifla_operstate(&nlmsg, interface, IF_OPER_UP);
+ if (ret < 0)
+ fail("initialize_wifi_devices: get_ifla_operstate failed for #%d, ret %d\n", device_id, ret);
+ }
+
+ close(sock);
+}
+#endif
+
#if SYZ_EXECUTOR || SYZ_NET_DEVICES
#include <arpa/inet.h>
#include <errno.h>
@@ -7629,6 +7882,9 @@ static int do_sandbox_none(void)
#if SYZ_EXECUTOR || SYZ_NET_DEVICES
initialize_netdevices();
#endif
+#if SYZ_EXECUTOR || SYZ_WIFI
+ initialize_wifi_devices();
+#endif
loop();
doexit(1);
}
@@ -7669,6 +7925,9 @@ static int do_sandbox_setuid(void)
#if SYZ_EXECUTOR || SYZ_NET_DEVICES
initialize_netdevices();
#endif
+#if SYZ_EXECUTOR || SYZ_WIFI
+ initialize_wifi_devices();
+#endif
const int nobody = 65534;
if (setgroups(0, NULL))
@@ -7716,6 +7975,9 @@ static int namespace_sandbox_proc(void* arg)
#if SYZ_EXECUTOR || SYZ_NET_DEVICES
initialize_netdevices();
#endif
+#if SYZ_EXECUTOR || SYZ_WIFI
+ initialize_wifi_devices();
+#endif
if (mkdir("./syz-tmp", 0777))
fail("mkdir(syz-tmp) failed");
@@ -9148,6 +9410,155 @@ static volatile long syz_fuse_handle_req(volatile long a0,
}
#endif
+#if SYZ_EXECUTOR || __NR_syz_80211_inject_frame
+#include <linux/genetlink.h>
+#include <linux/if_ether.h>
+#include <linux/nl80211.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+
+#define HWSIM_ATTR_RX_RATE 5
+#define HWSIM_ATTR_SIGNAL 6
+#define HWSIM_ATTR_ADDR_RECEIVER 1
+#define HWSIM_ATTR_FRAME 3
+
+#define WIFI_MAX_INJECT_LEN 2048
+
+static int hwsim_register_socket(struct nlmsg* nlmsg, int sock, int hwsim_family)
+{
+ struct genlmsghdr genlhdr;
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = HWSIM_CMD_REGISTER;
+ netlink_init(nlmsg, hwsim_family, 0, &genlhdr, sizeof(genlhdr));
+ int err = netlink_send(nlmsg, sock);
+ if (err < 0) {
+ debug("hwsim_register_device failed: %s\n", strerror(-err));
+ return -1;
+ }
+ return 0;
+}
+
+static int hwsim_inject_frame(struct nlmsg* nlmsg, int sock, int hwsim_family, uint8* mac_addr, uint8* data, int len)
+{
+ struct genlmsghdr genlhdr;
+ uint32 rx_rate = WIFI_DEFAULT_RX_RATE;
+ uint32 signal = WIFI_DEFAULT_SIGNAL;
+
+ memset(&genlhdr, 0, sizeof(genlhdr));
+ genlhdr.cmd = HWSIM_CMD_FRAME;
+ netlink_init(nlmsg, hwsim_family, 0, &genlhdr, sizeof(genlhdr));
+ netlink_attr(nlmsg, HWSIM_ATTR_RX_RATE, &rx_rate, sizeof(rx_rate));
+ netlink_attr(nlmsg, HWSIM_ATTR_SIGNAL, &signal, sizeof(signal));
+ netlink_attr(nlmsg, HWSIM_ATTR_ADDR_RECEIVER, mac_addr, ETH_ALEN);
+ netlink_attr(nlmsg, HWSIM_ATTR_FRAME, data, len);
+ int err = netlink_send(nlmsg, sock);
+ if (err < 0) {
+ debug("hwsim_inject_frame failed: %s\n", strerror(-err));
+ return -1;
+ }
+ return 0;
+}
+
+static long syz_80211_inject_frame(volatile long a0, volatile long a1, volatile long a2)
+{
+ uint8* mac_addr = (uint8*)a0;
+ uint8* buf = (uint8*)a1;
+ int buf_len = (int)a2;
+ struct nlmsg tmp_msg;
+
+ if (buf_len < 0 || buf_len > WIFI_MAX_INJECT_LEN) {
+ debug("syz_80211_inject_frame: wrong buffer size %d\n", buf_len);
+ return -1;
+ }
+
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock < 0) {
+ debug("syz_80211_inject_frame: socket creation failed, errno %d\n", errno);
+ return -1;
+ }
+
+ int hwsim_family_id = netlink_query_family_id(&tmp_msg, sock, "MAC80211_HWSIM");
+ int ret = hwsim_register_socket(&tmp_msg, sock, hwsim_family_id);
+ if (ret < 0) {
+ debug("syz_80211_inject_frame: failed to register socket, ret %d\n", ret);
+ close(sock);
+ return -1;
+ }
+
+ ret = hwsim_inject_frame(&tmp_msg, sock, hwsim_family_id, mac_addr, buf, buf_len);
+ close(sock);
+ if (ret < 0) {
+ debug("syz_80211_inject_frame: failed to inject message, ret %d\n", ret);
+ return -1;
+ }
+
+ return 0;
+}
+
+#endif
+
+#if SYZ_EXECUTOR || __NR_syz_80211_join_ibss
+
+#define WIFI_MAX_SSID_LEN 32
+
+#define WIFI_JOIN_IBSS_NO_SCAN 0
+#define WIFI_JOIN_IBSS_BG_SCAN 1
+#define WIFI_JOIN_IBSS_BG_NO_SCAN 2
+
+static long syz_80211_join_ibss(volatile long a0, volatile long a1, volatile long a2, volatile long a3)
+{
+ char* interface = (char*)a0;
+ uint8* ssid = (uint8*)a1;
+ int ssid_len = (int)a2;
+ int mode = (int)a3;
+
+ struct nlmsg tmp_msg;
+ uint8 bssid[ETH_ALEN] = WIFI_IBSS_BSSID;
+
+ if (ssid_len < 0 || ssid_len > WIFI_MAX_SSID_LEN) {
+ debug("syz_80211_join_ibss: invalid ssid len %d\n", ssid_len);
+ return -1;
+ }
+
+ if (mode < 0 || mode > WIFI_JOIN_IBSS_BG_NO_SCAN) {
+ debug("syz_80211_join_ibss: invalid mode %d\n", mode);
+ return -1;
+ }
+
+ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (sock < 0) {
+ debug("syz_80211_join_ibss: socket creation failed, errno %d\n", errno);
+ return -1;
+ }
+
+ int nl80211_family_id = netlink_query_family_id(&tmp_msg, sock, "nl80211");
+ struct join_ibss_props ibss_props = {
+ .wiphy_freq = WIFI_DEFAULT_FREQUENCY,
+ .wiphy_freq_fixed = (mode == WIFI_JOIN_IBSS_NO_SCAN || mode == WIFI_JOIN_IBSS_BG_NO_SCAN),
+ .mac = bssid,
+ .ssid = ssid,
+ .ssid_len = ssid_len};
+
+ int ret = nl80211_setup_ibss_interface(&tmp_msg, sock, nl80211_family_id, interface, &ibss_props);
+ close(sock);
+ if (ret < 0) {
+ debug("syz_80211_join_ibss: failed set up IBSS network for %.32s\n", interface);
+ return -1;
+ }
+
+ if (mode == WIFI_JOIN_IBSS_NO_SCAN) {
+ ret = await_ifla_operstate(&tmp_msg, interface, IF_OPER_UP);
+ if (ret < 0) {
+ debug("syz_80211_join_ibss: await_ifla_operstate failed for %.32s, ret %d\n", interface, ret);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+#endif
+
#elif GOOS_test
#include <stdlib.h>
diff --git a/pkg/csource/options.go b/pkg/csource/options.go
index cb1a19114..ba74eb37c 100644
--- a/pkg/csource/options.go
+++ b/pkg/csource/options.go
@@ -41,6 +41,7 @@ type Options struct {
DevlinkPCI bool `json:"devlinkpci,omitempty"`
USB bool `json:"usb,omitempty"`
VhciInjection bool `json:"vhci,omitempty"`
+ Wifi bool `json:"wifi,omitempty"`
UseTmpDir bool `json:"tmpdir,omitempty"`
HandleSegv bool `json:"segv,omitempty"`
@@ -92,6 +93,9 @@ func (opts Options) Check(OS string) error {
if opts.VhciInjection {
return errors.New("option VhciInjection without sandbox")
}
+ if opts.Wifi {
+ return errors.New("option Wifi without sandbox")
+ }
}
if opts.Sandbox == sandboxNamespace && !opts.UseTmpDir {
// This is borken and never worked.
@@ -142,6 +146,9 @@ func (opts Options) checkLinuxOnly(OS string) error {
if opts.VhciInjection {
return fmt.Errorf("option VHCI is not supported on %v", OS)
}
+ if opts.Wifi {
+ return fmt.Errorf("option Wifi is not supported on %v", OS)
+ }
if opts.Sandbox == sandboxNamespace ||
(opts.Sandbox == sandboxSetuid && !(OS == openbsd || OS == freebsd || OS == netbsd)) ||
opts.Sandbox == sandboxAndroid {
@@ -171,6 +178,7 @@ func DefaultOpts(cfg *mgrconfig.Config) Options {
CloseFDs: true,
DevlinkPCI: true,
VhciInjection: true,
+ Wifi: true,
UseTmpDir: true,
HandleSegv: true,
Repro: true,
@@ -185,6 +193,7 @@ func DefaultOpts(cfg *mgrconfig.Config) Options {
opts.DevlinkPCI = false
opts.USB = false
opts.VhciInjection = false
+ opts.Wifi = false
}
if cfg.Sandbox == "" || cfg.Sandbox == "setuid" {
opts.NetReset = false
@@ -266,6 +275,7 @@ func defaultFeatures(value bool) Features {
"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},
+ "wifi": {"setup and use mac80211_hwsim for wifi emulation", value},
}
}
diff --git a/pkg/csource/options_test.go b/pkg/csource/options_test.go
index 0786d6118..1c403ae06 100644
--- a/pkg/csource/options_test.go
+++ b/pkg/csource/options_test.go
@@ -236,6 +236,7 @@ func TestParseFeaturesFlags(t *testing.T) {
"devlink_pci": true,
"usb": true,
"vhci": true,
+ "wifi": true,
}},
{"none", "none", false, map[string]bool{
"tun": false,
@@ -247,6 +248,7 @@ func TestParseFeaturesFlags(t *testing.T) {
"devlink_pci": false,
"usb": false,
"vhci": false,
+ "wifi": false,
}},
{"all", "none", true, map[string]bool{
"tun": true,
@@ -258,6 +260,7 @@ func TestParseFeaturesFlags(t *testing.T) {
"devlink_pci": true,
"usb": true,
"vhci": true,
+ "wifi": true,
}},
{"", "none", true, map[string]bool{
"tun": false,
@@ -269,6 +272,7 @@ func TestParseFeaturesFlags(t *testing.T) {
"devlink_pci": false,
"usb": false,
"vhci": false,
+ "wifi": false,
}},
{"none", "all", true, map[string]bool{
"tun": false,
@@ -280,6 +284,7 @@ func TestParseFeaturesFlags(t *testing.T) {
"devlink_pci": false,
"usb": false,
"vhci": false,
+ "wifi": false,
}},
{"none", "", true, map[string]bool{
"tun": true,
@@ -291,6 +296,7 @@ func TestParseFeaturesFlags(t *testing.T) {
"devlink_pci": true,
"usb": true,
"vhci": true,
+ "wifi": true,
}},
{"tun,net_dev", "none", true, map[string]bool{
"tun": true,
@@ -302,6 +308,7 @@ func TestParseFeaturesFlags(t *testing.T) {
"devlink_pci": false,
"usb": false,
"vhci": false,
+ "wifi": false,
}},
{"none", "cgroups,net_dev", true, map[string]bool{
"tun": true,
@@ -313,6 +320,7 @@ func TestParseFeaturesFlags(t *testing.T) {
"devlink_pci": true,
"usb": true,
"vhci": true,
+ "wifi": true,
}},
{"close_fds", "none", true, map[string]bool{
"tun": false,
@@ -324,6 +332,7 @@ func TestParseFeaturesFlags(t *testing.T) {
"devlink_pci": false,
"usb": false,
"vhci": false,
+ "wifi": false,
}},
}
for i, test := range tests {
diff --git a/pkg/host/features.go b/pkg/host/features.go
index 07f6487a8..8b78637fb 100644
--- a/pkg/host/features.go
+++ b/pkg/host/features.go
@@ -28,6 +28,7 @@ const (
FeatureDevlinkPCI
FeatureUSBEmulation
FeatureVhciInjection
+ FeatureWifiEmulation
numFeatures
)
@@ -67,6 +68,7 @@ func Check(target *prog.Target) (*Features, error) {
FeatureDevlinkPCI: {Name: "devlink PCI setup", Reason: unsupported},
FeatureUSBEmulation: {Name: "USB emulation", Reason: unsupported},
FeatureVhciInjection: {Name: "hci packet injection", Reason: unsupported},
+ FeatureWifiEmulation: {Name: "wifi device emulation", Reason: unsupported},
}
if noHostChecks(target) {
return res, nil
diff --git a/pkg/host/features_linux.go b/pkg/host/features_linux.go
index 230022c38..5a91fc8ea 100644
--- a/pkg/host/features_linux.go
+++ b/pkg/host/features_linux.go
@@ -29,6 +29,7 @@ func init() {
checkFeature[FeatureDevlinkPCI] = checkDevlinkPCI
checkFeature[FeatureUSBEmulation] = checkUSBEmulation
checkFeature[FeatureVhciInjection] = checkVhciInjection
+ checkFeature[FeatureWifiEmulation] = checkWifiEmulation
}
func checkCoverage() string {
@@ -219,3 +220,10 @@ func checkDevlinkPCI() string {
}
return ""
}
+
+func checkWifiEmulation() string {
+ if err := osutil.IsAccessible("/sys/class/mac80211_hwsim/"); err != nil {
+ return err.Error()
+ }
+ return ""
+}
diff --git a/pkg/host/syscalls_linux.go b/pkg/host/syscalls_linux.go
index 192e88100..c66342ddf 100644
--- a/pkg/host/syscalls_linux.go
+++ b/pkg/host/syscalls_linux.go
@@ -186,6 +186,11 @@ func isVhciInjectionSupported(c *prog.Syscall, target *prog.Target, sandbox stri
return reason == "", reason
}
+func isWifiEmulationSupported(c *prog.Syscall, target *prog.Target, sandbox string) (bool, string) {
+ reason := checkWifiEmulation()
+ return reason == "", reason
+}
+
func isSyzKvmSetupCPUSupported(c *prog.Syscall, target *prog.Target, sandbox string) (bool, string) {
switch c.Name {
case "syz_kvm_setup_cpu$x86":
@@ -284,9 +289,11 @@ var syzkallSupport = map[string]func(*prog.Syscall, *prog.Target, string) (bool,
"syz_io_uring_setup": isSyzIoUringSupported,
// syz_memcpy_off is only used for io_uring descriptions, thus, enable it
// only if io_uring syscalls are enabled.
- "syz_memcpy_off": isSyzIoUringSupported,
- "syz_btf_id_by_name": isBtfVmlinuxSupported,
- "syz_fuse_handle_req": isSyzFuseSupported,
+ "syz_memcpy_off": isSyzIoUringSupported,
+ "syz_btf_id_by_name": isBtfVmlinuxSupported,
+ "syz_fuse_handle_req": isSyzFuseSupported,
+ "syz_80211_inject_frame": isWifiEmulationSupported,
+ "syz_80211_join_ibss": isWifiEmulationSupported,
}
func isSupportedSyzkall(c *prog.Syscall, target *prog.Target, sandbox string) (bool, string) {
diff --git a/pkg/ipc/ipc.go b/pkg/ipc/ipc.go
index 5ae502e5d..947c0f68d 100644
--- a/pkg/ipc/ipc.go
+++ b/pkg/ipc/ipc.go
@@ -41,6 +41,7 @@ const (
FlagEnableCloseFds // close fds after each program
FlagEnableDevlinkPCI // setup devlink PCI device
FlagEnableVhciInjection // setup and use /dev/vhci for hci packet injection
+ FlagEnableWifi // setup and use mac80211_hwsim for wifi emulation
)
// Per-exec flags for ExecOpts.Flags.
diff --git a/pkg/repro/repro.go b/pkg/repro/repro.go
index 7d22c018f..ec031c1c6 100644
--- a/pkg/repro/repro.go
+++ b/pkg/repro/repro.go
@@ -202,6 +202,9 @@ func createStartOptions(cfg *mgrconfig.Config, features *host.Features, crashTyp
if !features[host.FeatureVhciInjection].Enabled {
opts.VhciInjection = false
}
+ if !features[host.FeatureWifiEmulation].Enabled {
+ opts.Wifi = false
+ }
}
return opts
}
@@ -891,6 +894,7 @@ var cSimplifies = append(progSimplifies, []Simplify{
opts.DevlinkPCI = false
opts.USB = false
opts.VhciInjection = false
+ opts.Wifi = false
return true
},
func(opts *csource.Options) bool {
@@ -959,6 +963,13 @@ var cSimplifies = append(progSimplifies, []Simplify{
return true
},
func(opts *csource.Options) bool {
+ if !opts.Wifi {
+ return false
+ }
+ opts.Wifi = 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 54d949249..2352028fe 100644
--- a/pkg/runtest/run.go
+++ b/pkg/runtest/run.go
@@ -405,6 +405,9 @@ func (ctx *Context) createSyzTest(p *prog.Prog, sandbox string, threaded, cov bo
if ctx.Features[host.FeatureVhciInjection].Enabled {
cfg.Flags |= ipc.FlagEnableVhciInjection
}
+ if ctx.Features[host.FeatureWifiEmulation].Enabled {
+ cfg.Flags |= ipc.FlagEnableWifi
+ }
if ctx.Debug {
cfg.Flags |= ipc.FlagDebug
}
@@ -440,6 +443,9 @@ func (ctx *Context) createCTest(p *prog.Prog, sandbox string, threaded bool, tim
if ctx.Features[host.FeatureVhciInjection].Enabled {
opts.VhciInjection = true
}
+ if ctx.Features[host.FeatureWifiEmulation].Enabled {
+ opts.Wifi = true
+ }
}
src, err := csource.Write(p, opts)
if err != nil {
diff --git a/sys/linux/net_80211.txt b/sys/linux/net_80211.txt
new file mode 100644
index 000000000..0847b8cd9
--- /dev/null
+++ b/sys/linux/net_80211.txt
@@ -0,0 +1,51 @@
+# Copyright 2020 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+include <linux/ieee80211.h>
+
+type ieee80211_fixed_mac_addr[LAST] {
+ byte0 const[0x8, int8]
+ byte1 const[0x2, int8]
+ byte2 const[0x11, int8]
+ byte3 const[0x0, int8]
+ byte4 const[0x0, int8]
+ byte5 LAST
+} [packed]
+
+ieee80211_mac_addr [
+ device_a ieee80211_fixed_mac_addr[const[0x0, int8]]
+ device_b ieee80211_fixed_mac_addr[const[0x1, int8]]
+ broadcast array[const[0xff, int8], 6]
+]
+
+ieee80211_ssid [
+ random array[int8, 0:IEEE80211_MAX_SSID_LEN]
+ default_ibss_ssid array[const[0x1, int8], 6]
+] [varlen]
+
+type ieee80211_frame array[int8]
+
+# Inject an 802.11 frame.
+# mac_addr -- mac address of the device that will receive the message (actually it determines
+# the network interface that will receive this message).
+# buf -- raw 802.11 frame. It should neither include an FCS, nor leave space for it at the end of the frame.
+syz_80211_inject_frame(mac_addr ptr[in, ieee80211_mac_addr], buf ptr[in, ieee80211_frame], buf_len len[buf])
+
+# Pseudo system call that puts a specific interface into IBSS state and joins an IBSS network.
+# Although it is done for all interfaces at executor initialization and the nl80211 commands that it executes
+# are present in syzkaller descriptions of nl80211, experiments demonstrated that addition of this pseudo
+# syscall provokes a much bigger number of issues.
+# Also, this pseudo call makes it possible to put interfaces generated by sendmsg$NL80211_CMD_NEW_INTERFACE
+# into an operable state at runtime.
+syz_80211_join_ibss(interface ptr[in, string[devnames]], ssid ptr[in, ieee80211_ssid], ssid_len len[ssid], join_mode flags[join_ibss_modes])
+
+# Modes of syz_80211_join_ibss operation:
+# JOIN_IBSS_NO_SCAN -- channel scan is not performed and syz_80211_join_ibss waits until the interface reaches IF_OPER_UP
+# JOIN_IBSS_BG_SCAN -- channel scan is performed (takes ~ 9 seconds), syz_80211_join_ibss does not await IF_OPER_UP
+# JOIN_IBSS_BG_NO_SCAN -- channel scan is not performed, syz_80211_join_ibss does not await IF_OPER_UP
+
+define JOIN_IBSS_NO_SCAN 0x0
+define JOIN_IBSS_BG_SCAN 0x1
+define JOIN_IBSS_BG_NO_SCAN 0x2
+
+join_ibss_modes = JOIN_IBSS_NO_SCAN, JOIN_IBSS_BG_SCAN, JOIN_IBSS_BG_NO_SCAN
diff --git a/sys/linux/net_80211.txt.const b/sys/linux/net_80211.txt.const
new file mode 100644
index 000000000..86aaf01de
--- /dev/null
+++ b/sys/linux/net_80211.txt.const
@@ -0,0 +1,6 @@
+# Code generated by syz-sysgen. DO NOT EDIT.
+arches = 386, amd64, arm, arm64, mips64le, ppc64le, riscv64, s390x
+IEEE80211_MAX_SSID_LEN = 32
+JOIN_IBSS_BG_NO_SCAN = 2
+JOIN_IBSS_BG_SCAN = 1
+JOIN_IBSS_NO_SCAN = 0
diff --git a/sys/linux/socket.txt b/sys/linux/socket.txt
index a8595fc5e..5bc654c74 100644
--- a/sys/linux/socket.txt
+++ b/sys/linux/socket.txt
@@ -384,7 +384,7 @@ rtentry {
# Note: lapb0, bpq0 and hwsim0 are only present in init namespace.
# Note: for roseN and nrN we should use proc type, but for simplicity we currently use N=0.
# Note: netdevsim0 and netpci0 are renamed in initialize_devlink_ports()
-devnames = "", "lo", "tunl0", "gre0", "gretap0", "ip_vti0", "ip6_vti0", "sit0", "ip6tnl0", "ip6gre0", "ip6gretap0", "bond0", "dummy0", "nr0", "rose0", "erspan0", "vlan0", "bridge0", "vcan0", "team0", "syz_tun", "veth0", "veth1", "veth0_to_bridge", "veth1_to_bridge", "veth0_to_bond", "veth1_to_bond", "veth0_to_team", "veth1_to_team", "bridge_slave_0", "bridge_slave_1", "bond_slave_0", "bond_slave_1", "team_slave_0", "team_slave_1", "syzkaller0", "syzkaller1", "veth0_to_hsr", "veth1_to_hsr", "hsr0", "ip6erspan0", "vxcan1", "caif0", "batadv0", "veth0_to_batadv", "veth1_to_batadv", "batadv_slave_0", "batadv_slave_1", "netdevsim0", "netpci0", "xfrm0", "veth0_virt_wifi", "veth1_virt_wifi", "virt_wifi0", "veth0_vlan", "veth1_vlan", "vlan0", "vlan1", "macvlan0", "macvlan1", "ipvlan0", "ipvlan1", "veth0_macvtap", "veth1_macvtap", "macvtap0", "macsec0", "geneve0", "geneve1", "wg0", "wg1", "wg2"
+devnames = "", "lo", "tunl0", "gre0", "gretap0", "ip_vti0", "ip6_vti0", "sit0", "ip6tnl0", "ip6gre0", "ip6gretap0", "bond0", "dummy0", "nr0", "rose0", "erspan0", "vlan0", "bridge0", "vcan0", "team0", "syz_tun", "veth0", "veth1", "veth0_to_bridge", "veth1_to_bridge", "veth0_to_bond", "veth1_to_bond", "veth0_to_team", "veth1_to_team", "bridge_slave_0", "bridge_slave_1", "bond_slave_0", "bond_slave_1", "team_slave_0", "team_slave_1", "syzkaller0", "syzkaller1", "veth0_to_hsr", "veth1_to_hsr", "hsr0", "ip6erspan0", "vxcan1", "caif0", "batadv0", "veth0_to_batadv", "veth1_to_batadv", "batadv_slave_0", "batadv_slave_1", "netdevsim0", "netpci0", "xfrm0", "veth0_virt_wifi", "veth1_virt_wifi", "virt_wifi0", "veth0_vlan", "veth1_vlan", "vlan0", "vlan1", "macvlan0", "macvlan1", "ipvlan0", "ipvlan1", "veth0_macvtap", "veth1_macvtap", "macvtap0", "macsec0", "geneve0", "geneve1", "wg0", "wg1", "wg2", "wlan0", "wlan1"
type devname string[devnames, IFNAMSIZ]
diff --git a/sys/linux/test/80211_ibss b/sys/linux/test/80211_ibss
new file mode 100644
index 000000000..0bea2f5f8
--- /dev/null
+++ b/sys/linux/test/80211_ibss
@@ -0,0 +1,9 @@
+# requires: -sandbox=namespace
+
+# Join IBSSS network
+
+syz_80211_join_ibss(&AUTO='wlan0\x00', &AUTO=@default_ibss_ssid, 0x6, 0x0)
+
+# Inject an arbitrary packet
+
+syz_80211_inject_frame(&AUTO=@device_a, &AUTO="00112233445566778899", 0xa) \ No newline at end of file
diff --git a/syz-fuzzer/fuzzer.go b/syz-fuzzer/fuzzer.go
index ae9a5af59..16acd7a20 100644
--- a/syz-fuzzer/fuzzer.go
+++ b/syz-fuzzer/fuzzer.go
@@ -121,6 +121,9 @@ func createIPCConfig(features *host.Features, config *ipc.Config) {
if features[host.FeatureVhciInjection].Enabled {
config.Flags |= ipc.FlagEnableVhciInjection
}
+ if features[host.FeatureWifiEmulation].Enabled {
+ config.Flags |= ipc.FlagEnableWifi
+ }
}
// nolint: funlen
diff --git a/tools/syz-execprog/execprog.go b/tools/syz-execprog/execprog.go
index a5ef8fbc4..23fd881cd 100644
--- a/tools/syz-execprog/execprog.go
+++ b/tools/syz-execprog/execprog.go
@@ -332,5 +332,8 @@ func createConfig(target *prog.Target,
if featuresFlags["vhci"].Enabled && features[host.FeatureVhciInjection].Enabled {
config.Flags |= ipc.FlagEnableVhciInjection
}
+ if featuresFlags["wifi"].Enabled && features[host.FeatureWifiEmulation].Enabled {
+ config.Flags |= ipc.FlagEnableWifi
+ }
return config, execOpts
}
diff --git a/tools/syz-prog2c/prog2c.go b/tools/syz-prog2c/prog2c.go
index 4c04487ff..2f8c6c62a 100644
--- a/tools/syz-prog2c/prog2c.go
+++ b/tools/syz-prog2c/prog2c.go
@@ -92,6 +92,7 @@ func main() {
DevlinkPCI: features["devlink_pci"].Enabled,
USB: features["usb"].Enabled,
VhciInjection: features["vhci"].Enabled,
+ Wifi: features["wifi"].Enabled,
UseTmpDir: *flagUseTmpDir,
HandleSegv: *flagHandleSegv,
Repro: *flagRepro,
diff --git a/tools/syz-reprolist/reprolist.go b/tools/syz-reprolist/reprolist.go
index e4c26011f..95c099ba9 100644
--- a/tools/syz-reprolist/reprolist.go
+++ b/tools/syz-reprolist/reprolist.go
@@ -153,6 +153,8 @@ func createCRepro(bug *dashapi.LoadBugResp) error {
return err
}
+// Although liter complains about this function, it does not seem complex.
+// nolint: gocyclo
func createProg2CArgs(bug *dashapi.LoadBugResp, opts csource.Options, file string) []string {
haveEnableFlag := containsCommit("dfd609eca1871f01757d6b04b19fc273c87c14e5")
haveRepeatFlag := containsCommit("b25fc7b83119e8dca728a199fd92e24dd4c33fa4")
@@ -232,6 +234,10 @@ func createProg2CArgs(bug *dashapi.LoadBugResp, opts csource.Options, file strin
enable = append(enable, "vhci")
flags = append(flags, "-vhci")
}
+ if opts.Wifi {
+ enable = append(enable, "wifi")
+ flags = append(flags, "-wifi")
+ }
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 9ec0229f4..21926fe89 100644
--- a/tools/syz-stress/stress.go
+++ b/tools/syz-stress/stress.go
@@ -165,6 +165,9 @@ func createIPCConfig(target *prog.Target, features *host.Features, featuresFlags
if featuresFlags["vhci"].Enabled && features[host.FeatureVhciInjection].Enabled {
config.Flags |= ipc.FlagEnableVhciInjection
}
+ if featuresFlags["wifi"].Enabled && features[host.FeatureWifiEmulation].Enabled {
+ config.Flags |= ipc.FlagEnableWifi
+ }
return config, execOpts, nil
}