| // KMSAN: uninit-value in gue_err |
| // https://syzkaller.appspot.com/bug?id=1f0fc1e5c1000180b48892aa283f163e0d28132c |
| // status:fixed |
| // autogenerated by syzkaller (https://github.com/google/syzkaller) |
| |
| #define _GNU_SOURCE |
| |
| #include <arpa/inet.h> |
| #include <dirent.h> |
| #include <endian.h> |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <net/if.h> |
| #include <net/if_arp.h> |
| #include <netinet/in.h> |
| #include <sched.h> |
| #include <signal.h> |
| #include <stdarg.h> |
| #include <stdbool.h> |
| #include <stddef.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/ioctl.h> |
| #include <sys/mount.h> |
| #include <sys/prctl.h> |
| #include <sys/resource.h> |
| #include <sys/socket.h> |
| #include <sys/stat.h> |
| #include <sys/syscall.h> |
| #include <sys/time.h> |
| #include <sys/types.h> |
| #include <sys/uio.h> |
| #include <sys/wait.h> |
| #include <time.h> |
| #include <unistd.h> |
| |
| #include <linux/genetlink.h> |
| #include <linux/if_addr.h> |
| #include <linux/if_ether.h> |
| #include <linux/if_link.h> |
| #include <linux/if_tun.h> |
| #include <linux/in6.h> |
| #include <linux/ip.h> |
| #include <linux/kvm.h> |
| #include <linux/neighbour.h> |
| #include <linux/net.h> |
| #include <linux/netlink.h> |
| #include <linux/rtnetlink.h> |
| #include <linux/tcp.h> |
| #include <linux/veth.h> |
| |
| unsigned long long procid; |
| |
| static void sleep_ms(uint64_t ms) |
| { |
| usleep(ms * 1000); |
| } |
| |
| static uint64_t current_time_ms(void) |
| { |
| struct timespec ts; |
| if (clock_gettime(CLOCK_MONOTONIC, &ts)) |
| exit(1); |
| return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000; |
| } |
| |
| static bool write_file(const char* file, const char* what, ...) |
| { |
| char buf[1024]; |
| va_list args; |
| va_start(args, what); |
| vsnprintf(buf, sizeof(buf), what, args); |
| va_end(args); |
| buf[sizeof(buf) - 1] = 0; |
| int len = strlen(buf); |
| int fd = open(file, O_WRONLY | O_CLOEXEC); |
| if (fd == -1) |
| return false; |
| if (write(fd, buf, len) != len) { |
| int err = errno; |
| close(fd); |
| errno = err; |
| return false; |
| } |
| close(fd); |
| return true; |
| } |
| |
| static struct { |
| char* pos; |
| int nesting; |
| struct nlattr* nested[8]; |
| char buf[1024]; |
| } nlmsg; |
| |
| static void netlink_init(int typ, int flags, const void* data, int size) |
| { |
| memset(&nlmsg, 0, sizeof(nlmsg)); |
| struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf; |
| hdr->nlmsg_type = typ; |
| hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags; |
| memcpy(hdr + 1, data, size); |
| nlmsg.pos = (char*)(hdr + 1) + NLMSG_ALIGN(size); |
| } |
| |
| static void netlink_attr(int typ, const void* data, int size) |
| { |
| struct nlattr* attr = (struct nlattr*)nlmsg.pos; |
| attr->nla_len = sizeof(*attr) + size; |
| attr->nla_type = typ; |
| memcpy(attr + 1, data, size); |
| nlmsg.pos += NLMSG_ALIGN(attr->nla_len); |
| } |
| |
| static void netlink_nest(int typ) |
| { |
| struct nlattr* attr = (struct nlattr*)nlmsg.pos; |
| attr->nla_type = typ; |
| nlmsg.pos += sizeof(*attr); |
| nlmsg.nested[nlmsg.nesting++] = attr; |
| } |
| |
| static void netlink_done(void) |
| { |
| struct nlattr* attr = nlmsg.nested[--nlmsg.nesting]; |
| attr->nla_len = nlmsg.pos - (char*)attr; |
| } |
| |
| static int netlink_send(int sock) |
| { |
| if (nlmsg.pos > nlmsg.buf + sizeof(nlmsg.buf) || nlmsg.nesting) |
| exit(1); |
| struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg.buf; |
| hdr->nlmsg_len = nlmsg.pos - nlmsg.buf; |
| struct sockaddr_nl addr; |
| memset(&addr, 0, sizeof(addr)); |
| addr.nl_family = AF_NETLINK; |
| unsigned n = sendto(sock, nlmsg.buf, hdr->nlmsg_len, 0, |
| (struct sockaddr*)&addr, sizeof(addr)); |
| if (n != hdr->nlmsg_len) |
| exit(1); |
| n = recv(sock, nlmsg.buf, sizeof(nlmsg.buf), 0); |
| if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr)) |
| exit(1); |
| if (hdr->nlmsg_type != NLMSG_ERROR) |
| exit(1); |
| return -((struct nlmsgerr*)(hdr + 1))->error; |
| } |
| |
| static void netlink_add_device_impl(const char* type, const char* name) |
| { |
| struct ifinfomsg hdr; |
| memset(&hdr, 0, sizeof(hdr)); |
| netlink_init(RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr, sizeof(hdr)); |
| if (name) |
| netlink_attr(IFLA_IFNAME, name, strlen(name)); |
| netlink_nest(IFLA_LINKINFO); |
| netlink_attr(IFLA_INFO_KIND, type, strlen(type)); |
| } |
| |
| static void netlink_add_device(int sock, const char* type, const char* name) |
| { |
| netlink_add_device_impl(type, name); |
| netlink_done(); |
| int err = netlink_send(sock); |
| (void)err; |
| } |
| |
| static void netlink_add_veth(int sock, const char* name, const char* peer) |
| { |
| netlink_add_device_impl("veth", name); |
| netlink_nest(IFLA_INFO_DATA); |
| netlink_nest(VETH_INFO_PEER); |
| nlmsg.pos += sizeof(struct ifinfomsg); |
| netlink_attr(IFLA_IFNAME, peer, strlen(peer)); |
| netlink_done(); |
| netlink_done(); |
| netlink_done(); |
| int err = netlink_send(sock); |
| (void)err; |
| } |
| |
| static void netlink_add_hsr(int sock, const char* name, const char* slave1, |
| const char* slave2) |
| { |
| netlink_add_device_impl("hsr", name); |
| netlink_nest(IFLA_INFO_DATA); |
| int ifindex1 = if_nametoindex(slave1); |
| netlink_attr(IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1)); |
| int ifindex2 = if_nametoindex(slave2); |
| netlink_attr(IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2)); |
| netlink_done(); |
| netlink_done(); |
| int err = netlink_send(sock); |
| (void)err; |
| } |
| |
| static void netlink_device_change(int sock, const char* name, bool up, |
| const char* master, const void* mac, |
| int macsize) |
| { |
| struct ifinfomsg hdr; |
| memset(&hdr, 0, sizeof(hdr)); |
| if (up) |
| hdr.ifi_flags = hdr.ifi_change = IFF_UP; |
| netlink_init(RTM_NEWLINK, 0, &hdr, sizeof(hdr)); |
| netlink_attr(IFLA_IFNAME, name, strlen(name)); |
| if (master) { |
| int ifindex = if_nametoindex(master); |
| netlink_attr(IFLA_MASTER, &ifindex, sizeof(ifindex)); |
| } |
| if (macsize) |
| netlink_attr(IFLA_ADDRESS, mac, macsize); |
| int err = netlink_send(sock); |
| (void)err; |
| } |
| |
| static int netlink_add_addr(int sock, const char* dev, const void* addr, |
| int addrsize) |
| { |
| struct ifaddrmsg hdr; |
| memset(&hdr, 0, sizeof(hdr)); |
| hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6; |
| hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120; |
| hdr.ifa_scope = RT_SCOPE_UNIVERSE; |
| hdr.ifa_index = if_nametoindex(dev); |
| netlink_init(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr, sizeof(hdr)); |
| netlink_attr(IFA_LOCAL, addr, addrsize); |
| netlink_attr(IFA_ADDRESS, addr, addrsize); |
| return netlink_send(sock); |
| } |
| |
| static void netlink_add_addr4(int sock, const char* dev, const char* addr) |
| { |
| struct in_addr in_addr; |
| inet_pton(AF_INET, addr, &in_addr); |
| int err = netlink_add_addr(sock, dev, &in_addr, sizeof(in_addr)); |
| (void)err; |
| } |
| |
| static void netlink_add_addr6(int sock, const char* dev, const char* addr) |
| { |
| struct in6_addr in6_addr; |
| inet_pton(AF_INET6, addr, &in6_addr); |
| int err = netlink_add_addr(sock, dev, &in6_addr, sizeof(in6_addr)); |
| (void)err; |
| } |
| |
| static void netlink_add_neigh(int sock, const char* name, const void* addr, |
| int addrsize, const void* mac, int macsize) |
| { |
| struct ndmsg hdr; |
| memset(&hdr, 0, sizeof(hdr)); |
| hdr.ndm_family = addrsize == 4 ? AF_INET : AF_INET6; |
| hdr.ndm_ifindex = if_nametoindex(name); |
| hdr.ndm_state = NUD_PERMANENT; |
| netlink_init(RTM_NEWNEIGH, NLM_F_EXCL | NLM_F_CREATE, &hdr, sizeof(hdr)); |
| netlink_attr(NDA_DST, addr, addrsize); |
| netlink_attr(NDA_LLADDR, mac, macsize); |
| int err = netlink_send(sock); |
| (void)err; |
| } |
| |
| static int tunfd = -1; |
| static int tun_frags_enabled; |
| #define SYZ_TUN_MAX_PACKET_SIZE 1000 |
| |
| #define TUN_IFACE "syz_tun" |
| |
| #define LOCAL_MAC 0xaaaaaaaaaaaa |
| #define REMOTE_MAC 0xaaaaaaaaaabb |
| |
| #define LOCAL_IPV4 "172.20.20.170" |
| #define REMOTE_IPV4 "172.20.20.187" |
| |
| #define LOCAL_IPV6 "fe80::aa" |
| #define REMOTE_IPV6 "fe80::bb" |
| |
| #define IFF_NAPI 0x0010 |
| #define IFF_NAPI_FRAGS 0x0020 |
| |
| static void initialize_tun(void) |
| { |
| tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK); |
| if (tunfd == -1) { |
| printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n"); |
| printf("otherwise fuzzing or reproducing might not work as intended\n"); |
| return; |
| } |
| const int kTunFd = 240; |
| if (dup2(tunfd, kTunFd) < 0) |
| exit(1); |
| close(tunfd); |
| tunfd = kTunFd; |
| struct ifreq ifr; |
| memset(&ifr, 0, sizeof(ifr)); |
| strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ); |
| ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS; |
| if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) { |
| ifr.ifr_flags = IFF_TAP | IFF_NO_PI; |
| if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) |
| exit(1); |
| } |
| if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0) |
| exit(1); |
| tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0; |
| char sysctl[64]; |
| sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/accept_dad", TUN_IFACE); |
| write_file(sysctl, "0"); |
| sprintf(sysctl, "/proc/sys/net/ipv6/conf/%s/router_solicitations", TUN_IFACE); |
| write_file(sysctl, "0"); |
| int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); |
| if (sock == -1) |
| exit(1); |
| netlink_add_addr4(sock, TUN_IFACE, LOCAL_IPV4); |
| netlink_add_addr6(sock, TUN_IFACE, LOCAL_IPV6); |
| uint64_t macaddr = REMOTE_MAC; |
| struct in_addr in_addr; |
| inet_pton(AF_INET, REMOTE_IPV4, &in_addr); |
| netlink_add_neigh(sock, TUN_IFACE, &in_addr, sizeof(in_addr), &macaddr, |
| ETH_ALEN); |
| struct in6_addr in6_addr; |
| inet_pton(AF_INET6, REMOTE_IPV6, &in6_addr); |
| netlink_add_neigh(sock, TUN_IFACE, &in6_addr, sizeof(in6_addr), &macaddr, |
| ETH_ALEN); |
| macaddr = LOCAL_MAC; |
| netlink_device_change(sock, TUN_IFACE, true, 0, &macaddr, ETH_ALEN); |
| close(sock); |
| } |
| |
| #define DEV_IPV4 "172.20.20.%d" |
| #define DEV_IPV6 "fe80::%02hx" |
| #define DEV_MAC 0x00aaaaaaaaaa |
| static void initialize_netdevices(void) |
| { |
| char netdevsim[16]; |
| sprintf(netdevsim, "netdevsim%d", (int)procid); |
| struct { |
| const char* type; |
| const char* dev; |
| } devtypes[] = { |
| {"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"}, |
| {"vcan", "vcan0"}, {"bond", "bond0"}, |
| {"team", "team0"}, {"dummy", "dummy0"}, |
| {"nlmon", "nlmon0"}, {"caif", "caif0"}, |
| {"batadv", "batadv0"}, {"vxcan", "vxcan1"}, |
| {"netdevsim", netdevsim}, {"veth", 0}, |
| }; |
| const char* devmasters[] = {"bridge", "bond", "team"}; |
| struct { |
| const char* name; |
| 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}, |
| {"vxcan1", 0, true}, |
| {"caif0", ETH_ALEN}, |
| {"batadv0", ETH_ALEN}, |
| {netdevsim, ETH_ALEN}, |
| }; |
| int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); |
| if (sock == -1) |
| exit(1); |
| unsigned i; |
| for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) |
| netlink_add_device(sock, devtypes[i].type, devtypes[i].dev); |
| for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) { |
| char master[32], slave0[32], veth0[32], slave1[32], veth1[32]; |
| sprintf(slave0, "%s_slave_0", devmasters[i]); |
| sprintf(veth0, "veth0_to_%s", devmasters[i]); |
| netlink_add_veth(sock, slave0, veth0); |
| sprintf(slave1, "%s_slave_1", devmasters[i]); |
| sprintf(veth1, "veth1_to_%s", devmasters[i]); |
| netlink_add_veth(sock, slave1, veth1); |
| sprintf(master, "%s0", devmasters[i]); |
| netlink_device_change(sock, slave0, false, master, 0, 0); |
| netlink_device_change(sock, slave1, false, master, 0, 0); |
| } |
| netlink_device_change(sock, "bridge_slave_0", true, 0, 0, 0); |
| netlink_device_change(sock, "bridge_slave_1", true, 0, 0, 0); |
| netlink_add_veth(sock, "hsr_slave_0", "veth0_to_hsr"); |
| netlink_add_veth(sock, "hsr_slave_1", "veth1_to_hsr"); |
| netlink_add_hsr(sock, "hsr0", "hsr_slave_0", "hsr_slave_1"); |
| netlink_device_change(sock, "hsr_slave_0", true, 0, 0, 0); |
| netlink_device_change(sock, "hsr_slave_1", true, 0, 0, 0); |
| for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) { |
| char addr[32]; |
| sprintf(addr, DEV_IPV4, i + 10); |
| netlink_add_addr4(sock, devices[i].name, addr); |
| if (!devices[i].noipv6) { |
| sprintf(addr, DEV_IPV6, i + 10); |
| netlink_add_addr6(sock, devices[i].name, addr); |
| } |
| uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40); |
| netlink_device_change(sock, devices[i].name, true, 0, &macaddr, |
| devices[i].macsize); |
| } |
| close(sock); |
| } |
| static void initialize_netdevices_init(void) |
| { |
| int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); |
| if (sock == -1) |
| exit(1); |
| struct { |
| const char* type; |
| int macsize; |
| bool noipv6; |
| bool noup; |
| } devtypes[] = { |
| {"nr", 7, true}, {"rose", 5, true, true}, |
| }; |
| unsigned i; |
| for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) { |
| char dev[32], addr[32]; |
| sprintf(dev, "%s%d", devtypes[i].type, (int)procid); |
| sprintf(addr, "172.30.%d.%d", i, (int)procid + 1); |
| netlink_add_addr4(sock, dev, addr); |
| if (!devtypes[i].noipv6) { |
| sprintf(addr, "fe88::%02hx:%02hx", i, (int)procid + 1); |
| netlink_add_addr6(sock, dev, addr); |
| } |
| int macsize = devtypes[i].macsize; |
| uint64_t macaddr = 0xbbbbbb + |
| ((unsigned long long)i << (8 * (macsize - 2))) + |
| (procid << (8 * (macsize - 1))); |
| netlink_device_change(sock, dev, !devtypes[i].noup, 0, &macaddr, macsize); |
| } |
| close(sock); |
| } |
| |
| static int read_tun(char* data, int size) |
| { |
| if (tunfd < 0) |
| return -1; |
| int rv = read(tunfd, data, size); |
| if (rv < 0) { |
| if (errno == EAGAIN) |
| return -1; |
| if (errno == EBADFD) |
| return -1; |
| exit(1); |
| } |
| return rv; |
| } |
| |
| static void flush_tun() |
| { |
| char data[SYZ_TUN_MAX_PACKET_SIZE]; |
| while (read_tun(&data[0], sizeof(data)) != -1) { |
| } |
| } |
| |
| static long syz_open_dev(long a0, long a1, long a2) |
| { |
| if (a0 == 0xc || a0 == 0xb) { |
| char buf[128]; |
| sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1, |
| (uint8_t)a2); |
| return open(buf, O_RDWR, 0); |
| } else { |
| char buf[1024]; |
| char* hash; |
| strncpy(buf, (char*)a0, sizeof(buf) - 1); |
| buf[sizeof(buf) - 1] = 0; |
| while ((hash = strchr(buf, '#'))) { |
| *hash = '0' + (char)(a1 % 10); |
| a1 /= 10; |
| } |
| return open(buf, a2, 0); |
| } |
| } |
| |
| static long syz_genetlink_get_family_id(long name) |
| { |
| char buf[512] = {0}; |
| struct nlmsghdr* hdr = (struct nlmsghdr*)buf; |
| struct genlmsghdr* genlhdr = (struct genlmsghdr*)NLMSG_DATA(hdr); |
| struct nlattr* attr = (struct nlattr*)(genlhdr + 1); |
| hdr->nlmsg_len = |
| sizeof(*hdr) + sizeof(*genlhdr) + sizeof(*attr) + GENL_NAMSIZ; |
| hdr->nlmsg_type = GENL_ID_CTRL; |
| hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; |
| genlhdr->cmd = CTRL_CMD_GETFAMILY; |
| attr->nla_type = CTRL_ATTR_FAMILY_NAME; |
| attr->nla_len = sizeof(*attr) + GENL_NAMSIZ; |
| strncpy((char*)(attr + 1), (char*)name, GENL_NAMSIZ); |
| struct iovec iov = {hdr, hdr->nlmsg_len}; |
| struct sockaddr_nl addr = {0}; |
| addr.nl_family = AF_NETLINK; |
| int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); |
| if (fd == -1) { |
| return -1; |
| } |
| struct msghdr msg = {&addr, sizeof(addr), &iov, 1, NULL, 0, 0}; |
| if (sendmsg(fd, &msg, 0) == -1) { |
| close(fd); |
| return -1; |
| } |
| ssize_t n = recv(fd, buf, sizeof(buf), 0); |
| close(fd); |
| if (n <= 0) { |
| return -1; |
| } |
| if (hdr->nlmsg_type != GENL_ID_CTRL) { |
| return -1; |
| } |
| for (; (char*)attr < buf + n; |
| attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) { |
| if (attr->nla_type == CTRL_ATTR_FAMILY_ID) |
| return *(uint16_t*)(attr + 1); |
| } |
| return -1; |
| } |
| |
| const char kvm_asm16_cpl3[] = "\x0f\x20\xc0\x66\x83\xc8\x01\x0f\x22\xc0\xb8\xa0" |
| "\x00\x0f\x00\xd8\xb8\x2b\x00\x8e\xd8\x8e\xc0\x8e" |
| "\xe0\x8e\xe8\xbc\x00\x01\xc7\x06\x00\x01\x1d\xba" |
| "\xc7\x06\x02\x01\x23\x00\xc7\x06\x04\x01\x00\x01" |
| "\xc7\x06\x06\x01\x2b\x00\xcb"; |
| const char kvm_asm32_paged[] = "\x0f\x20\xc0\x0d\x00\x00\x00\x80\x0f\x22\xc0"; |
| const char kvm_asm32_vm86[] = |
| "\x66\xb8\xb8\x00\x0f\x00\xd8\xea\x00\x00\x00\x00\xd0\x00"; |
| const char kvm_asm32_paged_vm86[] = "\x0f\x20\xc0\x0d\x00\x00\x00\x80\x0f\x22" |
| "\xc0\x66\xb8\xb8\x00\x0f\x00\xd8\xea\x00" |
| "\x00\x00\x00\xd0\x00"; |
| const char kvm_asm64_vm86[] = "\x0f\x20\xc0\x0d\x00\x00\x00\x80\x0f\x22\xc0\x66" |
| "\xb8\xb8\x00\x0f\x00\xd8\xea\x00\x00\x00\x00\xd0" |
| "\x00"; |
| const char kvm_asm64_enable_long[] = "\x0f\x20\xc0\x0d\x00\x00\x00\x80\x0f\x22" |
| "\xc0\xea\xde\xc0\xad\x0b\x50\x00\x48\xc7" |
| "\xc0\xd8\x00\x00\x00\x0f\x00\xd8"; |
| const char kvm_asm64_init_vm[] = |
| "\x0f\x20\xc0\x0d\x00\x00\x00\x80\x0f\x22\xc0\xea\xde\xc0\xad\x0b\x50\x00" |
| "\x48\xc7\xc0\xd8\x00\x00\x00\x0f\x00\xd8\x48\xc7\xc1\x3a\x00\x00\x00\x0f" |
| "\x32\x48\x83\xc8\x05\x0f\x30\x0f\x20\xe0\x48\x0d\x00\x20\x00\x00\x0f\x22" |
| "\xe0\x48\xc7\xc1\x80\x04\x00\x00\x0f\x32\x48\xc7\xc2\x00\x60\x00\x00\x89" |
| "\x02\x48\xc7\xc2\x00\x70\x00\x00\x89\x02\x48\xc7\xc0\x00\x5f\x00\x00\xf3" |
| "\x0f\xc7\x30\x48\xc7\xc0\x08\x5f\x00\x00\x66\x0f\xc7\x30\x0f\xc7\x30\x48" |
| "\xc7\xc1\x81\x04\x00\x00\x0f\x32\x48\x83\xc8\x3f\x48\x21\xd0\x48\xc7\xc2" |
| "\x00\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x02\x40\x00\x00\x48\xb8\x84\x9e" |
| "\x99\xf3\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x1e\x40\x00\x00\x48\xc7" |
| "\xc0\x81\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc1\x83\x04\x00\x00\x0f\x32\x48" |
| "\x0d\xff\x6f\x03\x00\x48\x21\xd0\x48\xc7\xc2\x0c\x40\x00\x00\x0f\x79\xd0" |
| "\x48\xc7\xc1\x84\x04\x00\x00\x0f\x32\x48\x0d\xff\x17\x00\x00\x48\x21\xd0" |
| "\x48\xc7\xc2\x12\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x04\x2c\x00\x00\x48" |
| "\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x00\x28\x00\x00\x48\xc7" |
| "\xc0\xff\xff\xff\xff\x0f\x79\xd0\x48\xc7\xc2\x02\x0c\x00\x00\x48\xc7\xc0" |
| "\x50\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc0\x58\x00\x00\x00\x48\xc7\xc2\x00" |
| "\x0c\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x04\x0c\x00\x00\x0f\x79\xd0\x48\xc7" |
| "\xc2\x06\x0c\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x08\x0c\x00\x00\x0f\x79\xd0" |
| "\x48\xc7\xc2\x0a\x0c\x00\x00\x0f\x79\xd0\x48\xc7\xc0\xd8\x00\x00\x00\x48" |
| "\xc7\xc2\x0c\x0c\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x02\x2c\x00\x00\x48\xc7" |
| "\xc0\x00\x05\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x00\x4c\x00\x00\x48\xc7\xc0" |
| "\x50\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x10\x6c\x00\x00\x48\xc7\xc0\x00" |
| "\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x12\x6c\x00\x00\x48\xc7\xc0\x00\x00" |
| "\x00\x00\x0f\x79\xd0\x0f\x20\xc0\x48\xc7\xc2\x00\x6c\x00\x00\x48\x89\xc0" |
| "\x0f\x79\xd0\x0f\x20\xd8\x48\xc7\xc2\x02\x6c\x00\x00\x48\x89\xc0\x0f\x79" |
| "\xd0\x0f\x20\xe0\x48\xc7\xc2\x04\x6c\x00\x00\x48\x89\xc0\x0f\x79\xd0\x48" |
| "\xc7\xc2\x06\x6c\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7" |
| "\xc2\x08\x6c\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2" |
| "\x0a\x6c\x00\x00\x48\xc7\xc0\x00\x3a\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0c" |
| "\x6c\x00\x00\x48\xc7\xc0\x00\x10\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0e\x6c" |
| "\x00\x00\x48\xc7\xc0\x00\x38\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x14\x6c\x00" |
| "\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x16\x6c\x00\x00" |
| "\x48\x8b\x04\x25\x10\x5f\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x00\x00\x00\x00" |
| "\x48\xc7\xc0\x01\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x02\x00\x00\x00\x48" |
| "\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x00\x20\x00\x00\x48\xc7" |
| "\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x02\x20\x00\x00\x48\xc7\xc0" |
| "\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x04\x20\x00\x00\x48\xc7\xc0\x00" |
| "\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x06\x20\x00\x00\x48\xc7\xc0\x00\x00" |
| "\x00\x00\x0f\x79\xd0\x48\xc7\xc1\x77\x02\x00\x00\x0f\x32\x48\xc1\xe2\x20" |
| "\x48\x09\xd0\x48\xc7\xc2\x00\x2c\x00\x00\x48\x89\xc0\x0f\x79\xd0\x48\xc7" |
| "\xc2\x04\x40\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2" |
| "\x0a\x40\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0e" |
| "\x40\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x10\x40" |
| "\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x16\x40\x00" |
| "\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x14\x40\x00\x00" |
| "\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x00\x60\x00\x00\x48" |
| "\xc7\xc0\xff\xff\xff\xff\x0f\x79\xd0\x48\xc7\xc2\x02\x60\x00\x00\x48\xc7" |
| "\xc0\xff\xff\xff\xff\x0f\x79\xd0\x48\xc7\xc2\x1c\x20\x00\x00\x48\xc7\xc0" |
| "\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x1e\x20\x00\x00\x48\xc7\xc0\x00" |
| "\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x20\x20\x00\x00\x48\xc7\xc0\x00\x00" |
| "\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x22\x20\x00\x00\x48\xc7\xc0\x00\x00\x00" |
| "\x00\x0f\x79\xd0\x48\xc7\xc2\x00\x08\x00\x00\x48\xc7\xc0\x58\x00\x00\x00" |
| "\x0f\x79\xd0\x48\xc7\xc2\x02\x08\x00\x00\x48\xc7\xc0\x50\x00\x00\x00\x0f" |
| "\x79\xd0\x48\xc7\xc2\x04\x08\x00\x00\x48\xc7\xc0\x58\x00\x00\x00\x0f\x79" |
| "\xd0\x48\xc7\xc2\x06\x08\x00\x00\x48\xc7\xc0\x58\x00\x00\x00\x0f\x79\xd0" |
| "\x48\xc7\xc2\x08\x08\x00\x00\x48\xc7\xc0\x58\x00\x00\x00\x0f\x79\xd0\x48" |
| "\xc7\xc2\x0a\x08\x00\x00\x48\xc7\xc0\x58\x00\x00\x00\x0f\x79\xd0\x48\xc7" |
| "\xc2\x0c\x08\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2" |
| "\x0e\x08\x00\x00\x48\xc7\xc0\xd8\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x12" |
| "\x68\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x14\x68" |
| "\x00\x00\x48\xc7\xc0\x00\x3a\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x16\x68\x00" |
| "\x00\x48\xc7\xc0\x00\x10\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x18\x68\x00\x00" |
| "\x48\xc7\xc0\x00\x38\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x00\x48\x00\x00\x48" |
| "\xc7\xc0\xff\xff\x0f\x00\x0f\x79\xd0\x48\xc7\xc2\x02\x48\x00\x00\x48\xc7" |
| "\xc0\xff\xff\x0f\x00\x0f\x79\xd0\x48\xc7\xc2\x04\x48\x00\x00\x48\xc7\xc0" |
| "\xff\xff\x0f\x00\x0f\x79\xd0\x48\xc7\xc2\x06\x48\x00\x00\x48\xc7\xc0\xff" |
| "\xff\x0f\x00\x0f\x79\xd0\x48\xc7\xc2\x08\x48\x00\x00\x48\xc7\xc0\xff\xff" |
| "\x0f\x00\x0f\x79\xd0\x48\xc7\xc2\x0a\x48\x00\x00\x48\xc7\xc0\xff\xff\x0f" |
| "\x00\x0f\x79\xd0\x48\xc7\xc2\x0c\x48\x00\x00\x48\xc7\xc0\x00\x00\x00\x00" |
| "\x0f\x79\xd0\x48\xc7\xc2\x0e\x48\x00\x00\x48\xc7\xc0\xff\x1f\x00\x00\x0f" |
| "\x79\xd0\x48\xc7\xc2\x10\x48\x00\x00\x48\xc7\xc0\xff\x1f\x00\x00\x0f\x79" |
| "\xd0\x48\xc7\xc2\x12\x48\x00\x00\x48\xc7\xc0\xff\x1f\x00\x00\x0f\x79\xd0" |
| "\x48\xc7\xc2\x14\x48\x00\x00\x48\xc7\xc0\x93\x40\x00\x00\x0f\x79\xd0\x48" |
| "\xc7\xc2\x16\x48\x00\x00\x48\xc7\xc0\x9b\x20\x00\x00\x0f\x79\xd0\x48\xc7" |
| "\xc2\x18\x48\x00\x00\x48\xc7\xc0\x93\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc2" |
| "\x1a\x48\x00\x00\x48\xc7\xc0\x93\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x1c" |
| "\x48\x00\x00\x48\xc7\xc0\x93\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x1e\x48" |
| "\x00\x00\x48\xc7\xc0\x93\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x20\x48\x00" |
| "\x00\x48\xc7\xc0\x82\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x22\x48\x00\x00" |
| "\x48\xc7\xc0\x8b\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x1c\x68\x00\x00\x48" |
| "\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x1e\x68\x00\x00\x48\xc7" |
| "\xc0\x00\x91\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x20\x68\x00\x00\x48\xc7\xc0" |
| "\x02\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x06\x28\x00\x00\x48\xc7\xc0\x00" |
| "\x05\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0a\x28\x00\x00\x48\xc7\xc0\x00\x00" |
| "\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0c\x28\x00\x00\x48\xc7\xc0\x00\x00\x00" |
| "\x00\x0f\x79\xd0\x48\xc7\xc2\x0e\x28\x00\x00\x48\xc7\xc0\x00\x00\x00\x00" |
| "\x0f\x79\xd0\x48\xc7\xc2\x10\x28\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f" |
| "\x79\xd0\x0f\x20\xc0\x48\xc7\xc2\x00\x68\x00\x00\x48\x89\xc0\x0f\x79\xd0" |
| "\x0f\x20\xd8\x48\xc7\xc2\x02\x68\x00\x00\x48\x89\xc0\x0f\x79\xd0\x0f\x20" |
| "\xe0\x48\xc7\xc2\x04\x68\x00\x00\x48\x89\xc0\x0f\x79\xd0\x48\xc7\xc0\x18" |
| "\x5f\x00\x00\x48\x8b\x10\x48\xc7\xc0\x20\x5f\x00\x00\x48\x8b\x08\x48\x31" |
| "\xc0\x0f\x78\xd0\x48\x31\xc8\x0f\x79\xd0\x0f\x01\xc2\x48\xc7\xc2\x00\x44" |
| "\x00\x00\x0f\x78\xd0\xf4"; |
| const char kvm_asm64_vm_exit[] = "\x48\xc7\xc3\x00\x44\x00\x00\x0f\x78\xda\x48" |
| "\xc7\xc3\x02\x44\x00\x00\x0f\x78\xd9\x48\xc7" |
| "\xc0\x00\x64\x00\x00\x0f\x78\xc0\x48\xc7\xc3" |
| "\x1e\x68\x00\x00\x0f\x78\xdb\xf4"; |
| const char kvm_asm64_cpl3[] = |
| "\x0f\x20\xc0\x0d\x00\x00\x00\x80\x0f\x22\xc0\xea\xde\xc0\xad\x0b\x50\x00" |
| "\x48\xc7\xc0\xd8\x00\x00\x00\x0f\x00\xd8\x48\xc7\xc0\x6b\x00\x00\x00\x8e" |
| "\xd8\x8e\xc0\x8e\xe0\x8e\xe8\x48\xc7\xc4\x80\x0f\x00\x00\x48\xc7\x04\x24" |
| "\x1d\xba\x00\x00\x48\xc7\x44\x24\x04\x63\x00\x00\x00\x48\xc7\x44\x24\x08" |
| "\x80\x0f\x00\x00\x48\xc7\x44\x24\x0c\x6b\x00\x00\x00\xcb"; |
| |
| #define ADDR_TEXT 0x0000 |
| #define ADDR_GDT 0x1000 |
| #define ADDR_LDT 0x1800 |
| #define ADDR_PML4 0x2000 |
| #define ADDR_PDP 0x3000 |
| #define ADDR_PD 0x4000 |
| #define ADDR_STACK0 0x0f80 |
| #define ADDR_VAR_HLT 0x2800 |
| #define ADDR_VAR_SYSRET 0x2808 |
| #define ADDR_VAR_SYSEXIT 0x2810 |
| #define ADDR_VAR_IDT 0x3800 |
| #define ADDR_VAR_TSS64 0x3a00 |
| #define ADDR_VAR_TSS64_CPL3 0x3c00 |
| #define ADDR_VAR_TSS16 0x3d00 |
| #define ADDR_VAR_TSS16_2 0x3e00 |
| #define ADDR_VAR_TSS16_CPL3 0x3f00 |
| #define ADDR_VAR_TSS32 0x4800 |
| #define ADDR_VAR_TSS32_2 0x4a00 |
| #define ADDR_VAR_TSS32_CPL3 0x4c00 |
| #define ADDR_VAR_TSS32_VM86 0x4e00 |
| #define ADDR_VAR_VMXON_PTR 0x5f00 |
| #define ADDR_VAR_VMCS_PTR 0x5f08 |
| #define ADDR_VAR_VMEXIT_PTR 0x5f10 |
| #define ADDR_VAR_VMWRITE_FLD 0x5f18 |
| #define ADDR_VAR_VMWRITE_VAL 0x5f20 |
| #define ADDR_VAR_VMXON 0x6000 |
| #define ADDR_VAR_VMCS 0x7000 |
| #define ADDR_VAR_VMEXIT_CODE 0x9000 |
| #define ADDR_VAR_USER_CODE 0x9100 |
| #define ADDR_VAR_USER_CODE2 0x9120 |
| |
| #define SEL_LDT (1 << 3) |
| #define SEL_CS16 (2 << 3) |
| #define SEL_DS16 (3 << 3) |
| #define SEL_CS16_CPL3 ((4 << 3) + 3) |
| #define SEL_DS16_CPL3 ((5 << 3) + 3) |
| #define SEL_CS32 (6 << 3) |
| #define SEL_DS32 (7 << 3) |
| #define SEL_CS32_CPL3 ((8 << 3) + 3) |
| #define SEL_DS32_CPL3 ((9 << 3) + 3) |
| #define SEL_CS64 (10 << 3) |
| #define SEL_DS64 (11 << 3) |
| #define SEL_CS64_CPL3 ((12 << 3) + 3) |
| #define SEL_DS64_CPL3 ((13 << 3) + 3) |
| #define SEL_CGATE16 (14 << 3) |
| #define SEL_TGATE16 (15 << 3) |
| #define SEL_CGATE32 (16 << 3) |
| #define SEL_TGATE32 (17 << 3) |
| #define SEL_CGATE64 (18 << 3) |
| #define SEL_CGATE64_HI (19 << 3) |
| #define SEL_TSS16 (20 << 3) |
| #define SEL_TSS16_2 (21 << 3) |
| #define SEL_TSS16_CPL3 ((22 << 3) + 3) |
| #define SEL_TSS32 (23 << 3) |
| #define SEL_TSS32_2 (24 << 3) |
| #define SEL_TSS32_CPL3 ((25 << 3) + 3) |
| #define SEL_TSS32_VM86 (26 << 3) |
| #define SEL_TSS64 (27 << 3) |
| #define SEL_TSS64_HI (28 << 3) |
| #define SEL_TSS64_CPL3 ((29 << 3) + 3) |
| #define SEL_TSS64_CPL3_HI (30 << 3) |
| |
| #define MSR_IA32_FEATURE_CONTROL 0x3a |
| #define MSR_IA32_VMX_BASIC 0x480 |
| #define MSR_IA32_SMBASE 0x9e |
| #define MSR_IA32_SYSENTER_CS 0x174 |
| #define MSR_IA32_SYSENTER_ESP 0x175 |
| #define MSR_IA32_SYSENTER_EIP 0x176 |
| #define MSR_IA32_STAR 0xC0000081 |
| #define MSR_IA32_LSTAR 0xC0000082 |
| #define MSR_IA32_VMX_PROCBASED_CTLS2 0x48B |
| |
| #define NEXT_INSN $0xbadc0de |
| #define PREFIX_SIZE 0xba1d |
| |
| #define KVM_SMI _IO(KVMIO, 0xb7) |
| |
| #define CR0_PE 1 |
| #define CR0_MP (1 << 1) |
| #define CR0_EM (1 << 2) |
| #define CR0_TS (1 << 3) |
| #define CR0_ET (1 << 4) |
| #define CR0_NE (1 << 5) |
| #define CR0_WP (1 << 16) |
| #define CR0_AM (1 << 18) |
| #define CR0_NW (1 << 29) |
| #define CR0_CD (1 << 30) |
| #define CR0_PG (1 << 31) |
| |
| #define CR4_VME 1 |
| #define CR4_PVI (1 << 1) |
| #define CR4_TSD (1 << 2) |
| #define CR4_DE (1 << 3) |
| #define CR4_PSE (1 << 4) |
| #define CR4_PAE (1 << 5) |
| #define CR4_MCE (1 << 6) |
| #define CR4_PGE (1 << 7) |
| #define CR4_PCE (1 << 8) |
| #define CR4_OSFXSR (1 << 8) |
| #define CR4_OSXMMEXCPT (1 << 10) |
| #define CR4_UMIP (1 << 11) |
| #define CR4_VMXE (1 << 13) |
| #define CR4_SMXE (1 << 14) |
| #define CR4_FSGSBASE (1 << 16) |
| #define CR4_PCIDE (1 << 17) |
| #define CR4_OSXSAVE (1 << 18) |
| #define CR4_SMEP (1 << 20) |
| #define CR4_SMAP (1 << 21) |
| #define CR4_PKE (1 << 22) |
| |
| #define EFER_SCE 1 |
| #define EFER_LME (1 << 8) |
| #define EFER_LMA (1 << 10) |
| #define EFER_NXE (1 << 11) |
| #define EFER_SVME (1 << 12) |
| #define EFER_LMSLE (1 << 13) |
| #define EFER_FFXSR (1 << 14) |
| #define EFER_TCE (1 << 15) |
| #define PDE32_PRESENT 1 |
| #define PDE32_RW (1 << 1) |
| #define PDE32_USER (1 << 2) |
| #define PDE32_PS (1 << 7) |
| #define PDE64_PRESENT 1 |
| #define PDE64_RW (1 << 1) |
| #define PDE64_USER (1 << 2) |
| #define PDE64_ACCESSED (1 << 5) |
| #define PDE64_DIRTY (1 << 6) |
| #define PDE64_PS (1 << 7) |
| #define PDE64_G (1 << 8) |
| |
| struct tss16 { |
| uint16_t prev; |
| uint16_t sp0; |
| uint16_t ss0; |
| uint16_t sp1; |
| uint16_t ss1; |
| uint16_t sp2; |
| uint16_t ss2; |
| uint16_t ip; |
| uint16_t flags; |
| uint16_t ax; |
| uint16_t cx; |
| uint16_t dx; |
| uint16_t bx; |
| uint16_t sp; |
| uint16_t bp; |
| uint16_t si; |
| uint16_t di; |
| uint16_t es; |
| uint16_t cs; |
| uint16_t ss; |
| uint16_t ds; |
| uint16_t ldt; |
| } __attribute__((packed)); |
| |
| struct tss32 { |
| uint16_t prev, prevh; |
| uint32_t sp0; |
| uint16_t ss0, ss0h; |
| uint32_t sp1; |
| uint16_t ss1, ss1h; |
| uint32_t sp2; |
| uint16_t ss2, ss2h; |
| uint32_t cr3; |
| uint32_t ip; |
| uint32_t flags; |
| uint32_t ax; |
| uint32_t cx; |
| uint32_t dx; |
| uint32_t bx; |
| uint32_t sp; |
| uint32_t bp; |
| uint32_t si; |
| uint32_t di; |
| uint16_t es, esh; |
| uint16_t cs, csh; |
| uint16_t ss, ssh; |
| uint16_t ds, dsh; |
| uint16_t fs, fsh; |
| uint16_t gs, gsh; |
| uint16_t ldt, ldth; |
| uint16_t trace; |
| uint16_t io_bitmap; |
| } __attribute__((packed)); |
| |
| struct tss64 { |
| uint32_t reserved0; |
| uint64_t rsp[3]; |
| uint64_t reserved1; |
| uint64_t ist[7]; |
| uint64_t reserved2; |
| uint32_t reserved3; |
| uint32_t io_bitmap; |
| } __attribute__((packed)); |
| |
| static void fill_segment_descriptor(uint64_t* dt, uint64_t* lt, |
| struct kvm_segment* seg) |
| { |
| uint16_t index = seg->selector >> 3; |
| uint64_t limit = seg->g ? seg->limit >> 12 : seg->limit; |
| uint64_t sd = (limit & 0xffff) | (seg->base & 0xffffff) << 16 | |
| (uint64_t)seg->type << 40 | (uint64_t)seg->s << 44 | |
| (uint64_t)seg->dpl << 45 | (uint64_t)seg->present << 47 | |
| (limit & 0xf0000ULL) << 48 | (uint64_t)seg->avl << 52 | |
| (uint64_t)seg->l << 53 | (uint64_t)seg->db << 54 | |
| (uint64_t)seg->g << 55 | (seg->base & 0xff000000ULL) << 56; |
| dt[index] = sd; |
| lt[index] = sd; |
| } |
| |
| static void fill_segment_descriptor_dword(uint64_t* dt, uint64_t* lt, |
| struct kvm_segment* seg) |
| { |
| fill_segment_descriptor(dt, lt, seg); |
| uint16_t index = seg->selector >> 3; |
| dt[index + 1] = 0; |
| lt[index + 1] = 0; |
| } |
| |
| static void setup_syscall_msrs(int cpufd, uint16_t sel_cs, uint16_t sel_cs_cpl3) |
| { |
| char buf[sizeof(struct kvm_msrs) + 5 * sizeof(struct kvm_msr_entry)]; |
| memset(buf, 0, sizeof(buf)); |
| struct kvm_msrs* msrs = (struct kvm_msrs*)buf; |
| struct kvm_msr_entry* entries = msrs->entries; |
| msrs->nmsrs = 5; |
| entries[0].index = MSR_IA32_SYSENTER_CS; |
| entries[0].data = sel_cs; |
| entries[1].index = MSR_IA32_SYSENTER_ESP; |
| entries[1].data = ADDR_STACK0; |
| entries[2].index = MSR_IA32_SYSENTER_EIP; |
| entries[2].data = ADDR_VAR_SYSEXIT; |
| entries[3].index = MSR_IA32_STAR; |
| entries[3].data = ((uint64_t)sel_cs << 32) | ((uint64_t)sel_cs_cpl3 << 48); |
| entries[4].index = MSR_IA32_LSTAR; |
| entries[4].data = ADDR_VAR_SYSRET; |
| ioctl(cpufd, KVM_SET_MSRS, msrs); |
| } |
| |
| static void setup_32bit_idt(struct kvm_sregs* sregs, char* host_mem, |
| uintptr_t guest_mem) |
| { |
| sregs->idt.base = guest_mem + ADDR_VAR_IDT; |
| sregs->idt.limit = 0x1ff; |
| uint64_t* idt = (uint64_t*)(host_mem + sregs->idt.base); |
| int i; |
| for (i = 0; i < 32; i++) { |
| struct kvm_segment gate; |
| gate.selector = i << 3; |
| switch (i % 6) { |
| case 0: |
| gate.type = 6; |
| gate.base = SEL_CS16; |
| break; |
| case 1: |
| gate.type = 7; |
| gate.base = SEL_CS16; |
| break; |
| case 2: |
| gate.type = 3; |
| gate.base = SEL_TGATE16; |
| break; |
| case 3: |
| gate.type = 14; |
| gate.base = SEL_CS32; |
| break; |
| case 4: |
| gate.type = 15; |
| gate.base = SEL_CS32; |
| break; |
| case 6: |
| gate.type = 11; |
| gate.base = SEL_TGATE32; |
| break; |
| } |
| gate.limit = guest_mem + ADDR_VAR_USER_CODE2; |
| gate.present = 1; |
| gate.dpl = 0; |
| gate.s = 0; |
| gate.g = 0; |
| gate.db = 0; |
| gate.l = 0; |
| gate.avl = 0; |
| fill_segment_descriptor(idt, idt, &gate); |
| } |
| } |
| |
| static void setup_64bit_idt(struct kvm_sregs* sregs, char* host_mem, |
| uintptr_t guest_mem) |
| { |
| sregs->idt.base = guest_mem + ADDR_VAR_IDT; |
| sregs->idt.limit = 0x1ff; |
| uint64_t* idt = (uint64_t*)(host_mem + sregs->idt.base); |
| int i; |
| for (i = 0; i < 32; i++) { |
| struct kvm_segment gate; |
| gate.selector = (i * 2) << 3; |
| gate.type = (i & 1) ? 14 : 15; |
| gate.base = SEL_CS64; |
| gate.limit = guest_mem + ADDR_VAR_USER_CODE2; |
| gate.present = 1; |
| gate.dpl = 0; |
| gate.s = 0; |
| gate.g = 0; |
| gate.db = 0; |
| gate.l = 0; |
| gate.avl = 0; |
| fill_segment_descriptor_dword(idt, idt, &gate); |
| } |
| } |
| |
| struct kvm_text { |
| uintptr_t typ; |
| const void* text; |
| uintptr_t size; |
| }; |
| |
| struct kvm_opt { |
| uint64_t typ; |
| uint64_t val; |
| }; |
| |
| #define KVM_SETUP_PAGING (1 << 0) |
| #define KVM_SETUP_PAE (1 << 1) |
| #define KVM_SETUP_PROTECTED (1 << 2) |
| #define KVM_SETUP_CPL3 (1 << 3) |
| #define KVM_SETUP_VIRT86 (1 << 4) |
| #define KVM_SETUP_SMM (1 << 5) |
| #define KVM_SETUP_VM (1 << 6) |
| static uintptr_t syz_kvm_setup_cpu(uintptr_t a0, uintptr_t a1, uintptr_t a2, |
| uintptr_t a3, uintptr_t a4, uintptr_t a5, |
| uintptr_t a6, uintptr_t a7) |
| { |
| const int vmfd = a0; |
| const int cpufd = a1; |
| char* const host_mem = (char*)a2; |
| const struct kvm_text* const text_array_ptr = (struct kvm_text*)a3; |
| const uintptr_t text_count = a4; |
| const uintptr_t flags = a5; |
| const struct kvm_opt* const opt_array_ptr = (struct kvm_opt*)a6; |
| uintptr_t opt_count = a7; |
| const uintptr_t page_size = 4 << 10; |
| const uintptr_t ioapic_page = 10; |
| const uintptr_t guest_mem_size = 24 * page_size; |
| const uintptr_t guest_mem = 0; |
| (void)text_count; |
| int text_type = 0; |
| const void* text = 0; |
| uintptr_t text_size = 0; |
| text_type = text_array_ptr[0].typ; |
| text = text_array_ptr[0].text; |
| text_size = text_array_ptr[0].size; |
| uintptr_t i; |
| for (i = 0; i < guest_mem_size / page_size; i++) { |
| struct kvm_userspace_memory_region memreg; |
| memreg.slot = i; |
| memreg.flags = 0; |
| memreg.guest_phys_addr = guest_mem + i * page_size; |
| if (i == ioapic_page) |
| memreg.guest_phys_addr = 0xfec00000; |
| memreg.memory_size = page_size; |
| memreg.userspace_addr = (uintptr_t)host_mem + i * page_size; |
| ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, &memreg); |
| } |
| struct kvm_userspace_memory_region memreg; |
| memreg.slot = 1 + (1 << 16); |
| memreg.flags = 0; |
| memreg.guest_phys_addr = 0x30000; |
| memreg.memory_size = 64 << 10; |
| memreg.userspace_addr = (uintptr_t)host_mem; |
| ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, &memreg); |
| struct kvm_sregs sregs; |
| if (ioctl(cpufd, KVM_GET_SREGS, &sregs)) |
| return -1; |
| struct kvm_regs regs; |
| memset(®s, 0, sizeof(regs)); |
| regs.rip = guest_mem + ADDR_TEXT; |
| regs.rsp = ADDR_STACK0; |
| sregs.gdt.base = guest_mem + ADDR_GDT; |
| sregs.gdt.limit = 256 * sizeof(uint64_t) - 1; |
| uint64_t* gdt = (uint64_t*)(host_mem + sregs.gdt.base); |
| struct kvm_segment seg_ldt; |
| seg_ldt.selector = SEL_LDT; |
| seg_ldt.type = 2; |
| seg_ldt.base = guest_mem + ADDR_LDT; |
| seg_ldt.limit = 256 * sizeof(uint64_t) - 1; |
| seg_ldt.present = 1; |
| seg_ldt.dpl = 0; |
| seg_ldt.s = 0; |
| seg_ldt.g = 0; |
| seg_ldt.db = 1; |
| seg_ldt.l = 0; |
| sregs.ldt = seg_ldt; |
| uint64_t* ldt = (uint64_t*)(host_mem + sregs.ldt.base); |
| struct kvm_segment seg_cs16; |
| seg_cs16.selector = SEL_CS16; |
| seg_cs16.type = 11; |
| seg_cs16.base = 0; |
| seg_cs16.limit = 0xfffff; |
| seg_cs16.present = 1; |
| seg_cs16.dpl = 0; |
| seg_cs16.s = 1; |
| seg_cs16.g = 0; |
| seg_cs16.db = 0; |
| seg_cs16.l = 0; |
| struct kvm_segment seg_ds16 = seg_cs16; |
| seg_ds16.selector = SEL_DS16; |
| seg_ds16.type = 3; |
| struct kvm_segment seg_cs16_cpl3 = seg_cs16; |
| seg_cs16_cpl3.selector = SEL_CS16_CPL3; |
| seg_cs16_cpl3.dpl = 3; |
| struct kvm_segment seg_ds16_cpl3 = seg_ds16; |
| seg_ds16_cpl3.selector = SEL_DS16_CPL3; |
| seg_ds16_cpl3.dpl = 3; |
| struct kvm_segment seg_cs32 = seg_cs16; |
| seg_cs32.selector = SEL_CS32; |
| seg_cs32.db = 1; |
| struct kvm_segment seg_ds32 = seg_ds16; |
| seg_ds32.selector = SEL_DS32; |
| seg_ds32.db = 1; |
| struct kvm_segment seg_cs32_cpl3 = seg_cs32; |
| seg_cs32_cpl3.selector = SEL_CS32_CPL3; |
| seg_cs32_cpl3.dpl = 3; |
| struct kvm_segment seg_ds32_cpl3 = seg_ds32; |
| seg_ds32_cpl3.selector = SEL_DS32_CPL3; |
| seg_ds32_cpl3.dpl = 3; |
| struct kvm_segment seg_cs64 = seg_cs16; |
| seg_cs64.selector = SEL_CS64; |
| seg_cs64.l = 1; |
| struct kvm_segment seg_ds64 = seg_ds32; |
| seg_ds64.selector = SEL_DS64; |
| struct kvm_segment seg_cs64_cpl3 = seg_cs64; |
| seg_cs64_cpl3.selector = SEL_CS64_CPL3; |
| seg_cs64_cpl3.dpl = 3; |
| struct kvm_segment seg_ds64_cpl3 = seg_ds64; |
| seg_ds64_cpl3.selector = SEL_DS64_CPL3; |
| seg_ds64_cpl3.dpl = 3; |
| struct kvm_segment seg_tss32; |
| seg_tss32.selector = SEL_TSS32; |
| seg_tss32.type = 9; |
| seg_tss32.base = ADDR_VAR_TSS32; |
| seg_tss32.limit = 0x1ff; |
| seg_tss32.present = 1; |
| seg_tss32.dpl = 0; |
| seg_tss32.s = 0; |
| seg_tss32.g = 0; |
| seg_tss32.db = 0; |
| seg_tss32.l = 0; |
| struct kvm_segment seg_tss32_2 = seg_tss32; |
| seg_tss32_2.selector = SEL_TSS32_2; |
| seg_tss32_2.base = ADDR_VAR_TSS32_2; |
| struct kvm_segment seg_tss32_cpl3 = seg_tss32; |
| seg_tss32_cpl3.selector = SEL_TSS32_CPL3; |
| seg_tss32_cpl3.base = ADDR_VAR_TSS32_CPL3; |
| struct kvm_segment seg_tss32_vm86 = seg_tss32; |
| seg_tss32_vm86.selector = SEL_TSS32_VM86; |
| seg_tss32_vm86.base = ADDR_VAR_TSS32_VM86; |
| struct kvm_segment seg_tss16 = seg_tss32; |
| seg_tss16.selector = SEL_TSS16; |
| seg_tss16.base = ADDR_VAR_TSS16; |
| seg_tss16.limit = 0xff; |
| seg_tss16.type = 1; |
| struct kvm_segment seg_tss16_2 = seg_tss16; |
| seg_tss16_2.selector = SEL_TSS16_2; |
| seg_tss16_2.base = ADDR_VAR_TSS16_2; |
| seg_tss16_2.dpl = 0; |
| struct kvm_segment seg_tss16_cpl3 = seg_tss16; |
| seg_tss16_cpl3.selector = SEL_TSS16_CPL3; |
| seg_tss16_cpl3.base = ADDR_VAR_TSS16_CPL3; |
| seg_tss16_cpl3.dpl = 3; |
| struct kvm_segment seg_tss64 = seg_tss32; |
| seg_tss64.selector = SEL_TSS64; |
| seg_tss64.base = ADDR_VAR_TSS64; |
| seg_tss64.limit = 0x1ff; |
| struct kvm_segment seg_tss64_cpl3 = seg_tss64; |
| seg_tss64_cpl3.selector = SEL_TSS64_CPL3; |
| seg_tss64_cpl3.base = ADDR_VAR_TSS64_CPL3; |
| seg_tss64_cpl3.dpl = 3; |
| struct kvm_segment seg_cgate16; |
| seg_cgate16.selector = SEL_CGATE16; |
| seg_cgate16.type = 4; |
| seg_cgate16.base = SEL_CS16 | (2 << 16); |
| seg_cgate16.limit = ADDR_VAR_USER_CODE2; |
| seg_cgate16.present = 1; |
| seg_cgate16.dpl = 0; |
| seg_cgate16.s = 0; |
| seg_cgate16.g = 0; |
| seg_cgate16.db = 0; |
| seg_cgate16.l = 0; |
| seg_cgate16.avl = 0; |
| struct kvm_segment seg_tgate16 = seg_cgate16; |
| seg_tgate16.selector = SEL_TGATE16; |
| seg_tgate16.type = 3; |
| seg_cgate16.base = SEL_TSS16_2; |
| seg_tgate16.limit = 0; |
| struct kvm_segment seg_cgate32 = seg_cgate16; |
| seg_cgate32.selector = SEL_CGATE32; |
| seg_cgate32.type = 12; |
| seg_cgate32.base = SEL_CS32 | (2 << 16); |
| struct kvm_segment seg_tgate32 = seg_cgate32; |
| seg_tgate32.selector = SEL_TGATE32; |
| seg_tgate32.type = 11; |
| seg_tgate32.base = SEL_TSS32_2; |
| seg_tgate32.limit = 0; |
| struct kvm_segment seg_cgate64 = seg_cgate16; |
| seg_cgate64.selector = SEL_CGATE64; |
| seg_cgate64.type = 12; |
| seg_cgate64.base = SEL_CS64; |
| int kvmfd = open("/dev/kvm", O_RDWR); |
| char buf[sizeof(struct kvm_cpuid2) + 128 * sizeof(struct kvm_cpuid_entry2)]; |
| memset(buf, 0, sizeof(buf)); |
| struct kvm_cpuid2* cpuid = (struct kvm_cpuid2*)buf; |
| cpuid->nent = 128; |
| ioctl(kvmfd, KVM_GET_SUPPORTED_CPUID, cpuid); |
| ioctl(cpufd, KVM_SET_CPUID2, cpuid); |
| close(kvmfd); |
| const char* text_prefix = 0; |
| int text_prefix_size = 0; |
| char* host_text = host_mem + ADDR_TEXT; |
| if (text_type == 8) { |
| if (flags & KVM_SETUP_SMM) { |
| if (flags & KVM_SETUP_PROTECTED) { |
| sregs.cs = seg_cs16; |
| sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds16; |
| sregs.cr0 |= CR0_PE; |
| } else { |
| sregs.cs.selector = 0; |
| sregs.cs.base = 0; |
| } |
| |
| *(host_mem + ADDR_TEXT) = 0xf4; |
| host_text = host_mem + 0x8000; |
| ioctl(cpufd, KVM_SMI, 0); |
| } else if (flags & KVM_SETUP_VIRT86) { |
| sregs.cs = seg_cs32; |
| sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32; |
| sregs.cr0 |= CR0_PE; |
| sregs.efer |= EFER_SCE; |
| setup_syscall_msrs(cpufd, SEL_CS32, SEL_CS32_CPL3); |
| setup_32bit_idt(&sregs, host_mem, guest_mem); |
| if (flags & KVM_SETUP_PAGING) { |
| uint64_t pd_addr = guest_mem + ADDR_PD; |
| uint64_t* pd = (uint64_t*)(host_mem + ADDR_PD); |
| pd[0] = PDE32_PRESENT | PDE32_RW | PDE32_USER | PDE32_PS; |
| sregs.cr3 = pd_addr; |
| sregs.cr4 |= CR4_PSE; |
| text_prefix = kvm_asm32_paged_vm86; |
| text_prefix_size = sizeof(kvm_asm32_paged_vm86) - 1; |
| } else { |
| text_prefix = kvm_asm32_vm86; |
| text_prefix_size = sizeof(kvm_asm32_vm86) - 1; |
| } |
| } else { |
| sregs.cs.selector = 0; |
| sregs.cs.base = 0; |
| } |
| } else if (text_type == 16) { |
| if (flags & KVM_SETUP_CPL3) { |
| sregs.cs = seg_cs16; |
| sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds16; |
| text_prefix = kvm_asm16_cpl3; |
| text_prefix_size = sizeof(kvm_asm16_cpl3) - 1; |
| } else { |
| sregs.cr0 |= CR0_PE; |
| sregs.cs = seg_cs16; |
| sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds16; |
| } |
| } else if (text_type == 32) { |
| sregs.cr0 |= CR0_PE; |
| sregs.efer |= EFER_SCE; |
| setup_syscall_msrs(cpufd, SEL_CS32, SEL_CS32_CPL3); |
| setup_32bit_idt(&sregs, host_mem, guest_mem); |
| if (flags & KVM_SETUP_SMM) { |
| sregs.cs = seg_cs32; |
| sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32; |
| |
| *(host_mem + ADDR_TEXT) = 0xf4; |
| host_text = host_mem + 0x8000; |
| ioctl(cpufd, KVM_SMI, 0); |
| } else if (flags & KVM_SETUP_PAGING) { |
| sregs.cs = seg_cs32; |
| sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32; |
| uint64_t pd_addr = guest_mem + ADDR_PD; |
| uint64_t* pd = (uint64_t*)(host_mem + ADDR_PD); |
| pd[0] = PDE32_PRESENT | PDE32_RW | PDE32_USER | PDE32_PS; |
| sregs.cr3 = pd_addr; |
| sregs.cr4 |= CR4_PSE; |
| text_prefix = kvm_asm32_paged; |
| text_prefix_size = sizeof(kvm_asm32_paged) - 1; |
| } else if (flags & KVM_SETUP_CPL3) { |
| sregs.cs = seg_cs32_cpl3; |
| sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32_cpl3; |
| } else { |
| sregs.cs = seg_cs32; |
| sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32; |
| } |
| } else { |
| sregs.efer |= EFER_LME | EFER_SCE; |
| sregs.cr0 |= CR0_PE; |
| setup_syscall_msrs(cpufd, SEL_CS64, SEL_CS64_CPL3); |
| setup_64bit_idt(&sregs, host_mem, guest_mem); |
| sregs.cs = seg_cs32; |
| sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32; |
| uint64_t pml4_addr = guest_mem + ADDR_PML4; |
| uint64_t* pml4 = (uint64_t*)(host_mem + ADDR_PML4); |
| uint64_t pdpt_addr = guest_mem + ADDR_PDP; |
| uint64_t* pdpt = (uint64_t*)(host_mem + ADDR_PDP); |
| uint64_t pd_addr = guest_mem + ADDR_PD; |
| uint64_t* pd = (uint64_t*)(host_mem + ADDR_PD); |
| pml4[0] = PDE64_PRESENT | PDE64_RW | PDE64_USER | pdpt_addr; |
| pdpt[0] = PDE64_PRESENT | PDE64_RW | PDE64_USER | pd_addr; |
| pd[0] = PDE64_PRESENT | PDE64_RW | PDE64_USER | PDE64_PS; |
| sregs.cr3 = pml4_addr; |
| sregs.cr4 |= CR4_PAE; |
| if (flags & KVM_SETUP_VM) { |
| sregs.cr0 |= CR0_NE; |
| |
| *((uint64_t*)(host_mem + ADDR_VAR_VMXON_PTR)) = ADDR_VAR_VMXON; |
| *((uint64_t*)(host_mem + ADDR_VAR_VMCS_PTR)) = ADDR_VAR_VMCS; |
| memcpy(host_mem + ADDR_VAR_VMEXIT_CODE, kvm_asm64_vm_exit, |
| sizeof(kvm_asm64_vm_exit) - 1); |
| *((uint64_t*)(host_mem + ADDR_VAR_VMEXIT_PTR)) = ADDR_VAR_VMEXIT_CODE; |
| text_prefix = kvm_asm64_init_vm; |
| text_prefix_size = sizeof(kvm_asm64_init_vm) - 1; |
| } else if (flags & KVM_SETUP_CPL3) { |
| text_prefix = kvm_asm64_cpl3; |
| text_prefix_size = sizeof(kvm_asm64_cpl3) - 1; |
| } else { |
| text_prefix = kvm_asm64_enable_long; |
| text_prefix_size = sizeof(kvm_asm64_enable_long) - 1; |
| } |
| } |
| struct tss16 tss16; |
| memset(&tss16, 0, sizeof(tss16)); |
| tss16.ss0 = tss16.ss1 = tss16.ss2 = SEL_DS16; |
| tss16.sp0 = tss16.sp1 = tss16.sp2 = ADDR_STACK0; |
| tss16.ip = ADDR_VAR_USER_CODE2; |
| tss16.flags = (1 << 1); |
| tss16.cs = SEL_CS16; |
| tss16.es = tss16.ds = tss16.ss = SEL_DS16; |
| tss16.ldt = SEL_LDT; |
| struct tss16* tss16_addr = (struct tss16*)(host_mem + seg_tss16_2.base); |
| memcpy(tss16_addr, &tss16, sizeof(tss16)); |
| memset(&tss16, 0, sizeof(tss16)); |
| tss16.ss0 = tss16.ss1 = tss16.ss2 = SEL_DS16; |
| tss16.sp0 = tss16.sp1 = tss16.sp2 = ADDR_STACK0; |
| tss16.ip = ADDR_VAR_USER_CODE2; |
| tss16.flags = (1 << 1); |
| tss16.cs = SEL_CS16_CPL3; |
| tss16.es = tss16.ds = tss16.ss = SEL_DS16_CPL3; |
| tss16.ldt = SEL_LDT; |
| struct tss16* tss16_cpl3_addr = |
| (struct tss16*)(host_mem + seg_tss16_cpl3.base); |
| memcpy(tss16_cpl3_addr, &tss16, sizeof(tss16)); |
| struct tss32 tss32; |
| memset(&tss32, 0, sizeof(tss32)); |
| tss32.ss0 = tss32.ss1 = tss32.ss2 = SEL_DS32; |
| tss32.sp0 = tss32.sp1 = tss32.sp2 = ADDR_STACK0; |
| tss32.ip = ADDR_VAR_USER_CODE; |
| tss32.flags = (1 << 1) | (1 << 17); |
| tss32.ldt = SEL_LDT; |
| tss32.cr3 = sregs.cr3; |
| tss32.io_bitmap = offsetof(struct tss32, io_bitmap); |
| struct tss32* tss32_addr = (struct tss32*)(host_mem + seg_tss32_vm86.base); |
| memcpy(tss32_addr, &tss32, sizeof(tss32)); |
| memset(&tss32, 0, sizeof(tss32)); |
| tss32.ss0 = tss32.ss1 = tss32.ss2 = SEL_DS32; |
| tss32.sp0 = tss32.sp1 = tss32.sp2 = ADDR_STACK0; |
| tss32.ip = ADDR_VAR_USER_CODE; |
| tss32.flags = (1 << 1); |
| tss32.cr3 = sregs.cr3; |
| tss32.es = tss32.ds = tss32.ss = tss32.gs = tss32.fs = SEL_DS32; |
| tss32.cs = SEL_CS32; |
| tss32.ldt = SEL_LDT; |
| tss32.cr3 = sregs.cr3; |
| tss32.io_bitmap = offsetof(struct tss32, io_bitmap); |
| struct tss32* tss32_cpl3_addr = (struct tss32*)(host_mem + seg_tss32_2.base); |
| memcpy(tss32_cpl3_addr, &tss32, sizeof(tss32)); |
| struct tss64 tss64; |
| memset(&tss64, 0, sizeof(tss64)); |
| tss64.rsp[0] = ADDR_STACK0; |
| tss64.rsp[1] = ADDR_STACK0; |
| tss64.rsp[2] = ADDR_STACK0; |
| tss64.io_bitmap = offsetof(struct tss64, io_bitmap); |
| struct tss64* tss64_addr = (struct tss64*)(host_mem + seg_tss64.base); |
| memcpy(tss64_addr, &tss64, sizeof(tss64)); |
| memset(&tss64, 0, sizeof(tss64)); |
| tss64.rsp[0] = ADDR_STACK0; |
| tss64.rsp[1] = ADDR_STACK0; |
| tss64.rsp[2] = ADDR_STACK0; |
| tss64.io_bitmap = offsetof(struct tss64, io_bitmap); |
| struct tss64* tss64_cpl3_addr = |
| (struct tss64*)(host_mem + seg_tss64_cpl3.base); |
| memcpy(tss64_cpl3_addr, &tss64, sizeof(tss64)); |
| if (text_size > 1000) |
| text_size = 1000; |
| if (text_prefix) { |
| memcpy(host_text, text_prefix, text_prefix_size); |
| void* patch = 0; |
| patch = memmem(host_text, text_prefix_size, "\xde\xc0\xad\x0b", 4); |
| if (patch) |
| *((uint32_t*)patch) = |
| guest_mem + ADDR_TEXT + ((char*)patch - host_text) + 6; |
| uint16_t magic = PREFIX_SIZE; |
| patch = 0; |
| patch = memmem(host_text, text_prefix_size, &magic, sizeof(magic)); |
| if (patch) |
| *((uint16_t*)patch) = guest_mem + ADDR_TEXT + text_prefix_size; |
| } |
| memcpy((void*)(host_text + text_prefix_size), text, text_size); |
| *(host_text + text_prefix_size + text_size) = 0xf4; |
| |
| memcpy(host_mem + ADDR_VAR_USER_CODE, text, text_size); |
| *(host_mem + ADDR_VAR_USER_CODE + text_size) = 0xf4; |
| |
| *(host_mem + ADDR_VAR_HLT) = 0xf4; |
| memcpy(host_mem + ADDR_VAR_SYSRET, "\x0f\x07\xf4", 3); |
| memcpy(host_mem + ADDR_VAR_SYSEXIT, "\x0f\x35\xf4", 3); |
| |
| *(uint64_t*)(host_mem + ADDR_VAR_VMWRITE_FLD) = 0; |
| *(uint64_t*)(host_mem + ADDR_VAR_VMWRITE_VAL) = 0; |
| if (opt_count > 2) |
| opt_count = 2; |
| for (i = 0; i < opt_count; i++) { |
| uint64_t typ = 0; |
| uint64_t val = 0; |
| typ = opt_array_ptr[i].typ; |
| val = opt_array_ptr[i].val; |
| switch (typ % 9) { |
| case 0: |
| sregs.cr0 ^= val & (CR0_MP | CR0_EM | CR0_ET | CR0_NE | CR0_WP | CR0_AM | |
| CR0_NW | CR0_CD); |
| break; |
| case 1: |
| sregs.cr4 ^= |
| val & (CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_MCE | CR4_PGE | |
| CR4_PCE | CR4_OSFXSR | CR4_OSXMMEXCPT | CR4_UMIP | CR4_VMXE | |
| CR4_SMXE | CR4_FSGSBASE | CR4_PCIDE | CR4_OSXSAVE | CR4_SMEP | |
| CR4_SMAP | CR4_PKE); |
| break; |
| case 2: |
| sregs.efer ^= val & (EFER_SCE | EFER_NXE | EFER_SVME | EFER_LMSLE | |
| EFER_FFXSR | EFER_TCE); |
| break; |
| case 3: |
| val &= |
| ((1 << 8) | (1 << 9) | (1 << 10) | (1 << 12) | (1 << 13) | (1 << 14) | |
| (1 << 15) | (1 << 18) | (1 << 19) | (1 << 20) | (1 << 21)); |
| regs.rflags ^= val; |
| tss16_addr->flags ^= val; |
| tss16_cpl3_addr->flags ^= val; |
| tss32_addr->flags ^= val; |
| tss32_cpl3_addr->flags ^= val; |
| break; |
| case 4: |
| seg_cs16.type = val & 0xf; |
| seg_cs32.type = val & 0xf; |
| seg_cs64.type = val & 0xf; |
| break; |
| case 5: |
| seg_cs16_cpl3.type = val & 0xf; |
| seg_cs32_cpl3.type = val & 0xf; |
| seg_cs64_cpl3.type = val & 0xf; |
| break; |
| case 6: |
| seg_ds16.type = val & 0xf; |
| seg_ds32.type = val & 0xf; |
| seg_ds64.type = val & 0xf; |
| break; |
| case 7: |
| seg_ds16_cpl3.type = val & 0xf; |
| seg_ds32_cpl3.type = val & 0xf; |
| seg_ds64_cpl3.type = val & 0xf; |
| break; |
| case 8: |
| *(uint64_t*)(host_mem + ADDR_VAR_VMWRITE_FLD) = (val & 0xffff); |
| *(uint64_t*)(host_mem + ADDR_VAR_VMWRITE_VAL) = (val >> 16); |
| break; |
| default: |
| exit(1); |
| } |
| } |
| regs.rflags |= 2; |
| fill_segment_descriptor(gdt, ldt, &seg_ldt); |
| fill_segment_descriptor(gdt, ldt, &seg_cs16); |
| fill_segment_descriptor(gdt, ldt, &seg_ds16); |
| fill_segment_descriptor(gdt, ldt, &seg_cs16_cpl3); |
| fill_segment_descriptor(gdt, ldt, &seg_ds16_cpl3); |
| fill_segment_descriptor(gdt, ldt, &seg_cs32); |
| fill_segment_descriptor(gdt, ldt, &seg_ds32); |
| fill_segment_descriptor(gdt, ldt, &seg_cs32_cpl3); |
| fill_segment_descriptor(gdt, ldt, &seg_ds32_cpl3); |
| fill_segment_descriptor(gdt, ldt, &seg_cs64); |
| fill_segment_descriptor(gdt, ldt, &seg_ds64); |
| fill_segment_descriptor(gdt, ldt, &seg_cs64_cpl3); |
| fill_segment_descriptor(gdt, ldt, &seg_ds64_cpl3); |
| fill_segment_descriptor(gdt, ldt, &seg_tss32); |
| fill_segment_descriptor(gdt, ldt, &seg_tss32_2); |
| fill_segment_descriptor(gdt, ldt, &seg_tss32_cpl3); |
| fill_segment_descriptor(gdt, ldt, &seg_tss32_vm86); |
| fill_segment_descriptor(gdt, ldt, &seg_tss16); |
| fill_segment_descriptor(gdt, ldt, &seg_tss16_2); |
| fill_segment_descriptor(gdt, ldt, &seg_tss16_cpl3); |
| fill_segment_descriptor_dword(gdt, ldt, &seg_tss64); |
| fill_segment_descriptor_dword(gdt, ldt, &seg_tss64_cpl3); |
| fill_segment_descriptor(gdt, ldt, &seg_cgate16); |
| fill_segment_descriptor(gdt, ldt, &seg_tgate16); |
| fill_segment_descriptor(gdt, ldt, &seg_cgate32); |
| fill_segment_descriptor(gdt, ldt, &seg_tgate32); |
| fill_segment_descriptor_dword(gdt, ldt, &seg_cgate64); |
| if (ioctl(cpufd, KVM_SET_SREGS, &sregs)) |
| return -1; |
| if (ioctl(cpufd, KVM_SET_REGS, ®s)) |
| return -1; |
| return 0; |
| } |
| |
| static void setup_common() |
| { |
| if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) { |
| } |
| } |
| |
| static void loop(); |
| |
| static void sandbox_common() |
| { |
| prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); |
| setpgrp(); |
| setsid(); |
| struct rlimit rlim; |
| rlim.rlim_cur = rlim.rlim_max = 200 << 20; |
| setrlimit(RLIMIT_AS, &rlim); |
| rlim.rlim_cur = rlim.rlim_max = 32 << 20; |
| setrlimit(RLIMIT_MEMLOCK, &rlim); |
| rlim.rlim_cur = rlim.rlim_max = 136 << 20; |
| setrlimit(RLIMIT_FSIZE, &rlim); |
| rlim.rlim_cur = rlim.rlim_max = 1 << 20; |
| setrlimit(RLIMIT_STACK, &rlim); |
| rlim.rlim_cur = rlim.rlim_max = 0; |
| setrlimit(RLIMIT_CORE, &rlim); |
| rlim.rlim_cur = rlim.rlim_max = 256; |
| setrlimit(RLIMIT_NOFILE, &rlim); |
| if (unshare(CLONE_NEWNS)) { |
| } |
| if (unshare(CLONE_NEWIPC)) { |
| } |
| if (unshare(0x02000000)) { |
| } |
| if (unshare(CLONE_NEWUTS)) { |
| } |
| if (unshare(CLONE_SYSVSEM)) { |
| } |
| typedef struct { |
| const char* name; |
| const char* value; |
| } sysctl_t; |
| static const sysctl_t sysctls[] = { |
| {"/proc/sys/kernel/shmmax", "16777216"}, |
| {"/proc/sys/kernel/shmall", "536870912"}, |
| {"/proc/sys/kernel/shmmni", "1024"}, |
| {"/proc/sys/kernel/msgmax", "8192"}, |
| {"/proc/sys/kernel/msgmni", "1024"}, |
| {"/proc/sys/kernel/msgmnb", "1024"}, |
| {"/proc/sys/kernel/sem", "1024 1048576 500 1024"}, |
| }; |
| unsigned i; |
| for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++) |
| write_file(sysctls[i].name, sysctls[i].value); |
| } |
| |
| int wait_for_loop(int pid) |
| { |
| if (pid < 0) |
| exit(1); |
| int status = 0; |
| while (waitpid(-1, &status, __WALL) != pid) { |
| } |
| return WEXITSTATUS(status); |
| } |
| |
| static int do_sandbox_none(void) |
| { |
| if (unshare(CLONE_NEWPID)) { |
| } |
| int pid = fork(); |
| if (pid != 0) |
| return wait_for_loop(pid); |
| setup_common(); |
| sandbox_common(); |
| initialize_netdevices_init(); |
| if (unshare(CLONE_NEWNET)) { |
| } |
| initialize_tun(); |
| initialize_netdevices(); |
| loop(); |
| exit(1); |
| } |
| |
| static void kill_and_wait(int pid, int* status) |
| { |
| kill(-pid, SIGKILL); |
| kill(pid, SIGKILL); |
| int i; |
| for (i = 0; i < 100; i++) { |
| if (waitpid(-1, status, WNOHANG | __WALL) == pid) |
| return; |
| usleep(1000); |
| } |
| DIR* dir = opendir("/sys/fs/fuse/connections"); |
| if (dir) { |
| for (;;) { |
| struct dirent* ent = readdir(dir); |
| if (!ent) |
| break; |
| if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) |
| continue; |
| char abort[300]; |
| snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort", |
| ent->d_name); |
| int fd = open(abort, O_WRONLY); |
| if (fd == -1) { |
| continue; |
| } |
| if (write(fd, abort, 1) < 0) { |
| } |
| close(fd); |
| } |
| closedir(dir); |
| } else { |
| } |
| while (waitpid(-1, status, __WALL) != pid) { |
| } |
| } |
| |
| #define SYZ_HAVE_SETUP_TEST 1 |
| static void setup_test() |
| { |
| prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); |
| setpgrp(); |
| flush_tun(); |
| } |
| |
| #define SYZ_HAVE_RESET_TEST 1 |
| static void reset_test() |
| { |
| int fd; |
| for (fd = 3; fd < 30; fd++) |
| close(fd); |
| } |
| |
| static void execute_one(void); |
| |
| #define WAIT_FLAGS __WALL |
| |
| static void loop(void) |
| { |
| int iter; |
| for (iter = 0;; iter++) { |
| int pid = fork(); |
| if (pid < 0) |
| exit(1); |
| if (pid == 0) { |
| setup_test(); |
| execute_one(); |
| reset_test(); |
| exit(0); |
| } |
| int status = 0; |
| uint64_t start = current_time_ms(); |
| for (;;) { |
| if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid) |
| break; |
| sleep_ms(1); |
| if (current_time_ms() - start < 5 * 1000) |
| continue; |
| kill_and_wait(pid, &status); |
| break; |
| } |
| } |
| } |
| #ifndef __NR_bpf |
| #define __NR_bpf 321 |
| #endif |
| #ifndef __NR_pkey_alloc |
| #define __NR_pkey_alloc 330 |
| #endif |
| #ifndef __NR_pkey_mprotect |
| #define __NR_pkey_mprotect 329 |
| #endif |
| |
| uint64_t r[49] = {0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0x0, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff, |
| 0xffffffffffffffff}; |
| |
| void execute_one(void) |
| { |
| long res = 0; |
| res = syscall(__NR_openat, 0xffffffffffffff9c, 0, 0x800, 0); |
| if (res != -1) |
| r[0] = res; |
| syscall(__NR_write, r[0], 0, 0); |
| syscall(__NR_ioctl, -1, 0x41009432, 0); |
| res = syscall(__NR_socket, 2, 2, 0); |
| if (res != -1) |
| r[1] = res; |
| memcpy((void*)0x200000c0, "\x89\x07\x04\x04\x00", 5); |
| syscall(__NR_setsockopt, r[1], 0, 4, 0x200000c0, 5); |
| memcpy((void*)0x20000080, "syz_tun\x00\x81\x00\x00\x00\x00\x00\x00\x00", 16); |
| syscall(__NR_setsockopt, r[1], 1, 0x19, 0x20000080, 0x10); |
| *(uint16_t*)0x20000240 = 2; |
| *(uint16_t*)0x20000242 = htobe16(0); |
| *(uint32_t*)0x20000244 = htobe32(0xe0000001); |
| syscall(__NR_connect, r[1], 0x20000240, 0x10); |
| syscall(__NR_write, r[1], 0, 0); |
| res = syscall(__NR_dup, 0xffffff9c); |
| if (res != -1) |
| r[2] = res; |
| syscall(__NR_fremovexattr, r[2], 0); |
| res = syscall(__NR_openat, 0xffffffffffffff9c, 0, 0x40, 0); |
| if (res != -1) |
| r[3] = res; |
| res = syscall(__NR_socket, 0, 0x800, 7); |
| if (res != -1) |
| r[4] = res; |
| syscall(__NR_sendto, r[4], 0, 0, 0, 0, 0); |
| syscall(__NR_ioctl, -1, 0x40305652, 0); |
| syscall(__NR_setsockopt, r[4], 0x10f, 0x81, 0, 0); |
| syscall(__NR_ioctl, r[4], 0x5411, 0); |
| syscall(__NR_ioctl, r[3], 0x400454ca, 0); |
| res = syscall(__NR_openat, 0xffffffffffffff9c, 0, 2, 0); |
| if (res != -1) |
| r[5] = res; |
| syscall(__NR_ioctl, r[5], 0xc0106426, 0); |
| syscall(__NR_ioctl, r[5], 0x40086424, 0); |
| syscall(__NR_ioctl, r[5], 0xc010641d, 0); |
| syscall(__NR_socketpair, 1, 5, 0, 0); |
| syscall(__NR_ioctl, -1, 0x8912, 0x400200); |
| res = syscall(__NR_socket, 0xa, 1, 0); |
| if (res != -1) |
| r[6] = res; |
| syscall(__NR_setsockopt, r[6], 6, 0x13, 0, 0); |
| syscall(__NR_connect, r[6], 0, 0); |
| syscall(__NR_setsockopt, r[6], 6, 0x1f, 0, 0); |
| res = syz_open_dev(0, 0x815, 0); |
| if (res != -1) |
| r[7] = res; |
| res = syscall(__NR_ioctl, r[7], 0xae01, 0); |
| if (res != -1) |
| r[8] = res; |
| res = syscall(__NR_ioctl, r[8], 0xae41, 0); |
| if (res != -1) |
| r[9] = res; |
| syz_kvm_setup_cpu(r[8], -1, 0x20fe8000, 0, 0, 0, 0, 0); |
| syz_kvm_setup_cpu(r[8], r[9], 0x20000000, 0, 0, 0, 0, 0); |
| syscall(__NR_socket, 0x10, 3, 0xc); |
| res = syz_open_dev(0, 1, 2); |
| if (res != -1) |
| r[10] = res; |
| syscall(__NR_setsockopt, r[10], 0x84, 0x15, 0, 0); |
| syscall(__NR_ioctl, r[10], 0xab00, r[10]); |
| res = syz_open_dev(0, 7, 0x208a00); |
| if (res != -1) |
| r[11] = res; |
| syscall(__NR_fremovexattr, r[11], 0); |
| syscall(__NR_getsockopt, 0xffffff9c, 0x84, 0x11, 0, 0); |
| syscall(__NR_ioctl, -1, 0x8916, 0); |
| syscall(__NR_ioctl, -1, 0xc0745645, 0); |
| syscall(__NR_ioctl, -1, 0xc0405665, 0); |
| syscall(__NR_getsockopt, 0xffffff9c, 0x84, 0x11, 0, 0); |
| syscall(__NR_bpf, 0x14, 0, 0); |
| res = syz_open_dev(0, 0xeb, 0x10002); |
| if (res != -1) |
| r[12] = res; |
| res = syscall(__NR_openat, 0xffffffffffffff9c, 0, 2, 0); |
| if (res != -1) |
| r[13] = res; |
| syscall(__NR_ioctl, r[13], 0x40087543, 0); |
| syscall(__NR_ioctl, r[12], 0x127e, 0); |
| syscall(__NR_socketpair, 1, 5, 0, 0); |
| syscall(__NR_ioctl, -1, 0x8912, 0x400200); |
| res = syz_open_dev(0, 0xffffffffffff9daa, 0x800000002009); |
| if (res != -1) |
| r[14] = res; |
| syscall(__NR_clone, 0x10000fc, 0, 0x9999999999999999, 0, -1); |
| syscall(__NR_ioctl, r[14], 2, 0); |
| res = syscall(__NR_socket, 0x26, 5, 0); |
| if (res != -1) |
| r[15] = res; |
| syscall(__NR_setsockopt, r[15], 0x117, 1, 0, 0); |
| res = syscall(__NR_openat, 0xffffffffffffff9c, 0, 2, 0); |
| if (res != -1) |
| r[16] = res; |
| syscall(__NR_setsockopt, r[16], 0x84, 5, 0, 0); |
| syscall(__NR_getsockopt, -1, 0x84, 0x76, 0, 0); |
| syscall(__NR_getsockopt, -1, 0x84, 0x76, 0, 0); |
| syscall(__NR_socketpair, 1, 5, 0, 0); |
| syscall(__NR_ioctl, -1, 0x8912, 0x400200); |
| syscall(__NR_connect, -1, 0, 0); |
| syscall(__NR_setsockopt, -1, 6, 0x1f, 0, 0); |
| syz_open_dev(0, 0, 0x20002); |
| syscall(__NR_recvmsg, 0xffffff9c, 0, 0); |
| syscall(__NR_socketpair, 1, 0x1000000000000002, 0, 0); |
| syscall(__NR_ioctl, -1, 0x8912, 0x400200); |
| res = syscall(__NR_socket, 2, 0x4000000000000001, 1); |
| if (res != -1) |
| r[17] = res; |
| syscall(__NR_getpgrp, 0); |
| syscall(__NR_setsockopt, r[17], 6, 0xe, 0, 0); |
| syscall(__NR_getsockopt, -1, 0, 0x10, 0, 0); |
| syscall(__NR_ioctl, -1, 0x8933, 0); |
| syscall(__NR_sendto, r[17], 0, 0, 0x200007fd, 0, 0); |
| syscall(__NR_getsockopt, -1, 0x29, 0x23, 0, 0); |
| syscall(__NR_stat, 0, 0); |
| syscall(__NR_connect, -1, 0, 0xfffffffffffffebb); |
| syscall(__NR_setsockopt, -1, 6, 0x15, 0, 0x25f); |
| syscall(__NR_accept, -1, 0, 0); |
| syscall(__NR_getsockopt, -1, 0, 3, 0, 0); |
| syscall(__NR_setsockopt, -1, 0x29, 0xcc, 0, 0); |
| syscall(__NR_socket, 0xa, 2, 0); |
| syscall(__NR_close, r[17]); |
| res = syz_open_dev(0, 7, 0x208a00); |
| if (res != -1) |
| r[18] = res; |
| syscall(__NR_getsockopt, r[18], 0x84, 0x76, 0, 0); |
| syscall(__NR_getsockopt, r[18], 0x84, 0x6f, 0, 0); |
| res = syscall(__NR_socket, 0xa, 1, 0x84); |
| if (res != -1) |
| r[19] = res; |
| syscall(__NR_setsockopt, r[19], 0x84, 9, 0, 0); |
| syscall(__NR_getsockopt, 0xffffff9c, 0x84, 0x6d, 0, 0); |
| syscall(__NR_socketpair, 1, 5, 0, 0); |
| syscall(__NR_connect, -1, 0, 0); |
| syscall(__NR_setsockopt, -1, 6, 0x1f, 0, 0); |
| syscall(__NR_getsockopt, 0xffffff9c, 0x84, 0x11, 0, 0); |
| syscall(__NR_getsockopt, -1, 0x84, 0x76, 0, 0); |
| syscall(__NR_getsockopt, -1, 0x84, 0x76, 0, 0); |
| syscall(__NR_getsockopt, -1, 0x84, 0x6f, 0, 0); |
| syz_open_dev(0, 0x3f, 0x20000); |
| syscall(__NR_fremovexattr, -1, 0); |
| syscall(__NR_socketpair, 1, 1, 0, 0); |
| syscall(__NR_ioctl, -1, 0x8912, 0x400200); |
| res = syscall(__NR_socket, 0x11, 2, 0); |
| if (res != -1) |
| r[20] = res; |
| syscall(__NR_sendmmsg, r[20], 0, 0, 0); |
| syscall(__NR_socketpair, 1, 5, 0, 0); |
| syscall(__NR_ioctl, -1, 0x8912, 0x400200); |
| res = syscall(__NR_socket, 0xa, 1, 0); |
| if (res != -1) |
| r[21] = res; |
| syscall(__NR_setsockopt, r[21], 6, 0x13, 0, 0); |
| syscall(__NR_setsockopt, r[21], 6, 0x1f, 0, 0); |
| syscall(__NR_getsockopt, r[21], 6, 0xb, 0, 0); |
| res = syscall(__NR_socket, 0xa, 5, 0); |
| if (res != -1) |
| r[22] = res; |
| res = syscall(__NR_socket, 0xa, 5, 0x84); |
| if (res != -1) |
| r[23] = res; |
| syscall(__NR_getsockopt, r[23], 0x84, 0x76, 0, 0); |
| syscall(__NR_socketpair, 1, 0xfffffffffffffffd, 0, 0); |
| syscall(__NR_ioctl, -1, 0x8912, 0x400200); |
| syscall(__NR_sendmsg, r[22], 0, 0x20008844); |
| res = syscall(__NR_openat, 0xffffffffffffff9c, 0, 0x2b0002, 0); |
| if (res != -1) |
| r[24] = res; |
| syscall(__NR_getsockopt, r[24], 0x84, 0x74, 0, 0); |
| syscall(__NR_ioctl, -1, 0x8912, 0x400200); |
| syscall(__NR_openat, 0xffffffffffffff9c, 0, 0x109300, 0); |
| syscall(__NR_bpf, 6, 0, 0); |
| syscall(__NR_getsockopt, 0xffffff9c, 0x84, 0x11, 0, 0); |
| syscall(__NR_getsockopt, -1, 0x84, 0x76, 0, 0); |
| syscall(__NR_getsockopt, -1, 0x84, 0x76, 0, 0); |
| syscall(__NR_listxattr, 0, 0, 0); |
| syscall(__NR_fremovexattr, -1, 0); |
| syscall(__NR_ioctl, -1, 0x81009431, 0); |
| syscall(__NR_ioctl, -1, 0x540f, 0); |
| syscall(__NR_mount, 0, 0, 0, 0, 0); |
| syscall(__NR_openat, 0xffffff9c, 0, 0x80, 8); |
| syscall(__NR_openat, 0xffffffffffffff9c, 0, 0x100, 0); |
| syscall(__NR_openat, 0xffffffffffffff9c, 0, 0x101001, 0); |
| res = syscall(__NR_bpf, 0, 0, 0); |
| if (res != -1) |
| r[25] = res; |
| syscall(__NR_getresuid, 0, 0, 0); |
| syscall(__NR_stat, 0, 0); |
| syscall(__NR_getresgid, 0, 0, 0); |
| syscall(__NR_stat, 0, 0); |
| syscall(__NR_stat, 0, 0); |
| syscall(__NR_fsetxattr, r[25], 0, 0, 0, 1); |
| res = syscall(__NR_openat, 0xffffffffffffff9c, 0, 0x90142, 0); |
| if (res != -1) |
| r[26] = res; |
| syscall(__NR_ioctl, r[26], 0x80084503, 0); |
| syscall(__NR_readv, r[25], 0, 0); |
| syscall(__NR_perf_event_open, 0, 0, 0, -1, 0); |
| syscall(__NR_bpf, 2, 0, 0); |
| syscall(__NR_socketpair, 1, 5, 0, 0); |
| syscall(__NR_ioctl, -1, 0x8912, 0x400200); |
| syscall(__NR_setsockopt, -1, 6, 0x13, 0, 0); |
| syscall(__NR_connect, -1, 0, 0); |
| res = syz_open_dev(0, 7, 0x208a00); |
| if (res != -1) |
| r[27] = res; |
| syscall(__NR_getsockopt, 0xffffff9c, 0x84, 0x11, 0, 0); |
| syscall(__NR_getsockopt, r[27], 0x84, 0x6f, 0, 0); |
| syz_open_dev(0, 4, 0x100); |
| syscall(__NR_fremovexattr, r[27], 0); |
| res = syscall(__NR_creat, 0, 0x30); |
| if (res != -1) |
| r[28] = res; |
| syz_genetlink_get_family_id(0); |
| syscall(__NR_sendmsg, r[28], 0, 0x400c0); |
| syscall(__NR_ioctl, -1, 0x1000008912, 0); |
| syscall(__NR_write, -1, 0, 0); |
| res = syscall(__NR_socket, 0x8000000020, 0x3fffffffffffe, 3); |
| if (res != -1) |
| r[29] = res; |
| syscall(__NR_accept4, r[29], 0, 0, 0x800); |
| syscall(__NR_ioctl, -1, 0x541c, 0); |
| syscall(__NR_ioctl, -1, 0x4054561e, 0); |
| syscall(__NR_socketpair, 1, 5, 0, 0); |
| res = syscall(__NR_socket, 0xa, 1, 0); |
| if (res != -1) |
| r[30] = res; |
| syscall(__NR_connect, r[30], 0, 0); |
| syscall(__NR_setsockopt, -1, 6, 0x1f, 0, 0); |
| res = syz_open_dev(0, 7, 0x208a00); |
| if (res != -1) |
| r[31] = res; |
| syscall(__NR_getsockopt, 0xffffff9c, 0x84, 0x11, 0, 0); |
| syscall(__NR_getsockopt, r[31], 0x84, 0x76, 0, 0); |
| syscall(__NR_getsockopt, r[31], 0x84, 0x6f, 0, 0); |
| syz_open_dev(0, 0x3f, 0x20000); |
| syscall(__NR_listxattr, 0, 0, 0); |
| syscall(__NR_setsockopt, r[31], 0x112, 0xc, 0, 0); |
| syscall(__NR_fremovexattr, r[31], 0); |
| res = syscall(__NR_openat, 0xffffffffffffff9c, 0, 0x21a040, 0); |
| if (res != -1) |
| r[32] = res; |
| syscall(__NR_getsockopt, r[32], 0x10f, 0x82, 0, 0); |
| syscall(__NR_socket, 0x1e, 5, 0); |
| syscall(__NR_epoll_ctl, -1, 1, -1, 0); |
| syscall(__NR_socket, 2, 2, 0x88); |
| res = syscall(__NR_socket, 0xa, 2, 0x11); |
| if (res != -1) |
| r[33] = res; |
| syz_open_dev(0, 8, 0x220400); |
| syscall(__NR_sendmsg, r[33], 0, 0x8000); |
| syscall(__NR_sendmsg, -1, 0, 0x8000); |
| syscall(__NR_sendmsg, r[33], 0, 0); |
| syscall(__NR_ioctl, -1, 0x8912, 0x400200); |
| syscall(__NR_setsockopt, -1, 6, 0x13, 0, 0); |
| syscall(__NR_setsockopt, -1, 6, 0x1f, 0, 0); |
| syscall(__NR_openat, 0xffffffffffffff9c, 0, 0x200, 0); |
| syz_open_dev(0, 1, 0x805); |
| res = syscall(__NR_socket, 0xa, 1, 0); |
| if (res != -1) |
| r[34] = res; |
| syscall(__NR_setsockopt, r[34], 6, 0x1f, 0, 0); |
| syscall(__NR_bind, -1, 0, 0); |
| syscall(__NR_sendto, -1, 0, 0, 0x200007fd, 0, 0); |
| res = syscall(__NR_accept4, -1, 0, 0, 0x80800); |
| if (res != -1) |
| r[35] = res; |
| syscall(__NR_setsockopt, -1, 0x20, 3, 0, 0); |
| syscall(__NR_sendmsg, r[35], 0, 0x20000805); |
| syscall(__NR_read, -1, 0, 0); |
| syscall(__NR_sendmsg, r[35], 0, 4); |
| res = syz_open_dev(0, 7, 0x208a00); |
| if (res != -1) |
| r[36] = res; |
| syscall(__NR_getsockopt, 0xffffff9c, 0x84, 0x11, 0, 0); |
| syscall(__NR_getsockopt, r[36], 0x84, 0x6f, 0, 0); |
| syz_open_dev(0, 0x3f, 0x20000); |
| syz_open_dev(0, 4, 0x100); |
| syscall(__NR_fremovexattr, r[36], 0); |
| syscall(__NR_getpgrp, 0); |
| syscall(__NR_ioctl, -1, 0x8912, 0x400200); |
| syscall(__NR_ioctl, -1, 0x891b, 0); |
| syscall(__NR_socketpair, 1, 5, 0, 0); |
| syscall(__NR_setsockopt, -1, 6, 0x13, 0, 0); |
| syscall(__NR_connect, -1, 0, 0); |
| syscall(__NR_setsockopt, -1, 6, 0x1f, 0, 0); |
| res = syscall(__NR_socket, 0xa, 2, 0x73); |
| if (res != -1) |
| r[37] = res; |
| res = syz_open_dev(0, 0, 0x10000); |
| if (res != -1) |
| r[38] = res; |
| syscall(__NR_ftruncate, r[38], 9); |
| syscall(__NR_sendmsg, r[37], 0, 0); |
| syscall(__NR_ioctl, -1, 0x8912, 0x400200); |
| syscall(__NR_setsockopt, -1, 6, 0x13, 0, 0); |
| syscall(__NR_getsockopt, -1, 6, 0xb, 0, 0); |
| res = syz_open_dev(0, 7, 0x208a00); |
| if (res != -1) |
| r[39] = res; |
| syscall(__NR_getsockopt, 0xffffff9c, 0x84, 0x11, 0, 0); |
| syscall(__NR_getsockopt, r[39], 0x84, 0x76, 0, 0); |
| syscall(__NR_getsockopt, r[39], 0x84, 0x6f, 0, 0); |
| syz_open_dev(0, 0x3f, 0x20000); |
| syz_open_dev(0, 4, 0x100); |
| syz_open_dev(0, 9, 0x8000); |
| syscall(__NR_fremovexattr, r[39], 0); |
| syscall(__NR_getpgrp, 0); |
| syscall(__NR_listxattr, 0, 0, 0); |
| syscall(__NR_ioctl, -1, 0x540f, 0); |
| syscall(__NR_bpf, 0x14, 0, 0); |
| syscall(__NR_write, -1, 0, 0); |
| syscall(__NR_ioctl, -1, 0x408c5333, 0); |
| syscall(__NR_bpf, 0xd, 0, 0); |
| syscall(__NR_connect, -1, 0, 0); |
| syscall(__NR_socketpair, 1, 5, 0, 0); |
| syscall(__NR_ioctl, -1, 0x8912, 0x400200); |
| res = syscall(__NR_shmget, 0, 0x1000, 0, 0x20fff000); |
| if (res != -1) |
| r[40] = res; |
| syscall(__NR_shmctl, r[40], 0xd, 0); |
| res = syscall(__NR_openat, 0xffffffffffffff9c, 0, 0, 0); |
| if (res != -1) |
| r[41] = res; |
| res = syscall(__NR_accept, 0xffffff9c, 0, 0); |
| if (res != -1) |
| r[42] = res; |
| res = syscall(__NR_accept4, -1, 0, 0, 0x80000); |
| if (res != -1) |
| r[43] = res; |
| syscall(__NR_ioctl, r[41], 0x400448c8, 0); |
| syscall(__NR_sendfile, r[42], r[43], 0, 0x1ff); |
| syscall(__NR_shmctl, r[40], 0xc, 0); |
| syscall(__NR_ioctl, r[41], 0x406855c9, 0); |
| syscall(__NR_setsockopt, r[41], 0x84, 0x78, 0, 0); |
| res = syscall(__NR_openat, 0xffffffffffffff9c, 0, 0x8000, 0); |
| if (res != -1) |
| r[44] = res; |
| syscall(__NR_getsockopt, r[41], 0x84, 0x1b, 0, 0); |
| syscall(__NR_bpf, 0xf, 0, 0); |
| syscall(__NR_openat, 0xffffffffffffff9c, 0, 2, 0); |
| syscall(__NR_ioctl, r[41], 0x40045613, 0); |
| syscall(__NR_write, r[41], 0, 0); |
| syscall(__NR_ioctl, r[44], 0x5419, 0); |
| syscall(__NR_write, r[41], 0, 0); |
| syscall(__NR_setsockopt, r[44], 0x84, 2, 0, 0); |
| syscall(__NR_ioctl, r[41], 0xab0a, 1); |
| syscall(__NR_mprotect, 0x20ffc000, 0x4000, 0); |
| res = syz_open_dev(0, 3, 2); |
| if (res != -1) |
| r[45] = res; |
| syscall(__NR_ioctl, r[45], 0x40042408, r[41]); |
| syscall(__NR_setsockopt, r[41], 0x84, 0x18, 0, 0); |
| syscall(__NR_socketpair, 1, 2, 0, 0); |
| res = syscall(__NR_openat, 0xffffffffffffff9c, 0, 0x401, 0); |
| if (res != -1) |
| r[46] = res; |
| syscall(__NR_ioctl, r[46], 0x4040ae72, 0); |
| syscall(__NR_ioctl, -1, 0xc0386106, 0); |
| syscall(__NR_timer_create, 0, 0, 0); |
| res = syz_open_dev(0, 7, 0x208a00); |
| if (res != -1) |
| r[47] = res; |
| syscall(__NR_getsockopt, 0xffffff9c, 0x84, 0x11, 0, 0); |
| syscall(__NR_getsockopt, r[47], 0x84, 0x76, 0, 0); |
| syscall(__NR_getsockopt, r[47], 0x84, 0x76, 0, 0); |
| syscall(__NR_getsockopt, r[47], 0x84, 0x6f, 0, 0); |
| syscall(__NR_listxattr, 0, 0, 0); |
| syz_open_dev(0, 4, 0x100); |
| syscall(__NR_getpgrp, 0); |
| syscall(__NR_timer_create, 6, 0, 0); |
| syscall(__NR_setsockopt, -1, 0x112, 4, 0, 0); |
| syz_open_dev(0, 0x66dd, 0x40); |
| syscall(__NR_request_key, 0, 0, 0, 0); |
| syscall(__NR_getuid); |
| syscall(__NR_ioctl, -1, 0x40045731, 0); |
| syz_genetlink_get_family_id(0); |
| syscall(__NR_sendmsg, -1, 0, 0x80); |
| res = syscall(__NR_pkey_alloc, 0, 3); |
| if (res != -1) |
| r[48] = res; |
| syscall(__NR_pkey_mprotect, 0x20ff9000, 0x4000, 0x1000002, r[48]); |
| syscall(__NR_ioctl, -1, 0x8955, 0); |
| syscall(__NR_socketpair, 1, 5, 0, 0); |
| syscall(__NR_connect, -1, 0, 0); |
| syscall(__NR_setsockopt, -1, 6, 0x1f, 0, 0); |
| syscall(__NR_getsockopt, -1, 6, 0xb, 0, 0); |
| } |
| int main(void) |
| { |
| syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0); |
| do_sandbox_none(); |
| return 0; |
| } |