Professional Documents
Culture Documents
Dynamic Kernel Patching: How You Could Add Your Own System-Calls To Linux Without Editing and Recompiling The Kernel
Dynamic Kernel Patching: How You Could Add Your Own System-Calls To Linux Without Editing and Recompiling The Kernel
How you could add your own system-calls to Linux without editing and recompiling the kernel
System calls
System Calls are the basic OS mechanism for providing privileged kernel services to application programs (e.g., fork(), clone(), execve(), read(), write(), signal(), getpid(), waitpid(), gettimeofday(), setitimer(), etc.) Linux implements over 300 system calls To understand how system calls work, we can try creating one of our own design
Alternative to edit/recompile
Linux modules offer an alternative method for modifying the OS kernels functionality Its safer -- and vastly more convenient since error-recovery only needs a reboot, and minimal system knowledge suffices The main hurdle to be overcome concerns the issue of linking module code to some non-exported Linux kernel data-structures
application program
call ret
installable module
call int 0x80 ret
Linux kernel
iret
sys_restart_syscall
sys_exit sys_fork
.section .text
sys_read
sys_write sys_open sys_close
6
7 8
etc
Then you can use the grep command to find sys_call_table in your System.map file, like this:
$ grep sys_call_table /boot/System.map-2.6.22.5cslabs
Linkable File
Executable File
Where is sys_call_table[ ]?
This is how you use objdump and grep to find the sys_call_table[] address: $ cd /usr/src/linux $ objdump t vmlinux | grep sys_call_table
Exporting sys_call_table
Once you know the address of your kernels sys_call_table[], you can write a module to export that address to other modules, e.g.:
// declare global variable unsigned long *sys_call_table; EXPORT_SYMBOL(sys_call_table); int init_module( void) { sys_call_table = (unsigned long *)0xC0251500; return 0; }
Module paramerers
char *svctable; // declare global variable module_param( svctable, charp, 0444 );
// Linux will assign the address of your input string c0251500 to the svctable pointer:
simple_strtoul()
There is a kernel function you can use, in your init_module() function, that will convert a string of hexadecimal digits into an unsigned long: int init_module( void ) { unsigned long myval; myval = simple_strtoul( svctable, NULL, 16 ); sys_call_table = (unsigned long *)myval; return 0; }
Shell scripts
Its inconvenient and risks typing errors if you must manually search vmlinux and then type in the sys_call_table[]s address every time you want to install your module Fortunately this sequence of steps can be readily automated by using a shell-script We have created an example: myscript
shell-script format
First line: #!/bin/sh Some assignment-statements: version=$(uname r) mapfile=/boot/System.map-$version Some commands (useful while debugging) echo $version echo $mapfile
Finishing up
Our myscript concludes by executing the command which installs our myexport.o module into the kernel, and automatically supplies the required module-parameter If your /boot directory doesnt happen to have the System.map file in it, you can extract the sys_call_table[] address from the uncompressed vmlinux kernel-binary
newcall.c
We created this module to demonstrate the dynamic kernel patching technique It installs a function for system-call 17 This function increments the value stored in a variable of type int whose address is supplied as a function-argument We wrote the try17.cpp demo to test it!
page-frame attributes
virtual memory address of our sys_call_table[] array 0xC0251500 = 1100 0000 00 10 0101 0001 0101 0000 0000
S R / / P U W
In-class exercise #1
Write a kernel module (named unused.c) which will create a pseudo-file that reports how many unimplemented system-calls are still available. The total number of locations in the sys_call_table[] array is given by a defined constant: NR_syscalls so you can just search the array to count how many entries match sys_ni_syscall (its the value found initially in location 17)