LinuxQuestions.org
Did you know LQ has a Linux Hardware Compatibility List?
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie
User Name
Password
Linux - Newbie This Linux forum is for members that are new to Linux.
Just starting out and have a question? If it is not in the man pages or the how-to's this is the place!

Notices

Reply
 
Search this Thread
Old 11-18-2007, 12:33 AM   #1
Macska
LQ Newbie
 
Registered: Nov 2007
Posts: 7

Rep: Reputation: 0
Bad address error when using the system call rename


Hi,

I am trying to implement a system call in linux that calls sys_rename in namei.c. In my system call I pass in the file that already exists, and it is not a problem. For the file I want to rename it to I declare a char*
variable like this:
char *newpathname;
and I set it to: newpathname = "hhahathisworks";
then I call:
//rename pathname to newpathname
error_code = sys_rename(pathname, newpathname);
An error code of -14 (bad address) is returned. And I have managed to find that it is failing with the filename I want to rename the file to at this place:
static int do_getname(const char __user *filename, char *page)
{
int retval;
unsigned long len = PATH_MAX;
retval_greater_than_zero = 0;
filename_greater_than_task_size = 0;

if (!segment_eq(get_fs(), KERNEL_DS)) {
if ((unsigned long) filename >= TASK_SIZE)
return -EFAULT;
Does anyone know why this filename could be >= TASK_SIZE ?
It makes no sense to me. Please help.

Thank you
Macska
 
Old 11-18-2007, 01:55 PM   #2
osor
HCL Maintainer
 
Registered: Jan 2006
Distribution: (H)LFS, Gentoo
Posts: 2,450

Rep: Reputation: 70
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.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Get IP Address System call oulevon Programming 11 04-09-2010 05:32 PM
System call for getting MAC address Madhusudhan Linux - Networking 5 02-09-2006 09:06 PM
Setting IP Address to an Interface using System Call Kirthi Linux - Networking 1 01-30-2005 11:20 AM
NETPERF: ERROR --> send_udp_stream: error on remote: Interrupted system call dravya Linux - General 1 05-29-2004 05:49 PM


All times are GMT -5. The time now is 11:06 PM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration