I'll probably use the first one as I had similar approach in my mind but didn't know whether it was possible though its not the best approach.
So, basically I need to add 2 things in kernel.. A wrapper function with a null function pointer and a system call which ends up calling my implementation part of LKM thro that function pointer. right?
This was really helpful.. Thanks again..
Regards,
-Pradeep
On Tue, Sep 14, 2010 at 6:49 PM, Venkatram Tummala <venkatram867@xxxxxxxxx> wrote:
On Tue, Sep 14, 2010 at 2:40 PM, Pradeep Shetty <pradeepjshetty@xxxxxxxxx> wrote:
Hello,
I learnt that the sys_call_table is no longer is exportable in 2.6+. I'm using 2.6.35.4 and trying to implement it in a LKM. I read the virtual addr of sys_call_table from the system map and made its physical page writable and added my syscall in place of Andrew Filesystem syscall and then made the page readonly again. But when I call my system call it is still calling AFS syscall and hence getting back ENOSYS error. I printed the sys_call_table at AFS syscall index after making the change and it seems to have the addr of my syscall. I'm not understanding where did it go wrong. Any help on figuring this out would be appreciated. Below is my code...
I haven't yet implemented the sytem call. Its about encrypting and decrypting user specified files. I would do that later once have this infrastructure set. Now I'm just printing that "I was here!".
And is there a better way of implementing this? Like creating a system call stub in the kernel that calls my function which would be part of an LKM? I would really want a generic solution to this.You cannot add a new system call dynamically just in the kernel loadable modules.There are 2 ways to overcome this.(1) Creating a Wrapper which is statically compiled into the kernel image.Include the following code in the kernel source :// Creates a NULL function pointer which will be used to point to your processing routine in the loadable kernel module.long (*crypt_sys) (args....) = NULL;//Export This Function Pointer so that you can use it in LKM.EXPORT_SYMBOL(crypt_sys);// This is the hookasmlinkage long sys_crypt_sys(args...){return crypt_sys ? crypt_sys(args) : -ENOSYS;}Now, in your loadable module init function sys_crypt_init(), assign crypt to the function pointer crypt_sys exported from the kernel.crypt_sys = cryptAnd define crypt(.....) function as a normal function.Now, when you call crypt_sys(args) from anywhere, your crypt() function in the loadable module will be executed.But, the problem is technically, you still added code builtin to the kernel code. This is just a hackish way to implement a system call from the kernel module. This will speed up for development time as you dont have to reboot every time you make a change to the system call implementation ( unless you want to change the system call signature ). But this still is considered adding a system call in the kernel which is statically compiled into the kernel image. For a better method, look at solution (2)(2) Create & Open a miscdevice in your kernel module. That is, a dummy device ( /dev/crypt for example). Now, a system call can be implemented as operations on this device in the form of ioctls. Skeleton code is provided here.const struct file_operations crypt_fops = {.owner = THIS_MODULE,.ioctl = crypt_ioctl,};struct miscdevice crypt_dev = {MISC_DYNAMIC_MINOR,"crypt_dev",&crypt_fops};static int crypt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){// cmd is magic cookie of the ioctl call that was passed in from user-space.// You can pack all your "system call" arguments into a structure and then pass the object from the user-space if you have multiple arguments.// Use copy_from_user(...) to get the object and hence the arguments and do the processing here.}You can use different magic cookies to implement distinct "system calls". crypt_ioctl is the dispatcher function here. It will look at the magic cookie, copy_from_user(...) the arguments accordingly, then do the processing.The beauty of this approach is that everything can done in the kernel module.Hope this helps.Regards,Venkatram Tummala
[root]# grep sys_call_table System.map
c12ba180 R sys_call_table
-----------------------------------------------------------------------------------------
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/unistd.h>
#include <linux/mman.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
#include <asm/atomic.h>
#include <asm/mman.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/syscalls.h>
#include <asm/cacheflush.h>
#include <asm/page.h>
#include <linux/linkage.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("shetty");
MODULE_DESCRIPTION("sys_crypt implementation");
unsigned long *sys_call_table = (unsigned long *)0xc12ba180;
static asmlinkage int (*original_call) ();
#define __NR_afs_syscall 137
SYSCALL_DEFINE5(crypt,const char __user *, infile, const char __user *, outfile,
const char __user *, keybuf, int, keylen, char, flags)
{
printk(KERN_ALERT "I was here!\n");
return keylen;
}
EXPORT_SYMBOL(sys_crypt);
static int __init sys_crypt_init(void)
{
unsigned long addr;
struct page *page;
printk(KERN_ALERT "Inserting hw1-module...\n");
page_sys_call_table = virt_to_page(sys_call_table);
addr = (unsigned long)page_address(page);
set_memory_rw(addr, 1);
original_call = sys_call_table[__NR_afs_syscall];
sys_call_table[__NR_afs_syscall] = sys_crypt;
printk(KERN_ALERT "sys_crypt = %X\n", sys_crypt);
printk(KERN_ALERT "sys_call_table:sys_crypt = %X",sys_call_table[__NR_new_syscall]);
printk(KERN_ALERT "sys_call_table = %X\n", sys_call_table);
printk(KERN_ALERT "&sys_call_table:sys_crypt = %X",&sys_call_table[__NR_new_syscall]);
set_memory_ro(addr, 1);
printk(KERN_ALERT "sys_call_table is exported\n");
return 0;
}
static void __exit sys_crypt_exit(void)
{
unsigned long addr;
struct page *page;
page_sys_call_table = virt_to_page(sys_call_table);
addr = (unsigned long)page_address(page);
set_memory_rw(addr, 1);
sys_call_table[__NR_afs_syscall] = original_call;
set_memory_ro(addr, 1);
printk(KERN_ALERT "Removing hw1-module\n");
}
module_init(sys_crypt_init);
module_exit(sys_crypt_exit);
EXPORT_SYMBOL(sys_call_table);
-----------------------------------------------------------------------------------
/var/log/messages:
Sep 13 19:11:11 d136 kernel: Inserting hw1-module...
Sep 13 19:11:11 d136 kernel: sys_crypt = D084B000 <<<<<
Sep 13 19:11:11 d136 kernel: sys_call_table:sys_crypt = D084B000 <<<<<
Sep 13 19:11:11 d136 kernel: original_call = X
Sep 13 19:11:11 d136 kernel: sys_call_table = C12BA180
Sep 13 19:11:11 d136 kernel: &sys_call_table:sys_crypt = C12BA38C
Sep 13 19:11:11 d136 kernel: sys_call_table is exported
***************From strace*****************************
afs_syscall(0x8049708, 0xbf8a5828, 0x8048462, 0x9d0ff4, 0x9cf208) = -1 ENOSYS (Function not implemented)
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7813000
write(1, "-1Error: 38, Function not implem"..., 38) = 38
exit_group(36)
***********************************************************
Thanks..
-Pradeep