Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/openlaunchd
Path: blob/master/liblaunch/libvproc.c
374 views
1
/*
2
* Copyright (c) 1999-2012 Apple Inc. All rights reserved.
3
*
4
* @APPLE_APACHE_LICENSE_HEADER_START@
5
*
6
* Licensed under the Apache License, Version 2.0 (the "License");
7
* you may not use this file except in compliance with the License.
8
* You may obtain a copy of the License at
9
*
10
* http://www.apache.org/licenses/LICENSE-2.0
11
*
12
* Unless required by applicable law or agreed to in writing, software
13
* distributed under the License is distributed on an "AS IS" BASIS,
14
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
* See the License for the specific language governing permissions and
16
* limitations under the License.
17
*
18
* @APPLE_APACHE_LICENSE_HEADER_END@
19
*/
20
21
#include "config.h"
22
#include "vproc.h"
23
#include "vproc_priv.h"
24
#include "vproc_internal.h"
25
26
#include <dispatch/dispatch.h>
27
#include <libproc.h>
28
#if HAS_MACH
29
#include <mach/mach.h>
30
#include <mach/vm_map.h>
31
#endif
32
#include <sys/param.h>
33
#include <stdlib.h>
34
#include <stdio.h>
35
#include <errno.h>
36
#include <unistd.h>
37
#include <syslog.h>
38
#include <pthread.h>
39
#include <signal.h>
40
#include <assert.h>
41
#ifdef __APPLE__
42
#include <libkern/OSAtomic.h>
43
#else
44
#warning "PORT: What is libkern/OSAtomic.h?"
45
#endif
46
#include <sys/syscall.h>
47
#include <sys/event.h>
48
#ifdef __APPLE__
49
#include <System/sys/fileport.h>
50
#include <os/assumes.h>
51
#else
52
#warning "PORT: What do System/sys/fileport.h and os/assumes.h do?"
53
#endif
54
55
#if HAVE_QUARANTINE
56
#include <quarantine.h>
57
#endif
58
59
#include "launch.h"
60
#include "launch_priv.h"
61
#include "launch_internal.h"
62
#ifdef __APPLE__
63
/* NOTE: ktrace.h appears to enable Apple OS specific kernel tracing. Until
64
* this functionality can be verified further, there's no sense pulling it into
65
* the non-Apple builds
66
*/
67
#include "ktrace.h"
68
69
/*
70
* job.h, etc are generated by the Mach Interface Generator (MIG) based on the
71
* job.defs file in launchd/
72
*/
73
#include "job.h"
74
#include "helper.h"
75
/* NOTE: Not sure where helperServer.h is generated from, presumably MIG */
76
#include "helperServer.h"
77
#endif
78
79
#include "reboot2.h"
80
81
#define likely(x) __builtin_expect((bool)(x), true)
82
#define unlikely(x) __builtin_expect((bool)(x), false)
83
84
#define _vproc_set_crash_log_message(x)
85
86
void _vproc_transactions_enable_internal(void *arg);
87
void _vproc_transaction_begin_internal(void *arg __unused);
88
void _vproc_transaction_end_internal(void *arg __unused);
89
90
#pragma mark vproc Object
91
struct vproc_s {
92
int32_t refcount;
93
mach_port_t j_port;
94
};
95
96
vproc_t
97
vprocmgr_lookup_vproc(const char *label)
98
{
99
struct vproc_s *vp = NULL;
100
101
mach_port_t mp = MACH_PORT_NULL;
102
kern_return_t kr = vproc_mig_port_for_label(bootstrap_port, (char *)label, &mp);
103
if (kr == BOOTSTRAP_SUCCESS) {
104
vp = (struct vproc_s *)calloc(1, sizeof(struct vproc_s));
105
if (vp) {
106
vp->refcount = 1;
107
mach_port_mod_refs(mach_task_self(), mp, MACH_PORT_RIGHT_SEND, 1);
108
vp->j_port = mp;
109
}
110
(void)mach_port_deallocate(mach_task_self(), mp);
111
}
112
113
return vp;
114
}
115
116
vproc_t
117
vproc_retain(vproc_t vp)
118
{
119
int32_t orig = OSAtomicAdd32(1, &vp->refcount) - 1;
120
if (orig <= 0) {
121
_vproc_set_crash_log_message("Under-retain / over-release of vproc_t.");
122
abort();
123
}
124
125
return vp;
126
}
127
128
void
129
vproc_release(vproc_t vp)
130
{
131
int32_t newval = OSAtomicAdd32(-1, &vp->refcount);
132
if (newval < 0) {
133
_vproc_set_crash_log_message("Over-release of vproc_t.");
134
abort();
135
} else if (newval == 0) {
136
mach_port_deallocate(mach_task_self(), vp->j_port);
137
free(vp);
138
}
139
}
140
141
#pragma mark Transactions
142
static void
143
_vproc_transaction_init_once(void *arg __unused)
144
{
145
launch_globals_t globals = _launch_globals();
146
147
int64_t enable_transactions = 0;
148
(void)vproc_swap_integer(NULL, VPROC_GSK_TRANSACTIONS_ENABLED, 0, &enable_transactions);
149
if (enable_transactions != 0) {
150
(void)os_assumes_zero(proc_track_dirty(getpid(), PROC_DIRTY_TRACK));
151
globals->_vproc_transaction_enabled = 1;
152
}
153
globals->_vproc_transaction_queue = dispatch_queue_create("com.apple.idle-exit-queue", NULL);
154
}
155
156
void
157
_vproc_transactions_enable_internal(void *arg __unused)
158
{
159
launch_globals_t globals = _launch_globals();
160
161
if (!globals->_vproc_transaction_enabled) {
162
(void)os_assumes_zero(proc_track_dirty(getpid(), PROC_DIRTY_TRACK));
163
globals->_vproc_transaction_enabled = 1;
164
}
165
166
if (globals->_vproc_transaction_cnt > 0) {
167
(void)os_assumes_zero(proc_set_dirty(getpid(), true));
168
}
169
}
170
171
void
172
_vproc_transactions_enable(void)
173
{
174
launch_globals_t globals = _launch_globals();
175
176
dispatch_once_f(&globals->_vproc_transaction_once, NULL, _vproc_transaction_init_once);
177
dispatch_sync_f(globals->_vproc_transaction_queue, NULL, _vproc_transactions_enable_internal);
178
}
179
180
void
181
_vproc_transaction_begin_internal(void *ctx __unused)
182
{
183
launch_globals_t globals = _launch_globals();
184
185
int64_t new = ++globals->_vproc_transaction_cnt;
186
if (!globals->_vproc_transaction_enabled || new > 1) {
187
return;
188
}
189
190
if (new < 1) {
191
_vproc_set_crash_log_message("Underflow of transaction count.");
192
abort();
193
}
194
195
(void)os_assumes_zero(proc_set_dirty(getpid(), true));
196
}
197
198
void
199
_vproc_transaction_begin(void)
200
{
201
launch_globals_t globals = _launch_globals();
202
203
dispatch_once_f(&globals->_vproc_transaction_once, NULL, _vproc_transaction_init_once);
204
dispatch_sync_f(globals->_vproc_transaction_queue, NULL, _vproc_transaction_begin_internal);
205
}
206
207
vproc_transaction_t
208
vproc_transaction_begin(vproc_t vp __unused)
209
{
210
_vproc_transaction_begin();
211
212
/* Return non-NULL on success. Originally, there were dreams of returning
213
* an object or something, but those never panned out.
214
*/
215
return (vproc_transaction_t)vproc_transaction_begin;
216
}
217
218
void _vproc_transaction_end_flush(void);
219
220
void
221
_vproc_transaction_end_internal2(void *ctx)
222
{
223
launch_globals_t globals = _launch_globals();
224
225
globals->_vproc_gone2zero_callout(ctx);
226
_vproc_transaction_end_flush();
227
}
228
229
void
230
_vproc_transaction_end_internal(void *arg)
231
{
232
launch_globals_t globals = _launch_globals();
233
234
int64_t new = --globals->_vproc_transaction_cnt;
235
if (!globals->_vproc_transaction_enabled || new > 0) {
236
return;
237
}
238
239
if (new < 0) {
240
_vproc_set_crash_log_message("Underflow of transaction count.");
241
abort();
242
}
243
244
if (globals->_vproc_gone2zero_callout && !arg) {
245
globals->_vproc_transaction_cnt = 1;
246
dispatch_async_f(globals->_vproc_gone2zero_queue, globals->_vproc_gone2zero_ctx, _vproc_transaction_end_internal2);
247
} else {
248
(void)os_assumes_zero(proc_set_dirty(getpid(), false));
249
}
250
}
251
252
void
253
_vproc_transaction_end_flush2(void *ctx __unused)
254
{
255
_vproc_transaction_end_internal((void *)1);
256
}
257
258
void
259
_vproc_transaction_end_flush(void)
260
{
261
launch_globals_t globals = _launch_globals();
262
263
dispatch_sync_f(globals->_vproc_transaction_queue, NULL, _vproc_transaction_end_flush2);
264
}
265
266
void
267
_vproc_transaction_end(void)
268
{
269
launch_globals_t globals = _launch_globals();
270
271
dispatch_once_f(&globals->_vproc_transaction_once, NULL, _vproc_transaction_init_once);
272
dispatch_sync_f(globals->_vproc_transaction_queue, NULL, _vproc_transaction_end_internal);
273
}
274
275
void
276
vproc_transaction_end(vproc_t vp __unused, vproc_transaction_t vpt __unused)
277
{
278
_vproc_transaction_end();
279
}
280
281
size_t
282
_vproc_transaction_count(void)
283
{
284
launch_globals_t globals = _launch_globals();
285
286
return globals->_vproc_transaction_cnt;
287
}
288
289
size_t
290
_vproc_standby_count(void)
291
{
292
return 0;
293
}
294
295
size_t
296
_vproc_standby_timeout(void)
297
{
298
return 0;
299
}
300
301
bool
302
_vproc_pid_is_managed(pid_t p)
303
{
304
boolean_t result = false;
305
vproc_mig_pid_is_managed(bootstrap_port, p, &result);
306
307
return result;
308
}
309
310
kern_return_t
311
_vproc_transaction_count_for_pid(pid_t p, int32_t *count, bool *condemned)
312
{
313
/* Activity Monitor relies on us returning this error code when the process
314
* is not opted into Instant Off.
315
*/
316
kern_return_t error = BOOTSTRAP_NO_MEMORY;
317
318
if (condemned) {
319
*condemned = false;
320
}
321
322
if (count) {
323
uint32_t flags;
324
int ret = proc_get_dirty(p, &flags);
325
if (ret == 0) {
326
if (flags & PROC_DIRTY_TRACKED) {
327
*count = (flags & PROC_DIRTY_IS_DIRTY) ? 1 : 0;
328
error = BOOTSTRAP_SUCCESS;
329
} else {
330
error = BOOTSTRAP_NO_MEMORY;
331
}
332
} else if (ret == ENOTSUP) {
333
error = BOOTSTRAP_NO_MEMORY;
334
} else if (ret == ESRCH) {
335
error = BOOTSTRAP_UNKNOWN_SERVICE;
336
} else if (ret == EPERM) {
337
error = BOOTSTRAP_NOT_PRIVILEGED;
338
} else {
339
error = ret;
340
}
341
}
342
return error;
343
}
344
void
345
_vproc_transaction_try_exit(int status)
346
{
347
#if !TARGET_OS_EMBEDDED
348
launch_globals_t globals = _launch_globals();
349
if (globals->_vproc_transaction_cnt == 0) {
350
_exit(status);
351
}
352
#else
353
_exit(status);
354
#endif
355
}
356
357
void
358
_vproc_standby_begin(void)
359
{
360
361
}
362
363
vproc_standby_t
364
vproc_standby_begin(vproc_t vp __unused)
365
{
366
return (vproc_standby_t)vproc_standby_begin;
367
}
368
369
void
370
_vproc_standby_end(void)
371
{
372
373
}
374
375
void
376
_vproc_transaction_set_clean_callback(dispatch_queue_t targetq, void *ctx, dispatch_function_t func)
377
{
378
launch_globals_t globals = _launch_globals();
379
380
globals->_vproc_gone2zero_queue = targetq;
381
dispatch_retain(targetq);
382
383
globals->_vproc_gone2zero_callout = func;
384
globals->_vproc_gone2zero_ctx = ctx;
385
}
386
387
void
388
vproc_standby_end(vproc_t vp __unused, vproc_standby_t vpt __unused)
389
{
390
391
}
392
393
#pragma mark Miscellaneous SPI
394
kern_return_t
395
_vproc_grab_subset(mach_port_t bp, mach_port_t *reqport, mach_port_t *rcvright,
396
launch_data_t *outval, mach_port_array_t *ports,
397
mach_msg_type_number_t *portCnt)
398
{
399
mach_msg_type_number_t outdata_cnt;
400
vm_offset_t outdata = 0;
401
size_t data_offset = 0;
402
launch_data_t out_obj;
403
kern_return_t kr;
404
405
if ((kr = vproc_mig_take_subset(bp, reqport, rcvright, &outdata, &outdata_cnt, ports, portCnt))) {
406
goto out;
407
}
408
409
if ((out_obj = launch_data_unpack((void *)outdata, outdata_cnt, NULL, 0, &data_offset, NULL))) {
410
*outval = launch_data_copy(out_obj);
411
} else {
412
kr = 1;
413
}
414
415
out:
416
if (outdata) {
417
mig_deallocate(outdata, outdata_cnt);
418
}
419
420
return kr;
421
}
422
423
vproc_err_t
424
_vprocmgr_move_subset_to_user(uid_t target_user, const char *session_type, uint64_t flags)
425
{
426
kern_return_t kr = 0;
427
bool is_bkgd = (strcmp(session_type, VPROCMGR_SESSION_BACKGROUND) == 0);
428
int64_t ldpid, lduid;
429
430
if (vproc_swap_integer(NULL, VPROC_GSK_MGR_PID, 0, &ldpid) != 0) {
431
return (vproc_err_t)_vprocmgr_move_subset_to_user;
432
}
433
434
if (vproc_swap_integer(NULL, VPROC_GSK_MGR_UID, 0, &lduid) != 0) {
435
return (vproc_err_t)_vprocmgr_move_subset_to_user;
436
}
437
438
if (!is_bkgd && ldpid != 1) {
439
if (lduid == getuid()) {
440
return NULL;
441
}
442
/*
443
* Not all sessions can be moved.
444
* We should clean up this mess someday.
445
*/
446
return (vproc_err_t)_vprocmgr_move_subset_to_user;
447
}
448
449
mach_port_t puc = 0;
450
mach_port_t rootbs = MACH_PORT_NULL;
451
(void)bootstrap_get_root(bootstrap_port, &rootbs);
452
453
if (vproc_mig_lookup_per_user_context(rootbs, target_user, &puc) != 0) {
454
return (vproc_err_t)_vprocmgr_move_subset_to_user;
455
}
456
457
if (is_bkgd) {
458
task_set_bootstrap_port(mach_task_self(), puc);
459
mach_port_deallocate(mach_task_self(), bootstrap_port);
460
bootstrap_port = puc;
461
} else {
462
kr = vproc_mig_move_subset(puc, bootstrap_port, (char *)session_type, _audit_session_self(), flags);
463
mach_port_deallocate(mach_task_self(), puc);
464
}
465
466
if (kr) {
467
return (vproc_err_t)_vprocmgr_move_subset_to_user;
468
}
469
470
return _vproc_post_fork_ping();
471
}
472
473
vproc_err_t
474
_vprocmgr_switch_to_session(const char *target_session, vproc_flags_t flags __attribute__((unused)))
475
{
476
mach_port_t new_bsport = MACH_PORT_NULL;
477
kern_return_t kr = KERN_FAILURE;
478
479
mach_port_t tnp = MACH_PORT_NULL;
480
task_name_for_pid(mach_task_self(), getpid(), &tnp);
481
if ((kr = vproc_mig_switch_to_session(bootstrap_port, tnp, (char *)target_session, _audit_session_self(), &new_bsport)) != KERN_SUCCESS) {
482
_vproc_log(LOG_NOTICE, "_vprocmgr_switch_to_session(): kr = 0x%x", kr);
483
return (vproc_err_t)_vprocmgr_switch_to_session;
484
}
485
486
task_set_bootstrap_port(mach_task_self(), new_bsport);
487
mach_port_deallocate(mach_task_self(), bootstrap_port);
488
bootstrap_port = new_bsport;
489
490
return !issetugid() ? _vproc_post_fork_ping() : NULL;
491
}
492
493
vproc_err_t
494
_vprocmgr_detach_from_console(vproc_flags_t flags __attribute__((unused)))
495
{
496
return _vprocmgr_switch_to_session(VPROCMGR_SESSION_BACKGROUND, 0);
497
}
498
499
vproc_err_t
500
_vproc_post_fork_ping(void)
501
{
502
mach_port_t session = MACH_PORT_NULL;
503
kern_return_t kr = vproc_mig_post_fork_ping(bootstrap_port, mach_task_self(), &session);
504
if (kr) {
505
return _vproc_post_fork_ping;
506
}
507
508
if (session) {
509
(void)_audit_session_join(session);
510
(void)mach_port_deallocate(mach_task_self(), session);
511
}
512
513
return NULL;
514
}
515
516
vproc_err_t
517
_vprocmgr_init(const char *session_type)
518
{
519
if (vproc_mig_init_session(bootstrap_port, (char *)session_type, _audit_session_self()) == 0) {
520
return NULL;
521
}
522
523
return (vproc_err_t)_vprocmgr_init;
524
}
525
526
pid_t
527
_spawn_via_launchd(const char *label, const char *const *argv, const struct spawn_via_launchd_attr *spawn_attrs, int struct_version)
528
{
529
size_t i, good_enough_size = 10*1024*1024;
530
mach_msg_type_number_t indata_cnt = 0;
531
vm_offset_t indata = 0;
532
mach_port_t obsvr_port = MACH_PORT_NULL;
533
launch_data_t tmp, tmp_array, in_obj;
534
const char *const *tmpp;
535
kern_return_t kr = 1;
536
void *buf = NULL;
537
pid_t p = -1;
538
539
if ((in_obj = launch_data_alloc(LAUNCH_DATA_DICTIONARY)) == NULL) {
540
goto out;
541
}
542
543
if ((tmp = launch_data_new_string(label)) == NULL) {
544
goto out;
545
}
546
547
launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_LABEL);
548
549
if ((tmp_array = launch_data_alloc(LAUNCH_DATA_ARRAY)) == NULL) {
550
goto out;
551
}
552
553
for (i = 0; *argv; i++, argv++) {
554
tmp = launch_data_new_string(*argv);
555
if (tmp == NULL) {
556
goto out;
557
}
558
559
launch_data_array_set_index(tmp_array, tmp, i);
560
}
561
562
launch_data_dict_insert(in_obj, tmp_array, LAUNCH_JOBKEY_PROGRAMARGUMENTS);
563
564
if (spawn_attrs) switch (struct_version) {
565
case 3:
566
case 2:
567
#if HAVE_QUARANTINE
568
if (spawn_attrs->spawn_quarantine) {
569
char qbuf[QTN_SERIALIZED_DATA_MAX];
570
size_t qbuf_sz = QTN_SERIALIZED_DATA_MAX;
571
572
if (qtn_proc_to_data(spawn_attrs->spawn_quarantine, qbuf, &qbuf_sz) == 0) {
573
tmp = launch_data_new_opaque(qbuf, qbuf_sz);
574
launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_QUARANTINEDATA);
575
}
576
}
577
#endif
578
579
if (spawn_attrs->spawn_seatbelt_profile) {
580
tmp = launch_data_new_string(spawn_attrs->spawn_seatbelt_profile);
581
launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_SANDBOXPROFILE);
582
}
583
584
if (spawn_attrs->spawn_seatbelt_flags) {
585
tmp = launch_data_new_integer(*spawn_attrs->spawn_seatbelt_flags);
586
launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_SANDBOXFLAGS);
587
}
588
589
/* fall through */
590
case 1:
591
if (spawn_attrs->spawn_binpref) {
592
tmp_array = launch_data_alloc(LAUNCH_DATA_ARRAY);
593
for (i = 0; i < spawn_attrs->spawn_binpref_cnt; i++) {
594
tmp = launch_data_new_integer(spawn_attrs->spawn_binpref[i]);
595
launch_data_array_set_index(tmp_array, tmp, i);
596
}
597
launch_data_dict_insert(in_obj, tmp_array, LAUNCH_JOBKEY_BINARYORDERPREFERENCE);
598
}
599
/* fall through */
600
case 0:
601
if (spawn_attrs->spawn_flags & SPAWN_VIA_LAUNCHD_STOPPED) {
602
tmp = launch_data_new_bool(true);
603
launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_WAITFORDEBUGGER);
604
}
605
if (spawn_attrs->spawn_flags & SPAWN_VIA_LAUNCHD_TALAPP) {
606
tmp = launch_data_new_string(LAUNCH_KEY_POSIXSPAWNTYPE_TALAPP);
607
launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_POSIXSPAWNTYPE);
608
}
609
if (spawn_attrs->spawn_flags & SPAWN_VIA_LAUNCHD_DISABLE_ASLR) {
610
tmp = launch_data_new_bool(true);
611
launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_DISABLEASLR);
612
}
613
614
if (spawn_attrs->spawn_env) {
615
launch_data_t tmp_dict = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
616
617
for (tmpp = spawn_attrs->spawn_env; *tmpp; tmpp++) {
618
char *eqoff, tmpstr[strlen(*tmpp) + 1];
619
620
strcpy(tmpstr, *tmpp);
621
622
eqoff = strchr(tmpstr, '=');
623
624
if (!eqoff) {
625
goto out;
626
}
627
628
*eqoff = '\0';
629
630
launch_data_dict_insert(tmp_dict, launch_data_new_string(eqoff + 1), tmpstr);
631
}
632
633
launch_data_dict_insert(in_obj, tmp_dict, LAUNCH_JOBKEY_ENVIRONMENTVARIABLES);
634
}
635
636
if (spawn_attrs->spawn_path) {
637
tmp = launch_data_new_string(spawn_attrs->spawn_path);
638
launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_PROGRAM);
639
}
640
641
if (spawn_attrs->spawn_chdir) {
642
tmp = launch_data_new_string(spawn_attrs->spawn_chdir);
643
launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_WORKINGDIRECTORY);
644
}
645
646
if (spawn_attrs->spawn_umask) {
647
tmp = launch_data_new_integer(*spawn_attrs->spawn_umask);
648
launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_UMASK);
649
}
650
651
break;
652
default:
653
break;
654
}
655
656
if (!(buf = malloc(good_enough_size))) {
657
goto out;
658
}
659
660
if ((indata_cnt = launch_data_pack(in_obj, buf, good_enough_size, NULL, NULL)) == 0) {
661
goto out;
662
}
663
664
indata = (vm_offset_t)buf;
665
666
if (struct_version == 3) {
667
kr = vproc_mig_spawn2(bootstrap_port, indata, indata_cnt, _audit_session_self(), &p, &obsvr_port);
668
} else {
669
_vproc_set_crash_log_message("Bogus version passed to _spawn_via_launchd(). For this release, the only valid version is 3.");
670
}
671
672
if (kr == VPROC_ERR_TRY_PER_USER) {
673
mach_port_t puc;
674
675
if (vproc_mig_lookup_per_user_context(bootstrap_port, 0, &puc) == 0) {
676
if (struct_version == 3) {
677
kr = vproc_mig_spawn2(puc, indata, indata_cnt, _audit_session_self(), &p, &obsvr_port);
678
}
679
mach_port_deallocate(mach_task_self(), puc);
680
}
681
}
682
683
out:
684
if (in_obj) {
685
launch_data_free(in_obj);
686
}
687
688
if (buf) {
689
free(buf);
690
}
691
692
switch (kr) {
693
case BOOTSTRAP_SUCCESS:
694
if (spawn_attrs && spawn_attrs->spawn_observer_port) {
695
*spawn_attrs->spawn_observer_port = obsvr_port;
696
} else {
697
if (struct_version == 3) {
698
mach_port_mod_refs(mach_task_self(), obsvr_port, MACH_PORT_RIGHT_RECEIVE, -1);
699
} else {
700
mach_port_deallocate(mach_task_self(), obsvr_port);
701
}
702
}
703
return p;
704
case BOOTSTRAP_NOT_PRIVILEGED:
705
errno = EPERM; break;
706
case BOOTSTRAP_NO_MEMORY:
707
errno = ENOMEM; break;
708
case BOOTSTRAP_NAME_IN_USE:
709
errno = EEXIST; break;
710
case 1:
711
errno = EIO; break;
712
default:
713
errno = EINVAL; break;
714
}
715
716
return -1;
717
}
718
719
kern_return_t
720
mpm_wait(mach_port_t ajob __attribute__((unused)), int *wstatus)
721
{
722
*wstatus = 0;
723
return 0;
724
}
725
726
kern_return_t
727
mpm_uncork_fork(mach_port_t ajob __attribute__((unused)))
728
{
729
return KERN_FAILURE;
730
}
731
732
kern_return_t
733
_vprocmgr_getsocket(name_t sockpath)
734
{
735
return vproc_mig_getsocket(bootstrap_port, sockpath);
736
}
737
738
vproc_err_t
739
_vproc_get_last_exit_status(int *wstatus)
740
{
741
int64_t val;
742
743
if (vproc_swap_integer(NULL, VPROC_GSK_LAST_EXIT_STATUS, 0, &val) == 0) {
744
*wstatus = (int)val;
745
return NULL;
746
}
747
748
return (vproc_err_t)_vproc_get_last_exit_status;
749
}
750
751
vproc_err_t
752
_vproc_send_signal_by_label(const char *label, int sig)
753
{
754
if (vproc_mig_send_signal(bootstrap_port, (char *)label, sig) == 0) {
755
return NULL;
756
}
757
758
return _vproc_send_signal_by_label;
759
}
760
761
vproc_err_t
762
_vprocmgr_log_forward(mach_port_t mp, void *data, size_t len)
763
{
764
if (vproc_mig_log_forward(mp, (vm_offset_t)data, len) == 0) {
765
return NULL;
766
}
767
768
return _vprocmgr_log_forward;
769
}
770
771
vproc_err_t
772
_vprocmgr_log_drain(vproc_t vp __attribute__((unused)), pthread_mutex_t *mutex, _vprocmgr_log_drain_callback_t func)
773
{
774
mach_msg_type_number_t outdata_cnt, tmp_cnt;
775
vm_offset_t outdata = 0;
776
struct timeval tv;
777
struct logmsg_s *lm;
778
779
if (!func) {
780
return _vprocmgr_log_drain;
781
}
782
783
if (vproc_mig_log_drain(bootstrap_port, &outdata, &outdata_cnt) != 0) {
784
return _vprocmgr_log_drain;
785
}
786
787
tmp_cnt = outdata_cnt;
788
789
if (mutex) {
790
pthread_mutex_lock(mutex);
791
}
792
793
for (lm = (struct logmsg_s *)outdata; tmp_cnt > 0; lm = ((void *)lm + lm->obj_sz)) {
794
lm->from_name = (char *)lm + lm->from_name_offset;
795
lm->about_name = (char *)lm + lm->about_name_offset;
796
lm->msg = (char *)lm + lm->msg_offset;
797
lm->session_name = (char *)lm + lm->session_name_offset;
798
799
tv.tv_sec = lm->when / USEC_PER_SEC;
800
tv.tv_usec = lm->when % USEC_PER_SEC;
801
802
func(&tv, lm->from_pid, lm->about_pid, lm->sender_uid, lm->sender_gid, lm->pri,
803
lm->from_name, lm->about_name, lm->session_name, lm->msg);
804
805
tmp_cnt -= lm->obj_sz;
806
}
807
808
if (mutex) {
809
pthread_mutex_unlock(mutex);
810
}
811
812
if (outdata) {
813
mig_deallocate(outdata, outdata_cnt);
814
}
815
816
return NULL;
817
}
818
819
vproc_err_t
820
vproc_swap_integer(vproc_t vp, vproc_gsk_t key, int64_t *inval, int64_t *outval)
821
{
822
kern_return_t kr = KERN_FAILURE;
823
int64_t dummyval = 0;
824
mach_port_t mp = vp ? vp->j_port : bootstrap_port;
825
if ((kr = vproc_mig_swap_integer(mp, inval ? key : 0, outval ? key : 0, inval ? *inval : 0, outval ? outval : &dummyval)) == 0) {
826
switch (key) {
827
case VPROC_GSK_PERUSER_SUSPEND:
828
if (dummyval) {
829
/* Wait for the per-user launchd to exit before returning. */
830
int kq = kqueue();
831
struct kevent kev;
832
EV_SET(&kev, dummyval, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, 0);
833
int r = kevent(kq, &kev, 1, &kev, 1, NULL);
834
(void)close(kq);
835
if (r != 1) {
836
return NULL;
837
}
838
break;
839
}
840
default:
841
break;
842
}
843
return NULL;
844
}
845
846
return (vproc_err_t)vproc_swap_integer;
847
}
848
849
vproc_err_t
850
vproc_swap_complex(vproc_t vp, vproc_gsk_t key, launch_data_t inval, launch_data_t *outval)
851
{
852
size_t data_offset = 0, good_enough_size = 10*1024*1024;
853
mach_msg_type_number_t indata_cnt = 0, outdata_cnt;
854
vm_offset_t indata = 0, outdata = 0;
855
launch_data_t out_obj;
856
void *rval = vproc_swap_complex;
857
void *buf = NULL;
858
859
if (inval) {
860
if (!(buf = malloc(good_enough_size))) {
861
goto out;
862
}
863
864
if ((indata_cnt = launch_data_pack(inval, buf, good_enough_size, NULL, NULL)) == 0) {
865
goto out;
866
}
867
868
indata = (vm_offset_t)buf;
869
}
870
871
mach_port_t mp = vp ? vp->j_port : bootstrap_port;
872
if (vproc_mig_swap_complex(mp, inval ? key : 0, outval ? key : 0, indata, indata_cnt, &outdata, &outdata_cnt) != 0) {
873
goto out;
874
}
875
876
if (outval) {
877
if (!(out_obj = launch_data_unpack((void *)outdata, outdata_cnt, NULL, 0, &data_offset, NULL))) {
878
goto out;
879
}
880
881
if (!(*outval = launch_data_copy(out_obj))) {
882
goto out;
883
}
884
}
885
886
rval = NULL;
887
out:
888
if (buf) {
889
free(buf);
890
}
891
892
if (outdata) {
893
mig_deallocate(outdata, outdata_cnt);
894
}
895
896
return rval;
897
}
898
899
vproc_err_t
900
vproc_swap_string(vproc_t vp, vproc_gsk_t key, const char *instr, char **outstr)
901
{
902
launch_data_t instr_data = instr ? launch_data_new_string(instr) : NULL;
903
launch_data_t outstr_data = NULL;
904
905
vproc_err_t verr = vproc_swap_complex(vp, key, instr_data, &outstr_data);
906
if (!verr && outstr) {
907
if (launch_data_get_type(outstr_data) == LAUNCH_DATA_STRING) {
908
*outstr = strdup(launch_data_get_string(outstr_data));
909
} else {
910
verr = (vproc_err_t)vproc_swap_string;
911
}
912
launch_data_free(outstr_data);
913
}
914
if (instr_data) {
915
launch_data_free(instr_data);
916
}
917
918
return verr;
919
}
920
921
void *
922
reboot2(uint64_t flags)
923
{
924
mach_port_t rootbs = MACH_PORT_NULL;
925
(void)bootstrap_get_root(bootstrap_port, &rootbs);
926
if (vproc_mig_reboot2(rootbs, flags) == 0) {
927
(void)mach_port_deallocate(mach_task_self(), rootbs);
928
return NULL;
929
}
930
931
return reboot2;
932
}
933
934
vproc_err_t
935
_vproc_kickstart_by_label(const char *label, pid_t *out_pid,
936
mach_port_t *out_port_name __unused, mach_port_t *out_obsrvr_port __unused,
937
vproc_flags_t flags)
938
{
939
/* Ignore the two port parameters. This SPI isn't long for this world, and
940
* all the current clients just leak them anyway.
941
*/
942
kern_return_t kr = vproc_mig_kickstart(bootstrap_port, (char *)label, out_pid, flags);
943
if (kr == KERN_SUCCESS) {
944
return NULL;
945
}
946
947
return (vproc_err_t)_vproc_kickstart_by_label;
948
}
949
950
vproc_err_t
951
_vproc_set_global_on_demand(bool state)
952
{
953
int64_t val = state ? ~0 : 0;
954
955
if (vproc_swap_integer(NULL, VPROC_GSK_GLOBAL_ON_DEMAND, &val, NULL) == 0) {
956
return NULL;
957
}
958
959
return (vproc_err_t)_vproc_set_global_on_demand;
960
}
961
962
void
963
_vproc_logv(int pri, int err, const char *msg, va_list ap)
964
{
965
char flat_msg[3000];
966
967
vsnprintf(flat_msg, sizeof(flat_msg), msg, ap);
968
969
vproc_mig_log(bootstrap_port, pri, err, flat_msg);
970
}
971
972
void
973
_vproc_log(int pri, const char *msg, ...)
974
{
975
va_list ap;
976
977
va_start(ap, msg);
978
_vproc_logv(pri, 0, msg, ap);
979
va_end(ap);
980
}
981
982
void
983
_vproc_log_error(int pri, const char *msg, ...)
984
{
985
int saved_errno = errno;
986
va_list ap;
987
988
va_start(ap, msg);
989
_vproc_logv(pri, saved_errno, msg, ap);
990
va_end(ap);
991
}
992
993
/* The type naming convention is as follows:
994
* For requests...
995
* union __RequestUnion__<userprefix><subsystem>_subsystem
996
* For replies...
997
* union __ReplyUnion__<userprefix><subsystem>_subsystem
998
*/
999
union maxmsgsz {
1000
union __RequestUnion__helper_downcall_launchd_helper_subsystem req;
1001
union __ReplyUnion__helper_downcall_launchd_helper_subsystem rep;
1002
};
1003
1004
const size_t vprocmgr_helper_maxmsgsz = sizeof(union maxmsgsz);
1005
1006
kern_return_t
1007
helper_recv_wait(mach_port_t p, int status)
1008
{
1009
#if __LAUNCH_MACH_PORT_CONTEXT_T_DEFINED__
1010
mach_port_context_t ctx = status;
1011
#else
1012
mach_vm_address_t ctx = status;
1013
#endif
1014
1015
return (errno = mach_port_set_context(mach_task_self(), p, ctx));
1016
}
1017
1018
#if HAS_MACH
1019
/* It would appear that launch_wait is never referenced anywhere in launchd */
1020
int
1021
launch_wait(mach_port_t port) __attribute__(("deprecated"))
1022
{
1023
int status = -1;
1024
errno = mach_msg_server_once(launchd_helper_server, vprocmgr_helper_maxmsgsz, port, 0);
1025
if (errno == MACH_MSG_SUCCESS) {
1026
#if __LAUNCH_MACH_PORT_CONTEXT_T_DEFINED__
1027
mach_port_context_t ctx = 0;
1028
#else
1029
mach_vm_address_t ctx = 0;
1030
#endif
1031
if ((errno = mach_port_get_context(mach_task_self(), port, &ctx)) == KERN_SUCCESS) {
1032
status = ctx;
1033
}
1034
}
1035
1036
return status;
1037
}
1038
#endif
1039
launch_data_t
1040
launch_socket_service_check_in(void)
1041
{
1042
launch_data_t reply = NULL;
1043
1044
size_t big_enough = 10 * 1024;
1045
void *buff = malloc(big_enough);
1046
if (buff) {
1047
launch_data_t req = launch_data_new_string(LAUNCH_KEY_CHECKIN);
1048
if (req) {
1049
size_t sz = launch_data_pack(req, buff, big_enough, NULL, NULL);
1050
if (sz) {
1051
vm_address_t sreply = 0;
1052
mach_msg_size_t sreplyCnt = 0;
1053
mach_port_array_t fdps = NULL;
1054
mach_msg_size_t fdpsCnt = 0;
1055
kern_return_t kr = vproc_mig_legacy_ipc_request(bootstrap_port, (vm_address_t)buff, sz, NULL, 0, &sreply, &sreplyCnt, &fdps, &fdpsCnt, _audit_session_self());
1056
if (kr == BOOTSTRAP_SUCCESS) {
1057
int fds[128];
1058
1059
size_t i = 0;
1060
size_t nfds = fdpsCnt / sizeof(fdps[0]);
1061
for (i = 0; i < nfds; i++) {
1062
fds[i] = fileport_makefd(fdps[i]);
1063
(void)mach_port_deallocate(mach_task_self(), fdps[i]);
1064
}
1065
1066
size_t dataoff = 0;
1067
size_t fdoff = 0;
1068
reply = launch_data_unpack((void *)sreply, sreplyCnt, fds, nfds, &dataoff, &fdoff);
1069
reply = launch_data_copy(reply);
1070
1071
mig_deallocate(sreply, sreplyCnt);
1072
mig_deallocate((vm_address_t)fdps, fdpsCnt);
1073
}
1074
}
1075
1076
launch_data_free(req);
1077
}
1078
1079
free(buff);
1080
}
1081
1082
return reply;
1083
}
1084
1085