Bug 12155 - MALLOC_MMAP_THRESHOLD_ and MALLOC_MMAP_MAX_ have different effect for setgid than for setuid programs
Summary: MALLOC_MMAP_THRESHOLD_ and MALLOC_MMAP_MAX_ have different effect for setgid ...
Status: RESOLVED INVALID
Alias: None
Product: glibc
Classification: Unclassified
Component: malloc (show other bugs)
Version: 2.12
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-10-23 13:47 UTC by Michael Kerrisk
Modified: 2014-06-30 08:33 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments
test program (727 bytes, text/plain)
2010-10-23 13:49 UTC, Michael Kerrisk
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Michael Kerrisk 2010-10-23 13:47:41 UTC
Almost all of the the MALLOC_*_ environment variables that affect malloc() etc. are disabled (reasonably, for security) in set-user-ID and set-group-ID programs. However, while MALLOC_MMAP_THRESHOLD_ and MALLOC_MMAP_MAX_ are disabled for set-user-ID programs, they DO have an effect for set-group-ID programs. I have inspected the glibc source, and can't see why these variables have an effect in set-group-ID programs, but my text programs show that they do have an effect.
Comment 1 Michael Kerrisk 2010-10-23 13:49:26 UTC
Created attachment 5081 [details]
test program
Comment 2 Michael Kerrisk 2010-10-23 14:02:05 UTC
Initial runs of test program as normal user. Grepping the strace output of the second run shows that MALLOC_MMAP_THRESHOLD_ has an effect.

==
$ strace -o o ./t_M_MMAP_THRESHOLD -1 -1 0 1000 100000
$ grep brk o | wc; grep mmap o| wc
    503    1509   26156
      7      56     612
$ MALLOC_MMAP_THRESHOLD_=50000 strace -o o ./t_M_MMAP_THRESHOLD -1 -1 0 1000 100000
$ grep brk o | wc; grep mmap o| wc      3       9     156
   1006    8048   89523
==

Now, run the program first as setuid-root, and then as setgid-root. In the first case, MALLOC_MMAP_THRESHOLD_ has no effect, but in the second, MALLOC_MMAP_THRESHOLD_ does have an effect.

==
$ sudo chown root:root t_M_MMAP_THRESHOLD

$ sudo chmod u+s,g-s t_M_MMAP_THRESHOLD
$ ls -l t_M_MMAP_THRESHOLD
-rwsr-xr-x 1 root root 10126 Oct 23 15:32 t_M_MMAP_THRESHOLD

$ MALLOC_MMAP_THRESHOLD_=50000 strace -o o ./t_M_MMAP_THRESHOLD -1 -1 0 1000 100000
$ grep brk o | wc; grep mmap o| wc
    503    1509   26156
      7      56     612

$ sudo chmod u-s,g+s t_M_MMAP_THRESHOLD
$ ls -l t_M_MMAP_THRESHOLD
-rwxr-sr-x 1 root root 10126 Oct 23 15:32 t_M_MMAP_THRESHOLD

$ MALLOC_MMAP_THRESHOLD_=50000 strace -o o ./t_M_MMAP_THRESHOLD -1 -1 0 1000 100000
$ grep brk o | wc; grep mmap o| wc
      3       9     156
   1006    8048   89523
==
Comment 3 Ulrich Drepper 2010-10-23 14:54:04 UTC
And what is the issue?  Don't you have anything better to do than complain about completely irrelevant things?
Comment 4 Michael Kerrisk 2010-10-24 05:19:17 UTC
(In reply to comment #3)
> And what is the issue?  Don't you have anything better to do than complain
> about completely irrelevant things?

This is not a complaint. It's a bug report. Do you really have no better mode of response than this?

The issue is twofold:

1. Consistency: in almost all cases, the MALLOC_*_ environment variables are ignored in setuid and setgid programs. The inconsistency noted in this report could lead to unexpected behavior (bugs).

2. Security: if the MALLOC_*_ environment variables are disabled for security reasons, and in particular MALLOC_MMAP_*_ are disabled for setuid programs, the security risk must be similar for setgid programs. In other words, either

a) there is a security problem and these variables should be disabled for both setuid and setgid programs, or 

