On 20/08/22 9:56 pm, Florian Westphal wrote:
Harshit Mogalapalli <[email protected]> wrote:
In ebt_do_table() function dereferencing 'private->hook_entry[hook]'
can lead to NULL pointer dereference. So add a check to prevent that.

Hi Florian,

Thanks a lot for checking the patch.

This looks incorrect, i.e. paperimg over the problem.


Okay.

If hook_entry[hook] is NULL, how did this make it to the eval loop?


When I run the reproducer and have 'private->hook_entry[hook]' printed, it was NULL, so thought of adding a NULL check to prevent the NULL dereference.

Attaching the C reproducer.

Regards,
Harshit


I guess ebtables lacks a sanity check on incoming ruleset?

{\rtf1\ansi\ansicpg1252\cocoartf2639
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fmodern\fcharset0 Courier;}
{\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
{\*\expandedcolortbl;;\cssrgb\c0\c0\c0;}
\paperw11900\paperh16840\margl1440\margr1440\vieww11520\viewh8400\viewkind0
\deftab720
\pard\pardeftab720\partightenfactor0

\f0\fs26 \cf0 \expnd0\expndtw0\kerning0
\outl0\strokewidth0 \strokec2 #define _GNU_SOURCE \
\
#include <arpa/inet.h>\
#include <endian.h>\
#include <errno.h>\
#include <fcntl.h>\
#include <net/if.h>\
#include <net/if_arp.h>\
#include <netinet/in.h>\
#include <pthread.h>\
#include <sched.h>\
#include <stdarg.h>\
#include <stdbool.h>\
#include <stdint.h>\
#include <stdio.h>\
#include <stdlib.h>\
#include <string.h>\
#include <sys/epoll.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 <unistd.h>\
\
#include <linux/capability.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/neighbour.h>\
#include <linux/net.h>\
#include <linux/netlink.h>\
#include <linux/rfkill.h>\
#include <linux/rtnetlink.h>\
#include <linux/tcp.h>\
#include <linux/veth.h>\
\
static unsigned long long procid;\
\
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;\
\}\
\
struct nlmsg \{\
        char* pos;\
        int nesting;\
        struct nlattr* nested[8];\
        char buf[4096];\
\};\
\
static void netlink_init(struct nlmsg* nlmsg, 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(struct nlmsg* nlmsg, int typ,\
                         const void* data, int size)\
\{\
        struct nlattr* attr = (struct nlattr*)nlmsg->pos;\
        attr->nla_len = sizeof(*attr) + size;\
        attr->nla_type = typ;\
        if (size > 0)\
                memcpy(attr + 1, data, size);\
        nlmsg->pos += NLMSG_ALIGN(attr->nla_len);\
\}\
\
static void netlink_nest(struct nlmsg* nlmsg, 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(struct nlmsg* nlmsg)\
\{\
        struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];\
        attr->nla_len = nlmsg->pos - (char*)attr;\
\}\
\
static int netlink_send_ext(struct nlmsg* nlmsg, int sock,\
                            uint16_t reply_type, int* reply_len, bool dofail)\
\{\
        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;\
        ssize_t n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0, (struct 
sockaddr*)&addr, sizeof(addr));\
        if (n != (ssize_t)hdr->nlmsg_len) \{\
                if (dofail)\
        exit(1);\
                return -1;\
        \}\
        n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);\
        if (reply_len)\
                *reply_len = 0;\
        if (n < 0) \{\
                if (dofail)\
        exit(1);\
                return -1;\
        \}\
        if (n < (ssize_t)sizeof(struct nlmsghdr)) \{\
                errno = EINVAL;\
                if (dofail)\
        exit(1);\
                return -1;\
        \}\
        if (hdr->nlmsg_type == NLMSG_DONE)\
                return 0;\
        if (reply_len && hdr->nlmsg_type == reply_type) \{\
                *reply_len = n;\
                return 0;\
        \}\
        if (n < (ssize_t)(sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))) 
\{\
                errno = EINVAL;\
                if (dofail)\
        exit(1);\
                return -1;\
        \}\
        if (hdr->nlmsg_type != NLMSG_ERROR) \{\
                errno = EINVAL;\
                if (dofail)\
        exit(1);\
                return -1;\
        \}\
        errno = -((struct nlmsgerr*)(hdr + 1))->error;\
        return -errno;\
\}\
\
static int netlink_send(struct nlmsg* nlmsg, int sock)\
\{\
        return netlink_send_ext(nlmsg, sock, 0, NULL, true);\
\}\
\
static int netlink_query_family_id(struct nlmsg* nlmsg, int sock, const char* 
family_name, bool dofail)\
\{\
        struct genlmsghdr genlhdr;\
        memset(&genlhdr, 0, sizeof(genlhdr));\
        genlhdr.cmd = CTRL_CMD_GETFAMILY;\
        netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));\
        netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, family_name, 
strnlen(family_name, GENL_NAMSIZ - 1) + 1);\
        int n = 0;\
        int err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n, dofail);\
        if (err < 0) \{\
                return -1;\
        \}\
        uint16_t id = 0;\
        struct nlattr* attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN + 
NLMSG_ALIGN(sizeof(genlhdr)));\
        for (; (char*)attr < nlmsg->buf + n; attr = (struct 
nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) \{\
                if (attr->nla_type == CTRL_ATTR_FAMILY_ID) \{\
                        id = *(uint16_t*)(attr + 1);\
                        break;\
                \}\
        \}\
        if (!id) \{\
                errno = EINVAL;\
                return -1;\
        \}\
        recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);\
        return id;\
\}\
\
static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,\
                            unsigned int total_len)\
\{\
        struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);\
        if (offset == total_len || offset + hdr->nlmsg_len > total_len)\
                return -1;\
        return hdr->nlmsg_len;\
\}\
\
static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,\
                                    const char* name)\
