Download Dynamic Kernel Patching: Adding Custom System-Calls to Linux and more Slides Computer Applications in PDF only on Docsity!
‘Dynamic’ kernel patching
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 kernel’s functionality
- It’s 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
Invoking kernel services
application program
user-mode (restricted privileges) (^) (unrestricted privileges)kernel-mode
standard runtime libraries
call ret
Linux kernel
int 0x iret
installable module
call ret
Assembly language (.data)
.section .data
sys_call_table:
.long sys_restart_syscall .long sys_exit .long sys_fork .long sys_read .long sys_write // …etc (from ‘arch/i386/kernel/entry.S’)
The ‘jump-table’ idea
sys_restart_syscall sys_exit sys_fork sys_read sys_write sys_open sys_close
…etc…
sys_call_table 0 .section .text
1 2 3 4 5 6 7
Changing the jump-table
- To install our own system-call function, we just need to change an entry in the Linux ‘sys_call_table[]’ array, so it points to our own module function, but save the former entry somewhere (so we can restore it if we remove our module from the kernel)
- But we first need to find ‘sys_call_table[]’ -- and there are two easy ways to do that
Finding the jump-table
- Older versions of Linux (prior to 2.4.18) used to ‘export’ the ‘sys_call_table[]’ as a global symbol, but current versions keep this table’s address private (for security)
- But often during kernel-installation there is a ‘System.map’ file that gets put into the ‘/boot’ directory and – assuming it matches your compiled kernel – it holds the kernel address for the ‘sys_call_table[]’ array
The ‘vmlinux’ file
- Your compiled kernel (uncompressed) is left in the ‘/usr/src/linux’ directory
- It is an ELF-format (executable) file
- It contains .text and .data sections
- You can examine your ‘vmlinux’ kernel with the ‘objdump’ system-utility
- You can pipe the output through the ‘grep’ utility to locate the ‘sys_call_table’ symbol
Section-Header Table (optional)
Executable versus Linkable
ELF Header
Section 2 Data Section 3 Data … Section n Data
Segment 1 Data Segment 2 Data Segment 3 Data … Segment n Data
Linkable File Executable File
Section-Header Table
Program-Header Table (optional)
Program-Header Table
ELF Header
Section 1 Data
Exporting ‘sys_call_table’
- Once you know the address of your kernel’s ‘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; }
Avoid hard-coded constant
- You probably don’t want to ‘hard code’ the sys_call_table’s value in your module – if you ever recompile your kernel, or use a differently configured kernel, you’d have to remember to edit your module and then recompile it – or risk a corrupted system!
- There’s a way to suply the required value as a module-parameter during ‘insmod’
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
- It’s 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’