Skip to content

Commit 7615391

Browse files
executor: sys/linux: implement SYZOS_API_SET_IRQ_HANDLER
The new API call allows to initialize the handler with one of the three possible values: - NULL (should cause a page fault) - dummy_null_handler (should call iret) - uexit_irq_handler (should perform guest_uexit(UEXIT_IRQ)) Also add a test for uexit_irq_handler()
1 parent b74e149 commit 7615391

File tree

4 files changed

+99
-21
lines changed

4 files changed

+99
-21
lines changed

executor/common_kvm_amd64.h

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -256,18 +256,6 @@ struct kvm_syz_vm {
256256
#endif
257257

258258
#if SYZ_EXECUTOR || __NR_syz_kvm_add_vcpu
259-
// See https://wiki.osdev.org/Interrupt_Descriptor_Table#Gate_Descriptor_2.
260-
struct idt_entry_64 {
261-
uint16 offset_low;
262-
uint16 selector;
263-
// Interrupt Stack Table offset in bits 0..2
264-
uint8 ist;
265-
// Gate Type, P and DPL.
266-
uint8 type_attr;
267-
uint16 offset_mid;
268-
uint32 offset_high;
269-
uint32 reserved;
270-
} __attribute__((packed));
271259

272260
#define EXECUTOR_FN_GUEST_ADDRESS(f) arch_executor_fn_guest_address((uintptr_t)(f), X86_SYZOS_ADDR_EXECUTOR_CODE)
273261

@@ -1111,6 +1099,7 @@ static void install_syzos_got(void* host_got, size_t got_size)
11111099
{
11121100
uint64* got = (uint64*)host_got;
11131101
got[SYZOS_GOT_X86_NULL_HANDLER] = EXECUTOR_FN_GUEST_ADDRESS(dummy_null_handler);
1102+
got[SYZOS_GOT_X86_UEXIT_HANDLER] = EXECUTOR_FN_GUEST_ADDRESS(uexit_irq_handler);
11141103
}
11151104

11161105
static void setup_vm(int vmfd, struct kvm_syz_vm* vm)

executor/common_kvm_amd64_syzos.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@ typedef enum {
2222
SYZOS_API_WR_DRN = 110,
2323
SYZOS_API_IN_DX = 130,
2424
SYZOS_API_OUT_DX = 170,
25+
SYZOS_API_SET_IRQ_HANDLER = 190,
2526
SYZOS_API_STOP, // Must be the last one
2627
} syzos_api_id;
2728

2829
typedef enum {
2930
SYZOS_GOT_X86_NULL_HANDLER,
31+
SYZOS_GOT_X86_UEXIT_HANDLER,
3032
} syzos_got_records;
3133

3234
struct api_call_header {
@@ -74,6 +76,7 @@ static void guest_handle_wr_crn(struct api_call_2* cmd);
7476
static void guest_handle_wr_drn(struct api_call_2* cmd);
7577
static void guest_handle_in_dx(struct api_call_2* cmd);
7678
static void guest_handle_out_dx(struct api_call_3* cmd);
79+
static void guest_handle_set_irq_handler(struct api_call_2* cmd);
7780

7881
typedef enum {
7982
UEXIT_END = (uint64)-1,
@@ -88,6 +91,12 @@ dummy_null_handler()
8891
asm volatile("iretq");
8992
}
9093

94+
__attribute__((naked)) GUEST_CODE static void uexit_irq_handler()
95+
{
96+
guest_uexit(UEXIT_IRQ);
97+
asm volatile("iretq");
98+
}
99+
91100
// Main guest function that performs necessary setup and passes the control to the user-provided
92101
// payload.
93102
__attribute__((used))
@@ -144,6 +153,10 @@ guest_main(uint64 size, uint64 cpu)
144153
guest_handle_out_dx((struct api_call_3*)cmd);
145154
break;
146155
}
156+
case SYZOS_API_SET_IRQ_HANDLER: {
157+
guest_handle_set_irq_handler((struct api_call_2*)cmd);
158+
break;
159+
}
147160
}
148161
addr += cmd->size;
149162
size -= cmd->size;
@@ -326,3 +339,42 @@ GUEST_CODE static noinline void guest_handle_out_dx(struct api_call_3* cmd)
326339
return;
327340
}
328341
}
342+
343+
// See https://wiki.osdev.org/Interrupt_Descriptor_Table#Gate_Descriptor_2.
344+
struct idt_entry_64 {
345+
uint16 offset_low;
346+
uint16 selector;
347+
// Interrupt Stack Table offset in bits 0..2
348+
uint8 ist;
349+
// Gate Type, P and DPL.
350+
uint8 type_attr;
351+
uint16 offset_mid;
352+
uint32 offset_high;
353+
uint32 reserved;
354+
} __attribute__((packed));
355+
356+
GUEST_CODE static void set_idt_gate(uint8 vector, void* handler_addr)
357+
{
358+
volatile struct idt_entry_64* idt =
359+
(volatile struct idt_entry_64*)(X86_SYZOS_ADDR_VAR_IDT);
360+
volatile struct idt_entry_64* idt_entry = &idt[vector];
361+
uint64 handler = (uint64)handler_addr;
362+
idt_entry->offset_low = (uint16)handler;
363+
idt_entry->offset_mid = (uint16)(handler >> 16);
364+
idt_entry->offset_high = (uint32)(handler >> 32);
365+
}
366+
367+
GUEST_CODE static noinline void guest_handle_set_irq_handler(struct api_call_2* cmd)
368+
{
369+
uint8 vector = (uint8)cmd->args[0];
370+
uint64 type = cmd->args[1];
371+
uint64 handler_addr = 0;
372+
if (type == 1) {
373+
volatile uint64* got = (volatile uint64*)X86_SYZOS_ADDR_GOT;
374+
handler_addr = got[SYZOS_GOT_X86_NULL_HANDLER];
375+
} else if (type == 2) {
376+
volatile uint64* got = (volatile uint64*)X86_SYZOS_ADDR_GOT;
377+
handler_addr = got[SYZOS_GOT_X86_UEXIT_HANDLER];
378+
}
379+
set_idt_gate(vector, (void*)handler_addr);
380+
}

