New issue
Advanced search Search tips

Issue 756557 link

Starred by 3 users

Issue metadata

Status: ExternalDependency
Owner:
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Mac
Pri: 2
Type: Bug

Blocking:
issue 756102



Sign in to add a comment

macOS: Local DoS kernel panic from unprivileged, sandboxed process

Project Member Reported by rsesek@chromium.org, Aug 17 2017

Issue description

Splitting off the XNU issue details from  bug 756102  into here to keep the details restricted. I just submitted this report to Apple product security.

Follow-up: 671348000
--------------------

*Summary:*
A local, unprivileged, sandboxed process can trivially cause a local denial
of service/kernel panic by issuing one of several system calls.

*Impact:*
This issue affects macOS 10.11.6, 10.12.6, and 10.13 beta. macOS 10.10.5
and 10.9.5 are not affected. iOS was untested but is likely also affected.

*Root Cause:*
Several Mach traps make a call to waitq_link_reserve(). In 10.12.4
xnu-3789.1.32, this function calls wql_ensure_free_space(), which calls
ltable_grow(). If the waitq link table exceeds its maximum element size,
the system will panic with "No more room to grow table". Because
waitq_link_reserve() is not expected to fail, it is called from trap
handlers without any capacity checks, which means that by issuing a system
call, an unprivileged process can flood the waitq link table and cause a
kernel panic.

Examining xnu-3789.1.32, there are several userspace-accessible traps that
may be vulnerable to this:
- mach_port_allocate for MACH_PORT_RIGHT_PORT_SET
- mach_port_allocate_full for MACH_PORT_RIGHT_PORT_SET
- mach_port_insert_right
- mach_port_move_member
- kevent for EVFILT_MACHPORT
- select

I've attached two small test programs for the port set operations to
demonstrate the problem. Running either on the affected macOS versions will
cause a kernel panic within seconds. This issue is triggerable from within
the confines of the sandbox, including the web process sandboxes used by
Safari and Chrome.

The waitq-link-pset.c program merely allocates port sets in an unbounded
loop, until the waitq link table is exhausted and the system panics. The
waitq-link-pset-insert.c program is more interesting, in that it races
amongst threads the use of mach_port_insert_member(). While
mach_port_insert_member() does call waitq_link_release() at the end of the
routine, other threads (or tasks) may cause the waitq link table to become
exhausted if they are modifying port sets concurrently.

Note that the above is not an exhaustive list of calls to
waitq_link_reserve(), and others within xnu should be evaluated.

*Remediation:*
At minimum, the waitq_link_reserve() function should be able to return an
error if a link reservation fails, rather than causing a panic. This would
allow system call handlers to report up KERN_RESOURCE_SHORTAGE in this
scenario. If waitq-link-pset.c is run on macOS 10.10, for example,
KERN_NO_SPACE is returned.

More broadly, the introduction of this system-wide limit on waitq links
effectively puts a cap on the number of port sets that may be allocated
within the system. Even if waitq_link_reserve() were to return an error
when the link table is full, an unprivileged process would still be able to
cause denial-of-service to other privileged processes by preventing the
creation of new waitq links (e.g., port sets, kevents, etc.). Prior to the
introduction of the waitq link table in macOS 10.11, the limit on port sets
was a per-task resource.

*Comments:*
For port sets, the system-wide limit of 262142 is too low. This issue was
discovered because the kernel panic was reported by users who were
experiencing it on systems with moderate-to-heavy process usage. If
possible, it would be best to remove the system-wide limit on port sets and
restore the previous behavior in which they were a per-task resource. We
have observed both the mach_port_insert_member() race and the
mach_port_allocate() exhaustion in reports from users.

*Disclosure deadline:*
This bug is subject to a 90 day disclosure deadline. If 90 days elapse
without a broadly available patch, then the bug report will automatically
become visible to the public.
 
Kernel_2017-08-17-185745_Ten-Twelve-VM.panic
5.0 KB Download
Kernel_2017-08-17-190120_Ten-Twelve-VM.panic
5.2 KB Download
waitq-link-pset.c
515 bytes View Download
waitq-link-pset-insert.c
1.6 KB View Download

Comment 1 by rsesek@chromium.org, Aug 17 2017

The two kernel panics symbolize to:

panic (in kernel) (debug.c:461)
ltable_alloc_elem (in kernel) (ltable.c:462)
waitq_link_reserve (in kernel) (waitq.c:3620)
ipc_pset_alloc (in kernel) (ipc_pset.c:111)
mach_port_allocate_full (in kernel) (mach_port.c:715)
_kernelrpc_mach_port_allocate_trap (in kernel) (mach_kernelrpc.c:161)
mach_call_munger64 (in kernel) (bsd_i386.c:556)
hndl_mach_scall64 (in kernel) + 22

And:

ltable_alloc_elem (in kernel) (ltable.c:462)
waitq_link_reserve (in kernel) (waitq.c:3620)
mach_port_insert_member (in kernel) (mach_port.c:2045)
_kernelrpc_mach_port_insert_member_trap (in kernel) (mach_kernelrpc.c:280)
mach_call_munger64 (in kernel) (bsd_i386.c:556)
hndl_mach_scall64 (in kernel) + 22

Comment 2 by rsesek@chromium.org, Aug 28 2017

Labels: -Restrict-View-SecurityTeam
NextAction: ----
Lifting the view restriction.

On Tue, Aug 22, 2017 at 5:08 PM, product-security wrote:
> Hello Robert,
>
> After further examining your report we do not see any actual security implications. We have forwarded your report to the appropriate team to address the issue.
>
> If you have any questions or concerns please feel free to let us know.
This appears to be fixed on 10.14 beta 4 18A336e.
Spoke a bit too soon. waitq-link-pset.c no longer panics, but waitq-link-pset-insert.c still does.

Sign in to add a comment