Download presentation
Presentation is loading. Please wait.
1
Dynamic kernel patching Could we implement a new Linux system-call without modifying any officially released kernel sources?
2
Upcoming Lab Project 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 around 200 system calls To understand how system calls work, we want to try building one of our own (LAB5)
3
‘Open Source’ philosophy Linux source-code is publicly available In principle, anyone could edit the sources to add their own new functions into Linux In practice, it is inconvenient to do this The steps needed involve reconfiguring, recompiling, and reinstalling your kernel For the novice these steps are arduous! Any error risks data-loss and down-time
4
Alternative to static patching 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
5
Invoking kernel services application program user-mode (restricted privileges) kernel-mode (unrestricted privileges) standard runtime libraries call ret Linux kernel int 0x80 iret installable module call ret
6
The system-call jump-table There are approximately 200 system-calls Any specific system-call is selected by its ID-number (it’s placed into register %eax) It would be inefficient to use if-else tests or even a switch-statement to transfer to the service-routine’s entry-point Instead an array of function-pointers is directly accessed (using the ID-number) This array is named ‘sys_call_table[]’
7
Assembly language (.data).section.data sys_call_table:.longsys_ni_syscall.longsys_exit.longsys_fork.longsys_read.longsys_write // …etc
8
Assembly language (.text).section.text system_call: // copy parameters from registers onto stack… callsys_call_table(,%eax,4) jmpret_from_sys_call ret_from_sys_call: // perform rescheduling and signal-handling… iret// return to caller (in user-mode)
9
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
10
Which entry can we change? We would not want to risk disrupting the normal Linux behavior through unintended alterations of some vital system-service But a few entries in ‘sys_call_table[]’ are no longer being used by the newer kernels If documented as being ‘obsolete’ it would be reasonably safe for us to ‘reuse’ an array-entry for our own purposes For example: system-call 17 is ‘obsolete’
11
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
12
Using ‘uname’ and ‘grep’ You can use the ‘uname’ command to find out which kernel-version is running: $ uname -r 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.4.26
13
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; int init_module( void) { sys_call_table = (unsigned long *)0xC025F580; return0; }
14
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’
15
Module paramerers char *svctable; // declare global variable MODULE_PARM( svctable, “s” ); // Then you install your module like this: $ /sbin/insmod myexport.o svctable=c025f580 // Linux will assign the address of your input string “c025f580” to the ‘svctable’ pointer
16
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; }
17
Shell scripts It’s inconvenient – and risks typing errors – if you must manually search ‘System.map’ and then type in 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’
18
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
19
The ‘cut’ command You can use the ‘cut’ operation on a line of text to remove the parts you don’t want An output-line from the ‘grep’ program can be piped in as a input-line to ‘cut’ You supply a command-line argument to the ‘cut’ program, to tell it which parts of the character-array you wish to retain: –For example: cut –c0-8 –Only characters 0 through 8 will be retained
20
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 doesn’t happen to have the ‘System.map’ file in it, you can extract the ‘sys_call_table[]’ address from the uncompressed ‘vmlinux’ kernel-binary
21
The ‘objdump’ program The ‘vmlinux’ file contains a Symbol-Table section that includes ‘sys_call_table’ You can display that Symbol-Table using the ‘objdump’ command with the –t flag: $ objdump –t /usr/src/linux/vmlinux You can pipe the output into ‘grep’ to find the ‘sys_call_table’ symbol-value You can use ‘cut’ to isolate the address
22
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’ (it’s the value found initially in location 17)
23
In-class exercise #2 Another important “hidden” kernel object is the Interrupt Descriptor Table It’s an array of ‘struct desc_struct’ entries and it’s named ‘idt_table[]’ Try modifying our ‘myexport.c’ demo so it will export the address for ‘idt_table[]’ Try modifying our ‘myscript’ so that it will automate your module-installation steps
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.