I thought I'd document whatever I learnt last week about the OABI and the EABI ARM system call application binary interfaces. As you probably know, the ABI describes, amongst other things, how the system call number and arguments are passed in to the kernel.
First, a hardware(read: floating-point-related) perspective. There is quite a bit on this out there so I'll make this short and sweet. ARM processors don't really have opcodes and instructions to manipulate and work with floating point numbers in their core instruction set. Currently, if you need to work with floating point numbers there are 2 options : Either you have an ARM machine that comes with a coprocessor(number 10) that supports floating point instructions and registers(ARM coprocessors introduce a certain set of new opcodes and registers for added functionality); Or you can use software emulated floating point instructions. Now that we have that out the way, lets look at OABI vs EABI.
First, a hardware(read: floating-point-related) perspective. There is quite a bit on this out there so I'll make this short and sweet. ARM processors don't really have opcodes and instructions to manipulate and work with floating point numbers in their core instruction set. Currently, if you need to work with floating point numbers there are 2 options : Either you have an ARM machine that comes with a coprocessor(number 10) that supports floating point instructions and registers(ARM coprocessors introduce a certain set of new opcodes and registers for added functionality); Or you can use software emulated floating point instructions. Now that we have that out the way, lets look at OABI vs EABI.
- OABI came out first. It assumed that your underlying machine supports floating point instructions and generates code to run on it. Now if your machine did not have support for floating point instructions, an exception is generated and the operation will be emulated in the kernel(section 2 here for more). The kernel support for this is termed NWFPE. Using NWFPE means you have context switch into the kernel for each floating point instruction. NWFPE is no longer present in the Linux ARM kernel.
- EABI to the rescue. You pass "-mfloat-abi=soft" to gcc and the compiler converts floating point operations to library calls that implement these operations in userspace. Newer ARM processors also come with coprocessors such as VFP(section 3.1)(-mfpu=softfp/hard) and NEON(section 3.2)(-mfpu-neon).
From an exploitation perspective(and this is where its related to my GSoC work), OABI and EABI primarily differ in how system call numbers are passed into the kernel.
- If you look here you can see that system call numbers have a __NR_SYSCALL_BASE specified. System call numbers are defined relative to __NR_SYSCALL_BASE. For eg:
#define __NR_sigreturn (__NR_SYSCALL_BASE+119)
If the kernel is compiled for either thumb or with EABI support __NR_SYSCALL_BASE is set to 0. Else, it is set to 0x900000. What this means is that if you are writing a srop exploit for a raspberry pi, you can set r7 to 0x77. If you're trying out on a kernel compiled with OABI, the exploit on qemu(user emulation) mode, there is a chance that your syscall number needs to be 0x900077.
- The way system call numbers are passed into the kernel for OABI and EABI are different. The former requires that the system call number be encoded into the instruction and the latter requires that the system call number be present in r7. Look at the table under "Architecture calling conventions" here.
You can see that the common entry point for syscalls here where it extracts the system call number from swi/svc or r7.