\{\
        struct ifinfomsg hdr;\
        memset(&hdr, 0, sizeof(hdr));\
        netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr, 
sizeof(hdr));\
        if (name)\
                netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));\
        netlink_nest(nlmsg, IFLA_LINKINFO);\
        netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));\
\}\
\
static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,\
                               const char* name)\
\{\
        netlink_add_device_impl(nlmsg, type, name);\
        netlink_done(nlmsg);\
        int err = netlink_send(nlmsg, sock);\
        if (err < 0) \{\
        \}\
\}\
\
static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,\
                             const char* peer)\
\{\
        netlink_add_device_impl(nlmsg, "veth", name);\
        netlink_nest(nlmsg, IFLA_INFO_DATA);\
        netlink_nest(nlmsg, VETH_INFO_PEER);\
        nlmsg->pos += sizeof(struct ifinfomsg);\
        netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));\
        netlink_done(nlmsg);\
        netlink_done(nlmsg);\
        netlink_done(nlmsg);\
        int err = netlink_send(nlmsg, sock);\
        if (err < 0) \{\
        \}\
\}\
\
static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,\
                            const char* slave1, const char* slave2)\
\{\
        netlink_add_device_impl(nlmsg, "hsr", name);\
        netlink_nest(nlmsg, IFLA_INFO_DATA);\
        int ifindex1 = if_nametoindex(slave1);\
        netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));\
        int ifindex2 = if_nametoindex(slave2);\
        netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));\
        netlink_done(nlmsg);\
        netlink_done(nlmsg);\
        int err = netlink_send(nlmsg, sock);\
        if (err < 0) \{\
        \}\
\}\
\
static void netlink_add_linked(struct nlmsg* nlmsg, int sock, const char* type, 
const char* name, const char* link)\
\{\
        netlink_add_device_impl(nlmsg, type, name);\
        netlink_done(nlmsg);\
        int ifindex = if_nametoindex(link);\
        netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));\
        int err = netlink_send(nlmsg, sock);\
        if (err < 0) \{\
        \}\
\}\
\
static void netlink_add_vlan(struct nlmsg* nlmsg, int sock, const char* name, 
const char* link, uint16_t id, uint16_t proto)\
\{\
        netlink_add_device_impl(nlmsg, "vlan", name);\
        netlink_nest(nlmsg, IFLA_INFO_DATA);\
        netlink_attr(nlmsg, IFLA_VLAN_ID, &id, sizeof(id));\
        netlink_attr(nlmsg, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));\
        netlink_done(nlmsg);\
        netlink_done(nlmsg);\
        int ifindex = if_nametoindex(link);\
        netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));\
        int err = netlink_send(nlmsg, sock);\
        if (err < 0) \{\
        \}\
\}\
\
static void netlink_add_macvlan(struct nlmsg* nlmsg, int sock, const char* 
name, const char* link)\
\{\
        netlink_add_device_impl(nlmsg, "macvlan", name);\
        netlink_nest(nlmsg, IFLA_INFO_DATA);\
        uint32_t mode = MACVLAN_MODE_BRIDGE;\
        netlink_attr(nlmsg, IFLA_MACVLAN_MODE, &mode, sizeof(mode));\
        netlink_done(nlmsg);\
        netlink_done(nlmsg);\
        int ifindex = if_nametoindex(link);\
        netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));\
        int err = netlink_send(nlmsg, sock);\
        if (err < 0) \{\
        \}\
\}\
\
static void netlink_add_geneve(struct nlmsg* nlmsg, int sock, const char* name, 
uint32_t vni, struct in_addr* addr4, struct in6_addr* addr6)\
\{\
        netlink_add_device_impl(nlmsg, "geneve", name);\
        netlink_nest(nlmsg, IFLA_INFO_DATA);\
        netlink_attr(nlmsg, IFLA_GENEVE_ID, &vni, sizeof(vni));\
        if (addr4)\
                netlink_attr(nlmsg, IFLA_GENEVE_REMOTE, addr4, sizeof(*addr4));\
        if (addr6)\
                netlink_attr(nlmsg, IFLA_GENEVE_REMOTE6, addr6, 
sizeof(*addr6));\
        netlink_done(nlmsg);\
        netlink_done(nlmsg);\
        int err = netlink_send(nlmsg, sock);\
        if (err < 0) \{\
        \}\
\}\
\
#define IFLA_IPVLAN_FLAGS 2\
#define IPVLAN_MODE_L3S 2\
#undef IPVLAN_F_VEPA\
#define IPVLAN_F_VEPA 2\
\
static void netlink_add_ipvlan(struct nlmsg* nlmsg, int sock, const char* name, 
const char* link, uint16_t mode, uint16_t flags)\
\{\
        netlink_add_device_impl(nlmsg, "ipvlan", name);\
        netlink_nest(nlmsg, IFLA_INFO_DATA);\
        netlink_attr(nlmsg, IFLA_IPVLAN_MODE, &mode, sizeof(mode));\
        netlink_attr(nlmsg, IFLA_IPVLAN_FLAGS, &flags, sizeof(flags));\
        netlink_done(nlmsg);\
        netlink_done(nlmsg);\
        int ifindex = if_nametoindex(link);\
        netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));\
        int err = netlink_send(nlmsg, sock);\
        if (err < 0) \{\
        \}\
\}\
\
static void netlink_device_change(struct nlmsg* nlmsg, int sock, const char* 
name, bool up,\
                                  const char* master, const void* mac, int 
macsize,\
                                  const char* new_name)\
\{\
        struct ifinfomsg hdr;\
        memset(&hdr, 0, sizeof(hdr));\
        if (up)\
                hdr.ifi_flags = hdr.ifi_change = IFF_UP;\
        hdr.ifi_index = if_nametoindex(name);\
        netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));\
        if (new_name)\
                netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));\
        if (master) \{\
                int ifindex = if_nametoindex(master);\
                netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));\
        \}\
        if (macsize)\
                netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);\
        int err = netlink_send(nlmsg, sock);\
        if (err < 0) \{\
        \}\
