Context description
Code: Select all
int MyClass::MyFunc(int a, struct bleh b)
{
START_KERNEL;
...
END_KERNEL(my_return_value);
}
Code: Select all
#define START_KERNEL \
u32int __start_kernel_ring3 = 0; \
asm volatile("mov %%ss, %0" : "=r"(__start_kernel_ring3)); \
if(__start_kernel_ring3==0x23) \
{ \
fastSyscall(); \
}
fastSyscall is a pile of asm which will call an kernel trampoline via SYSENTER and magically pop out of it in ring0. It then returns, and the function can execute in ring0. there is a similar function fastSysexit() which is called in END_KERNEL.
The problem
This assembly trampoline could be exploited to run any code in ring 0 mode.
The potential solutions
1. Have a check: if (address_to_return_to > KERNEL_END) PANIC(); This has another problem: any arbitrary kernel code can be run (i.e. just find somewhere where a 'cli' is called and get that code called directly. Not good).
2. Have a call table. This is possible, but it has a few problems. As mentioned these syscall functions can be (and mostly are) member functions, which means function pointers cannot be easily gleaned and once gotten there is almost nil way to manipulate them. Also this will take away some of the transparency in syntax that I have worked so hard for.
3. Use a post-processor to find the valid entry points and populate a table with their locations. This again has its problems - including efficiency: every syscall would have to grep through an array of valid locations to see if it can find itself there.
I'd love to hear any ideas / points you have, and your thoughts. Am I barking totally up the wrong tree? should I be going back to an int 0x80-style C interface? Or is this possible? I'd really really like to keep my interface C++ based as my entire kernel is written in C++: it seems a little wasteful to have a whole C->C++ and C++->C layer.
Cheers!
JamesM