OSDev.org

The Place to Start for Operating System Developers
It is currently Tue May 17, 2022 9:38 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 10 posts ] 
Author Message
 Post subject: Return from interrupt without iret
PostPosted: Thu Jan 27, 2022 6:00 am 
Offline
Member
Member

Joined: Tue Aug 31, 2021 7:25 am
Posts: 60
Say a software interrupt just happened. How would you "acknowledge" the interrupt without using an IRET instruction? I tried simply clearing the interrupt data from the stack and then setting the interrupt flag but that does not work very well. The wiki also does not make it clear what steps are required in order to exit the interrupt state.

Thanks!


Top
 Profile  
 
 Post subject: Re: Return from interrupt without iret
PostPosted: Thu Jan 27, 2022 6:57 am 
Offline
Member
Member

Joined: Tue Feb 18, 2020 3:29 pm
Posts: 908
Interrupts always return with IRET. Very rarely is there an exception to that rule. If you want to just acknowledge, then send EOI in the case of a hardware interrupt, and then use IRET


Top
 Profile  
 
 Post subject: Re: Return from interrupt without iret
PostPosted: Thu Jan 27, 2022 7:00 am 
Offline
Member
Member
User avatar

Joined: Sat Mar 31, 2012 3:07 am
Posts: 4349
Location: Chichester, UK
How would a software interrupt "just happen"? Either you executed an "int" instruction or you didn't. And why are you reluctant to use an "iret" instruction to end the interrupt handler?


Top
 Profile  
 
 Post subject: Re: Return from interrupt without iret
PostPosted: Thu Jan 27, 2022 7:41 am 
Offline
Member
Member

Joined: Thu May 17, 2007 1:27 pm
Posts: 999
It's not really possible to return from an interrupt without iret unless you're willing to add strange hacks. You need an atomic way to jump to a user mode address and to set IF to zero at the same time┬╣. Outside iret, you could use something like sysret for that purpose, but it is more messy and not intended for the purpose of returning from an arbitrary interrupt.

┬╣ Technically, that's not required but any other design can easily run into nasty pitfalls.