\}\
\
static int netlink_add_addr(struct nlmsg* nlmsg, 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(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr, 
sizeof(hdr));\
        netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);\
        netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);\
        return netlink_send(nlmsg, sock);\
\}\
\
static void netlink_add_addr4(struct nlmsg* nlmsg, 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(nlmsg, sock, dev, &in_addr, 
sizeof(in_addr));\
        if (err < 0) \{\
        \}\
\}\
\
static void netlink_add_addr6(struct nlmsg* nlmsg, 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(nlmsg, sock, dev, &in6_addr, 
sizeof(in6_addr));\
        if (err < 0) \{\
        \}\
\}\
\
static struct nlmsg nlmsg;\
\
#define DEVLINK_FAMILY_NAME "devlink"\
\
#define DEVLINK_CMD_PORT_GET 5\
#define DEVLINK_ATTR_BUS_NAME 1\
#define DEVLINK_ATTR_DEV_NAME 2\
#define DEVLINK_ATTR_NETDEV_NAME 7\
\
static struct nlmsg nlmsg2;\
\
static void initialize_devlink_ports(const char* bus_name, const char* 
dev_name,\
                                     const char* netdev_prefix)\
\{\
        struct genlmsghdr genlhdr;\
        int len, total_len, id, err, offset;\
        uint16_t netdev_index;\
        int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);\
        if (sock == -1)\
        exit(1);\
        int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);\
        if (rtsock == -1)\
        exit(1);\
        id = netlink_query_family_id(&nlmsg, sock, DEVLINK_FAMILY_NAME, true);\
        if (id == -1)\
                goto error;\
        memset(&genlhdr, 0, sizeof(genlhdr));\
        genlhdr.cmd = DEVLINK_CMD_PORT_GET;\
        netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));\
        netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) 
+ 1);\
        netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) 
+ 1);\
        err = netlink_send_ext(&nlmsg, sock, id, &total_len, true);\
        if (err < 0) \{\
                goto error;\
        \}\
        offset = 0;\
        netdev_index = 0;\
        while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) \{\
                struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + 
NLMSG_HDRLEN + NLMSG_ALIGN(sizeof(genlhdr)));\
                for (; (char*)attr < nlmsg.buf + offset + len; attr = (struct 
nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) \{\
                        if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) \{\
                                char* port_name;\
                                char netdev_name[IFNAMSIZ];\
                                port_name = (char*)(attr + 1);\
                                snprintf(netdev_name, sizeof(netdev_name), 
"%s%d", netdev_prefix, netdev_index);\
                                netlink_device_change(&nlmsg2, rtsock, 
port_name, true, 0, 0, 0, netdev_name);\
                                break;\
                        \}\
                \}\
                offset += len;\
                netdev_index++;\
        \}\
error:\
        close(rtsock);\
        close(sock);\
