On Tue, Sep 14, 2010 at 4:04 PM, Pradeep Shetty <pradeepjshe...@gmail.com>wrote:
> 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? > You can declare & export your null function pointer globally and the system call processing routing will check that function pointer for a non-null value. If it is non-null, then it means that the loadable module must have initialized the function pointer to the function in the loadable module (crypt), and hence the system call processing function can call the crypt function in the LKM. O'wise -ENOSYS is returned. Keep in mind that you have to call the "system call" by the function pointer (crypt_sys(...)) from the user code to invoke the system call, NOT by calling crypt( ). Regards, Venkatram Tummala > > 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 >>> >> >> >