Introduction

Problem description:

Linux kernel binfmt_script handling in
combination with CONFIG_MODULES can lead to disclosure of kernel
stack data during execve via copy of data from dangling pointer to stack
to growing argv list. Apart from that, the
BINPRM_MAX_RECURSION can be exceeded: the maximum of 4 recursions
is ignored, instead a maximum of roughly 2^6 recursions is in place.

Method

Execution of a sequence of crafted scripts causes
bprm->interp pointer to be set to data within current
stack frame. When frame is left, data at location of dangling pointer
can be overwritten before it is added to argv-list in next run
and then exported to userspace.

Results, Discussion

The overwrite is triggered when executables with special names
handled by binfmt_script call each other until BINPRM_MAX_RECURSION
is reached. During each round, load_script from
fs/binfmt_script.c extracts the interpreter name for the
next round and stores it within the current stack frame. The pointer
to this name is also copied to bprm->interp and used during
execution of the next interpreter (also a script) within
search_binary_handler function. This is not problematic
unless CONFIG_MODULES is also defined. When
BINPRM_MAX_RECURSION is reached, load_script returns,
thus leaving bprm->interp pointing to a now non-existing
stack frame. Due to CONFIG_MODULES and the special interpreter
name, search_binary_handler will trigger request for
loading of module via request_module and invoke
load_script again. The function will then append the data
from dangling pointer bprm->interp to exec args, thus
disclosing some kernel stack bytes. Output on 64-bit system
might contain:

Apart from memory disclosure, reaching BINPRM_MAX_RECURSION
will not terminate execve call with error, but invocation of
load_script is triggered more than the intended maximum
of loader invocations, leading to higher CPU consumption from
single call to execve.

Impact:

Impact is low, since exploitation would need
local code execution anyway. Only disclosure of kernel addresses
when System.map is not readable seems interesting. The increased
CPU load itself could be deemed unproblematic, an attacker in
the same position but without this POC would need to fork more
processes instead to get same load, which is quite feasable in
most situations.

Affected versions:

Not clear right now, bug might have been
introduced recently.

Ubuntu Oneiric i386 kernel (3.0.0-24-generic): Not affected, test
script does not cause excessive recursion. Not clear if bug could
be triggered using other conditions.

Further analysis:

It seems, that this scheme with only
binfmt_elf and binfmt_script cannot lead to kernel OOPS or problematic
stack writes. It could be investigated, if additional modules, e.g.
binfmt_misc could open such a hole.