\}\
\
#define DEV_IPV4 "172.20.20.%d"\
#define DEV_IPV6 "fe80::%02x"\
#define DEV_MAC 0x00aaaaaaaaaa\
\
static void netdevsim_add(unsigned int addr, unsigned int port_count)\
\{\
        char buf[16];\
        sprintf(buf, "%u %u", addr, port_count);\
        if (write_file("/sys/bus/netdevsim/new_device", buf)) \{\
                snprintf(buf, sizeof(buf), "netdevsim%d", addr);\
                initialize_devlink_ports("netdevsim", buf, "netdevsim");\
        \}\
\}\
\
#define WG_GENL_NAME "wireguard"\
enum wg_cmd \{\
        WG_CMD_GET_DEVICE,\
        WG_CMD_SET_DEVICE,\
\};\
enum wgdevice_attribute \{\
        WGDEVICE_A_UNSPEC,\
        WGDEVICE_A_IFINDEX,\
        WGDEVICE_A_IFNAME,\
        WGDEVICE_A_PRIVATE_KEY,\
        WGDEVICE_A_PUBLIC_KEY,\
        WGDEVICE_A_FLAGS,\
        WGDEVICE_A_LISTEN_PORT,\
        WGDEVICE_A_FWMARK,\
        WGDEVICE_A_PEERS,\
\};\
enum wgpeer_attribute \{\
        WGPEER_A_UNSPEC,\
        WGPEER_A_PUBLIC_KEY,\
        WGPEER_A_PRESHARED_KEY,\
        WGPEER_A_FLAGS,\
        WGPEER_A_ENDPOINT,\
        WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,\
        WGPEER_A_LAST_HANDSHAKE_TIME,\
        WGPEER_A_RX_BYTES,\
        WGPEER_A_TX_BYTES,\
        WGPEER_A_ALLOWEDIPS,\
        WGPEER_A_PROTOCOL_VERSION,\
\};\
enum wgallowedip_attribute \{\
        WGALLOWEDIP_A_UNSPEC,\
        WGALLOWEDIP_A_FAMILY,\
        WGALLOWEDIP_A_IPADDR,\
        WGALLOWEDIP_A_CIDR_MASK,\
\};\
\
static void netlink_wireguard_setup(void)\
\{\
        const char ifname_a[] = "wg0";\
        const char ifname_b[] = "wg1";\
        const char ifname_c[] = "wg2";\
        const char private_a[] = 
"\\xa0\\x5c\\xa8\\x4f\\x6c\\x9c\\x8e\\x38\\x53\\xe2\\xfd\\x7a\\x70\\xae\\x0f\\xb2\\x0f\\xa1\\x52\\x60\\x0c\\xb0\\x08\\x45\\x17\\x4f\\x08\\x07\\x6f\\x8d\\x78\\x43";\
        const char private_b[] = 
"\\xb0\\x80\\x73\\xe8\\xd4\\x4e\\x91\\xe3\\xda\\x92\\x2c\\x22\\x43\\x82\\x44\\xbb\\x88\\x5c\\x69\\xe2\\x69\\xc8\\xe9\\xd8\\x35\\xb1\\x14\\x29\\x3a\\x4d\\xdc\\x6e";\
        const char private_c[] = 
"\\xa0\\xcb\\x87\\x9a\\x47\\xf5\\xbc\\x64\\x4c\\x0e\\x69\\x3f\\xa6\\xd0\\x31\\xc7\\x4a\\x15\\x53\\xb6\\xe9\\x01\\xb9\\xff\\x2f\\x51\\x8c\\x78\\x04\\x2f\\xb5\\x42";\
        const char public_a[] = 
"\\x97\\x5c\\x9d\\x81\\xc9\\x83\\xc8\\x20\\x9e\\xe7\\x81\\x25\\x4b\\x89\\x9f\\x8e\\xd9\\x25\\xae\\x9f\\x09\\x23\\xc2\\x3c\\x62\\xf5\\x3c\\x57\\xcd\\xbf\\x69\\x1c";\
        const char public_b[] = 
"\\xd1\\x73\\x28\\x99\\xf6\\x11\\xcd\\x89\\x94\\x03\\x4d\\x7f\\x41\\x3d\\xc9\\x57\\x63\\x0e\\x54\\x93\\xc2\\x85\\xac\\xa4\\x00\\x65\\xcb\\x63\\x11\\xbe\\x69\\x6b";\
        const char public_c[] = 
"\\xf4\\x4d\\xa3\\x67\\xa8\\x8e\\xe6\\x56\\x4f\\x02\\x02\\x11\\x45\\x67\\x27\\x08\\x2f\\x5c\\xeb\\xee\\x8b\\x1b\\xf5\\xeb\\x73\\x37\\x34\\x1b\\x45\\x9b\\x39\\x22";\
        const uint16_t listen_a = 20001;\
        const uint16_t listen_b = 20002;\
        const uint16_t listen_c = 20003;\
        const uint16_t af_inet = AF_INET;\
        const uint16_t af_inet6 = AF_INET6;\
        const struct sockaddr_in endpoint_b_v4 = \{\
            .sin_family = AF_INET,\
            .sin_port = htons(listen_b),\
            .sin_addr = \{htonl(INADDR_LOOPBACK)\}\};\
        const struct sockaddr_in endpoint_c_v4 = \{\
            .sin_family = AF_INET,\
            .sin_port = htons(listen_c),\
            .sin_addr = \{htonl(INADDR_LOOPBACK)\}\};\
        struct sockaddr_in6 endpoint_a_v6 = \{\
            .sin6_family = AF_INET6,\
            .sin6_port = htons(listen_a)\};\
        endpoint_a_v6.sin6_addr = in6addr_loopback;\
        struct sockaddr_in6 endpoint_c_v6 = \{\
            .sin6_family = AF_INET6,\
            .sin6_port = htons(listen_c)\};\
        endpoint_c_v6.sin6_addr = in6addr_loopback;\
        const struct in_addr first_half_v4 = \{0\};\
        const struct in_addr second_half_v4 = \{(uint32_t)htonl(128 << 24)\};\
        const struct in6_addr first_half_v6 = \{\{\{0\}\}\};\
        const struct in6_addr second_half_v6 = \{\{\{0x80\}\}\};\
        const uint8_t half_cidr = 1;\
        const uint16_t persistent_keepalives[] = \{1, 3, 7, 9, 14, 19\};\
        struct genlmsghdr genlhdr = \{\
            .cmd = WG_CMD_SET_DEVICE,\
            .version = 1\};\
        int sock;\
        int id, err;\
        sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);\
        if (sock == -1) \{\
                return;\
        \}\
        id = netlink_query_family_id(&nlmsg, sock, WG_GENL_NAME, true);\
        if (id == -1)\
                goto error;\
        netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));\
        netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_a, strlen(ifname_a) + 
1);\
        netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_a, 32);\
        netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_a, 2);\
        netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);\
        netlink_nest(&nlmsg, NLA_F_NESTED | 0);\
        netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);\
        netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4, 
sizeof(endpoint_b_v4));\
        netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, 
&persistent_keepalives[0], 2);\
        netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);\
        netlink_nest(&nlmsg, NLA_F_NESTED | 0);\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4, 
sizeof(first_half_v4));\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);\
        netlink_done(&nlmsg);\
        netlink_nest(&nlmsg, NLA_F_NESTED | 0);\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6, 
sizeof(first_half_v6));\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);\
        netlink_done(&nlmsg);\
        netlink_done(&nlmsg);\
        netlink_done(&nlmsg);\
        netlink_nest(&nlmsg, NLA_F_NESTED | 0);\
        netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);\
        netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v6, 
sizeof(endpoint_c_v6));\
        netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, 
&persistent_keepalives[1], 2);\
        netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);\
        netlink_nest(&nlmsg, NLA_F_NESTED | 0);\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4, 
sizeof(second_half_v4));\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);\
        netlink_done(&nlmsg);\
        netlink_nest(&nlmsg, NLA_F_NESTED | 0);\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6, 
sizeof(second_half_v6));\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);\
        netlink_done(&nlmsg);\
        netlink_done(&nlmsg);\
        netlink_done(&nlmsg);\
        netlink_done(&nlmsg);\
        err = netlink_send(&nlmsg, sock);\
        if (err < 0) \{\
        \}\
        netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));\
        netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_b, strlen(ifname_b) + 
1);\
        netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_b, 32);\
        netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_b, 2);\
        netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);\
        netlink_nest(&nlmsg, NLA_F_NESTED | 0);\
        netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);\
        netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6, 
sizeof(endpoint_a_v6));\
        netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, 
&persistent_keepalives[2], 2);\
        netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);\
        netlink_nest(&nlmsg, NLA_F_NESTED | 0);\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4, 
sizeof(first_half_v4));\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);\
        netlink_done(&nlmsg);\
        netlink_nest(&nlmsg, NLA_F_NESTED | 0);\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6, 
