all: integrate with mac80211_hwsim

Two virtual wireless devices are instantiated during network devices
initialization.

A new flag (-wifi) is added that controls whether these virtual wifi
devices are instantiated and configured during proc initialization.

Also, two new pseudo syscalls are added:
1. syz_80211_inject_frame(mac_addr, packet, packet_len) -- injects an
arbitrary packet into the wireless stack. It is injected as if it
originated from the device identitied by mac_addr.
2. syz_80211_join_ibss(interface_name, ssid, ssid_len, mode) --
puts a specific network interface into IBSS state and joins an IBSS
network.

Arguments of syz_80211_join_ibss:
1) interface_name -- null-terminated string that identifies
a wireless interface
2) ssid, ssid_len -- SSID of an IBSS network to join to
3) mode -- mode of syz_80211_join_ibss operation (see below)

Modes of operation:
JOIN_IBSS_NO_SCAN (0x0) -- channel scan is not performed and
syz_80211_join_ibss waits until the interface reaches IF_OPER_UP.
JOIN_IBSS_BG_SCAN (0x1) -- channel scan is performed (takes ~ 9
seconds), syz_80211_join_ibss does not await IF_OPER_UP.
JOIN_IBSS_BG_NO_SCAN (0x2) -- channel scan is not performed,
syz_80211_join_ibss does not await IF_OPER_UP.

Local testing ensured that these syscalls are indeed able to set up an
operating network and inject packets into mac80211.
This commit is contained in:
Aleksandr Nogikh 2020-09-08 08:25:27 +03:00 committed by Dmitry Vyukov
parent 1125444eb8
commit 9133037195
21 changed files with 1009 additions and 10 deletions

View File

@ -107,7 +107,8 @@ static bool write_file(const char* file, const char* what, ...)
} }
#endif #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 <arpa/inet.h>
#include <net/if.h> #include <net/if.h>
#include <netinet/in.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; 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) static int netlink_send(struct nlmsg* nlmsg, int sock)
{ {
return netlink_send_ext(nlmsg, sock, 0, NULL); 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
#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; static struct nlmsg nlmsg;
#endif #endif
@ -728,6 +730,278 @@ static void initialize_devlink_pci(void)
#endif #endif
#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 #if SYZ_EXECUTOR || SYZ_NET_DEVICES
#include <arpa/inet.h> #include <arpa/inet.h>
#include <errno.h> #include <errno.h>
@ -3385,6 +3659,9 @@ static int do_sandbox_none(void)
#endif #endif
#if SYZ_EXECUTOR || SYZ_NET_DEVICES #if SYZ_EXECUTOR || SYZ_NET_DEVICES
initialize_netdevices(); initialize_netdevices();
#endif
#if SYZ_EXECUTOR || SYZ_WIFI
initialize_wifi_devices();
#endif #endif
loop(); loop();
doexit(1); doexit(1);
@ -3426,6 +3703,9 @@ static int do_sandbox_setuid(void)
#if SYZ_EXECUTOR || SYZ_NET_DEVICES #if SYZ_EXECUTOR || SYZ_NET_DEVICES
initialize_netdevices(); initialize_netdevices();
#endif #endif
#if SYZ_EXECUTOR || SYZ_WIFI
initialize_wifi_devices();
#endif
const int nobody = 65534; const int nobody = 65534;
if (setgroups(0, NULL)) if (setgroups(0, NULL))
@ -3486,6 +3766,9 @@ static int namespace_sandbox_proc(void* arg)
#if SYZ_EXECUTOR || SYZ_NET_DEVICES #if SYZ_EXECUTOR || SYZ_NET_DEVICES
initialize_netdevices(); initialize_netdevices();
#endif #endif
#if SYZ_EXECUTOR || SYZ_WIFI
initialize_wifi_devices();
#endif
if (mkdir("./syz-tmp", 0777)) if (mkdir("./syz-tmp", 0777))
fail("mkdir(syz-tmp) failed"); 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); return fuse_send_response(fd, in_hdr, out_hdr);
} }
#endif #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

View File

