views:

616

answers:

3

I am writing kernel module(C in Linux) and I want to change the permission of the other files in it. any solution? since I am in kernel I can't use chmod syscall and ... thanks for your help

This is my Makefile:

> obj-m += ca.o
> 
>     all:
>       make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
>     
>     clean:
>       make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

And this is my Code:

> #include <linux/string.h>
> #include <linux/mm.h>
> /* Snip, tons of includes (all of them :))*/
> #include <linux/delay.h> .... int procfile_write(struct file *file,
> const char *buffer, unsigned long
> count,
>       void *data) { ...  sys_chmod(path, per); ... } ...

When Making it gives a warning:

WARNING: "sys_chmod" [file] undefiened

and when loading the module with "sudo insmod" it gives this error:

Unknown sybol in module

it seems that this error happens especialy in kernel modules. any idea? again thanks!

+4  A: 

Welcome to stackoverflow! IIRC you want sys_chmod()

From the Linux Kernel Mailing List

On Thu, Feb 20, 2003 at 11:10:27PM +0100, Andrea Arcangeli wrote: On Thu, Feb 20, 2003 at 12:40:43PM -0500, Jeff Garzik wrote:

On Thu, Feb 20, 2003 at 11:04:37PM +0530, Prasad wrote:

Is there a way using which i could invoke a syscall in the kernel space? The syscall is to be run disguised as another process. The actual

Call sys_whatever(). Look at the kernel code for examples.

The kernel already does this in various places. sys_read, sys_write, open_filp, sys_close, and other functions are safe to call from kernel code -- though this is discouraged. init/do_mounts.c is a particularly annoying case, and is a big reason why klibc needs to be merged. syscalls should be made from userspace, not the kernel.

People are starting to worry, as this isn't the kind of thing you might do in the kernel (unless you are use you know what you are doing). If you just want to change permissions on a certain event, do it from userspace with inotify or similar.

Disclaimer aside:

Here is some code I found in another kernel module, which uses the sys_* calls:

#include <linux/init.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/syscalls.h>
/* Snip */

int openflags = O_WRONLY|O_CREAT;
if (ml != 1)
        openflags |= O_TRUNC;
wfd = sys_open(collected, openflags, mode);

if (wfd >= 0) {
    sys_fchown(wfd, uid, gid);
    sys_fchmod(wfd, mode);
    state = CopyFile;
}

Also found:

asmlinkage long sys_rename(const char __user *oldname, const char __user *newname);
asmlinkage long sys_chmod(const char __user *filename, mode_t mode);
asmlinkage long sys_fchmod(unsigned int fd, mode_t mode);

in include/linux/syscalls.h

Mind you, it has been a while since I did any kernel stuff. Check that this is the appropriate interface for chmod stuff and that you arn't shortcutting any other call that might implement security hooks, for example.

Also, This link contains information on syscalls and their symbols. Also Here is a quick-reference of user-space API system calls and where they are implemented in the kernel.

Aiden Bell
thanks! it compiled with sys_chmod and gave a WARNING: "sys_chmod is not defiened". and when loading by "sudo insmod ..." gave ERROR: "unknown symbol in module"I had included all header files including syscalls, sys and 40 others.
Mehrdad
http://lxr.linux.no/#linux+v2.6.30.5/include/linux/syscalls.h#L428http://www.gelato.unsw.edu.au/lxr/ident?i=sys_chmodThose might help.
Aiden Bell
Also, see edit. I added the includes from the source snippet (which was the source of initramfs)
Aiden Bell
Also check your linker stuff such as "-L/linux-2.6.x/..." in your Makefile/GCC
Aiden Bell
really really thanks for the time you put on it! but it still has warning and error. I put the details on the edit.
Mehrdad
Looks like your compilation process is broken, not your source. You will need to ask another question :) Also see edit at the top of my post.
Aiden Bell
This will not work for modules.
Nicolas Viennot
+2  A: 

The syscalls are not exported symbols. You need to do a little bit of hacking if you want them.

you want to get your fingers on sys_call_table. It contains a pointer to every syscall. Look at arch/x86/kernel/syscall_table_32.S or arch/i386/kernel/entry.S on older kernels.

You can grep sys_call_table /usr/src/linux/System.map (or /proc/kallsyms if the symbols are exported) to find the base address of this table. You can have this address as a parameter for your module (converting an hex string to a pointer will be needed).

You'll be able to call the right syscall with the offset defined in arch/x86/include/asm/unistd_32.h (or include/asm-i386/unistd.h on older kernels). You get something like: #define __NR_chmod 15

Macros are helpful:

#define DO_SYSCALL_2(sc, t1, a1, t2, a2)                       \
    (((asmlinkage long (*)(t1, t2)) sys_call_table[__NR_##sc]) (a1, a2));
#define USER_SYSCALL_2(sc, t1, a1, t2, a2)                     \
    static inline asmlinkage long syscall_##sc(t1 a1, t2 a2)   \
    { return DO_SYSCALL_2(sc, t1, a1, t2, a2) }

USER_SYSCALL_2(chmod, const char __user *, filename, mode_t, mode);
int my_code(void) { return syscall_chmod(arg1, arg2); }

Also, if you are passing kernel buffer (for filename for examples) that are supposed to be user buffers, don't forget to change the data segment:

mm_segment_t oldfs = get_fs(); set_fs(KERNEL_DS);
ret = syscall_XXX(...);
set_fs(oldfd);
Nicolas Viennot
+1 (wish I could +4) excellent answer Pafy. I nominate this for the correct answer in-place of my own 'guess'
Aiden Bell
wow! thanks! I will try it as soon as possible! it seems so nice:-D
Mehrdad
:)And also, you can hijack them (just replace the right pointer in the syscall table with a function of your own). And if you save the original pointer, you have a wrapper :)
Nicolas Viennot
A: 

I am working on kernel 2.6.14.-16 (Ununtu distro). I am trying similar things; calling sys_getpid() and getting same error. But I see my kernel EXPORT all these symbols (/proc/kallsyms.

why sys_* symbols are not getting linked???/

Thanks, Raman Chalotra.

Raman