2002-07-01 17:24:44

by Timo Benk

[permalink] [raw]
Subject: allocate memory in userspace

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

--
gpg key fingerprint = 6832 C8EC D823 4059 0CD1 6FBF 9383 7DBD 109E 98DC


2002-07-01 17:47:14

by Erik Andersen

[permalink] [raw]
Subject: Re: allocate memory in userspace

On Mon Jul 01, 2002 at 07:26:59PM +0200, Timo Benk wrote:
> 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()

> 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--

2002-07-01 18:37:27

by Calin A. Culianu

[permalink] [raw]
Subject: Re: allocate memory in userspace


Why don't you just exec a process?

On Mon, 1 Jul 2002, Timo Benk wrote:

> 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
>
>

2002-07-02 07:48:58

by Timo Benk

[permalink] [raw]
Subject: Re: allocate memory in userspace (Answer)

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

--
gpg key fingerprint = 6832 C8EC D823 4059 0CD1 6FBF 9383 7DBD 109E 98DC

2002-07-02 08:36:11

by William Lee Irwin III

[permalink] [raw]
Subject: Re: allocate memory in userspace

On Mon, Jul 01, 2002 at 11:49:13AM -0600, Erik Andersen wrote:
> 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

2002-07-02 08:42:39

by William Lee Irwin III

[permalink] [raw]
Subject: Re: allocate memory in userspace

On Mon, Jul 01, 2002 at 11:49:13AM -0600, Erik Andersen wrote:
>> 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));
>> }

On Tue, Jul 02, 2002 at 01:37:37AM -0700, William Lee Irwin III wrote:
> 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

2002-07-02 08:57:38

by Erik Andersen

[permalink] [raw]
Subject: Re: allocate memory in userspace

On Tue Jul 02, 2002 at 01:44:18AM -0700, William Lee Irwin III wrote:
> On Mon, Jul 01, 2002 at 11:49:13AM -0600, Erik Andersen wrote:
> >> 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));
> >> }
>
> On Tue, Jul 02, 2002 at 01:37:37AM -0700, William Lee Irwin III wrote:
> > 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--

2002-07-02 09:28:07

by Andi Kleen

[permalink] [raw]
Subject: Re: allocate memory in userspace

Timo Benk <[email protected]> writes:

> 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

2002-07-02 10:22:30

by Timo Benk

[permalink] [raw]
Subject: 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>----
> 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

2002-07-02 10:20:06

by Timo Benk

[permalink] [raw]
Subject: Re: allocate memory in userspace

On Tue, Jul 02, 2002 at 11:30:34AM +0200, Andi Kleen wrote:
> Timo Benk <[email protected]> writes:
>
> > 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);
Thank you very much for that hint.

> 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.
I will post a followup, but please tell me
a) a good doc for that topic where i can read why it is so bad
b) a reference for the do_mmap call

While searching through the ng archives i just found (lots of) hints
that this can be done with mmap, so that was my approach to solve
the problem.

Maybe it will be better that you (or any other) will comment what
is so bad, as i told in my first post i am a newbie, so please keep
that in mind.

-timo

--
gpg key fingerprint = 6832 C8EC D823 4059 0CD1 6FBF 9383 7DBD 109E 98DC

2002-07-02 12:22:13

by Brian Gerst

[permalink] [raw]
Subject: Re: allocate memory in userspace

Timo Benk wrote:
> 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