github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/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; 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 46 static intptr_t execute_syscall(const call_t* c, intptr_t a[kMaxArgs]) 47 { 48 if (c->call) 49 return c->call(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]); 50 #if GOOS_openbsd 51 failmsg("no call", "missing target for %s", c->name); 52 #else 53 return __syscall(c->sys_nr, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]); 54 #endif 55 } 56 57 static void cover_open(cover_t* cov, bool extra) 58 { 59 int fd = open("/dev/kcov", O_RDWR); 60 if (fd == -1) 61 fail("open of /dev/kcov failed"); 62 if (dup2(fd, cov->fd) < 0) 63 failmsg("failed to dup cover fd", "from=%d, to=%d", fd, cov->fd); 64 close(fd); 65 66 #if GOOS_freebsd 67 if (ioctl(cov->fd, KIOSETBUFSIZE, kCoverSize)) 68 fail("ioctl init trace write failed"); 69 cov->mmap_alloc_size = kCoverSize * KCOV_ENTRY_SIZE; 70 #elif GOOS_openbsd 71 unsigned long cover_size = kCoverSize; 72 if (ioctl(cov->fd, KIOSETBUFSIZE, &cover_size)) 73 fail("ioctl init trace write failed"); 74 if (extra) { 75 struct kio_remote_attach args; 76 args.subsystem = KCOV_REMOTE_COMMON; 77 args.id = 0; 78 if (ioctl(cov->fd, KIOREMOTEATTACH, &args)) 79 fail("ioctl remote attach failed"); 80 } 81 cov->mmap_alloc_size = kCoverSize * (is_kernel_64_bit ? 8 : 4); 82 #elif GOOS_netbsd 83 uint64_t cover_size; 84 if (extra) { 85 // USB coverage, the size is fixed to the maximum 86 cover_size = (256 << 10); // maximum size 87 struct kcov_ioc_remote_attach args; 88 args.subsystem = KCOV_REMOTE_VHCI; 89 args.id = KCOV_REMOTE_VHCI_ID(procid, 1); // first port 90 if (ioctl(cov->fd, KCOV_IOC_REMOTE_ATTACH, &args)) 91 fail("ioctl remote attach failed"); 92 } else { 93 // Normal coverage 94 cover_size = kCoverSize; 95 if (ioctl(cov->fd, KCOV_IOC_SETBUFSIZE, &cover_size)) 96 fail("ioctl init trace write failed"); 97 } 98 cov->mmap_alloc_size = cover_size * KCOV_ENTRY_SIZE; 99 #endif 100 } 101 102 static void cover_mmap(cover_t* cov) 103 { 104 if (cov->data != NULL) 105 fail("cover_mmap invoked on an already mmapped cover_t object"); 106 void* mmap_ptr = mmap(NULL, cov->mmap_alloc_size, PROT_READ | PROT_WRITE, 107 MAP_SHARED, cov->fd, 0); 108 if (mmap_ptr == MAP_FAILED) 109 fail("cover mmap failed"); 110 cov->data = (char*)mmap_ptr; 111 cov->data_end = cov->data + cov->mmap_alloc_size; 112 cov->data_offset = is_kernel_64_bit ? sizeof(uint64_t) : sizeof(uint32_t); 113 cov->pc_offset = 0; 114 } 115 116 static void cover_protect(cover_t* cov) 117 { 118 #if GOOS_freebsd 119 size_t mmap_alloc_size = kCoverSize * KCOV_ENTRY_SIZE; 120 long page_size = sysconf(_SC_PAGESIZE); 121 if (page_size > 0) 122 mprotect(cov->data + page_size, mmap_alloc_size - page_size, 123 PROT_READ); 124 #elif GOOS_openbsd 125 int mib[2], page_size; 126 size_t mmap_alloc_size = kCoverSize * sizeof(uintptr_t); 127 mib[0] = CTL_HW; 128 mib[1] = HW_PAGESIZE; 129 size_t len = sizeof(page_size); 130 if (sysctl(mib, ARRAY_SIZE(mib), &page_size, &len, NULL, 0) != -1) 131 mprotect(cov->data + page_size, mmap_alloc_size - page_size, PROT_READ); 132 #endif 133 } 134 135 static void cover_unprotect(cover_t* cov) 136 { 137 #if GOOS_freebsd 138 size_t mmap_alloc_size = kCoverSize * KCOV_ENTRY_SIZE; 139 mprotect(cov->data, mmap_alloc_size, PROT_READ | PROT_WRITE); 140 #elif GOOS_openbsd 141 size_t mmap_alloc_size = kCoverSize * sizeof(uintptr_t); 142 mprotect(cov->data, mmap_alloc_size, PROT_READ | PROT_WRITE); 143 #endif 144 } 145 146 static void cover_enable(cover_t* cov, bool collect_comps, bool extra) 147 { 148 int kcov_mode = collect_comps ? KCOV_MODE_TRACE_CMP : KCOV_MODE_TRACE_PC; 149 #if GOOS_freebsd 150 // FreeBSD uses an int as the third argument. 151 if (ioctl(cov->fd, KIOENABLE, kcov_mode)) 152 exitf("cover enable write trace failed, mode=%d", kcov_mode); 153 #elif GOOS_openbsd 154 // OpenBSD uses an pointer to an int as the third argument. 155 // Whether it is a regular coverage or an extra coverage, the enable 156 // ioctl is the same. 157 if (ioctl(cov->fd, KIOENABLE, &kcov_mode)) 158 exitf("cover enable write trace failed, mode=%d", kcov_mode); 159 #elif GOOS_netbsd 160 // Whether it is a regular coverage or a USB coverage, the enable 161 // ioctl is the same. 162 if (ioctl(cov->fd, KCOV_IOC_ENABLE, &kcov_mode)) 163 exitf("cover enable write trace failed, mode=%d", kcov_mode); 164 #endif 165 } 166 167 static void cover_reset(cover_t* cov) 168 { 169 *(uint64*)cov->data = 0; 170 } 171 172 static void cover_collect(cover_t* cov) 173 { 174 cov->size = *(uint64*)cov->data; 175 } 176 177 static bool use_cover_edges(uint64 pc) 178 { 179 return true; 180 } 181 182 #if GOOS_netbsd 183 #define SYZ_HAVE_FEATURES 1 184 static feature_t features[] = { 185 {rpc::Feature::USBEmulation, setup_usb}, 186 {rpc::Feature::Fault, setup_fault}, 187 }; 188 189 static void setup_sysctl(void) 190 { 191 } 192 193 static void setup_cgroups(void) 194 { 195 } 196 #endif