2 This file is part of NYX.
4 Copyright (c) 2021 Sergej Schumilo
5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 of this software and associated documentation files (the "Software"), to deal
7 in the Software without restriction, including without limitation the rights
8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 copies of the Software, and to permit persons to whom the Software is
10 furnished to do so, subject to the following conditions:
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
35 #define uint64_t UINT64
47 #define HYPERCALL_KAFL_RAX_ID 0x01f
48 #define HYPERCALL_KAFL_ACQUIRE 0
49 #define HYPERCALL_KAFL_GET_PAYLOAD 1
52 #define HYPERCALL_KAFL_GET_PROGRAM 2
54 #define HYPERCALL_KAFL_GET_ARGV 3
56 #define HYPERCALL_KAFL_RELEASE 4
57 #define HYPERCALL_KAFL_SUBMIT_CR3 5
58 #define HYPERCALL_KAFL_SUBMIT_PANIC 6
61 #define HYPERCALL_KAFL_SUBMIT_KASAN 7
63 #define HYPERCALL_KAFL_PANIC 8
66 #define HYPERCALL_KAFL_KASAN 9
67 #define HYPERCALL_KAFL_LOCK 10
70 #define HYPERCALL_KAFL_INFO 11
72 #define HYPERCALL_KAFL_NEXT_PAYLOAD 12
73 #define HYPERCALL_KAFL_PRINTF 13
76 #define HYPERCALL_KAFL_PRINTK_ADDR 14
78 #define HYPERCALL_KAFL_PRINTK 15
80 /* user space only hypercalls */
81 #define HYPERCALL_KAFL_USER_RANGE_ADVISE 16
82 #define HYPERCALL_KAFL_USER_SUBMIT_MODE 17
83 #define HYPERCALL_KAFL_USER_FAST_ACQUIRE 18
84 /* 19 is already used for exit reason KVM_EXIT_KAFL_TOPA_MAIN_FULL */
85 #define HYPERCALL_KAFL_USER_ABORT 20
86 #define HYPERCALL_KAFL_RANGE_SUBMIT 29
87 #define HYPERCALL_KAFL_REQ_STREAM_DATA 30
88 #define HYPERCALL_KAFL_PANIC_EXTENDED 32
90 #define HYPERCALL_KAFL_CREATE_TMP_SNAPSHOT 33
91 #define HYPERCALL_KAFL_DEBUG_TMP_SNAPSHOT 34 /* hypercall for debugging / development purposes */
93 #define HYPERCALL_KAFL_GET_HOST_CONFIG 35
94 #define HYPERCALL_KAFL_SET_AGENT_CONFIG 36
96 #define HYPERCALL_KAFL_DUMP_FILE 37
98 #define HYPERCALL_KAFL_REQ_STREAM_DATA_BULK 38
99 #define HYPERCALL_KAFL_PERSIST_PAGE_PAST_SNAPSHOT 39
101 /* hypertrash only hypercalls */
102 #define HYPERTRASH_HYPERCALL_MASK 0xAA000000
104 #define HYPERCALL_KAFL_NESTED_PREPARE (0 | HYPERTRASH_HYPERCALL_MASK)
105 #define HYPERCALL_KAFL_NESTED_CONFIG (1 | HYPERTRASH_HYPERCALL_MASK)
106 #define HYPERCALL_KAFL_NESTED_ACQUIRE (2 | HYPERTRASH_HYPERCALL_MASK)
107 #define HYPERCALL_KAFL_NESTED_RELEASE (3 | HYPERTRASH_HYPERCALL_MASK)
108 #define HYPERCALL_KAFL_NESTED_HPRINTF (4 | HYPERTRASH_HYPERCALL_MASK)gre
110 #define HPRINTF_MAX_SIZE 0x1000 /* up to 4KB hprintf strings */
112 /* specific defines to enable support for NYX hypercalls on unmodified KVM builds */
113 /* PIO port number used by VMWare backdoor */
114 #define VMWARE_PORT 0x5658
115 /* slightly changed RAX_ID to avoid vmware backdoor collisions */
116 #define HYPERCALL_KAFL_RAX_ID_VMWARE 0x8080801f
129 #define KAFL_MODE_64 0
130 #define KAFL_MODE_32 1
131 #define KAFL_MODE_16 2
133 #if defined(__i386__)
134 #define KAFL_HYPERCALL_NO_PT(_ebx, _ecx) ({ \
135 uint32_t _eax = HYPERCALL_KAFL_RAX_ID_VMWARE; \
138 "outl %%eax, %%dx;" \
140 : "b" (_ebx), "c" (_ecx), "d" (VMWARE_PORT) \
147 #define KAFL_HYPERCALL_PT(_ebx, _ecx) ({ \
148 uint32_t _eax = HYPERCALL_KAFL_RAX_ID; \
153 : "b" (_ebx), "c" (_ecx) \
162 #define KAFL_HYPERCALL_NO_PT(_rbx, _rcx) ({ \
163 uint64_t _rax = HYPERCALL_KAFL_RAX_ID_VMWARE; \
166 "outl %%eax, %%dx;" \
168 : "b" (_rbx), "c" (_rcx), "d" (VMWARE_PORT) \
175 #define KAFL_HYPERCALL_PT(_rbx, _rcx) ({ \
176 uint64_t _rax = HYPERCALL_KAFL_RAX_ID; \
181 : "b" (_rbx), "c" (_rcx) \
190 #if defined(__i386__)
193 #define KAFL_HYPERCALL(__rbx, __rcx) \
194 KAFL_HYPERCALL_NO_PT(_rbx, _rcx); \
197 static inline uint32_t kAFL_hypercall(uint32_t rbx, uint32_t rcx){
198 return KAFL_HYPERCALL_NO_PT(rbx, rcx);
201 #define KAFL_HYPERCALL(__rbx, __rcx) \
202 KAFL_HYPERCALL_PT(_rbx, _rcx); \
205 static inline uint32_t kAFL_hypercall(uint32_t rbx, uint32_t rcx){
207 return KAFL_HYPERCALL_PT(rbx, rcx);
212 #elif defined(__x86_64__)
215 #define KAFL_HYPERCALL(__rbx, __rcx) \
216 KAFL_HYPERCALL_NO_PT(_rbx, _rcx); \
219 static inline uint64_t kAFL_hypercall(uint64_t rbx, uint64_t rcx){
220 return KAFL_HYPERCALL_NO_PT(rbx, rcx);
223 #define KAFL_HYPERCALL(__rbx, __rcx) \
224 KAFL_HYPERCALL_PT(_rbx, _rcx); \
227 static inline uint64_t kAFL_hypercall(uint64_t rbx, uint64_t rcx){
229 return KAFL_HYPERCALL_PT(rbx, rcx);
236 //extern uint8_t* hprintf_buffer;
238 static inline uint8_t alloc_hprintf_buffer(uint8_t** hprintf_buffer){
239 if(!*hprintf_buffer){
241 *hprintf_buffer = (uint8_t*)VirtualAlloc(0, HPRINTF_MAX_SIZE, MEM_COMMIT, PAGE_READWRITE);
243 *hprintf_buffer = (uint8_t*)mmap((void*)NULL, HPRINTF_MAX_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
245 if(!*hprintf_buffer){
253 int (*hprintf)(const char * format, ...) = printf;
255 static void hprintf(const char * format, ...) __attribute__ ((unused));
257 static void hprintf(const char * format, ...){
258 static uint8_t* hprintf_buffer = NULL;
261 va_start(args, format);
262 if(alloc_hprintf_buffer(&hprintf_buffer)){
263 vsnprintf((char*)hprintf_buffer, HPRINTF_MAX_SIZE, format, args);
264 kAFL_hypercall(HYPERCALL_KAFL_PRINTF, (uintptr_t)hprintf_buffer);
266 //vprintf(format, args);
271 static void habort(char* msg){
272 kAFL_hypercall(HYPERCALL_KAFL_USER_ABORT, (uintptr_t)msg);
275 #define NYX_HOST_MAGIC 0x4878794e
276 #define NYX_AGENT_MAGIC 0x4178794e
278 #define NYX_HOST_VERSION 2
279 #define NYX_AGENT_VERSION 1
281 typedef struct host_config_s{
283 uint32_t host_version;
284 uint32_t bitmap_size;
285 uint32_t ijon_bitmap_size;
286 uint32_t payload_buffer_size;
289 } __attribute__((packed)) host_config_t;
291 typedef struct agent_config_s{
292 uint32_t agent_magic;
293 uint32_t agent_version;
294 uint8_t agent_timeout_detection;
295 uint8_t agent_tracing;
296 uint8_t agent_ijon_tracing;
297 uint8_t agent_non_reload_mode;
298 uint64_t trace_buffer_vaddr;
299 uint64_t ijon_trace_buffer_vaddr;
300 uint32_t coverage_bitmap_size;
301 uint32_t input_buffer_size; // TODO: remove this later
303 uint8_t dump_payloads; /* set by hypervisor */
305 } __attribute__((packed)) agent_config_t;
307 typedef struct kafl_dump_file_s{
308 uint64_t file_name_str_ptr;
312 } __attribute__((packed)) kafl_dump_file_t;
317 nyx_cpu_v1, /* Nyx CPU used by KVM-PT */
318 nyx_cpu_v2 /* Nyx CPU used by vanilla KVM + VMWare backdoor */
321 #define cpuid(in,a,b,c,d)\
322 asm("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (in));
324 static int is_nyx_vcpu(void){
325 unsigned long eax,ebx,ecx,edx;
327 cpuid(0x80000004,eax,ebx,ecx,edx);
329 for(int j=0;j<4;j++){
330 str[j] = eax >> (8*j);
331 str[j+4] = ebx >> (8*j);
334 return !memcmp(&str, "NYX vCPU", 8);
337 static int get_nyx_cpu_type(void){
338 unsigned long eax,ebx,ecx,edx;
340 cpuid(0x80000004,eax,ebx,ecx,edx);
342 for(int j=0;j<4;j++){
343 str[j] = eax >> (8*j);
344 str[j+4] = ebx >> (8*j);
347 if(memcmp(&str, "NYX vCPU", 8) != 0){
351 for(int j=0;j<4;j++){
352 str[j] = ecx >> (8*j);
353 str[j+4] = edx >> (8*j);
356 if(memcmp(&str, " (NO-PT)", 8) != 0){
363 printf("ECX: %s\n", str);
366 typedef struct req_data_bulk_s{
368 uint64_t num_addresses;
369 uint64_t addresses[479];