sizeof(first_half_v6));\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);\
        netlink_done(&nlmsg);\
        netlink_done(&nlmsg);\
        netlink_done(&nlmsg);\
        netlink_nest(&nlmsg, NLA_F_NESTED | 0);\
        netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);\
        netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v4, 
sizeof(endpoint_c_v4));\
        netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, 
&persistent_keepalives[3], 2);\
        netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);\
        netlink_nest(&nlmsg, NLA_F_NESTED | 0);\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4, 
sizeof(second_half_v4));\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);\
        netlink_done(&nlmsg);\
        netlink_nest(&nlmsg, NLA_F_NESTED | 0);\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6, 
sizeof(second_half_v6));\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);\
        netlink_done(&nlmsg);\
        netlink_done(&nlmsg);\
        netlink_done(&nlmsg);\
        netlink_done(&nlmsg);\
        err = netlink_send(&nlmsg, sock);\
        if (err < 0) \{\
        \}\
        netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));\
        netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_c, strlen(ifname_c) + 
1);\
        netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_c, 32);\
        netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_c, 2);\
        netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);\
        netlink_nest(&nlmsg, NLA_F_NESTED | 0);\
        netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);\
        netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6, 
sizeof(endpoint_a_v6));\
        netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, 
&persistent_keepalives[4], 2);\
        netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);\
        netlink_nest(&nlmsg, NLA_F_NESTED | 0);\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4, 
sizeof(first_half_v4));\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);\
        netlink_done(&nlmsg);\
        netlink_nest(&nlmsg, NLA_F_NESTED | 0);\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6, 
sizeof(first_half_v6));\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);\
        netlink_done(&nlmsg);\
        netlink_done(&nlmsg);\
        netlink_done(&nlmsg);\
        netlink_nest(&nlmsg, NLA_F_NESTED | 0);\
        netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);\
        netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4, 
sizeof(endpoint_b_v4));\
        netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, 
&persistent_keepalives[5], 2);\
        netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);\
        netlink_nest(&nlmsg, NLA_F_NESTED | 0);\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4, 
sizeof(second_half_v4));\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);\
        netlink_done(&nlmsg);\
        netlink_nest(&nlmsg, NLA_F_NESTED | 0);\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6, 
sizeof(second_half_v6));\
        netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);\
        netlink_done(&nlmsg);\
        netlink_done(&nlmsg);\
        netlink_done(&nlmsg);\
        netlink_done(&nlmsg);\
        err = netlink_send(&nlmsg, sock);\
        if (err < 0) \{\
        \}\
\
error:\
        close(sock);\
\}\
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\},\
            \{"xfrm", "xfrm0"\},\
            \{"wireguard", "wg0"\},\
            \{"wireguard", "wg1"\},\
            \{"wireguard", "wg2"\},\
        \};\
        const char* devmasters[] = \{"bridge", "bond", "team", "batadv"\};\
        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\},\
            \{"vxcan0", 0, true\},\
            \{"vxcan1", 0, true\},\
            \{"caif0", ETH_ALEN\},\
            \{"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)\
        exit(1);\
        unsigned i;\
        for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)\
                netlink_add_device(&nlmsg, 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(&nlmsg, sock, slave0, veth0);\
                sprintf(slave1, "%s_slave_1", devmasters[i]);\
                sprintf(veth1, "veth1_to_%s", devmasters[i]);\
                netlink_add_veth(&nlmsg, sock, slave1, veth1);\
                sprintf(master, "%s0", devmasters[i]);\
                netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 
0, NULL);\
                netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 
0, NULL);\
        \}\
        netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, 
NULL);\
        netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, 
NULL);\
        netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");\
        netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");\
        netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");\
        netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, 
NULL);\
        netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, 
NULL);\
        netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");\
        netlink_add_linked(&nlmsg, sock, "virt_wifi", "virt_wifi0", 
"veth1_virt_wifi");\
        netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");\
        netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, 
htons(ETH_P_8021Q));\
        netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, 
htons(ETH_P_8021AD));\
        netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");\
        netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");\
        netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", 
IPVLAN_MODE_L2, 0);\
        netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", 
IPVLAN_MODE_L3S, IPVLAN_F_VEPA);\
        netlink_add_veth(&nlmsg, sock, "veth0_macvtap", "veth1_macvtap");\
        netlink_add_linked(&nlmsg, sock, "macvtap", "macvtap0", 
"veth0_macvtap");\
        netlink_add_linked(&nlmsg, sock, "macsec", "macsec0", "veth1_macvtap");\
        char addr[32];\
        sprintf(addr, DEV_IPV4, 14 + 10);\
        struct in_addr geneve_addr4;\
        if (inet_pton(AF_INET, addr, &geneve_addr4) <= 0)\
        exit(1);\
        struct in6_addr geneve_addr6;\
        if (inet_pton(AF_INET6, "fc00::01", &geneve_addr6) <= 0)\
        exit(1);\
        netlink_add_geneve(&nlmsg, sock, "geneve0", 0, &geneve_addr4, 0);\
        netlink_add_geneve(&nlmsg, sock, "geneve1", 1, 0, &geneve_addr6);\
        netdevsim_add((int)procid, 4);\
        netlink_wireguard_setup();\
        for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) \{\
                char addr[32];\
                sprintf(addr, DEV_IPV4, i + 10);\
                netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);\
                if (!devices[i].noipv6) \{\
                        sprintf(addr, DEV_IPV6, i + 10);\
                        netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);\
                \}\
                uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);\
                netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, 
&macaddr, devices[i].macsize, NULL);\
        \}\
        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(&nlmsg, sock, dev, addr);\
                if (!devtypes[i].noipv6) \{\
                        sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);\
                        netlink_add_addr6(&nlmsg, 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(&nlmsg, sock, dev, !devtypes[i].noup, 0, 
&macaddr, macsize, NULL);\
        \}\
        close(sock);\
