Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
Bug 164656 - sandbox: use own malloc
Summary: sandbox: use own malloc
Status: RESOLVED FIXED
Alias: None
Product: Portage Development
Classification: Unclassified
Component: Sandbox (show other bugs)
Hardware: All Linux
: High normal (vote)
Assignee: Sandbox Maintainers
URL:
Whiteboard:
Keywords:
Depends on:
Blocks: 161041
  Show dependency tree
 
Reported: 2007-01-31 05:59 UTC by Ed Catmur
Modified: 2008-11-09 17:03 UTC (History)
1 user (show)

See Also:
Package list:
Runtime testing required: ---


Attachments
sandbox-use-own-malloc.patch (sandbox-use-own-malloc.patch,2.33 KB, patch)
2007-01-31 06:00 UTC, Ed Catmur
Details | Diff
sandbox-use-own-malloc.patch (sandbox-use-own-malloc.patch,2.61 KB, patch)
2007-03-18 19:13 UTC, Ed Catmur
Details | Diff
malloc.c (malloc.c,1.13 KB, text/plain)
2007-03-18 22:16 UTC, SpanKY
Details
minimal-malloc.patch (minimal-malloc.patch,2.12 KB, patch)
2007-06-24 18:50 UTC, Ed Catmur
Details | Diff
minimal-malloc.patch (minimal-malloc.patch,4.46 KB, patch)
2007-10-06 23:58 UTC, Ed Catmur
Details | Diff
minimal-malloc.patch (minimal-malloc.patch,4.45 KB, patch)
2007-10-07 17:54 UTC, Ed Catmur
Details | Diff
minimal-malloc.patch (minimal-malloc.patch,5.07 KB, patch)
2007-10-21 21:59 UTC, Ed Catmur
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Ed Catmur 2007-01-31 05:59:08 UTC
Sandbox failures bug 161045 and bug 131505 are down to Lisps providing their own malloc, which sandbox ends up calling when setting up env vars etc, but doesn't behave exactly like a standard malloc should.

The solution is obvious if you're insane: we should provide our own malloc.  The easiest way to do this is to take a malloc (e.g. ptmalloc3) that we can limit to mmap (no morecore/sbrk), link in to the sandbox sofile, and make sure that all allocation functions (strdup etc.) call our malloc.

Crazy, but it works; I'll attach the POC patch (against 1.2.18.1), confirmed to work with both gcl and emacs-cvs.
Comment 1 Ed Catmur 2007-01-31 06:00:49 UTC
Created attachment 108718 [details, diff]
sandbox-use-own-malloc.patch

Against 1.2.18.1; unpack http://www.malloc.de/malloc/ptmalloc3-current.tar.gz into src/.
Comment 2 SpanKY gentoo-dev 2007-01-31 06:06:19 UTC
erm, that's really a path to pain ...

why not lookup malloc in the libc library like we do with the other functions and call that
Comment 3 Ed Catmur 2007-01-31 06:31:44 UTC
Because there can only be one malloc using the heap.  If you have more than one malloc calling sbrk() then one or both will get very confused.
Comment 4 SpanKY gentoo-dev 2007-01-31 07:19:17 UTC
you mean the lisp is using sbrk so that would cause us troubles when the glibc malloc attempts to use sbrk

how exactly does the lisp malloc differ ?  perhaps changing those would be an option