b) there is no security problem and they should be enabled for both setuid and setgid programs.
Comment 5 Eero Tamminen 2011-07-30 16:28:43 UTC
After quick glimpse at the (v2.11) malloc.c, the effect of these variables is:

* MALLOC_MMAP_MAX_ : how many simultenous mmap() requests glibc allocator can do before falling back to heap (or asserting?)

* MALLOC_MMAP_THRESHOLD_ : which sized allocs will use mmap() instead of heap

I.e. these affect only to what size program's heap may grow and how many mmap()s the program causes with its allocations.

The threshold value can be only between 4KB and:
--------
#ifndef DEFAULT_MMAP_THRESHOLD_MAX
  /* For 32-bit platforms we cannot increase the maximum mmap
     threshold much because it is also the minimum value for the
     maximum heap size and its alignment.  Going above 512k (i.e., 1M
     for new heaps) wastes too much address space.  */
# if __WORDSIZE == 32
#  define DEFAULT_MMAP_THRESHOLD_MAX (512 * 1024)
# else
#  define DEFAULT_MMAP_THRESHOLD_MAX (4 * 1024 * 1024 * sizeof(long))
# endif
#endif
--------

Only issue that I could think with these is that program can use a lot more memory and/or be slower.  If it does enough allocs and mmap threshold is set to 4kB, app might crash due to running out of address space, but I think that's all.  But if user is able to run the program to set its environment variables, he's able to kill it directly too.  And slowdown can be gotten by running other programs.

With this one may be able to trigger allocation failure earlier.  If program doesn't handle allocation failures properly (AFAIK e.g. Glib & Qt by default abort on them), its memory may get corrupted.  However, you can get this simpler just by lowering resource limits lower before running the program.

As a conclusion, I don't see this as a security issue, but consistency one.
Comment 6 Ondrej Bilka 2013-10-31 14:42:09 UTC
Weird as these variables are handled by malloc/arena.c:

 if (! __builtin_expect (__libc_enable_secure, 0))
                {
                  if (memcmp (envline, "TRIM_THRESHOLD_", 15) == 0)
                    __libc_mallopt(M_TRIM_THRESHOLD, atoi(&envline[16]));
                  else if (memcmp (envline, "MMAP_THRESHOLD_", 15) == 0)
                    __libc_mallopt(M_MMAP_THRESHOLD, atoi(&envline[16]));
                }

and __libc_enable_secure is defined as

  if (__libc_enable_secure_decided == 0)
    __libc_enable_secure = (__geteuid () != __getuid ()
                            || __getegid () != __getgid ());

A simple program shows that this is enabled in both cases.

extern int __libc_enable_secure;
int main ()
{
  printf ("%i %i %i %i", getuid(), geteuid(), getgid(), getegid());
  printf (" %i", __libc_enable_secure);
}
Comment 7 Florian Weimer 2014-06-30 07:22:48 UTC
The strace invocation looks suspicious.  Ptracing a process will inhibit the SUID/SGID transition, particularly if run as an unprivileged user, as the $ prompt suggests.  Michael, are you sure you are running strace in the right way?
Comment 8 Michael Kerrisk 2014-06-30 08:32:06 UTC
(In reply to Florian Weimer from comment #7)
> The strace invocation looks suspicious.  Ptracing a process will inhibit the
> SUID/SGID transition, particularly if run as an unprivileged user, as the $
> prompt suggests.  Michael, are you sure you are running strace in the right
> way?

Ach! You're exactly right. I completely overlooked this strace(1) behavior. Running my program under strace(1) the right way:

$ MALLOC_MMAP_THRESHOLD_=50000 sudo strace -u mtk -o o ./t_M_MMAP_THRESHOLD -1 -1 0 1000 100000
$ grep brk o | wc; grep mmap o| wc
   1002    3006   52104
      9      72     862

In other words, MALLOC_MMAP_THRESHOLD_ has no effect, as it should.

Thanks for educating me, Florian.
Comment 9 Michael Kerrisk 2014-06-30 08:33:15 UTC
As realized by Florian, my testing was bogus. Move along folks, there's no bug to see here.