\}\
\
#define MAX_FDS 30\
\
#define BTPROTO_HCI 1\
#define ACL_LINK 1\
#define SCAN_PAGE 2\
\
typedef struct \{\
        uint8_t b[6];\
\} __attribute__((packed)) bdaddr_t;\
\
#define HCI_COMMAND_PKT 1\
#define HCI_EVENT_PKT 4\
#define HCI_VENDOR_PKT 0xff\
\
struct hci_command_hdr \{\
        uint16_t opcode;\
        uint8_t plen;\
\} __attribute__((packed));\
\
struct hci_event_hdr \{\
        uint8_t evt;\
        uint8_t plen;\
\} __attribute__((packed));\
\
#define HCI_EV_CONN_COMPLETE 0x03\
struct hci_ev_conn_complete \{\
        uint8_t status;\
        uint16_t handle;\
        bdaddr_t bdaddr;\
        uint8_t link_type;\
        uint8_t encr_mode;\
\} __attribute__((packed));\
\
#define HCI_EV_CONN_REQUEST 0x04\
struct hci_ev_conn_request \{\
        bdaddr_t bdaddr;\
        uint8_t dev_class[3];\
        uint8_t link_type;\
\} __attribute__((packed));\
\
#define HCI_EV_REMOTE_FEATURES 0x0b\
struct hci_ev_remote_features \{\
        uint8_t status;\
        uint16_t handle;\
        uint8_t features[8];\
\} __attribute__((packed));\
\
#define HCI_EV_CMD_COMPLETE 0x0e\
struct hci_ev_cmd_complete \{\
        uint8_t ncmd;\
        uint16_t opcode;\
\} __attribute__((packed));\
\
#define HCI_OP_WRITE_SCAN_ENABLE 0x0c1a\
\
#define HCI_OP_READ_BUFFER_SIZE 0x1005\
struct hci_rp_read_buffer_size \{\
        uint8_t status;\
        uint16_t acl_mtu;\
        uint8_t sco_mtu;\
        uint16_t acl_max_pkt;\
        uint16_t sco_max_pkt;\
\} __attribute__((packed));\
\
#define HCI_OP_READ_BD_ADDR 0x1009\
struct hci_rp_read_bd_addr \{\
        uint8_t status;\
        bdaddr_t bdaddr;\
\} __attribute__((packed));\
\
#define HCI_EV_LE_META 0x3e\
struct hci_ev_le_meta \{\
        uint8_t subevent;\
\} __attribute__((packed));\
\
#define HCI_EV_LE_CONN_COMPLETE 0x01\
struct hci_ev_le_conn_complete \{\
        uint8_t status;\
        uint16_t handle;\
        uint8_t role;\
        uint8_t bdaddr_type;\
        bdaddr_t bdaddr;\
        uint16_t interval;\
        uint16_t latency;\
        uint16_t supervision_timeout;\
        uint8_t clk_accurancy;\
\} __attribute__((packed));\
\
struct hci_dev_req \{\
        uint16_t dev_id;\
        uint32_t dev_opt;\
\};\
\
struct vhci_vendor_pkt \{\
        uint8_t type;\
        uint8_t opcode;\
        uint16_t id;\
\};\
\
#define HCIDEVUP _IOW('H', 201, int)\
#define HCISETSCAN _IOW('H', 221, int)\
\
static int vhci_fd = -1;\
\
static void rfkill_unblock_all()\
\{\
        int fd = open("/dev/rfkill", O_WRONLY);\
        if (fd < 0)\
        exit(1);\
        struct rfkill_event event = \{0\};\
        event.idx = 0;\
        event.type = RFKILL_TYPE_ALL;\
        event.op = RFKILL_OP_CHANGE_ALL;\
        event.soft = 0;\
        event.hard = 0;\
        if (write(fd, &event, sizeof(event)) < 0)\
        exit(1);\
        close(fd);\
\}\
\
static void hci_send_event_packet(int fd, uint8_t evt, void* data, size_t 
data_len)\
\{\
        struct iovec iv[3];\
        struct hci_event_hdr hdr;\
        hdr.evt = evt;\
        hdr.plen = data_len;\
        uint8_t type = HCI_EVENT_PKT;\
        iv[0].iov_base = &type;\
        iv[0].iov_len = sizeof(type);\
        iv[1].iov_base = &hdr;\
        iv[1].iov_len = sizeof(hdr);\
        iv[2].iov_base = data;\
        iv[2].iov_len = data_len;\
        if (writev(fd, iv, sizeof(iv) / sizeof(struct iovec)) < 0)\
        exit(1);\
\}\
\
static void hci_send_event_cmd_complete(int fd, uint16_t opcode, void* data, 
size_t data_len)\
\{\
        struct iovec iv[4];\
        struct hci_event_hdr hdr;\
        hdr.evt = HCI_EV_CMD_COMPLETE;\
        hdr.plen = sizeof(struct hci_ev_cmd_complete) + data_len;\
        struct hci_ev_cmd_complete evt_hdr;\
        evt_hdr.ncmd = 1;\
        evt_hdr.opcode = opcode;\
        uint8_t type = HCI_EVENT_PKT;\
        iv[0].iov_base = &type;\
        iv[0].iov_len = sizeof(type);\
        iv[1].iov_base = &hdr;\
        iv[1].iov_len = sizeof(hdr);\
        iv[2].iov_base = &evt_hdr;\
        iv[2].iov_len = sizeof(evt_hdr);\
        iv[3].iov_base = data;\
        iv[3].iov_len = data_len;\
        if (writev(fd, iv, sizeof(iv) / sizeof(struct iovec)) < 0)\
        exit(1);\
\}\
\
static bool process_command_pkt(int fd, char* buf, ssize_t buf_size)\
\{\
        struct hci_command_hdr* hdr = (struct hci_command_hdr*)buf;\
        if (buf_size < (ssize_t)sizeof(struct hci_command_hdr) ||\
            hdr->plen != buf_size - sizeof(struct hci_command_hdr))\
        exit(1);\
        switch (hdr->opcode) \{\
        case HCI_OP_WRITE_SCAN_ENABLE: \{\
                uint8_t status = 0;\
                hci_send_event_cmd_complete(fd, hdr->opcode, &status, 
sizeof(status));\
                return true;\
        \}\
        case HCI_OP_READ_BD_ADDR: \{\
                struct hci_rp_read_bd_addr rp = \{0\};\
                rp.status = 0;\
                memset(&rp.bdaddr, 0xaa, 6);\
                hci_send_event_cmd_complete(fd, hdr->opcode, &rp, sizeof(rp));\
                return false;\
        \}\
        case HCI_OP_READ_BUFFER_SIZE: \{\
                struct hci_rp_read_buffer_size rp = \{0\};\
                rp.status = 0;\
                rp.acl_mtu = 1021;\
                rp.sco_mtu = 96;\
                rp.acl_max_pkt = 4;\
                rp.sco_max_pkt = 6;\
                hci_send_event_cmd_complete(fd, hdr->opcode, &rp, sizeof(rp));\
                return false;\
        \}\
        \}\
        char dummy[0xf9] = \{0\};\
        hci_send_event_cmd_complete(fd, hdr->opcode, dummy, sizeof(dummy));\
        return false;\
\}\
\
static void* event_thread(void* arg)\
\{\
        while (1) \{\
                char buf[1024] = \{0\};\
                ssize_t buf_size = read(vhci_fd, buf, sizeof(buf));\
                if (buf_size < 0)\
        exit(1);\
                if (buf_size > 0 && buf[0] == HCI_COMMAND_PKT) \{\
                        if (process_command_pkt(vhci_fd, buf + 1, buf_size - 
1))\
                                break;\
                \}\
        \}\
        return NULL;\
\}\
#define HCI_HANDLE_1 200\
#define HCI_HANDLE_2 201\
\
static void initialize_vhci()\
\{\
        int hci_sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);\
        if (hci_sock < 0)\
        exit(1);\
        vhci_fd = open("/dev/vhci", O_RDWR);\
        if (vhci_fd == -1)\
        exit(1);\
        const int kVhciFd = 202;\
        if (dup2(vhci_fd, kVhciFd) < 0)\
        exit(1);\
        close(vhci_fd);\
        vhci_fd = kVhciFd;\
        struct vhci_vendor_pkt vendor_pkt;\
        if (read(vhci_fd, &vendor_pkt, sizeof(vendor_pkt)) != 
sizeof(vendor_pkt))\
        exit(1);\
        if (vendor_pkt.type != HCI_VENDOR_PKT)\
        exit(1);\
        pthread_t th;\
        if (pthread_create(&th, NULL, event_thread, NULL))\
        exit(1);\
        int ret = ioctl(hci_sock, HCIDEVUP, vendor_pkt.id);\
        if (ret) \{\
                if (errno == ERFKILL) \{\
                        rfkill_unblock_all();\
                        ret = ioctl(hci_sock, HCIDEVUP, vendor_pkt.id);\
                \}\
                if (ret && errno != EALREADY)\
        exit(1);\
        \}\
        struct hci_dev_req dr = \{0\};\
        dr.dev_id = vendor_pkt.id;\
        dr.dev_opt = SCAN_PAGE;\
        if (ioctl(hci_sock, HCISETSCAN, &dr))\
        exit(1);\
        struct hci_ev_conn_request request;\
        memset(&request, 0, sizeof(request));\
        memset(&request.bdaddr, 0xaa, 6);\
        *(uint8_t*)&request.bdaddr.b[5] = 0x10;\
        request.link_type = ACL_LINK;\
        hci_send_event_packet(vhci_fd, HCI_EV_CONN_REQUEST, &request, 
sizeof(request));\
        struct hci_ev_conn_complete complete;\
        memset(&complete, 0, sizeof(complete));\
        complete.status = 0;\
        complete.handle = HCI_HANDLE_1;\
        memset(&complete.bdaddr, 0xaa, 6);\
        *(uint8_t*)&complete.bdaddr.b[5] = 0x10;\
        complete.link_type = ACL_LINK;\
        complete.encr_mode = 0;\
        hci_send_event_packet(vhci_fd, HCI_EV_CONN_COMPLETE, &complete, 
sizeof(complete));\
        struct hci_ev_remote_features features;\
        memset(&features, 0, sizeof(features));\
        features.status = 0;\
        features.handle = HCI_HANDLE_1;\
        hci_send_event_packet(vhci_fd, HCI_EV_REMOTE_FEATURES, &features, 
sizeof(features));\
        struct \{\
                struct hci_ev_le_meta le_meta;\
                struct hci_ev_le_conn_complete le_conn;\
        \} le_conn;\
        memset(&le_conn, 0, sizeof(le_conn));\
        le_conn.le_meta.subevent = HCI_EV_LE_CONN_COMPLETE;\
        memset(&le_conn.le_conn.bdaddr, 0xaa, 6);\
        *(uint8_t*)&le_conn.le_conn.bdaddr.b[5] = 0x11;\
        le_conn.le_conn.role = 1;\
        le_conn.le_conn.handle = HCI_HANDLE_2;\
        hci_send_event_packet(vhci_fd, HCI_EV_LE_META, &le_conn, 
sizeof(le_conn));\
        pthread_join(th, NULL);\
        close(hci_sock);\