sys/linux/dev_kvm_amd64.txt

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -89,16 +89,22 @@ syzos_api_out_dx {
8989
arg_val int64
9090
}
9191

92+
syzos_api_set_irq_handler {
93+
arg_vector int64[0:255]
94+
arg_handler_type int64[0:2]
95+
}
96+
9297
syzos_api_call$x86 [
93-
uexit syzos_api$x86[0, intptr]
94-
code syzos_api$x86[10, syzos_api_code$x86]
95-
cpuid syzos_api$x86[20, syzos_api_cpuid]
96-
wrmsr syzos_api$x86[30, syzos_api_wrmsr]
97-
rdmsr syzos_api$x86[50, syzos_api_rdmsr]
98-
wr_crn syzos_api$x86[70, syzos_api_wr_crn]
99-
wr_drn syzos_api$x86[110, syzos_api_wr_drn]
100-
in_dx syzos_api$x86[130, syzos_api_in_dx]
101-
out_dx syzos_api$x86[170, syzos_api_out_dx]
98+
uexit syzos_api$x86[0, intptr]
99+
code syzos_api$x86[10, syzos_api_code$x86]
100+
cpuid syzos_api$x86[20, syzos_api_cpuid]
101+
wrmsr syzos_api$x86[30, syzos_api_wrmsr]
102+
rdmsr syzos_api$x86[50, syzos_api_rdmsr]
103+
wr_crn syzos_api$x86[70, syzos_api_wr_crn]
104+
wr_drn syzos_api$x86[110, syzos_api_wr_drn]
105+
in_dx syzos_api$x86[130, syzos_api_in_dx]
106+
out_dx syzos_api$x86[170, syzos_api_out_dx]
107+
set_irq_handler syzos_api$x86[190, syzos_api_set_irq_handler]
102108
] [varlen]
103109

104110
kvm_text_x86 [
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#
2+
# requires: arch=amd64 -threaded
3+
#
4+
r0 = openat$kvm(0, &AUTO='/dev/kvm\x00', 0x0, 0x0)
5+
r1 = ioctl$KVM_CREATE_VM(r0, AUTO, 0x0)
6+
r2 = syz_kvm_setup_syzos_vm$x86(r1, &(0x7f0000c00000/0x400000)=nil)
7+
#
8+
# Set a non-dummy IRQ handler for vector 0x80.
9+
#
10+
r3 = syz_kvm_add_vcpu$x86(r2, &AUTO={0x0, &AUTO=[@set_irq_handler={AUTO, AUTO, {0x80, 0x2}}, @uexit={AUTO, AUTO, 0xaaaa}], AUTO})
11+
r4 = ioctl$KVM_GET_VCPU_MMAP_SIZE(r0, AUTO)
12+
r5 = mmap$KVM_VCPU(&(0x7f0000009000/0x1000)=nil, r4, 0x3, 0x1, r3, 0x0)
13+
14+
# Run till uexit(0xaaaa).
15+
#
16+
ioctl$KVM_RUN(r3, AUTO, 0x0)
17+
syz_kvm_assert_syzos_uexit$x86(r5, 0xaaaa)
18+
19+
# Inject interrupt 0x80.
20+
#
21+
ioctl$KVM_INTERRUPT(r3, AUTO, &AUTO=0x80)
22+
ioctl$KVM_RUN(r3, AUTO, 0x0)
23+
24+
# Ensure that the uexit code is UEXIT_IRQ.
25+
#
26+
syz_kvm_assert_syzos_uexit$x86(r5, 0xfffffffffffffffe)
27+
28+
# Run till the end.
29+
#
30+
ioctl$KVM_RUN(r3, AUTO, 0x0)
31+
syz_kvm_assert_syzos_uexit$x86(r5, 0xffffffffffffffff)

0 commit comments

Comments
 (0)