_________________
managarm: Microkernel-based OS capable of running a Wayland desktop (Discord: https://discord.gg/7WB6Ur3). My OS-dev projects: [mlibc: Portable C library for managarm, qword, Linux, Sigma, ...] [LAI: AML interpreter] [xbstrap: Build system for OS distributions].


Top
 Profile  
 
 Post subject: Re: Return from interrupt without iret
PostPosted: Thu Jan 27, 2022 7:45 am 
Offline

Joined: Fri Nov 26, 2021 11:08 am
Posts: 3
Upon entry the interrupt flag gets cleared. The iret instruction restores it because it pops the previous flags from the stack.

iret is basically: popf + retf, just that the ordering on the stack is reversed. In order to actually replace it with these two instructions, you would need to do quite some stack shuffling. But I cannot think of a good reason to do so.


Top
 Profile  
 
 Post subject: Re: Return from interrupt without iret
PostPosted: Thu Jan 27, 2022 10:04 am 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 3820
YDeeps1 wrote:
without using an IRET instruction

Why don't you want to use an IRET instruction?


Top
 Profile  
 
 Post subject: Re: Return from interrupt without iret
PostPosted: Thu Jan 27, 2022 12:02 pm 
Offline
Member
Member

Joined: Thu Feb 09, 2012 6:53 am
Posts: 63
Location: Czechoslovakia
I had to exit interrupt handler without iretq too. But that was very special case. There is no way to block #NMI in Intel VMX root mode unlike at AMD SVM where you can (using CLGI instruction). While my hypervisor accepted #NMI I wanted to let the CPU in #NMI blocking mode to prevent more #NMI to arrive as I was able to inject only 1 #NMI into guest during every VM entry. These #NMI came as IPIs from different cpus/cores where hyper-v was running as a child under nested environment. At the end I solved my problem but during observation and development I had to try that way to leave #NMI blocked so I had to avoid iretq as iretq unblocks #NMI.
I used this way at the end of my #NMI handler:
Code:
push rax
; now the stack looks this way:
; qword [rsp+8*0] RAX
; qword [rsp+8*1] RIP
;  word [rsp+8*2] CS
; qword [rsp+8*3] RFLAGS
; qword [rsp+8*4] RSP
;  word [rsp+8*5] SS
; this leaves interrupt handler and lets NMIs blocked:
mov rax,rsp
lss rsp,[rax+8*4]   ; load RSP from qword [rax+8*4] and SS from [rax+8*4+8]
push qword [rax+8*3]
popf
push qword [rax+8*2]   ; CS
push qword [rax+8*1]   ; RIP
mov rax,[rax+8*0]   ; restore RAX
retf

_________________
hypervisor-based solutions developer (Intel, AMD)


Top
 Profile  
 
 Post subject: Re: Return from interrupt without iret
PostPosted: Thu Jan 27, 2022 1:31 pm 
Online
Member
Member

Joined: Wed Aug 30, 2017 8:24 am
Posts: 1231
This solution has the drawback of executing kernel code on user stack. After the lss instruction, any exception that occurs will be taken on user stack. After the popf, any external interrupt will be as well. User space can make you hit unmapped space, leading to double-fault. Alternatively, second user-space thread can manipulate the stack frame, leading to ring 0 arbitrary code execution. Attacker only has to get lucky once, and can try as often as they want.

_________________
Carpe diem!


Top
 Profile  
 
 Post subject: Re: Return from interrupt without iret
PostPosted: Fri Jan 28, 2022 3:05 am 
Offline
Member
Member

Joined: Wed Oct 01, 2008 1:55 pm
Posts: 2806
First, I feel it is a bad idea to let software interrupts from the application disable interrupts. You should use the IDT entry that keeps interrupts enabled.

When it comes to not using iret, it's possible to use retf instead, provided you don't care about restoring the state of flags (which assumes you either enabled interrupts specifically, or used a interrupt gate that doesn't disable interrupts.

However, I think it would be more useful to modify the contents of the flag image on the stack instead if you want to return specific flags (like NC/CY) to the caller.

Another issue is if the kernel even allow software interrupts from user space. This is decided per IDT entry. In my kernel, all IDTs disallow software interrupts from the application, and they are instead emulated in the GPF handler.

Also, iret doesn't acknowledge an interrupt. It's just a way to unwind the call stack. It's EOI that acknowledge a hardware interrupt, and if you forget that and just use iret then hardware interrupts will be messed up. For software interrupts, there is no acknowledge.


Top
 Profile  
 
 Post subject: Re: Return from interrupt without iret
PostPosted: Sun Jan 30, 2022 4:34 am 
Offline
Member
Member

Joined: Thu Feb 09, 2012 6:53 am
Posts: 63
Location: Czechoslovakia
nullplan - exactly as you wrote, this method is useless for OS development.
The #NMI arrived in vmx root mode so before #NMI hypervisor stack was loaded (ring-1, VCMS.host_RSP, VMCS.host_SS etc) and when transferring to #NMI handler the private NMI stack was loaded using hypervisor VMCS.host_TSS.IST feature. So at the end of NMI handler the LSS loaded original hypervisor stack, not guest kernelmode stack (ring0) either guest usermode stack (ring3).
These #NMI always arrived as IPI from different cpus/cores and were send by hyper-v, I had to prevent delivering more than 1 #NMI during 1 cycle of vmx root mode (from vm exit till vm entry). During vm entry I had to inject this captured #NMI back into guest, I did not care whether the guest was going to be in ring0 or ring3, handling that was let for cpu (hardware). But the origin of these #NMI was certainly from hyper-v because disabling hyper-v in registry and rebooting then no more #NMI captured in my hypervisor. Hyper-v was running in ring0 mode, not in ring-1. My hypervisor was running in ring-1 as a parent and provided nested capabilities for child hyper-v (so hyper-v was thinking it was running in ring-1 but in fact it was running in ring0 and my parent hypervisor provided emulation of ring-1 instructions for hyper-v).
It was a nightmare but finally I solved that. I just had to keep ring-1 execution with #NMI blocked after capturing #NMI (avoid IRETQ at the end of #NMI handler) so no more than 1 #NMI arrived, then during vm entry I had to clear NMI blocking for guest in VMCS and inject the NMI into guest using VMCS fields so the #NMI was delivered to guest immediately at vm entry. It was very specific situation. For OS development I do not see any advantage of avoiding IRETQ. From hypervisor point you can easily manipulate guest state whether you want your guest is in NMI blocking mode or unblocked mode using 1 bit in VMCS but for root mode there is no such way how to change NMI blocking. My only one idea was to avoid IRETQ which let cpu in NMI blocking mode.
On AMD there is no such problem as at AMD SVM you can easily toggle NMI blocking so #NMI never arrives into your hypervisor. The problem was only at Intel VMX where you can't (at Intel you can only unblock NMI blocking by execution of IRETQ but there is no way how to set CPU into NMI blocking mode).

_________________
hypervisor-based solutions developer (Intel, AMD)


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 10 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: PetalBot [Bot] and 8 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group