\}\
\
static void setup_common()\
\{\
        if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) \{\
        \}\
\}\
\
static void setup_binderfs()\
\{\
        if (mkdir("/dev/binderfs", 0777)) \{\
        \}\
        if (mount("binder", "/dev/binderfs", "binder", 0, NULL)) \{\
        \}\
        if (symlink("/dev/binderfs", "./binderfs")) \{\
        \}\
\}\
\
static void loop();\
\
static void sandbox_common()\
\{\
        prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);\
        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 (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL)) \{\
        \}\
        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);\
\}\
\
static int wait_for_loop(int pid)\
\{\
        if (pid < 0)\
        exit(1);\
        int status = 0;\
        while (waitpid(-1, &status, __WALL) != pid) \{\
        \}\
        return WEXITSTATUS(status);\
\}\
\
static void drop_caps(void)\
\{\
        struct __user_cap_header_struct cap_hdr = \{\};\
        struct __user_cap_data_struct cap_data[2] = \{\};\
        cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;\
        cap_hdr.pid = getpid();\
        if (syscall(SYS_capget, &cap_hdr, &cap_data))\
        exit(1);\
        const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);\
        cap_data[0].effective &= ~drop;\
        cap_data[0].permitted &= ~drop;\
        cap_data[0].inheritable &= ~drop;\
        if (syscall(SYS_capset, &cap_hdr, &cap_data))\
        exit(1);\
