Skip to contentSkip to conversation

allocate memory in userspace

DISCUSSION Timo Benk 5 participants 9 messages Jul 1, 2002 – Jul 2, 2002

lore
Share & tools
lore

Timo Benk

author
#0 lore raw

Hi,

I am a kernel newbie and i am writing a module. I need to allocate some memory in userspace because i want to access syscalls like open(), lstat() etc. I need to call these methods in the kernel, and in my special case there is no other way, but i do not want to reimplement all the syscalls.

I read that it should be possible, but i cannot find any example or recipe on how to do it. It should work with do_mmap() and fd=-1 and MAP_ANON, but i jusst can't get it to work.

Do you now any working example, or a good reference for the do_mmap() call?

Thanks in advance,

-timo

Signature · 1 line
gpg key fingerprint = 6832 C8EC D823 4059 0CD1  6FBF 9383 7DBD 109E 98DC
#1 lore raw
Quoted 8 lines · Timo Benk

Hi,

I am a kernel newbie and i am writing a module. I need to allocate some memory in userspace because i want to access syscalls like open(), lstat() etc. I need to call these methods in the kernel, and in my special case there is no other way, but i do not want to reimplement all the syscalls.

So use the C library and call malloc()

Quoted 4 lines

I read that it should be possible, but i cannot find any example or recipe on how to do it. It should work with do_mmap() and fd=-1 and MAP_ANON, but i jusst can't get it to work.

void *malloc(size_t size)

