aboutsummaryrefslogtreecommitdiff
path: root/executor/common_bsd.h
diff options
context:
space:
mode:
Diffstat (limited to 'executor/common_bsd.h')
-rw-r--r--executor/common_bsd.h399
1 files changed, 4 insertions, 395 deletions
diff --git a/executor/common_bsd.h b/executor/common_bsd.h
index 95f08bcc5..b678dd968 100644
--- a/executor/common_bsd.h
+++ b/executor/common_bsd.h
@@ -5,407 +5,16 @@
#include <unistd.h>
-#include <pwd.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <string.h>
-#include <sys/syscall.h>
-
-#if GOOS_openbsd
-
-#define __syscall syscall
-
-#if SYZ_EXECUTOR || __NR_syz_open_pts
-
-#include <termios.h>
-#include <util.h>
-
-static uintptr_t syz_open_pts(void)
-{
- int master, slave;
-
- if (openpty(&master, &slave, NULL, NULL, NULL) == -1)
- return -1;
- // Move the master fd up in order to reduce the chances of the fuzzer
- // generating a call to close(2) with the same fd.
- if (dup2(master, master + 100) != -1)
- close(master);
- return slave;
-}
-
-#endif // SYZ_EXECUTOR || __NR_syz_open_pts
-
-#endif // GOOS_openbsd
-
-#if GOOS_freebsd || GOOS_openbsd || GOOS_netbsd
-
-#if SYZ_EXECUTOR || SYZ_TUN_ENABLE
-
-#include <fcntl.h>
-#include <net/if_tun.h>
-#include <sys/types.h>
-
-static int tunfd = -1;
-
-// We just need this to be large enough to hold headers that we parse (ethernet/ip/tcp).
-// Rest of the packet (if any) will be silently truncated which is fine.
-#define SYZ_TUN_MAX_PACKET_SIZE 1000
-
-#if GOOS_netbsd
-// Increased number of tap and tun devices if image script is used
-#define MAX_TUN 64
-
-#else
-// Maximum number of tun devices in the default install.
-#define MAX_TUN 4
-#endif
-
-// All patterns are non-expanding given values < MAX_TUN.
-#define TUN_IFACE "tap%d"
-#define TUN_DEVICE "/dev/tap%d"
-
-#define LOCAL_MAC "aa:aa:aa:aa:aa:aa"
-#define REMOTE_MAC "aa:aa:aa:aa:aa:bb"
-#define LOCAL_IPV4 "172.20.%d.170"
-#define REMOTE_IPV4 "172.20.%d.187"
-#define LOCAL_IPV6 "fe80::%02hxaa"
-#define REMOTE_IPV6 "fe80::%02hxbb"
-
-static void vsnprintf_check(char* str, size_t size, const char* format, va_list args)
-{
- int rv;
-
- rv = vsnprintf(str, size, format, args);
- if (rv < 0)
- fail("vsnprintf failed");
- if ((size_t)rv >= size)
- fail("vsnprintf: string '%s...' doesn't fit into buffer", str);
-}
-
-static void snprintf_check(char* str, size_t size, const char* format, ...)
-{
- va_list args;
-
- va_start(args, format);
- vsnprintf_check(str, size, format, args);
- va_end(args);
-}
-
-#define COMMAND_MAX_LEN 128
-#define PATH_PREFIX "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin "
-#define PATH_PREFIX_LEN (sizeof(PATH_PREFIX) - 1)
-
-static void execute_command(bool panic, const char* format, ...)
-{
- va_list args;
- char command[PATH_PREFIX_LEN + COMMAND_MAX_LEN];
- int rv;
-
- va_start(args, format);
- // Executor process does not have any env, including PATH.
- // On some distributions, system/shell adds a minimal PATH, on some it does not.
- // Set own standard PATH to make it work across distributions.
- memcpy(command, PATH_PREFIX, PATH_PREFIX_LEN);
- vsnprintf_check(command + PATH_PREFIX_LEN, COMMAND_MAX_LEN, format, args);
- va_end(args);
- rv = system(command);
- if (rv) {
- if (panic)
- fail("command '%s' failed: %d", &command[0], rv);
- debug("command '%s': %d\n", &command[0], rv);
- }
-}
-
-static void initialize_tun(int tun_id)
-{
-#if SYZ_EXECUTOR
- if (!flag_enable_tun)
- return;
-#endif // SYZ_EXECUTOR
-
- if (tun_id < 0 || tun_id >= MAX_TUN) {
- fail("tun_id out of range %d\n", tun_id);
- }
-
- char tun_device[sizeof(TUN_DEVICE)];
- snprintf_check(tun_device, sizeof(tun_device), TUN_DEVICE, tun_id);
-
- char tun_iface[sizeof(TUN_IFACE)];
- snprintf_check(tun_iface, sizeof(tun_iface), TUN_IFACE, tun_id);
-
-#if GOOS_netbsd
- // open(2) doesn't create an new tap/tun interface node
- // so we use ifconfig to create the node. Might be casued due to regression
- execute_command(0, "ifconfig %s destroy", tun_iface);
- execute_command(0, "ifconfig %s create", tun_iface);
-#else
- execute_command(0, "ifconfig %s destroy", tun_device);
-#endif
-
- tunfd = open(tun_device, O_RDWR | O_NONBLOCK);
-#if GOOS_freebsd
- if ((tunfd < 0) && (errno == ENOENT)) {
- execute_command(0, "kldload -q if_tap");
- tunfd = open(tun_device, O_RDWR | O_NONBLOCK);
- }
-#endif
- if (tunfd == -1) {
-#if SYZ_EXECUTOR
- fail("tun: can't open %s\n", tun_device);
-#else
- printf("tun: can't open %s: errno=%d\n", tun_device, errno);
- return;
-#endif // SYZ_EXECUTOR
- }
- // Remap tun onto higher fd number to hide it from fuzzer and to keep
- // fd numbers stable regardless of whether tun is opened or not (also see kMaxFd).
- const int kTunFd = 240;
- if (dup2(tunfd, kTunFd) < 0)
- fail("dup2(tunfd, kTunFd) failed");
- close(tunfd);
- tunfd = kTunFd;
-
- char local_mac[sizeof(LOCAL_MAC)];
- snprintf_check(local_mac, sizeof(local_mac), LOCAL_MAC);
-
- // Set the MAC address of the interface to LOCAL_MAC
-#if GOOS_openbsd
- execute_command(1, "ifconfig %s lladdr %s", tun_iface, local_mac);
-#elif GOOS_netbsd
- execute_command(1, "ifconfig %s link %s", tun_iface, local_mac);
-#else
- execute_command(1, "ifconfig %s ether %s", tun_iface, local_mac);
-#endif
-
- // Setting up a static ip for the interface
- char local_ipv4[sizeof(LOCAL_IPV4)];
- snprintf_check(local_ipv4, sizeof(local_ipv4), LOCAL_IPV4, tun_id);
- execute_command(1, "ifconfig %s inet %s netmask 255.255.255.0", tun_iface, local_ipv4);
-
- // Creates an ARP table entry for the remote ip and MAC address
- char remote_mac[sizeof(REMOTE_MAC)];
- char remote_ipv4[sizeof(REMOTE_IPV4)];
- snprintf_check(remote_mac, sizeof(remote_mac), REMOTE_MAC);
- snprintf_check(remote_ipv4, sizeof(remote_ipv4), REMOTE_IPV4, tun_id);
- execute_command(0, "arp -s %s %s", remote_ipv4, remote_mac);
-
- // Set up a static ipv6 address for the interface
- char local_ipv6[sizeof(LOCAL_IPV6)];
- snprintf_check(local_ipv6, sizeof(local_ipv6), LOCAL_IPV6, tun_id);
- execute_command(1, "ifconfig %s inet6 %s", tun_iface, local_ipv6);
-
- // Registers an NDP entry for the remote MAC with the remote ipv6 address
- char remote_ipv6[sizeof(REMOTE_IPV6)];
- snprintf_check(remote_ipv6, sizeof(remote_ipv6), REMOTE_IPV6, tun_id);
- execute_command(0, "ndp -s %s%%%s %s", remote_ipv6, tun_iface, remote_mac);
-}
-
-#endif // SYZ_EXECUTOR || SYZ_TUN_ENABLE
-
-#if SYZ_EXECUTOR || __NR_syz_emit_ethernet && SYZ_TUN_ENABLE
-#include <stdbool.h>
-#include <sys/uio.h>
-
-static long syz_emit_ethernet(volatile long a0, volatile long a1)
-{
- // syz_emit_ethernet(len len[packet], packet ptr[in, array[int8]])
- if (tunfd < 0)
- return (uintptr_t)-1;
-
- size_t length = a0;
- const char* data = (char*)a1;
- debug_dump_data(data, length);
-
- return write(tunfd, data, length);
-}
-#endif
-
-#if SYZ_EXECUTOR || SYZ_TUN_ENABLE && (__NR_syz_extract_tcp_res || SYZ_REPEAT)
-#include <errno.h>
-
-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;
- fail("tun: read failed with %d", rv);
- }
- return rv;
-}
-#endif
-
-#if SYZ_EXECUTOR || __NR_syz_extract_tcp_res && SYZ_TUN_ENABLE
-
-struct tcp_resources {
- uint32 seq;
- uint32 ack;
-};
-
-#if GOOS_freebsd
-#include <net/ethernet.h>
-#else
-#include <net/ethertypes.h>
-#endif
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <netinet/ip6.h>
-#include <netinet/tcp.h>
-
-// Include order matters, empty line prevent re-sorting. See a workaround in
-// pkg/csource hoistIncludes.
-#include <netinet/if_ether.h>
-
-static long syz_extract_tcp_res(volatile long a0, volatile long a1, volatile long a2)
-{
- // syz_extract_tcp_res(res ptr[out, tcp_resources], seq_inc int32, ack_inc int32)
-
- if (tunfd < 0)
- return (uintptr_t)-1;
-
- char data[SYZ_TUN_MAX_PACKET_SIZE];
- int rv = read_tun(&data[0], sizeof(data));
- if (rv == -1)
- return (uintptr_t)-1;
- size_t length = rv;
- debug_dump_data(data, length);
-
- struct tcphdr* tcphdr;
-
- if (length < sizeof(struct ether_header))
- return (uintptr_t)-1;
- struct ether_header* ethhdr = (struct ether_header*)&data[0];
-
- if (ethhdr->ether_type == htons(ETHERTYPE_IP)) {
- if (length < sizeof(struct ether_header) + sizeof(struct ip))
- return (uintptr_t)-1;
- struct ip* iphdr = (struct ip*)&data[sizeof(struct ether_header)];
- if (iphdr->ip_p != IPPROTO_TCP)
- return (uintptr_t)-1;
- if (length < sizeof(struct ether_header) + iphdr->ip_hl * 4 + sizeof(struct tcphdr))
- return (uintptr_t)-1;
- tcphdr = (struct tcphdr*)&data[sizeof(struct ether_header) + iphdr->ip_hl * 4];
- } else {
- if (length < sizeof(struct ether_header) + sizeof(struct ip6_hdr))
- return (uintptr_t)-1;
- struct ip6_hdr* ipv6hdr = (struct ip6_hdr*)&data[sizeof(struct ether_header)];
- // TODO: parse and skip extension headers.
- if (ipv6hdr->ip6_nxt != IPPROTO_TCP)
- return (uintptr_t)-1;
- if (length < sizeof(struct ether_header) + sizeof(struct ip6_hdr) + sizeof(struct tcphdr))
- return (uintptr_t)-1;
- tcphdr = (struct tcphdr*)&data[sizeof(struct ether_header) + sizeof(struct ip6_hdr)];
- }
-
- struct tcp_resources* res = (struct tcp_resources*)a0;
- NONFAILING(res->seq = htonl((ntohl(tcphdr->th_seq) + (uint32)a1)));
- NONFAILING(res->ack = htonl((ntohl(tcphdr->th_ack) + (uint32)a2)));
-
- debug("extracted seq: %08x\n", res->seq);
- debug("extracted ack: %08x\n", res->ack);
-
- return 0;
-}
-#endif
-#endif // GOOS_freebsd || GOOS_openbsd
-
-#if SYZ_EXECUTOR || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NONE
-
-#include <sys/resource.h>
-#include <unistd.h>
-
-static void sandbox_common()
-{
- if (setsid() == -1)
- fail("setsid failed");
-
- // Some minimal sandboxing.
- struct rlimit rlim;
-#ifdef GOOS_freebsd
- // Documented bug in OpenBSD.
- // This causes frequent random aborts. Reason unknown.
-
- // This also causes ENOMEM on NetBSD during early init.
- rlim.rlim_cur = rlim.rlim_max = 128 << 20;
- setrlimit(RLIMIT_AS, &rlim);
-#endif
- rlim.rlim_cur = rlim.rlim_max = 8 << 20;
- setrlimit(RLIMIT_MEMLOCK, &rlim);
- rlim.rlim_cur = rlim.rlim_max = 1 << 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; // see kMaxFd
- setrlimit(RLIMIT_NOFILE, &rlim);
-}
-#endif // SYZ_EXECUTOR || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NONE
-
#if SYZ_EXECUTOR || SYZ_SANDBOX_NONE
-
static void loop();
-
static int do_sandbox_none(void)
{
- sandbox_common();
-#if (GOOS_freebsd || GOOS_openbsd || GOOS_netbsd) && (SYZ_EXECUTOR || SYZ_TUN_ENABLE)
- initialize_tun(procid);
-#endif
loop();
return 0;
}
-#endif // SYZ_EXECUTOR || SYZ_SANDBOX_NONE
-
-#if SYZ_EXECUTOR || SYZ_SANDBOX_SETUID
-
-#include <sys/resource.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-static void loop();
-
-static int wait_for_loop(int pid)
-{
- if (pid < 0)
- fail("sandbox fork failed");
- debug("spawned loop pid %d\n", pid);
- int status = 0;
- while (waitpid(-1, &status, WUNTRACED) != pid) {
- }
- return WEXITSTATUS(status);
-}
-
-#define SYZ_HAVE_SANDBOX_SETUID 1
-static int do_sandbox_setuid(void)
-{
- int pid = fork();
- if (pid != 0)
- return wait_for_loop(pid);
-
- sandbox_common();
-#if (GOOS_freebsd || GOOS_openbsd || GOOS_netbsd) && (SYZ_EXECUTOR || SYZ_TUN_ENABLE)
- initialize_tun(procid);
#endif
- char pwbuf[1024];
- struct passwd *pw, pwres;
- if (getpwnam_r("nobody", &pwres, pwbuf, sizeof(pwbuf), &pw) != 0 || !pw)
- fail("getpwnam_r(\"nobody\") failed");
-
- if (setgroups(0, NULL))
- fail("failed to setgroups");
- if (setgid(pw->pw_gid))
- fail("failed to setgid");
- if (setuid(pw->pw_uid))
- fail("failed to setuid");
-
- loop();
- doexit(1);
-}
-#endif // SYZ_EXECUTOR || SYZ_SANDBOX_SETUID
+#if SYZ_EXECUTOR
+#define do_sandbox_setuid() 0
+#define do_sandbox_namespace() 0
+#endif