\}\
\
static int do_sandbox_none(void)\
\{\
        if (unshare(CLONE_NEWPID)) \{\
        \}\
        int pid = fork();\
        if (pid != 0)\
                return wait_for_loop(pid);\
        setup_common();\
        initialize_vhci();\
        sandbox_common();\
        drop_caps();\
        initialize_netdevices_init();\
        if (unshare(CLONE_NEWNET)) \{\
        \}\
        initialize_netdevices();\
        setup_binderfs();\
        loop();\
        exit(1);\
\}\
\
static void close_fds()\
\{\
        for (int fd = 3; fd < MAX_FDS; fd++)\
                close(fd);\
\}\
\
static void setup_binfmt_misc()\
\{\
        if (mount(0, "/proc/sys/fs/binfmt_misc", "binfmt_misc", 0, 0)) \{\
        \}\
        write_file("/proc/sys/fs/binfmt_misc/register", 
":syz0:M:0:\\x01::./file0:");\
        write_file("/proc/sys/fs/binfmt_misc/register", 
":syz1:M:1:\\x02::./file0:POC");\
\}\
\
static void setup_sysctl()\
\{\
        char mypid[32];\
        snprintf(mypid, sizeof(mypid), "%d", getpid());\
        struct \{\
                const char* name;\
                const char* data;\
        \} files[] = \{\
                \{"/sys/kernel/debug/x86/nmi_longest_ns", "10000000000"\},\
                \{"/proc/sys/kernel/hung_task_check_interval_secs", "20"\},\
                \{"/proc/sys/net/core/bpf_jit_kallsyms", "1"\},\
                \{"/proc/sys/net/core/bpf_jit_harden", "0"\},\
                \{"/proc/sys/kernel/kptr_restrict", "0"\},\
                \{"/proc/sys/kernel/softlockup_all_cpu_backtrace", "1"\},\
                \{"/proc/sys/fs/mount-max", "100"\},\
                \{"/proc/sys/vm/oom_dump_tasks", "0"\},\
                \{"/proc/sys/debug/exception-trace", "0"\},\
                \{"/proc/sys/kernel/printk", "7 4 1 3"\},\
                \{"/proc/sys/net/ipv4/ping_group_range", "0 65535"\},\
                \{"/proc/sys/kernel/keys/gc_delay", "1"\},\
                \{"/proc/sys/vm/oom_kill_allocating_task", "1"\},\
                \{"/proc/sys/kernel/ctrl-alt-del", "0"\},\
                \{"/proc/sys/kernel/cad_pid", mypid\},\
        \};\
        for (size_t i = 0; i < sizeof(files) / sizeof(files[0]); i++) \{\
                if (!write_file(files[i].name, files[i].data))\
                        printf("write to %s failed: %s\\n", files[i].name, 
strerror(errno));\
        \}\
\}\
\
uint64_t r[1] = \{0xffffffffffffffff\};\
\
void loop(void)\
\{\
                intptr_t res = 0;\
        res = syscall(__NR_socket, 2ul, 2ul, 0x73);\
        if (res != -1)\
                r[0] = res;\
memcpy((void*)0x20000040, 
"filter\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000",
 32);\
*(uint32_t*)0x20000060 = 6;\
*(uint32_t*)0x20000064 = 0;\
*(uint32_t*)0x20000068 = 0x90;\
*(uint64_t*)0x20000070 = 0;\
*(uint64_t*)0x20000078 = 0x20000400;\
*(uint64_t*)0x20000080 = 0x20000430;\
*(uint64_t*)0x20000088 = 0;\
*(uint64_t*)0x20000090 = 0;\
*(uint64_t*)0x20000098 = 0;\
*(uint32_t*)0x200000a0 = 0;\
*(uint64_t*)0x200000a8 = 0;\
*(uint64_t*)0x200000b0 = 0x20000400;\
*(uint32_t*)0x20000400 = 0;\
memset((void*)0x20000404, 0, 32);\
*(uint32_t*)0x20000424 = 0;\
*(uint32_t*)0x20000428 = -1;\
*(uint32_t*)0x2000042c = 0;\
*(uint32_t*)0x20000430 = 0;\
memset((void*)0x20000434, 0, 32);\
*(uint32_t*)0x20000454 = 0;\
*(uint32_t*)0x20000458 = -1;\
*(uint32_t*)0x2000045c = 0;\
*(uint32_t*)0x20000460 = 0;\
memset((void*)0x20000464, 0, 32);\
*(uint32_t*)0x20000484 = 0;\
*(uint32_t*)0x20000488 = 0xfffffffc;\
*(uint32_t*)0x2000048c = 0;\
        syscall(__NR_setsockopt, r[0], 0, 0x80, 0x20000040ul, 0x108ul);\
        close_fds();\
\}\
int main(void)\
\{\
                syscall(__NR_mmap, 0x1ffff000ul, 0x1000ul, 0ul, 0x32ul, -1, 
0ul);\
        syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 7ul, 0x32ul, -1, 0ul);\
        syscall(__NR_mmap, 0x21000000ul, 0x1000ul, 0ul, 0x32ul, -1, 0ul);\
        setup_sysctl();\
        setup_binfmt_misc();\
                        do_sandbox_none();\
        return 0;\
\}\
}

Reply via email to