{
    void *result;
    if (size == 0)
	return NULL;
    result = mmap((void *) 0, size + sizeof(size_t), PROT_READ | PROT_WRITE, 
	    MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
    if (result == MAP_FAILED)
	return 0;
    * (size_t *) result = size;
    return(result + sizeof(size_t));
}

void * calloc(size_t nelem, size_t size)

{
    void *result;
    result = malloc(size * nelem);
    if (result)
	memset(result, 0, nelem * size);
    return result;
}

void *realloc(void *ptr, size_t size)

{
    void *newptr = NULL;
    if (size > 0) {
	newptr = malloc(size);
	if (newptr && ptr) {
	    memcpy(newptr, ptr, * ((size_t *) (ptr - sizeof(size_t))));
	    free(ptr);
	}
    }
    else {
	free(ptr);
    }
    return newptr;
}

void free(void *ptr)

{
    if (ptr) {
	ptr -= sizeof(size_t);
	munmap(ptr, * (size_t *) ptr);
    }
}

-Erik

--
Erik B. Andersen http://codepoet-consulting.com/
--This message was written using 73% post-consumer electrons--

#2 lore raw
Quoted 12 lines · Erik Andersen

void *malloc(size_t size)

{
    void *result;
    if (size == 0)
	return NULL;
    result = mmap((void *) 0, size + sizeof(size_t), PROT_READ | PROT_WRITE, 
	    MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
    if (result == MAP_FAILED)
	return 0;
    * (size_t *) result = size;
    return(result + sizeof(size_t));
}

This looks like a very bad idea. Userspace allocators should make some attempt at avoiding diving into the kernel at every allocation like this. Also, they should be intelligent enough to get around TASK_UNMAPPED_BASE. Wilson's allocator survey has an excellent discussion of the issues. Doug Lea has a better example of a userspace memory allocator.

Cheers,
Bill

#3 lore raw
Quoted 12 lines · Erik Andersen
Quoted 12 lines

void *malloc(size_t size)

{
    void *result;
    if (size == 0)
	return NULL;
    result = mmap((void *) 0, size + sizeof(size_t), PROT_READ | PROT_WRITE, 
	    MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
    if (result == MAP_FAILED)
	return 0;
    * (size_t *) result = size;
    return(result + sizeof(size_t));
}
Quoted 2 lines · William Lee Irwin III

This looks like a very bad idea. Userspace allocators should make some attempt at avoiding diving into the kernel at every allocation like this.

Sorry, I also forgot the rather severe internal fragmentation this is likely to suffer due to page-level restrictions on mmap's operation.

Cheers,
Bill

#4 lore raw
Quoted 14 lines · William Lee Irwin III
Quoted 4 lines · Erik Andersen
Quoted 4 lines

void *malloc(size_t size)

{
    void *result;
    if (size == 0)
Quoted 8 lines
Quoted 8 lines
	return NULL;
    result = mmap((void *) 0, size + sizeof(size_t), PROT_READ | PROT_WRITE, 
	    MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
    if (result == MAP_FAILED)
	return 0;
    * (size_t *) result = size;
    return(result + sizeof(size_t));
}
Quoted 6 lines
Quoted 2 lines · William Lee Irwin III

This looks like a very bad idea. Userspace allocators should make some attempt at avoiding diving into the kernel at every allocation like this.

Sorry, I also forgot the rather severe internal fragmentation this is likely to suffer due to page-level restrictions on mmap's operation.

Of course. No question there -- actually using such an allocator (with a standard linux kernel) would be a terrible idea. I was merely providing a trivial answer to his question on how to use mmap to allocate memory.

-Erik

--
Erik B. Andersen http://codepoet-consulting.com/
--This message was written using 73% post-consumer electrons--

#5 lore raw
In reply to Timo Benk

Why don't you just exec a process?

Quoted 22 lines · Timo Benk

Hi,

I am a kernel newbie and i am writing a module. I need to allocate some memory in userspace because i want to access syscalls like open(), lstat() etc. I need to call these methods in the kernel, and in my special case there is no other way, but i do not want to reimplement all the syscalls.

I read that it should be possible, but i cannot find any example or recipe on how to do it. It should work with do_mmap() and fd=-1 and MAP_ANON, but i jusst can't get it to work.

Do you now any working example, or a good reference for the do_mmap() call?

Thanks in advance,

-timo

author
#6 lore raw

Re: allocate memory in userspace (Answer)

In reply to Timo Benk

Hi,

I found the following function in arch/i386/kernel/sys_i386.c:

---<snip>---
/* common code for old and new mmaps */
long do_mmap2
(
unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
unsigned long fd, unsigned long pgoff
)

{
	int error = -EBADF;
	struct file * file = NULL;

	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
	if (!(flags & MAP_ANONYMOUS)) {
		file = fget(fd);
		if (!file)
			goto out;
	}

	down_write(&current->mm->mmap_sem);
	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
	up_write(&current->mm->mmap_sem);

	if (file)
		fput(file);
out:
	return error;
}

---<snap>---

the following code works for me(of course
don't forget to munmap the memory).
---<snip>---

	char *userspace;
	char kernelspace[2048];

	userspace = (char*)do_mmap2
			(
				0, 
				2048, 
				PROT_READ|PROT_WRITE, 
				MAP_PRIVATE|MAP_ANON, 
				-1, 
				0
			);
			
	copy_to_user( userspace, "/dev/hda", 9 );
	
	copy_from_user( kernelspace, userspace, 9 );
	printk("%s\n",kernelspace);

---<snap>---

Hope that helps any other struggling newbie:-)

-timo

Signature · 1 line
gpg key fingerprint = 6832 C8EC D823 4059 0CD1  6FBF 9383 7DBD 109E 98DC
author
#7 lore raw

Re: allocate memory in userspace (Answer)

As stated by Andy Kleen this is not a good solution. This is his post to the topic:

----<snip>----

Quoted 9 lines

I am a kernel newbie and i am writing a module. I need to allocate some memory in userspace because i want to access syscalls like open(), lstat() etc. I need to call these methods in the kernel, and in my special case there is no other way, but i do not want to reimplement all the syscalls.

I read that it should be possible, but i cannot find any example or recipe on how to do it.

mm_segment_t oldfs = get_fs();
set_fs(KERNEL_DS);
ret = sys_yoursyscall(kernelargs ...)
set_fs(oldfs);

Do not even think about using mmap or accessing sys_call_table for this. Your other post was so tasteless that it would be good if you retracted it with a followup because it would be very bad to have such an bad example
in the l-k archives open to innocent search machine users uncommented.

-Andi
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
----<snap>-----

Quoted 63 lines · Timo Benk

Hi,

I found the following function in arch/i386/kernel/sys_i386.c:

---<snip>---
/* common code for old and new mmaps */
long do_mmap2
(
unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
unsigned long fd, unsigned long pgoff
)

{
	int error = -EBADF;
	struct file * file = NULL;

	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
	if (!(flags & MAP_ANONYMOUS)) {
		file = fget(fd);
		if (!file)
			goto out;
	}

	down_write(&current->mm->mmap_sem);
	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
	up_write(&current->mm->mmap_sem);

	if (file)
		fput(file);
out:
	return error;
}

---<snap>---

the following code works for me(of course don't forget to munmap the memory). ---<snip>---

	char *userspace;
	char kernelspace[2048];

	userspace = (char*)do_mmap2
			(
				0, 
				2048, 
				PROT_READ|PROT_WRITE, 
				MAP_PRIVATE|MAP_ANON, 
				-1, 
				0
			);
			
	copy_to_user( userspace, "/dev/hda", 9 );
	
	copy_from_user( kernelspace, userspace, 9 );
	printk("%s\n",kernelspace);

---<snap>---

Hope that helps any other struggling newbie:-)

-timo

Signature · 1 line
gpg key fingerprint = 6832 C8EC D823 4059 0CD1  6FBF 9383 7DBD 109E 98DC
Signature · 1 line
gpg key fingerprint = 6832 C8EC D823 4059 0CD1  6FBF 9383 7DBD 109E 98DC
#8 lore raw
In reply to Timo Benk
Quoted 6 lines · Timo Benk

Hi,

I am a kernel newbie and i am writing a module. I need to allocate some memory in userspace because i want to access syscalls like open(), lstat() etc.
I need to call these methods in the kernel, and in
my special case there is no other way, but i do not want to reimplement all the syscalls.

What are you trying to do with this module? If you are needing to use syscalls like open(), you are probably trying to do something that is forbidden in kernel space. For example, trying to read a configuration file.

Recommended reading:
http://www.linux.org.uk/~ajh/ols2002_proceedings.pdf.gz
The chapter named "How NOT to write kernel drivers", especially sections 7 and 8.

--
Brian Gerst