diff options
Diffstat (limited to 'executor')
| -rw-r--r-- | executor/common_kvm.h | 45 | ||||
| -rw-r--r-- | executor/common_kvm_amd64.h | 14 | ||||
| -rw-r--r-- | executor/common_kvm_amd64_syzos.h | 25 | ||||
| -rw-r--r-- | executor/common_kvm_arm64.h | 11 | ||||
| -rw-r--r-- | executor/common_kvm_arm64_syzos.h | 24 | ||||
| -rw-r--r-- | executor/common_kvm_syzos.h | 8 |
6 files changed, 63 insertions, 64 deletions
diff --git a/executor/common_kvm.h b/executor/common_kvm.h index b11e3e06b..5be283046 100644 --- a/executor/common_kvm.h +++ b/executor/common_kvm.h @@ -5,23 +5,34 @@ // Common KVM-related definitions. -extern char *__start_guest, *__stop_guest; - -// Define a function that calculates the guest physical address for a guest function. -// Execute failure_action if the function does not belong to the guest section. -// This function is using volatile accesses, otherwise the compiler may attempt -// to store e.g. &__start_guest + offset as a constant in .rodata. -#define DEFINE_GUEST_FN_TO_GPA_FN(fn_name, offset, failure_action) \ - static inline uintptr_t fn_name(uintptr_t f) \ - { \ - volatile uintptr_t start = (uintptr_t)&__start_guest; \ - volatile uintptr_t stop = (uintptr_t)&__stop_guest; \ - if (f >= start && f < stop) { \ - return f - start + (offset); \ - } \ - (failure_action); \ - return 0; \ - } +#include "common_kvm_syzos.h" +#include "kvm.h" + +#if SYZ_EXECUTOR || __NR_syz_kvm_add_vcpu +extern char* __start_guest; + +// executor_fn_guest_addr() is compiled into both the host and the guest code. +static inline uintptr_t executor_fn_guest_addr(void* fn) +{ + // Prevent the compiler from creating a .rodata constant for + // &__start_guest + SYZOS_ADDR_EXECUTOR_CODE. + volatile uintptr_t start = (uintptr_t)&__start_guest; + volatile uintptr_t offset = SYZOS_ADDR_EXECUTOR_CODE; + return (uintptr_t)fn - start + offset; +} + +#if SYZ_EXECUTOR +// In Clang-based C++ builds, use template magic to ensure that only guest functions can be passed +// to executor_fn_guest_addr(). +template <typename R, typename... A> +uintptr_t static inline executor_fn_guest_addr(__addrspace_guest R (*fn)(A...)) +{ + return executor_fn_guest_addr((void*)fn); +} + +#endif + +#endif #if SYZ_EXECUTOR || __NR_syz_kvm_assert_syzos_kvm_exit static long syz_kvm_assert_syzos_kvm_exit(volatile long a0, volatile long a1) diff --git a/executor/common_kvm_amd64.h b/executor/common_kvm_amd64.h index 1783b7686..3c376e017 100644 --- a/executor/common_kvm_amd64.h +++ b/executor/common_kvm_amd64.h @@ -253,15 +253,6 @@ struct kvm_syz_vm { #if SYZ_EXECUTOR || __NR_syz_kvm_add_vcpu -// Post-processing code in pkg/csource/csource.go is very picky and won't let us directly pass -// fail() to DEFINE_GUEST_FN_TO_GPA_FN. -static inline void error_in_executor_fn_guest_addr() -{ - fail("SYZOS: executor_fn_guest_addr: invalid guest address"); -} - -DEFINE_GUEST_FN_TO_GPA_FN(executor_fn_guest_addr, X86_SYZOS_ADDR_EXECUTOR_CODE, error_in_executor_fn_guest_addr()); - #define X86_NUM_IDT_ENTRIES 256 static void syzos_setup_idt(struct kvm_syz_vm* vm, struct kvm_sregs* sregs) { @@ -269,7 +260,7 @@ static void syzos_setup_idt(struct kvm_syz_vm* vm, struct kvm_sregs* sregs) sregs->idt.limit = (X86_NUM_IDT_ENTRIES * sizeof(struct idt_entry_64)) - 1; volatile struct idt_entry_64* idt = (volatile struct idt_entry_64*)((uint64)vm->host_mem + sregs->idt.base); - uint64 handler_addr = executor_fn_guest_addr((uintptr_t)dummy_null_handler); + uint64 handler_addr = executor_fn_guest_addr(dummy_null_handler); for (int i = 0; i < X86_NUM_IDT_ENTRIES; i++) { idt[i].offset_low = (uint16)(handler_addr & 0xFFFF); idt[i].selector = X86_SYZOS_SEL_CODE; @@ -1031,6 +1022,7 @@ static volatile long syz_kvm_setup_cpu(volatile long a0, volatile long a1, volat #define RFLAGS_1_BIT (1ULL << 1) #define RFLAGS_IF_BIT (1ULL << 9) + static void reset_cpu_regs(int cpufd, int cpu_id, size_t text_size) { struct kvm_regs regs; @@ -1039,7 +1031,7 @@ static void reset_cpu_regs(int cpufd, int cpu_id, size_t text_size) // RFLAGS.1 must be 1, RFLAGS.IF enables interrupts. regs.rflags |= RFLAGS_1_BIT | RFLAGS_IF_BIT; // PC points to the relative offset of guest_main() within the guest code. - regs.rip = executor_fn_guest_addr((uintptr_t)guest_main); + regs.rip = executor_fn_guest_addr(guest_main); regs.rsp = X86_SYZOS_ADDR_STACK0; // Pass parameters to guest_main(). regs.rdi = text_size; diff --git a/executor/common_kvm_amd64_syzos.h b/executor/common_kvm_amd64_syzos.h index 0ccc4879e..e815e087d 100644 --- a/executor/common_kvm_amd64_syzos.h +++ b/executor/common_kvm_amd64_syzos.h @@ -65,19 +65,19 @@ struct api_call_3 { #ifdef __cplusplus extern "C" { #endif -static void guest_uexit(uint64 exit_code); +GUEST_CODE static void guest_uexit(uint64 exit_code); #ifdef __cplusplus } #endif -static void guest_execute_code(uint8* insns, uint64 size); -static void guest_handle_cpuid(uint32 eax, uint32 ecx); -static void guest_handle_wrmsr(uint64 reg, uint64 val); -static void guest_handle_rdmsr(uint64 reg); -static void guest_handle_wr_crn(struct api_call_2* cmd); -static void guest_handle_wr_drn(struct api_call_2* cmd); -static void guest_handle_in_dx(struct api_call_2* cmd); -static void guest_handle_out_dx(struct api_call_3* cmd); -static void guest_handle_set_irq_handler(struct api_call_2* cmd); +GUEST_CODE static void guest_execute_code(uint8* insns, uint64 size); +GUEST_CODE static void guest_handle_cpuid(uint32 eax, uint32 ecx); +GUEST_CODE static void guest_handle_wrmsr(uint64 reg, uint64 val); +GUEST_CODE static void guest_handle_rdmsr(uint64 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); typedef enum { UEXIT_END = (uint64)-1, @@ -383,15 +383,14 @@ GUEST_CODE static void set_idt_gate(uint8 vector, uint64 handler) idt_entry->reserved = 0; } -DEFINE_GUEST_FN_TO_GPA_FN(syzos_fn_address, X86_SYZOS_ADDR_EXECUTOR_CODE, guest_uexit(UEXIT_ASSERT)) GUEST_CODE static noinline void guest_handle_set_irq_handler(struct api_call_2* cmd) { uint8 vector = (uint8)cmd->args[0]; uint64 type = cmd->args[1]; volatile uint64 handler_addr = 0; if (type == 1) - handler_addr = syzos_fn_address((uintptr_t)dummy_null_handler); + handler_addr = executor_fn_guest_addr(dummy_null_handler); else if (type == 2) - handler_addr = syzos_fn_address((uintptr_t)uexit_irq_handler); + handler_addr = executor_fn_guest_addr(uexit_irq_handler); set_idt_gate(vector, handler_addr); } diff --git a/executor/common_kvm_arm64.h b/executor/common_kvm_arm64.h index 0837017ef..8c02b0745 100644 --- a/executor/common_kvm_arm64.h +++ b/executor/common_kvm_arm64.h @@ -144,20 +144,11 @@ static void vcpu_set_reg(int vcpu_fd, uint64 id, uint64 val) ioctl(vcpu_fd, KVM_SET_ONE_REG, ®); } -// Post-processing code in pkg/csource/csource.go is very picky and won't let us directly pass -// fail() to DEFINE_GUEST_FN_TO_GPA_FN. -static inline void error_in_executor_fn_guest_addr() -{ - fail("SYZOS: executor_fn_guest_addr: invalid guest address"); -} - -DEFINE_GUEST_FN_TO_GPA_FN(executor_fn_guest_addr, ARM64_ADDR_EXECUTOR_CODE, error_in_executor_fn_guest_addr()); - // Set up CPU registers. static void reset_cpu_regs(int cpufd, int cpu_id, size_t text_size) { // PC points to the relative offset of guest_main() within the guest code. - vcpu_set_reg(cpufd, KVM_ARM64_REGS_PC, executor_fn_guest_addr((uintptr_t)guest_main)); + vcpu_set_reg(cpufd, KVM_ARM64_REGS_PC, executor_fn_guest_addr(guest_main)); vcpu_set_reg(cpufd, KVM_ARM64_REGS_SP_EL1, ARM64_ADDR_EL1_STACK_BOTTOM + KVM_PAGE_SIZE - 128); // Store the CPU ID in TPIDR_EL1. vcpu_set_reg(cpufd, KVM_ARM64_REGS_TPIDR_EL1, cpu_id); diff --git a/executor/common_kvm_arm64_syzos.h b/executor/common_kvm_arm64_syzos.h index 2dd00a146..0a9e3391f 100644 --- a/executor/common_kvm_arm64_syzos.h +++ b/executor/common_kvm_arm64_syzos.h @@ -89,18 +89,18 @@ struct api_call_its_send_cmd { uint32 cpuid2; }; -static void guest_uexit(uint64 exit_code); -static void guest_execute_code(uint32* insns, uint64 size); -static void guest_handle_mrs(uint64 reg); -static void guest_handle_msr(uint64 reg, uint64 val); -static void guest_handle_smc(struct api_call_smccc* cmd); -static void guest_handle_hvc(struct api_call_smccc* cmd); -static void guest_handle_svc(struct api_call_smccc* cmd); -static void guest_handle_eret(uint64 unused); -static void guest_handle_irq_setup(struct api_call_irq_setup* cmd); -static void guest_handle_memwrite(struct api_call_memwrite* cmd); -static void guest_handle_its_setup(struct api_call_3* cmd); -static void guest_handle_its_send_cmd(struct api_call_its_send_cmd* cmd); +GUEST_CODE static void guest_uexit(uint64 exit_code); +GUEST_CODE static void guest_execute_code(uint32* insns, uint64 size); +GUEST_CODE static void guest_handle_mrs(uint64 reg); +GUEST_CODE static void guest_handle_msr(uint64 reg, uint64 val); +GUEST_CODE static void guest_handle_smc(struct api_call_smccc* cmd); +GUEST_CODE static void guest_handle_hvc(struct api_call_smccc* cmd); +GUEST_CODE static void guest_handle_svc(struct api_call_smccc* cmd); +GUEST_CODE static void guest_handle_eret(uint64 unused); +GUEST_CODE static void guest_handle_irq_setup(struct api_call_irq_setup* cmd); +GUEST_CODE static void guest_handle_memwrite(struct api_call_memwrite* cmd); +GUEST_CODE static void guest_handle_its_setup(struct api_call_3* cmd); +GUEST_CODE static void guest_handle_its_send_cmd(struct api_call_its_send_cmd* cmd); typedef enum { UEXIT_END = (uint64)-1, diff --git a/executor/common_kvm_syzos.h b/executor/common_kvm_syzos.h index a635d517b..be530319e 100644 --- a/executor/common_kvm_syzos.h +++ b/executor/common_kvm_syzos.h @@ -12,8 +12,11 @@ // TODO(glider): once syz-env-old migrates to GCC>11 we can just use // __attribute__((no_stack_protector)). #if defined(__clang__) + // Clang supports the no_stack_protector attribute. #define __no_stack_protector __attribute__((no_stack_protector)) +#define __addrspace_guest __attribute__((address_space(10))) + #elif defined(__GNUC__) // The no_stack_protector attribute was introduced in GCC 11.1. #if __GNUC__ > 11 @@ -22,12 +25,15 @@ // Fallback to the optimize attribute for older GCC versions. #define __no_stack_protector __attribute__((__optimize__("-fno-stack-protector"))) #endif +#define __addrspace_guest + #else #define __no_stack_protector +#define __addrspace_guest #endif // Host will map the code in this section into the guest address space. -#define GUEST_CODE __attribute__((section("guest"))) __no_stack_protector +#define GUEST_CODE __attribute__((section("guest"))) __no_stack_protector __addrspace_guest // Start/end of the guest section. extern char *__start_guest, *__stop_guest; |
