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
>

Reply via email to