diff options
| author | Alexander Potapenko <glider@google.com> | 2025-07-23 13:57:42 +0200 |
|---|---|---|
| committer | Alexander Potapenko <glider@google.com> | 2025-07-24 12:46:04 +0000 |
| commit | c76c0ee772387ce764344e75570062c4219bf495 (patch) | |
| tree | d3531688dc37e6c06fbc89cf3fa557de86ba151a | |
| parent | 925dbff34225cb5d2677b079aa2db86719ec10fc (diff) | |
executor: sys/linux/dev_kvm_amd64.txt: implement rdmsr/wrmsr
Let SYZOS execute RDMSR and WRMSR on x86.
| -rw-r--r-- | executor/common_kvm_amd64_syzos.h | 54 | ||||
| -rw-r--r-- | sys/linux/dev_kvm_amd64.txt | 11 |
2 files changed, 65 insertions, 0 deletions
diff --git a/executor/common_kvm_amd64_syzos.h b/executor/common_kvm_amd64_syzos.h index 64f50dfcd..22c00b501 100644 --- a/executor/common_kvm_amd64_syzos.h +++ b/executor/common_kvm_amd64_syzos.h @@ -26,6 +26,8 @@ typedef enum { SYZOS_API_UEXIT = 0, SYZOS_API_CODE = 10, SYZOS_API_CPUID = 20, + SYZOS_API_WRMSR = 30, + SYZOS_API_RDMSR = 50, SYZOS_API_STOP, // Must be the last one } syzos_api_id; @@ -50,9 +52,21 @@ struct api_call_cpuid { uint32 ecx; }; +struct api_call_1 { + struct api_call_header header; + uint64 arg; +}; + +struct api_call_2 { + struct api_call_header header; + uint64 args[2]; +}; + static void guest_uexit(uint64 exit_code); static void guest_execute_code(uint8* insns, uint64 size); static void guest_cpuid(uint32 eax, uint32 ecx); +static void guest_wrmsr(uint64 reg, uint64 val); +static void guest_rdmsr(uint64 reg); typedef enum { UEXIT_END = (uint64)-1, @@ -90,6 +104,16 @@ guest_main(uint64 size, uint64 cpu) guest_cpuid(ccmd->eax, ccmd->ecx); break; } + case SYZOS_API_WRMSR: { + struct api_call_2* ccmd = (struct api_call_2*)cmd; + guest_wrmsr(ccmd->args[0], ccmd->args[1]); + break; + } + case SYZOS_API_RDMSR: { + struct api_call_1* ccmd = (struct api_call_1*)cmd; + guest_rdmsr(ccmd->arg); + break; + } } addr += cmd->size; size -= cmd->size; @@ -120,3 +144,33 @@ GUEST_CODE static noinline void guest_cpuid(uint32 eax, uint32 ecx) : "a"(eax), "c"(ecx) : "rbx", "rdx"); } + +// Write val into an MSR register reg. +GUEST_CODE static noinline void guest_wrmsr(uint64 reg, uint64 val) +{ + // The wrmsr instruction takes its arguments in specific registers: + // edx:eax contains the 64-bit value to write, ecx contains the MSR address. + asm volatile( + "wrmsr" + : + : "c"(reg), + "a"((uint32)val), + "d"((uint32)(val >> 32)) + : "memory"); +} + +// Read an MSR register, ignore the result. +GUEST_CODE static noinline void guest_rdmsr(uint64 reg) +{ + uint32 low = 0, high = 0; + // The rdmsr instruction takes the MSR address in ecx. + // It puts the lower 32 bits of the MSR value into eax, and the upper. + // 32 bits of the MSR value into edx. + asm volatile( + "rdmsr" + : "=a"(low), + "=d"(high) + : "c"(reg) + : // No explicit clobbers. + ); +} diff --git a/sys/linux/dev_kvm_amd64.txt b/sys/linux/dev_kvm_amd64.txt index a76e3be7f..0585a2d57 100644 --- a/sys/linux/dev_kvm_amd64.txt +++ b/sys/linux/dev_kvm_amd64.txt @@ -50,10 +50,21 @@ syzos_api_cpuid { ecx int32 } +syzos_api_wrmsr { + arg_reg flags[msr_index, int64] + arg_value int64 +} + +syzos_api_rdmsr { + arg_reg flags[msr_index, int64] +} + syzos_api_call$x86 [ uexit syzos_api$x86[0, intptr] code syzos_api$x86[10, syzos_api_code$x86] cpuid syzos_api$x86[20, syzos_api_cpuid] + wrmsr syzos_api$x86[30, syzos_api_wrmsr] + rdmsr syzos_api$x86[50, syzos_api_rdmsr] ] [varlen] kvm_text_x86 [ |
