1 /*
2 * Copyright 2014-2015 iXsystems, Inc.
3 * All rights reserved
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted providing that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
23 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 *
26 */
27
28 #include <sys/types.h>
29 #include <sys/errno.h>
30 #include <sys/sbuf.h>
31 #include <mach/mach.h>
32 #include <xpc/launchd.h>
33 #include <machine/atomic.h>
34 #include <assert.h>
35 #include <syslog.h>
36 #include <stdarg.h>
37 #include <uuid.h>
38
39 #include "xpc_internal.h"
40
41 #define MAX_RECV 8192
42 #define XPC_RECV_SIZE \
43 MAX_RECV - \
44 sizeof(mach_msg_header_t) - \
45 sizeof(mach_msg_trailer_t) - \
46 sizeof(uint64_t) - \
47 sizeof(size_t)
48
49 struct xpc_message {
50 mach_msg_header_t header;
51 size_t size;
52 uint64_t id;
53 char data[0];
54 mach_msg_trailer_t trailer;
55 };
56
57 struct xpc_recv_message {
58 mach_msg_header_t header;
59 size_t size;
60 uint64_t id;
61 char data[XPC_RECV_SIZE];
62 mach_msg_trailer_t trailer;
63 };
64
65 static void xpc_copy_description_level(xpc_object_t obj, struct sbuf *sbuf,
66 int level);
67
68 void
fail_log(const char * exp)69 fail_log(const char *exp)
70 {
71 syslog(LOG_ERR, "%s", exp);
72 //sleep(1);
73 printf("%s", exp);
74 //abort();
75 }
76
77 static void nvlist_add_prim(nvlist_t *nv, const char *key, xpc_object_t xobj);
78
79 static void
xpc_dictionary_destroy(struct xpc_object * dict)80 xpc_dictionary_destroy(struct xpc_object *dict)
81 {
82 struct xpc_dict_head *head;
83 struct xpc_dict_pair *p, *ptmp;
84
85 head = &dict->xo_dict;
86
87 TAILQ_FOREACH_SAFE(p, head, xo_link, ptmp) {
88 TAILQ_REMOVE(head, p, xo_link);
89 xpc_object_destroy(p->value);
90 free(p);
91 }
92 }
93
94 static void
xpc_array_destroy(struct xpc_object * dict)95 xpc_array_destroy(struct xpc_object *dict)
96 {
97 struct xpc_object *p, *ptmp;
98 struct xpc_array_head *head;
99
100 head = &dict->xo_array;
101
102 TAILQ_FOREACH_SAFE(p, head, xo_link, ptmp) {
103 TAILQ_REMOVE(head, p, xo_link);
104 xpc_object_destroy(p);
105 }
106 }
107
108 static int
xpc_pack(struct xpc_object * xo,void * buf,size_t * size)109 xpc_pack(struct xpc_object *xo, void *buf, size_t *size)
110 {
111 nvlist_t *nv;
112 void *packed;
113
114 nv = xpc2nv(xo);
115
116 packed = nvlist_pack_buffer(nv, NULL, size);
117 if (packed == NULL) {
118 errno = EINVAL;
119 return (-1);
120 }
121
122 memcpy(buf, packed, *size);
123 return (0);
124 }
125
126 static struct xpc_object *
xpc_unpack(void * buf,size_t size)127 xpc_unpack(void *buf, size_t size)
128 {
129 struct xpc_object *xo;
130 nvlist_t *nv;
131
132 nv = nvlist_unpack(buf, size);
133 xo = nv2xpc(nv);
134 return (xo);
135 }
136
137 void
xpc_object_destroy(struct xpc_object * xo)138 xpc_object_destroy(struct xpc_object *xo)
139 {
140 if (xo->xo_xpc_type == _XPC_TYPE_DICTIONARY)
141 xpc_dictionary_destroy(xo);
142
143 if (xo->xo_xpc_type == _XPC_TYPE_ARRAY)
144 xpc_array_destroy(xo);
145
146 free(xo);
147 }
148
149 xpc_object_t
xpc_retain(xpc_object_t obj)150 xpc_retain(xpc_object_t obj)
151 {
152 struct xpc_object *xo;
153
154 xo = obj;
155 atomic_add_int(&xo->xo_refcnt, 1);
156 return (obj);
157 }
158
159 void
xpc_release(xpc_object_t obj)160 xpc_release(xpc_object_t obj)
161 {
162 struct xpc_object *xo;
163
164 xo = obj;
165 if (atomic_fetchadd_int(&xo->xo_refcnt, -1) > 1)
166 return;
167
168 xpc_object_destroy(xo);
169 }
170
171 static const char *xpc_errors[] = {
172 "No Error Found",
173 "No Memory",
174 "Invalid Argument",
175 "No Such Process"
176 };
177
178
179 const char *
xpc_strerror(int error)180 xpc_strerror(int error)
181 {
182
183 if (error > EXMAX || error < 0)
184 return "BAD ERROR";
185 return (xpc_errors[error]);
186 }
187
188 char *
xpc_copy_description(xpc_object_t obj)189 xpc_copy_description(xpc_object_t obj)
190 {
191 char *result;
192 struct sbuf *sbuf;
193
194 sbuf = sbuf_new_auto();
195 xpc_copy_description_level(obj, sbuf, 0);
196 sbuf_finish(sbuf);
197 result = strdup(sbuf_data(sbuf));
198 sbuf_delete(sbuf);
199
200 return (result);
201 }
202
203 static void
xpc_copy_description_level(xpc_object_t obj,struct sbuf * sbuf,int level)204 xpc_copy_description_level(xpc_object_t obj, struct sbuf *sbuf, int level)
205 {
206 struct xpc_object *xo = obj;
207 struct uuid *id;
208 char *uuid_str;
209 uint32_t uuid_status;
210
211 if (obj == NULL) {
212 sbuf_printf(sbuf, "<null value>\n");
213 return;
214 }
215
216 sbuf_printf(sbuf, "(%s) ", _xpc_get_type_name(obj));
217
218 switch (xo->xo_xpc_type) {
219 case _XPC_TYPE_DICTIONARY:
220 sbuf_printf(sbuf, "\n");
221 xpc_dictionary_apply(xo, ^(const char *k, xpc_object_t v) {
222 sbuf_printf(sbuf, "%*s\"%s\": ", level * 4, " ", k);
223 xpc_copy_description_level(v, sbuf, level + 1);
224 return ((bool)true);
225 });
226 break;
227
228 case _XPC_TYPE_ARRAY:
229 sbuf_printf(sbuf, "\n");
230 xpc_array_apply(xo, ^(size_t idx, xpc_object_t v) {
231 sbuf_printf(sbuf, "%*s%ld: ", level * 4, " ", idx);
232 xpc_copy_description_level(v, sbuf, level + 1);
233 return ((bool)true);
234 });
235 break;
236
237 case _XPC_TYPE_BOOL:
238 sbuf_printf(sbuf, "%s\n",
239 xpc_bool_get_value(obj) ? "true" : "false");
240 break;
241
242 case _XPC_TYPE_STRING:
243 sbuf_printf(sbuf, "\"%s\"\n",
244 xpc_string_get_string_ptr(obj));
245 break;
246
247 case _XPC_TYPE_INT64:
248 sbuf_printf(sbuf, "%lld\n",
249 xpc_int64_get_value(obj));
250 break;
251
252 case _XPC_TYPE_UINT64:
253 sbuf_printf(sbuf, "0x%llx\n",
254 xpc_uint64_get_value(obj));
255 break;
256
257 case _XPC_TYPE_DATE:
258 sbuf_printf(sbuf, "%llu\n",
259 xpc_date_get_value(obj));
260 break;
261
262 case _XPC_TYPE_UUID:
263 id = (struct uuid *)xpc_uuid_get_bytes(obj);
264 uuid_to_string(id, &uuid_str, &uuid_status);
265 sbuf_printf(sbuf, "%s\n", uuid_str);
266 free(uuid_str);
267 break;
268
269 case _XPC_TYPE_ENDPOINT:
270 sbuf_printf(sbuf, "<%d>\n", xo->xo_int);
271 break;
272
273 case _XPC_TYPE_NULL:
274 sbuf_printf(sbuf, "<null>\n");
275 break;
276 }
277 }
278
279 struct _launch_data {
280 uint64_t type;
281 union {
282 struct {
283 union {
284 launch_data_t *_array;
285 char *string;
286 void *opaque;
287 int64_t __junk;
288 };
289 union {
290 uint64_t _array_cnt;
291 uint64_t string_len;
292 uint64_t opaque_size;
293 };
294 };
295 int64_t fd;
296 uint64_t mp;
297 uint64_t err;
298 int64_t number;
299 uint64_t boolean; /* We'd use 'bool' but this struct needs to be used under Rosetta, and sizeof(bool) is different between PowerPC and Intel */
300 double float_num;
301 };
302 };
303
304 static uint8_t ld_to_xpc_type[] = {
305 _XPC_TYPE_INVALID,
306 _XPC_TYPE_DICTIONARY,
307 _XPC_TYPE_ARRAY,
308 _XPC_TYPE_FD,
309 _XPC_TYPE_UINT64,
310 _XPC_TYPE_DOUBLE,
311 _XPC_TYPE_BOOL,
312 _XPC_TYPE_STRING,
313 _XPC_TYPE_DATA,
314 _XPC_TYPE_ERROR,
315 _XPC_TYPE_ENDPOINT
316 };
317
318 xpc_object_t
ld2xpc(launch_data_t ld)319 ld2xpc(launch_data_t ld)
320 {
321 struct xpc_object *xo;
322 xpc_u val;
323
324
325 if (ld->type > LAUNCH_DATA_MACHPORT)
326 return (NULL);
327 if (ld->type == LAUNCH_DATA_STRING || ld->type == LAUNCH_DATA_OPAQUE) {
328 val.str = malloc(ld->string_len);
329 memcpy(__DECONST(void *, val.str), ld->string, ld->string_len);
330 xo = _xpc_prim_create(ld_to_xpc_type[ld->type], val, ld->string_len);
331 } else if (ld->type == LAUNCH_DATA_BOOL) {
332 val.b = (bool)ld->boolean;
333 xo = _xpc_prim_create(ld_to_xpc_type[ld->type], val, 0);
334 } else if (ld->type == LAUNCH_DATA_ARRAY) {
335 xo = xpc_array_create(NULL, 0);
336 for (uint64_t i = 0; i < ld->_array_cnt; i++)
337 xpc_array_append_value(xo, ld2xpc(ld->_array[i]));
338 } else {
339 val.ui = ld->mp;
340 xo = _xpc_prim_create(ld_to_xpc_type[ld->type], val, ld->string_len);
341 }
342 return (xo);
343 }
344
345 xpc_object_t
xpc_copy_entitlement_for_token(const char * key __unused,audit_token_t * token __unused)346 xpc_copy_entitlement_for_token(const char *key __unused, audit_token_t *token __unused)
347 {
348 xpc_u val;
349
350 val.b = true;
351 return (_xpc_prim_create(_XPC_TYPE_BOOL, val,0));
352 }
353
354
355 #define XPC_RPORT "XPC remote port"
356 int
xpc_pipe_routine_reply(xpc_object_t xobj)357 xpc_pipe_routine_reply(xpc_object_t xobj)
358 {
359 struct xpc_object *xo;
360 size_t size, msg_size;
361 struct xpc_message *message;
362 kern_return_t kr;
363 int err;
364
365 xo = xobj;
366 assert(xo->xo_xpc_type == _XPC_TYPE_DICTIONARY);
367 // size = nvlist_size(xo->xo_nv);
368 msg_size = size + sizeof(mach_msg_header_t) + sizeof(size_t);
369 if ((message = malloc(msg_size)) == NULL)
370 return (ENOMEM);
371 //if (xpc2nv(xobj, &message->data, &size) == NULL)
372 // return (EINVAL);
373
374 message->header.msgh_size = msg_size;
375 message->header.msgh_remote_port = xpc_dictionary_copy_mach_send(xobj, XPC_RPORT);
376 message->header.msgh_local_port = MACH_PORT_NULL;
377 message->size = size;
378 kr = mach_msg_send(&message->header);
379 if (kr != KERN_SUCCESS)
380 err = (kr == KERN_INVALID_TASK) ? EPIPE : EINVAL;
381 else
382 err = 0;
383 free(message);
384 return (err);
385 }
386
387 int
xpc_pipe_send(xpc_object_t xobj,mach_port_t dst,mach_port_t local,uint64_t id)388 xpc_pipe_send(xpc_object_t xobj, mach_port_t dst, mach_port_t local,
389 uint64_t id)
390 {
391 struct xpc_object *xo;
392 size_t size, msg_size;
393 struct xpc_message *message;
394 kern_return_t kr;
395 int err;
396
397 xo = xobj;
398 assert(xo->xo_xpc_type == _XPC_TYPE_DICTIONARY);
399
400 if ((message = malloc(msg_size)) == NULL)
401 return (ENOMEM);
402
403 if (xpc_pack(xo, &message->data, &size) != 0)
404 return (EINVAL);
405
406 msg_size = _ALIGN(size + sizeof(mach_msg_header_t) + sizeof(size_t) + sizeof(uint64_t));
407 message->header.msgh_size = msg_size;
408 message->header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,
409 MACH_MSG_TYPE_MAKE_SEND);
410 message->header.msgh_remote_port = dst;
411 message->header.msgh_local_port = local;
412 message->id = id;
413 message->size = size;
414 kr = mach_msg_send(&message->header);
415 if (kr != KERN_SUCCESS)
416 err = (kr == KERN_INVALID_TASK) ? EPIPE : EINVAL;
417 else
418 err = 0;
419 free(message);
420 return (err);
421 }
422
423 #define LOG(...) \
424 do { \
425 syslog(LOG_ERR, "%s:%u: ", __FILE__, __LINE__); \
426 syslog(LOG_ERR, __VA_ARGS__); \
427 } while (0)
428
429 int
xpc_pipe_receive(mach_port_t local,mach_port_t * remote,xpc_object_t * result,uint64_t * id)430 xpc_pipe_receive(mach_port_t local, mach_port_t *remote, xpc_object_t *result,
431 uint64_t *id)
432 {
433 struct xpc_recv_message message;
434 mach_msg_header_t *request;
435 kern_return_t kr;
436 mig_reply_error_t response;
437 mach_msg_trailer_t *tr;
438 int data_size;
439 struct xpc_object *xo;
440 audit_token_t *auditp;
441 xpc_u val;
442
443 request = &message.header;
444 /* should be size - but what about arbitrary XPC data? */
445 request->msgh_size = MAX_RECV;
446 request->msgh_local_port = local;
447 kr = mach_msg(request, MACH_RCV_MSG |
448 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) |
449 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT),
450 0, request->msgh_size, request->msgh_local_port,
451 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
452
453 if (kr != 0)
454 LOG("mach_msg_receive returned %d\n", kr);
455 *remote = request->msgh_remote_port;
456 *id = message.id;
457 data_size = message.size;
458 LOG("unpacking data_size=%d", data_size);
459 xo = xpc_unpack(&message.data, data_size);
460
461 tr = (mach_msg_trailer_t *)(((char *)&message) + request->msgh_size);
462 auditp = &((mach_msg_audit_trailer_t *)tr)->msgh_audit;
463
464 xo->xo_audit_token = malloc(sizeof(*auditp));
465 memcpy(xo->xo_audit_token, auditp, sizeof(*auditp));
466
467 xpc_dictionary_set_mach_send(xo, XPC_RPORT, request->msgh_remote_port);
468 xpc_dictionary_set_uint64(xo, XPC_SEQID, message.id);
469 *result = xo;
470 return (0);
471 }
472
473 int
xpc_pipe_try_receive(mach_port_t portset,xpc_object_t * requestobj,mach_port_t * rcvport,boolean_t (* demux)(mach_msg_header_t *,mach_msg_header_t *),mach_msg_size_t msgsize __unused,int flags __unused)474 xpc_pipe_try_receive(mach_port_t portset, xpc_object_t *requestobj, mach_port_t *rcvport,
475 boolean_t (*demux)(mach_msg_header_t *, mach_msg_header_t *), mach_msg_size_t msgsize __unused,
476 int flags __unused)
477 {
478 struct xpc_recv_message message;
479 mach_msg_header_t *request;
480 kern_return_t kr;
481 mig_reply_error_t response;
482 mach_msg_trailer_t *tr;
483 int data_size;
484 struct xpc_object *xo;
485 audit_token_t *auditp;
486 xpc_u val;
487
488 request = &message.header;
489 /* should be size - but what about arbitrary XPC data? */
490 request->msgh_size = MAX_RECV;
491 request->msgh_local_port = portset;
492 kr = mach_msg(request, MACH_RCV_MSG |
493 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) |
494 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT),
495 0, request->msgh_size, request->msgh_local_port,
496 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
497
498 if (kr != 0)
499 LOG("mach_msg_receive returned %d\n", kr);
500 *rcvport = request->msgh_remote_port;
501 if (demux(request, (mach_msg_header_t *)&response)) {
502 (void)mach_msg_send((mach_msg_header_t *)&response);
503 /* can't do anything with the return code
504 * just tell the caller this has been handled
505 */
506 return (TRUE);
507 }
508 LOG("demux returned false\n");
509 data_size = request->msgh_size;
510 LOG("unpacking data_size=%d", data_size);
511 xo = xpc_unpack(&message.data, data_size);
512 /* is padding for alignment enforced in the kernel?*/
513 tr = (mach_msg_trailer_t *)(((char *)&message) + request->msgh_size);
514 auditp = &((mach_msg_audit_trailer_t *)tr)->msgh_audit;
515
516 xo->xo_audit_token = malloc(sizeof(*auditp));
517 memcpy(xo->xo_audit_token, auditp, sizeof(*auditp));
518
519 xpc_dictionary_set_mach_send(xo, XPC_RPORT, request->msgh_remote_port);
520 xpc_dictionary_set_uint64(xo, XPC_SEQID, message.id);
521 *requestobj = xo;
522 return (0);
523 }
524
525 int
xpc_call_wakeup(mach_port_t rport,int retcode)526 xpc_call_wakeup(mach_port_t rport, int retcode)
527 {
528 mig_reply_error_t msg;
529 int err;
530 kern_return_t kr;
531
532 msg.Head.msgh_remote_port = rport;
533 msg.RetCode = retcode;
534 kr = mach_msg_send(&msg.Head);
535 if (kr != KERN_SUCCESS)
536 err = (kr == KERN_INVALID_TASK) ? EPIPE : EINVAL;
537 else
538 err = 0;
539
540 return (err);
541 }
542