@ -129,6 +129,7 @@ static bool flag_cgroups;
static bool flag_close_fds; static bool flag_close_fds;
static bool flag_devlink_pci; static bool flag_devlink_pci;
static bool flag_vhci_injection; static bool flag_vhci_injection;
static bool flag_wifi;
static bool flag_collect_cover; static bool flag_collect_cover;
static bool flag_dedup_cover; static bool flag_dedup_cover;
@ -492,6 +493,7 @@ void parse_env_flags(uint64 flags)
flag_close_fds = flags & (1 << 10); flag_close_fds = flags & (1 << 10);
flag_devlink_pci = flags & (1 << 11); flag_devlink_pci = flags & (1 << 11);
flag_vhci_injection = flags & (1 << 12); flag_vhci_injection = flags & (1 << 12);
flag_wifi = flags & (1 << 13);
} }
#if SYZ_EXECUTOR_USES_FORK_SERVER #if SYZ_EXECUTOR_USES_FORK_SERVER

View File

@ -125,6 +125,7 @@ func commonDefines(p *prog.Prog, opts Options) map[string]bool {
"SYZ_HANDLE_SEGV": opts.HandleSegv, "SYZ_HANDLE_SEGV": opts.HandleSegv,
"SYZ_REPRO": opts.Repro, "SYZ_REPRO": opts.Repro,
"SYZ_TRACE": opts.Trace, "SYZ_TRACE": opts.Trace,
"SYZ_WIFI": opts.Wifi,
"SYZ_EXECUTOR_USES_SHMEM": sysTarget.ExecutorUsesShmem, "SYZ_EXECUTOR_USES_SHMEM": sysTarget.ExecutorUsesShmem,
"SYZ_EXECUTOR_USES_FORK_SERVER": sysTarget.ExecutorUsesForkServer, "SYZ_EXECUTOR_USES_FORK_SERVER": sysTarget.ExecutorUsesForkServer,
} }

View File

