// https://syzkaller.appspot.com/bug?id=7701b971a675cbab8050ab88f2188706d1b7450a // autogenerated by syzkaller (https://github.com/google/syzkaller) #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef __NR_memfd_create #define __NR_memfd_create 319 #endif static unsigned long long procid; static __thread int clone_ongoing; static __thread int skip_segv; static __thread jmp_buf segv_env; static void segv_handler(int sig, siginfo_t* info, void* ctx) { if (__atomic_load_n(&clone_ongoing, __ATOMIC_RELAXED) != 0) { exit(sig); } uintptr_t addr = (uintptr_t)info->si_addr; const uintptr_t prog_start = 1 << 20; const uintptr_t prog_end = 100 << 20; int skip = __atomic_load_n(&skip_segv, __ATOMIC_RELAXED) != 0; int valid = addr < prog_start || addr > prog_end; if (skip && valid) { _longjmp(segv_env, 1); } exit(sig); } static void install_segv_handler(void) { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_IGN; syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8); syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8); memset(&sa, 0, sizeof(sa)); sa.sa_sigaction = segv_handler; sa.sa_flags = SA_NODEFER | SA_SIGINFO; sigaction(SIGSEGV, &sa, NULL); sigaction(SIGBUS, &sa, NULL); } #define NONFAILING(...) \ ({ \ int ok = 1; \ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \ if (_setjmp(segv_env) == 0) { \ __VA_ARGS__; \ } else \ ok = 0; \ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \ ok; \ }) 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 void thread_start(void* (*fn)(void*), void* arg) { pthread_t th; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, 128 << 10); int i = 0; for (; i < 100; i++) { if (pthread_create(&th, &attr, fn, arg) == 0) { pthread_attr_destroy(&attr); return; } if (errno == EAGAIN) { usleep(50); continue; } break; } exit(1); } typedef struct { int state; } event_t; static void event_init(event_t* ev) { ev->state = 0; } static void event_reset(event_t* ev) { ev->state = 0; } static void event_set(event_t* ev) { if (ev->state) exit(1); __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE); syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000); } static void event_wait(event_t* ev) { while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE)) syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0); } static int event_isset(event_t* ev) { return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE); } static int event_timedwait(event_t* ev, uint64_t timeout) { uint64_t start = current_time_ms(); uint64_t now = start; for (;;) { uint64_t remain = timeout - (now - start); struct timespec ts; ts.tv_sec = remain / 1000; ts.tv_nsec = (remain % 1000) * 1000 * 1000; syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts); if (__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE)) return 1; now = current_time_ms(); if (now - start > timeout) return 0; } } 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; } //% This code is derived from puff.{c,h}, found in the zlib development. The //% original files come with the following copyright notice: //% Copyright (C) 2002-2013 Mark Adler, all rights reserved //% version 2.3, 21 Jan 2013 //% This software is provided 'as-is', without any express or implied //% warranty. In no event will the author be held liable for any damages //% arising from the use of this software. //% Permission is granted to anyone to use this software for any purpose, //% including commercial applications, and to alter it and redistribute it //% freely, subject to the following restrictions: //% 1. The origin of this software must not be misrepresented; you must not //% claim that you wrote the original software. If you use this software //% in a product, an acknowledgment in the product documentation would be //% appreciated but is not required. //% 2. Altered source versions must be plainly marked as such, and must not be //% misrepresented as being the original software. //% 3. This notice may not be removed or altered from any source distribution. //% Mark Adler madler@alumni.caltech.edu //% BEGIN CODE DERIVED FROM puff.{c,h} #define MAXBITS 15 #define MAXLCODES 286 #define MAXDCODES 30 #define MAXCODES (MAXLCODES + MAXDCODES) #define FIXLCODES 288 struct puff_state { unsigned char* out; unsigned long outlen; unsigned long outcnt; const unsigned char* in; unsigned long inlen; unsigned long incnt; int bitbuf; int bitcnt; jmp_buf env; }; static int puff_bits(struct puff_state* s, int need) { long val = s->bitbuf; while (s->bitcnt < need) { if (s->incnt == s->inlen) longjmp(s->env, 1); val |= (long)(s->in[s->incnt++]) << s->bitcnt; s->bitcnt += 8; } s->bitbuf = (int)(val >> need); s->bitcnt -= need; return (int)(val & ((1L << need) - 1)); } static int puff_stored(struct puff_state* s) { s->bitbuf = 0; s->bitcnt = 0; if (s->incnt + 4 > s->inlen) return 2; unsigned len = s->in[s->incnt++]; len |= s->in[s->incnt++] << 8; if (s->in[s->incnt++] != (~len & 0xff) || s->in[s->incnt++] != ((~len >> 8) & 0xff)) return -2; if (s->incnt + len > s->inlen) return 2; if (s->outcnt + len > s->outlen) return 1; for (; len--; s->outcnt++, s->incnt++) { if (s->in[s->incnt]) s->out[s->outcnt] = s->in[s->incnt]; } return 0; } struct puff_huffman { short* count; short* symbol; }; static int puff_decode(struct puff_state* s, const struct puff_huffman* h) { int first = 0; int index = 0; int bitbuf = s->bitbuf; int left = s->bitcnt; int code = first = index = 0; int len = 1; short* next = h->count + 1; while (1) { while (left--) { code |= bitbuf & 1; bitbuf >>= 1; int count = *next++; if (code - count < first) { s->bitbuf = bitbuf; s->bitcnt = (s->bitcnt - len) & 7; return h->symbol[index + (code - first)]; } index += count; first += count; first <<= 1; code <<= 1; len++; } left = (MAXBITS + 1) - len; if (left == 0) break; if (s->incnt == s->inlen) longjmp(s->env, 1); bitbuf = s->in[s->incnt++]; if (left > 8) left = 8; } return -10; } static int puff_construct(struct puff_huffman* h, const short* length, int n) { int len; for (len = 0; len <= MAXBITS; len++) h->count[len] = 0; int symbol; for (symbol = 0; symbol < n; symbol++) (h->count[length[symbol]])++; if (h->count[0] == n) return 0; int left = 1; for (len = 1; len <= MAXBITS; len++) { left <<= 1; left -= h->count[len]; if (left < 0) return left; } short offs[MAXBITS + 1]; offs[1] = 0; for (len = 1; len < MAXBITS; len++) offs[len + 1] = offs[len] + h->count[len]; for (symbol = 0; symbol < n; symbol++) if (length[symbol] != 0) h->symbol[offs[length[symbol]]++] = symbol; return left; } static int puff_codes(struct puff_state* s, const struct puff_huffman* lencode, const struct puff_huffman* distcode) { static const short lens[29] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258}; static const short lext[29] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0}; static const short dists[30] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; static const short dext[30] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; int symbol; do { symbol = puff_decode(s, lencode); if (symbol < 0) return symbol; if (symbol < 256) { if (s->outcnt == s->outlen) return 1; if (symbol) s->out[s->outcnt] = symbol; s->outcnt++; } else if (symbol > 256) { symbol -= 257; if (symbol >= 29) return -10; int len = lens[symbol] + puff_bits(s, lext[symbol]); symbol = puff_decode(s, distcode); if (symbol < 0) return symbol; unsigned dist = dists[symbol] + puff_bits(s, dext[symbol]); if (dist > s->outcnt) return -11; if (s->outcnt + len > s->outlen) return 1; while (len--) { if (dist <= s->outcnt && s->out[s->outcnt - dist]) s->out[s->outcnt] = s->out[s->outcnt - dist]; s->outcnt++; } } } while (symbol != 256); return 0; } static int puff_fixed(struct puff_state* s) { static int virgin = 1; static short lencnt[MAXBITS + 1], lensym[FIXLCODES]; static short distcnt[MAXBITS + 1], distsym[MAXDCODES]; static struct puff_huffman lencode, distcode; if (virgin) { lencode.count = lencnt; lencode.symbol = lensym; distcode.count = distcnt; distcode.symbol = distsym; short lengths[FIXLCODES]; int symbol; for (symbol = 0; symbol < 144; symbol++) lengths[symbol] = 8; for (; symbol < 256; symbol++) lengths[symbol] = 9; for (; symbol < 280; symbol++) lengths[symbol] = 7; for (; symbol < FIXLCODES; symbol++) lengths[symbol] = 8; puff_construct(&lencode, lengths, FIXLCODES); for (symbol = 0; symbol < MAXDCODES; symbol++) lengths[symbol] = 5; puff_construct(&distcode, lengths, MAXDCODES); virgin = 0; } return puff_codes(s, &lencode, &distcode); } static int puff_dynamic(struct puff_state* s) { static const short order[19] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; int nlen = puff_bits(s, 5) + 257; int ndist = puff_bits(s, 5) + 1; int ncode = puff_bits(s, 4) + 4; if (nlen > MAXLCODES || ndist > MAXDCODES) return -3; short lengths[MAXCODES]; int index; for (index = 0; index < ncode; index++) lengths[order[index]] = puff_bits(s, 3); for (; index < 19; index++) lengths[order[index]] = 0; short lencnt[MAXBITS + 1], lensym[MAXLCODES]; struct puff_huffman lencode = {lencnt, lensym}; int err = puff_construct(&lencode, lengths, 19); if (err != 0) return -4; index = 0; while (index < nlen + ndist) { int symbol; int len; symbol = puff_decode(s, &lencode); if (symbol < 0) return symbol; if (symbol < 16) lengths[index++] = symbol; else { len = 0; if (symbol == 16) { if (index == 0) return -5; len = lengths[index - 1]; symbol = 3 + puff_bits(s, 2); } else if (symbol == 17) symbol = 3 + puff_bits(s, 3); else symbol = 11 + puff_bits(s, 7); if (index + symbol > nlen + ndist) return -6; while (symbol--) lengths[index++] = len; } } if (lengths[256] == 0) return -9; err = puff_construct(&lencode, lengths, nlen); if (err && (err < 0 || nlen != lencode.count[0] + lencode.count[1])) return -7; short distcnt[MAXBITS + 1], distsym[MAXDCODES]; struct puff_huffman distcode = {distcnt, distsym}; err = puff_construct(&distcode, lengths + nlen, ndist); if (err && (err < 0 || ndist != distcode.count[0] + distcode.count[1])) return -8; return puff_codes(s, &lencode, &distcode); } static int puff(unsigned char* dest, unsigned long* destlen, const unsigned char* source, unsigned long sourcelen) { struct puff_state s = { .out = dest, .outlen = *destlen, .outcnt = 0, .in = source, .inlen = sourcelen, .incnt = 0, .bitbuf = 0, .bitcnt = 0, }; int err; if (setjmp(s.env) != 0) err = 2; else { int last; do { last = puff_bits(&s, 1); int type = puff_bits(&s, 2); err = type == 0 ? puff_stored(&s) : (type == 1 ? puff_fixed(&s) : (type == 2 ? puff_dynamic(&s) : -1)); if (err != 0) break; } while (!last); } *destlen = s.outcnt; return err; } //% END CODE DERIVED FROM puff.{c,h} #define ZLIB_HEADER_WIDTH 2 static int puff_zlib_to_file(const unsigned char* source, unsigned long sourcelen, int dest_fd) { if (sourcelen < ZLIB_HEADER_WIDTH) return 0; source += ZLIB_HEADER_WIDTH; sourcelen -= ZLIB_HEADER_WIDTH; const unsigned long max_destlen = 132 << 20; void* ret = mmap(0, max_destlen, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANON, -1, 0); if (ret == MAP_FAILED) return -1; unsigned char* dest = (unsigned char*)ret; unsigned long destlen = max_destlen; int err = puff(dest, &destlen, source, sourcelen); if (err) { munmap(dest, max_destlen); errno = -err; return -1; } if (write(dest_fd, dest, destlen) != (ssize_t)destlen) { munmap(dest, max_destlen); return -1; } return munmap(dest, max_destlen); } static int setup_loop_device(unsigned char* data, unsigned long size, const char* loopname, int* loopfd_p) { int err = 0, loopfd = -1; int memfd = syscall(__NR_memfd_create, "syzkaller", 0); if (memfd == -1) { err = errno; goto error; } if (puff_zlib_to_file(data, size, memfd)) { err = errno; goto error_close_memfd; } loopfd = open(loopname, O_RDWR); if (loopfd == -1) { err = errno; goto error_close_memfd; } if (ioctl(loopfd, LOOP_SET_FD, memfd)) { if (errno != EBUSY) { err = errno; goto error_close_loop; } ioctl(loopfd, LOOP_CLR_FD, 0); usleep(1000); if (ioctl(loopfd, LOOP_SET_FD, memfd)) { err = errno; goto error_close_loop; } } close(memfd); *loopfd_p = loopfd; return 0; error_close_loop: close(loopfd); error_close_memfd: close(memfd); error: errno = err; return -1; } static void reset_loop_device(const char* loopname) { int loopfd = open(loopname, O_RDWR); if (loopfd == -1) { return; } if (ioctl(loopfd, LOOP_CLR_FD, 0)) { } close(loopfd); } static long syz_mount_image(volatile long fsarg, volatile long dir, volatile long flags, volatile long optsarg, volatile long change_dir, volatile unsigned long size, volatile long image) { unsigned char* data = (unsigned char*)image; int res = -1, err = 0, need_loop_device = !!size; char* mount_opts = (char*)optsarg; char* target = (char*)dir; char* fs = (char*)fsarg; char* source = NULL; char loopname[64]; if (need_loop_device) { int loopfd; memset(loopname, 0, sizeof(loopname)); snprintf(loopname, sizeof(loopname), "/dev/loop%llu", procid); if (setup_loop_device(data, size, loopname, &loopfd) == -1) return -1; close(loopfd); source = loopname; } mkdir(target, 0777); char opts[256]; memset(opts, 0, sizeof(opts)); if (strlen(mount_opts) > (sizeof(opts) - 32)) { } strncpy(opts, mount_opts, sizeof(opts) - 32); if (strcmp(fs, "iso9660") == 0) { flags |= MS_RDONLY; } else if (strncmp(fs, "ext", 3) == 0) { bool has_remount_ro = false; char* remount_ro_start = strstr(opts, "errors=remount-ro"); if (remount_ro_start != NULL) { char after = *(remount_ro_start + strlen("errors=remount-ro")); char before = remount_ro_start == opts ? '\0' : *(remount_ro_start - 1); has_remount_ro = ((before == '\0' || before == ',') && (after == '\0' || after == ',')); } if (strstr(opts, "errors=panic") || !has_remount_ro) strcat(opts, ",errors=continue"); } else if (strcmp(fs, "xfs") == 0) { strcat(opts, ",nouuid"); } else if (strncmp(fs, "gfs2", 4) == 0 && (strstr(opts, "errors=panic") || strstr(opts, "debug"))) { strcat(opts, ",errors=withdraw"); } res = mount(source, target, fs, flags, opts); if (res == -1) { err = errno; goto error_clear_loop; } res = open(target, O_RDONLY | O_DIRECTORY); if (res == -1) { err = errno; goto error_clear_loop; } if (change_dir) { res = chdir(target); if (res == -1) { err = errno; } } error_clear_loop: if (need_loop_device) reset_loop_device(loopname); errno = err; return res; } #define noinline __attribute__((noinline)) #define always_inline __attribute__((always_inline)) inline #define __no_stack_protector #define __addrspace_guest #define __optnone #define GUEST_CODE \ __attribute__((section("guest"))) __no_stack_protector __addrspace_guest extern char *__start_guest, *__stop_guest; struct api_call_header { uint64_t call; uint64_t size; }; struct api_call_1 { struct api_call_header header; uint64_t arg; }; struct api_call_2 { struct api_call_header header; uint64_t args[2]; }; struct api_call_3 { struct api_call_header header; uint64_t args[3]; }; struct api_call_5 { struct api_call_header header; uint64_t args[5]; }; #define X86_ADDR_TEXT 0x0000 #define X86_ADDR_PD_IOAPIC 0x0000 #define X86_ADDR_GDT 0x1000 #define X86_ADDR_LDT 0x1800 #define X86_ADDR_PML4 0x2000 #define X86_ADDR_PDP 0x3000 #define X86_ADDR_PD 0x4000 #define X86_ADDR_STACK0 0x0f80 #define X86_ADDR_VAR_HLT 0x2800 #define X86_ADDR_VAR_SYSRET 0x2808 #define X86_ADDR_VAR_SYSEXIT 0x2810 #define X86_ADDR_VAR_IDT 0x3800 #define X86_ADDR_VAR_TSS64 0x3a00 #define X86_ADDR_VAR_TSS64_CPL3 0x3c00 #define X86_ADDR_VAR_TSS16 0x3d00 #define X86_ADDR_VAR_TSS16_2 0x3e00 #define X86_ADDR_VAR_TSS16_CPL3 0x3f00 #define X86_ADDR_VAR_TSS32 0x4800 #define X86_ADDR_VAR_TSS32_2 0x4a00 #define X86_ADDR_VAR_TSS32_CPL3 0x4c00 #define X86_ADDR_VAR_TSS32_VM86 0x4e00 #define X86_ADDR_VAR_VMXON_PTR 0x5f00 #define X86_ADDR_VAR_VMCS_PTR 0x5f08 #define X86_ADDR_VAR_VMEXIT_PTR 0x5f10 #define X86_ADDR_VAR_VMWRITE_FLD 0x5f18 #define X86_ADDR_VAR_VMWRITE_VAL 0x5f20 #define X86_ADDR_VAR_VMXON 0x6000 #define X86_ADDR_VAR_VMCS 0x7000 #define X86_ADDR_VAR_VMEXIT_CODE 0x9000 #define X86_ADDR_VAR_USER_CODE 0x9100 #define X86_ADDR_VAR_USER_CODE2 0x9120 #define X86_SYZOS_ADDR_ZERO 0x0 #define X86_SYZOS_ADDR_GDT 0x1000 #define X86_SYZOS_ADDR_PML4 0x2000 #define X86_SYZOS_ADDR_PDP 0x3000 #define X86_SYZOS_ADDR_VAR_IDT 0x25000 #define X86_SYZOS_ADDR_VAR_TSS 0x26000 #define X86_SYZOS_ADDR_BOOT_ARGS 0x2F000 #define X86_SYZOS_ADDR_SMRAM 0x30000 #define X86_SYZOS_ADDR_EXIT 0x40000 #define X86_SYZOS_ADDR_UEXIT (X86_SYZOS_ADDR_EXIT + 256) #define X86_SYZOS_ADDR_DIRTY_PAGES 0x41000 #define X86_SYZOS_ADDR_USER_CODE 0x50000 #define SYZOS_ADDR_EXECUTOR_CODE 0x54000 #define X86_SYZOS_ADDR_SCRATCH_CODE 0x58000 #define X86_SYZOS_ADDR_STACK_BOTTOM 0x60000 #define X86_SYZOS_ADDR_STACK0 0x60f80 #define X86_SYZOS_PER_VCPU_REGIONS_BASE 0x400000 #define X86_SYZOS_L1_VCPU_REGION_SIZE 0x40000 #define X86_SYZOS_L1_VCPU_OFFSET_VM_ARCH_SPECIFIC 0x0000 #define X86_SYZOS_L1_VCPU_OFFSET_L2_VMS_AREA 0x1000 #define X86_SYZOS_ADDR_GLOBALS 0x17F000 #define X86_SYZOS_ADDR_PT_POOL 0x180000 #define X86_SYZOS_PT_POOL_SIZE 64 #define X86_SYZOS_L2_VM_REGION_SIZE 0x8000 #define X86_SYZOS_L2_VM_OFFSET_VMCS_VMCB 0x0000 #define X86_SYZOS_L2_VM_OFFSET_VM_STACK 0x1000 #define X86_SYZOS_L2_VM_OFFSET_VM_CODE 0x2000 #define X86_SYZOS_L2_VM_OFFSET_VM_PGTABLE 0x3000 #define X86_SYZOS_L2_VM_OFFSET_MSR_BITMAP 0x7000 #define X86_SYZOS_ADDR_UNUSED 0x1000000 #define X86_SYZOS_ADDR_IOAPIC 0xfec00000 #define X86_SYZOS_ADDR_VMCS_VMCB(cpu, vm) \ (X86_SYZOS_PER_VCPU_REGIONS_BASE + (cpu) * X86_SYZOS_L1_VCPU_REGION_SIZE + \ X86_SYZOS_L1_VCPU_OFFSET_L2_VMS_AREA + (vm) * X86_SYZOS_L2_VM_REGION_SIZE + \ X86_SYZOS_L2_VM_OFFSET_VMCS_VMCB) #define X86_SYZOS_ADDR_VM_CODE(cpu, vm) \ (X86_SYZOS_PER_VCPU_REGIONS_BASE + (cpu) * X86_SYZOS_L1_VCPU_REGION_SIZE + \ X86_SYZOS_L1_VCPU_OFFSET_L2_VMS_AREA + (vm) * X86_SYZOS_L2_VM_REGION_SIZE + \ X86_SYZOS_L2_VM_OFFSET_VM_CODE) #define X86_SYZOS_ADDR_VM_STACK(cpu, vm) \ (X86_SYZOS_PER_VCPU_REGIONS_BASE + (cpu) * X86_SYZOS_L1_VCPU_REGION_SIZE + \ X86_SYZOS_L1_VCPU_OFFSET_L2_VMS_AREA + (vm) * X86_SYZOS_L2_VM_REGION_SIZE + \ X86_SYZOS_L2_VM_OFFSET_VM_STACK) #define X86_SYZOS_ADDR_VM_PGTABLE(cpu, vm) \ (X86_SYZOS_PER_VCPU_REGIONS_BASE + (cpu) * X86_SYZOS_L1_VCPU_REGION_SIZE + \ X86_SYZOS_L1_VCPU_OFFSET_L2_VMS_AREA + (vm) * X86_SYZOS_L2_VM_REGION_SIZE + \ X86_SYZOS_L2_VM_OFFSET_VM_PGTABLE) #define X86_SYZOS_ADDR_MSR_BITMAP(cpu, vm) \ (X86_SYZOS_PER_VCPU_REGIONS_BASE + (cpu) * X86_SYZOS_L1_VCPU_REGION_SIZE + \ X86_SYZOS_L1_VCPU_OFFSET_L2_VMS_AREA + (vm) * X86_SYZOS_L2_VM_REGION_SIZE + \ X86_SYZOS_L2_VM_OFFSET_MSR_BITMAP) #define X86_SYZOS_ADDR_VM_ARCH_SPECIFIC(cpu) \ (X86_SYZOS_PER_VCPU_REGIONS_BASE + (cpu) * X86_SYZOS_L1_VCPU_REGION_SIZE + \ X86_SYZOS_L1_VCPU_OFFSET_VM_ARCH_SPECIFIC) #define X86_SYZOS_SEL_CODE 0x8 #define X86_SYZOS_SEL_DATA 0x10 #define X86_SYZOS_SEL_TSS64 0x18 #define X86_CR0_PE 1ULL #define X86_CR0_MP (1ULL << 1) #define X86_CR0_EM (1ULL << 2) #define X86_CR0_TS (1ULL << 3) #define X86_CR0_ET (1ULL << 4) #define X86_CR0_NE (1ULL << 5) #define X86_CR0_WP (1ULL << 16) #define X86_CR0_AM (1ULL << 18) #define X86_CR0_NW (1ULL << 29) #define X86_CR0_CD (1ULL << 30) #define X86_CR0_PG (1ULL << 31) #define X86_CR4_VME 1ULL #define X86_CR4_PVI (1ULL << 1) #define X86_CR4_TSD (1ULL << 2) #define X86_CR4_DE (1ULL << 3) #define X86_CR4_PSE (1ULL << 4) #define X86_CR4_PAE (1ULL << 5) #define X86_CR4_MCE (1ULL << 6) #define X86_CR4_PGE (1ULL << 7) #define X86_CR4_PCE (1ULL << 8) #define X86_CR4_OSFXSR (1ULL << 9) #define X86_CR4_OSXMMEXCPT (1ULL << 10) #define X86_CR4_UMIP (1ULL << 11) #define X86_CR4_VMXE (1ULL << 13) #define X86_CR4_SMXE (1ULL << 14) #define X86_CR4_FSGSBASE (1ULL << 16) #define X86_CR4_PCIDE (1ULL << 17) #define X86_CR4_OSXSAVE (1ULL << 18) #define X86_CR4_SMEP (1ULL << 20) #define X86_CR4_SMAP (1ULL << 21) #define X86_CR4_PKE (1ULL << 22) #define X86_EFER_SCE 1ULL #define X86_EFER_LME (1ULL << 8) #define X86_EFER_LMA (1ULL << 10) #define X86_EFER_NXE (1ULL << 11) #define X86_EFER_SVME (1ULL << 12) #define X86_EFER_LMSLE (1ULL << 13) #define X86_EFER_FFXSR (1ULL << 14) #define X86_EFER_TCE (1ULL << 15) #define X86_PDE32_PRESENT 1UL #define X86_PDE32_RW (1UL << 1) #define X86_PDE32_USER (1UL << 2) #define X86_PDE32_PS (1UL << 7) #define X86_PDE64_PRESENT 1 #define X86_PDE64_RW (1ULL << 1) #define X86_PDE64_USER (1ULL << 2) #define X86_PDE64_ACCESSED (1ULL << 5) #define X86_PDE64_DIRTY (1ULL << 6) #define X86_PDE64_PS (1ULL << 7) #define X86_PDE64_G (1ULL << 8) #define EPT_MEMTYPE_WB (6ULL << 3) #define EPT_ACCESSED (1ULL << 8) #define EPT_DIRTY (1ULL << 9) #define X86_SEL_LDT (1 << 3) #define X86_SEL_CS16 (2 << 3) #define X86_SEL_DS16 (3 << 3) #define X86_SEL_CS16_CPL3 ((4 << 3) + 3) #define X86_SEL_DS16_CPL3 ((5 << 3) + 3) #define X86_SEL_CS32 (6 << 3) #define X86_SEL_DS32 (7 << 3) #define X86_SEL_CS32_CPL3 ((8 << 3) + 3) #define X86_SEL_DS32_CPL3 ((9 << 3) + 3) #define X86_SEL_CS64 (10 << 3) #define X86_SEL_DS64 (11 << 3) #define X86_SEL_CS64_CPL3 ((12 << 3) + 3) #define X86_SEL_DS64_CPL3 ((13 << 3) + 3) #define X86_SEL_CGATE16 (14 << 3) #define X86_SEL_TGATE16 (15 << 3) #define X86_SEL_CGATE32 (16 << 3) #define X86_SEL_TGATE32 (17 << 3) #define X86_SEL_CGATE64 (18 << 3) #define X86_SEL_CGATE64_HI (19 << 3) #define X86_SEL_TSS16 (20 << 3) #define X86_SEL_TSS16_2 (21 << 3) #define X86_SEL_TSS16_CPL3 ((22 << 3) + 3) #define X86_SEL_TSS32 (23 << 3) #define X86_SEL_TSS32_2 (24 << 3) #define X86_SEL_TSS32_CPL3 ((25 << 3) + 3) #define X86_SEL_TSS32_VM86 (26 << 3) #define X86_SEL_TSS64 (27 << 3) #define X86_SEL_TSS64_HI (28 << 3) #define X86_SEL_TSS64_CPL3 ((29 << 3) + 3) #define X86_SEL_TSS64_CPL3_HI (30 << 3) #define X86_MSR_IA32_FEATURE_CONTROL 0x3a #define X86_MSR_IA32_VMX_BASIC 0x480 #define X86_MSR_IA32_SMBASE 0x9e #define X86_MSR_IA32_SYSENTER_CS 0x174 #define X86_MSR_IA32_SYSENTER_ESP 0x175 #define X86_MSR_IA32_SYSENTER_EIP 0x176 #define X86_MSR_IA32_CR_PAT 0x277 #define X86_MSR_CORE_PERF_GLOBAL_CTRL 0x38f #define X86_MSR_IA32_VMX_TRUE_PINBASED_CTLS 0x48d #define X86_MSR_IA32_VMX_TRUE_PROCBASED_CTLS 0x48e #define X86_MSR_IA32_VMX_TRUE_EXIT_CTLS 0x48f #define X86_MSR_IA32_VMX_TRUE_ENTRY_CTLS 0x490 #define X86_MSR_IA32_EFER 0xc0000080 #define X86_MSR_IA32_STAR 0xC0000081 #define X86_MSR_IA32_LSTAR 0xC0000082 #define X86_MSR_FS_BASE 0xc0000100 #define X86_MSR_GS_BASE 0xc0000101 #define X86_MSR_VM_HSAVE_PA 0xc0010117 #define X86_MSR_IA32_VMX_PROCBASED_CTLS2 0x48B #define RFLAGS_1_BIT (1ULL << 1) #define CPU_BASED_HLT_EXITING (1U << 7) #define CPU_BASED_RDTSC_EXITING (1U << 12) #define AR_TSS_AVAILABLE 0x0089 #define SVM_ATTR_LDTR_UNUSABLE 0x0000 #define VMX_AR_TSS_BUSY 0x008b #define VMX_AR_TSS_AVAILABLE 0x0089 #define VMX_AR_LDTR_UNUSABLE 0x10000 #define VM_ENTRY_IA32E_MODE (1U << 9) #define SECONDARY_EXEC_ENABLE_EPT (1U << 1) #define SECONDARY_EXEC_ENABLE_RDTSCP (1U << 3) #define VM_EXIT_HOST_ADDR_SPACE_SIZE (1U << 9) #define CPU_BASED_ACTIVATE_SECONDARY_CONTROLS (1U << 31) #define VMX_ACCESS_RIGHTS_P (1 << 7) #define VMX_ACCESS_RIGHTS_S (1 << 4) #define VMX_ACCESS_RIGHTS_TYPE_A (1 << 0) #define VMX_ACCESS_RIGHTS_TYPE_RW (1 << 1) #define VMX_ACCESS_RIGHTS_TYPE_E (1 << 3) #define VMX_ACCESS_RIGHTS_G (1 << 15) #define VMX_ACCESS_RIGHTS_DB (1 << 14) #define VMX_ACCESS_RIGHTS_L (1 << 13) #define VMX_AR_64BIT_DATA_STACK \ (VMX_ACCESS_RIGHTS_P | VMX_ACCESS_RIGHTS_S | VMX_ACCESS_RIGHTS_TYPE_RW | \ VMX_ACCESS_RIGHTS_TYPE_A | VMX_ACCESS_RIGHTS_G | VMX_ACCESS_RIGHTS_DB) #define VMX_AR_64BIT_CODE \ (VMX_ACCESS_RIGHTS_P | VMX_ACCESS_RIGHTS_S | VMX_ACCESS_RIGHTS_TYPE_E | \ VMX_ACCESS_RIGHTS_TYPE_RW | VMX_ACCESS_RIGHTS_TYPE_A | \ VMX_ACCESS_RIGHTS_G | VMX_ACCESS_RIGHTS_L) #define VMCS_VIRTUAL_PROCESSOR_ID 0x00000000 #define VMCS_POSTED_INTR_NV 0x00000002 #define VMCS_MSR_BITMAP 0x00002004 #define VMCS_VMREAD_BITMAP 0x00002006 #define VMCS_VMWRITE_BITMAP 0x00002008 #define VMCS_EPT_POINTER 0x0000201a #define VMCS_LINK_POINTER 0x00002800 #define VMCS_PIN_BASED_VM_EXEC_CONTROL 0x00004000 #define VMCS_CPU_BASED_VM_EXEC_CONTROL 0x00004002 #define VMCS_EXCEPTION_BITMAP 0x00004004 #define VMCS_PAGE_FAULT_ERROR_CODE_MASK 0x00004006 #define VMCS_PAGE_FAULT_ERROR_CODE_MATCH 0x00004008 #define VMCS_CR3_TARGET_COUNT 0x0000400a #define VMCS_VM_EXIT_CONTROLS 0x0000400c #define VMCS_VM_EXIT_MSR_STORE_COUNT 0x0000400e #define VMCS_VM_EXIT_MSR_LOAD_COUNT 0x00004010 #define VMCS_VM_ENTRY_CONTROLS 0x00004012 #define VMCS_VM_ENTRY_MSR_LOAD_COUNT 0x00004014 #define VMCS_VM_ENTRY_INTR_INFO_FIELD 0x00004016 #define VMCS_TPR_THRESHOLD 0x0000401c #define VMCS_SECONDARY_VM_EXEC_CONTROL 0x0000401e #define VMCS_VM_INSTRUCTION_ERROR 0x00004400 #define VMCS_VM_EXIT_REASON 0x00004402 #define VMCS_VMX_PREEMPTION_TIMER_VALUE 0x0000482e #define VMCS_CR0_GUEST_HOST_MASK 0x00006000 #define VMCS_CR4_GUEST_HOST_MASK 0x00006002 #define VMCS_CR0_READ_SHADOW 0x00006004 #define VMCS_CR4_READ_SHADOW 0x00006006 #define VMCS_HOST_ES_SELECTOR 0x00000c00 #define VMCS_HOST_CS_SELECTOR 0x00000c02 #define VMCS_HOST_SS_SELECTOR 0x00000c04 #define VMCS_HOST_DS_SELECTOR 0x00000c06 #define VMCS_HOST_FS_SELECTOR 0x00000c08 #define VMCS_HOST_GS_SELECTOR 0x00000c0a #define VMCS_HOST_TR_SELECTOR 0x00000c0c #define VMCS_HOST_IA32_PAT 0x00002c00 #define VMCS_HOST_IA32_EFER 0x00002c02 #define VMCS_HOST_IA32_PERF_GLOBAL_CTRL 0x00002c04 #define VMCS_HOST_IA32_SYSENTER_CS 0x00004c00 #define VMCS_HOST_CR0 0x00006c00 #define VMCS_HOST_CR3 0x00006c02 #define VMCS_HOST_CR4 0x00006c04 #define VMCS_HOST_FS_BASE 0x00006c06 #define VMCS_HOST_GS_BASE 0x00006c08 #define VMCS_HOST_TR_BASE 0x00006c0a #define VMCS_HOST_GDTR_BASE 0x00006c0c #define VMCS_HOST_IDTR_BASE 0x00006c0e #define VMCS_HOST_IA32_SYSENTER_ESP 0x00006c10 #define VMCS_HOST_IA32_SYSENTER_EIP 0x00006c12 #define VMCS_HOST_RSP 0x00006c14 #define VMCS_HOST_RIP 0x00006c16 #define VMCS_GUEST_INTR_STATUS 0x00000810 #define VMCS_GUEST_PML_INDEX 0x00000812 #define VMCS_GUEST_PHYSICAL_ADDRESS 0x00002400 #define VMCS_GUEST_IA32_DEBUGCTL 0x00002802 #define VMCS_GUEST_IA32_PAT 0x00002804 #define VMCS_GUEST_IA32_EFER 0x00002806 #define VMCS_GUEST_IA32_PERF_GLOBAL_CTRL 0x00002808 #define VMCS_GUEST_ES_SELECTOR 0x00000800 #define VMCS_GUEST_CS_SELECTOR 0x00000802 #define VMCS_GUEST_SS_SELECTOR 0x00000804 #define VMCS_GUEST_DS_SELECTOR 0x00000806 #define VMCS_GUEST_FS_SELECTOR 0x00000808 #define VMCS_GUEST_GS_SELECTOR 0x0000080a #define VMCS_GUEST_LDTR_SELECTOR 0x0000080c #define VMCS_GUEST_TR_SELECTOR 0x0000080e #define VMCS_GUEST_ES_LIMIT 0x00004800 #define VMCS_GUEST_CS_LIMIT 0x00004802 #define VMCS_GUEST_SS_LIMIT 0x00004804 #define VMCS_GUEST_DS_LIMIT 0x00004806 #define VMCS_GUEST_FS_LIMIT 0x00004808 #define VMCS_GUEST_GS_LIMIT 0x0000480a #define VMCS_GUEST_LDTR_LIMIT 0x0000480c #define VMCS_GUEST_TR_LIMIT 0x0000480e #define VMCS_GUEST_GDTR_LIMIT 0x00004810 #define VMCS_GUEST_IDTR_LIMIT 0x00004812 #define VMCS_GUEST_ES_ACCESS_RIGHTS 0x00004814 #define VMCS_GUEST_CS_ACCESS_RIGHTS 0x00004816 #define VMCS_GUEST_SS_ACCESS_RIGHTS 0x00004818 #define VMCS_GUEST_DS_ACCESS_RIGHTS 0x0000481a #define VMCS_GUEST_FS_ACCESS_RIGHTS 0x0000481c #define VMCS_GUEST_GS_ACCESS_RIGHTS 0x0000481e #define VMCS_GUEST_LDTR_ACCESS_RIGHTS 0x00004820 #define VMCS_GUEST_TR_ACCESS_RIGHTS 0x00004822 #define VMCS_GUEST_ACTIVITY_STATE 0x00004824 #define VMCS_GUEST_INTERRUPTIBILITY_INFO 0x00004826 #define VMCS_GUEST_SYSENTER_CS 0x0000482a #define VMCS_GUEST_CR0 0x00006800 #define VMCS_GUEST_CR3 0x00006802 #define VMCS_GUEST_CR4 0x00006804 #define VMCS_GUEST_ES_BASE 0x00006806 #define VMCS_GUEST_CS_BASE 0x00006808 #define VMCS_GUEST_SS_BASE 0x0000680a #define VMCS_GUEST_DS_BASE 0x0000680c #define VMCS_GUEST_FS_BASE 0x0000680e #define VMCS_GUEST_GS_BASE 0x00006810 #define VMCS_GUEST_LDTR_BASE 0x00006812 #define VMCS_GUEST_TR_BASE 0x00006814 #define VMCS_GUEST_GDTR_BASE 0x00006816 #define VMCS_GUEST_IDTR_BASE 0x00006818 #define VMCS_GUEST_DR7 0x0000681a #define VMCS_GUEST_RSP 0x0000681c #define VMCS_GUEST_RIP 0x0000681e #define VMCS_GUEST_RFLAGS 0x00006820 #define VMCS_GUEST_PENDING_DBG_EXCEPTIONS 0x00006822 #define VMCS_GUEST_SYSENTER_ESP 0x00006824 #define VMCS_GUEST_SYSENTER_EIP 0x00006826 #define VMCB_CTRL_INTERCEPT_VEC3 0x0c #define VMCB_CTRL_INTERCEPT_VEC3_ALL (0xffffffff) #define VMCB_CTRL_INTERCEPT_VEC4 0x10 #define VMCB_CTRL_INTERCEPT_VEC4_ALL (0x3ff) #define VMCB_CTRL_ASID 0x058 #define VMCB_EXIT_CODE 0x070 #define VMCB_EXITINFO2 0x080 #define VMCB_CTRL_NP_ENABLE 0x090 #define VMCB_CTRL_NPT_ENABLE_BIT 0 #define VMCB_CTRL_N_CR3 0x0b0 #define VMCB_GUEST_ES_SEL 0x400 #define VMCB_GUEST_ES_ATTR 0x402 #define VMCB_GUEST_ES_LIM 0x404 #define VMCB_GUEST_ES_BASE 0x408 #define VMCB_GUEST_CS_SEL 0x410 #define VMCB_GUEST_CS_ATTR 0x412 #define VMCB_GUEST_CS_LIM 0x414 #define VMCB_GUEST_CS_BASE 0x418 #define VMCB_GUEST_SS_SEL 0x420 #define VMCB_GUEST_SS_ATTR 0x422 #define VMCB_GUEST_SS_LIM 0x424 #define VMCB_GUEST_SS_BASE 0x428 #define VMCB_GUEST_DS_SEL 0x430 #define VMCB_GUEST_DS_ATTR 0x432 #define VMCB_GUEST_DS_LIM 0x434 #define VMCB_GUEST_DS_BASE 0x438 #define VMCB_GUEST_FS_SEL 0x440 #define VMCB_GUEST_FS_ATTR 0x442 #define VMCB_GUEST_FS_LIM 0x444 #define VMCB_GUEST_FS_BASE 0x448 #define VMCB_GUEST_GS_SEL 0x450 #define VMCB_GUEST_GS_ATTR 0x452 #define VMCB_GUEST_GS_LIM 0x454 #define VMCB_GUEST_GS_BASE 0x458 #define VMCB_GUEST_IDTR_SEL 0x480 #define VMCB_GUEST_IDTR_ATTR 0x482 #define VMCB_GUEST_IDTR_LIM 0x484 #define VMCB_GUEST_IDTR_BASE 0x488 #define VMCB_GUEST_GDTR_SEL 0x460 #define VMCB_GUEST_GDTR_ATTR 0x462 #define VMCB_GUEST_GDTR_LIM 0x464 #define VMCB_GUEST_GDTR_BASE 0x468 #define VMCB_GUEST_LDTR_SEL 0x470 #define VMCB_GUEST_LDTR_ATTR 0x472 #define VMCB_GUEST_LDTR_LIM 0x474 #define VMCB_GUEST_LDTR_BASE 0x478 #define VMCB_GUEST_TR_SEL 0x490 #define VMCB_GUEST_TR_ATTR 0x492 #define VMCB_GUEST_TR_LIM 0x494 #define VMCB_GUEST_TR_BASE 0x498 #define VMCB_GUEST_EFER 0x4d0 #define VMCB_GUEST_CR4 0x548 #define VMCB_GUEST_CR3 0x550 #define VMCB_GUEST_CR0 0x558 #define VMCB_GUEST_DR7 0x560 #define VMCB_GUEST_DR6 0x568 #define VMCB_GUEST_RFLAGS 0x570 #define VMCB_GUEST_RIP 0x578 #define VMCB_GUEST_RSP 0x5d8 #define VMCB_GUEST_PAT 0x668 #define VMCB_GUEST_DEBUGCTL 0x670 #define VMCB_RAX 0x5f8 #define SVM_ATTR_G (1 << 15) #define SVM_ATTR_DB (1 << 14) #define SVM_ATTR_L (1 << 13) #define SVM_ATTR_P (1 << 7) #define SVM_ATTR_S (1 << 4) #define SVM_ATTR_TYPE_A (1 << 0) #define SVM_ATTR_TYPE_RW (1 << 1) #define SVM_ATTR_TYPE_E (1 << 3) #define SVM_ATTR_TSS_BUSY 0x008b #define SVM_ATTR_64BIT_CODE \ (SVM_ATTR_P | SVM_ATTR_S | SVM_ATTR_TYPE_E | SVM_ATTR_TYPE_RW | \ SVM_ATTR_TYPE_A | SVM_ATTR_L | SVM_ATTR_G) #define SVM_ATTR_64BIT_DATA \ (SVM_ATTR_P | SVM_ATTR_S | SVM_ATTR_TYPE_RW | SVM_ATTR_TYPE_A | \ SVM_ATTR_DB | SVM_ATTR_G) #define X86_NEXT_INSN $0xbadc0de #define X86_PREFIX_SIZE 0xba1d #define KVM_MAX_VCPU 4 #define KVM_MAX_L2_VMS 4 #define KVM_PAGE_SIZE (1 << 12) #define KVM_GUEST_PAGES 1024 #define KVM_GUEST_MEM_SIZE (KVM_GUEST_PAGES * KVM_PAGE_SIZE) #define SZ_4K 0x00001000 #define SZ_64K 0x00010000 #define GENMASK_ULL(h, l) \ (((~0ULL) - (1ULL << (l)) + 1ULL) & (~0ULL >> (63 - (h)))) extern char* __start_guest; static always_inline uintptr_t executor_fn_guest_addr(void* fn) { volatile uintptr_t start = (uintptr_t)&__start_guest; volatile uintptr_t offset = SYZOS_ADDR_EXECUTOR_CODE; return (uintptr_t)fn - start + offset; } typedef enum { SYZOS_API_UEXIT = 0, SYZOS_API_CODE = 10, SYZOS_API_CPUID = 100, SYZOS_API_WRMSR = 101, SYZOS_API_RDMSR = 102, SYZOS_API_WR_CRN = 103, SYZOS_API_WR_DRN = 104, SYZOS_API_IN_DX = 105, SYZOS_API_OUT_DX = 106, SYZOS_API_SET_IRQ_HANDLER = 200, SYZOS_API_ENABLE_NESTED = 300, SYZOS_API_NESTED_CREATE_VM = 301, SYZOS_API_NESTED_LOAD_CODE = 302, SYZOS_API_NESTED_VMLAUNCH = 303, SYZOS_API_NESTED_VMRESUME = 304, SYZOS_API_NESTED_LOAD_SYZOS = 310, SYZOS_API_NESTED_INTEL_VMWRITE_MASK = 340, SYZOS_API_NESTED_AMD_VMCB_WRITE_MASK = 380, SYZOS_API_NESTED_AMD_INVLPGA = 381, SYZOS_API_NESTED_AMD_STGI = 382, SYZOS_API_NESTED_AMD_CLGI = 383, SYZOS_API_NESTED_AMD_INJECT_EVENT = 384, SYZOS_API_NESTED_AMD_SET_INTERCEPT = 385, SYZOS_API_NESTED_AMD_VMLOAD = 386, SYZOS_API_NESTED_AMD_VMSAVE = 387, SYZOS_API_STOP, } syzos_api_id; struct api_call_uexit { struct api_call_header header; uint64_t exit_code; }; struct api_call_code { struct api_call_header header; uint8_t insns[]; }; struct api_call_nested_load_code { struct api_call_header header; uint64_t vm_id; uint8_t insns[]; }; struct api_call_nested_load_syzos { struct api_call_header header; uint64_t vm_id; uint64_t unused_pages; uint8_t program[]; }; struct api_call_cpuid { struct api_call_header header; uint32_t eax; uint32_t ecx; }; struct l2_guest_regs { uint64_t rax, rbx, rcx, rdx, rsi, rdi, rbp; uint64_t r8, r9, r10, r11, r12, r13, r14, r15; }; #define MEM_REGION_FLAG_USER_CODE (1 << 0) #define MEM_REGION_FLAG_DIRTY_LOG (1 << 1) #define MEM_REGION_FLAG_READONLY (1 << 2) #define MEM_REGION_FLAG_EXECUTOR_CODE (1 << 3) #define MEM_REGION_FLAG_GPA0 (1 << 5) #define MEM_REGION_FLAG_NO_HOST_MEM (1 << 6) #define MEM_REGION_FLAG_REMAINING (1 << 7) struct mem_region { uint64_t gpa; int pages; uint32_t flags; }; struct syzos_boot_args { uint32_t region_count; uint32_t reserved; struct mem_region regions[]; }; struct syzos_globals { uint64_t alloc_offset; uint64_t total_size; uint64_t text_sizes[KVM_MAX_VCPU]; struct l2_guest_regs l2_ctx[KVM_MAX_VCPU][KVM_MAX_L2_VMS]; uint64_t active_vm_id[KVM_MAX_VCPU]; }; GUEST_CODE static void guest_uexit(uint64_t exit_code); GUEST_CODE static void nested_vm_exit_handler_intel(uint64_t exit_reason, struct l2_guest_regs* regs); GUEST_CODE static void nested_vm_exit_handler_amd(uint64_t exit_reason, struct l2_guest_regs* regs); GUEST_CODE static void guest_execute_code(uint8_t* insns, uint64_t size); GUEST_CODE static void guest_handle_cpuid(uint32_t eax, uint32_t ecx); GUEST_CODE static void guest_handle_wrmsr(uint64_t reg, uint64_t val); GUEST_CODE static void guest_handle_rdmsr(uint64_t reg); GUEST_CODE static void guest_handle_wr_crn(struct api_call_2* cmd); GUEST_CODE static void guest_handle_wr_drn(struct api_call_2* cmd); GUEST_CODE static void guest_handle_in_dx(struct api_call_2* cmd); GUEST_CODE static void guest_handle_out_dx(struct api_call_3* cmd); GUEST_CODE static void guest_handle_set_irq_handler(struct api_call_2* cmd); GUEST_CODE static void guest_handle_enable_nested(struct api_call_1* cmd, uint64_t cpu_id); GUEST_CODE static void guest_handle_nested_create_vm(struct api_call_1* cmd, uint64_t cpu_id); GUEST_CODE static void guest_handle_nested_load_code(struct api_call_nested_load_code* cmd, uint64_t cpu_id); GUEST_CODE static void guest_handle_nested_load_syzos(struct api_call_nested_load_syzos* cmd, uint64_t cpu_id); GUEST_CODE static void guest_handle_nested_vmlaunch(struct api_call_1* cmd, uint64_t cpu_id); GUEST_CODE static void guest_handle_nested_vmresume(struct api_call_1* cmd, uint64_t cpu_id); GUEST_CODE static void guest_handle_nested_intel_vmwrite_mask(struct api_call_5* cmd, uint64_t cpu_id); GUEST_CODE static void guest_handle_nested_amd_vmcb_write_mask(struct api_call_5* cmd, uint64_t cpu_id); GUEST_CODE static void guest_handle_nested_amd_invlpga(struct api_call_2* cmd, uint64_t cpu_id); GUEST_CODE static void guest_handle_nested_amd_stgi(); GUEST_CODE static void guest_handle_nested_amd_clgi(); GUEST_CODE static void guest_handle_nested_amd_inject_event(struct api_call_5* cmd, uint64_t cpu_id); GUEST_CODE static void guest_handle_nested_amd_set_intercept(struct api_call_5* cmd, uint64_t cpu_id); GUEST_CODE static void guest_handle_nested_amd_vmload(struct api_call_1* cmd, uint64_t cpu_id); GUEST_CODE static void guest_handle_nested_amd_vmsave(struct api_call_1* cmd, uint64_t cpu_id); typedef enum { UEXIT_END = (uint64_t)-1, UEXIT_IRQ = (uint64_t)-2, UEXIT_ASSERT = (uint64_t)-3, UEXIT_INVALID_MAIN = (uint64_t)-4, } uexit_code; typedef enum { CPU_VENDOR_INTEL, CPU_VENDOR_AMD, } cpu_vendor_id; __attribute__((naked)) GUEST_CODE static void dummy_null_handler() { asm("iretq"); } __attribute__((naked)) GUEST_CODE static void uexit_irq_handler() { asm volatile(R"( movq $-2, %rdi call guest_uexit iretq )"); } __attribute__((used)) GUEST_CODE static void guest_main(uint64_t cpu) { volatile struct syzos_globals* globals = (volatile struct syzos_globals*)X86_SYZOS_ADDR_GLOBALS; uint64_t size = globals->text_sizes[cpu]; uint64_t addr = X86_SYZOS_ADDR_USER_CODE + cpu * KVM_PAGE_SIZE; while (size >= sizeof(struct api_call_header)) { struct api_call_header* cmd = (struct api_call_header*)addr; volatile uint64_t call = cmd->call; if ((call >= SYZOS_API_STOP) || (cmd->size > size)) { guest_uexit(UEXIT_INVALID_MAIN); return; } if (call == SYZOS_API_UEXIT) { struct api_call_uexit* ucmd = (struct api_call_uexit*)cmd; guest_uexit(ucmd->exit_code); } else if (call == SYZOS_API_CODE) { struct api_call_code* ccmd = (struct api_call_code*)cmd; guest_execute_code(ccmd->insns, cmd->size - sizeof(struct api_call_header)); } else if (call == SYZOS_API_CPUID) { struct api_call_cpuid* ccmd = (struct api_call_cpuid*)cmd; guest_handle_cpuid(ccmd->eax, ccmd->ecx); } else if (call == SYZOS_API_WRMSR) { struct api_call_2* ccmd = (struct api_call_2*)cmd; guest_handle_wrmsr(ccmd->args[0], ccmd->args[1]); } else if (call == SYZOS_API_RDMSR) { struct api_call_1* ccmd = (struct api_call_1*)cmd; guest_handle_rdmsr(ccmd->arg); } else if (call == SYZOS_API_WR_CRN) { guest_handle_wr_crn((struct api_call_2*)cmd); } else if (call == SYZOS_API_WR_DRN) { guest_handle_wr_drn((struct api_call_2*)cmd); } else if (call == SYZOS_API_IN_DX) { guest_handle_in_dx((struct api_call_2*)cmd); } else if (call == SYZOS_API_OUT_DX) { guest_handle_out_dx((struct api_call_3*)cmd); } else if (call == SYZOS_API_SET_IRQ_HANDLER) { guest_handle_set_irq_handler((struct api_call_2*)cmd); } else if (call == SYZOS_API_ENABLE_NESTED) { guest_handle_enable_nested((struct api_call_1*)cmd, cpu); } else if (call == SYZOS_API_NESTED_CREATE_VM) { guest_handle_nested_create_vm((struct api_call_1*)cmd, cpu); } else if (call == SYZOS_API_NESTED_LOAD_CODE) { guest_handle_nested_load_code((struct api_call_nested_load_code*)cmd, cpu); } else if (call == SYZOS_API_NESTED_LOAD_SYZOS) { guest_handle_nested_load_syzos((struct api_call_nested_load_syzos*)cmd, cpu); } else if (call == SYZOS_API_NESTED_VMLAUNCH) { guest_handle_nested_vmlaunch((struct api_call_1*)cmd, cpu); } else if (call == SYZOS_API_NESTED_VMRESUME) { guest_handle_nested_vmresume((struct api_call_1*)cmd, cpu); } else if (call == SYZOS_API_NESTED_INTEL_VMWRITE_MASK) { guest_handle_nested_intel_vmwrite_mask((struct api_call_5*)cmd, cpu); } else if (call == SYZOS_API_NESTED_AMD_VMCB_WRITE_MASK) { guest_handle_nested_amd_vmcb_write_mask((struct api_call_5*)cmd, cpu); } else if (call == SYZOS_API_NESTED_AMD_INVLPGA) { guest_handle_nested_amd_invlpga((struct api_call_2*)cmd, cpu); } else if (call == SYZOS_API_NESTED_AMD_STGI) { guest_handle_nested_amd_stgi(); } else if (call == SYZOS_API_NESTED_AMD_CLGI) { guest_handle_nested_amd_clgi(); } else if (call == SYZOS_API_NESTED_AMD_INJECT_EVENT) { guest_handle_nested_amd_inject_event((struct api_call_5*)cmd, cpu); } else if (call == SYZOS_API_NESTED_AMD_SET_INTERCEPT) { guest_handle_nested_amd_set_intercept((struct api_call_5*)cmd, cpu); } else if (call == SYZOS_API_NESTED_AMD_VMLOAD) { guest_handle_nested_amd_vmload((struct api_call_1*)cmd, cpu); } else if (call == SYZOS_API_NESTED_AMD_VMSAVE) { guest_handle_nested_amd_vmsave((struct api_call_1*)cmd, cpu); } addr += cmd->size; size -= cmd->size; }; guest_uexit(UEXIT_END); } GUEST_CODE static noinline void guest_execute_code(uint8_t* insns, uint64_t size) { volatile void (*fn)() = (volatile void (*)())insns; fn(); } __attribute__((used)) GUEST_CODE static noinline void guest_uexit(uint64_t exit_code) { volatile uint64_t* ptr = (volatile uint64_t*)X86_SYZOS_ADDR_UEXIT; asm volatile("movq %0, (%1)" ::"a"(exit_code), "r"(ptr) : "memory"); } GUEST_CODE static noinline void guest_handle_cpuid(uint32_t eax, uint32_t ecx) { asm volatile("cpuid\n" : : "a"(eax), "c"(ecx) : "rbx", "rdx"); } GUEST_CODE static noinline void wrmsr(uint64_t reg, uint64_t val) { asm volatile("wrmsr" : : "c"(reg), "a"((uint32_t)val), "d"((uint32_t)(val >> 32)) : "memory"); } GUEST_CODE static noinline void guest_handle_wrmsr(uint64_t reg, uint64_t val) { wrmsr(reg, val); } GUEST_CODE static noinline uint64_t rdmsr(uint64_t msr_id) { uint32_t low = 0, high = 0; asm volatile("rdmsr" : "=a"(low), "=d"(high) : "c"(msr_id)); return ((uint64_t)high << 32) | low; } GUEST_CODE static noinline void guest_handle_rdmsr(uint64_t reg) { (void)rdmsr(reg); } GUEST_CODE static noinline void guest_handle_wr_crn(struct api_call_2* cmd) { uint64_t value = cmd->args[1]; volatile uint64_t reg = cmd->args[0]; if (reg == 0) { asm volatile("movq %0, %%cr0" ::"r"(value) : "memory"); return; } if (reg == 2) { asm volatile("movq %0, %%cr2" ::"r"(value) : "memory"); return; } if (reg == 3) { asm volatile("movq %0, %%cr3" ::"r"(value) : "memory"); return; } if (reg == 4) { asm volatile("movq %0, %%cr4" ::"r"(value) : "memory"); return; } if (reg == 8) { asm volatile("movq %0, %%cr8" ::"r"(value) : "memory"); return; } } GUEST_CODE static noinline void guest_handle_wr_drn(struct api_call_2* cmd) { uint64_t value = cmd->args[1]; volatile uint64_t reg = cmd->args[0]; if (reg == 0) { asm volatile("movq %0, %%dr0" ::"r"(value) : "memory"); return; } if (reg == 1) { asm volatile("movq %0, %%dr1" ::"r"(value) : "memory"); return; } if (reg == 2) { asm volatile("movq %0, %%dr2" ::"r"(value) : "memory"); return; } if (reg == 3) { asm volatile("movq %0, %%dr3" ::"r"(value) : "memory"); return; } if (reg == 4) { asm volatile("movq %0, %%dr4" ::"r"(value) : "memory"); return; } if (reg == 5) { asm volatile("movq %0, %%dr5" ::"r"(value) : "memory"); return; } if (reg == 6) { asm volatile("movq %0, %%dr6" ::"r"(value) : "memory"); return; } if (reg == 7) { asm volatile("movq %0, %%dr7" ::"r"(value) : "memory"); return; } } GUEST_CODE static noinline void guest_handle_in_dx(struct api_call_2* cmd) { uint16_t port = cmd->args[0]; volatile int size = cmd->args[1]; if (size == 1) { uint8_t unused; asm volatile("inb %1, %0" : "=a"(unused) : "d"(port)); return; } if (size == 2) { uint16_t unused; asm volatile("inw %1, %0" : "=a"(unused) : "d"(port)); return; } if (size == 4) { uint32_t unused; asm volatile("inl %1, %0" : "=a"(unused) : "d"(port)); } return; } GUEST_CODE static noinline void guest_handle_out_dx(struct api_call_3* cmd) { uint16_t port = cmd->args[0]; volatile int size = cmd->args[1]; uint32_t data = (uint32_t)cmd->args[2]; if (size == 1) { asm volatile("outb %b0, %w1" ::"a"(data), "d"(port)); return; } if (size == 2) { asm volatile("outw %w0, %w1" ::"a"(data), "d"(port)); return; } if (size == 4) { asm volatile("outl %k0, %w1" ::"a"(data), "d"(port)); return; } } struct idt_entry_64 { uint16_t offset_low; uint16_t selector; uint8_t ist; uint8_t type_attr; uint16_t offset_mid; uint32_t offset_high; uint32_t reserved; } __attribute__((packed)); GUEST_CODE static void set_idt_gate(uint8_t vector, uint64_t handler) { volatile struct idt_entry_64* idt = (volatile struct idt_entry_64*)(X86_SYZOS_ADDR_VAR_IDT); volatile struct idt_entry_64* idt_entry = &idt[vector]; idt_entry->offset_low = (uint16_t)handler; idt_entry->offset_mid = (uint16_t)(handler >> 16); idt_entry->offset_high = (uint32_t)(handler >> 32); idt_entry->selector = X86_SYZOS_SEL_CODE; idt_entry->type_attr = 0x8E; idt_entry->ist = 0; idt_entry->reserved = 0; } GUEST_CODE static noinline void guest_handle_set_irq_handler(struct api_call_2* cmd) { uint8_t vector = (uint8_t)cmd->args[0]; uint64_t type = cmd->args[1]; volatile uint64_t handler_addr = 0; if (type == 1) handler_addr = executor_fn_guest_addr(dummy_null_handler); else if (type == 2) handler_addr = executor_fn_guest_addr(uexit_irq_handler); set_idt_gate(vector, handler_addr); } GUEST_CODE static cpu_vendor_id get_cpu_vendor(void) { uint32_t ebx, eax = 0; asm volatile("cpuid" : "+a"(eax), "=b"(ebx) : : "ecx", "edx"); if (ebx == 0x756e6547) { return CPU_VENDOR_INTEL; } else if (ebx == 0x68747541) { return CPU_VENDOR_AMD; } else { guest_uexit(UEXIT_ASSERT); return CPU_VENDOR_INTEL; } } GUEST_CODE static inline uint64_t read_cr0(void) { uint64_t val; asm volatile("mov %%cr0, %0" : "=r"(val)); return val; } GUEST_CODE static inline uint64_t read_cr3(void) { uint64_t val; asm volatile("mov %%cr3, %0" : "=r"(val)); return val; } GUEST_CODE static inline uint64_t read_cr4(void) { uint64_t val; asm volatile("mov %%cr4, %0" : "=r"(val)); return val; } GUEST_CODE static inline void write_cr4(uint64_t val) { asm volatile("mov %0, %%cr4" : : "r"(val)); } GUEST_CODE static noinline void vmwrite(uint64_t field, uint64_t value) { uint8_t error = 0; asm volatile("vmwrite %%rax, %%rbx; setna %0" : "=q"(error) : "a"(value), "b"(field) : "cc", "memory"); if (error) guest_uexit(UEXIT_ASSERT); } GUEST_CODE static noinline uint64_t vmread(uint64_t field) { uint64_t value; asm volatile("vmread %%rbx, %%rax" : "=a"(value) : "b"(field) : "cc"); return value; } GUEST_CODE static inline void nested_vmptrld(uint64_t cpu_id, uint64_t vm_id) { uint64_t vmcs_addr = X86_SYZOS_ADDR_VMCS_VMCB(cpu_id, vm_id); uint8_t error = 0; asm volatile("vmptrld %1; setna %0" : "=q"(error) : "m"(vmcs_addr) : "memory", "cc"); if (error) guest_uexit(0xE2BAD2); } GUEST_CODE static noinline void vmcb_write16(uint64_t vmcb, uint16_t offset, uint16_t val) { *((volatile uint16_t*)(vmcb + offset)) = val; } GUEST_CODE static noinline void vmcb_write32(uint64_t vmcb, uint16_t offset, uint32_t val) { *((volatile uint32_t*)(vmcb + offset)) = val; } GUEST_CODE static noinline uint32_t vmcb_read32(uint64_t vmcb, uint16_t offset) { return *((volatile uint32_t*)(vmcb + offset)); } GUEST_CODE static noinline void vmcb_write64(uint64_t vmcb, uint16_t offset, uint64_t val) { *((volatile uint64_t*)(vmcb + offset)) = val; } GUEST_CODE static noinline uint64_t vmcb_read64(volatile uint8_t* vmcb, uint16_t offset) { return *((volatile uint64_t*)(vmcb + offset)); } GUEST_CODE static void guest_memset(void* s, uint8_t c, int size) { volatile uint8_t* p = (volatile uint8_t*)s; for (int i = 0; i < size; i++) p[i] = c; } GUEST_CODE static void guest_memcpy(void* dst, void* src, int size) { volatile uint8_t* d = (volatile uint8_t*)dst; volatile uint8_t* s = (volatile uint8_t*)src; for (int i = 0; i < size; i++) d[i] = s[i]; } GUEST_CODE static noinline void nested_enable_vmx_intel(uint64_t cpu_id) { uint64_t vmxon_addr = X86_SYZOS_ADDR_VM_ARCH_SPECIFIC(cpu_id); uint64_t cr4 = read_cr4(); cr4 |= X86_CR4_VMXE; write_cr4(cr4); uint64_t feature_control = rdmsr(X86_MSR_IA32_FEATURE_CONTROL); if ((feature_control & 1) == 0) { feature_control |= 0b101; asm volatile("wrmsr" : : "d"(0x0), "c"(X86_MSR_IA32_FEATURE_CONTROL), "A"(feature_control)); } *(uint32_t*)vmxon_addr = rdmsr(X86_MSR_IA32_VMX_BASIC); uint8_t error; asm volatile("vmxon %1; setna %0" : "=q"(error) : "m"(vmxon_addr) : "memory", "cc"); if (error) { guest_uexit(0xE2BAD0); return; } } GUEST_CODE static noinline void nested_enable_svm_amd(uint64_t cpu_id) { uint64_t hsave_addr = X86_SYZOS_ADDR_VM_ARCH_SPECIFIC(cpu_id); uint64_t efer = rdmsr(X86_MSR_IA32_EFER); efer |= X86_EFER_SVME; wrmsr(X86_MSR_IA32_EFER, efer); wrmsr(X86_MSR_VM_HSAVE_PA, hsave_addr); } GUEST_CODE static noinline void guest_handle_enable_nested(struct api_call_1* cmd, uint64_t cpu_id) { if (get_cpu_vendor() == CPU_VENDOR_INTEL) { nested_enable_vmx_intel(cpu_id); } else { nested_enable_svm_amd(cpu_id); } } GUEST_CODE static uint64_t get_unused_memory_size() { volatile struct syzos_boot_args* args = (volatile struct syzos_boot_args*)X86_SYZOS_ADDR_BOOT_ARGS; for (uint32_t i = 0; i < args->region_count; i++) { if (args->regions[i].gpa == X86_SYZOS_ADDR_UNUSED) return args->regions[i].pages * KVM_PAGE_SIZE; } return 0; } GUEST_CODE static uint64_t guest_alloc_page() { volatile struct syzos_globals* globals = (volatile struct syzos_globals*)X86_SYZOS_ADDR_GLOBALS; if (globals->total_size == 0) { uint64_t size = get_unused_memory_size(); __sync_val_compare_and_swap(&globals->total_size, 0, size); } uint64_t offset = __sync_fetch_and_add(&globals->alloc_offset, KVM_PAGE_SIZE); if (offset >= globals->total_size) guest_uexit(UEXIT_ASSERT); uint64_t ptr = X86_SYZOS_ADDR_UNUSED + offset; guest_memset((void*)ptr, 0, KVM_PAGE_SIZE); return ptr; } GUEST_CODE static void l2_map_page(uint64_t cpu_id, uint64_t vm_id, uint64_t gpa, uint64_t host_pa, uint64_t flags) { uint64_t pml4_addr = X86_SYZOS_ADDR_VM_PGTABLE(cpu_id, vm_id); volatile uint64_t* pml4 = (volatile uint64_t*)pml4_addr; uint64_t pml4_idx = (gpa >> 39) & 0x1FF; if (!(pml4[pml4_idx] & X86_PDE64_PRESENT)) { uint64_t page = guest_alloc_page(); pml4[pml4_idx] = page | X86_PDE64_PRESENT | X86_PDE64_RW | X86_PDE64_USER; } volatile uint64_t* pdpt = (volatile uint64_t*)(pml4[pml4_idx] & ~0xFFF); uint64_t pdpt_idx = (gpa >> 30) & 0x1FF; if (!(pdpt[pdpt_idx] & X86_PDE64_PRESENT)) { uint64_t page = guest_alloc_page(); pdpt[pdpt_idx] = page | X86_PDE64_PRESENT | X86_PDE64_RW | X86_PDE64_USER; } volatile uint64_t* pd = (volatile uint64_t*)(pdpt[pdpt_idx] & ~0xFFF); uint64_t pd_idx = (gpa >> 21) & 0x1FF; if (!(pd[pd_idx] & X86_PDE64_PRESENT)) { uint64_t page = guest_alloc_page(); pd[pd_idx] = page | X86_PDE64_PRESENT | X86_PDE64_RW | X86_PDE64_USER; } volatile uint64_t* pt = (volatile uint64_t*)(pd[pd_idx] & ~0xFFF); uint64_t pt_idx = (gpa >> 12) & 0x1FF; if (!(pt[pt_idx] & X86_PDE64_PRESENT)) pt[pt_idx] = (host_pa & ~0xFFF) | flags; } GUEST_CODE static noinline void setup_l2_page_tables(cpu_vendor_id vendor, uint64_t cpu_id, uint64_t vm_id, uint64_t unused_pages) { uint64_t flags = X86_PDE64_PRESENT | X86_PDE64_RW | X86_PDE64_USER; if (vendor == CPU_VENDOR_INTEL) { flags |= EPT_MEMTYPE_WB | EPT_ACCESSED | EPT_DIRTY; } else { flags |= X86_PDE64_ACCESSED | X86_PDE64_DIRTY; } volatile struct syzos_boot_args* args = (volatile struct syzos_boot_args*)X86_SYZOS_ADDR_BOOT_ARGS; for (uint32_t i = 0; i < args->region_count; i++) { struct mem_region r; r.gpa = args->regions[i].gpa; r.pages = args->regions[i].pages; r.flags = args->regions[i].flags; if (r.flags & MEM_REGION_FLAG_NO_HOST_MEM) continue; if (r.flags & MEM_REGION_FLAG_REMAINING) { r.pages = (unused_pages < 16) ? 16 : unused_pages; } for (int p = 0; p < r.pages; p++) { uint64_t gpa = r.gpa + (p * KVM_PAGE_SIZE); uint64_t backing; if (r.gpa == X86_SYZOS_ADDR_USER_CODE && p == 0) { backing = X86_SYZOS_ADDR_VM_CODE(cpu_id, vm_id); } else if (r.gpa == X86_SYZOS_ADDR_STACK_BOTTOM) { backing = X86_SYZOS_ADDR_VM_STACK(cpu_id, vm_id); } else { backing = gpa; } l2_map_page(cpu_id, vm_id, gpa, backing, flags); } } } GUEST_CODE static noinline void init_vmcs_control_fields(uint64_t cpu_id, uint64_t vm_id) { uint64_t vmx_msr = rdmsr(X86_MSR_IA32_VMX_TRUE_PINBASED_CTLS); vmwrite(VMCS_PIN_BASED_VM_EXEC_CONTROL, (uint32_t)vmx_msr); vmx_msr = (uint32_t)rdmsr(X86_MSR_IA32_VMX_PROCBASED_CTLS2); vmx_msr |= SECONDARY_EXEC_ENABLE_EPT | SECONDARY_EXEC_ENABLE_RDTSCP; vmwrite(VMCS_SECONDARY_VM_EXEC_CONTROL, vmx_msr); vmx_msr = rdmsr(X86_MSR_IA32_VMX_TRUE_PROCBASED_CTLS); vmx_msr |= CPU_BASED_ACTIVATE_SECONDARY_CONTROLS; vmx_msr |= CPU_BASED_HLT_EXITING | CPU_BASED_RDTSC_EXITING; vmwrite(VMCS_CPU_BASED_VM_EXEC_CONTROL, (uint32_t)vmx_msr); vmx_msr = rdmsr(X86_MSR_IA32_VMX_TRUE_EXIT_CTLS); vmwrite(VMCS_VM_EXIT_CONTROLS, (uint32_t)vmx_msr | VM_EXIT_HOST_ADDR_SPACE_SIZE); vmx_msr = rdmsr(X86_MSR_IA32_VMX_TRUE_ENTRY_CTLS); vmwrite(VMCS_VM_ENTRY_CONTROLS, (uint32_t)vmx_msr | VM_ENTRY_IA32E_MODE); uint64_t eptp = (X86_SYZOS_ADDR_VM_PGTABLE(cpu_id, vm_id) & ~0xFFF) | (6 << 0) | (3 << 3); vmwrite(VMCS_EPT_POINTER, eptp); vmwrite(VMCS_CR0_GUEST_HOST_MASK, 0); vmwrite(VMCS_CR4_GUEST_HOST_MASK, 0); vmwrite(VMCS_CR0_READ_SHADOW, read_cr0()); vmwrite(VMCS_CR4_READ_SHADOW, read_cr4()); vmwrite(VMCS_MSR_BITMAP, 0); vmwrite(VMCS_VMREAD_BITMAP, 0); vmwrite(VMCS_VMWRITE_BITMAP, 0); vmwrite(VMCS_EXCEPTION_BITMAP, (1 << 6)); vmwrite(VMCS_VIRTUAL_PROCESSOR_ID, 0); vmwrite(VMCS_POSTED_INTR_NV, 0); vmwrite(VMCS_PAGE_FAULT_ERROR_CODE_MASK, 0); vmwrite(VMCS_PAGE_FAULT_ERROR_CODE_MATCH, -1); vmwrite(VMCS_CR3_TARGET_COUNT, 0); vmwrite(VMCS_VM_EXIT_MSR_STORE_COUNT, 0); vmwrite(VMCS_VM_EXIT_MSR_LOAD_COUNT, 0); vmwrite(VMCS_VM_ENTRY_MSR_LOAD_COUNT, 0); vmwrite(VMCS_VM_ENTRY_INTR_INFO_FIELD, 0); vmwrite(VMCS_TPR_THRESHOLD, 0); } typedef enum { SYZOS_NESTED_EXIT_REASON_HLT = 1, SYZOS_NESTED_EXIT_REASON_INVD = 2, SYZOS_NESTED_EXIT_REASON_CPUID = 3, SYZOS_NESTED_EXIT_REASON_RDTSC = 4, SYZOS_NESTED_EXIT_REASON_RDTSCP = 5, SYZOS_NESTED_EXIT_REASON_EPT_VIOLATION = 6, SYZOS_NESTED_EXIT_REASON_UNKNOWN = 0xFF, } syz_nested_exit_reason; GUEST_CODE static void handle_nested_uexit(uint64_t exit_code) { uint64_t level = (exit_code >> 56) + 1; exit_code = (exit_code & 0x00FFFFFFFFFFFFFFULL) | (level << 56); guest_uexit(exit_code); } GUEST_CODE static void guest_uexit_l2(uint64_t exit_reason, syz_nested_exit_reason mapped_reason, cpu_vendor_id vendor) { if (mapped_reason != SYZOS_NESTED_EXIT_REASON_UNKNOWN) { guest_uexit(0xe2e20000 | mapped_reason); } else if (vendor == CPU_VENDOR_INTEL) { guest_uexit(0xe2110000 | exit_reason); } else { guest_uexit(0xe2aa0000 | exit_reason); } } #define EXIT_REASON_CPUID 0xa #define EXIT_REASON_HLT 0xc #define EXIT_REASON_INVD 0xd #define EXIT_REASON_EPT_VIOLATION 0x30 #define EXIT_REASON_RDTSC 0x10 #define EXIT_REASON_RDTSCP 0x33 GUEST_CODE static syz_nested_exit_reason map_intel_exit_reason(uint64_t basic_reason) { volatile uint64_t reason = basic_reason; if (reason == EXIT_REASON_HLT) return SYZOS_NESTED_EXIT_REASON_HLT; if (reason == EXIT_REASON_INVD) return SYZOS_NESTED_EXIT_REASON_INVD; if (reason == EXIT_REASON_CPUID) return SYZOS_NESTED_EXIT_REASON_CPUID; if (reason == EXIT_REASON_RDTSC) return SYZOS_NESTED_EXIT_REASON_RDTSC; if (reason == EXIT_REASON_RDTSCP) return SYZOS_NESTED_EXIT_REASON_RDTSCP; if (reason == EXIT_REASON_EPT_VIOLATION) return SYZOS_NESTED_EXIT_REASON_EPT_VIOLATION; return SYZOS_NESTED_EXIT_REASON_UNKNOWN; } GUEST_CODE static void advance_l2_rip_intel(uint64_t basic_reason) { volatile uint64_t reason = basic_reason; uint64_t rip = vmread(VMCS_GUEST_RIP); if ((reason == EXIT_REASON_INVD) || (reason == EXIT_REASON_CPUID) || (reason == EXIT_REASON_RDTSC)) { rip += 2; } else if (reason == EXIT_REASON_RDTSCP) { rip += 3; } vmwrite(VMCS_GUEST_RIP, rip); } __attribute__((used)) GUEST_CODE static void nested_vm_exit_handler_intel(uint64_t exit_reason, struct l2_guest_regs* regs) { volatile struct syzos_globals* globals = (volatile struct syzos_globals*)X86_SYZOS_ADDR_GLOBALS; uint64_t cpu_id = *(uint64_t*)((char*)regs + sizeof(struct l2_guest_regs) + 7 * 8); uint64_t vm_id = globals->active_vm_id[cpu_id]; guest_memcpy((void*)&globals->l2_ctx[cpu_id][vm_id], regs, sizeof(struct l2_guest_regs)); uint64_t basic_reason = exit_reason & 0xFFFF; if (basic_reason == EXIT_REASON_EPT_VIOLATION) { uint64_t gpa = vmread(VMCS_GUEST_PHYSICAL_ADDRESS); if ((gpa & ~0xFFF) == X86_SYZOS_ADDR_EXIT) { handle_nested_uexit(regs->rax); vmwrite(VMCS_GUEST_RIP, vmread(VMCS_GUEST_RIP) + 3); return; } } syz_nested_exit_reason mapped_reason = map_intel_exit_reason(basic_reason); guest_uexit_l2(exit_reason, mapped_reason, CPU_VENDOR_INTEL); advance_l2_rip_intel(basic_reason); } extern char after_vmentry_label; __attribute__((naked)) GUEST_CODE static void nested_vm_exit_handler_intel_asm(void) { asm volatile(R"( push %%r15 push %%r14 push %%r13 push %%r12 push %%r11 push %%r10 push %%r9 push %%r8 push %%rbp push %%rdi push %%rsi push %%rdx push %%rcx push %%rbx push %%rax mov %%rsp, %%rsi mov %[vm_exit_reason], %%rbx vmread %%rbx, %%rdi call nested_vm_exit_handler_intel add %[l2_regs_size], %%rsp pop %%r15 pop %%r14 pop %%r13 pop %%r12 pop %%rbp pop %%rbx add $16, %%rsp add $128, %%rsp jmp after_vmentry_label )" : : [l2_regs_size] "i"(sizeof(struct l2_guest_regs)), [vm_exit_reason] "i"(VMCS_VM_EXIT_REASON) : "memory", "cc", "rbx", "rdi", "rsi"); } #define VMEXIT_RDTSC 0x6e #define VMEXIT_CPUID 0x72 #define VMEXIT_INVD 0x76 #define VMEXIT_HLT 0x78 #define VMEXIT_NPF 0x400 #define VMEXIT_RDTSCP 0x87 GUEST_CODE static syz_nested_exit_reason map_amd_exit_reason(uint64_t basic_reason) { volatile uint64_t reason = basic_reason; if (reason == VMEXIT_HLT) return SYZOS_NESTED_EXIT_REASON_HLT; if (reason == VMEXIT_INVD) return SYZOS_NESTED_EXIT_REASON_INVD; if (reason == VMEXIT_CPUID) return SYZOS_NESTED_EXIT_REASON_CPUID; if (reason == VMEXIT_RDTSC) return SYZOS_NESTED_EXIT_REASON_RDTSC; if (reason == VMEXIT_RDTSCP) return SYZOS_NESTED_EXIT_REASON_RDTSCP; if (reason == VMEXIT_NPF) return SYZOS_NESTED_EXIT_REASON_EPT_VIOLATION; return SYZOS_NESTED_EXIT_REASON_UNKNOWN; } GUEST_CODE static void advance_l2_rip_amd(uint64_t basic_reason, uint64_t cpu_id, uint64_t vm_id) { volatile uint64_t reason = basic_reason; uint64_t vmcb_addr = X86_SYZOS_ADDR_VMCS_VMCB(cpu_id, vm_id); uint64_t rip = vmcb_read64((volatile uint8_t*)vmcb_addr, VMCB_GUEST_RIP); if ((reason == VMEXIT_INVD) || (reason == VMEXIT_CPUID) || (reason == VMEXIT_RDTSC)) { rip += 2; } else if (reason == VMEXIT_RDTSCP) { rip += 3; } vmcb_write64(vmcb_addr, VMCB_GUEST_RIP, rip); } __attribute__((used)) GUEST_CODE static void nested_vm_exit_handler_amd(uint64_t exit_reason, struct l2_guest_regs* regs) { volatile struct syzos_globals* globals = (volatile struct syzos_globals*)X86_SYZOS_ADDR_GLOBALS; uint64_t cpu_id = *(uint64_t*)((char*)regs + sizeof(struct l2_guest_regs) + 8 * 8); uint64_t vm_id = globals->active_vm_id[cpu_id]; guest_memcpy((void*)&globals->l2_ctx[cpu_id][vm_id], regs, sizeof(struct l2_guest_regs)); volatile uint64_t basic_reason = exit_reason & 0xFFFF; if (basic_reason == VMEXIT_NPF) { uint64_t vmcb_addr = X86_SYZOS_ADDR_VMCS_VMCB(cpu_id, vm_id); uint64_t fault_gpa = vmcb_read64((volatile uint8_t*)vmcb_addr, VMCB_EXITINFO2); if ((fault_gpa & ~0xFFF) == X86_SYZOS_ADDR_EXIT) { handle_nested_uexit(regs->rax); uint64_t rip = vmcb_read64((volatile uint8_t*)vmcb_addr, VMCB_GUEST_RIP); vmcb_write64(vmcb_addr, VMCB_GUEST_RIP, rip + 3); return; } } syz_nested_exit_reason mapped_reason = map_amd_exit_reason(basic_reason); guest_uexit_l2(exit_reason, mapped_reason, CPU_VENDOR_AMD); advance_l2_rip_amd(basic_reason, cpu_id, vm_id); } GUEST_CODE static noinline void init_vmcs_host_state(void) { vmwrite(VMCS_HOST_CS_SELECTOR, X86_SYZOS_SEL_CODE); vmwrite(VMCS_HOST_DS_SELECTOR, X86_SYZOS_SEL_DATA); vmwrite(VMCS_HOST_ES_SELECTOR, X86_SYZOS_SEL_DATA); vmwrite(VMCS_HOST_SS_SELECTOR, X86_SYZOS_SEL_DATA); vmwrite(VMCS_HOST_FS_SELECTOR, X86_SYZOS_SEL_DATA); vmwrite(VMCS_HOST_GS_SELECTOR, X86_SYZOS_SEL_DATA); vmwrite(VMCS_HOST_TR_SELECTOR, X86_SYZOS_SEL_TSS64); vmwrite(VMCS_HOST_TR_BASE, X86_SYZOS_ADDR_VAR_TSS); vmwrite(VMCS_HOST_GDTR_BASE, X86_SYZOS_ADDR_GDT); vmwrite(VMCS_HOST_IDTR_BASE, X86_SYZOS_ADDR_VAR_IDT); vmwrite(VMCS_HOST_FS_BASE, rdmsr(X86_MSR_FS_BASE)); vmwrite(VMCS_HOST_GS_BASE, rdmsr(X86_MSR_GS_BASE)); vmwrite(VMCS_HOST_RIP, (uintptr_t)nested_vm_exit_handler_intel_asm); vmwrite(VMCS_HOST_CR0, read_cr0()); vmwrite(VMCS_HOST_CR3, read_cr3()); vmwrite(VMCS_HOST_CR4, read_cr4()); vmwrite(VMCS_HOST_IA32_PAT, rdmsr(X86_MSR_IA32_CR_PAT)); vmwrite(VMCS_HOST_IA32_EFER, rdmsr(X86_MSR_IA32_EFER)); vmwrite(VMCS_HOST_IA32_PERF_GLOBAL_CTRL, rdmsr(X86_MSR_CORE_PERF_GLOBAL_CTRL)); vmwrite(VMCS_HOST_IA32_SYSENTER_CS, rdmsr(X86_MSR_IA32_SYSENTER_CS)); vmwrite(VMCS_HOST_IA32_SYSENTER_ESP, rdmsr(X86_MSR_IA32_SYSENTER_ESP)); vmwrite(VMCS_HOST_IA32_SYSENTER_EIP, rdmsr(X86_MSR_IA32_SYSENTER_EIP)); } #define COPY_VMCS_FIELD(GUEST_FIELD, HOST_FIELD) \ vmwrite(GUEST_FIELD, vmread(HOST_FIELD)) #define SETUP_L2_SEGMENT(SEG, SELECTOR, BASE, LIMIT, AR) \ vmwrite(VMCS_GUEST_##SEG##_SELECTOR, SELECTOR); \ vmwrite(VMCS_GUEST_##SEG##_BASE, BASE); \ vmwrite(VMCS_GUEST_##SEG##_LIMIT, LIMIT); \ vmwrite(VMCS_GUEST_##SEG##_ACCESS_RIGHTS, AR); GUEST_CODE static noinline void init_vmcs_guest_state(uint64_t cpu_id, uint64_t vm_id) { uint64_t l2_code_addr = X86_SYZOS_ADDR_VM_CODE(cpu_id, vm_id); uint64_t l2_stack_addr = X86_SYZOS_ADDR_VM_STACK(cpu_id, vm_id); SETUP_L2_SEGMENT(CS, vmread(VMCS_HOST_CS_SELECTOR), 0, 0xFFFFFFFF, VMX_AR_64BIT_CODE); SETUP_L2_SEGMENT(DS, vmread(VMCS_HOST_DS_SELECTOR), 0, 0xFFFFFFFF, VMX_AR_64BIT_DATA_STACK); SETUP_L2_SEGMENT(ES, vmread(VMCS_HOST_ES_SELECTOR), 0, 0xFFFFFFFF, VMX_AR_64BIT_DATA_STACK); SETUP_L2_SEGMENT(SS, vmread(VMCS_HOST_SS_SELECTOR), 0, 0xFFFFFFFF, VMX_AR_64BIT_DATA_STACK); SETUP_L2_SEGMENT(FS, vmread(VMCS_HOST_FS_SELECTOR), vmread(VMCS_HOST_FS_BASE), 0xFFFFFFFF, VMX_AR_64BIT_DATA_STACK); SETUP_L2_SEGMENT(GS, vmread(VMCS_HOST_GS_SELECTOR), vmread(VMCS_HOST_GS_BASE), 0xFFFFFFFF, VMX_AR_64BIT_DATA_STACK); SETUP_L2_SEGMENT(TR, vmread(VMCS_HOST_TR_SELECTOR), vmread(VMCS_HOST_TR_BASE), 0x67, VMX_AR_TSS_BUSY); SETUP_L2_SEGMENT(LDTR, 0, 0, 0, VMX_AR_LDTR_UNUSABLE); vmwrite(VMCS_GUEST_CR0, vmread(VMCS_HOST_CR0)); vmwrite(VMCS_GUEST_CR3, vmread(VMCS_HOST_CR3)); vmwrite(VMCS_GUEST_CR4, vmread(VMCS_HOST_CR4)); vmwrite(VMCS_GUEST_RIP, l2_code_addr); vmwrite(VMCS_GUEST_RSP, l2_stack_addr + KVM_PAGE_SIZE - 8); vmwrite(VMCS_GUEST_RFLAGS, RFLAGS_1_BIT); vmwrite(VMCS_GUEST_DR7, 0x400); COPY_VMCS_FIELD(VMCS_GUEST_IA32_EFER, VMCS_HOST_IA32_EFER); COPY_VMCS_FIELD(VMCS_GUEST_IA32_PAT, VMCS_HOST_IA32_PAT); COPY_VMCS_FIELD(VMCS_GUEST_IA32_PERF_GLOBAL_CTRL, VMCS_HOST_IA32_PERF_GLOBAL_CTRL); COPY_VMCS_FIELD(VMCS_GUEST_SYSENTER_CS, VMCS_HOST_IA32_SYSENTER_CS); COPY_VMCS_FIELD(VMCS_GUEST_SYSENTER_ESP, VMCS_HOST_IA32_SYSENTER_ESP); COPY_VMCS_FIELD(VMCS_GUEST_SYSENTER_EIP, VMCS_HOST_IA32_SYSENTER_EIP); vmwrite(VMCS_GUEST_IA32_DEBUGCTL, 0); vmwrite(VMCS_GUEST_GDTR_BASE, vmread(VMCS_HOST_GDTR_BASE)); vmwrite(VMCS_GUEST_GDTR_LIMIT, 0xffff); vmwrite(VMCS_GUEST_IDTR_BASE, vmread(VMCS_HOST_IDTR_BASE)); vmwrite(VMCS_GUEST_IDTR_LIMIT, 0xffff); vmwrite(VMCS_LINK_POINTER, 0xffffffffffffffff); vmwrite(VMCS_GUEST_ACTIVITY_STATE, 0); vmwrite(VMCS_GUEST_INTERRUPTIBILITY_INFO, 0); vmwrite(VMCS_GUEST_PENDING_DBG_EXCEPTIONS, 0); vmwrite(VMCS_VMX_PREEMPTION_TIMER_VALUE, 0); vmwrite(VMCS_GUEST_INTR_STATUS, 0); vmwrite(VMCS_GUEST_PML_INDEX, 0); } GUEST_CODE static noinline void nested_create_vm_intel(struct api_call_1* cmd, uint64_t cpu_id) { uint64_t vm_id = cmd->arg; uint64_t vmcs_addr = X86_SYZOS_ADDR_VMCS_VMCB(cpu_id, vm_id); uint8_t error = 0; uint64_t l2_pml4_addr = X86_SYZOS_ADDR_VM_PGTABLE(cpu_id, vm_id); uint64_t l2_msr_bitmap = X86_SYZOS_ADDR_MSR_BITMAP(cpu_id, vm_id); *(uint32_t*)vmcs_addr = rdmsr(X86_MSR_IA32_VMX_BASIC); asm volatile("vmclear %1; setna %0" : "=q"(error) : "m"(vmcs_addr) : "memory", "cc"); if (error) { guest_uexit(0xE2BAD1); return; } nested_vmptrld(cpu_id, vm_id); guest_memset((void*)l2_pml4_addr, 0, KVM_PAGE_SIZE); guest_memset((void*)l2_msr_bitmap, 0, KVM_PAGE_SIZE); setup_l2_page_tables(CPU_VENDOR_INTEL, cpu_id, vm_id, 0); init_vmcs_control_fields(cpu_id, vm_id); init_vmcs_host_state(); init_vmcs_guest_state(cpu_id, vm_id); } #define SETUP_L2_SEGMENT_SVM(VMBC_PTR, SEG_NAME, SELECTOR, BASE, LIMIT, ATTR) \ vmcb_write16(VMBC_PTR, VMCB_GUEST_##SEG_NAME##_SEL, SELECTOR); \ vmcb_write16(VMBC_PTR, VMCB_GUEST_##SEG_NAME##_ATTR, ATTR); \ vmcb_write32(VMBC_PTR, VMCB_GUEST_##SEG_NAME##_LIM, LIMIT); \ vmcb_write64(VMBC_PTR, VMCB_GUEST_##SEG_NAME##_BASE, BASE); GUEST_CODE static noinline void init_vmcb_guest_state(uint64_t cpu_id, uint64_t vm_id) { uint64_t vmcb_addr = X86_SYZOS_ADDR_VMCS_VMCB(cpu_id, vm_id); uint64_t l2_code_addr = X86_SYZOS_ADDR_VM_CODE(cpu_id, vm_id); uint64_t l2_stack_addr = X86_SYZOS_ADDR_VM_STACK(cpu_id, vm_id); uint64_t npt_pml4_addr = X86_SYZOS_ADDR_VM_PGTABLE(cpu_id, vm_id); SETUP_L2_SEGMENT_SVM(vmcb_addr, CS, X86_SYZOS_SEL_CODE, 0, 0xFFFFFFFF, SVM_ATTR_64BIT_CODE); SETUP_L2_SEGMENT_SVM(vmcb_addr, DS, X86_SYZOS_SEL_DATA, 0, 0xFFFFFFFF, SVM_ATTR_64BIT_DATA); SETUP_L2_SEGMENT_SVM(vmcb_addr, ES, X86_SYZOS_SEL_DATA, 0, 0xFFFFFFFF, SVM_ATTR_64BIT_DATA); SETUP_L2_SEGMENT_SVM(vmcb_addr, SS, X86_SYZOS_SEL_DATA, 0, 0xFFFFFFFF, SVM_ATTR_64BIT_DATA); SETUP_L2_SEGMENT_SVM(vmcb_addr, FS, X86_SYZOS_SEL_DATA, 0, 0xFFFFFFFF, SVM_ATTR_64BIT_DATA); SETUP_L2_SEGMENT_SVM(vmcb_addr, GS, X86_SYZOS_SEL_DATA, 0, 0xFFFFFFFF, SVM_ATTR_64BIT_DATA); SETUP_L2_SEGMENT_SVM(vmcb_addr, TR, X86_SYZOS_SEL_TSS64, X86_SYZOS_ADDR_VAR_TSS, 0x67, SVM_ATTR_TSS_BUSY); SETUP_L2_SEGMENT_SVM(vmcb_addr, LDTR, 0, 0, 0, SVM_ATTR_LDTR_UNUSABLE); vmcb_write64(vmcb_addr, VMCB_GUEST_CR0, read_cr0() | X86_CR0_WP); vmcb_write64(vmcb_addr, VMCB_GUEST_CR3, read_cr3()); vmcb_write64(vmcb_addr, VMCB_GUEST_CR4, read_cr4()); vmcb_write64(vmcb_addr, VMCB_GUEST_RIP, l2_code_addr); vmcb_write64(vmcb_addr, VMCB_GUEST_RSP, l2_stack_addr + KVM_PAGE_SIZE - 8); vmcb_write64(vmcb_addr, VMCB_GUEST_RFLAGS, RFLAGS_1_BIT); vmcb_write64(vmcb_addr, VMCB_GUEST_EFER, X86_EFER_LME | X86_EFER_LMA | X86_EFER_SVME); vmcb_write64(vmcb_addr, VMCB_RAX, 0); struct { uint16_t limit; uint64_t base; } __attribute__((packed)) gdtr, idtr; asm volatile("sgdt %0" : "=m"(gdtr)); asm volatile("sidt %0" : "=m"(idtr)); vmcb_write64(vmcb_addr, VMCB_GUEST_GDTR_BASE, gdtr.base); vmcb_write32(vmcb_addr, VMCB_GUEST_GDTR_LIM, gdtr.limit); vmcb_write64(vmcb_addr, VMCB_GUEST_IDTR_BASE, idtr.base); vmcb_write32(vmcb_addr, VMCB_GUEST_IDTR_LIM, idtr.limit); vmcb_write32(vmcb_addr, VMCB_CTRL_INTERCEPT_VEC3, VMCB_CTRL_INTERCEPT_VEC3_ALL); vmcb_write32(vmcb_addr, VMCB_CTRL_INTERCEPT_VEC4, VMCB_CTRL_INTERCEPT_VEC4_ALL); vmcb_write64(vmcb_addr, VMCB_CTRL_NP_ENABLE, (1 << VMCB_CTRL_NPT_ENABLE_BIT)); uint64_t npt_pointer = (npt_pml4_addr & ~0xFFF); vmcb_write64(vmcb_addr, VMCB_CTRL_N_CR3, npt_pointer); vmcb_write32(vmcb_addr, VMCB_CTRL_ASID, 1); } GUEST_CODE static noinline void nested_create_vm_amd(struct api_call_1* cmd, uint64_t cpu_id) { uint64_t vm_id = cmd->arg; uint64_t vmcb_addr = X86_SYZOS_ADDR_VMCS_VMCB(cpu_id, vm_id); uint64_t l2_pml4_addr = X86_SYZOS_ADDR_VM_PGTABLE(cpu_id, vm_id); uint64_t l2_msr_bitmap = X86_SYZOS_ADDR_MSR_BITMAP(cpu_id, vm_id); guest_memset((void*)vmcb_addr, 0, KVM_PAGE_SIZE); guest_memset((void*)X86_SYZOS_ADDR_VM_ARCH_SPECIFIC(cpu_id), 0, KVM_PAGE_SIZE); guest_memset((void*)l2_pml4_addr, 0, KVM_PAGE_SIZE); guest_memset((void*)l2_msr_bitmap, 0, KVM_PAGE_SIZE); setup_l2_page_tables(CPU_VENDOR_AMD, cpu_id, vm_id, 0); init_vmcb_guest_state(cpu_id, vm_id); } GUEST_CODE static noinline void guest_handle_nested_create_vm(struct api_call_1* cmd, uint64_t cpu_id) { if (get_cpu_vendor() == CPU_VENDOR_INTEL) { nested_create_vm_intel(cmd, cpu_id); } else { nested_create_vm_amd(cmd, cpu_id); } } GUEST_CODE static uint64_t l2_gpa_to_pa(uint64_t cpu_id, uint64_t vm_id, uint64_t gpa) { uint64_t pml4_addr = X86_SYZOS_ADDR_VM_PGTABLE(cpu_id, vm_id); volatile uint64_t* pml4 = (volatile uint64_t*)pml4_addr; uint64_t pml4_idx = (gpa >> 39) & 0x1FF; if (!(pml4[pml4_idx] & X86_PDE64_PRESENT)) return 0; volatile uint64_t* pdpt = (volatile uint64_t*)(pml4[pml4_idx] & ~0xFFF); uint64_t pdpt_idx = (gpa >> 30) & 0x1FF; if (!(pdpt[pdpt_idx] & X86_PDE64_PRESENT)) return 0; volatile uint64_t* pd = (volatile uint64_t*)(pdpt[pdpt_idx] & ~0xFFF); uint64_t pd_idx = (gpa >> 21) & 0x1FF; if (!(pd[pd_idx] & X86_PDE64_PRESENT)) return 0; volatile uint64_t* pt = (volatile uint64_t*)(pd[pd_idx] & ~0xFFF); uint64_t pt_idx = (gpa >> 12) & 0x1FF; if (!(pt[pt_idx] & X86_PDE64_PRESENT)) return 0; return (pt[pt_idx] & ~0xFFF) + (gpa & 0xFFF); } GUEST_CODE static noinline void guest_handle_nested_load_code(struct api_call_nested_load_code* cmd, uint64_t cpu_id) { uint64_t vm_id = cmd->vm_id; uint64_t l2_code_backing = l2_gpa_to_pa(cpu_id, vm_id, X86_SYZOS_ADDR_USER_CODE); if (!l2_code_backing) { guest_uexit(0xE2BAD4); return; } uint64_t l2_code_size = cmd->header.size - sizeof(struct api_call_header) - sizeof(uint64_t); if (l2_code_size > KVM_PAGE_SIZE) l2_code_size = KVM_PAGE_SIZE; guest_memcpy((void*)l2_code_backing, (void*)cmd->insns, l2_code_size); if (get_cpu_vendor() == CPU_VENDOR_INTEL) { nested_vmptrld(cpu_id, vm_id); vmwrite(VMCS_GUEST_RIP, X86_SYZOS_ADDR_USER_CODE); vmwrite(VMCS_GUEST_RSP, X86_SYZOS_ADDR_STACK_BOTTOM + KVM_PAGE_SIZE - 8); } else { vmcb_write64(X86_SYZOS_ADDR_VMCS_VMCB(cpu_id, vm_id), VMCB_GUEST_RIP, X86_SYZOS_ADDR_USER_CODE); vmcb_write64(X86_SYZOS_ADDR_VMCS_VMCB(cpu_id, vm_id), VMCB_GUEST_RSP, X86_SYZOS_ADDR_STACK_BOTTOM + KVM_PAGE_SIZE - 8); } } GUEST_CODE static noinline void guest_handle_nested_load_syzos(struct api_call_nested_load_syzos* cmd, uint64_t cpu_id) { uint64_t vm_id = cmd->vm_id; uint64_t prog_size = cmd->header.size - __builtin_offsetof(struct api_call_nested_load_syzos, program); uint64_t l2_code_backing = X86_SYZOS_ADDR_VM_CODE(cpu_id, vm_id); volatile struct syzos_globals* globals = (volatile struct syzos_globals*)X86_SYZOS_ADDR_GLOBALS; if (prog_size > KVM_PAGE_SIZE) prog_size = KVM_PAGE_SIZE; guest_memcpy((void*)l2_code_backing, (void*)cmd->program, prog_size); uint64_t globals_pa = l2_gpa_to_pa(cpu_id, vm_id, X86_SYZOS_ADDR_GLOBALS); if (!globals_pa) { guest_uexit(0xE2BAD3); return; } volatile struct syzos_globals* l2_globals = (volatile struct syzos_globals*)globals_pa; for (int i = 0; i < KVM_MAX_VCPU; i++) { l2_globals->text_sizes[i] = prog_size; globals->l2_ctx[i][vm_id].rdi = i; globals->l2_ctx[i][vm_id].rax = 0; } uint64_t entry_rip = executor_fn_guest_addr(guest_main); if (get_cpu_vendor() == CPU_VENDOR_INTEL) { nested_vmptrld(cpu_id, vm_id); vmwrite(VMCS_GUEST_RIP, entry_rip); vmwrite(VMCS_GUEST_RSP, X86_SYZOS_ADDR_STACK_BOTTOM + KVM_PAGE_SIZE - 8); } else { uint64_t vmcb = X86_SYZOS_ADDR_VMCS_VMCB(cpu_id, vm_id); vmcb_write64(vmcb, VMCB_GUEST_RIP, entry_rip); vmcb_write64(vmcb, VMCB_GUEST_RSP, X86_SYZOS_ADDR_STACK_BOTTOM + KVM_PAGE_SIZE - 8); } } GUEST_CODE static noinline void guest_handle_nested_vmentry_intel(uint64_t vm_id, uint64_t cpu_id, bool is_launch) { volatile struct syzos_globals* globals = (volatile struct syzos_globals*)X86_SYZOS_ADDR_GLOBALS; struct l2_guest_regs* l2_regs = (struct l2_guest_regs*)&globals->l2_ctx[cpu_id][vm_id]; uint64_t vmx_error_code = 0; uint64_t fail_flag = 0; nested_vmptrld(cpu_id, vm_id); globals->active_vm_id[cpu_id] = vm_id; asm volatile( R"( sub $128, %%rsp push %[cpu_id] push %[launch] push %%rbx push %%rbp push %%r12 push %%r13 push %%r14 push %%r15 mov %[host_rsp_field], %%r10 mov %%rsp, %%r11 vmwrite %%r11, %%r10 mov %[l2_regs], %%rax mov 8(%%rax), %%rbx mov 16(%%rax), %%rcx mov 24(%%rax), %%rdx mov 32(%%rax), %%rsi mov 40(%%rax), %%rdi mov 48(%%rax), %%rbp mov 56(%%rax), %%r8 mov 64(%%rax), %%r9 mov 72(%%rax), %%r10 mov 80(%%rax), %%r11 mov 88(%%rax), %%r12 mov 96(%%rax), %%r13 mov 104(%%rax), %%r14 mov 112(%%rax), %%r15 mov 0(%%rax), %%rax cmpq $0, 48(%%rsp) je 1f vmlaunch jmp 2f 1: vmresume 2: pop %%r15 pop %%r14 pop %%r13 pop %%r12 pop %%rbp pop %%rbx add $16, %%rsp add $128, %%rsp mov $1, %[ret] jmp 3f .globl after_vmentry_label after_vmentry_label: xor %[ret], %[ret] 3: )" : [ret] "=&r"(fail_flag) : [launch] "r"((uint64_t)is_launch), [host_rsp_field] "i"(VMCS_HOST_RSP), [cpu_id] "r"(cpu_id), [l2_regs] "r"(l2_regs) : "cc", "memory", "rax", "rcx", "rdx", "rsi", "rdi", "r8", "r9", "r10", "r11"); if (fail_flag) { vmx_error_code = vmread(VMCS_VM_INSTRUCTION_ERROR); guest_uexit(0xE2E10000 | (uint32_t)vmx_error_code); return; } } GUEST_CODE static noinline void guest_run_amd_vm(uint64_t cpu_id, uint64_t vm_id) { uint64_t vmcb_addr = X86_SYZOS_ADDR_VMCS_VMCB(cpu_id, vm_id); volatile struct syzos_globals* globals = (volatile struct syzos_globals*)X86_SYZOS_ADDR_GLOBALS; globals->active_vm_id[cpu_id] = vm_id; struct l2_guest_regs* l2_regs = (struct l2_guest_regs*)&globals->l2_ctx[cpu_id][vm_id]; uint8_t fail_flag = 0; asm volatile( R"( sub $128, %%rsp push %[cpu_id] push %[vmcb_addr] push %%rbx push %%rbp push %%r12 push %%r13 push %%r14 push %%r15 mov %[l2_regs], %%rax mov 0(%%rax), %%rbx mov %[vmcb_addr], %%rcx mov %%rbx, 0x5f8(%%rcx) mov 8(%%rax), %%rbx mov 16(%%rax), %%rcx mov 24(%%rax), %%rdx mov 32(%%rax), %%rsi mov 40(%%rax), %%rdi mov 48(%%rax), %%rbp mov 56(%%rax), %%r8 mov 64(%%rax), %%r9 mov 72(%%rax), %%r10 mov 80(%%rax), %%r11 mov 88(%%rax), %%r12 mov 96(%%rax), %%r13 mov 104(%%rax), %%r14 mov 112(%%rax), %%r15 clgi mov 48(%%rsp), %%rax vmrun 1: mov 48(%%rsp), %%rax setc %[fail_flag] pushq 0x70(%%rax) push %%r15 push %%r14 push %%r13 push %%r12 push %%r11 push %%r10 push %%r9 push %%r8 push %%rbp push %%rdi push %%rsi push %%rdx push %%rcx push %%rbx mov 176(%%rsp), %%rax pushq 0x5f8(%%rax) mov 120(%%rsp), %%rdi mov %%rsp, %%rsi call nested_vm_exit_handler_amd add $128, %%rsp pop %%r15 pop %%r14 pop %%r13 pop %%r12 pop %%rbp pop %%rbx add $16, %%rsp add $128, %%rsp stgi after_vmentry_label_amd: )" : [fail_flag] "=m"(fail_flag) : [cpu_id] "r"(cpu_id), [vmcb_addr] "r"(vmcb_addr), [l2_regs] "r"(l2_regs), [l2_regs_size] "i"(sizeof(struct l2_guest_regs)) : "cc", "memory", "rax", "rcx", "rdx", "rsi", "rdi", "r8", "r9", "r10", "r11"); if (fail_flag) { guest_uexit(0xE2E10000 | 0xFFFF); return; } } GUEST_CODE static noinline void guest_handle_nested_vmlaunch(struct api_call_1* cmd, uint64_t cpu_id) { uint64_t vm_id = cmd->arg; if (get_cpu_vendor() == CPU_VENDOR_INTEL) { guest_handle_nested_vmentry_intel(vm_id, cpu_id, true); } else { guest_run_amd_vm(cpu_id, vm_id); } } GUEST_CODE static noinline void guest_handle_nested_vmresume(struct api_call_1* cmd, uint64_t cpu_id) { uint64_t vm_id = cmd->arg; if (get_cpu_vendor() == CPU_VENDOR_INTEL) { guest_handle_nested_vmentry_intel(vm_id, cpu_id, false); } else { guest_run_amd_vm(cpu_id, vm_id); } } GUEST_CODE static noinline void guest_handle_nested_intel_vmwrite_mask(struct api_call_5* cmd, uint64_t cpu_id) { if (get_cpu_vendor() != CPU_VENDOR_INTEL) return; uint64_t vm_id = cmd->args[0]; nested_vmptrld(cpu_id, vm_id); uint64_t field = cmd->args[1]; uint64_t set_mask = cmd->args[2]; uint64_t unset_mask = cmd->args[3]; uint64_t flip_mask = cmd->args[4]; uint64_t current_value = vmread(field); uint64_t new_value = (current_value & ~unset_mask) | set_mask; new_value ^= flip_mask; vmwrite(field, new_value); } GUEST_CODE static noinline void guest_handle_nested_amd_vmcb_write_mask(struct api_call_5* cmd, uint64_t cpu_id) { if (get_cpu_vendor() != CPU_VENDOR_AMD) return; uint64_t vm_id = cmd->args[0]; uint64_t vmcb_addr = X86_SYZOS_ADDR_VMCS_VMCB(cpu_id, vm_id); uint64_t offset = cmd->args[1]; uint64_t set_mask = cmd->args[2]; uint64_t unset_mask = cmd->args[3]; uint64_t flip_mask = cmd->args[4]; uint64_t current_value = vmcb_read64((volatile uint8_t*)vmcb_addr, offset); uint64_t new_value = (current_value & ~unset_mask) | set_mask; new_value ^= flip_mask; vmcb_write64(vmcb_addr, offset, new_value); } GUEST_CODE static noinline void guest_handle_nested_amd_invlpga(struct api_call_2* cmd, uint64_t cpu_id) { if (get_cpu_vendor() != CPU_VENDOR_AMD) return; uint64_t linear_addr = cmd->args[0]; uint32_t asid = (uint32_t)cmd->args[1]; asm volatile("invlpga" : : "a"(linear_addr), "c"(asid) : "memory"); } GUEST_CODE static noinline void guest_handle_nested_amd_stgi() { if (get_cpu_vendor() != CPU_VENDOR_AMD) return; asm volatile("stgi" ::: "memory"); } GUEST_CODE static noinline void guest_handle_nested_amd_clgi() { if (get_cpu_vendor() != CPU_VENDOR_AMD) return; asm volatile("clgi" ::: "memory"); } GUEST_CODE static noinline void guest_handle_nested_amd_inject_event(struct api_call_5* cmd, uint64_t cpu_id) { if (get_cpu_vendor() != CPU_VENDOR_AMD) return; uint64_t vm_id = cmd->args[0]; uint64_t vmcb_addr = X86_SYZOS_ADDR_VMCS_VMCB(cpu_id, vm_id); uint64_t vector = cmd->args[1] & 0xFF; uint64_t type = cmd->args[2] & 0x7; uint64_t error_code = cmd->args[3] & 0xFFFFFFFF; uint64_t flags = cmd->args[4]; uint64_t event_inj = vector; event_inj |= (type << 8); if (flags & 2) event_inj |= (1ULL << 11); if (flags & 1) event_inj |= (1ULL << 31); event_inj |= (error_code << 32); vmcb_write64(vmcb_addr, 0x60, event_inj); } GUEST_CODE static noinline void guest_handle_nested_amd_set_intercept(struct api_call_5* cmd, uint64_t cpu_id) { if (get_cpu_vendor() != CPU_VENDOR_AMD) return; uint64_t vm_id = cmd->args[0]; uint64_t vmcb_addr = X86_SYZOS_ADDR_VMCS_VMCB(cpu_id, vm_id); uint64_t offset = cmd->args[1]; uint64_t bit_mask = cmd->args[2]; uint64_t action = cmd->args[3]; uint32_t current = vmcb_read32(vmcb_addr, (uint16_t)offset); if (action == 1) current |= (uint32_t)bit_mask; else current &= ~((uint32_t)bit_mask); vmcb_write32(vmcb_addr, (uint16_t)offset, current); } GUEST_CODE static noinline void guest_handle_nested_amd_vmload(struct api_call_1* cmd, uint64_t cpu_id) { if (get_cpu_vendor() != CPU_VENDOR_AMD) return; uint64_t vm_id = cmd->arg; uint64_t vmcb_pa = X86_SYZOS_ADDR_VMCS_VMCB(cpu_id, vm_id); asm volatile("vmload %%rax" ::"a"(vmcb_pa) : "memory"); } GUEST_CODE static noinline void guest_handle_nested_amd_vmsave(struct api_call_1* cmd, uint64_t cpu_id) { if (get_cpu_vendor() != CPU_VENDOR_AMD) return; uint64_t vm_id = cmd->arg; uint64_t vmcb_pa = X86_SYZOS_ADDR_VMCS_VMCB(cpu_id, vm_id); asm volatile("vmsave %%rax" ::"a"(vmcb_pa) : "memory"); } 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_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\x00\x48\x21\xd0\x48\xc7\xc2" "\x00\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc1\x82\x04\x00\x00\x0f\x32\x48\x83" "\xc8\x00\x48\x21\xd0\x48\xc7\xc2\x02\x40\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 KVM_SMI _IO(KVMIO, 0xb7) 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; uint16_t reserved3; uint16_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 = X86_MSR_IA32_SYSENTER_CS; entries[0].data = sel_cs; entries[1].index = X86_MSR_IA32_SYSENTER_ESP; entries[1].data = X86_ADDR_STACK0; entries[2].index = X86_MSR_IA32_SYSENTER_EIP; entries[2].data = X86_ADDR_VAR_SYSEXIT; entries[3].index = X86_MSR_IA32_STAR; entries[3].data = ((uint64_t)sel_cs << 32) | ((uint64_t)sel_cs_cpl3 << 48); entries[4].index = X86_MSR_IA32_LSTAR; entries[4].data = X86_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 + X86_ADDR_VAR_IDT; sregs->idt.limit = 0x1ff; uint64_t* idt = (uint64_t*)(host_mem + sregs->idt.base); for (int i = 0; i < 32; i++) { struct kvm_segment gate; gate.selector = i << 3; switch (i % 6) { case 0: gate.type = 6; gate.base = X86_SEL_CS16; break; case 1: gate.type = 7; gate.base = X86_SEL_CS16; break; case 2: gate.type = 3; gate.base = X86_SEL_TGATE16; break; case 3: gate.type = 14; gate.base = X86_SEL_CS32; break; case 4: gate.type = 15; gate.base = X86_SEL_CS32; break; case 5: gate.type = 11; gate.base = X86_SEL_TGATE32; break; } gate.limit = guest_mem + X86_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 + X86_ADDR_VAR_IDT; sregs->idt.limit = 0x1ff; uint64_t* idt = (uint64_t*)(host_mem + sregs->idt.base); for (int i = 0; i < 32; i++) { struct kvm_segment gate; gate.selector = (i * 2) << 3; gate.type = (i & 1) ? 14 : 15; gate.base = X86_SEL_CS64; gate.limit = guest_mem + X86_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); } } static const struct mem_region syzos_mem_regions[] = { {X86_SYZOS_ADDR_ZERO, 5, MEM_REGION_FLAG_GPA0}, {X86_SYZOS_ADDR_VAR_IDT, 10, 0}, {X86_SYZOS_ADDR_BOOT_ARGS, 1, 0}, {X86_SYZOS_ADDR_PT_POOL, X86_SYZOS_PT_POOL_SIZE, 0}, {X86_SYZOS_ADDR_GLOBALS, 1, 0}, {X86_SYZOS_ADDR_SMRAM, 10, 0}, {X86_SYZOS_ADDR_EXIT, 1, MEM_REGION_FLAG_NO_HOST_MEM}, {X86_SYZOS_ADDR_DIRTY_PAGES, 2, MEM_REGION_FLAG_DIRTY_LOG}, {X86_SYZOS_ADDR_USER_CODE, KVM_MAX_VCPU, MEM_REGION_FLAG_READONLY | MEM_REGION_FLAG_USER_CODE}, {SYZOS_ADDR_EXECUTOR_CODE, 4, MEM_REGION_FLAG_READONLY | MEM_REGION_FLAG_EXECUTOR_CODE}, {X86_SYZOS_ADDR_SCRATCH_CODE, 1, 0}, {X86_SYZOS_ADDR_STACK_BOTTOM, 1, 0}, {X86_SYZOS_PER_VCPU_REGIONS_BASE, (KVM_MAX_VCPU * X86_SYZOS_L1_VCPU_REGION_SIZE) / KVM_PAGE_SIZE, 0}, {X86_SYZOS_ADDR_IOAPIC, 1, 0}, {X86_SYZOS_ADDR_UNUSED, 0, MEM_REGION_FLAG_REMAINING}, }; #define SYZOS_REGION_COUNT \ (sizeof(syzos_mem_regions) / sizeof(syzos_mem_regions[0])) struct kvm_syz_vm { int vmfd; int next_cpu_id; void* host_mem; size_t total_pages; void* user_text; void* gpa0_mem; void* pt_pool_mem; void* globals_mem; void* region_base[SYZOS_REGION_COUNT]; }; static inline void* gpa_to_hva(struct kvm_syz_vm* vm, uint64_t gpa) { for (size_t i = 0; i < SYZOS_REGION_COUNT; i++) { const struct mem_region* r = &syzos_mem_regions[i]; if (r->flags & MEM_REGION_FLAG_NO_HOST_MEM) continue; if (r->gpa == X86_SYZOS_ADDR_UNUSED) break; size_t region_size = r->pages * KVM_PAGE_SIZE; if (gpa >= r->gpa && gpa < r->gpa + region_size) return (void*)((char*)vm->region_base[i] + (gpa - r->gpa)); } return NULL; } 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 volatile long syz_kvm_setup_cpu(volatile long a0, volatile long a1, volatile long a2, volatile long a3, volatile long a4, volatile long a5, volatile long a6, volatile long 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 = text_array_ptr[0].typ; const void* text = text_array_ptr[0].text; uintptr_t text_size = text_array_ptr[0].size; for (uintptr_t 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 + X86_ADDR_TEXT; regs.rsp = X86_ADDR_STACK0; sregs.gdt.base = guest_mem + X86_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; memset(&seg_ldt, 0, sizeof(seg_ldt)); seg_ldt.selector = X86_SEL_LDT; seg_ldt.type = 2; seg_ldt.base = guest_mem + X86_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; memset(&seg_cs16, 0, sizeof(seg_cs16)); seg_cs16.selector = X86_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 = X86_SEL_DS16; seg_ds16.type = 3; struct kvm_segment seg_cs16_cpl3 = seg_cs16; seg_cs16_cpl3.selector = X86_SEL_CS16_CPL3; seg_cs16_cpl3.dpl = 3; struct kvm_segment seg_ds16_cpl3 = seg_ds16; seg_ds16_cpl3.selector = X86_SEL_DS16_CPL3; seg_ds16_cpl3.dpl = 3; struct kvm_segment seg_cs32 = seg_cs16; seg_cs32.selector = X86_SEL_CS32; seg_cs32.db = 1; struct kvm_segment seg_ds32 = seg_ds16; seg_ds32.selector = X86_SEL_DS32; seg_ds32.db = 1; struct kvm_segment seg_cs32_cpl3 = seg_cs32; seg_cs32_cpl3.selector = X86_SEL_CS32_CPL3; seg_cs32_cpl3.dpl = 3; struct kvm_segment seg_ds32_cpl3 = seg_ds32; seg_ds32_cpl3.selector = X86_SEL_DS32_CPL3; seg_ds32_cpl3.dpl = 3; struct kvm_segment seg_cs64 = seg_cs16; seg_cs64.selector = X86_SEL_CS64; seg_cs64.l = 1; struct kvm_segment seg_ds64 = seg_ds32; seg_ds64.selector = X86_SEL_DS64; struct kvm_segment seg_cs64_cpl3 = seg_cs64; seg_cs64_cpl3.selector = X86_SEL_CS64_CPL3; seg_cs64_cpl3.dpl = 3; struct kvm_segment seg_ds64_cpl3 = seg_ds64; seg_ds64_cpl3.selector = X86_SEL_DS64_CPL3; seg_ds64_cpl3.dpl = 3; struct kvm_segment seg_tss32; memset(&seg_tss32, 0, sizeof(seg_tss32)); seg_tss32.selector = X86_SEL_TSS32; seg_tss32.type = 9; seg_tss32.base = X86_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 = X86_SEL_TSS32_2; seg_tss32_2.base = X86_ADDR_VAR_TSS32_2; struct kvm_segment seg_tss32_cpl3 = seg_tss32; seg_tss32_cpl3.selector = X86_SEL_TSS32_CPL3; seg_tss32_cpl3.base = X86_ADDR_VAR_TSS32_CPL3; struct kvm_segment seg_tss32_vm86 = seg_tss32; seg_tss32_vm86.selector = X86_SEL_TSS32_VM86; seg_tss32_vm86.base = X86_ADDR_VAR_TSS32_VM86; struct kvm_segment seg_tss16 = seg_tss32; seg_tss16.selector = X86_SEL_TSS16; seg_tss16.base = X86_ADDR_VAR_TSS16; seg_tss16.limit = 0xff; seg_tss16.type = 1; struct kvm_segment seg_tss16_2 = seg_tss16; seg_tss16_2.selector = X86_SEL_TSS16_2; seg_tss16_2.base = X86_ADDR_VAR_TSS16_2; seg_tss16_2.dpl = 0; struct kvm_segment seg_tss16_cpl3 = seg_tss16; seg_tss16_cpl3.selector = X86_SEL_TSS16_CPL3; seg_tss16_cpl3.base = X86_ADDR_VAR_TSS16_CPL3; seg_tss16_cpl3.dpl = 3; struct kvm_segment seg_tss64 = seg_tss32; seg_tss64.selector = X86_SEL_TSS64; seg_tss64.base = X86_ADDR_VAR_TSS64; seg_tss64.limit = 0x1ff; struct kvm_segment seg_tss64_cpl3 = seg_tss64; seg_tss64_cpl3.selector = X86_SEL_TSS64_CPL3; seg_tss64_cpl3.base = X86_ADDR_VAR_TSS64_CPL3; seg_tss64_cpl3.dpl = 3; struct kvm_segment seg_cgate16; memset(&seg_cgate16, 0, sizeof(seg_cgate16)); seg_cgate16.selector = X86_SEL_CGATE16; seg_cgate16.type = 4; seg_cgate16.base = X86_SEL_CS16 | (2 << 16); seg_cgate16.limit = X86_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 = X86_SEL_TGATE16; seg_tgate16.type = 3; seg_cgate16.base = X86_SEL_TSS16_2; seg_tgate16.limit = 0; struct kvm_segment seg_cgate32 = seg_cgate16; seg_cgate32.selector = X86_SEL_CGATE32; seg_cgate32.type = 12; seg_cgate32.base = X86_SEL_CS32 | (2 << 16); struct kvm_segment seg_tgate32 = seg_cgate32; seg_tgate32.selector = X86_SEL_TGATE32; seg_tgate32.type = 11; seg_tgate32.base = X86_SEL_TSS32_2; seg_tgate32.limit = 0; struct kvm_segment seg_cgate64 = seg_cgate16; seg_cgate64.selector = X86_SEL_CGATE64; seg_cgate64.type = 12; seg_cgate64.base = X86_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 + X86_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 |= X86_CR0_PE; } else { sregs.cs.selector = 0; sregs.cs.base = 0; } *(host_mem + X86_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 |= X86_CR0_PE; sregs.efer |= X86_EFER_SCE; setup_syscall_msrs(cpufd, X86_SEL_CS32, X86_SEL_CS32_CPL3); setup_32bit_idt(&sregs, host_mem, guest_mem); if (flags & KVM_SETUP_PAGING) { uint64_t pd_addr = guest_mem + X86_ADDR_PD; uint64_t* pd = (uint64_t*)(host_mem + X86_ADDR_PD); pd[0] = X86_PDE32_PRESENT | X86_PDE32_RW | X86_PDE32_USER | X86_PDE32_PS; sregs.cr3 = pd_addr; sregs.cr4 |= X86_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 |= X86_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 |= X86_CR0_PE; sregs.efer |= X86_EFER_SCE; setup_syscall_msrs(cpufd, X86_SEL_CS32, X86_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 + X86_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 + X86_ADDR_PD; uint64_t* pd = (uint64_t*)(host_mem + X86_ADDR_PD); pd[0] = X86_PDE32_PRESENT | X86_PDE32_RW | X86_PDE32_USER | X86_PDE32_PS; sregs.cr3 = pd_addr; sregs.cr4 |= X86_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 |= X86_EFER_LME | X86_EFER_SCE; sregs.cr0 |= X86_CR0_PE; setup_syscall_msrs(cpufd, X86_SEL_CS64, X86_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 + X86_ADDR_PML4; uint64_t* pml4 = (uint64_t*)(host_mem + X86_ADDR_PML4); uint64_t pdpt_addr = guest_mem + X86_ADDR_PDP; uint64_t* pdpt = (uint64_t*)(host_mem + X86_ADDR_PDP); uint64_t pd_addr = guest_mem + X86_ADDR_PD; uint64_t* pd = (uint64_t*)(host_mem + X86_ADDR_PD); pml4[0] = X86_PDE64_PRESENT | X86_PDE64_RW | X86_PDE64_USER | pdpt_addr; pdpt[0] = X86_PDE64_PRESENT | X86_PDE64_RW | X86_PDE64_USER | pd_addr; pd[0] = X86_PDE64_PRESENT | X86_PDE64_RW | X86_PDE64_USER | X86_PDE64_PS; sregs.cr3 = pml4_addr; sregs.cr4 |= X86_CR4_PAE; if (flags & KVM_SETUP_VM) { sregs.cr0 |= X86_CR0_NE; *((uint64_t*)(host_mem + X86_ADDR_VAR_VMXON_PTR)) = X86_ADDR_VAR_VMXON; *((uint64_t*)(host_mem + X86_ADDR_VAR_VMCS_PTR)) = X86_ADDR_VAR_VMCS; memcpy(host_mem + X86_ADDR_VAR_VMEXIT_CODE, kvm_asm64_vm_exit, sizeof(kvm_asm64_vm_exit) - 1); *((uint64_t*)(host_mem + X86_ADDR_VAR_VMEXIT_PTR)) = X86_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 = X86_SEL_DS16; tss16.sp0 = tss16.sp1 = tss16.sp2 = X86_ADDR_STACK0; tss16.ip = X86_ADDR_VAR_USER_CODE2; tss16.flags = (1 << 1); tss16.cs = X86_SEL_CS16; tss16.es = tss16.ds = tss16.ss = X86_SEL_DS16; tss16.ldt = X86_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 = X86_SEL_DS16; tss16.sp0 = tss16.sp1 = tss16.sp2 = X86_ADDR_STACK0; tss16.ip = X86_ADDR_VAR_USER_CODE2; tss16.flags = (1 << 1); tss16.cs = X86_SEL_CS16_CPL3; tss16.es = tss16.ds = tss16.ss = X86_SEL_DS16_CPL3; tss16.ldt = X86_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 = X86_SEL_DS32; tss32.sp0 = tss32.sp1 = tss32.sp2 = X86_ADDR_STACK0; tss32.ip = X86_ADDR_VAR_USER_CODE; tss32.flags = (1 << 1) | (1 << 17); tss32.ldt = X86_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 = X86_SEL_DS32; tss32.sp0 = tss32.sp1 = tss32.sp2 = X86_ADDR_STACK0; tss32.ip = X86_ADDR_VAR_USER_CODE; tss32.flags = (1 << 1); tss32.cr3 = sregs.cr3; tss32.es = tss32.ds = tss32.ss = tss32.gs = tss32.fs = X86_SEL_DS32; tss32.cs = X86_SEL_CS32; tss32.ldt = X86_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] = X86_ADDR_STACK0; tss64.rsp[1] = X86_ADDR_STACK0; tss64.rsp[2] = X86_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] = X86_ADDR_STACK0; tss64.rsp[1] = X86_ADDR_STACK0; tss64.rsp[2] = X86_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 = memmem(host_text, text_prefix_size, "\xde\xc0\xad\x0b", 4); if (patch) *((uint32_t*)patch) = guest_mem + X86_ADDR_TEXT + ((char*)patch - host_text) + 6; uint16_t magic = X86_PREFIX_SIZE; patch = memmem(host_text, text_prefix_size, &magic, sizeof(magic)); if (patch) *((uint16_t*)patch) = guest_mem + X86_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 + X86_ADDR_VAR_USER_CODE, text, text_size); *(host_mem + X86_ADDR_VAR_USER_CODE + text_size) = 0xf4; *(host_mem + X86_ADDR_VAR_HLT) = 0xf4; memcpy(host_mem + X86_ADDR_VAR_SYSRET, "\x0f\x07\xf4", 3); memcpy(host_mem + X86_ADDR_VAR_SYSEXIT, "\x0f\x35\xf4", 3); *(uint64_t*)(host_mem + X86_ADDR_VAR_VMWRITE_FLD) = 0; *(uint64_t*)(host_mem + X86_ADDR_VAR_VMWRITE_VAL) = 0; if (opt_count > 2) opt_count = 2; for (uintptr_t i = 0; i < opt_count; i++) { uint64_t typ = opt_array_ptr[i].typ; uint64_t val = opt_array_ptr[i].val; switch (typ % 9) { case 0: sregs.cr0 ^= val & (X86_CR0_MP | X86_CR0_EM | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM | X86_CR0_NW | X86_CR0_CD); break; case 1: sregs.cr4 ^= val & (X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | X86_CR4_DE | X86_CR4_MCE | X86_CR4_PGE | X86_CR4_PCE | X86_CR4_OSFXSR | X86_CR4_OSXMMEXCPT | X86_CR4_UMIP | X86_CR4_VMXE | X86_CR4_SMXE | X86_CR4_FSGSBASE | X86_CR4_PCIDE | X86_CR4_OSXSAVE | X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_PKE); break; case 2: sregs.efer ^= val & (X86_EFER_SCE | X86_EFER_NXE | X86_EFER_SVME | X86_EFER_LMSLE | X86_EFER_FFXSR | X86_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 + X86_ADDR_VAR_VMWRITE_FLD) = (val & 0xffff); *(uint64_t*)(host_mem + X86_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 kill_and_wait(int pid, int* status) { kill(-pid, SIGKILL); kill(pid, SIGKILL); for (int 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) { } } static void reset_loop() { char buf[64]; snprintf(buf, sizeof(buf), "/dev/loop%llu", procid); int loopfd = open(buf, O_RDWR); if (loopfd != -1) { ioctl(loopfd, LOOP_CLR_FD, 0); close(loopfd); } } static void setup_test() { prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); setpgrp(); write_file("/proc/self/oom_score_adj", "1000"); } static void setup_sysctl() { int cad_pid = fork(); if (cad_pid < 0) exit(1); if (cad_pid == 0) { for (;;) sleep(100); } char tmppid[32]; snprintf(tmppid, sizeof(tmppid), "%d", cad_pid); 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/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", tmppid}, }; for (size_t i = 0; i < sizeof(files) / sizeof(files[0]); i++) { if (!write_file(files[i].name, files[i].data)) { } } kill(cad_pid, SIGKILL); while (waitpid(cad_pid, NULL, 0) != cad_pid) ; } struct thread_t { int created, call; event_t ready, done; }; static struct thread_t threads[16]; static void execute_call(int call); static int running; static void* thr(void* arg) { struct thread_t* th = (struct thread_t*)arg; for (;;) { event_wait(&th->ready); event_reset(&th->ready); execute_call(th->call); __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED); event_set(&th->done); } return 0; } static void execute_one(void) { if (write(1, "executing program\n", sizeof("executing program\n") - 1)) { } int i, call, thread; for (call = 0; call < 9; call++) { for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0])); thread++) { struct thread_t* th = &threads[thread]; if (!th->created) { th->created = 1; event_init(&th->ready); event_init(&th->done); event_set(&th->done); thread_start(thr, th); } if (!event_isset(&th->done)) continue; event_reset(&th->done); th->call = call; __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED); event_set(&th->ready); if (call == 4 || call == 7) break; event_timedwait(&th->done, 50 + (call == 7 ? 4000 : 0)); break; } } for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++) sleep_ms(1); } static void execute_one(void); #define WAIT_FLAGS __WALL static void loop(void) { int iter = 0; for (;; iter++) { reset_loop(); int pid = fork(); if (pid < 0) exit(1); if (pid == 0) { setup_test(); execute_one(); exit(0); } int status = 0; uint64_t start = current_time_ms(); for (;;) { sleep_ms(10); if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid) break; if (current_time_ms() - start < 5000) continue; kill_and_wait(pid, &status); break; } } } uint64_t r[7] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff}; void execute_call(int call) { intptr_t res = 0; switch (call) { case 0: // openat$kvm arguments: [ // fd: const = 0xffffffffffffff9c (8 bytes) // file: ptr[in, buffer] { // buffer: {2f 64 65 76 2f 6b 76 6d 00} (length 0x9) // } // flags: open_flags = 0x0 (4 bytes) // mode: const = 0x0 (2 bytes) // ] // returns fd_kvm NONFAILING(memcpy((void*)0x200000000140, "/dev/kvm\000", 9)); res = syscall(__NR_openat, /*fd=*/0xffffffffffffff9cul, /*file=*/0x200000000140ul, /*flags=*/0, /*mode=*/0); if (res != -1) r[0] = res; break; case 1: // ioctl$KVM_CREATE_VM arguments: [ // fd: fd_kvm (resource) // cmd: const = 0xae01 (4 bytes) // type: intptr = 0x0 (8 bytes) // ] // returns fd_kvmvm res = syscall(__NR_ioctl, /*fd=*/r[0], /*cmd=*/0xae01, /*type=*/0ul); if (res != -1) r[1] = res; break; case 2: // dup arguments: [ // oldfd: fd (resource) // ] // returns fd res = syscall(__NR_dup, /*oldfd=*/r[1]); if (res != -1) r[2] = res; break; case 3: // ioctl$KVM_CREATE_VCPU arguments: [ // fd: fd_kvmvm (resource) // cmd: const = 0xae41 (4 bytes) // id: intptr = 0x0 (8 bytes) // ] // returns fd_kvmcpu res = syscall(__NR_ioctl, /*fd=*/r[2], /*cmd=*/0xae41, /*id=*/0ul); if (res != -1) r[3] = res; break; case 4: // syz_kvm_setup_cpu$x86 arguments: [ // fd: fd_kvmvm (resource) // cpufd: fd_kvmcpu (resource) // usermem: VMA[0x18000] // text: ptr[in, array[kvm_text_x86]] { // array[kvm_text_x86] { // union kvm_text_x86 { // text64: kvm_text_x86_64 { // typ: const = 0x40 (8 bytes) // text: nil // size: len = 0x0 (8 bytes) // } // } // } // } // ntext: len = 0x1 (8 bytes) // flags: kvm_setup_flags = 0x0 (8 bytes) // opts: nil // nopt: len = 0x0 (8 bytes) // ] NONFAILING(*(uint64_t*)0x200000000100 = 0x40); NONFAILING(*(uint64_t*)0x200000000108 = 0); NONFAILING(*(uint64_t*)0x200000000110 = 0); NONFAILING(syz_kvm_setup_cpu(/*fd=*/-1, /*cpufd=*/r[3], /*usermem=*/0x200000000000, /*text=*/0x200000000100, /*ntext=*/1, /*flags=*/0, /*opts=*/0, /*nopt=*/0)); break; case 5: // openat$cgroup_ro arguments: [ // fd: fd_cgroup (resource) // file: ptr[in, buffer] { // buffer: {62 6c 6b 69 6f 2e 62 66 71 2e 69 6f 5f 73 65 72 76 69 63 65 // 5f 74 69 6d 65 5f 72 65 63 75 72 73 69 76 65 00} (length 0x24) // } // flags: const = 0x275a (4 bytes) // mode: const = 0x0 (2 bytes) // ] // returns fd NONFAILING(memcpy((void*)0x2000000010c0, "blkio.bfq.io_service_time_recursive\000", 36)); res = syscall(__NR_openat, /*fd=*/0xffffff9c, /*file=*/0x2000000010c0ul, /*flags=*/0x275a, /*mode=*/0); if (res != -1) r[4] = res; break; case 6: // read$FUSE arguments: [ // fd: fd_fuse (resource) // buf: ptr[out, fuse_in[read_buffer]] { // fuse_in[read_buffer] { // len: len = 0x2020 (4 bytes) // opcode: int32 = 0x0 (4 bytes) // unique: fuse_unique (resource) // uid: uid (resource) // gid: gid (resource) // pid: pid (resource) // padding: int32 = 0x0 (4 bytes) // payload: buffer: (DirOut) // } // } // len: bytesize = 0x2020 (8 bytes) // ] res = syscall(__NR_read, /*fd=*/r[4], /*buf=*/0x20000000a240ul, /*len=*/0x2020ul); if (res != -1) { NONFAILING(r[5] = *(uint32_t*)0x20000000a254); NONFAILING(r[6] = *(uint32_t*)0x20000000a258); } break; case 7: // syz_mount_image$exfat arguments: [ // fs: ptr[in, buffer] { // buffer: {65 78 66 61 74 00} (length 0x6) // } // dir: ptr[in, buffer] { // buffer: {2e 2f 66 69 6c 65 30 00} (length 0x8) // } // flags: mount_flags = 0x800 (8 bytes) // opts: ptr[inout, array[ANYUNION]] { // array[ANYUNION] { // union ANYUNION { // ANYBLOB: buffer: {64 6d 61 73 6b 3d 30 30 30 30 30 30 30 30 30 // 30 30 30 30 30 30 30 30 30 30 30 30 30 37 2c 75 74 66 38 2c 69 // 6f 63 68 61 72 73 65 74 3d 69 73 6f 38 38 35 39 2d 31 2c 61 6c // 6c 6f 77 5f 75 74 69 6d 65 3d 30 30 30 30 30 30 30 30 30 30 30 // 30 30 30 30 30 30 30 30 32 30 30 31 2c 66 6d 61 73 6b 3d 30 30 // 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 32 // 2c 61 6c 6c 6f 77 5f 75 74 69 6d 65 3d 30 30 30 30 30 30 30 30 // 30 30 30 30 30 30 30 30 30 30 30 30 30 30 35 2c 75 6d 61 73 6b // 3d 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 // 30 30 31 2c 67 69 64 3d} (length 0xbf) // } // union ANYUNION { // ANYRESHEX: ANYRES64 (resource) // } // union ANYUNION { // ANYBLOB: buffer: {2c 75 69 64 3d} (length 0x5) // } // union ANYUNION { // ANYRESHEX: ANYRES64 (resource) // } // union ANYUNION { // ANYRESHEX: ANYRES64 (resource) // } // } // } // chdir: int8 = 0x0 (1 bytes) // size: len = 0x14fe (8 bytes) // img: ptr[in, buffer] { // buffer: (compressed buffer with length 0x14fe) // } // ] // returns fd_dir NONFAILING(memcpy((void*)0x200000001500, "exfat\000", 6)); NONFAILING(memcpy((void*)0x200000000140, "./file0\000", 8)); NONFAILING(memcpy( (void*)0x200000004800, "dmask=00000000000000000000007,utf8,iocharset=iso8859-1,allow_utime=" "00000000000000000002001,fmask=00000000000000000000002,allow_utime=" "00000000000000000000005,umask=00000000000000000000001,gid=", 191)); NONFAILING(sprintf((char*)0x2000000048bf, "0x%016llx", (long long)r[6])); NONFAILING(memcpy((void*)0x2000000048d1, ",uid=", 5)); NONFAILING(sprintf((char*)0x2000000048d6, "0x%016llx", (long long)-1)); NONFAILING(sprintf((char*)0x2000000048e8, "0x%016llx", (long long)r[5])); NONFAILING(memcpy( (void*)0x200000002a40, "\x78\x9c\xec\xdc\x0b\x98\x8d\x55\xfb\x30\xf0\x75\xaf\xb5\x1e\xc6\x34" "\xb1\x9b\xe4\x30\xac\x7b\xdd\x0f\x3b\x0d\x96\x43\x92\x1c\x92\xe4\x90" "\x24\x49\x92\xe4\x94\x90\x34\x49\x92\x90\x18\x72\x4a\x1a\x92\x90\xe3" "\x24\x89\x21\x24\x87\x69\x4c\x1a\xe7\xf3\x21\xe7\x24\x79\xa5\x49\x92" "\x9c\x72\x0a\xeb\xbb\xa6\xde\xf7\xf3\x7f\xdf\xde\xf7\xeb\xfb\x7f\x6f" "\xdf\xdf\xf7\xfd\xe7\xfe\x5d\xd7\xba\xf6\xba\x67\xef\x7b\xed\x7b\xed" "\x7b\xcf\xec\xe7\x79\xe6\xba\xf6\x0f\x3d\x47\xd5\x6b\x51\xbf\x76\x33" "\x22\x12\xff\x16\xf8\xed\x26\x59\x08\x11\x23\x84\x18\x26\x84\x28\x20" "\x84\x08\x84\x10\x95\xe3\x2b\xc7\xe7\xdc\x9f\x4f\x41\xf2\xbf\xf7\x24" "\xec\xcf\xf5\x48\xda\xb5\xae\x80\x5d\x4b\xdc\xff\xdc\x8d\xfb\x9f\xbb" "\x71\xff\x73\x37\xee\x7f\xee\xc6\xfd\xcf\xdd\xb8\xff\xb9\x1b\xf7\x3f" "\x77\xe3\xfe\x33\x96\x9b\x6d\x9b\x5d\xf4\x06\x1e\xb9\x77\xf0\xf5\xff" "\xdc\x8c\x3f\xff\xff\x1b\xc9\x2e\x37\xf9\x9b\x0d\xe5\x6e\xea\xf5\x9f" "\x48\xe1\xfe\xe7\x6e\xdc\xff\xdc\x8d\xfb\x9f\xbb\x71\xff\x73\x37\xee" "\x7f\xee\xc6\xfd\xcf\xdd\xb8\xff\xb9\x1b\xf7\x9f\xb1\xdc\xec\x5a\x5f" "\x7f\xe6\x71\x6d\xc7\xb5\x7e\xff\x31\xc6\x18\x63\x8c\x31\xc6\x18\x63" "\x8c\x31\xc6\x18\x63\x8c\x31\xc6\x18\x63\x8c\x31\xc6\x18\x63\x8c\x31" "\xc6\x18\x63\x8c\x31\xc6\x18\x63\x8c\x31\xc6\x18\x63\x8c\x31\xc6\x18" "\x63\x8c\x31\xc6\x18\x63\x8c\x31\xc6\x18\x63\x8c\x31\xc6\x18\x63\x8c" "\x31\xc6\x18\x63\x8c\x31\xc6\x18\x63\x8c\x31\xc6\x18\x63\x8c\x31\xc6" "\x18\x63\x8c\x31\xc6\x18\x63\x8c\x31\xc6\x18\x63\x8c\x31\xc6\x18\x63" "\x8c\x31\xc6\x18\x63\x8c\x31\xc6\x18\x63\x8c\x31\xc6\x18\x63\x8c\x31" "\xc6\x18\x63\x8c\x31\xc6\x18\x63\x8c\x31\xc6\x18\x63\x8c\x31\xc6\x18" "\xcb\x1d\xce\xfb\xab\xb4\x10\x22\xe7\x36\xf8\x57\x0f\x4e\xfe\xaf\xad" "\x8d\x31\xc6\x18\x63\x8c\x31\xc6\x18\x63\x7f\x0e\x9f\xf7\x5a\x57\xc0" "\x18\x63\x8c\x31\xc6\x18\x63\x8c\xb1\xff\xfb\x40\x48\xa1\x84\x16\x81" "\xc8\x23\xf2\x8a\x18\x91\x4f\xc4\x8a\xeb\x44\x9c\xb8\x5e\xe4\x17\x05" "\x44\x44\xdc\x20\xe2\xc5\x8d\xa2\xa0\xb8\x49\x14\x12\x85\x45\x11\x51" "\x54\x24\x88\x62\xa2\xb8\x30\x02\x85\x15\x24\x42\x51\x42\x94\x14\x51" "\x71\xb3\x28\x25\x6e\x11\x89\xa2\xb4\x28\x23\xca\x0a\x27\xca\x89\xf2" "\xa2\x82\xa8\x28\x6e\x15\x95\xc4\x6d\xa2\xb2\xb8\x5d\x54\x11\x77\x88" "\xaa\xa2\x9a\xa8\x2e\x6a\x88\x3b\x45\x4d\x71\x97\xa8\x25\xee\x16\xb5" "\xc5\x3d\xa2\x8e\xa8\x2b\xea\x89\xfa\xe2\x5e\xd1\x40\xdc\x27\x1a\x8a" "\xfb\x45\x23\xf1\x80\x68\x2c\x1e\x14\x4d\xc4\x43\xa2\xa9\x78\x58\x34" "\x13\x8f\x88\xe6\xe2\x51\xd1\x42\x3c\x26\x5a\x8a\xc7\x45\x2b\xd1\x5a" "\xb4\x11\x6d\x45\xbb\xff\xa3\xfc\x97\x45\x5f\xf1\x8a\xe8\x27\xfa\x8b" "\x64\x31\x40\x0c\x14\xaf\x8a\x41\x62\xb0\x18\x22\x86\x8a\x61\xe2\x35" "\x31\x5c\xbc\x2e\x46\x88\x37\x44\x8a\x18\x29\x46\x89\x37\xc5\x68\xf1" "\x96\x18\x23\xde\x16\x63\xc5\x38\x31\x5e\xbc\x23\x26\x88\x89\x62\x92" "\x98\x2c\xa6\x88\xa9\x22\x55\xbc\x2b\xa6\x89\xf7\xc4\x74\xf1\xfe\xc8" "\xbf\xbd\xa2\x69\x62\xb6\x98\x23\x3e\x14\x73\xc5\x3c\x31\x5f\x7c\x24" "\x16\x88\x8f\xc5\x42\xb1\x48\x2c\x16\x4b\x44\xba\xf8\x44\x64\x88\xa5" "\x22\x53\x7c\x2a\x96\x89\xcf\x44\x96\x58\x2e\x56\x88\x95\x62\x95\x58" "\x2d\xd6\x88\xb5\x62\x9d\x58\x2f\x36\x88\x8d\x62\x93\xd8\x2c\xb6\x88" "\xad\x62\x9b\xf8\x5c\x6c\x17\x3b\xc4\x4e\xb1\x4b\xec\x16\x7b\xc4\x5e" "\xf1\x85\xd8\x27\xbe\x14\xfb\xc5\x57\xe2\x80\xf8\xfa\x3f\x99\x7f\xee" "\x1f\xf2\x7b\x81\x00\x01\x12\x24\x68\xd0\x90\x07\xf2\x40\x0c\xc4\x40" "\x2c\xc4\x42\x1c\xc4\x41\x7e\xc8\x0f\x11\x88\x40\x3c\xc4\x43\x41\x28" "\x08\x85\xa0\x10\x14\x81\x22\x90\x00\x09\x50\x1c\x8a\x03\x02\x02\x01" "\x41\x09\x28\x01\x51\x88\x42\x29\x28\x05\x89\x90\x08\x65\xa0\x0c\x38" "\x70\x50\x1e\xca\x43\x45\xb8\x15\x2a\x41\x25\xa8\x0c\x95\xa1\x0a\x54" "\x81\xaa\x50\x0d\xaa\x41\x0d\xa8\x01\x35\xa1\x26\xd4\x82\x5a\x50\x1b" "\x6a\x43\x1d\xa8\x03\xf5\xa0\x1e\xdc\x0b\xf7\xc2\x7d\xd0\x10\x1a\x42" "\x23\x68\x04\x8d\xa1\x31\x34\x81\x26\xd0\x14\x9a\x42\x33\x68\x06\xcd" "\xa1\x39\xb4\x80\x16\xd0\x12\x5a\x42\x2b\x68\x05\x6d\xa0\x0d\xb4\x83" "\x76\xd0\x1e\xda\x43\x07\xe8\x00\x9d\xa0\x13\x74\x86\xce\xd0\x05\xba" "\x40\x12\x24\x41\x57\xe8\x0a\xdd\xa0\x1b\x74\x87\xee\xd0\x03\x7a\x40" "\x4f\xe8\x09\xbd\xa0\x37\xf4\x86\x97\xe1\x65\x78\x05\x5e\x81\xfe\x50" "\x47\x0e\x80\x81\x30\x10\x06\xc1\x20\x18\x02\x43\x61\x28\xbc\x06\xc3" "\xe1\x75\x78\x1d\xde\x80\x14\x18\x09\xa3\xe0\x4d\x78\x13\xde\x82\x31" "\x70\x16\xc6\xc2\x38\x18\x0f\xe3\xa1\xa6\x9c\x08\x93\x60\x32\x90\x9c" "\x0a\xa9\x90\x0a\xd3\x60\x1a\x4c\x87\xe9\x30\x03\x3e\x80\x0f\x60\x16" "\xa4\xc1\x6c\x98\x03\x73\x60\x2e\xcc\x83\x79\xf0\x11\x2c\x80\x8f\xe1" "\x63\x58\x04\x8b\x60\x09\xa4\x43\x3a\x64\xc0\x52\xc8\x84\x4c\x58\x06" "\xe7\x20\x0b\x96\xc3\x0a\x58\x09\xab\x60\x35\xac\x82\xb5\xb0\x0e\xd6" "\xc2\x06\xd8\x08\x1b\x60\x33\x6c\x86\xad\xb0\x15\x3e\x87\xcf\x61\x07" "\xec\x80\x5d\xb0\x0b\xf6\xc0\x1e\xf8\x02\xbe\x80\x2f\xe1\x4b\x48\x81" "\x03\x00\xfa\xb7\x77\xdc\x21\x38\x0c\x87\x21\x1b\xb2\xe1\x08\x1c\x81" "\xa3\x70\x14\x8e\xc1\x31\x38\x0e\xc7\xe1\x04\x9c\x84\x53\x70\x12\xce" "\xc0\x19\x38\x0b\xe7\xe0\x3c\x9c\x87\x8b\x70\x11\x2e\xc1\x8b\x09\xdf" "\x35\xdf\x53\x7a\x7d\x8a\x90\x39\xb4\xd4\x32\x8f\xcc\x23\x63\x64\x8c" "\x8c\x95\xb1\x32\x4e\xc6\xc9\xfc\x32\xbf\x8c\xc8\x88\x8c\x97\xf1\xb2" "\xa0\x2c\x28\x0b\xc9\x42\xb2\x88\x2c\x22\x13\x64\x82\x2c\x2e\x8b\x4b" "\x94\x28\x49\x86\xb2\x84\x2c\x21\xa3\x32\x2a\x4b\xc9\x52\x32\x51\x26" "\xca\x32\xb2\x8c\x74\xd2\xc9\xf2\xb2\xbc\xac\x28\x2b\xca\x4a\xb2\x92" "\xac\x2c\x6f\x97\x55\xe4\x1d\xb2\xaa\xac\x26\x3b\xba\x1a\xb2\x86\xac" "\x29\x3b\xb9\x5a\xf2\x6e\x59\x5b\xd6\x96\x75\x64\x5d\x59\x4f\xd6\x97" "\xf5\x65\x03\xd9\x40\x36\x94\x0d\x65\x23\xd9\x48\x36\x96\x8d\x65\x13" "\xf9\x90\x6c\x2a\x07\xc0\x10\x78\x44\xe6\x74\xa6\x85\x1c\x09\x2d\xe5" "\x28\x68\x25\x5b\xcb\x36\xb2\xad\x7c\x0b\x9e\x90\xed\xe5\x18\xe8\x20" "\x3b\xca\x4e\xf2\x29\x39\x0e\xc6\x42\x17\xd9\xde\x25\xc9\x67\x65\x57" "\x39\x09\xba\xc9\xe7\xe5\x64\x78\x41\xf6\x90\x53\xa1\xa7\x7c\x49\xf6" "\x92\xbd\x65\x1f\xf9\xb2\xec\x2b\x3b\xb8\x7e\xb2\xbf\x9c\x01\x03\xe4" "\x40\x39\x0b\x06\xc9\xc1\x72\x88\x1c\x2a\xe7\x42\x5d\x99\xd3\xb1\x7a" "\xf2\x0d\x99\x22\x47\xca\x51\xf2\x4d\xb9\x04\xde\x92\x63\xe4\xdb\x72" "\xac\x1c\x27\xc7\xcb\x77\xe4\x04\x39\x51\x4e\x92\x93\xe5\x14\x39\x55" "\xa6\xca\x77\xe5\x34\xf9\x9e\x9c\x2e\xdf\x97\x33\xe4\x07\x72\xa6\x9c" "\x25\xd3\xe4\x6c\x39\x47\x7e\x28\xe7\xca\x79\x72\xbe\xfc\x48\x2e\x90" "\x1f\xcb\x85\x72\x91\x5c\x2c\x97\xc8\x74\xf9\x89\xcc\x90\x4b\x65\xa6" "\xfc\x54\x2e\x93\x9f\xc9\x2c\xb9\x5c\xae\x90\x2b\xe5\x2a\xb9\x5a\xae" "\x91\x6b\xe5\x3a\xb9\x5e\x6e\x90\x1b\xe5\x26\xb9\x59\x6e\x91\x5b\xe5" "\x36\xf9\xb9\xdc\x2e\x77\xc8\x9d\x72\x97\xdc\x2d\xf7\xc8\xbd\xf2\x0b" "\xb9\x4f\x7e\x29\xf7\xcb\xaf\xe4\x01\xf9\xb5\x3c\x28\xff\x22\x0f\xc9" "\x6f\xe4\x61\xf9\xad\xcc\x96\xdf\xc9\x23\xf2\x7b\x79\x54\xfe\x20\x8f" "\xc9\x1f\xe5\x71\xf9\x93\x3c\x21\x4f\xca\x53\xf2\xb4\x3c\x23\x7f\x96" "\x67\xe5\x39\x79\x5e\x5e\x90\x17\xe5\x2f\xf2\x92\xbc\x2c\xaf\x48\x2f" "\x85\x02\x25\x95\x52\x5a\x05\x2a\x8f\xca\xab\x62\x54\x3e\x15\xab\xae" "\x53\x71\xea\x7a\x95\x5f\x15\x50\x11\x75\x83\x8a\x57\x37\xaa\x82\xea" "\x26\x55\x48\x15\x56\x45\x54\x51\x95\xa0\x8a\xa9\xe2\xca\x28\x54\x56" "\x91\x0a\x55\x09\x55\x52\x45\xd5\xcd\xaa\x94\xba\x45\x25\xaa\xd2\xaa" "\x8c\x2a\xab\x9c\x2a\xa7\xca\xab\x0a\xaa\xa2\xba\x55\x55\x52\xb7\xa9" "\xca\xea\x76\x55\x45\xdd\xa1\xaa\xaa\x6a\xaa\xba\xaa\xa1\xee\x54\x35" "\xd5\x5d\xaa\x96\xba\x5b\xd5\x56\xf7\xa8\x3a\xaa\xae\xaa\xa7\xea\xab" "\x7b\x55\x03\x75\x9f\x6a\xa8\xee\x57\x8d\xd4\x03\xaa\xb1\x7a\x50\x35" "\x51\x0f\xa9\xa6\xea\x61\xd5\x4c\x3d\xa2\x9a\xab\x47\x55\x0b\xf5\x98" "\x6a\xa9\x1e\x57\xad\x54\x6b\xd5\x46\xb5\x55\xed\xd4\x13\xaa\xbd\x7a" "\x52\x75\x50\x1d\x55\x27\xf5\x94\xea\xac\x9e\x56\x5d\xd4\x33\x2a\x49" "\x3d\xab\xba\xaa\xe7\x54\x37\xf5\xbc\xea\xae\x5e\x50\x3d\xd4\x8b\xaa" "\xa7\x7a\x49\xf5\x52\xbd\x55\x1f\x75\x59\x5d\x51\x5e\xf5\x53\xfd\x55" "\xb2\x1a\xa0\x06\xaa\x57\xd5\x20\x35\x58\x0d\x51\x43\xd5\x30\xf5\x9a" "\x1a\xae\x5e\x57\x23\xd4\x1b\x2a\x45\x8d\x54\xa3\xd4\x9b\x6a\xb4\x7a" "\x4b\x8d\x51\x6f\xab\xb1\x6a\x9c\x1a\xaf\xde\x51\x13\xd4\x44\x35\x49" "\x4d\x56\x53\xd4\x54\x95\xaa\xde\x55\xd3\xd4\x7b\x6a\xba\x7a\x5f\xcd" "\x50\x1f\xa8\x99\x6a\x96\x4a\x53\xb3\xd5\x90\xbf\xae\x34\xff\x7f\x23" "\xff\xbd\x7f\x92\x3f\xe2\xd7\x67\xdf\xaa\xb6\xa9\xcf\xd5\x76\xb5\x43" "\xed\x54\xbb\xd4\x6e\xb5\x47\xed\x55\x7b\xd5\x3e\xb5\x4f\xed\x57\xfb" "\xd5\x01\x75\x40\x1d\x54\x07\xd5\x21\x75\x48\x1d\x56\x87\x55\xb6\xca" "\x56\x47\xd4\x11\x75\x54\x1d\x55\xc7\xd4\x31\x75\x5c\x1d\x57\x27\xd4" "\x49\x75\x41\x9d\x56\x67\xd4\xcf\xea\xac\x3a\xa7\xce\xa9\x0b\xea\xa2" "\xba\xa8\x2e\xfd\xf5\x35\x10\x1a\xb4\xd4\x4a\x6b\x1d\xe8\x3c\x3a\xaf" "\x8e\xd1\xf9\x74\xac\xbe\x4e\xc7\xe9\xeb\x75\x7e\x5d\x40\x47\xf4\x0d" "\x3a\x5e\xdf\xa8\x0b\xea\x9b\x74\x21\x5d\x58\x17\xd1\x45\x75\x82\x2e" "\xa6\x8b\x6b\xa3\x51\x5b\x4d\x3a\xd4\x25\x74\x49\x1d\xd5\x37\xeb\x52" "\xfa\x16\x9d\xa8\x4b\xeb\x32\xba\xac\x76\xba\x9c\xf6\xba\xc2\xbf\x95" "\x5f\x5e\x57\xd0\x7f\x54\x5f\x3b\xdd\x4e\xb7\xd7\xed\x75\x07\xdd\x41" "\x77\xd2\x9d\x74\x67\xdd\x59\x77\xd1\x5d\x74\x92\x4e\xd2\x5d\x75\x57" "\xdd\x4d\x77\xd3\xdd\x75\x77\xdd\x43\xf7\xd0\x3d\x75\x4f\xdd\x4b\xf7" "\xd2\x7d\x74\x1f\xdd\x57\xf7\xd5\xfd\x74\x3f\x9d\xac\x93\xf5\x40\xfd" "\xaa\x1e\xa4\x07\xeb\x21\x7a\xa8\x1e\xa6\x5f\xd3\xc3\xf5\x70\x3d\x42" "\x8f\xd0\x29\x3a\x45\x8f\xd2\xa3\xf4\x68\x3d\x5a\x8f\xd1\x63\xf4\x58" "\x3d\x56\x8f\xd7\xe3\xf5\x04\x3d\x41\x4f\xd2\x93\xf4\x14\x3d\x45\xa7" "\xea\x54\x3d\x4d\x4f\xd3\xd3\xf5\x74\x3d\x43\xcf\xd0\x33\xf5\x4c\x9d" "\xa6\xd3\xf4\x1c\x3d\x47\xcf\xd5\x73\xf5\x7c\x3d\x5f\x2f\xd0\x0b\xf4" "\x42\xbd\x50\x2f\xd6\x8b\x75\xba\x4e\xd7\x19\x3a\x43\x67\xea\x4c\xbd" "\x4c\x2f\xd3\x59\x7a\xb9\x5e\xae\x57\xea\x95\x7a\xb5\x5e\xad\xd7\xea" "\xb5\x7a\xbd\x5e\xaf\x37\xea\x8d\x7a\xb3\xde\xac\xb3\xf4\x36\xbd\x4d" "\x6f\xd7\xdb\xf5\x4e\xbd\x53\xef\xd6\xbb\xf5\x5e\xbd\x57\xef\xd3\xfb" "\xf4\x7e\xbd\x5f\x1f\xd0\x07\xf4\x41\x7d\x50\x1f\xd2\x87\xf4\x61\x7d" "\x58\x67\xeb\x6c\x7d\x44\x1f\xd1\x47\xf5\x51\x7d\x4c\x1f\xd3\xc7\xf5" "\x71\x7d\x42\x9f\xd0\xa7\xf4\x29\x7d\x46\x9f\xd1\x67\xf5\x59\x7d\x5e" "\x9f\xd7\x17\xf5\x45\x7d\x49\x5f\xd2\x57\xf4\x95\x9c\xc3\xbe\x40\x06" "\x32\xd0\x81\x0e\xf2\x04\x79\x82\x98\x20\x26\x88\x0d\x62\x83\xb8\x20" "\x2e\xc8\x1f\xe4\x0f\x22\x41\x24\x88\x0f\xe2\x83\x82\xc1\x4d\x41\xa1" "\xa0\x70\x50\x24\x28\x1a\x24\x04\xc5\x82\xe2\x81\x09\x30\xb0\x01\x05" "\x61\x50\x22\x28\x19\x44\x83\x9b\x83\x52\xc1\x2d\x41\x62\x50\x3a\x28" "\x13\x94\x0d\x5c\x50\x2e\x28\x1f\x54\x08\x2a\x06\xb7\x06\x95\x82\xdb" "\x82\xca\xc1\xed\x41\x95\xe0\x8e\xa0\x6a\x50\x2d\xa8\x1e\xd4\x08\xee" "\x0c\x6a\x06\x77\x05\xb5\x82\xbb\x83\xda\xc1\x3d\x41\x9d\xa0\x6e\x50" "\x2f\xa8\x1f\xdc\x1b\x34\x08\xee\x0b\x1a\x06\xf7\x07\x8d\x82\x07\x82" "\xc6\xc1\x83\x41\x93\xe0\xa1\xa0\x69\xf0\x70\xd0\x2c\x78\x24\x68\x1e" "\x3c\x1a\xb4\x08\x1e\x0b\x5a\x06\x8f\x07\xad\x82\xd6\x41\x9b\xa0\x6d" "\xd0\xee\x4f\x5d\xdf\xfb\xb3\x85\x9f\x74\xfd\x4c\x7f\x93\x6c\x06\x98" "\x81\xe6\x55\x33\xc8\x0c\x36\x43\xcc\x50\x33\xcc\xbc\x66\x86\x9b\xd7" "\xcd\x08\xf3\x86\x49\x31\x23\xcd\x28\xf3\xa6\x19\x6d\xde\x32\x63\xcc" "\xdb\x66\xac\x19\x67\xc6\x9b\x77\xcc\x04\x33\xd1\x4c\x32\x93\xcd\x14" "\x33\xd5\xa4\x9a\x77\xcd\x34\xf3\x9e\x99\x6e\xde\x37\x33\xcc\x07\x66" "\xa6\x99\x65\xd2\xcc\x6c\x33\xc7\x7c\x68\xe6\x9a\x79\x66\xbe\xf9\xc8" "\x2c\x30\x1f\x9b\x85\x66\x91\x59\x6c\x96\x98\x74\xf3\x89\xc9\x30\x4b" "\x4d\xa6\xf9\xd4\x2c\x33\x9f\x99\x2c\xb3\xdc\xac\x30\x2b\xcd\x2a\xb3" "\xda\xac\x31\x6b\xcd\x3a\xb3\xde\x6c\x30\x1b\xcd\x26\xb3\xd9\x6c\x31" "\x5b\xcd\x36\xf3\xb9\xd9\x6e\x76\x98\x9d\x66\x97\xd9\x6d\xf6\x98\xbd" "\xe6\x0b\xb3\xcf\x7c\x69\xf6\x9b\xaf\xcc\x01\xf3\xb5\x39\x68\xfe\x62" "\x0e\x99\x6f\xcc\x61\xf3\xad\xc9\x36\xdf\x99\x23\xe6\x7b\x73\xd4\xfc" "\x60\x8e\x99\x1f\xcd\x71\xf3\x93\x39\x61\x4e\x9a\x53\xe6\xb4\x39\x63" "\x7e\x36\x67\xcd\x39\x73\xde\x5c\x30\x17\xcd\x2f\xe6\x92\xb9\x6c\xae" "\x18\x9f\x73\x70\x9f\xf3\xf1\x8e\x1a\x35\xe6\xc1\x3c\x18\x83\x31\x18" "\x8b\xb1\x18\x87\x71\x98\x1f\xf3\x63\x04\x23\x18\x8f\xf1\x58\x10\x0b" "\x62\x21\x2c\x84\x45\xb0\x08\x26\x60\x02\x16\xc7\xe2\x98\x83\x90\xb0" "\x04\x96\xc0\x28\x46\xb1\x14\x96\xc2\x44\x4c\xc4\x32\x58\x06\x1d\x3a" "\x2c\x8f\xe5\xb1\x22\x56\xc4\x4a\x58\x09\x2b\x63\x65\xac\x82\x55\xb0" "\x2a\x56\xc5\xea\x58\x1d\xef\xc4\x3b\xf1\x2e\xbc\x0b\xef\xc6\xbb\xf1" "\x1e\xbc\x07\xeb\x62\x5d\xac\x8f\xf5\xb1\x01\x36\xc0\x86\xd8\x10\x1b" "\x61\x23\x6c\x8c\x8d\xb1\x09\x36\xc1\xa6\xd8\x14\x9b\x61\x33\x6c\x8e" "\xcd\xb1\x05\xb6\xc0\x96\xd8\x12\x5b\x61\x2b\x6c\x83\x6d\xb0\x1d\xb6" "\xc3\xf6\xd8\x1e\x3b\x60\x07\xec\x84\x9d\xb0\x33\x76\xc6\x2e\xd8\x05" "\x93\x30\x09\xbb\x62\x57\xec\x86\xdd\xb0\x3b\x76\xc7\x1e\xd8\x03\x7b" "\x62\x4f\xec\x85\xbd\xb0\x0f\xf6\xc1\xbe\xd8\x17\xfb\x61\x3f\x4c\xc6" "\x64\x1c\x88\x03\x71\x10\x0e\xc2\x21\x38\x04\x87\xe1\x30\x1c\x8e\xc3" "\x71\x04\x8e\xc0\x14\x4c\xc1\x51\x38\x0a\x47\xe3\x68\x1c\x83\x63\x70" "\x2c\x8e\xc3\xf1\xf8\x0e\x4e\xc0\x89\x38\x09\x27\xe3\x14\x9c\x8a\xa9" "\x98\x8a\xd3\x70\x1a\x4e\xc7\xe9\x38\x03\x67\xe0\x4c\x9c\x89\x69\x98" "\x86\x73\x70\x0e\xce\xc5\xb9\x38\x1f\xe7\xe3\x02\x5c\x80\x0b\x71\x21" "\x2e\xc6\xc5\x98\x8e\xe9\x98\x81\x19\x98\x89\x99\xb8\x0c\x97\x61\x16" "\x66\xe1\x0a\x5c\x81\xab\x70\x15\xae\xc1\x35\xb8\x0e\xd7\xe1\x06\xdc" "\x80\x9b\x70\x13\x6e\xc1\x2d\xb8\x0d\xb7\xe1\x76\xdc\x8e\x3b\x71\x27" "\xee\xc6\xdd\xb8\x17\xf7\xe2\x3e\xdc\x87\xfb\x71\x3f\x1e\xc0\x03\x78" "\x10\x0f\xe2\x21\x3c\x84\x87\xf1\x30\x66\x63\x36\x1e\xc1\x23\x78\x14" "\x8f\xe2\x31\x3c\x86\xc7\xf1\x38\x9e\xc0\x13\x78\x0a\x4f\xe1\x19\x3c" "\x83\x67\xf1\x2c\x9e\xc7\xf3\x78\x11\x7f\xc1\x4b\x78\x19\xaf\xa0\xc7" "\x18\x9b\xcf\xc6\xda\xeb\x6c\x9c\xbd\xde\xe6\xb7\x05\xec\x3f\xc6\x45" "\x6c\x51\x9b\x60\x8b\xd9\xe2\xd6\xd8\x42\xb6\xf0\xdf\xc5\x68\xad\x4d" "\xb4\xa5\x6d\x19\x5b\xd6\x3a\x5b\xce\x96\xb7\x15\x7e\x17\x57\xb5\xd5" "\x6c\x75\x5b\xc3\xde\x69\x6b\xda\xbb\x6c\xad\xdf\xc5\x0d\xec\x7d\xb6" "\xa1\xbd\xdf\x36\xb2\x0f\xd8\xfa\xf6\xde\xbf\x8b\x1b\xdb\x07\x6d\x13" "\xfb\x98\x6d\x6a\x1f\xb7\xcd\x6c\x6b\xdb\xdc\xb6\xb5\x2d\xec\x63\xb6" "\xa5\x7d\xdc\xb6\xb2\xad\x6d\x1b\xdb\xd6\x76\xb6\x4f\xdb\x2e\xf6\x19" "\x9b\x64\x9f\xb5\x5d\xed\x73\xbf\x8b\x33\xec\x52\xbb\xce\xae\xb7\x1b" "\xec\x46\xbb\xcf\x7e\x69\xcf\xdb\x0b\xf6\xa8\xfd\xc1\x5e\xb4\xbf\xd8" "\x7e\xb6\xbf\x1d\x66\x5f\xb3\xc3\xed\xeb\x76\x84\x7d\xc3\xa6\xd8\x91" "\xbf\x8b\xc7\xdb\x77\xec\x04\x3b\xd1\x4e\xb2\x93\xed\x14\x3b\xf5\x77" "\xf1\x4c\x3b\xcb\xa6\xd9\xd9\x76\x8e\xfd\xd0\xce\xb5\xf3\x7e\x17\xa7" "\xdb\x4f\xec\x02\x9b\x69\x17\xda\x45\x76\xb1\x5d\xf2\x6b\x9c\x53\x53" "\xa6\xfd\xd4\x2e\xb3\x9f\xd9\x2c\xbb\xdc\xae\xb0\x2b\xed\x2a\xbb\xda" "\xae\xb1\x6b\xff\x67\xad\x2b\xed\x66\xbb\xc5\x6e\xb5\x7b\xed\x17\x76" "\xbb\xdd\x61\x77\xda\x5d\x76\xb7\xdd\xf3\x6b\x9c\xb3\x8f\xfd\xf6\x2b" "\x7b\xc0\x7e\x6d\x8f\xd8\xef\xed\x21\xfb\x8d\x3d\x6c\x8f\xd9\x6c\xfb" "\xdd\xaf\x71\xce\xfe\x8e\xd9\x1f\xed\x71\xfb\x93\x3d\x61\x4f\xda\x53" "\xf6\xb4\x3d\x63\x7f\xb6\x67\xed\xb9\x5f\xf7\x9f\xb3\xf7\xd3\xf6\xb2" "\xbd\x62\xbd\x15\x04\x24\x49\x91\xa6\x80\xf2\x50\x5e\x8a\xa1\x7c\x14" "\x4b\xd7\x51\x1c\x5d\x4f\xf9\xa9\x00\x45\xe8\x06\x8a\xa7\x1b\xa9\x20" "\xdd\x44\x85\xa8\x30\x15\xa1\xa2\x94\x40\xc5\xa8\x38\x19\x42\xb2\x44" "\x14\x52\x09\x2a\x49\x51\xba\x99\x4a\xd1\x2d\x94\x48\xa5\xa9\x0c\x95" "\x25\x47\xe5\xa8\x3c\x55\xa0\x8a\x74\x2b\x55\xa2\xdb\xa8\x32\xdd\x4e" "\x55\xe8\x0e\xaa\x4a\xd5\xa8\x3a\xd5\xa0\x3b\xa9\x26\xdd\x45\xb5\xe8" "\x6e\xaa\x4d\xf7\x50\x1d\xaa\x4b\xf5\xa8\x3e\xdd\x4b\x0d\xe8\x3e\x6a" "\x48\xf7\x53\x23\x7a\x80\x1a\xd3\x83\xd4\x84\x1e\xa2\xa6\xf4\x30\x35" "\xa3\x47\xa8\x39\x3d\x4a\x2d\xe8\x31\x6a\x49\x8f\x53\x2b\x6a\x4d\x6d" "\xa8\x2d\xb5\xa3\x27\xa8\x3d\x3d\x49\x1d\xa8\x23\x75\xa2\xa7\xa8\x33" "\x3d\x4d\x5d\xe8\x19\x4a\xa2\x67\xa9\x2b\x3d\x47\xdd\xe8\x79\xea\x4e" "\x2f\x50\x0f\x7a\x91\x7a\xd2\x4b\xd4\x8b\x7a\x53\x1f\x7a\x99\xfa\xd2" "\x2b\xd4\x8f\xfa\x53\x32\x0d\xa0\x81\xf4\x2a\x0d\xa2\xc1\x34\x84\x86" "\xd2\x30\x7a\x8d\x86\xd3\xeb\x34\x82\xde\xa0\x14\x1a\x49\xa3\xe8\x4d" "\x1a\x4d\x6f\xd1\x18\x7a\x9b\xc6\xd2\x38\x1a\x4f\xef\xd0\x04\x9a\x48" "\x93\x68\x32\x4d\xa1\xa9\x94\x4a\xef\xd2\x34\x7a\x8f\xa6\xd3\xfb\x34" "\x83\x3e\xa0\x99\x34\x8b\xd2\x68\x36\xcd\xa1\x0f\x69\x2e\xcd\xa3\xf9" "\xf4\x11\x2d\xa0\x8f\x69\x21\x2d\xa2\xc5\xb4\x84\xd2\xe9\x13\xca\xa0" "\xa5\x94\x49\x9f\xd2\x32\xfa\x8c\xb2\x68\x39\xad\xa0\x95\xb4\x8a\x56" "\xd3\x1a\x5a\x4b\xeb\x68\x3d\x6d\xa0\x8d\xb4\x89\x36\xd3\x16\xda\x4a" "\xdb\xe8\x73\xda\x4e\x3b\x68\x27\xed\xa2\xdd\xb4\x87\xf6\xd2\x17\xb4" "\x8f\xbe\xa4\xfd\xf4\x15\x1d\xa0\xaf\xe9\x20\xfd\x85\x0e\xd1\x37\x74" "\x98\xbe\xa5\x6c\xfa\x8e\x8e\xd0\xf7\x74\x94\x7e\xa0\x63\xf4\x23\x1d" "\xa7\x9f\xe8\x04\x9d\xa4\x53\x74\x9a\xce\xd0\xcf\x74\x96\xce\xd1\x79" "\xba\x40\x17\xe9\x17\xba\x44\x97\xe9\x0a\x79\x12\x21\x84\x32\x54\xa1" "\x0e\x83\x30\x4f\x98\x37\x8c\x09\xf3\x85\xb1\xe1\x75\x61\x5c\x78\x7d" "\x98\x3f\x2c\x10\x46\xc2\x1b\xc2\xf8\xf0\xc6\xb0\x60\x78\x53\x58\x28" "\x2c\x1c\x16\x09\x8b\x86\x09\x61\xb1\xb0\x78\x68\x42\x0c\x6d\x48\x61" "\x18\x96\x08\x4b\x86\xd1\xf0\xe6\xb0\x54\x78\x4b\x98\x18\x96\x0e\xcb" "\x84\x65\x43\x17\x96\x0b\xcb\x87\x15\xc2\x8a\xe1\xad\x61\xa5\xf0\xb6" "\xb0\x72\x78\x7b\x58\x25\xbc\x23\xac\x1a\x56\x0b\x1f\x7b\xa0\x46\x78" "\x67\x58\x33\xbc\x2b\xac\x15\xde\x1d\xd6\x0e\xef\x09\xeb\x84\x75\xc3" "\x7a\x61\xfd\xf0\xde\xb0\x41\x78\x5f\xd8\x30\xbc\x3f\x6c\x14\x3e\x10" "\x56\x0a\x1f\x0c\x9b\x84\x0f\x85\x4d\xc3\x87\xc3\x66\xe1\x23\x61\xf3" "\xf0\xd1\xb0\x45\xf8\x58\xd8\x32\x7c\x3c\x6c\x15\xb6\x0e\xdb\x84\x6d" "\xc3\x76\xe1\x13\x61\xfb\xf0\xc9\xb0\x43\xd8\x31\xec\x14\x3e\x15\x76" "\x0e\x9f\x0e\xbb\x84\xcf\x84\x49\xe1\xb3\x61\xd7\xf0\xb9\x3f\xbc\x3f" "\x39\x1c\x10\x0e\x0c\x5f\x0d\x5f\x0d\xbd\xbf\x5f\x2d\x8e\x2e\x89\xa6" "\x47\x3f\x89\x66\x44\x97\x46\x33\xa3\x9f\x46\x97\x45\x3f\x8b\x66\x45" "\x97\x47\x57\x44\x57\x46\x57\x45\x57\x47\xd7\x44\xd7\x46\xd7\x45\xd7" "\x47\x37\x44\x37\x46\x37\x45\x37\x47\xb7\x44\xb7\x46\xbd\xaf\x9f\x57" "\x38\x70\xd2\x29\xa7\x5d\xe0\xf2\xb8\xbc\x2e\xc6\xe5\x73\xb1\xee\x3a" "\x17\xe7\xae\x77\xf9\x5d\x01\x17\x71\x37\xb8\x78\x77\xa3\x2b\xe8\x6e" "\x72\x85\x5c\x61\x57\xc4\x15\x75\x09\xae\x98\x2b\xee\x8c\x43\x67\x1d" "\xb9\xd0\x95\x70\x25\x5d\xd4\xdd\xec\x4a\xb9\x5b\x5c\xa2\x2b\xed\xca" "\xb8\xb2\xce\xb9\x72\xae\xbc\x6b\xeb\xda\xb9\x76\xae\xbd\x7b\xd2\x75" "\x70\x1d\x5d\x27\xf7\x94\x7b\xca\x3d\xed\x9e\x76\xcf\xb8\x67\xdc\xb3" "\xae\xab\x7b\xce\x75\x73\xcf\xbb\xee\xee\x05\xd7\xc3\xbd\xe8\x5e\x74" "\x2f\xb9\x5e\xae\xb7\xeb\xe3\x5e\x76\x7d\xdd\x2b\xae\x9f\xeb\xef\x92" "\x5d\xb2\x1b\xe8\x06\xba\x41\x6e\x90\x1b\xe2\x86\xb8\x61\x6e\x98\x1b" "\xee\x86\xbb\x11\x6e\x84\x4b\x71\x29\x6e\x94\x1b\xe5\x46\xbb\xd1\x6e" "\x8c\x1b\xe3\xc6\xba\xb1\x6e\xbc\x1b\xef\x26\xb8\x09\x6e\x92\x9b\xe4" "\xa6\xb8\x29\x2e\xd5\xa5\xba\x69\x6e\x9a\x9b\xee\xa6\xbb\x19\x6e\x86" "\x9e\xe9\x66\xba\x34\x97\xe6\xe6\xb8\x39\x6e\xae\x9b\xeb\xe6\xbb\xf9" "\x6e\x41\xe2\x02\xb7\xd0\x2d\x74\x8b\xdd\x62\x97\xee\xd2\x5d\x86\xcb" "\x70\x99\x2e\xd3\x2d\x73\xcb\x5c\x96\xcb\x72\x2b\xdc\x0a\xb7\xca\xad" "\x72\x6b\xdc\x1a\xb7\xce\xad\x73\x1b\xdc\x06\xb7\xc9\x6d\x72\x5b\xdc" "\x16\xb7\xcd\x6d\x73\xdb\xdd\x76\xb7\xd3\xed\x74\xbb\xdd\x6e\xb7\xd7" "\xed\x75\xfb\xdc\x3e\x2d\xdc\x7e\x77\xc0\x1d\x70\x07\xdd\x41\x77\xc8" "\x1d\x72\x87\xdd\xb7\x2e\xdb\x7d\xe7\x8e\xb8\xef\xdd\x51\xf7\x83\x3b" "\xe6\x7e\x74\xc7\xdd\x4f\xee\x84\x3b\xe9\x4e\xb9\xd3\xee\x8c\xfb\xd9" "\x9d\x75\xe7\xdc\x79\x77\xc1\x5d\x74\xbf\xb8\x4b\xee\xb2\xbb\xe2\xbc" "\x4b\x8d\xbc\x1b\x99\x16\x79\x2f\x32\x3d\xf2\x7e\x64\x46\xe4\x83\xc8" "\xcc\xc8\xac\x48\x5a\x64\x76\x64\x4e\xe4\xc3\xc8\xdc\xc8\xbc\xc8\xfc" "\xc8\x47\x91\x05\x91\x8f\x23\x0b\x23\x8b\x22\x8b\x23\x4b\x22\xe9\x91" "\x4f\x22\x19\x91\xa5\x91\xcc\xc8\xa7\x91\x65\x91\xcf\x22\x59\x91\xe5" "\x91\x15\x91\x95\x91\x55\x91\xd5\x11\xef\x8b\x6d\x0f\x7d\x09\x5f\xd2" "\x47\xfd\xcd\xbe\x94\xbf\xc5\x27\xfa\xd2\xbe\x8c\x2f\xeb\x9d\x2f\xe7" "\xcb\xfb\x0a\xbe\xa2\xbf\xd5\x57\xf2\xb7\xf9\xca\xfe\x76\x5f\xc5\xdf" "\xe1\xab\xfa\x6a\xbe\xba\x7f\xdc\xb7\xf2\xad\x7d\x1b\xdf\xd6\xb7\xf3" "\x4f\xf8\xf6\xfe\x49\xdf\xc1\x77\xf4\x9d\xfc\x53\xbe\xb3\x7f\xda\x77" "\xf1\xcf\xf8\x24\xff\xac\xef\xea\x9f\xf3\xdd\xfc\xf3\xbe\xbb\x7f\xc1" "\xf7\xf0\x2f\xfa\x9e\xfe\x25\xdf\xcb\xf7\xf6\x7d\xfc\xcb\xbe\xaf\x7f" "\xc5\xf7\xf3\xfd\x7d\xb2\x1f\xe0\x07\xfa\x57\xfd\x20\x3f\xd8\x0f\xf1" "\x43\xfd\x30\xff\x9a\x1f\xee\x5f\xf7\x23\xfc\x1b\x3e\xc5\x8f\xf4\xa3" "\xfc\x9b\x7e\xb4\x7f\xcb\x8f\xf1\x6f\xfb\xb1\x7e\x9c\x1f\xef\xdf\xf1" "\x13\xfc\x44\x3f\xc9\x4f\xf6\x53\xfc\x54\x9f\xea\xdf\xf5\xd3\xfc\x7b" "\x7e\xba\x7f\xdf\xcf\xf0\x1f\xf8\x99\x7e\x96\x4f\xf3\xb3\xfd\x1c\xff" "\xa1\x9f\xeb\xe7\xf9\xf9\xfe\x23\xbf\xc0\x7f\xec\x17\xfa\x45\x7e\xb1" "\x5f\xe2\xd3\xfd\x27\x3e\xc3\x2f\xf5\x99\xfe\x53\xbf\xcc\x7f\xe6\xb3" "\xfc\x72\xbf\xc2\xaf\xf4\xab\xfc\x6a\xbf\xc6\xaf\xf5\xeb\xfc\x7a\xbf" "\xc1\x6f\xf4\x9b\xfc\x66\xbf\xc5\x6f\xf5\xdb\xfc\xe7\x7e\xbb\xdf\xe1" "\x77\xfa\x5d\x7e\xb7\xdf\xe3\xf7\xfa\x2f\xfc\x3e\xff\xa5\xdf\xef\xbf" "\xf2\x07\xfc\xd7\xfe\xa0\xff\x8b\x3f\xe4\xbf\xf1\x87\xfd\xb7\x3e\xdb" "\x7f\xe7\x8f\xf8\xef\xfd\x51\xff\x83\x3f\xe6\x7f\xf4\xc7\xfd\x4f\xfe" "\x84\x3f\xe9\x4f\xf9\xd3\xfe\x8c\xff\xd9\x9f\xf5\xe7\xfc\x79\x7f\xc1" "\x5f\xf4\xbf\xf8\x4b\xfe\xb2\xbf\xe2\xbd\xbf\x86\x17\xd1\x19\x63\x8c" "\x31\xc6\xfe\xbf\xa1\xfe\xe0\xfe\x01\xff\xe4\x67\xf2\xaf\x23\xc7\x40" "\x21\xc4\xf5\x3b\x8a\x66\xff\xe3\x9a\x9b\x0a\xfd\x36\x1f\x2c\x13\x3a" "\x47\x84\x10\xcf\xf6\xef\xf9\xc8\xdf\x46\x9d\x3a\xc9\xc9\x7f\xfb\x2a" "\x81\x2c\x25\x82\x92\x8b\x84\x10\x91\xab\xf9\x79\xc4\xd5\x78\xb9\xe8" "\x24\x9e\x16\x49\xa2\xa3\xa8\xf8\x4f\xeb\x1b\x2c\x7b\x5f\xa4\x3f\x58" "\x3f\x7a\xbb\x10\xb1\xff\x21\x27\x46\x5c\x8d\xaf\xae\x7f\xeb\xbf\x58" "\xff\x89\xa7\xc6\x67\x54\x09\xcf\xc7\xff\x2f\xd6\x5f\x24\x44\x62\xc9" "\xab\x39\xf9\xc4\xd5\x78\xb9\xe8\xf4\xeb\xff\x68\x3b\x8a\x4a\xff\x62" "\xfd\xc2\xed\xff\xa0\xfe\x7c\xdf\xa4\x0a\xd1\xe1\x3f\xe4\xc4\x89\xab" "\x71\x4e\xfd\xbe\xc0\x6f\xf3\x27\xc5\x73\x22\xe9\xef\x1e\xc9\x18\x63" "\x8c\x31\xc6\x18\x63\x8c\xfd\x66\xb0\xac\xde\xfd\x8f\xce\x9f\x73\xce" "\xcf\x13\xf4\xd5\x9c\xbc\xe2\x6a\xfc\x47\xe7\xe7\x8c\x31\xc6\x18\x63" "\x8c\x31\xc6\x18\xbb\xf6\x5e\xe8\xdd\xe7\x99\x27\x92\x92\x3a\x76\xe7" "\x09\x4f\x78\xf2\xff\xd6\x44\x5d\xcb\x5f\xcf\x6b\xfd\x97\x89\x31\xc6" "\x18\x63\x8c\x31\xf6\x67\xbb\x7a\xd0\x7f\xad\x2b\x61\x8c\x31\xc6\x18" "\x63\x8c\x31\xc6\x18\x63\x8c\x31\xc6\x18\x63\x8c\x31\xc6\x18\x63\x8c" "\x31\xc6\x18\x63\x8c\x31\xc6\x18\x63\x8c\x31\xc6\x18\x63\x8c\x31\xc6" "\x72\xaf\xff\x8a\xaf\x13\xbb\xd6\x7b\x64\x8c\x31\xc6\x18\x63\x8c\x31" "\xc6\x18\x63\x8c\x31\xc6\x18\x63\x8c\x31\xc6\x18\x63\x8c\x31\xc6\x18" "\x63\x8c\x31\xc6\x18\x63\x8c\x31\xc6\x18\x63\x8c\x31\xc6\x18\x63\x8c" "\x31\xc6\x18\x63\x8c\x31\xc6\xae\xb5\xff\x11\x00\x00\xff\xff\x68\x87" "\x30\xba", 5374)); NONFAILING(syz_mount_image(/*fs=*/0x200000001500, /*dir=*/0x200000000140, /*flags=MS_NODIRATIME*/ 0x800, /*opts=*/0x200000004800, /*chdir=*/0, /*size=*/0x14fe, /*img=*/0x200000002a40)); break; case 8: // sync arguments: [ // ] syscall(__NR_sync); break; } } int main(void) { syscall(__NR_mmap, /*addr=*/0x1ffffffff000ul, /*len=*/0x1000, /*prot=*/0ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul); syscall(__NR_mmap, /*addr=*/0x200000000000ul, /*len=*/0x1000000, /*prot=PROT_WRITE|PROT_READ|PROT_EXEC*/ 7ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul); syscall(__NR_mmap, /*addr=*/0x200001000000ul, /*len=*/0x1000, /*prot=*/0ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul); setup_sysctl(); const char* reason; (void)reason; install_segv_handler(); for (procid = 0; procid < 5; procid++) { if (fork() == 0) { loop(); } } sleep(1000000); return 0; }