i really really really want to avoid what you're proposing here simply because it can easily be a maintenance nightmare
Comment 5 Ed Catmur 2007-02-01 14:20:47 UTC
(In reply to comment #4)
> you mean the lisp is using sbrk so that would cause us troubles when the glibc
> malloc attempts to use sbrk
Yeah, the lisp malloc assumes that it owns the whole heap and is the only one calling sbrk.

> how exactly does the lisp malloc differ ?  perhaps changing those would be an
> option
It's like nothing I've seen anywhere else.  It's heavily integrated with lisp gc (which happily relocates objects) and with the GCL serialization-through-memory-dump (si::save-system).  I've tried tinkering with various bits but getting something that works and doesn't break assumptions elsewhere is beyond me.  And, of course, it's completely undocumented.

> i really really really want to avoid what you're proposing here simply because
> it can easily be a maintenance nightmare
Will it, though?  Sandbox is constrained to using a minimal subset of the C library, and there really isn't that much that does memory allocation:
- malloc/calloc/realloc/free: done or easily implementable
- getcwd(NULL, ...): non-POSIX, avoidable
- realpath(..., NULL): non-POSIX, avoidable
- strdup: implemented in patch
- tempnam: highly deprecated
Comment 6 SpanKY gentoo-dev 2007-02-01 21:49:53 UTC
you feel like porting and validating this custom malloc to every architecture/OS we support ?  i dont

what i meant by "how does it differ" is "why is it actually causing crashes" ?  if all the lisp malloc is doing is allocating memory and giving us a pointer to it, why is it crashing ?  glibc is designed to allow custom memory allocators take over the symbols at runtime
Comment 7 Ed Catmur 2007-02-02 23:46:28 UTC
(In reply to comment #6)
> you feel like porting and validating this custom malloc to every
> architecture/OS we support ?  i dont
That's why I'm suggesting using ptmalloc; it's the standard malloc, everyone uses it.

> what i meant by "how does it differ" is "why is it actually causing crashes" ? 
> if all the lisp malloc is doing is allocating memory and giving us a pointer to
> it, why is it crashing ?  glibc is designed to allow custom memory allocators
> take over the symbols at runtime
It's giving us a pointer to memory past the top of the heap.

The reason this happens: the backtrace has

#4  0x08088ac2 in unexec (
    new_name=0x9001000 <Address 0x9001000 out of bounds>, 
    old_name=0x1003 <Address 0x1003 out of bounds>, data_start=1073902592, 
    bss_start=0, entry_address=0) at unexelf.c:672
#5  0x08089d3e in Lsave () at save.c:12
#6  0x0805293d in siLsave_system () at main.c:977

In siLsave_system() GCL gcs and compacts (relocating) the heap down, then uses brk() to shrink it to the actually used region.  It then calls Lsave() which is supposed to dump the data segment into a file, then grows the heap back up to give room to allocate from.
The problem is that sandbox calls malloc repeatedly inside Lsave(); as a result GCL's malloc gets very confused (nothing is supposed to be calling malloc at this point, because it's saving the data segment) and returns a pointer past the (temporarily lowered) top of the heap.

I don't see how this is fixable, bar severely modifying gcl; gcl's malloc is not designed to be called within Lsave().
Comment 8 SpanKY gentoo-dev 2007-03-12 20:21:09 UTC
your patch there doesnt actually include any source code ...

however, a trivial implementation of malloc() would be to simply call anonymous mmap()'s ... and then free() would simply be munmap() ... that would be completely portable
Comment 9 Ed Catmur 2007-03-18 19:13:55 UTC
Created attachment 113681 [details, diff]
sandbox-use-own-malloc.patch

