Thanks Venkatram... 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 <venkatram...@gmail.com>wrote: > On Tue, Sep 14, 2010 at 2:40 PM, Pradeep Shetty > <pradeepjshe...@gmail.com>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 hook > asmlinkage 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 = crypt > > And 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 >> > >