aboutsummaryrefslogtreecommitdiffstats
path: root/executor
diff options
context:
space:
mode:
Diffstat (limited to 'executor')
-rw-r--r--executor/common_linux.h293
-rw-r--r--executor/executor.cc2
2 files changed, 219 insertions, 76 deletions
diff --git a/executor/common_linux.h b/executor/common_linux.h
index 4c525760a..d3f4b6ea1 100644
--- a/executor/common_linux.h
+++ b/executor/common_linux.h
@@ -109,7 +109,7 @@ static bool write_file(const char* file, const char* what, ...)
#endif
#if SYZ_EXECUTOR || SYZ_NET_DEVICES || SYZ_NET_INJECTION || SYZ_DEVLINK_PCI || SYZ_WIFI || SYZ_802154 || \
- __NR_syz_genetlink_get_family_id || __NR_syz_80211_inject_frame || __NR_syz_80211_join_ibss
+ __NR_syz_genetlink_get_family_id || __NR_syz_80211_inject_frame || __NR_syz_80211_join_ibss || SYZ_NIC_VF
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/in.h>
@@ -171,6 +171,87 @@ static void netlink_done(struct nlmsg* nlmsg)
struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
attr->nla_len = nlmsg->pos - (char*)attr;
}
+
+#if SYZ_EXECUTOR || SYZ_NIC_VF
+#include <ifaddrs.h>
+#include <linux/ethtool.h>
+#include <linux/sockios.h>
+#include <sys/ioctl.h>
+
+struct vf_intf {
+ char pass_thru_intf[IFNAMSIZ];
+ int ppid; // used by Child
+};
+
+static struct vf_intf vf_intf;
+
+static void find_vf_interface(void)
+{
+#if SYZ_EXECUTOR
+ if (!flag_nic_vf)
+ return;
+#endif
+ struct ifaddrs* addresses = NULL;
+ int pid = getpid();
+ int ret = 0;
+
+ memset(&vf_intf, 0, sizeof(struct vf_intf));
+
+ debug("Checking for VF pass-thru interface.\n");
+ if (getifaddrs(&addresses) == -1) {
+ debug("%s: getifaddrs() failed.\n", __func__);
+ return;
+ }
+
+ int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+
+ if (fd < 0) {
+ debug("%s: socket() failed.\n", __func__);
+ return;
+ }
+ struct ifreq ifr;
+ struct ethtool_drvinfo drvinfo;
+ struct ifaddrs* address = addresses;
+
+ while (address) {
+ debug("ifa_name: %s\n", address->ifa_name);
+ memset(&ifr, 0, sizeof(struct ifreq));
+ strcpy(ifr.ifr_name, address->ifa_name);
+ memset(&drvinfo, 0, sizeof(struct ethtool_drvinfo));
+ drvinfo.cmd = ETHTOOL_GDRVINFO;
+ ifr.ifr_data = (caddr_t)&drvinfo;
+ ret = ioctl(fd, SIOCETHTOOL, &ifr);
+
+ if (ret < 0) {
+ debug("%s: ioctl() failed.\n", __func__);
+ } else if (strlen(drvinfo.bus_info)) {
+ debug("bus_info: %s, strlen(drvinfo.bus_info)=%zu\n",
+ drvinfo.bus_info, strlen(drvinfo.bus_info));
+ if (strcmp(drvinfo.bus_info, "0000:00:11.0") == 0) {
+ if (strlen(address->ifa_name) < IFNAMSIZ) {
+ strncpy(vf_intf.pass_thru_intf,
+ address->ifa_name, IFNAMSIZ);
+ vf_intf.ppid = pid;
+ } else {
+ debug("%s: %d strlen(%s) >= IFNAMSIZ.\n",
+ __func__, pid, address->ifa_name);
+ }
+ break;
+ }
+ }
+ address = address->ifa_next;
+ }
+ freeifaddrs(addresses);
+ if (!vf_intf.ppid) {
+ memset(&vf_intf, 0, sizeof(struct vf_intf));
+ debug("%s: %d could not find VF pass-thru interface.\n", __func__, pid);
+ return;
+ }
+ debug("%s: %d found VF pass-thru interface %s\n",
+ __func__, pid, vf_intf.pass_thru_intf);
+}
+#endif // SYZ_NIC_VF
+
#endif
static int netlink_send_ext(struct nlmsg* nlmsg, int sock,
@@ -1345,6 +1426,52 @@ error:
close(sock);
}
+#if SYZ_EXECUTOR || SYZ_NIC_VF
+static int runcmdline(char* cmdline)
+{
+ debug("%s\n", cmdline);
+ int ret = system(cmdline);
+ if (ret) {
+ debug("FAIL: %s\n", cmdline);
+ }
+ return ret;
+}
+
+static void netlink_nicvf_setup(void)
+{
+ char cmdline[256];
+
+#if SYZ_EXECUTOR
+ if (!flag_nic_vf)
+ return;
+#endif
+ if (!vf_intf.ppid)
+ return;
+
+ debug("ppid = %d, vf_intf.pass_thru_intf: %s\n",
+ vf_intf.ppid, vf_intf.pass_thru_intf);
+
+ sprintf(cmdline, "nsenter -t 1 -n ip link set %s netns %d",
+ vf_intf.pass_thru_intf, getpid());
+ if (runcmdline(cmdline))
+ return;
+
+ sprintf(cmdline, "ip a s %s", vf_intf.pass_thru_intf);
+ if (runcmdline(cmdline))
+ return;
+
+ sprintf(cmdline, "ip link set %s down", vf_intf.pass_thru_intf);
+ if (runcmdline(cmdline))
+ return;
+
+ sprintf(cmdline, "ip link set %s name nicvf0", vf_intf.pass_thru_intf);
+ if (runcmdline(cmdline))
+ return;
+
+ debug("nicvf0 VF pass-through setup complete.\n");
+}
+#endif // SYZ_NIC_VF
+
// We test in a separate namespace, which does not have any network devices initially (even lo).
// Create/up as many as we can.
static void initialize_netdevices(void)
@@ -1374,23 +1501,26 @@ static void initialize_netdevices(void)
const char* type;
const char* dev;
} devtypes[] = {
- // Note: ip6erspan device can't be added if ip6gretap exists in the same namespace.
- {"ip6gretap", "ip6gretap0"},
- {"bridge", "bridge0"},
- {"vcan", "vcan0"},
- {"bond", "bond0"},
- {"team", "team0"},
- {"dummy", "dummy0"},
- {"nlmon", "nlmon0"},
- {"caif", "caif0"},
- {"batadv", "batadv0"},
- // Note: this adds vxcan0/vxcan1 pair, similar to veth (creating vxcan0 would fail).
- {"vxcan", "vxcan1"},
- // This adds connected veth0 and veth1 devices.
- {"veth", 0},
- {"wireguard", "wg0"},
- {"wireguard", "wg1"},
- {"wireguard", "wg2"},
+ // Note: ip6erspan device can't be added if ip6gretap exists in the same namespace.
+ {"ip6gretap", "ip6gretap0"},
+ {"bridge", "bridge0"},
+ {"vcan", "vcan0"},
+ {"bond", "bond0"},
+ {"team", "team0"},
+ {"dummy", "dummy0"},
+#if SYZ_EXECUTOR || SYZ_NIC_VF
+ {"nicvf", "nicvf0"},
+#endif
+ {"nlmon", "nlmon0"},
+ {"caif", "caif0"},
+ {"batadv", "batadv0"},
+ // Note: this adds vxcan0/vxcan1 pair, similar to veth (creating vxcan0 would fail).
+ {"vxcan", "vxcan1"},
+ // This adds connected veth0 and veth1 devices.
+ {"veth", 0},
+ {"wireguard", "wg0"},
+ {"wireguard", "wg1"},
+ {"wireguard", "wg2"},
};
const char* devmasters[] = {"bridge", "bond", "team", "batadv"};
// If you extend this array, also update netdev_addr_id in vnet.txt
@@ -1400,64 +1530,67 @@ static void initialize_netdevices(void)
int macsize;
bool noipv6;
} devices[] = {
- {"lo", ETH_ALEN},
- {"sit0", 0},
- {"bridge0", ETH_ALEN},
- {"vcan0", 0, true},
- {"tunl0", 0},
- {"gre0", 0},
- {"gretap0", ETH_ALEN},
- {"ip_vti0", 0},
- {"ip6_vti0", 0},
- {"ip6tnl0", 0},
- {"ip6gre0", 0},
- {"ip6gretap0", ETH_ALEN},
- {"erspan0", ETH_ALEN},
- {"bond0", ETH_ALEN},
- {"veth0", ETH_ALEN},
- {"veth1", ETH_ALEN},
- {"team0", ETH_ALEN},
- {"veth0_to_bridge", ETH_ALEN},
- {"veth1_to_bridge", ETH_ALEN},
- {"veth0_to_bond", ETH_ALEN},
- {"veth1_to_bond", ETH_ALEN},
- {"veth0_to_team", ETH_ALEN},
- {"veth1_to_team", ETH_ALEN},
- {"veth0_to_hsr", ETH_ALEN},
- {"veth1_to_hsr", ETH_ALEN},
- {"hsr0", 0},
- {"dummy0", ETH_ALEN},
- {"nlmon0", 0},
- {"vxcan0", 0, true},
- {"vxcan1", 0, true},
- {"caif0", ETH_ALEN}, // TODO: up'ing caif fails with ENODEV
- {"batadv0", ETH_ALEN},
- {netdevsim, ETH_ALEN},
- {"xfrm0", ETH_ALEN},
- {"veth0_virt_wifi", ETH_ALEN},
- {"veth1_virt_wifi", ETH_ALEN},
- {"virt_wifi0", ETH_ALEN},
- {"veth0_vlan", ETH_ALEN},
- {"veth1_vlan", ETH_ALEN},
- {"vlan0", ETH_ALEN},
- {"vlan1", ETH_ALEN},
- {"macvlan0", ETH_ALEN},
- {"macvlan1", ETH_ALEN},
- {"ipvlan0", ETH_ALEN},
- {"ipvlan1", ETH_ALEN},
- {"veth0_macvtap", ETH_ALEN},
- {"veth1_macvtap", ETH_ALEN},
- {"macvtap0", ETH_ALEN},
- {"macsec0", ETH_ALEN},
- {"veth0_to_batadv", ETH_ALEN},
- {"veth1_to_batadv", ETH_ALEN},
- {"batadv_slave_0", ETH_ALEN},
- {"batadv_slave_1", ETH_ALEN},
- {"geneve0", ETH_ALEN},
- {"geneve1", ETH_ALEN},
- {"wg0", 0},
- {"wg1", 0},
- {"wg2", 0},
+ {"lo", ETH_ALEN},
+ {"sit0", 0},
+ {"bridge0", ETH_ALEN},
+ {"vcan0", 0, true},
+ {"tunl0", 0},
+ {"gre0", 0},
+ {"gretap0", ETH_ALEN},
+ {"ip_vti0", 0},
+ {"ip6_vti0", 0},
+ {"ip6tnl0", 0},
+ {"ip6gre0", 0},
+ {"ip6gretap0", ETH_ALEN},
+ {"erspan0", ETH_ALEN},
+ {"bond0", ETH_ALEN},
+ {"veth0", ETH_ALEN},
+ {"veth1", ETH_ALEN},
+ {"team0", ETH_ALEN},
+ {"veth0_to_bridge", ETH_ALEN},
+ {"veth1_to_bridge", ETH_ALEN},
+ {"veth0_to_bond", ETH_ALEN},
+ {"veth1_to_bond", ETH_ALEN},
+ {"veth0_to_team", ETH_ALEN},
+ {"veth1_to_team", ETH_ALEN},
+ {"veth0_to_hsr", ETH_ALEN},
+ {"veth1_to_hsr", ETH_ALEN},
+ {"hsr0", 0},
+ {"dummy0", ETH_ALEN},
+#if SYZ_EXECUTOR || SYZ_NIC_VF
+ {"nicvf0", 0, true},
+#endif
+ {"nlmon0", 0},
+ {"vxcan0", 0, true},
+ {"vxcan1", 0, true},
+ {"caif0", ETH_ALEN}, // TODO: up'ing caif fails with ENODEV
+ {"batadv0", ETH_ALEN},
+ {netdevsim, ETH_ALEN},
+ {"xfrm0", ETH_ALEN},
+ {"veth0_virt_wifi", ETH_ALEN},
+ {"veth1_virt_wifi", ETH_ALEN},
+ {"virt_wifi0", ETH_ALEN},
+ {"veth0_vlan", ETH_ALEN},
+ {"veth1_vlan", ETH_ALEN},
+ {"vlan0", ETH_ALEN},
+ {"vlan1", ETH_ALEN},
+ {"macvlan0", ETH_ALEN},
+ {"macvlan1", ETH_ALEN},
+ {"ipvlan0", ETH_ALEN},
+ {"ipvlan1", ETH_ALEN},
+ {"veth0_macvtap", ETH_ALEN},
+ {"veth1_macvtap", ETH_ALEN},
+ {"macvtap0", ETH_ALEN},
+ {"macsec0", ETH_ALEN},
+ {"veth0_to_batadv", ETH_ALEN},
+ {"veth1_to_batadv", ETH_ALEN},
+ {"batadv_slave_0", ETH_ALEN},
+ {"batadv_slave_1", ETH_ALEN},
+ {"geneve0", ETH_ALEN},
+ {"geneve1", ETH_ALEN},
+ {"wg0", 0},
+ {"wg1", 0},
+ {"wg2", 0},
};
int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (sock == -1)
@@ -1526,6 +1659,10 @@ static void initialize_netdevices(void)
netlink_wireguard_setup();
+#if SYZ_EXECUTOR || SYZ_NIC_VF
+ netlink_nicvf_setup();
+#endif
+
for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
// Assign some unique address to devices. Some devices won't up without this.
// Shift addresses by 10 because 0 subnet address can mean special things.
@@ -1582,6 +1719,10 @@ static void initialize_netdevices_init(void)
netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr, macsize, NULL);
}
close(sock);
+
+#if SYZ_EXECUTOR || SYZ_NIC_VF
+ find_vf_interface();
+#endif
}
#endif
diff --git a/executor/executor.cc b/executor/executor.cc
index 3c76738d2..efd072a75 100644
--- a/executor/executor.cc
+++ b/executor/executor.cc
@@ -173,6 +173,7 @@ static bool flag_net_reset;
static bool flag_cgroups;
static bool flag_close_fds;
static bool flag_devlink_pci;
+static bool flag_nic_vf;
static bool flag_vhci_injection;
static bool flag_wifi;
static bool flag_delay_kcov_mmap;
@@ -621,6 +622,7 @@ void parse_env_flags(uint64 flags)
flag_vhci_injection = flags & (1 << 12);
flag_wifi = flags & (1 << 13);
flag_delay_kcov_mmap = flags & (1 << 14);
+ flag_nic_vf = flags & (1 << 15);
}
#if SYZ_EXECUTOR_USES_FORK_SERVER