(In reply to comment #8)
> your patch there doesnt actually include any source code ...
It uses ptmalloc3 from the tarball (i.e. just add ptmalloc3-current.tar.gz to SRC_URI, apply the patch, run eautoreconf).  It finds ptmalloc via ptmalloc_srcdir=$(top_srcdir)/../ptmalloc3.  I forgot to put up the more recent version of the patch, sorry.

The ebuild is in my tree, of course.
Comment 10 Ed Catmur 2007-03-18 20:20:54 UTC
(In reply to comment #8)
> however, a trivial implementation of malloc() would be to simply call anonymous
> mmap()'s ... and then free() would simply be munmap() ... that would be
> completely portable
Well, that is effectively what we have compiling ptmalloc to use mmap.
Do you mean providing our own implementations of the malloc/calloc/realloc/free symbols for resolution within libsandbox, or replacing calls with mmap/munmap?  I'm prepared to implement either if it'd get accepted, but I'd prefer to know what you think would work.
Comment 11 SpanKY gentoo-dev 2007-03-18 22:03:51 UTC
i really dont know what "ptmalloc" is since your patch didnt include the ebuild patch

assuming you mean http://www.malloc.de/, that's way over the top for what i would want to include

replacing with mmap/munmap is quite trivial:
void *malloc(size_t size) 
{
    size_t *ret;
    size += sizeof(size_t);
    ret = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
    if (ret == MAP_FAILED) 
        return NULL;
    *ret = size;
    return ret+1;
}
void free(void *ptr)
{
    size_t *mmap_start, size; 
    if (ptr == NULL)
        return;
    mmap_start = ((size_t*)ptr) - 1;
    size = *mmap_start;
    munmap(mmap_start, size);
}
Comment 12 SpanKY gentoo-dev 2007-03-18 22:16:42 UTC
Created attachment 113720 [details]
malloc.c
Comment 13 SpanKY gentoo-dev 2007-03-24 08:37:55 UTC
due to the obvious performance degradation versus the glibc malloc, i'm not sure we want to have this enabled for everyone all the time ...

perhaps in sandbox startup we would do:
 - grab malloc symbols from libc.so.6
 - grab malloc symbols from normal resolving
 - if they are different, have sandbox use internal malloc symbols

or we could just have the behavior depend on an env var that broken packages would need to export: SANDBOX_LOCAL_MALLOC=1
Comment 14 SpanKY gentoo-dev 2007-04-11 23:14:01 UTC
actually, that has a subtle buffer overflow when using realloc() to shrink a buffer ... the memcpy() needs to read:
memcpy(ret, ptr, (size < old_malloc_size ? size : old_malloc_size));

otherwise, if this solves your problems with the test case packages, i have no problem merging this version
Comment 15 Ed Catmur 2007-06-24 18:50:58 UTC
Created attachment 122973 [details, diff]
minimal-malloc.patch

Sorry, been busy for a while.  Here's a patch with your mmalloc.c, with strdup added and improved NULL handling, plus src/Makefile.am change.  I've been using this for a while with no issues.

As for performance degradation, I'm not so sure that there is much of an issue here.  Obviously there will be some degradation on startup/init, but if we're doing malloc at syscall time then that's going to be slow anyway.
Comment 16 SpanKY gentoo-dev 2007-06-24 18:56:13 UTC
sure there's a performance difference ... this simple malloc has an exact 1-to-1 correlation between malloc() and having to do a system call

the glibc malloc is able to satisfy smaller requests from its own managed heap without having to enter kernel space

but unless someone does some actual profiling, i dont think it'll be a big deal for the majority of our users
Comment 17 Ed Catmur 2007-10-06 23:58:08 UTC
Created attachment 132779 [details, diff]
minimal-malloc.patch

Updated, respects SANDBOX_LOCAL_MALLOC env flag and fixes a strdup bug.
Comment 18 SpanKY gentoo-dev 2007-10-07 03:23:16 UTC
you can just do 'return memcpy(...)' in strdup()
Comment 19 Ed Catmur 2007-10-07 17:54:12 UTC
Created attachment 132845 [details, diff]
minimal-malloc.patch

Yup.
Comment 20 Ed Catmur 2007-10-21 21:59:36 UTC
Created attachment 134085 [details, diff]
minimal-malloc.patch

Was having issues calling getenv from free at process exit.  This checks it once only.
Comment 21 SpanKY gentoo-dev 2008-11-09 12:27:48 UTC
ive committed this stuff to svn ... but ive always enabled it.  this is because the number of allocations actually done by libsandbox is relatively small, so the perf penality is negligible i think.

it also simplifies the code and keeps us from having to worry about tracking two distinctive code paths and maintainers having to track down random crashes ... things "just work" for them
Comment 22 Ulrich Müller gentoo-dev 2008-11-09 13:37:53 UTC
NB, this will not help for Emacs. The reason that we disable the sandbox there is a different one: Emacs dumps its executable, and we don't want any sandbox code included with its final binary. See bug 233 and bug 131505 for further details.
Comment 23 SpanKY gentoo-dev 2008-11-09 14:41:49 UTC
the pkg that prompted this was gcl, not emacs.  i know emacs has a retarded build system and i really dont plan on trying to "fix" it.
Comment 24 Ulrich Müller gentoo-dev 2008-11-09 17:03:16 UTC
> the pkg that prompted this was gcl, not emacs.

Yes, but comment #0 also mentions emacs-cvs.