Software interrupt
A software interrupt is an explicit call to a sub-function (usually an operating system function). It has nothing to do with an interrupt (asynchronous interruption), although the same jump distributor (interrupt table) is often used. Common mnemonics are:
- INT xxh ( interrupt with Intel 8086 )
- SC xxh ( System Call for Zilog Z8000 )
- TRAP xh ( Trap with Motorola 68000 )
- CALL 0005h ( CP / M-80 , the Intel 8080 / Zilog Z80 didn't have a special command for it)
Such function calls are called by programs with the help of special architecture-dependent commands. To do this, the number for the required sub-function must be known. This number is used as an index in a jump table (mostly interrupt vector table) which contains the start address of the subroutine.
backgrounds
Originally only used as a convenient and portable jump distributor ( MS-DOS ) - this avoids version-dependent entries directly into the operating system code (e.g. JSR $EDB9
) - these function calls have been given additional functions in modern operating systems. With these commands, context and task changes are possible that cannot (intentionally) be implemented with classic commands. So that can be INT 21h
simulated under MS-DOS using classic commands (approx. 20), but no longer INT 80h
the one used to call operating system functions in Unix binaries.
This technology only enables protected operating systems, since the change to the context of the operating system can only take place at precisely defined points.
Example for a call (Unix, Intel i386)
The POSIX function read (reading data from a filehandle into the memory) is to be implemented:
read ( int FileHandle, void* Buffer, unsigned int BufferLength ) ;
The (minimal) implementation (in libc) looks like this:
read proc
push ebx
push ecx
push edx
mov ebx, [esp+16] ; FileHandle
mov ecx, [esp+20] ; Buffer
mov edx, [esp+24] ; BufferLength
mov eax, 0003h ; Funktionnummer für read
int 80h
pop edx
pop ecx
pop ebx
cmp eax, -124 ; Werte von 0...0FFFFFF84h sind Rückgabewerte, -123...-1 sind (negierte) Fehlernummern
jbe .noError
neg eax ; Aus Rückgabewerten -1...-123 werden die Fehlernummern 1...123
mov __errno, eax ; Fehler in errno abspeichern
mov eax, -1
.noError:
ret
end proc
Treatment of the processor and operating system
The command INT 80h
does the following:
- Since the jump goes through a call gate, the priority level changes from 3 (user) to 0 ( kernel ),
- then the processor switches from the user space stack to the kernel space stack,
- then saved the flag register and
- Finally, there is a jump to an address stored by the operating system.
The first action in the kernel is to save and test the arguments:
- Can the process write to the memory area between Buffer and Buffer + BufferLength-1?
- if not ⇒ EFAULT
- Is the FileHandle valid for this process?
- if not ⇒ EBADF
- Is the memory area between Buffer and Buffer + BufferLength-1 in main memory?
- ...
An inadequate test of the arguments was still common in the early to mid-1990s. Calling system functions with purely random values was enough to crash operating systems, the crashme test program was able to demonstrate this impressively. Nowadays, every operating system is orders of magnitude more resistant to such attacks. Attacks are no longer possible with random values; sophisticated scenarios are necessary for this.
In the end, the kernel has processed the function call and returns IRET
control to the program. The return is made again via a call gate.
- Get return address from the stack
- Reconstruct flag register
- Switch back to the userspace stack
- Set the priority level back to 3