Bug 194809 - [PATCH] binfmts.h MAX_ARG_STRINGS excessive value allows heap spraying
Summary: [PATCH] binfmts.h MAX_ARG_STRINGS excessive value allows heap spraying
Status: NEW
Alias: None
Product: Other
Classification: Unclassified
Component: Other (show other bugs)
Hardware: All Linux
: P1 normal
Assignee: other_other
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-03-07 14:39 UTC by Leonard den Ottolander
Modified: 2017-03-09 14:52 UTC (History)
0 users

See Also:
Kernel Version: 4.10.1 and below
Subsystem:
Regression: No
Bisected commit-id:


Attachments
set MAX_ARG_STRINGS to 4096 to avoid heap spraying (417 bytes, patch)
2017-03-07 14:39 UTC, Leonard den Ottolander
Details | Diff
Introduce MAX_ARG_STRSLEN to cap MAX_ARG_STRINGS * MAX_ARG_STRLEN to avoid heap spraying (1.56 KB, patch)
2017-03-09 14:52 UTC, Leonard den Ottolander
Details | Diff

Description Leonard den Ottolander 2017-03-07 14:39:13 UTC
Created attachment 255111 [details]
set MAX_ARG_STRINGS to 4096 to avoid heap spraying

In the article 
https://googleprojectzero.blogspot.nl/2014/08/the-poisoned-nul-byte-2014-edition.html
the author describes launching an attack on an off by one NUL byte bug in glibc.

He explains that both the memory leak in the option parsing of PolKits pkexec.c and the excessive value of MAX_ARG_STRINGS in the kernels include/uapi/linux/binfmts.h (#define MAX_ARG_STRINGS 0x7FFFFFFF) enabled his attack.

The rationale for that excessive value is a bit odd:

"MAX_ARG_STRINGS is chosen to fit in a signed 32-bit integer."

https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/include/uapi/linux/binfmts.h?id=607ca46e97a1b6594b29647d98a32d545c24bdff

The fact that the integer is so large makes that on a 32 bit platform the entire heap can be initialized with values the attacker provides,
given the memory leak in the option parsing of pkexec.c, an approach the author calls "heap spraying".

(Note that two similar memory leaks exist in the option parsing of pkexecs sibling pkcheck.c, so pkcheck will also allow an attacker to
heap spray its entire memory on a 32 bit system.)

If you compare http://www.linuxjournal.com/article/6060 you will see that the TOTAL amount of memory reserved for command line arguments used
to be 32 pages, i.e. 128KiB (#define MAX_ARG_PAGES 32). The amount of memory reserved for command line arguments in more current kernels is
the multiplication of MAX_ARG_STRINGS and MAX_ARG_STRLEN.

Both the memory leaks in pkexec.c and pkcheck.c seem very severe, but their impact would be much less if MAX_ARG_STRINGS would hold a sensible value.

After some experimentation with
$ rpmbuild -ba kernel.spec
on CentOS-7 I've come up with values that allow this kernel compilation.
As this kind of build is probably one of the most demanding actions in relation to MAX_ARG_STRINGS and MAX_ARG_STRLEN I believe below values to be sensible and much safer defaults:

#define MAX_ARG_STRLEN 65536
#define MAX_ARG_STRINGS 4096

allow me to build a kernel on a system using those values.

Since the above value of MAX_ARG_STRLEN is half of the current value we might leave it alone and only alter MAX_ARG_STRINGS. See attached patch.
Comment 1 Leonard den Ottolander 2017-03-09 14:52:36 UTC
Created attachment 255163 [details]
Introduce MAX_ARG_STRSLEN to cap MAX_ARG_STRINGS * MAX_ARG_STRLEN to avoid heap spraying

Consider the original patch an "emergency bandaid". These values allow me to build a kernel, but does not handle directories with more than MAX_ARG_STRINGS.

The problem here is that the multiplier of MAX_ARG_STRINGS and MAX_ARG_STRLEN may not be 2 ^ 32 - stacksize (roughly 4GiB) or heap spraying is possible on 32-bit systems.

Attached patch introduces a new value, MAX_ARG_STRSLEN, along the lines of MAX_ARG_PAGES. Keeping this value (well) below 4GiB and it is now safe to increase both MAX_ARG_STRINGS and MAX_ARG_STRLEN beyond where their multiplier is 2 ^ 32.

Attached patch uses conservative values
#define MAX_ARG_STRSLEN 262144
#define MAX_ARG_STRLEN 65536
#define MAX_ARG_STRINGS 4096

that allow me to build a kernel on CentOS-7.

These values can now be safely increased though if a larger default is required. For example:

#define MAX_ARG_STRSLEN 4194304
#define MAX_ARG_STRLEN 131072
#define MAX_ARG_STRINGS 131072

Note You need to log in before you can comment on or make changes to this bug.