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 >