@ -2338,7 +2338,8 @@ static bool write_file(const char* file, const char* what, ...)
} }
#endif #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 <arpa/inet.h>
#include <net/if.h> #include <net/if.h>
#include <netinet/in.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; 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) static int netlink_send(struct nlmsg* nlmsg, int sock)
{ {
return netlink_send_ext(nlmsg, sock, 0, NULL); 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
#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; static struct nlmsg nlmsg;
#endif #endif
@ -2944,6 +2946,257 @@ static void initialize_devlink_pci(void)
#endif #endif
#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 #if SYZ_EXECUTOR || SYZ_NET_DEVICES
#include <arpa/inet.h> #include <arpa/inet.h>
#include <errno.h> #include <errno.h>
@ -7628,6 +7881,9 @@ static int do_sandbox_none(void)
#endif #endif
#if SYZ_EXECUTOR || SYZ_NET_DEVICES #if SYZ_EXECUTOR || SYZ_NET_DEVICES
initialize_netdevices(); initialize_netdevices();
#endif
#if SYZ_EXECUTOR || SYZ_WIFI
initialize_wifi_devices();
#endif #endif
loop(); loop();
doexit(1); doexit(1);
@ -7669,6 +7925,9 @@ static int do_sandbox_setuid(void)
#if SYZ_EXECUTOR || SYZ_NET_DEVICES #if SYZ_EXECUTOR || SYZ_NET_DEVICES
initialize_netdevices(); initialize_netdevices();
#endif #endif
#if SYZ_EXECUTOR || SYZ_WIFI
initialize_wifi_devices();
#endif
const int nobody = 65534; const int nobody = 65534;
if (setgroups(0, NULL)) if (setgroups(0, NULL))
@ -7716,6 +7975,9 @@ static int namespace_sandbox_proc(void* arg)
#if SYZ_EXECUTOR || SYZ_NET_DEVICES #if SYZ_EXECUTOR || SYZ_NET_DEVICES
initialize_netdevices(); initialize_netdevices();
#endif #endif
#if SYZ_EXECUTOR || SYZ_WIFI
initialize_wifi_devices();
#endif
if (mkdir("./syz-tmp", 0777)) if (mkdir("./syz-tmp", 0777))
fail("mkdir(syz-tmp) failed"); fail("mkdir(syz-tmp) failed");
@ -9148,6 +9410,155 @@ static volatile long syz_fuse_handle_req(volatile long a0,
} }
#endif #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 #elif GOOS_test
#include <stdlib.h> #include <stdlib.h>

View File

@ -41,6 +41,7 @@ type Options struct {
DevlinkPCI bool `json:"devlinkpci,omitempty"` DevlinkPCI bool `json:"devlinkpci,omitempty"`
USB bool `json:"usb,omitempty"` USB bool `json:"usb,omitempty"`
VhciInjection bool `json:"vhci,omitempty"` VhciInjection bool `json:"vhci,omitempty"`
Wifi bool `json:"wifi,omitempty"`
UseTmpDir bool `json:"tmpdir,omitempty"` UseTmpDir bool `json:"tmpdir,omitempty"`
HandleSegv bool `json:"segv,omitempty"` HandleSegv bool `json:"segv,omitempty"`
@ -92,6 +93,9 @@ func (opts Options) Check(OS string) error {
if opts.VhciInjection { if opts.VhciInjection {
return errors.New("option VhciInjection without sandbox") return errors.New("option VhciInjection without sandbox")
} }
if opts.Wifi {
return errors.New("option Wifi without sandbox")
}
} }
if opts.Sandbox == sandboxNamespace && !opts.UseTmpDir { if opts.Sandbox == sandboxNamespace && !opts.UseTmpDir {
// This is borken and never worked. // This is borken and never worked.
@ -142,6 +146,9 @@ func (opts Options) checkLinuxOnly(OS string) error {
if opts.VhciInjection { if opts.VhciInjection {
return fmt.Errorf("option VHCI is not supported on %v", OS) 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 || if opts.Sandbox == sandboxNamespace ||
(opts.Sandbox == sandboxSetuid && !(OS == openbsd || OS == freebsd || OS == netbsd)) || (opts.Sandbox == sandboxSetuid && !(OS == openbsd || OS == freebsd || OS == netbsd)) ||
opts.Sandbox == sandboxAndroid { opts.Sandbox == sandboxAndroid {
@ -171,6 +178,7 @@ func DefaultOpts(cfg *mgrconfig.Config) Options {
CloseFDs: true, CloseFDs: true,
DevlinkPCI: true, DevlinkPCI: true,
VhciInjection: true, VhciInjection: true,
Wifi: true,
UseTmpDir: true, UseTmpDir: true,
HandleSegv: true, HandleSegv: true,
Repro: true, Repro: true,
@ -185,6 +193,7 @@ func DefaultOpts(cfg *mgrconfig.Config) Options {
opts.DevlinkPCI = false opts.DevlinkPCI = false
opts.USB = false opts.USB = false
opts.VhciInjection = false opts.VhciInjection = false
opts.Wifi = false
} }
if cfg.Sandbox == "" || cfg.Sandbox == "setuid" { if cfg.Sandbox == "" || cfg.Sandbox == "setuid" {
opts.NetReset = false opts.NetReset = false
@ -266,6 +275,7 @@ func defaultFeatures(value bool) Features {
"devlink_pci": {"setup devlink PCI device", value}, "devlink_pci": {"setup devlink PCI device", value},
"usb": {"setup and use /dev/raw-gadget for USB emulation", value}, "usb": {"setup and use /dev/raw-gadget for USB emulation", value},
"vhci": {"setup and use /dev/vhci for hci packet injection", value}, "vhci": {"setup and use /dev/vhci for hci packet injection", value},
"wifi": {"setup and use mac80211_hwsim for wifi emulation", value},
} }
} }

View File

@ -236,6 +236,7 @@ func TestParseFeaturesFlags(t *testing.T) {
"devlink_pci": true, "devlink_pci": true,
"usb": true, "usb": true,
"vhci": true, "vhci": true,
"wifi": true,
}}, }},
{"none", "none", false, map[string]bool{ {"none", "none", false, map[string]bool{
"tun": false, "tun": false,
@ -247,6 +248,7 @@ func TestParseFeaturesFlags(t *testing.T) {
"devlink_pci": false, "devlink_pci": false,
"usb": false, "usb": false,
"vhci": false, "vhci": false,
"wifi": false,
}}, }},
{"all", "none", true, map[string]bool{ {"all", "none", true, map[string]bool{
"tun": true, "tun": true,
@ -258,6 +260,7 @@ func TestParseFeaturesFlags(t *testing.T) {
"devlink_pci": true, "devlink_pci": true,
"usb": true, "usb": true,
"vhci": true, "vhci": true,
"wifi": true,
}}, }},
{"", "none", true, map[string]bool{ {"", "none", true, map[string]bool{
"tun": false, "tun": false,
@ -269,6 +272,7 @@ func TestParseFeaturesFlags(t *testing.T) {
"devlink_pci": false, "devlink_pci": false,
"usb": false, "usb": false,
"vhci": false, "vhci": false,
"wifi": false,
}}, }},
{"none", "all", true, map[string]bool{ {"none", "all", true, map[string]bool{
"tun": false, "tun": false,
@ -280,6 +284,7 @@ func TestParseFeaturesFlags(t *testing.T) {
"devlink_pci": false, "devlink_pci": false,
"usb": false, "usb": false,
"vhci": false, "vhci": false,
"wifi": false,
}}, }},
{"none", "", true, map[string]bool{ {"none", "", true, map[string]bool{
"tun": true, "tun": true,
@ -291,6 +296,7 @@ func TestParseFeaturesFlags(t *testing.T) {
"devlink_pci": true, "devlink_pci": true,
"usb": true, "usb": true,
"vhci": true, "vhci": true,
"wifi": true,
}}, }},
{"tun,net_dev", "none", true, map[string]bool{ {"tun,net_dev", "none", true, map[string]bool{
"tun": true, "tun": true,
@ -302,6 +308,7 @@ func TestParseFeaturesFlags(t *testing.T) {
"devlink_pci": false, "devlink_pci": false,
"usb": false, "usb": false,
"vhci": false, "vhci": false,
"wifi": false,
}}, }},
{"none", "cgroups,net_dev", true, map[string]bool{ {"none", "cgroups,net_dev", true, map[string]bool{
"tun": true, "tun": true,
@ -313,6 +320,7 @@ func TestParseFeaturesFlags(t *testing.T) {
"devlink_pci": true, "devlink_pci": true,
"usb": true, "usb": true,
"vhci": true, "vhci": true,
"wifi": true,
}}, }},
{"close_fds", "none", true, map[string]bool{ {"close_fds", "none", true, map[string]bool{
"tun": false, "tun": false,
@ -324,6 +332,7 @@ func TestParseFeaturesFlags(t *testing.T) {
"devlink_pci": false, "devlink_pci": false,
"usb": false, "usb": false,
"vhci": false, "vhci": false,
"wifi": false,
}}, }},
} }
for i, test := range tests { for i, test := range tests {

View File

@ -28,6 +28,7 @@ const (
FeatureDevlinkPCI FeatureDevlinkPCI
FeatureUSBEmulation FeatureUSBEmulation
FeatureVhciInjection FeatureVhciInjection
FeatureWifiEmulation
numFeatures numFeatures
) )
@ -67,6 +68,7 @@ func Check(target *prog.Target) (*Features, error) {
FeatureDevlinkPCI: {Name: "devlink PCI setup", Reason: unsupported}, FeatureDevlinkPCI: {Name: "devlink PCI setup", Reason: unsupported},
FeatureUSBEmulation: {Name: "USB emulation", Reason: unsupported}, FeatureUSBEmulation: {Name: "USB emulation", Reason: unsupported},
FeatureVhciInjection: {Name: "hci packet injection", Reason: unsupported}, FeatureVhciInjection: {Name: "hci packet injection", Reason: unsupported},
FeatureWifiEmulation: {Name: "wifi device emulation", Reason: unsupported},
} }
if noHostChecks(target) { if noHostChecks(target) {
return res, nil return res, nil

View File

@ -29,6 +29,7 @@ func init() {
checkFeature[FeatureDevlinkPCI] = checkDevlinkPCI checkFeature[FeatureDevlinkPCI] = checkDevlinkPCI
checkFeature[FeatureUSBEmulation] = checkUSBEmulation checkFeature[FeatureUSBEmulation] = checkUSBEmulation
checkFeature[FeatureVhciInjection] = checkVhciInjection checkFeature[FeatureVhciInjection] = checkVhciInjection
checkFeature[FeatureWifiEmulation] = checkWifiEmulation
} }
func checkCoverage() string { func checkCoverage() string {
@ -219,3 +220,10 @@ func checkDevlinkPCI() string {
} }
return "" return ""
} }
func checkWifiEmulation() string {
if err := osutil.IsAccessible("/sys/class/mac80211_hwsim/"); err != nil {
return err.Error()
}
return ""
}

View File

@ -186,6 +186,11 @@ func isVhciInjectionSupported(c *prog.Syscall, target *prog.Target, sandbox stri
return reason == "", reason 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) { func isSyzKvmSetupCPUSupported(c *prog.Syscall, target *prog.Target, sandbox string) (bool, string) {
switch c.Name { switch c.Name {
case "syz_kvm_setup_cpu$x86": 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_io_uring_setup": isSyzIoUringSupported,
// syz_memcpy_off is only used for io_uring descriptions, thus, enable it // syz_memcpy_off is only used for io_uring descriptions, thus, enable it
// only if io_uring syscalls are enabled. // only if io_uring syscalls are enabled.
"syz_memcpy_off": isSyzIoUringSupported, "syz_memcpy_off": isSyzIoUringSupported,
"syz_btf_id_by_name": isBtfVmlinuxSupported, "syz_btf_id_by_name": isBtfVmlinuxSupported,
"syz_fuse_handle_req": isSyzFuseSupported, "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) { func isSupportedSyzkall(c *prog.Syscall, target *prog.Target, sandbox string) (bool, string) {

View File

@ -41,6 +41,7 @@ const (
FlagEnableCloseFds // close fds after each program FlagEnableCloseFds // close fds after each program
FlagEnableDevlinkPCI // setup devlink PCI device FlagEnableDevlinkPCI // setup devlink PCI device
FlagEnableVhciInjection // setup and use /dev/vhci for hci packet injection 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. // Per-exec flags for ExecOpts.Flags.

View File

@ -202,6 +202,9 @@ func createStartOptions(cfg *mgrconfig.Config, features *host.Features, crashTyp
if !features[host.FeatureVhciInjection].Enabled { if !features[host.FeatureVhciInjection].Enabled {
opts.VhciInjection = false opts.VhciInjection = false
} }
if !features[host.FeatureWifiEmulation].Enabled {
opts.Wifi = false
}
} }
return opts return opts
} }
@ -891,6 +894,7 @@ var cSimplifies = append(progSimplifies, []Simplify{
opts.DevlinkPCI = false opts.DevlinkPCI = false
opts.USB = false opts.USB = false
opts.VhciInjection = false opts.VhciInjection = false
opts.Wifi = false
return true return true
}, },
func(opts *csource.Options) bool { func(opts *csource.Options) bool {
@ -958,6 +962,13 @@ var cSimplifies = append(progSimplifies, []Simplify{
opts.VhciInjection = false opts.VhciInjection = false
return true return true
}, },
func(opts *csource.Options) bool {
if !opts.Wifi {
return false
}
opts.Wifi = false
return true
},
func(opts *csource.Options) bool { func(opts *csource.Options) bool {
if !opts.UseTmpDir || opts.Sandbox == "namespace" || opts.Cgroups { if !opts.UseTmpDir || opts.Sandbox == "namespace" || opts.Cgroups {
return false return false

View File

@ -405,6 +405,9 @@ func (ctx *Context) createSyzTest(p *prog.Prog, sandbox string, threaded, cov bo
if ctx.Features[host.FeatureVhciInjection].Enabled { if ctx.Features[host.FeatureVhciInjection].Enabled {
cfg.Flags |= ipc.FlagEnableVhciInjection cfg.Flags |= ipc.FlagEnableVhciInjection
} }
if ctx.Features[host.FeatureWifiEmulation].Enabled {
cfg.Flags |= ipc.FlagEnableWifi
}
if ctx.Debug { if ctx.Debug {
cfg.Flags |= ipc.FlagDebug 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 { if ctx.Features[host.FeatureVhciInjection].Enabled {
opts.VhciInjection = true opts.VhciInjection = true
} }
if ctx.Features[host.FeatureWifiEmulation].Enabled {
opts.Wifi = true
}
} }
src, err := csource.Write(p, opts) src, err := csource.Write(p, opts)
if err != nil { if err != nil {

51
sys/linux/net_80211.txt Normal file
View File

@ -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

View File

@ -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

View File

@ -384,7 +384,7 @@ rtentry {
# Note: lapb0, bpq0 and hwsim0 are only present in init namespace. # 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: 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() # 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] type devname string[devnames, IFNAMSIZ]

View File

@ -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)

View File

@ -121,6 +121,9 @@ func createIPCConfig(features *host.Features, config *ipc.Config) {
if features[host.FeatureVhciInjection].Enabled { if features[host.FeatureVhciInjection].Enabled {
config.Flags |= ipc.FlagEnableVhciInjection config.Flags |= ipc.FlagEnableVhciInjection
} }
if features[host.FeatureWifiEmulation].Enabled {
config.Flags |= ipc.FlagEnableWifi
}
} }
// nolint: funlen // nolint: funlen

View File

@ -332,5 +332,8 @@ func createConfig(target *prog.Target,
if featuresFlags["vhci"].Enabled && features[host.FeatureVhciInjection].Enabled { if featuresFlags["vhci"].Enabled && features[host.FeatureVhciInjection].Enabled {
config.Flags |= ipc.FlagEnableVhciInjection config.Flags |= ipc.FlagEnableVhciInjection
} }
if featuresFlags["wifi"].Enabled && features[host.FeatureWifiEmulation].Enabled {
config.Flags |= ipc.FlagEnableWifi
}
return config, execOpts return config, execOpts
} }

View File

@ -92,6 +92,7 @@ func main() {
DevlinkPCI: features["devlink_pci"].Enabled, DevlinkPCI: features["devlink_pci"].Enabled,
USB: features["usb"].Enabled, USB: features["usb"].Enabled,
VhciInjection: features["vhci"].Enabled, VhciInjection: features["vhci"].Enabled,
Wifi: features["wifi"].Enabled,
UseTmpDir: *flagUseTmpDir, UseTmpDir: *flagUseTmpDir,
HandleSegv: *flagHandleSegv, HandleSegv: *flagHandleSegv,
Repro: *flagRepro, Repro: *flagRepro,

View File

@ -153,6 +153,8 @@ func createCRepro(bug *dashapi.LoadBugResp) error {
return err 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 { func createProg2CArgs(bug *dashapi.LoadBugResp, opts csource.Options, file string) []string {
haveEnableFlag := containsCommit("dfd609eca1871f01757d6b04b19fc273c87c14e5") haveEnableFlag := containsCommit("dfd609eca1871f01757d6b04b19fc273c87c14e5")
haveRepeatFlag := containsCommit("b25fc7b83119e8dca728a199fd92e24dd4c33fa4") haveRepeatFlag := containsCommit("b25fc7b83119e8dca728a199fd92e24dd4c33fa4")
@ -232,6 +234,10 @@ func createProg2CArgs(bug *dashapi.LoadBugResp, opts csource.Options, file strin
enable = append(enable, "vhci") enable = append(enable, "vhci")
flags = append(flags, "-vhci") flags = append(flags, "-vhci")
} }
if opts.Wifi {
enable = append(enable, "wifi")
flags = append(flags, "-wifi")
}
if !haveEnableFlag { if !haveEnableFlag {
args = append(args, flags...) args = append(args, flags...)
} else if len(enable) != 0 { } else if len(enable) != 0 {

View File

@ -165,6 +165,9 @@ func createIPCConfig(target *prog.Target, features *host.Features, featuresFlags
if featuresFlags["vhci"].Enabled && features[host.FeatureVhciInjection].Enabled { if featuresFlags["vhci"].Enabled && features[host.FeatureVhciInjection].Enabled {
config.Flags |= ipc.FlagEnableVhciInjection config.Flags |= ipc.FlagEnableVhciInjection
} }
if featuresFlags["wifi"].Enabled && features[host.FeatureWifiEmulation].Enabled {
config.Flags |= ipc.FlagEnableWifi
}
return config, execOpts, nil return config, execOpts, nil
} }