You seem to be confusing kernelspace with userspace. First off,
sys_rename() isn’t even an exported symbol on my machine (and a cursory search shows it is not exported on any other vanilla linux kernels from at least 2.0.40 to 2.6.23). The reason it is not exported is that it is not meant to be used from kernelspace. If you find yourself trying to use it, ask yourself if the problem you’re trying to solve is better addressable in userspace.
But suppose you recompiled the kernel to export the symbol. Then, what? Well, the prototype for
sys_rename() is as follows:
Code:
asmlinkage long sys_rename(const char __user *oldname, const char __user *newname)
You see that the arguments are pointers holding
USERSPACE addresses (not kernelspace). Userspace virtual addresses all have values strictly less than
TASK_SIZE.
TASK_SIZE is an architecture-dependent macro; on a default i386 setup its value is 0xC0000000 (3GB). So at least one of the paths of execution starting at
sys_rename() will check to see if the addresses are bad (i.e., there is no possible way that a userspace program would be able to address such a memory location).
Almost all third party kernel code is a module that is initially executed as kernel code running in a user context (e.g., it is associated with a userspace process). So you need some way to tell the checking mechanism that you are actually in kernelspace. There are certain macros
get_fs() and
set_fs() that will allow you to view or change the address limit for the associated process (respectively). This allows you to temporarily give the userspace process access to kernelspace addresses.
So, you have to sandwich all code that calls such addresses by changing the address limit and resetting it to its original value. For example, suppose I write a module where I want to rename a file upon module loading. This is what it might look like:
Code:
#include <linux/module.h>
#include <asm/uaccess.h>
#include <linux/syscalls.h>
MODULE_LICENSE("GPL");
char old_name [] = "/home/osor/oldname";
char new_name [] = "/home/osor/newname";
int init_module()
{
int retval;
mm_segment_t oldfs;
oldfs = get_fs();
set_fs (KERNEL_DS);
retval = sys_rename(old_name, new_name);
set_fs(oldfs);
return retval;
}
void cleanup_module() { }
Note that this code assumes the following patch (which allows the direct calling of
sys_rename()) to the 2.6.23 kernel:
Code:
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2639,6 +2639,7 @@ asmlinkage long sys_rename(const char __user *oldname, const char __user *newnam
{
return sys_renameat(AT_FDCWD, oldname, AT_FDCWD, newname);
}
+EXPORT_SYMBOL_GPL(sys_rename);
int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen, const char *link)
{
P.S.
It seems that the desire to do userspace activities in kernelspace is systemic in the kernel-newbie community. This is the third
such question I have seen in a month.