Very strange SIGQUIT when try to switch from ring 0 to ring
Posted: Wed Jun 08, 2022 7:49 am
I am working on enabling Intel SGX on a unikernel that does not have a native ring 3 support. Hence in order to invoke the user-mode SGX instruction I need to implement a ring switch routine. I followed the JamesM's tutorial (http://jamesmolloy.co.uk/tutorial_html/ ... 0Mode.html) , which is a 32-bit solution) to drafted a long-mode version:
I am sure that I have set up GDT entries properly and 0x23/0x1B is exactly the indexes of user-mode code/data descriptors, in which the code descriptor value is 0xaffb000000ffff and the data descriptor value is 0xaff3000000ffff.
What's strange is that the iretq can be executed successfully, and the rip register could go to the next instruction of the iretq, which is a nop if I disabled the optimization and a ret if I enabled the optimization. However, when executing the next instruction, it will die without any output (my unikernel has an exception handler, even if for unhandled exceptions, it will output something). I try to use GDB to debug and GDB said that the program received SIGQUIT.
I checked the registers but find nothing wrong, cs is 0x1b, ss, ds and es are 0x23, and rip points correctly to the next instruction of iretq.
I am really confused about why it receives SIGQUIT. If some exception happened, it should output the dump message, or at least qemu log will track some 'check_exception' message, but the log is empty. Everything seems okay, correct segment registers, correct rsp/rbp/rip, the kernel code segment is user-accessible by setting the conformed bit of its descriptor, and the high/low base address in all descriptors are pointed to 0x0.
Being trapped in this problem for a whole day but cannot find any solution. I hope someone here could save my life T_T
Code: Select all
void switch_to_ring3()
{
asm volatile(" \
mov $0x23, %rax; \
mov %rax, %ds; \
mov %rax, %es; \
mov %rsp, %rax; \
push $0x23; \
push %rax; \
pushf; \
push $0x1B; \
push $1f; \
iretq; \
1: \
");
return;
What's strange is that the iretq can be executed successfully, and the rip register could go to the next instruction of the iretq, which is a nop if I disabled the optimization and a ret if I enabled the optimization. However, when executing the next instruction, it will die without any output (my unikernel has an exception handler, even if for unhandled exceptions, it will output something). I try to use GDB to debug and GDB said that the program received SIGQUIT.
I checked the registers but find nothing wrong, cs is 0x1b, ss, ds and es are 0x23, and rip points correctly to the next instruction of iretq.
I am really confused about why it receives SIGQUIT. If some exception happened, it should output the dump message, or at least qemu log will track some 'check_exception' message, but the log is empty. Everything seems okay, correct segment registers, correct rsp/rbp/rip, the kernel code segment is user-accessible by setting the conformed bit of its descriptor, and the high/low base address in all descriptors are pointed to 0x0.
Being trapped in this problem for a whole day but cannot find any solution. I hope someone here could save my life T_T