github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/executor/executor_bsd.h (about) 1 // Copyright 2017 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 #include <fcntl.h> 5 #include <stdlib.h> 6 #include <sys/ioctl.h> 7 #include <sys/kcov.h> 8 #include <sys/mman.h> 9 #include <sys/resource.h> 10 #include <sys/stat.h> 11 #include <sys/types.h> 12 #include <unistd.h> 13 14 #if GOOS_openbsd 15 #include <sys/sysctl.h> 16 #endif 17 18 static void os_init(int argc, char** argv, void* data, size_t data_size) 19 { 20 #if GOOS_openbsd 21 // W^X not allowed by default on OpenBSD. 22 int prot = PROT_READ | PROT_WRITE; 23 #elif GOOS_netbsd 24 // W^X not allowed by default on NetBSD (PaX MPROTECT). 25 int prot = PROT_READ | PROT_WRITE | PROT_MPROTECT(PROT_EXEC); 26 #else 27 int prot = PROT_READ | PROT_WRITE | PROT_EXEC; 28 #endif 29 30 int flags = MAP_ANON | MAP_PRIVATE | MAP_FIXED_EXCLUSIVE; 31 #if GOOS_freebsd 32 // Fail closed if the chosen data offset conflicts with an existing mapping. 33 flags |= MAP_EXCL; 34 #endif 35 36 void* got = mmap(data, data_size, prot, flags, -1, 0); 37 if (data != got) 38 failmsg("mmap of data segment failed", "want %p, got %p", data, got); 39 40 // Makes sure the file descriptor limit is sufficient to map control pipes. 41 struct rlimit rlim; 42 rlim.rlim_cur = rlim.rlim_max = kMaxFd; 43 setrlimit(RLIMIT_NOFILE, &rlim); 44 45 // A SIGCHLD handler makes sleep in loop exit immediately return with EINTR with a child exits. 46 struct sigaction act = {}; 47 act.sa_handler = [](int) {}; 48 sigaction(SIGCHLD, &act, nullptr); 49 } 50 51 static intptr_t execute_syscall(const call_t* c, intptr_t a[kMaxArgs]) 52 { 53 if (c->call) 54 return c->call(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]); 55 #if GOOS_openbsd 56 failmsg("no call", "missing target for %s", c->name); 57 #else 58 return __syscall(c->sys_nr, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]); 59 #endif 60 } 61 62 static void cover_open(cover_t* cov, bool extra) 63 { 64 int fd = open("/dev/kcov", O_RDWR); 65 if (fd == -1) 66 fail("open of /dev/kcov failed"); 67 if (dup2(fd, cov->fd) < 0) 68 failmsg("failed to dup cover fd", "from=%d, to=%d", fd, cov->fd); 69 close(fd); 70 71 #if GOOS_freebsd 72 if (ioctl(cov->fd, KIOSETBUFSIZE, kCoverSize)) 73 fail("ioctl init trace write failed"); 74 cov->data_size = kCoverSize * KCOV_ENTRY_SIZE; 75 #elif GOOS_openbsd 76 unsigned long cover_size = kCoverSize; 77 if (ioctl(cov->fd, KIOSETBUFSIZE, &cover_size)) 78 fail("ioctl init trace write failed"); 79 if (extra) { 80 struct kio_remote_attach args; 81 args.subsystem = KCOV_REMOTE_COMMON; 82 args.id = 0; 83 if (ioctl(cov->fd, KIOREMOTEATTACH, &args)) 84 fail("ioctl remote attach failed"); 85 } 86 cov->data_size = kCoverSize * (is_kernel_64_bit ? 8 : 4); 87 #elif GOOS_netbsd 88 uint64_t cover_size; 89 if (extra) { 90 // USB coverage, the size is fixed to the maximum 91 cover_size = (256 << 10); // maximum size 92 struct kcov_ioc_remote_attach args; 93 args.subsystem = KCOV_REMOTE_VHCI; 94 args.id = KCOV_REMOTE_VHCI_ID(procid, 1); // first port 95 if (ioctl(cov->fd, KCOV_IOC_REMOTE_ATTACH, &args)) 96 fail("ioctl remote attach failed"); 97 } else { 98 // Normal coverage 99 cover_size = kCoverSize; 100 if (ioctl(cov->fd, KCOV_IOC_SETBUFSIZE, &cover_size)) 101 fail("ioctl init trace write failed"); 102 } 103 cov->data_size = cover_size * KCOV_ENTRY_SIZE; 104 #endif 105 } 106 107 static void cover_mmap(cover_t* cov) 108 { 109 if (cov->mmap_alloc_ptr != NULL) 110 fail("cover_mmap invoked on an already mmapped cover_t object"); 111 cov->mmap_alloc_size = cov->data_size; 112 void* mmap_ptr = mmap(NULL, cov->mmap_alloc_size, PROT_READ | PROT_WRITE, 113 MAP_SHARED, cov->fd, 0); 114 if (mmap_ptr == MAP_FAILED) 115 fail("cover mmap failed"); 116 cov->mmap_alloc_ptr = (char*)mmap_ptr; 117 cov->data = (char*)mmap_ptr; 118 cov->data_end = cov->data + cov->mmap_alloc_size; 119 cov->data_offset = is_kernel_64_bit ? sizeof(uint64_t) : sizeof(uint32_t); 120 cov->pc_offset = 0; 121 } 122 123 static void cover_protect(cover_t* cov) 124 { 125 if (cov->mmap_alloc_ptr == NULL) 126 fail("cover_protect invoked on an unmapped cover_t object"); 127 #if GOOS_freebsd 128 size_t mmap_alloc_size = kCoverSize * KCOV_ENTRY_SIZE; 129 long page_size = sysconf(_SC_PAGESIZE); 130 if (page_size > 0) 131 mprotect(cov->mmap_alloc_ptr + page_size, mmap_alloc_size - page_size, 132 PROT_READ); 133 #elif GOOS_openbsd 134 int mib[2], page_size; 135 size_t mmap_alloc_size = kCoverSize * sizeof(uintptr_t); 136 mib[0] = CTL_HW; 137 mib[1] = HW_PAGESIZE; 138 size_t len = sizeof(page_size); 139 if (sysctl(mib, ARRAY_SIZE(mib), &page_size, &len, NULL, 0) != -1) 140 mprotect(cov->mmap_alloc_ptr + page_size, mmap_alloc_size - page_size, PROT_READ); 141 #endif 142 } 143 144 static void cover_unprotect(cover_t* cov) 145 { 146 if (cov->mmap_alloc_ptr == NULL) 147 fail("cover_unprotect invoked on an unmapped cover_t object"); 148 #if GOOS_freebsd 149 size_t mmap_alloc_size = kCoverSize * KCOV_ENTRY_SIZE; 150 mprotect(cov->mmap_alloc_ptr, mmap_alloc_size, PROT_READ | PROT_WRITE); 151 #elif GOOS_openbsd 152 size_t mmap_alloc_size = kCoverSize * sizeof(uintptr_t); 153 mprotect(cov->mmap_alloc_ptr, mmap_alloc_size, PROT_READ | PROT_WRITE); 154 #endif 155 } 156 157 static void cover_enable(cover_t* cov, bool collect_comps, bool extra) 158 { 159 int kcov_mode = collect_comps ? KCOV_MODE_TRACE_CMP : KCOV_MODE_TRACE_PC; 160 #if GOOS_freebsd 161 // FreeBSD uses an int as the third argument. 162 if (ioctl(cov->fd, KIOENABLE, kcov_mode)) 163 exitf("cover enable write trace failed, mode=%d", kcov_mode); 164 #elif GOOS_openbsd 165 // OpenBSD uses an pointer to an int as the third argument. 166 // Whether it is a regular coverage or an extra coverage, the enable 167 // ioctl is the same. 168 if (ioctl(cov->fd, KIOENABLE, &kcov_mode)) 169 exitf("cover enable write trace failed, mode=%d", kcov_mode); 170 #elif GOOS_netbsd 171 // Whether it is a regular coverage or a USB coverage, the enable 172 // ioctl is the same. 173 if (ioctl(cov->fd, KCOV_IOC_ENABLE, &kcov_mode)) 174 exitf("cover enable write trace failed, mode=%d", kcov_mode); 175 #endif 176 } 177 178 static void cover_reset(cover_t* cov) 179 { 180 *(uint64*)cov->data = 0; 181 } 182 183 static void cover_collect(cover_t* cov) 184 { 185 cov->size = *(uint64*)cov->data; 186 } 187 188 #if GOOS_netbsd 189 #define SYZ_HAVE_FEATURES 1 190 static feature_t features[] = { 191 {rpc::Feature::USBEmulation, setup_usb}, 192 {rpc::Feature::Fault, setup_fault}, 193 }; 194 195 static void setup_sysctl(void) 196 { 197 } 198 199 static void setup_cgroups(void) 200 { 201 } 202 #endif