diff options
Diffstat (limited to 'executor')
| -rw-r--r-- | executor/common_linux.h | 293 | ||||
| -rw-r--r-- | executor/executor.cc | 2 |
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 |
