1 /*
2 * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * @OSF_FREE_COPYRIGHT@
30 */
31 /*
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University
34 * All Rights Reserved.
35 *
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
41 *
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 * Software Distribution Coordinator or [email protected]
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56 /*
57 * File: kern/task.c
58 * Author: Avadis Tevanian, Jr., Michael Wayne Young, David Golub,
59 * David Black
60 *
61 * Task management primitives implementation.
62 */
63 /*
64 * Copyright (c) 1993 The University of Utah and
65 * the Computer Systems Laboratory (CSL). All rights reserved.
66 *
67 * Permission to use, copy, modify and distribute this software and its
68 * documentation is hereby granted, provided that both the copyright
69 * notice and this permission notice appear in all copies of the
70 * software, derivative works or modified versions, and any portions
71 * thereof, and that both notices appear in supporting documentation.
72 *
73 * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
74 * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
75 * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
76 *
77 * CSL requests users of this software to return to [email protected] any
78 * improvements that they make and grant CSL redistribution rights.
79 *
80 */
81 /*
82 * NOTICE: This file was modified by McAfee Research in 2004 to introduce
83 * support for mandatory and extensible security protections. This notice
84 * is included in support of clause 2.2 (b) of the Apple Public License,
85 * Version 2.0.
86 * Copyright (c) 2005 SPARTA, Inc.
87 */
88
89 #include <mach/mach_types.h>
90 #include <mach/boolean.h>
91 #include <mach/host_priv.h>
92 #include <mach/machine/vm_types.h>
93 #include <mach/vm_param.h>
94 #include <mach/mach_vm.h>
95 #include <mach/semaphore.h>
96 #include <mach/task_info.h>
97 #include <mach/task_inspect.h>
98 #include <mach/task_special_ports.h>
99 #include <mach/sdt.h>
100 #include <mach/mach_test_upcall.h>
101
102 #include <ipc/ipc_importance.h>
103 #include <ipc/ipc_types.h>
104 #include <ipc/ipc_space.h>
105 #include <ipc/ipc_entry.h>
106 #include <ipc/ipc_hash.h>
107 #include <ipc/ipc_init.h>
108
109 #include <kern/kern_types.h>
110 #include <kern/mach_param.h>
111 #include <kern/misc_protos.h>
112 #include <kern/task.h>
113 #include <kern/thread.h>
114 #include <kern/coalition.h>
115 #include <kern/zalloc.h>
116 #include <kern/kalloc.h>
117 #include <kern/kern_cdata.h>
118 #include <kern/processor.h>
119 #include <kern/recount.h>
120 #include <kern/sched_prim.h> /* for thread_wakeup */
121 #include <kern/ipc_tt.h>
122 #include <kern/host.h>
123 #include <kern/clock.h>
124 #include <kern/timer.h>
125 #include <kern/assert.h>
126 #include <kern/affinity.h>
127 #include <kern/exc_resource.h>
128 #include <kern/machine.h>
129 #include <kern/policy_internal.h>
130 #include <kern/restartable.h>
131 #include <kern/ipc_kobject.h>
132
133 #include <corpses/task_corpse.h>
134 #if CONFIG_TELEMETRY
135 #include <kern/telemetry.h>
136 #endif
137
138 #if CONFIG_PERVASIVE_CPI
139 #include <kern/monotonic.h>
140 #include <machine/monotonic.h>
141 #endif /* CONFIG_PERVASIVE_CPI */
142
143 #include <os/log.h>
144
145 #include <vm/pmap.h>
146 #include <vm/vm_map.h>
147 #include <vm/vm_kern.h> /* for kernel_map, ipc_kernel_map */
148 #include <vm/vm_pageout.h>
149 #include <vm/vm_protos.h>
150 #include <vm/vm_purgeable_internal.h>
151 #include <vm/vm_compressor_pager.h>
152 #include <vm/vm_reclaim_internal.h>
153
154 #include <sys/proc_ro.h>
155 #include <sys/resource.h>
156 #include <sys/signalvar.h> /* for coredump */
157 #include <sys/bsdtask_info.h>
158 /*
159 * Exported interfaces
160 */
161
162 #include <mach/task_server.h>
163 #include <mach/mach_host_server.h>
164 #include <mach/mach_port_server.h>
165
166 #include <vm/vm_shared_region.h>
167
168 #include <libkern/OSDebug.h>
169 #include <libkern/OSAtomic.h>
170 #include <libkern/section_keywords.h>
171
172 #include <mach-o/loader.h>
173 #include <kdp/kdp_dyld.h>
174
175 #include <kern/sfi.h> /* picks up ledger.h */
176
177 #if CONFIG_MACF
178 #include <security/mac_mach_internal.h>
179 #endif
180
181 #include <IOKit/IOBSD.h>
182 #include <kdp/processor_core.h>
183
184 #if KPERF
185 extern int kpc_force_all_ctrs(task_t, int);
186 #endif
187
188 SECURITY_READ_ONLY_LATE(task_t) kernel_task;
189
190 int64_t next_taskuniqueid = 0;
191 const size_t task_alignment = _Alignof(struct task);
192 extern const size_t proc_alignment;
193 extern size_t proc_struct_size;
194 extern size_t proc_and_task_size;
195 size_t task_struct_size;
196
197 extern uint32_t ipc_control_port_options;
198
199 extern int large_corpse_count;
200
201 extern boolean_t proc_send_synchronous_EXC_RESOURCE(void *p);
202 extern void task_disown_frozen_csegs(task_t owner_task);
203
204 static void task_port_no_senders(ipc_port_t, mach_msg_type_number_t);
205 static void task_port_with_flavor_no_senders(ipc_port_t, mach_msg_type_number_t);
206 static void task_suspension_no_senders(ipc_port_t, mach_msg_type_number_t);
207 static inline void task_zone_init(void);
208
209 IPC_KOBJECT_DEFINE(IKOT_TASK_NAME);
210 IPC_KOBJECT_DEFINE(IKOT_TASK_CONTROL,
211 .iko_op_no_senders = task_port_no_senders);
212 IPC_KOBJECT_DEFINE(IKOT_TASK_READ,
213 .iko_op_no_senders = task_port_with_flavor_no_senders);
214 IPC_KOBJECT_DEFINE(IKOT_TASK_INSPECT,
215 .iko_op_no_senders = task_port_with_flavor_no_senders);
216 IPC_KOBJECT_DEFINE(IKOT_TASK_RESUME,
217 .iko_op_no_senders = task_suspension_no_senders);
218
219 #if CONFIG_PROC_RESOURCE_LIMITS
220 static void task_fatal_port_no_senders(ipc_port_t, mach_msg_type_number_t);
221 static mach_port_t task_allocate_fatal_port(void);
222
223 IPC_KOBJECT_DEFINE(IKOT_TASK_FATAL,
224 .iko_op_stable = true,
225 .iko_op_no_senders = task_fatal_port_no_senders);
226
227 extern void task_id_token_set_port(task_id_token_t token, ipc_port_t port);
228 #endif /* CONFIG_PROC_RESOURCE_LIMITS */
229
230 /* Flag set by core audio when audio is playing. Used to stifle EXC_RESOURCE generation when active. */
231 int audio_active = 0;
232
233 /*
234 * structure for tracking zone usage
235 * Used either one per task/thread for all zones or <per-task,per-zone>.
236 */
237 typedef struct zinfo_usage_store_t {
238 /* These fields may be updated atomically, and so must be 8 byte aligned */
239 uint64_t alloc __attribute__((aligned(8))); /* allocation counter */
240 uint64_t free __attribute__((aligned(8))); /* free counter */
241 } zinfo_usage_store_t;
242
243 zinfo_usage_store_t tasks_tkm_private;
244 zinfo_usage_store_t tasks_tkm_shared;
245
246 /* A container to accumulate statistics for expired tasks */
247 expired_task_statistics_t dead_task_statistics;
248 LCK_SPIN_DECLARE_ATTR(dead_task_statistics_lock, &task_lck_grp, &task_lck_attr);
249
250 ledger_template_t task_ledger_template = NULL;
251
252 /* global lock for task_dyld_process_info_notify_{register, deregister, get_trap} */
253 LCK_GRP_DECLARE(g_dyldinfo_mtx_grp, "g_dyldinfo");
254 LCK_MTX_DECLARE(g_dyldinfo_mtx, &g_dyldinfo_mtx_grp);
255
256 SECURITY_READ_ONLY_LATE(struct _task_ledger_indices) task_ledgers __attribute__((used)) =
257 {.cpu_time = -1,
258 .tkm_private = -1,
259 .tkm_shared = -1,
260 .phys_mem = -1,
261 .wired_mem = -1,
262 .internal = -1,
263 .iokit_mapped = -1,
264 .external = -1,
265 .reusable = -1,
266 .alternate_accounting = -1,
267 .alternate_accounting_compressed = -1,
268 .page_table = -1,
269 .phys_footprint = -1,
270 .internal_compressed = -1,
271 .purgeable_volatile = -1,
272 .purgeable_nonvolatile = -1,
273 .purgeable_volatile_compressed = -1,
274 .purgeable_nonvolatile_compressed = -1,
275 .tagged_nofootprint = -1,
276 .tagged_footprint = -1,
277 .tagged_nofootprint_compressed = -1,
278 .tagged_footprint_compressed = -1,
279 .network_volatile = -1,
280 .network_nonvolatile = -1,
281 .network_volatile_compressed = -1,
282 .network_nonvolatile_compressed = -1,
283 .media_nofootprint = -1,
284 .media_footprint = -1,
285 .media_nofootprint_compressed = -1,
286 .media_footprint_compressed = -1,
287 .graphics_nofootprint = -1,
288 .graphics_footprint = -1,
289 .graphics_nofootprint_compressed = -1,
290 .graphics_footprint_compressed = -1,
291 .neural_nofootprint = -1,
292 .neural_footprint = -1,
293 .neural_nofootprint_compressed = -1,
294 .neural_footprint_compressed = -1,
295 .platform_idle_wakeups = -1,
296 .interrupt_wakeups = -1,
297 #if CONFIG_SCHED_SFI
298 .sfi_wait_times = { 0 /* initialized at runtime */},
299 #endif /* CONFIG_SCHED_SFI */
300 .cpu_time_billed_to_me = -1,
301 .cpu_time_billed_to_others = -1,
302 .physical_writes = -1,
303 .logical_writes = -1,
304 .logical_writes_to_external = -1,
305 #if DEBUG || DEVELOPMENT
306 .pages_grabbed = -1,
307 .pages_grabbed_kern = -1,
308 .pages_grabbed_iopl = -1,
309 .pages_grabbed_upl = -1,
310 #endif
311 #if CONFIG_FREEZE
312 .frozen_to_swap = -1,
313 #endif /* CONFIG_FREEZE */
314 .energy_billed_to_me = -1,
315 .energy_billed_to_others = -1,
316 #if CONFIG_PHYS_WRITE_ACCT
317 .fs_metadata_writes = -1,
318 #endif /* CONFIG_PHYS_WRITE_ACCT */
319 #if CONFIG_MEMORYSTATUS
320 .memorystatus_dirty_time = -1,
321 #endif /* CONFIG_MEMORYSTATUS */
322 .swapins = -1, };
323
324 /* System sleep state */
325 boolean_t tasks_suspend_state;
326
327
328 void init_task_ledgers(void);
329 void task_footprint_exceeded(int warning, __unused const void *param0, __unused const void *param1);
330 void task_wakeups_rate_exceeded(int warning, __unused const void *param0, __unused const void *param1);
331 void task_io_rate_exceeded(int warning, const void *param0, __unused const void *param1);
332 void __attribute__((noinline)) SENDING_NOTIFICATION__THIS_PROCESS_IS_CAUSING_TOO_MANY_WAKEUPS(void);
333 void __attribute__((noinline)) PROC_CROSSED_HIGH_WATERMARK__SEND_EXC_RESOURCE_AND_SUSPEND(int max_footprint_mb, boolean_t is_fatal);
334 void __attribute__((noinline)) SENDING_NOTIFICATION__THIS_PROCESS_IS_CAUSING_TOO_MUCH_IO(int flavor);
335 #if CONFIG_PROC_RESOURCE_LIMITS
336 void __attribute__((noinline)) SENDING_NOTIFICATION__THIS_PROCESS_HAS_TOO_MANY_FILE_DESCRIPTORS(task_t task, int current_size, int soft_limit, int hard_limit);
337 mach_port_name_t current_task_get_fatal_port_name(void);
338 #endif /* CONFIG_PROC_RESOURCE_LIMITS */
339
340 kern_return_t task_suspend_internal(task_t);
341 kern_return_t task_resume_internal(task_t);
342 static kern_return_t task_start_halt_locked(task_t task, boolean_t should_mark_corpse);
343
344 extern kern_return_t iokit_task_terminate(task_t task);
345 extern void iokit_task_app_suspended_changed(task_t task);
346
347 extern kern_return_t exception_deliver(thread_t, exception_type_t, mach_exception_data_t, mach_msg_type_number_t, struct exception_action *, lck_mtx_t *);
348 extern void bsd_copythreadname(void *dst_uth, void *src_uth);
349 extern kern_return_t thread_resume(thread_t thread);
350
351 extern int exit_with_port_space_exception(void *proc, mach_exception_code_t code, mach_exception_subcode_t subcode);
352
353 // Warn tasks when they hit 80% of their memory limit.
354 #define PHYS_FOOTPRINT_WARNING_LEVEL 80
355
356 #define TASK_WAKEUPS_MONITOR_DEFAULT_LIMIT 150 /* wakeups per second */
357 #define TASK_WAKEUPS_MONITOR_DEFAULT_INTERVAL 300 /* in seconds. */
358
359 /*
360 * Level (in terms of percentage of the limit) at which the wakeups monitor triggers telemetry.
361 *
362 * (ie when the task's wakeups rate exceeds 70% of the limit, start taking user
363 * stacktraces, aka micro-stackshots)
364 */
365 #define TASK_WAKEUPS_MONITOR_DEFAULT_USTACKSHOTS_TRIGGER 70
366
367 int task_wakeups_monitor_interval; /* In seconds. Time period over which wakeups rate is observed */
368 int task_wakeups_monitor_rate; /* In hz. Maximum allowable wakeups per task before EXC_RESOURCE is sent */
369
370 unsigned int task_wakeups_monitor_ustackshots_trigger_pct; /* Percentage. Level at which we start gathering telemetry. */
371
372 int disable_exc_resource; /* Global override to supress EXC_RESOURCE for resource monitor violations. */
373
374 ledger_amount_t max_task_footprint = 0; /* Per-task limit on physical memory consumption in bytes */
375 unsigned int max_task_footprint_warning_level = 0; /* Per-task limit warning percentage */
376 int max_task_footprint_mb = 0; /* Per-task limit on physical memory consumption in megabytes */
377
378 /* I/O Monitor Limits */
379 #define IOMON_DEFAULT_LIMIT (20480ull) /* MB of logical/physical I/O */
380 #define IOMON_DEFAULT_INTERVAL (86400ull) /* in seconds */
381
382 uint64_t task_iomon_limit_mb; /* Per-task I/O monitor limit in MBs */
383 uint64_t task_iomon_interval_secs; /* Per-task I/O monitor interval in secs */
384
385 #define IO_TELEMETRY_DEFAULT_LIMIT (10ll * 1024ll * 1024ll)
386 int64_t io_telemetry_limit; /* Threshold to take a microstackshot (0 indicated I/O telemetry is turned off) */
387 int64_t global_logical_writes_count = 0; /* Global count for logical writes */
388 int64_t global_logical_writes_to_external_count = 0; /* Global count for logical writes to external storage*/
389 static boolean_t global_update_logical_writes(int64_t, int64_t*);
390
391 #define TASK_MAX_THREAD_LIMIT 256
392
393 #if MACH_ASSERT
394 int pmap_ledgers_panic = 1;
395 int pmap_ledgers_panic_leeway = 3;
396 #endif /* MACH_ASSERT */
397
398 int task_max = CONFIG_TASK_MAX; /* Max number of tasks */
399
400 #if CONFIG_COREDUMP
401 int hwm_user_cores = 0; /* high watermark violations generate user core files */
402 #endif
403
404 #ifdef MACH_BSD
405 extern uint32_t proc_platform(const struct proc *);
406 extern uint32_t proc_sdk(struct proc *);
407 extern void proc_getexecutableuuid(void *, unsigned char *, unsigned long);
408 extern int proc_pid(struct proc *p);
409 extern int proc_selfpid(void);
410 extern struct proc *current_proc(void);
411 extern char *proc_name_address(struct proc *p);
412 extern uint64_t get_dispatchqueue_offset_from_proc(void *);
413 extern int kevent_proc_copy_uptrs(void *proc, uint64_t *buf, uint32_t bufsize);
414 extern void workq_proc_suspended(struct proc *p);
415 extern void workq_proc_resumed(struct proc *p);
416 extern struct proc *kernproc;
417
418 #if CONFIG_MEMORYSTATUS
419 extern void proc_memstat_skip(struct proc* p, boolean_t set);
420 extern void memorystatus_on_ledger_footprint_exceeded(int warning, boolean_t memlimit_is_active, boolean_t memlimit_is_fatal);
421 extern void memorystatus_log_exception(const int max_footprint_mb, boolean_t memlimit_is_active, boolean_t memlimit_is_fatal);
422 extern boolean_t memorystatus_allowed_vm_map_fork(task_t task, bool *is_large);
423 extern uint64_t memorystatus_available_memory_internal(struct proc *p);
424
425 #if DEVELOPMENT || DEBUG
426 extern void memorystatus_abort_vm_map_fork(task_t);
427 #endif
428
429 #endif /* CONFIG_MEMORYSTATUS */
430
431 #endif /* MACH_BSD */
432
433 #if DEVELOPMENT || DEBUG
434 int exc_resource_threads_enabled;
435 #endif /* DEVELOPMENT || DEBUG */
436
437 /* Boot-arg that turns on fatal pac exception delivery for all first-party apps */
438 static TUNABLE(bool, enable_pac_exception, "enable_pac_exception", false);
439
440 /*
441 * Defaults for controllable EXC_GUARD behaviors
442 *
443 * Internal builds are fatal by default (except BRIDGE).
444 * Create an alternate set of defaults for special processes by name.
445 */
446 struct task_exc_guard_named_default {
447 char *name;
448 uint32_t behavior;
449 };
450 #define _TASK_EXC_GUARD_MP_CORPSE (TASK_EXC_GUARD_MP_DELIVER | TASK_EXC_GUARD_MP_CORPSE)
451 #define _TASK_EXC_GUARD_MP_ONCE (_TASK_EXC_GUARD_MP_CORPSE | TASK_EXC_GUARD_MP_ONCE)
452 #define _TASK_EXC_GUARD_MP_FATAL (TASK_EXC_GUARD_MP_DELIVER | TASK_EXC_GUARD_MP_FATAL)
453
454 #define _TASK_EXC_GUARD_VM_CORPSE (TASK_EXC_GUARD_VM_DELIVER | TASK_EXC_GUARD_VM_ONCE)
455 #define _TASK_EXC_GUARD_VM_ONCE (_TASK_EXC_GUARD_VM_CORPSE | TASK_EXC_GUARD_VM_ONCE)
456 #define _TASK_EXC_GUARD_VM_FATAL (TASK_EXC_GUARD_VM_DELIVER | TASK_EXC_GUARD_VM_FATAL)
457
458 #define _TASK_EXC_GUARD_ALL_CORPSE (_TASK_EXC_GUARD_MP_CORPSE | _TASK_EXC_GUARD_VM_CORPSE)
459 #define _TASK_EXC_GUARD_ALL_ONCE (_TASK_EXC_GUARD_MP_ONCE | _TASK_EXC_GUARD_VM_ONCE)
460 #define _TASK_EXC_GUARD_ALL_FATAL (_TASK_EXC_GUARD_MP_FATAL | _TASK_EXC_GUARD_VM_FATAL)
461
462 /* cannot turn off FATAL and DELIVER bit if set */
463 uint32_t task_exc_guard_no_unset_mask = TASK_EXC_GUARD_MP_FATAL | TASK_EXC_GUARD_VM_FATAL |
464 TASK_EXC_GUARD_MP_DELIVER | TASK_EXC_GUARD_VM_DELIVER;
465 /* cannot turn on ONCE bit if unset */
466 uint32_t task_exc_guard_no_set_mask = TASK_EXC_GUARD_MP_ONCE | TASK_EXC_GUARD_VM_ONCE;
467
468 #if !defined(XNU_TARGET_OS_BRIDGE)
469
470 uint32_t task_exc_guard_default = _TASK_EXC_GUARD_ALL_FATAL;
471 uint32_t task_exc_guard_config_mask = TASK_EXC_GUARD_MP_ALL | TASK_EXC_GUARD_VM_ALL;
472 /*
473 * These "by-process-name" default overrides are intended to be a short-term fix to
474 * quickly get over races between changes introducing new EXC_GUARD raising behaviors
475 * in some process and a change in default behavior for same. We should ship with
476 * these lists empty (by fixing the bugs, or explicitly changing the task's EXC_GUARD
477 * exception behavior via task_set_exc_guard_behavior()).
478 *
479 * XXX Remember to add/remove TASK_EXC_GUARD_HONOR_NAMED_DEFAULTS back to
480 * task_exc_guard_default when transitioning this list between empty and
481 * non-empty.
482 */
483 static struct task_exc_guard_named_default task_exc_guard_named_defaults[] = {};
484
485 #else /* !defined(XNU_TARGET_OS_BRIDGE) */
486
487 uint32_t task_exc_guard_default = _TASK_EXC_GUARD_ALL_ONCE;
488 uint32_t task_exc_guard_config_mask = TASK_EXC_GUARD_MP_ALL | TASK_EXC_GUARD_VM_ALL;
489 static struct task_exc_guard_named_default task_exc_guard_named_defaults[] = {};
490
491 #endif /* !defined(XNU_TARGET_OS_BRIDGE) */
492
493 /* Forwards */
494
495 static void task_hold_locked(task_t task);
496 static void task_wait_locked(task_t task, boolean_t until_not_runnable);
497 static void task_release_locked(task_t task);
498 extern task_t proc_get_task_raw(void *proc);
499 extern void task_ref_hold_proc_task_struct(task_t task);
500 extern void task_release_proc_task_struct(task_t task);
501
502 static void task_synchronizer_destroy_all(task_t task);
503 static os_ref_count_t
504 task_add_turnstile_watchports_locked(
505 task_t task,
506 struct task_watchports *watchports,
507 struct task_watchport_elem **previous_elem_array,
508 ipc_port_t *portwatch_ports,
509 uint32_t portwatch_count);
510
511 static os_ref_count_t
512 task_remove_turnstile_watchports_locked(
513 task_t task,
514 struct task_watchports *watchports,
515 ipc_port_t *port_freelist);
516
517 static struct task_watchports *
518 task_watchports_alloc_init(
519 task_t task,
520 thread_t thread,
521 uint32_t count);
522
523 static void
524 task_watchports_deallocate(
525 struct task_watchports *watchports);
526
527 void
task_set_64bit(task_t task,boolean_t is_64bit,boolean_t is_64bit_data)528 task_set_64bit(
529 task_t task,
530 boolean_t is_64bit,
531 boolean_t is_64bit_data)
532 {
533 #if defined(__i386__) || defined(__x86_64__) || defined(__arm64__)
534 thread_t thread;
535 #endif /* defined(__i386__) || defined(__x86_64__) || defined(__arm64__) */
536
537 task_lock(task);
538
539 /*
540 * Switching to/from 64-bit address spaces
541 */
542 if (is_64bit) {
543 if (!task_has_64Bit_addr(task)) {
544 task_set_64Bit_addr(task);
545 }
546 } else {
547 if (task_has_64Bit_addr(task)) {
548 task_clear_64Bit_addr(task);
549 }
550 }
551
552 /*
553 * Switching to/from 64-bit register state.
554 */
555 if (is_64bit_data) {
556 if (task_has_64Bit_data(task)) {
557 goto out;
558 }
559
560 task_set_64Bit_data(task);
561 } else {
562 if (!task_has_64Bit_data(task)) {
563 goto out;
564 }
565
566 task_clear_64Bit_data(task);
567 }
568
569 /* FIXME: On x86, the thread save state flavor can diverge from the
570 * task's 64-bit feature flag due to the 32-bit/64-bit register save
571 * state dichotomy. Since we can be pre-empted in this interval,
572 * certain routines may observe the thread as being in an inconsistent
573 * state with respect to its task's 64-bitness.
574 */
575
576 #if defined(__x86_64__) || defined(__arm64__)
577 queue_iterate(&task->threads, thread, thread_t, task_threads) {
578 thread_mtx_lock(thread);
579 machine_thread_switch_addrmode(thread);
580 thread_mtx_unlock(thread);
581 }
582 #endif /* defined(__x86_64__) || defined(__arm64__) */
583
584 out:
585 task_unlock(task);
586 }
587
588 bool
task_get_64bit_addr(task_t task)589 task_get_64bit_addr(task_t task)
590 {
591 return task_has_64Bit_addr(task);
592 }
593
594 bool
task_get_64bit_data(task_t task)595 task_get_64bit_data(task_t task)
596 {
597 return task_has_64Bit_data(task);
598 }
599
600 void
task_set_platform_binary(task_t task,boolean_t is_platform)601 task_set_platform_binary(
602 task_t task,
603 boolean_t is_platform)
604 {
605 if (is_platform) {
606 task_ro_flags_set(task, TFRO_PLATFORM);
607 } else {
608 task_ro_flags_clear(task, TFRO_PLATFORM);
609 }
610 }
611
612 boolean_t
task_get_platform_binary(task_t task)613 task_get_platform_binary(task_t task)
614 {
615 return (task_ro_flags_get(task) & TFRO_PLATFORM) != 0;
616 }
617
618 void
task_set_immovable_pinned(task_t task)619 task_set_immovable_pinned(task_t task)
620 {
621 ipc_task_set_immovable_pinned(task);
622 }
623
624 /*
625 * Set or clear per-task TF_CA_CLIENT_WI flag according to specified argument.
626 * Returns "false" if flag is already set, and "true" in other cases.
627 */
628 bool
task_set_ca_client_wi(task_t task,boolean_t set_or_clear)629 task_set_ca_client_wi(
630 task_t task,
631 boolean_t set_or_clear)
632 {
633 bool ret = true;
634 task_lock(task);
635 if (set_or_clear) {
636 /* Tasks can have only one CA_CLIENT work interval */
637 if (task->t_flags & TF_CA_CLIENT_WI) {
638 ret = false;
639 } else {
640 task->t_flags |= TF_CA_CLIENT_WI;
641 }
642 } else {
643 task->t_flags &= ~TF_CA_CLIENT_WI;
644 }
645 task_unlock(task);
646 return ret;
647 }
648
649 /*
650 * task_set_dyld_info() is called at most three times.
651 * 1) at task struct creation to set addr/size to zero.
652 * 2) in mach_loader.c to set location of __all_image_info section in loaded dyld
653 * 3) is from dyld itself to update location of all_image_info
654 * For security any calls after that are ignored. The TF_DYLD_ALL_IMAGE_SET bit is used to determine state.
655 */
656 kern_return_t
task_set_dyld_info(task_t task,mach_vm_address_t addr,mach_vm_size_t size)657 task_set_dyld_info(
658 task_t task,
659 mach_vm_address_t addr,
660 mach_vm_size_t size)
661 {
662 mach_vm_address_t end;
663 if (os_add_overflow(addr, size, &end)) {
664 return KERN_FAILURE;
665 }
666
667 task_lock(task);
668 /* don't accept updates if all_image_info_addr is final */
669 if ((task->t_flags & TF_DYLD_ALL_IMAGE_FINAL) == 0) {
670 bool inputNonZero = ((addr != 0) || (size != 0));
671 bool currentNonZero = ((task->all_image_info_addr != 0) || (task->all_image_info_size != 0));
672 task->all_image_info_addr = addr;
673 task->all_image_info_size = size;
674 /* can only change from a non-zero value to another non-zero once */
675 if (inputNonZero && currentNonZero) {
676 task->t_flags |= TF_DYLD_ALL_IMAGE_FINAL;
677 }
678 task_unlock(task);
679 return KERN_SUCCESS;
680 } else {
681 task_unlock(task);
682 return KERN_FAILURE;
683 }
684 }
685
686 bool
task_donates_own_pages(task_t task)687 task_donates_own_pages(
688 task_t task)
689 {
690 return task->donates_own_pages;
691 }
692
693 void
task_set_mach_header_address(task_t task,mach_vm_address_t addr)694 task_set_mach_header_address(
695 task_t task,
696 mach_vm_address_t addr)
697 {
698 task_lock(task);
699 task->mach_header_vm_address = addr;
700 task_unlock(task);
701 }
702
703 void
task_bank_reset(__unused task_t task)704 task_bank_reset(__unused task_t task)
705 {
706 if (task->bank_context != NULL) {
707 bank_task_destroy(task);
708 }
709 }
710
711 /*
712 * NOTE: This should only be called when the P_LINTRANSIT
713 * flag is set (the proc_trans lock is held) on the
714 * proc associated with the task.
715 */
716 void
task_bank_init(__unused task_t task)717 task_bank_init(__unused task_t task)
718 {
719 if (task->bank_context != NULL) {
720 panic("Task bank init called with non null bank context for task: %p and bank_context: %p", task, task->bank_context);
721 }
722 bank_task_initialize(task);
723 }
724
725 void
task_set_did_exec_flag(task_t task)726 task_set_did_exec_flag(task_t task)
727 {
728 task->t_procflags |= TPF_DID_EXEC;
729 }
730
731 void
task_clear_exec_copy_flag(task_t task)732 task_clear_exec_copy_flag(task_t task)
733 {
734 task->t_procflags &= ~TPF_EXEC_COPY;
735 }
736
737 event_t
task_get_return_wait_event(task_t task)738 task_get_return_wait_event(task_t task)
739 {
740 return (event_t)&task->returnwait_inheritor;
741 }
742
743 void
task_clear_return_wait(task_t task,uint32_t flags)744 task_clear_return_wait(task_t task, uint32_t flags)
745 {
746 if (flags & TCRW_CLEAR_INITIAL_WAIT) {
747 thread_wakeup(task_get_return_wait_event(task));
748 }
749
750 if (flags & TCRW_CLEAR_FINAL_WAIT) {
751 is_write_lock(task->itk_space);
752
753 task->t_returnwaitflags &= ~TRW_LRETURNWAIT;
754 task->returnwait_inheritor = NULL;
755
756 if (task->t_returnwaitflags & TRW_LRETURNWAITER) {
757 struct turnstile *turnstile = turnstile_prepare_hash((uintptr_t) task_get_return_wait_event(task),
758 TURNSTILE_ULOCK);
759
760 waitq_wakeup64_all(&turnstile->ts_waitq,
761 CAST_EVENT64_T(task_get_return_wait_event(task)),
762 THREAD_AWAKENED, WAITQ_UPDATE_INHERITOR);
763
764 turnstile_update_inheritor_complete(turnstile, TURNSTILE_INTERLOCK_HELD);
765
766 turnstile_complete_hash((uintptr_t) task_get_return_wait_event(task), TURNSTILE_ULOCK);
767 turnstile_cleanup();
768 task->t_returnwaitflags &= ~TRW_LRETURNWAITER;
769 }
770 is_write_unlock(task->itk_space);
771 }
772 }
773
774 void __attribute__((noreturn))
task_wait_to_return(void)775 task_wait_to_return(void)
776 {
777 task_t task = current_task();
778
779 is_write_lock(task->itk_space);
780
781 if (task->t_returnwaitflags & TRW_LRETURNWAIT) {
782 struct turnstile *turnstile = turnstile_prepare_hash((uintptr_t) task_get_return_wait_event(task),
783 TURNSTILE_ULOCK);
784
785 do {
786 task->t_returnwaitflags |= TRW_LRETURNWAITER;
787 turnstile_update_inheritor(turnstile, task->returnwait_inheritor,
788 (TURNSTILE_DELAYED_UPDATE | TURNSTILE_INHERITOR_THREAD));
789
790 waitq_assert_wait64(&turnstile->ts_waitq,
791 CAST_EVENT64_T(task_get_return_wait_event(task)),
792 THREAD_UNINT, TIMEOUT_WAIT_FOREVER);
793
794 is_write_unlock(task->itk_space);
795
796 turnstile_update_inheritor_complete(turnstile, TURNSTILE_INTERLOCK_NOT_HELD);
797
798 thread_block(THREAD_CONTINUE_NULL);
799
800 is_write_lock(task->itk_space);
801 } while (task->t_returnwaitflags & TRW_LRETURNWAIT);
802
803 turnstile_complete_hash((uintptr_t) task_get_return_wait_event(task), TURNSTILE_ULOCK);
804 }
805
806 is_write_unlock(task->itk_space);
807 turnstile_cleanup();
808
809
810 #if CONFIG_MACF
811 /*
812 * Before jumping to userspace and allowing this process to execute any code,
813 * notify any interested parties.
814 */
815 mac_proc_notify_exec_complete(current_proc());
816 #endif
817
818 thread_bootstrap_return();
819 }
820
821 boolean_t
task_is_exec_copy(task_t task)822 task_is_exec_copy(task_t task)
823 {
824 return task_is_exec_copy_internal(task);
825 }
826
827 boolean_t
task_did_exec(task_t task)828 task_did_exec(task_t task)
829 {
830 return task_did_exec_internal(task);
831 }
832
833 boolean_t
task_is_active(task_t task)834 task_is_active(task_t task)
835 {
836 return task->active;
837 }
838
839 boolean_t
task_is_halting(task_t task)840 task_is_halting(task_t task)
841 {
842 return task->halting;
843 }
844
845 void
task_init(void)846 task_init(void)
847 {
848 /*
849 * Configure per-task memory limit.
850 * The boot-arg is interpreted as Megabytes,
851 * and takes precedence over the device tree.
852 * Setting the boot-arg to 0 disables task limits.
853 */
854 if (!PE_parse_boot_argn("max_task_pmem", &max_task_footprint_mb,
855 sizeof(max_task_footprint_mb))) {
856 /*
857 * No limit was found in boot-args, so go look in the device tree.
858 */
859 if (!PE_get_default("kern.max_task_pmem", &max_task_footprint_mb,
860 sizeof(max_task_footprint_mb))) {
861 /*
862 * No limit was found in device tree.
863 */
864 max_task_footprint_mb = 0;
865 }
866 }
867
868 if (max_task_footprint_mb != 0) {
869 #if CONFIG_MEMORYSTATUS
870 if (max_task_footprint_mb < 50) {
871 printf("Warning: max_task_pmem %d below minimum.\n",
872 max_task_footprint_mb);
873 max_task_footprint_mb = 50;
874 }
875 printf("Limiting task physical memory footprint to %d MB\n",
876 max_task_footprint_mb);
877
878 max_task_footprint = (ledger_amount_t)max_task_footprint_mb * 1024 * 1024; // Convert MB to bytes
879
880 /*
881 * Configure the per-task memory limit warning level.
882 * This is computed as a percentage.
883 */
884 max_task_footprint_warning_level = 0;
885
886 if (max_mem < 0x40000000) {
887 /*
888 * On devices with < 1GB of memory:
889 * -- set warnings to 50MB below the per-task limit.
890 */
891 if (max_task_footprint_mb > 50) {
892 max_task_footprint_warning_level = ((max_task_footprint_mb - 50) * 100) / max_task_footprint_mb;
893 }
894 } else {
895 /*
896 * On devices with >= 1GB of memory:
897 * -- set warnings to 100MB below the per-task limit.
898 */
899 if (max_task_footprint_mb > 100) {
900 max_task_footprint_warning_level = ((max_task_footprint_mb - 100) * 100) / max_task_footprint_mb;
901 }
902 }
903
904 /*
905 * Never allow warning level to land below the default.
906 */
907 if (max_task_footprint_warning_level < PHYS_FOOTPRINT_WARNING_LEVEL) {
908 max_task_footprint_warning_level = PHYS_FOOTPRINT_WARNING_LEVEL;
909 }
910
911 printf("Limiting task physical memory warning to %d%%\n", max_task_footprint_warning_level);
912
913 #else
914 printf("Warning: max_task_pmem specified, but jetsam not configured; ignoring.\n");
915 #endif /* CONFIG_MEMORYSTATUS */
916 }
917
918 #if DEVELOPMENT || DEBUG
919 if (!PE_parse_boot_argn("exc_resource_threads",
920 &exc_resource_threads_enabled,
921 sizeof(exc_resource_threads_enabled))) {
922 exc_resource_threads_enabled = 1;
923 }
924 PE_parse_boot_argn("task_exc_guard_default",
925 &task_exc_guard_default,
926 sizeof(task_exc_guard_default));
927 #endif /* DEVELOPMENT || DEBUG */
928
929 #if CONFIG_COREDUMP
930 if (!PE_parse_boot_argn("hwm_user_cores", &hwm_user_cores,
931 sizeof(hwm_user_cores))) {
932 hwm_user_cores = 0;
933 }
934 #endif
935
936 proc_init_cpumon_params();
937
938 if (!PE_parse_boot_argn("task_wakeups_monitor_rate", &task_wakeups_monitor_rate, sizeof(task_wakeups_monitor_rate))) {
939 task_wakeups_monitor_rate = TASK_WAKEUPS_MONITOR_DEFAULT_LIMIT;
940 }
941
942 if (!PE_parse_boot_argn("task_wakeups_monitor_interval", &task_wakeups_monitor_interval, sizeof(task_wakeups_monitor_interval))) {
943 task_wakeups_monitor_interval = TASK_WAKEUPS_MONITOR_DEFAULT_INTERVAL;
944 }
945
946 if (!PE_parse_boot_argn("task_wakeups_monitor_ustackshots_trigger_pct", &task_wakeups_monitor_ustackshots_trigger_pct,
947 sizeof(task_wakeups_monitor_ustackshots_trigger_pct))) {
948 task_wakeups_monitor_ustackshots_trigger_pct = TASK_WAKEUPS_MONITOR_DEFAULT_USTACKSHOTS_TRIGGER;
949 }
950
951 if (!PE_parse_boot_argn("disable_exc_resource", &disable_exc_resource,
952 sizeof(disable_exc_resource))) {
953 disable_exc_resource = 0;
954 }
955
956 if (!PE_parse_boot_argn("task_iomon_limit_mb", &task_iomon_limit_mb, sizeof(task_iomon_limit_mb))) {
957 task_iomon_limit_mb = IOMON_DEFAULT_LIMIT;
958 }
959
960 if (!PE_parse_boot_argn("task_iomon_interval_secs", &task_iomon_interval_secs, sizeof(task_iomon_interval_secs))) {
961 task_iomon_interval_secs = IOMON_DEFAULT_INTERVAL;
962 }
963
964 if (!PE_parse_boot_argn("io_telemetry_limit", &io_telemetry_limit, sizeof(io_telemetry_limit))) {
965 io_telemetry_limit = IO_TELEMETRY_DEFAULT_LIMIT;
966 }
967
968 /*
969 * If we have coalitions, coalition_init() will call init_task_ledgers() as it
970 * sets up the ledgers for the default coalition. If we don't have coalitions,
971 * then we have to call it now.
972 */
973 #if CONFIG_COALITIONS
974 assert(task_ledger_template);
975 #else /* CONFIG_COALITIONS */
976 init_task_ledgers();
977 #endif /* CONFIG_COALITIONS */
978
979 task_ref_init();
980 task_zone_init();
981
982 #ifdef __LP64__
983 boolean_t is_64bit = TRUE;
984 #else
985 boolean_t is_64bit = FALSE;
986 #endif
987
988 kernproc = (struct proc *)zalloc_flags(proc_task_zone, Z_WAITOK | Z_ZERO);
989 kernel_task = proc_get_task_raw(kernproc);
990
991 /*
992 * Create the kernel task as the first task.
993 */
994 if (task_create_internal(TASK_NULL, NULL, NULL, FALSE,
995 is_64bit, is_64bit, TF_NONE, TPF_NONE, TWF_NONE, kernel_task) != KERN_SUCCESS) {
996 panic("task_init");
997 }
998
999 ipc_task_enable(kernel_task);
1000
1001 #if defined(HAS_APPLE_PAC)
1002 kernel_task->rop_pid = ml_default_rop_pid();
1003 kernel_task->jop_pid = ml_default_jop_pid();
1004 // kernel_task never runs at EL0, but machine_thread_state_convert_from/to_user() relies on
1005 // disable_user_jop to be false for kernel threads (e.g. in exception delivery on thread_exception_daemon)
1006 ml_task_set_disable_user_jop(kernel_task, FALSE);
1007 #endif
1008
1009 vm_map_deallocate(kernel_task->map);
1010 kernel_task->map = kernel_map;
1011 }
1012
1013 static inline void
task_zone_init(void)1014 task_zone_init(void)
1015 {
1016 proc_struct_size = roundup(proc_struct_size, task_alignment);
1017 task_struct_size = roundup(sizeof(struct task), proc_alignment);
1018 proc_and_task_size = proc_struct_size + task_struct_size;
1019
1020 proc_task_zone = zone_create_ext("proc_task", proc_and_task_size,
1021 ZC_ZFREE_CLEARMEM | ZC_SEQUESTER, ZONE_ID_PROC_TASK, NULL); /* sequester is needed for proc_rele() */
1022 }
1023
1024 /*
1025 * Task ledgers
1026 * ------------
1027 *
1028 * phys_footprint
1029 * Physical footprint: This is the sum of:
1030 * + (internal - alternate_accounting)
1031 * + (internal_compressed - alternate_accounting_compressed)
1032 * + iokit_mapped
1033 * + purgeable_nonvolatile
1034 * + purgeable_nonvolatile_compressed
1035 * + page_table
1036 *
1037 * internal
1038 * The task's anonymous memory, which on iOS is always resident.
1039 *
1040 * internal_compressed
1041 * Amount of this task's internal memory which is held by the compressor.
1042 * Such memory is no longer actually resident for the task [i.e., resident in its pmap],
1043 * and could be either decompressed back into memory, or paged out to storage, depending
1044 * on our implementation.
1045 *
1046 * iokit_mapped
1047 * IOKit mappings: The total size of all IOKit mappings in this task, regardless of
1048 * clean/dirty or internal/external state].
1049 *
1050 * alternate_accounting
1051 * The number of internal dirty pages which are part of IOKit mappings. By definition, these pages
1052 * are counted in both internal *and* iokit_mapped, so we must subtract them from the total to avoid
1053 * double counting.
1054 *
1055 * pages_grabbed
1056 * pages_grabbed counts all page grabs in a task. It is also broken out into three subtypes
1057 * which track UPL, IOPL and Kernel page grabs.
1058 */
1059 void
init_task_ledgers(void)1060 init_task_ledgers(void)
1061 {
1062 ledger_template_t t;
1063
1064 assert(task_ledger_template == NULL);
1065 assert(kernel_task == TASK_NULL);
1066
1067 #if MACH_ASSERT
1068 PE_parse_boot_argn("pmap_ledgers_panic",
1069 &pmap_ledgers_panic,
1070 sizeof(pmap_ledgers_panic));
1071 PE_parse_boot_argn("pmap_ledgers_panic_leeway",
1072 &pmap_ledgers_panic_leeway,
1073 sizeof(pmap_ledgers_panic_leeway));
1074 #endif /* MACH_ASSERT */
1075
1076 if ((t = ledger_template_create("Per-task ledger")) == NULL) {
1077 panic("couldn't create task ledger template");
1078 }
1079
1080 task_ledgers.cpu_time = ledger_entry_add(t, "cpu_time", "sched", "ns");
1081 task_ledgers.tkm_private = ledger_entry_add(t, "tkm_private",
1082 "physmem", "bytes");
1083 task_ledgers.tkm_shared = ledger_entry_add(t, "tkm_shared", "physmem",
1084 "bytes");
1085 task_ledgers.phys_mem = ledger_entry_add(t, "phys_mem", "physmem",
1086 "bytes");
1087 task_ledgers.wired_mem = ledger_entry_add(t, "wired_mem", "physmem",
1088 "bytes");
1089 task_ledgers.internal = ledger_entry_add(t, "internal", "physmem",
1090 "bytes");
1091 task_ledgers.iokit_mapped = ledger_entry_add_with_flags(t, "iokit_mapped", "mappings",
1092 "bytes", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1093 task_ledgers.alternate_accounting = ledger_entry_add_with_flags(t, "alternate_accounting", "physmem",
1094 "bytes", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1095 task_ledgers.alternate_accounting_compressed = ledger_entry_add_with_flags(t, "alternate_accounting_compressed", "physmem",
1096 "bytes", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1097 task_ledgers.page_table = ledger_entry_add_with_flags(t, "page_table", "physmem",
1098 "bytes", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1099 task_ledgers.phys_footprint = ledger_entry_add(t, "phys_footprint", "physmem",
1100 "bytes");
1101 task_ledgers.internal_compressed = ledger_entry_add(t, "internal_compressed", "physmem",
1102 "bytes");
1103 task_ledgers.reusable = ledger_entry_add(t, "reusable", "physmem", "bytes");
1104 task_ledgers.external = ledger_entry_add(t, "external", "physmem", "bytes");
1105 task_ledgers.purgeable_volatile = ledger_entry_add_with_flags(t, "purgeable_volatile", "physmem", "bytes", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1106 task_ledgers.purgeable_nonvolatile = ledger_entry_add_with_flags(t, "purgeable_nonvolatile", "physmem", "bytes", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1107 task_ledgers.purgeable_volatile_compressed = ledger_entry_add_with_flags(t, "purgeable_volatile_compress", "physmem", "bytes", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1108 task_ledgers.purgeable_nonvolatile_compressed = ledger_entry_add_with_flags(t, "purgeable_nonvolatile_compress", "physmem", "bytes", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1109 #if DEBUG || DEVELOPMENT
1110 task_ledgers.pages_grabbed = ledger_entry_add_with_flags(t, "pages_grabbed", "physmem", "count", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1111 task_ledgers.pages_grabbed_kern = ledger_entry_add_with_flags(t, "pages_grabbed_kern", "physmem", "count", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1112 task_ledgers.pages_grabbed_iopl = ledger_entry_add_with_flags(t, "pages_grabbed_iopl", "physmem", "count", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1113 task_ledgers.pages_grabbed_upl = ledger_entry_add_with_flags(t, "pages_grabbed_upl", "physmem", "count", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1114 #endif
1115 task_ledgers.tagged_nofootprint = ledger_entry_add_with_flags(t, "tagged_nofootprint", "physmem", "bytes", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1116 task_ledgers.tagged_footprint = ledger_entry_add_with_flags(t, "tagged_footprint", "physmem", "bytes", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1117 task_ledgers.tagged_nofootprint_compressed = ledger_entry_add_with_flags(t, "tagged_nofootprint_compressed", "physmem", "bytes", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1118 task_ledgers.tagged_footprint_compressed = ledger_entry_add_with_flags(t, "tagged_footprint_compressed", "physmem", "bytes", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1119 task_ledgers.network_volatile = ledger_entry_add_with_flags(t, "network_volatile", "physmem", "bytes", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1120 task_ledgers.network_nonvolatile = ledger_entry_add_with_flags(t, "network_nonvolatile", "physmem", "bytes", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1121 task_ledgers.network_volatile_compressed = ledger_entry_add_with_flags(t, "network_volatile_compressed", "physmem", "bytes", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1122 task_ledgers.network_nonvolatile_compressed = ledger_entry_add_with_flags(t, "network_nonvolatile_compressed", "physmem", "bytes", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1123 task_ledgers.media_nofootprint = ledger_entry_add_with_flags(t, "media_nofootprint", "physmem", "bytes", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1124 task_ledgers.media_footprint = ledger_entry_add_with_flags(t, "media_footprint", "physmem", "bytes", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1125 task_ledgers.media_nofootprint_compressed = ledger_entry_add_with_flags(t, "media_nofootprint_compressed", "physmem", "bytes", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1126 task_ledgers.media_footprint_compressed = ledger_entry_add_with_flags(t, "media_footprint_compressed", "physmem", "bytes", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1127 task_ledgers.graphics_nofootprint = ledger_entry_add_with_flags(t, "graphics_nofootprint", "physmem", "bytes", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1128 task_ledgers.graphics_footprint = ledger_entry_add_with_flags(t, "graphics_footprint", "physmem", "bytes", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1129 task_ledgers.graphics_nofootprint_compressed = ledger_entry_add_with_flags(t, "graphics_nofootprint_compressed", "physmem", "bytes", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1130 task_ledgers.graphics_footprint_compressed = ledger_entry_add_with_flags(t, "graphics_footprint_compressed", "physmem", "bytes", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1131 task_ledgers.neural_nofootprint = ledger_entry_add_with_flags(t, "neural_nofootprint", "physmem", "bytes", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1132 task_ledgers.neural_footprint = ledger_entry_add_with_flags(t, "neural_footprint", "physmem", "bytes", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1133 task_ledgers.neural_nofootprint_compressed = ledger_entry_add_with_flags(t, "neural_nofootprint_compressed", "physmem", "bytes", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1134 task_ledgers.neural_footprint_compressed = ledger_entry_add_with_flags(t, "neural_footprint_compressed", "physmem", "bytes", LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1135
1136 #if CONFIG_FREEZE
1137 task_ledgers.frozen_to_swap = ledger_entry_add(t, "frozen_to_swap", "physmem", "bytes");
1138 #endif /* CONFIG_FREEZE */
1139
1140 task_ledgers.platform_idle_wakeups = ledger_entry_add(t, "platform_idle_wakeups", "power",
1141 "count");
1142 task_ledgers.interrupt_wakeups = ledger_entry_add(t, "interrupt_wakeups", "power",
1143 "count");
1144
1145 #if CONFIG_SCHED_SFI
1146 sfi_class_id_t class_id, ledger_alias;
1147 for (class_id = SFI_CLASS_UNSPECIFIED; class_id < MAX_SFI_CLASS_ID; class_id++) {
1148 task_ledgers.sfi_wait_times[class_id] = -1;
1149 }
1150
1151 /* don't account for UNSPECIFIED */
1152 for (class_id = SFI_CLASS_UNSPECIFIED + 1; class_id < MAX_SFI_CLASS_ID; class_id++) {
1153 ledger_alias = sfi_get_ledger_alias_for_class(class_id);
1154 if (ledger_alias != SFI_CLASS_UNSPECIFIED) {
1155 /* Check to see if alias has been registered yet */
1156 if (task_ledgers.sfi_wait_times[ledger_alias] != -1) {
1157 task_ledgers.sfi_wait_times[class_id] = task_ledgers.sfi_wait_times[ledger_alias];
1158 } else {
1159 /* Otherwise, initialize it first */
1160 task_ledgers.sfi_wait_times[class_id] = task_ledgers.sfi_wait_times[ledger_alias] = sfi_ledger_entry_add(t, ledger_alias);
1161 }
1162 } else {
1163 task_ledgers.sfi_wait_times[class_id] = sfi_ledger_entry_add(t, class_id);
1164 }
1165
1166 if (task_ledgers.sfi_wait_times[class_id] < 0) {
1167 panic("couldn't create entries for task ledger template for SFI class 0x%x", class_id);
1168 }
1169 }
1170
1171 assert(task_ledgers.sfi_wait_times[MAX_SFI_CLASS_ID - 1] != -1);
1172 #endif /* CONFIG_SCHED_SFI */
1173
1174 task_ledgers.cpu_time_billed_to_me = ledger_entry_add(t, "cpu_time_billed_to_me", "sched", "ns");
1175 task_ledgers.cpu_time_billed_to_others = ledger_entry_add(t, "cpu_time_billed_to_others", "sched", "ns");
1176 task_ledgers.physical_writes = ledger_entry_add(t, "physical_writes", "res", "bytes");
1177 task_ledgers.logical_writes = ledger_entry_add(t, "logical_writes", "res", "bytes");
1178 task_ledgers.logical_writes_to_external = ledger_entry_add(t, "logical_writes_to_external", "res", "bytes");
1179 #if CONFIG_PHYS_WRITE_ACCT
1180 task_ledgers.fs_metadata_writes = ledger_entry_add(t, "fs_metadata_writes", "res", "bytes");
1181 #endif /* CONFIG_PHYS_WRITE_ACCT */
1182 task_ledgers.energy_billed_to_me = ledger_entry_add(t, "energy_billed_to_me", "power", "nj");
1183 task_ledgers.energy_billed_to_others = ledger_entry_add(t, "energy_billed_to_others", "power", "nj");
1184
1185 #if CONFIG_MEMORYSTATUS
1186 task_ledgers.memorystatus_dirty_time = ledger_entry_add(t, "memorystatus_dirty_time", "physmem", "ns");
1187 #endif /* CONFIG_MEMORYSTATUS */
1188
1189 task_ledgers.swapins = ledger_entry_add_with_flags(t, "swapins", "physmem", "bytes",
1190 LEDGER_ENTRY_ALLOW_PANIC_ON_NEGATIVE);
1191
1192 if ((task_ledgers.cpu_time < 0) ||
1193 (task_ledgers.tkm_private < 0) ||
1194 (task_ledgers.tkm_shared < 0) ||
1195 (task_ledgers.phys_mem < 0) ||
1196 (task_ledgers.wired_mem < 0) ||
1197 (task_ledgers.internal < 0) ||
1198 (task_ledgers.external < 0) ||
1199 (task_ledgers.reusable < 0) ||
1200 (task_ledgers.iokit_mapped < 0) ||
1201 (task_ledgers.alternate_accounting < 0) ||
1202 (task_ledgers.alternate_accounting_compressed < 0) ||
1203 (task_ledgers.page_table < 0) ||
1204 (task_ledgers.phys_footprint < 0) ||
1205 (task_ledgers.internal_compressed < 0) ||
1206 (task_ledgers.purgeable_volatile < 0) ||
1207 (task_ledgers.purgeable_nonvolatile < 0) ||
1208 (task_ledgers.purgeable_volatile_compressed < 0) ||
1209 (task_ledgers.purgeable_nonvolatile_compressed < 0) ||
1210 (task_ledgers.tagged_nofootprint < 0) ||
1211 (task_ledgers.tagged_footprint < 0) ||
1212 (task_ledgers.tagged_nofootprint_compressed < 0) ||
1213 (task_ledgers.tagged_footprint_compressed < 0) ||
1214 #if CONFIG_FREEZE
1215 (task_ledgers.frozen_to_swap < 0) ||
1216 #endif /* CONFIG_FREEZE */
1217 (task_ledgers.network_volatile < 0) ||
1218 (task_ledgers.network_nonvolatile < 0) ||
1219 (task_ledgers.network_volatile_compressed < 0) ||
1220 (task_ledgers.network_nonvolatile_compressed < 0) ||
1221 (task_ledgers.media_nofootprint < 0) ||
1222 (task_ledgers.media_footprint < 0) ||
1223 (task_ledgers.media_nofootprint_compressed < 0) ||
1224 (task_ledgers.media_footprint_compressed < 0) ||
1225 (task_ledgers.graphics_nofootprint < 0) ||
1226 (task_ledgers.graphics_footprint < 0) ||
1227 (task_ledgers.graphics_nofootprint_compressed < 0) ||
1228 (task_ledgers.graphics_footprint_compressed < 0) ||
1229 (task_ledgers.neural_nofootprint < 0) ||
1230 (task_ledgers.neural_footprint < 0) ||
1231 (task_ledgers.neural_nofootprint_compressed < 0) ||
1232 (task_ledgers.neural_footprint_compressed < 0) ||
1233 (task_ledgers.platform_idle_wakeups < 0) ||
1234 (task_ledgers.interrupt_wakeups < 0) ||
1235 (task_ledgers.cpu_time_billed_to_me < 0) || (task_ledgers.cpu_time_billed_to_others < 0) ||
1236 (task_ledgers.physical_writes < 0) ||
1237 (task_ledgers.logical_writes < 0) ||
1238 (task_ledgers.logical_writes_to_external < 0) ||
1239 #if CONFIG_PHYS_WRITE_ACCT
1240 (task_ledgers.fs_metadata_writes < 0) ||
1241 #endif /* CONFIG_PHYS_WRITE_ACCT */
1242 #if CONFIG_MEMORYSTATUS
1243 (task_ledgers.memorystatus_dirty_time < 0) ||
1244 #endif /* CONFIG_MEMORYSTATUS */
1245 (task_ledgers.energy_billed_to_me < 0) ||
1246 (task_ledgers.energy_billed_to_others < 0) ||
1247 (task_ledgers.swapins < 0)
1248 ) {
1249 panic("couldn't create entries for task ledger template");
1250 }
1251
1252 ledger_track_credit_only(t, task_ledgers.phys_footprint);
1253 ledger_track_credit_only(t, task_ledgers.internal);
1254 ledger_track_credit_only(t, task_ledgers.external);
1255 ledger_track_credit_only(t, task_ledgers.reusable);
1256
1257 ledger_track_maximum(t, task_ledgers.phys_footprint, 60);
1258 ledger_track_maximum(t, task_ledgers.phys_mem, 60);
1259 ledger_track_maximum(t, task_ledgers.internal, 60);
1260 ledger_track_maximum(t, task_ledgers.internal_compressed, 60);
1261 ledger_track_maximum(t, task_ledgers.reusable, 60);
1262 ledger_track_maximum(t, task_ledgers.external, 60);
1263 #if MACH_ASSERT
1264 if (pmap_ledgers_panic) {
1265 ledger_panic_on_negative(t, task_ledgers.phys_footprint);
1266 ledger_panic_on_negative(t, task_ledgers.page_table);
1267 ledger_panic_on_negative(t, task_ledgers.internal);
1268 ledger_panic_on_negative(t, task_ledgers.iokit_mapped);
1269 ledger_panic_on_negative(t, task_ledgers.alternate_accounting);
1270 ledger_panic_on_negative(t, task_ledgers.alternate_accounting_compressed);
1271 ledger_panic_on_negative(t, task_ledgers.purgeable_volatile);
1272 ledger_panic_on_negative(t, task_ledgers.purgeable_nonvolatile);
1273 ledger_panic_on_negative(t, task_ledgers.purgeable_volatile_compressed);
1274 ledger_panic_on_negative(t, task_ledgers.purgeable_nonvolatile_compressed);
1275 #if CONFIG_PHYS_WRITE_ACCT
1276 ledger_panic_on_negative(t, task_ledgers.fs_metadata_writes);
1277 #endif /* CONFIG_PHYS_WRITE_ACCT */
1278
1279 ledger_panic_on_negative(t, task_ledgers.tagged_nofootprint);
1280 ledger_panic_on_negative(t, task_ledgers.tagged_footprint);
1281 ledger_panic_on_negative(t, task_ledgers.tagged_nofootprint_compressed);
1282 ledger_panic_on_negative(t, task_ledgers.tagged_footprint_compressed);
1283 ledger_panic_on_negative(t, task_ledgers.network_volatile);
1284 ledger_panic_on_negative(t, task_ledgers.network_nonvolatile);
1285 ledger_panic_on_negative(t, task_ledgers.network_volatile_compressed);
1286 ledger_panic_on_negative(t, task_ledgers.network_nonvolatile_compressed);
1287 ledger_panic_on_negative(t, task_ledgers.media_nofootprint);
1288 ledger_panic_on_negative(t, task_ledgers.media_footprint);
1289 ledger_panic_on_negative(t, task_ledgers.media_nofootprint_compressed);
1290 ledger_panic_on_negative(t, task_ledgers.media_footprint_compressed);
1291 ledger_panic_on_negative(t, task_ledgers.graphics_nofootprint);
1292 ledger_panic_on_negative(t, task_ledgers.graphics_footprint);
1293 ledger_panic_on_negative(t, task_ledgers.graphics_nofootprint_compressed);
1294 ledger_panic_on_negative(t, task_ledgers.graphics_footprint_compressed);
1295 ledger_panic_on_negative(t, task_ledgers.neural_nofootprint);
1296 ledger_panic_on_negative(t, task_ledgers.neural_footprint);
1297 ledger_panic_on_negative(t, task_ledgers.neural_nofootprint_compressed);
1298 ledger_panic_on_negative(t, task_ledgers.neural_footprint_compressed);
1299 }
1300 #endif /* MACH_ASSERT */
1301
1302 #if CONFIG_MEMORYSTATUS
1303 ledger_set_callback(t, task_ledgers.phys_footprint, task_footprint_exceeded, NULL, NULL);
1304 #endif /* CONFIG_MEMORYSTATUS */
1305
1306 ledger_set_callback(t, task_ledgers.interrupt_wakeups,
1307 task_wakeups_rate_exceeded, NULL, NULL);
1308 ledger_set_callback(t, task_ledgers.physical_writes, task_io_rate_exceeded, (void *)FLAVOR_IO_PHYSICAL_WRITES, NULL);
1309
1310 #if !XNU_MONITOR
1311 ledger_template_complete(t);
1312 #else /* !XNU_MONITOR */
1313 ledger_template_complete_secure_alloc(t);
1314 #endif /* XNU_MONITOR */
1315 task_ledger_template = t;
1316 }
1317
1318 /* Create a task, but leave the task ports disabled */
1319 kern_return_t
task_create_internal(task_t parent_task,proc_ro_t proc_ro,coalition_t * parent_coalitions __unused,boolean_t inherit_memory,boolean_t is_64bit __unused,boolean_t is_64bit_data,uint32_t t_flags,uint32_t t_procflags,uint8_t t_returnwaitflags,task_t child_task)1320 task_create_internal(
1321 task_t parent_task, /* Null-able */
1322 proc_ro_t proc_ro,
1323 coalition_t *parent_coalitions __unused,
1324 boolean_t inherit_memory,
1325 boolean_t is_64bit __unused,
1326 boolean_t is_64bit_data,
1327 uint32_t t_flags,
1328 uint32_t t_procflags,
1329 uint8_t t_returnwaitflags,
1330 task_t child_task)
1331 {
1332 task_t new_task;
1333 vm_shared_region_t shared_region;
1334 ledger_t ledger = NULL;
1335 struct task_ro_data task_ro_data = {};
1336 uint32_t parent_t_flags_ro = 0;
1337
1338 new_task = child_task;
1339
1340 if (task_ref_count_init(new_task) != KERN_SUCCESS) {
1341 return KERN_RESOURCE_SHORTAGE;
1342 }
1343
1344 /* allocate with active entries */
1345 assert(task_ledger_template != NULL);
1346 ledger = ledger_instantiate(task_ledger_template, LEDGER_CREATE_ACTIVE_ENTRIES);
1347 if (ledger == NULL) {
1348 task_ref_count_fini(new_task);
1349 return KERN_RESOURCE_SHORTAGE;
1350 }
1351
1352 counter_alloc(&(new_task->faults));
1353
1354 #if defined(HAS_APPLE_PAC)
1355 ml_task_set_rop_pid(new_task, parent_task, inherit_memory);
1356 ml_task_set_jop_pid(new_task, parent_task, inherit_memory);
1357 ml_task_set_disable_user_jop(new_task, inherit_memory ? parent_task->disable_user_jop : FALSE);
1358 #endif
1359
1360
1361 new_task->ledger = ledger;
1362
1363 /* if inherit_memory is true, parent_task MUST not be NULL */
1364 if (!(t_flags & TF_CORPSE_FORK) && inherit_memory) {
1365 #if CONFIG_DEFERRED_RECLAIM
1366 if (parent_task->deferred_reclamation_metadata) {
1367 /*
1368 * Prevent concurrent reclaims while we're forking the parent_task's map,
1369 * so that the child's map is in sync with the forked reclamation
1370 * metadata.
1371 */
1372 vm_deferred_reclamation_buffer_lock(parent_task->deferred_reclamation_metadata);
1373 }
1374 #endif /* CONFIG_DEFERRED_RECLAIM */
1375 new_task->map = vm_map_fork(ledger, parent_task->map, 0);
1376 #if CONFIG_DEFERRED_RECLAIM
1377 if (parent_task->deferred_reclamation_metadata) {
1378 new_task->deferred_reclamation_metadata =
1379 vm_deferred_reclamation_buffer_fork(new_task, parent_task->deferred_reclamation_metadata);
1380 }
1381 #endif /* CONFIG_DEFERRED_RECLAIM */
1382 } else {
1383 unsigned int pmap_flags = is_64bit ? PMAP_CREATE_64BIT : 0;
1384 pmap_t pmap = pmap_create_options(ledger, 0, pmap_flags);
1385 if (pmap == NULL) {
1386 counter_free(&new_task->faults);
1387 ledger_dereference(ledger);
1388 task_ref_count_fini(new_task);
1389 return KERN_RESOURCE_SHORTAGE;
1390 }
1391 new_task->map = vm_map_create_options(pmap,
1392 (vm_map_offset_t)(VM_MIN_ADDRESS),
1393 (vm_map_offset_t)(VM_MAX_ADDRESS),
1394 VM_MAP_CREATE_PAGEABLE);
1395 }
1396
1397 if (new_task->map == NULL) {
1398 counter_free(&new_task->faults);
1399 ledger_dereference(ledger);
1400 task_ref_count_fini(new_task);
1401 return KERN_RESOURCE_SHORTAGE;
1402 }
1403
1404 #if defined(CONFIG_SCHED_MULTIQ)
1405 new_task->sched_group = sched_group_create();
1406 #endif
1407
1408 /* Inherit address space and memlock limit from parent */
1409 if (parent_task) {
1410 vm_map_set_size_limit(new_task->map, parent_task->map->size_limit);
1411 vm_map_set_data_limit(new_task->map, parent_task->map->data_limit);
1412 vm_map_set_user_wire_limit(new_task->map, (vm_size_t)parent_task->map->user_wire_limit);
1413 }
1414
1415 lck_mtx_init(&new_task->lock, &task_lck_grp, &task_lck_attr);
1416 queue_init(&new_task->threads);
1417 new_task->suspend_count = 0;
1418 new_task->thread_count = 0;
1419 new_task->active_thread_count = 0;
1420 new_task->user_stop_count = 0;
1421 new_task->legacy_stop_count = 0;
1422 new_task->active = TRUE;
1423 new_task->halting = FALSE;
1424 new_task->priv_flags = 0;
1425 new_task->t_flags = t_flags;
1426 new_task->t_procflags = t_procflags;
1427 new_task->t_returnwaitflags = t_returnwaitflags;
1428 new_task->returnwait_inheritor = current_thread();
1429 new_task->importance = 0;
1430 new_task->crashed_thread_id = 0;
1431 new_task->exec_token = 0;
1432 new_task->watchports = NULL;
1433 new_task->t_rr_ranges = NULL;
1434
1435 new_task->bank_context = NULL;
1436
1437 if (parent_task) {
1438 parent_t_flags_ro = task_ro_flags_get(parent_task);
1439 }
1440
1441 #if __has_feature(ptrauth_calls)
1442 /* Inherit the pac exception flags from parent if in fork */
1443 if (parent_task && inherit_memory) {
1444 task_ro_data.t_flags_ro |= (parent_t_flags_ro & (TFRO_PAC_ENFORCE_USER_STATE |
1445 TFRO_PAC_EXC_FATAL));
1446 }
1447 #endif
1448
1449 #ifdef MACH_BSD
1450 new_task->corpse_info = NULL;
1451 #endif /* MACH_BSD */
1452
1453 /* kern_task not created by this function has unique id 0, start with 1 here. */
1454 task_set_uniqueid(new_task);
1455
1456 #if CONFIG_MACF
1457 set_task_crash_label(new_task, NULL);
1458
1459 task_ro_data.task_filters.mach_trap_filter_mask = NULL;
1460 task_ro_data.task_filters.mach_kobj_filter_mask = NULL;
1461 #endif
1462
1463 #if CONFIG_MEMORYSTATUS
1464 if (max_task_footprint != 0) {
1465 ledger_set_limit(ledger, task_ledgers.phys_footprint, max_task_footprint, PHYS_FOOTPRINT_WARNING_LEVEL);
1466 }
1467 #endif /* CONFIG_MEMORYSTATUS */
1468
1469 if (task_wakeups_monitor_rate != 0) {
1470 uint32_t flags = WAKEMON_ENABLE | WAKEMON_SET_DEFAULTS;
1471 int32_t rate; // Ignored because of WAKEMON_SET_DEFAULTS
1472 task_wakeups_monitor_ctl(new_task, &flags, &rate);
1473 }
1474
1475 #if CONFIG_IO_ACCOUNTING
1476 uint32_t flags = IOMON_ENABLE;
1477 task_io_monitor_ctl(new_task, &flags);
1478 #endif /* CONFIG_IO_ACCOUNTING */
1479
1480 machine_task_init(new_task, parent_task, inherit_memory);
1481
1482 new_task->task_debug = NULL;
1483
1484 #if DEVELOPMENT || DEBUG
1485 new_task->task_unnested = FALSE;
1486 new_task->task_disconnected_count = 0;
1487 #endif
1488 queue_init(&new_task->semaphore_list);
1489 new_task->semaphores_owned = 0;
1490
1491 new_task->vtimers = 0;
1492
1493 new_task->shared_region = NULL;
1494
1495 new_task->affinity_space = NULL;
1496
1497 new_task->t_kpc = 0;
1498
1499 new_task->pidsuspended = FALSE;
1500 new_task->frozen = FALSE;
1501 new_task->changing_freeze_state = FALSE;
1502 new_task->rusage_cpu_flags = 0;
1503 new_task->rusage_cpu_percentage = 0;
1504 new_task->rusage_cpu_interval = 0;
1505 new_task->rusage_cpu_deadline = 0;
1506 new_task->rusage_cpu_callt = NULL;
1507 #if MACH_ASSERT
1508 new_task->suspends_outstanding = 0;
1509 #endif
1510 recount_task_init(&new_task->tk_recount);
1511
1512 #if HYPERVISOR
1513 new_task->hv_task_target = NULL;
1514 #endif /* HYPERVISOR */
1515
1516 #if CONFIG_TASKWATCH
1517 queue_init(&new_task->task_watchers);
1518 new_task->num_taskwatchers = 0;
1519 new_task->watchapplying = 0;
1520 #endif /* CONFIG_TASKWATCH */
1521
1522 new_task->mem_notify_reserved = 0;
1523 new_task->memlimit_attrs_reserved = 0;
1524
1525 new_task->requested_policy = default_task_requested_policy;
1526 new_task->effective_policy = default_task_effective_policy;
1527
1528 new_task->task_shared_region_slide = -1;
1529
1530 if (parent_task != NULL) {
1531 task_ro_data.task_tokens.sec_token = *task_get_sec_token(parent_task);
1532 task_ro_data.task_tokens.audit_token = *task_get_audit_token(parent_task);
1533
1534 /* only inherit the option bits, no effect until task_set_immovable_pinned() */
1535 task_ro_data.task_control_port_options = task_get_control_port_options(parent_task);
1536
1537 task_ro_data.t_flags_ro |= parent_t_flags_ro & TFRO_FILTER_MSG;
1538 } else {
1539 task_ro_data.task_tokens.sec_token = KERNEL_SECURITY_TOKEN;
1540 task_ro_data.task_tokens.audit_token = KERNEL_AUDIT_TOKEN;
1541
1542 task_ro_data.task_control_port_options = TASK_CONTROL_PORT_OPTIONS_NONE;
1543 }
1544
1545 /* must set before task_importance_init_from_parent: */
1546 if (proc_ro != NULL) {
1547 new_task->bsd_info_ro = proc_ro_ref_task(proc_ro, new_task, &task_ro_data);
1548 } else {
1549 new_task->bsd_info_ro = proc_ro_alloc(NULL, NULL, new_task, &task_ro_data);
1550 }
1551
1552 ipc_task_init(new_task, parent_task);
1553
1554 task_importance_init_from_parent(new_task, parent_task);
1555
1556 new_task->corpse_vmobject_list = NULL;
1557
1558 if (parent_task != TASK_NULL) {
1559 /* inherit the parent's shared region */
1560 shared_region = vm_shared_region_get(parent_task);
1561 if (shared_region != NULL) {
1562 vm_shared_region_set(new_task, shared_region);
1563 }
1564
1565 #if __has_feature(ptrauth_calls)
1566 /* use parent's shared_region_id */
1567 char *shared_region_id = task_get_vm_shared_region_id_and_jop_pid(parent_task, NULL);
1568 if (shared_region_id != NULL) {
1569 shared_region_key_alloc(shared_region_id, FALSE, 0); /* get a reference */
1570 }
1571 task_set_shared_region_id(new_task, shared_region_id);
1572 #endif /* __has_feature(ptrauth_calls) */
1573
1574 if (task_has_64Bit_addr(parent_task)) {
1575 task_set_64Bit_addr(new_task);
1576 }
1577
1578 if (task_has_64Bit_data(parent_task)) {
1579 task_set_64Bit_data(new_task);
1580 }
1581
1582 new_task->all_image_info_addr = parent_task->all_image_info_addr;
1583 new_task->all_image_info_size = parent_task->all_image_info_size;
1584 new_task->mach_header_vm_address = 0;
1585
1586 if (inherit_memory && parent_task->affinity_space) {
1587 task_affinity_create(parent_task, new_task);
1588 }
1589
1590 new_task->pset_hint = parent_task->pset_hint = task_choose_pset(parent_task);
1591
1592 new_task->task_exc_guard = parent_task->task_exc_guard;
1593 if (parent_task->t_flags & TF_NO_SMT) {
1594 new_task->t_flags |= TF_NO_SMT;
1595 }
1596
1597 if (parent_task->t_flags & TF_USE_PSET_HINT_CLUSTER_TYPE) {
1598 new_task->t_flags |= TF_USE_PSET_HINT_CLUSTER_TYPE;
1599 }
1600
1601 if (parent_task->t_flags & TF_TECS) {
1602 new_task->t_flags |= TF_TECS;
1603 }
1604
1605 #if defined(__x86_64__)
1606 if (parent_task->t_flags & TF_INSN_COPY_OPTOUT) {
1607 new_task->t_flags |= TF_INSN_COPY_OPTOUT;
1608 }
1609 #endif
1610 new_task->priority = BASEPRI_DEFAULT;
1611 new_task->max_priority = MAXPRI_USER;
1612
1613 task_policy_create(new_task, parent_task);
1614 } else {
1615 #ifdef __LP64__
1616 if (is_64bit) {
1617 task_set_64Bit_addr(new_task);
1618 }
1619 #endif
1620
1621 if (is_64bit_data) {
1622 task_set_64Bit_data(new_task);
1623 }
1624
1625 new_task->all_image_info_addr = (mach_vm_address_t)0;
1626 new_task->all_image_info_size = (mach_vm_size_t)0;
1627
1628 new_task->pset_hint = PROCESSOR_SET_NULL;
1629
1630 new_task->task_exc_guard = TASK_EXC_GUARD_NONE;
1631
1632 if (new_task == kernel_task) {
1633 new_task->priority = BASEPRI_KERNEL;
1634 new_task->max_priority = MAXPRI_KERNEL;
1635 } else {
1636 new_task->priority = BASEPRI_DEFAULT;
1637 new_task->max_priority = MAXPRI_USER;
1638 }
1639 }
1640
1641 bzero(new_task->coalition, sizeof(new_task->coalition));
1642 for (int i = 0; i < COALITION_NUM_TYPES; i++) {
1643 queue_chain_init(new_task->task_coalition[i]);
1644 }
1645
1646 /* Allocate I/O Statistics */
1647 new_task->task_io_stats = kalloc_data(sizeof(struct io_stat_info),
1648 Z_WAITOK | Z_ZERO | Z_NOFAIL);
1649
1650 bzero(&(new_task->cpu_time_eqos_stats), sizeof(new_task->cpu_time_eqos_stats));
1651 bzero(&(new_task->cpu_time_rqos_stats), sizeof(new_task->cpu_time_rqos_stats));
1652
1653 bzero(&new_task->extmod_statistics, sizeof(new_task->extmod_statistics));
1654
1655 counter_alloc(&(new_task->pageins));
1656 counter_alloc(&(new_task->cow_faults));
1657 counter_alloc(&(new_task->messages_sent));
1658 counter_alloc(&(new_task->messages_received));
1659
1660 /* Copy resource acc. info from Parent for Corpe Forked task. */
1661 if (parent_task != NULL && (t_flags & TF_CORPSE_FORK)) {
1662 task_rollup_accounting_info(new_task, parent_task);
1663 task_store_owned_vmobject_info(new_task, parent_task);
1664 } else {
1665 /* Initialize to zero for standard fork/spawn case */
1666 new_task->total_runnable_time = 0;
1667 new_task->syscalls_mach = 0;
1668 new_task->syscalls_unix = 0;
1669 new_task->c_switch = 0;
1670 new_task->p_switch = 0;
1671 new_task->ps_switch = 0;
1672 new_task->decompressions = 0;
1673 new_task->low_mem_notified_warn = 0;
1674 new_task->low_mem_notified_critical = 0;
1675 new_task->purged_memory_warn = 0;
1676 new_task->purged_memory_critical = 0;
1677 new_task->low_mem_privileged_listener = 0;
1678 new_task->memlimit_is_active = 0;
1679 new_task->memlimit_is_fatal = 0;
1680 new_task->memlimit_active_exc_resource = 0;
1681 new_task->memlimit_inactive_exc_resource = 0;
1682 new_task->task_timer_wakeups_bin_1 = 0;
1683 new_task->task_timer_wakeups_bin_2 = 0;
1684 new_task->task_gpu_ns = 0;
1685 new_task->task_writes_counters_internal.task_immediate_writes = 0;
1686 new_task->task_writes_counters_internal.task_deferred_writes = 0;
1687 new_task->task_writes_counters_internal.task_invalidated_writes = 0;
1688 new_task->task_writes_counters_internal.task_metadata_writes = 0;
1689 new_task->task_writes_counters_external.task_immediate_writes = 0;
1690 new_task->task_writes_counters_external.task_deferred_writes = 0;
1691 new_task->task_writes_counters_external.task_invalidated_writes = 0;
1692 new_task->task_writes_counters_external.task_metadata_writes = 0;
1693 #if CONFIG_PHYS_WRITE_ACCT
1694 new_task->task_fs_metadata_writes = 0;
1695 #endif /* CONFIG_PHYS_WRITE_ACCT */
1696 }
1697
1698
1699 new_task->donates_own_pages = FALSE;
1700 #if CONFIG_COALITIONS
1701 if (!(t_flags & TF_CORPSE_FORK)) {
1702 /* TODO: there is no graceful failure path here... */
1703 if (parent_coalitions && parent_coalitions[COALITION_TYPE_RESOURCE]) {
1704 coalitions_adopt_task(parent_coalitions, new_task);
1705 if (parent_coalitions[COALITION_TYPE_JETSAM]) {
1706 new_task->donates_own_pages = coalition_is_swappable(parent_coalitions[COALITION_TYPE_JETSAM]);
1707 }
1708 } else if (parent_task && parent_task->coalition[COALITION_TYPE_RESOURCE]) {
1709 /*
1710 * all tasks at least have a resource coalition, so
1711 * if the parent has one then inherit all coalitions
1712 * the parent is a part of
1713 */
1714 coalitions_adopt_task(parent_task->coalition, new_task);
1715 if (parent_task->coalition[COALITION_TYPE_JETSAM]) {
1716 new_task->donates_own_pages = coalition_is_swappable(parent_task->coalition[COALITION_TYPE_JETSAM]);
1717 }
1718 } else {
1719 /* TODO: assert that new_task will be PID 1 (launchd) */
1720 coalitions_adopt_init_task(new_task);
1721 }
1722 /*
1723 * on exec, we need to transfer the coalition roles from the
1724 * parent task to the exec copy task.
1725 */
1726 if (parent_task && (t_procflags & TPF_EXEC_COPY)) {
1727 int coal_roles[COALITION_NUM_TYPES];
1728 task_coalition_roles(parent_task, coal_roles);
1729 (void)coalitions_set_roles(new_task->coalition, new_task, coal_roles);
1730 }
1731 } else {
1732 coalitions_adopt_corpse_task(new_task);
1733 }
1734
1735 if (new_task->coalition[COALITION_TYPE_RESOURCE] == COALITION_NULL) {
1736 panic("created task is not a member of a resource coalition");
1737 }
1738 task_set_coalition_member(new_task);
1739 #endif /* CONFIG_COALITIONS */
1740
1741 new_task->dispatchqueue_offset = 0;
1742 if (parent_task != NULL) {
1743 new_task->dispatchqueue_offset = parent_task->dispatchqueue_offset;
1744 }
1745
1746 new_task->task_can_transfer_memory_ownership = FALSE;
1747 new_task->task_volatile_objects = 0;
1748 new_task->task_nonvolatile_objects = 0;
1749 new_task->task_objects_disowning = FALSE;
1750 new_task->task_objects_disowned = FALSE;
1751 new_task->task_owned_objects = 0;
1752 queue_init(&new_task->task_objq);
1753
1754 #if CONFIG_FREEZE
1755 queue_init(&new_task->task_frozen_cseg_q);
1756 #endif /* CONFIG_FREEZE */
1757
1758 task_objq_lock_init(new_task);
1759
1760 #if __arm64__
1761 new_task->task_legacy_footprint = FALSE;
1762 new_task->task_extra_footprint_limit = FALSE;
1763 new_task->task_ios13extended_footprint_limit = FALSE;
1764 #endif /* __arm64__ */
1765 new_task->task_region_footprint = FALSE;
1766 new_task->task_has_crossed_thread_limit = FALSE;
1767 new_task->task_thread_limit = 0;
1768 #if CONFIG_SECLUDED_MEMORY
1769 new_task->task_can_use_secluded_mem = FALSE;
1770 new_task->task_could_use_secluded_mem = FALSE;
1771 new_task->task_could_also_use_secluded_mem = FALSE;
1772 new_task->task_suppressed_secluded = FALSE;
1773 #endif /* CONFIG_SECLUDED_MEMORY */
1774
1775 /*
1776 * t_flags is set up above. But since we don't
1777 * support darkwake mode being set that way
1778 * currently, we clear it out here explicitly.
1779 */
1780 new_task->t_flags &= ~(TF_DARKWAKE_MODE);
1781
1782 queue_init(&new_task->io_user_clients);
1783 new_task->loadTag = 0;
1784
1785 lck_mtx_lock(&tasks_threads_lock);
1786 queue_enter(&tasks, new_task, task_t, tasks);
1787 tasks_count++;
1788 if (tasks_suspend_state) {
1789 task_suspend_internal(new_task);
1790 }
1791 lck_mtx_unlock(&tasks_threads_lock);
1792 task_ref_hold_proc_task_struct(new_task);
1793
1794 return KERN_SUCCESS;
1795 }
1796
1797 /*
1798 * task_rollup_accounting_info
1799 *
1800 * Roll up accounting stats. Used to rollup stats
1801 * for exec copy task and corpse fork.
1802 */
1803 void
task_rollup_accounting_info(task_t to_task,task_t from_task)1804 task_rollup_accounting_info(task_t to_task, task_t from_task)
1805 {
1806 assert(from_task != to_task);
1807
1808 recount_task_copy(&to_task->tk_recount, &from_task->tk_recount);
1809 to_task->total_runnable_time = from_task->total_runnable_time;
1810 counter_add(&to_task->faults, counter_load(&from_task->faults));
1811 counter_add(&to_task->pageins, counter_load(&from_task->pageins));
1812 counter_add(&to_task->cow_faults, counter_load(&from_task->cow_faults));
1813 counter_add(&to_task->messages_sent, counter_load(&from_task->messages_sent));
1814 counter_add(&to_task->messages_received, counter_load(&from_task->messages_received));
1815 to_task->decompressions = from_task->decompressions;
1816 to_task->syscalls_mach = from_task->syscalls_mach;
1817 to_task->syscalls_unix = from_task->syscalls_unix;
1818 to_task->c_switch = from_task->c_switch;
1819 to_task->p_switch = from_task->p_switch;
1820 to_task->ps_switch = from_task->ps_switch;
1821 to_task->extmod_statistics = from_task->extmod_statistics;
1822 to_task->low_mem_notified_warn = from_task->low_mem_notified_warn;
1823 to_task->low_mem_notified_critical = from_task->low_mem_notified_critical;
1824 to_task->purged_memory_warn = from_task->purged_memory_warn;
1825 to_task->purged_memory_critical = from_task->purged_memory_critical;
1826 to_task->low_mem_privileged_listener = from_task->low_mem_privileged_listener;
1827 *to_task->task_io_stats = *from_task->task_io_stats;
1828 to_task->cpu_time_eqos_stats = from_task->cpu_time_eqos_stats;
1829 to_task->cpu_time_rqos_stats = from_task->cpu_time_rqos_stats;
1830 to_task->task_timer_wakeups_bin_1 = from_task->task_timer_wakeups_bin_1;
1831 to_task->task_timer_wakeups_bin_2 = from_task->task_timer_wakeups_bin_2;
1832 to_task->task_gpu_ns = from_task->task_gpu_ns;
1833 to_task->task_writes_counters_internal.task_immediate_writes = from_task->task_writes_counters_internal.task_immediate_writes;
1834 to_task->task_writes_counters_internal.task_deferred_writes = from_task->task_writes_counters_internal.task_deferred_writes;
1835 to_task->task_writes_counters_internal.task_invalidated_writes = from_task->task_writes_counters_internal.task_invalidated_writes;
1836 to_task->task_writes_counters_internal.task_metadata_writes = from_task->task_writes_counters_internal.task_metadata_writes;
1837 to_task->task_writes_counters_external.task_immediate_writes = from_task->task_writes_counters_external.task_immediate_writes;
1838 to_task->task_writes_counters_external.task_deferred_writes = from_task->task_writes_counters_external.task_deferred_writes;
1839 to_task->task_writes_counters_external.task_invalidated_writes = from_task->task_writes_counters_external.task_invalidated_writes;
1840 to_task->task_writes_counters_external.task_metadata_writes = from_task->task_writes_counters_external.task_metadata_writes;
1841 #if CONFIG_PHYS_WRITE_ACCT
1842 to_task->task_fs_metadata_writes = from_task->task_fs_metadata_writes;
1843 #endif /* CONFIG_PHYS_WRITE_ACCT */
1844
1845 #if CONFIG_MEMORYSTATUS
1846 ledger_rollup_entry(to_task->ledger, from_task->ledger, task_ledgers.memorystatus_dirty_time);
1847 #endif /* CONFIG_MEMORYSTATUS */
1848
1849 /* Skip ledger roll up for memory accounting entries */
1850 ledger_rollup_entry(to_task->ledger, from_task->ledger, task_ledgers.cpu_time);
1851 ledger_rollup_entry(to_task->ledger, from_task->ledger, task_ledgers.platform_idle_wakeups);
1852 ledger_rollup_entry(to_task->ledger, from_task->ledger, task_ledgers.interrupt_wakeups);
1853 #if CONFIG_SCHED_SFI
1854 for (sfi_class_id_t class_id = SFI_CLASS_UNSPECIFIED; class_id < MAX_SFI_CLASS_ID; class_id++) {
1855 ledger_rollup_entry(to_task->ledger, from_task->ledger, task_ledgers.sfi_wait_times[class_id]);
1856 }
1857 #endif
1858 ledger_rollup_entry(to_task->ledger, from_task->ledger, task_ledgers.cpu_time_billed_to_me);
1859 ledger_rollup_entry(to_task->ledger, from_task->ledger, task_ledgers.cpu_time_billed_to_others);
1860 ledger_rollup_entry(to_task->ledger, from_task->ledger, task_ledgers.physical_writes);
1861 ledger_rollup_entry(to_task->ledger, from_task->ledger, task_ledgers.logical_writes);
1862 ledger_rollup_entry(to_task->ledger, from_task->ledger, task_ledgers.energy_billed_to_me);
1863 ledger_rollup_entry(to_task->ledger, from_task->ledger, task_ledgers.energy_billed_to_others);
1864 }
1865
1866 /*
1867 * task_deallocate_internal:
1868 *
1869 * Drop a reference on a task.
1870 * Don't call this directly.
1871 */
1872 extern void task_deallocate_internal(task_t task, os_ref_count_t refs);
1873 void
task_deallocate_internal(task_t task,os_ref_count_t refs)1874 task_deallocate_internal(
1875 task_t task,
1876 os_ref_count_t refs)
1877 {
1878 ledger_amount_t credit, debit, interrupt_wakeups, platform_idle_wakeups;
1879
1880 if (task == TASK_NULL) {
1881 return;
1882 }
1883
1884 #if IMPORTANCE_INHERITANCE
1885 if (refs == 1) {
1886 /*
1887 * If last ref potentially comes from the task's importance,
1888 * disconnect it. But more task refs may be added before
1889 * that completes, so wait for the reference to go to zero
1890 * naturally (it may happen on a recursive task_deallocate()
1891 * from the ipc_importance_disconnect_task() call).
1892 */
1893 if (IIT_NULL != task->task_imp_base) {
1894 ipc_importance_disconnect_task(task);
1895 }
1896 return;
1897 }
1898 #endif /* IMPORTANCE_INHERITANCE */
1899
1900 if (refs > 0) {
1901 return;
1902 }
1903
1904 /*
1905 * The task should be dead at this point. Ensure other resources
1906 * like threads, are gone before we trash the world.
1907 */
1908 assert(queue_empty(&task->threads));
1909 assert(get_bsdtask_info(task) == NULL);
1910 assert(!is_active(task->itk_space));
1911 assert(!task->active);
1912 assert(task->active_thread_count == 0);
1913
1914 lck_mtx_lock(&tasks_threads_lock);
1915 assert(terminated_tasks_count > 0);
1916 queue_remove(&terminated_tasks, task, task_t, tasks);
1917 terminated_tasks_count--;
1918 lck_mtx_unlock(&tasks_threads_lock);
1919
1920 /*
1921 * remove the reference on bank context
1922 */
1923 task_bank_reset(task);
1924
1925 kfree_data(task->task_io_stats, sizeof(struct io_stat_info));
1926
1927 /*
1928 * Give the machine dependent code a chance
1929 * to perform cleanup before ripping apart
1930 * the task.
1931 */
1932 machine_task_terminate(task);
1933
1934 ipc_task_terminate(task);
1935
1936 /* let iokit know */
1937 iokit_task_terminate(task);
1938
1939 /* Unregister task from userspace coredumps on panic */
1940 kern_unregister_userspace_coredump(task);
1941
1942 if (task->affinity_space) {
1943 task_affinity_deallocate(task);
1944 }
1945
1946 #if MACH_ASSERT
1947 if (task->ledger != NULL &&
1948 task->map != NULL &&
1949 task->map->pmap != NULL &&
1950 task->map->pmap->ledger != NULL) {
1951 assert(task->ledger == task->map->pmap->ledger);
1952 }
1953 #endif /* MACH_ASSERT */
1954
1955 vm_owned_objects_disown(task);
1956 assert(task->task_objects_disowned);
1957 if (task->task_owned_objects != 0) {
1958 panic("task_deallocate(%p): "
1959 "volatile_objects=%d nonvolatile_objects=%d owned=%d\n",
1960 task,
1961 task->task_volatile_objects,
1962 task->task_nonvolatile_objects,
1963 task->task_owned_objects);
1964 }
1965
1966 #if CONFIG_DEFERRED_RECLAIM
1967 if (task->deferred_reclamation_metadata != NULL) {
1968 vm_deferred_reclamation_buffer_deallocate(task->deferred_reclamation_metadata);
1969 task->deferred_reclamation_metadata = NULL;
1970 }
1971 #endif /* CONFIG_DEFERRED_RECLAIM */
1972
1973 vm_map_deallocate(task->map);
1974 if (task->is_large_corpse) {
1975 assert(large_corpse_count > 0);
1976 OSDecrementAtomic(&large_corpse_count);
1977 task->is_large_corpse = false;
1978 }
1979 is_release(task->itk_space);
1980 if (task->t_rr_ranges) {
1981 restartable_ranges_release(task->t_rr_ranges);
1982 }
1983
1984 ledger_get_entries(task->ledger, task_ledgers.interrupt_wakeups,
1985 &interrupt_wakeups, &debit);
1986 ledger_get_entries(task->ledger, task_ledgers.platform_idle_wakeups,
1987 &platform_idle_wakeups, &debit);
1988
1989 #if defined(CONFIG_SCHED_MULTIQ)
1990 sched_group_destroy(task->sched_group);
1991 #endif
1992
1993 struct recount_times_mach sum = { 0 };
1994 struct recount_times_mach p_only = { 0 };
1995 recount_task_times_perf_only(task, &sum, &p_only);
1996 #if CONFIG_PERVASIVE_ENERGY
1997 uint64_t energy = recount_task_energy_nj(task);
1998 #endif /* CONFIG_PERVASIVE_ENERGY */
1999 recount_task_deinit(&task->tk_recount);
2000
2001 /* Accumulate statistics for dead tasks */
2002 lck_spin_lock(&dead_task_statistics_lock);
2003 dead_task_statistics.total_user_time += sum.rtm_user;
2004 dead_task_statistics.total_system_time += sum.rtm_system;
2005
2006 dead_task_statistics.task_interrupt_wakeups += interrupt_wakeups;
2007 dead_task_statistics.task_platform_idle_wakeups += platform_idle_wakeups;
2008
2009 dead_task_statistics.task_timer_wakeups_bin_1 += task->task_timer_wakeups_bin_1;
2010 dead_task_statistics.task_timer_wakeups_bin_2 += task->task_timer_wakeups_bin_2;
2011 dead_task_statistics.total_ptime += p_only.rtm_user + p_only.rtm_system;
2012 dead_task_statistics.total_pset_switches += task->ps_switch;
2013 dead_task_statistics.task_gpu_ns += task->task_gpu_ns;
2014 #if CONFIG_PERVASIVE_ENERGY
2015 dead_task_statistics.task_energy += energy;
2016 #endif /* CONFIG_PERVASIVE_ENERGY */
2017
2018 lck_spin_unlock(&dead_task_statistics_lock);
2019 lck_mtx_destroy(&task->lock, &task_lck_grp);
2020
2021 if (!ledger_get_entries(task->ledger, task_ledgers.tkm_private, &credit,
2022 &debit)) {
2023 OSAddAtomic64(credit, (int64_t *)&tasks_tkm_private.alloc);
2024 OSAddAtomic64(debit, (int64_t *)&tasks_tkm_private.free);
2025 }
2026 if (!ledger_get_entries(task->ledger, task_ledgers.tkm_shared, &credit,
2027 &debit)) {
2028 OSAddAtomic64(credit, (int64_t *)&tasks_tkm_shared.alloc);
2029 OSAddAtomic64(debit, (int64_t *)&tasks_tkm_shared.free);
2030 }
2031 ledger_dereference(task->ledger);
2032
2033 counter_free(&task->faults);
2034 counter_free(&task->pageins);
2035 counter_free(&task->cow_faults);
2036 counter_free(&task->messages_sent);
2037 counter_free(&task->messages_received);
2038
2039 #if CONFIG_COALITIONS
2040 task_release_coalitions(task);
2041 #endif /* CONFIG_COALITIONS */
2042
2043 bzero(task->coalition, sizeof(task->coalition));
2044
2045 #if MACH_BSD
2046 /* clean up collected information since last reference to task is gone */
2047 if (task->corpse_info) {
2048 void *corpse_info_kernel = kcdata_memory_get_begin_addr(task->corpse_info);
2049 task_crashinfo_destroy(task->corpse_info);
2050 task->corpse_info = NULL;
2051 kfree_data(corpse_info_kernel, CORPSEINFO_ALLOCATION_SIZE);
2052 }
2053 #endif
2054
2055 #if CONFIG_MACF
2056 if (get_task_crash_label(task)) {
2057 mac_exc_free_label(get_task_crash_label(task));
2058 set_task_crash_label(task, NULL);
2059 }
2060 #endif
2061
2062 assert(queue_empty(&task->task_objq));
2063 task_objq_lock_destroy(task);
2064
2065 if (task->corpse_vmobject_list) {
2066 kfree_data(task->corpse_vmobject_list,
2067 (vm_size_t)task->corpse_vmobject_list_size);
2068 }
2069
2070 task_ref_count_fini(task);
2071
2072 task->bsd_info_ro = proc_ro_release_task((proc_ro_t)task->bsd_info_ro);
2073
2074 if (task->bsd_info_ro != NULL) {
2075 proc_ro_free(task->bsd_info_ro);
2076 task->bsd_info_ro = NULL;
2077 }
2078
2079 task_release_proc_task_struct(task);
2080 }
2081
2082 /*
2083 * task_name_deallocate_mig:
2084 *
2085 * Drop a reference on a task name.
2086 */
2087 void
task_name_deallocate_mig(task_name_t task_name)2088 task_name_deallocate_mig(
2089 task_name_t task_name)
2090 {
2091 return task_deallocate_grp((task_t)task_name, TASK_GRP_MIG);
2092 }
2093
2094 /*
2095 * task_policy_set_deallocate_mig:
2096 *
2097 * Drop a reference on a task type.
2098 */
2099 void
task_policy_set_deallocate_mig(task_policy_set_t task_policy_set)2100 task_policy_set_deallocate_mig(task_policy_set_t task_policy_set)
2101 {
2102 return task_deallocate_grp((task_t)task_policy_set, TASK_GRP_MIG);
2103 }
2104
2105 /*
2106 * task_policy_get_deallocate_mig:
2107 *
2108 * Drop a reference on a task type.
2109 */
2110 void
task_policy_get_deallocate_mig(task_policy_get_t task_policy_get)2111 task_policy_get_deallocate_mig(task_policy_get_t task_policy_get)
2112 {
2113 return task_deallocate_grp((task_t)task_policy_get, TASK_GRP_MIG);
2114 }
2115
2116 /*
2117 * task_inspect_deallocate_mig:
2118 *
2119 * Drop a task inspection reference.
2120 */
2121 void
task_inspect_deallocate_mig(task_inspect_t task_inspect)2122 task_inspect_deallocate_mig(
2123 task_inspect_t task_inspect)
2124 {
2125 return task_deallocate_grp((task_t)task_inspect, TASK_GRP_MIG);
2126 }
2127
2128 /*
2129 * task_read_deallocate_mig:
2130 *
2131 * Drop a reference on task read port.
2132 */
2133 void
task_read_deallocate_mig(task_read_t task_read)2134 task_read_deallocate_mig(
2135 task_read_t task_read)
2136 {
2137 return task_deallocate_grp((task_t)task_read, TASK_GRP_MIG);
2138 }
2139
2140 /*
2141 * task_suspension_token_deallocate:
2142 *
2143 * Drop a reference on a task suspension token.
2144 */
2145 void
task_suspension_token_deallocate(task_suspension_token_t token)2146 task_suspension_token_deallocate(
2147 task_suspension_token_t token)
2148 {
2149 return task_deallocate((task_t)token);
2150 }
2151
2152 void
task_suspension_token_deallocate_grp(task_suspension_token_t token,task_grp_t grp)2153 task_suspension_token_deallocate_grp(
2154 task_suspension_token_t token,
2155 task_grp_t grp)
2156 {
2157 return task_deallocate_grp((task_t)token, grp);
2158 }
2159
2160 /*
2161 * task_collect_crash_info:
2162 *
2163 * collect crash info from bsd and mach based data
2164 */
2165 kern_return_t
task_collect_crash_info(task_t task,struct label * crash_label,int is_corpse_fork)2166 task_collect_crash_info(
2167 task_t task,
2168 #ifdef CONFIG_MACF
2169 struct label *crash_label,
2170 #endif
2171 int is_corpse_fork)
2172 {
2173 kern_return_t kr = KERN_SUCCESS;
2174
2175 kcdata_descriptor_t crash_data = NULL;
2176 kcdata_descriptor_t crash_data_release = NULL;
2177 mach_msg_type_number_t size = CORPSEINFO_ALLOCATION_SIZE;
2178 mach_vm_offset_t crash_data_ptr = 0;
2179 void *crash_data_kernel = NULL;
2180 void *crash_data_kernel_release = NULL;
2181 #if CONFIG_MACF
2182 struct label *label, *free_label;
2183 #endif
2184
2185 if (!corpses_enabled()) {
2186 return KERN_NOT_SUPPORTED;
2187 }
2188
2189 #if CONFIG_MACF
2190 free_label = label = mac_exc_create_label(NULL);
2191 #endif
2192
2193 task_lock(task);
2194
2195 assert(is_corpse_fork || get_bsdtask_info(task) != NULL);
2196 if (task->corpse_info == NULL && (is_corpse_fork || get_bsdtask_info(task) != NULL)) {
2197 #if CONFIG_MACF
2198 /* Set the crash label, used by the exception delivery mac hook */
2199 free_label = get_task_crash_label(task); // Most likely NULL.
2200 set_task_crash_label(task, label);
2201 mac_exc_update_task_crash_label(task, crash_label);
2202 #endif
2203 task_unlock(task);
2204
2205 crash_data_kernel = kalloc_data(CORPSEINFO_ALLOCATION_SIZE,
2206 Z_WAITOK | Z_ZERO);
2207 if (crash_data_kernel == NULL) {
2208 kr = KERN_RESOURCE_SHORTAGE;
2209 goto out_no_lock;
2210 }
2211 crash_data_ptr = (mach_vm_offset_t) crash_data_kernel;
2212
2213 /* Do not get a corpse ref for corpse fork */
2214 crash_data = task_crashinfo_alloc_init((mach_vm_address_t)crash_data_ptr, size,
2215 is_corpse_fork ? 0 : CORPSE_CRASHINFO_HAS_REF,
2216 KCFLAG_USE_MEMCOPY);
2217 if (crash_data) {
2218 task_lock(task);
2219 crash_data_release = task->corpse_info;
2220 crash_data_kernel_release = kcdata_memory_get_begin_addr(crash_data_release);
2221 task->corpse_info = crash_data;
2222
2223 task_unlock(task);
2224 kr = KERN_SUCCESS;
2225 } else {
2226 kfree_data(crash_data_kernel,
2227 CORPSEINFO_ALLOCATION_SIZE);
2228 kr = KERN_FAILURE;
2229 }
2230
2231 if (crash_data_release != NULL) {
2232 task_crashinfo_destroy(crash_data_release);
2233 }
2234 kfree_data(crash_data_kernel_release, CORPSEINFO_ALLOCATION_SIZE);
2235 } else {
2236 task_unlock(task);
2237 }
2238
2239 out_no_lock:
2240 #if CONFIG_MACF
2241 if (free_label != NULL) {
2242 mac_exc_free_label(free_label);
2243 }
2244 #endif
2245 return kr;
2246 }
2247
2248 /*
2249 * task_deliver_crash_notification:
2250 *
2251 * Makes outcall to registered host port for a corpse.
2252 */
2253 kern_return_t
task_deliver_crash_notification(task_t corpse,thread_t thread,exception_type_t etype,mach_exception_subcode_t subcode)2254 task_deliver_crash_notification(
2255 task_t corpse, /* corpse or corpse fork */
2256 thread_t thread,
2257 exception_type_t etype,
2258 mach_exception_subcode_t subcode)
2259 {
2260 kcdata_descriptor_t crash_info = corpse->corpse_info;
2261 thread_t th_iter = NULL;
2262 kern_return_t kr = KERN_SUCCESS;
2263 wait_interrupt_t wsave;
2264 mach_exception_data_type_t code[EXCEPTION_CODE_MAX];
2265 ipc_port_t corpse_port;
2266
2267 if (crash_info == NULL) {
2268 return KERN_FAILURE;
2269 }
2270
2271 assert(task_is_a_corpse(corpse));
2272
2273 task_lock(corpse);
2274
2275 /*
2276 * Always populate code[0] as the effective exception type for EXC_CORPSE_NOTIFY.
2277 * Crash reporters should derive whether it's fatal from corpse blob.
2278 */
2279 code[0] = etype;
2280 code[1] = subcode;
2281
2282 queue_iterate(&corpse->threads, th_iter, thread_t, task_threads)
2283 {
2284 if (th_iter->corpse_dup == FALSE) {
2285 ipc_thread_reset(th_iter);
2286 }
2287 }
2288 task_unlock(corpse);
2289
2290 /* Arm the no-sender notification for taskport */
2291 task_reference(corpse);
2292 corpse_port = convert_corpse_to_port_and_nsrequest(corpse);
2293
2294 wsave = thread_interrupt_level(THREAD_UNINT);
2295 kr = exception_triage_thread(EXC_CORPSE_NOTIFY, code, EXCEPTION_CODE_MAX, thread);
2296 if (kr != KERN_SUCCESS) {
2297 printf("Failed to send exception EXC_CORPSE_NOTIFY. error code: %d for pid %d\n", kr, task_pid(corpse));
2298 }
2299
2300 (void)thread_interrupt_level(wsave);
2301
2302 /*
2303 * Drop the send right on corpse port, will fire the
2304 * no-sender notification if exception deliver failed.
2305 */
2306 ipc_port_release_send(corpse_port);
2307 return kr;
2308 }
2309
2310 /*
2311 * task_terminate:
2312 *
2313 * Terminate the specified task. See comments on thread_terminate
2314 * (kern/thread.c) about problems with terminating the "current task."
2315 */
2316
2317 kern_return_t
task_terminate(task_t task)2318 task_terminate(
2319 task_t task)
2320 {
2321 if (task == TASK_NULL) {
2322 return KERN_INVALID_ARGUMENT;
2323 }
2324
2325 if (get_bsdtask_info(task)) {
2326 return KERN_FAILURE;
2327 }
2328
2329 return task_terminate_internal(task);
2330 }
2331
2332 #if MACH_ASSERT
2333 extern int proc_pid(struct proc *);
2334 extern void proc_name_kdp(struct proc *p, char *buf, int size);
2335 #endif /* MACH_ASSERT */
2336
2337 #define VM_MAP_PARTIAL_REAP 0x54 /* 0x150 */
2338 static void
task_partial_reap(task_t task,__unused int pid)2339 __unused task_partial_reap(task_t task, __unused int pid)
2340 {
2341 unsigned int reclaimed_resident = 0;
2342 unsigned int reclaimed_compressed = 0;
2343 uint64_t task_page_count;
2344
2345 task_page_count = (get_task_phys_footprint(task) / PAGE_SIZE_64);
2346
2347 KERNEL_DEBUG_CONSTANT((MACHDBG_CODE(DBG_MACH_VM, VM_MAP_PARTIAL_REAP) | DBG_FUNC_START),
2348 pid, task_page_count, 0, 0, 0);
2349
2350 vm_map_partial_reap(task->map, &reclaimed_resident, &reclaimed_compressed);
2351
2352 KERNEL_DEBUG_CONSTANT((MACHDBG_CODE(DBG_MACH_VM, VM_MAP_PARTIAL_REAP) | DBG_FUNC_END),
2353 pid, reclaimed_resident, reclaimed_compressed, 0, 0);
2354 }
2355
2356 /*
2357 * task_mark_corpse:
2358 *
2359 * Mark the task as a corpse. Called by crashing thread.
2360 */
2361 kern_return_t
task_mark_corpse(task_t task)2362 task_mark_corpse(task_t task)
2363 {
2364 kern_return_t kr = KERN_SUCCESS;
2365 thread_t self_thread;
2366 (void) self_thread;
2367 wait_interrupt_t wsave;
2368 #if CONFIG_MACF
2369 struct label *crash_label = NULL;
2370 #endif
2371
2372 assert(task != kernel_task);
2373 assert(task == current_task());
2374 assert(!task_is_a_corpse(task));
2375
2376 #if CONFIG_MACF
2377 crash_label = mac_exc_create_label_for_proc((struct proc*)get_bsdtask_info(task));
2378 #endif
2379
2380 kr = task_collect_crash_info(task,
2381 #if CONFIG_MACF
2382 crash_label,
2383 #endif
2384 FALSE);
2385 if (kr != KERN_SUCCESS) {
2386 goto out;
2387 }
2388
2389 self_thread = current_thread();
2390
2391 wsave = thread_interrupt_level(THREAD_UNINT);
2392 task_lock(task);
2393
2394 /*
2395 * Check if any other thread called task_terminate_internal
2396 * and made the task inactive before we could mark it for
2397 * corpse pending report. Bail out if the task is inactive.
2398 */
2399 if (!task->active) {
2400 kcdata_descriptor_t crash_data_release = task->corpse_info;;
2401 void *crash_data_kernel_release = kcdata_memory_get_begin_addr(crash_data_release);;
2402
2403 task->corpse_info = NULL;
2404 task_unlock(task);
2405
2406 if (crash_data_release != NULL) {
2407 task_crashinfo_destroy(crash_data_release);
2408 }
2409 kfree_data(crash_data_kernel_release, CORPSEINFO_ALLOCATION_SIZE);
2410 return KERN_TERMINATED;
2411 }
2412
2413 task_set_corpse_pending_report(task);
2414 task_set_corpse(task);
2415 task->crashed_thread_id = thread_tid(self_thread);
2416
2417 kr = task_start_halt_locked(task, TRUE);
2418 assert(kr == KERN_SUCCESS);
2419
2420 task_set_uniqueid(task);
2421
2422 task_unlock(task);
2423
2424 /*
2425 * ipc_task_reset() moved to last thread_terminate_self(): rdar://75737960.
2426 * disable old ports here instead.
2427 *
2428 * The vm_map and ipc_space must exist until this function returns,
2429 * convert_port_to_{map,space}_with_flavor relies on this behavior.
2430 */
2431 ipc_task_disable(task);
2432
2433 /* terminate the ipc space */
2434 ipc_space_terminate(task->itk_space);
2435
2436 /* Add it to global corpse task list */
2437 task_add_to_corpse_task_list(task);
2438
2439 thread_terminate_internal(self_thread);
2440
2441 (void) thread_interrupt_level(wsave);
2442 assert(task->halting == TRUE);
2443
2444 out:
2445 #if CONFIG_MACF
2446 mac_exc_free_label(crash_label);
2447 #endif
2448 return kr;
2449 }
2450
2451 /*
2452 * task_set_uniqueid
2453 *
2454 * Set task uniqueid to systemwide unique 64 bit value
2455 */
2456 void
task_set_uniqueid(task_t task)2457 task_set_uniqueid(task_t task)
2458 {
2459 task->task_uniqueid = OSIncrementAtomic64(&next_taskuniqueid);
2460 }
2461
2462 /*
2463 * task_clear_corpse
2464 *
2465 * Clears the corpse pending bit on task.
2466 * Removes inspection bit on the threads.
2467 */
2468 void
task_clear_corpse(task_t task)2469 task_clear_corpse(task_t task)
2470 {
2471 thread_t th_iter = NULL;
2472
2473 task_lock(task);
2474 queue_iterate(&task->threads, th_iter, thread_t, task_threads)
2475 {
2476 thread_mtx_lock(th_iter);
2477 th_iter->inspection = FALSE;
2478 ipc_thread_disable(th_iter);
2479 thread_mtx_unlock(th_iter);
2480 }
2481
2482 thread_terminate_crashed_threads();
2483 /* remove the pending corpse report flag */
2484 task_clear_corpse_pending_report(task);
2485
2486 task_unlock(task);
2487 }
2488
2489 /*
2490 * task_port_no_senders
2491 *
2492 * Called whenever the Mach port system detects no-senders on
2493 * the task port of a corpse.
2494 * Each notification that comes in should terminate the task (corpse).
2495 */
2496 static void
task_port_no_senders(ipc_port_t port,__unused mach_port_mscount_t mscount)2497 task_port_no_senders(ipc_port_t port, __unused mach_port_mscount_t mscount)
2498 {
2499 task_t task = ipc_kobject_get_locked(port, IKOT_TASK_CONTROL);
2500
2501 assert(task != TASK_NULL);
2502 assert(task_is_a_corpse(task));
2503
2504 /* Remove the task from global corpse task list */
2505 task_remove_from_corpse_task_list(task);
2506
2507 task_clear_corpse(task);
2508 task_terminate_internal(task);
2509 }
2510
2511 /*
2512 * task_port_with_flavor_no_senders
2513 *
2514 * Called whenever the Mach port system detects no-senders on
2515 * the task inspect or read port. These ports are allocated lazily and
2516 * should be deallocated here when there are no senders remaining.
2517 */
2518 static void
task_port_with_flavor_no_senders(ipc_port_t port,mach_port_mscount_t mscount __unused)2519 task_port_with_flavor_no_senders(
2520 ipc_port_t port,
2521 mach_port_mscount_t mscount __unused)
2522 {
2523 task_t task;
2524 mach_task_flavor_t flavor;
2525 ipc_kobject_type_t kotype;
2526
2527 ip_mq_lock(port);
2528 if (port->ip_srights > 0) {
2529 ip_mq_unlock(port);
2530 return;
2531 }
2532 kotype = ip_kotype(port);
2533 assert((IKOT_TASK_READ == kotype) || (IKOT_TASK_INSPECT == kotype));
2534 task = ipc_kobject_get_locked(port, kotype);
2535 if (task != TASK_NULL) {
2536 task_reference(task);
2537 }
2538 ip_mq_unlock(port);
2539
2540 if (task == TASK_NULL) {
2541 /* The task is exiting or disabled; it will eventually deallocate the port */
2542 return;
2543 }
2544
2545 if (kotype == IKOT_TASK_READ) {
2546 flavor = TASK_FLAVOR_READ;
2547 } else {
2548 flavor = TASK_FLAVOR_INSPECT;
2549 }
2550
2551 itk_lock(task);
2552 ip_mq_lock(port);
2553
2554 /*
2555 * If the port is no longer active, then ipc_task_terminate() ran
2556 * and destroyed the kobject already. Just deallocate the task
2557 * ref we took and go away.
2558 *
2559 * It is also possible that several nsrequests are in flight,
2560 * only one shall NULL-out the port entry, and this is the one
2561 * that gets to dealloc the port.
2562 *
2563 * Check for a stale no-senders notification. A call to any function
2564 * that vends out send rights to this port could resurrect it between
2565 * this notification being generated and actually being handled here.
2566 */
2567 if (!ip_active(port) ||
2568 task->itk_task_ports[flavor] != port ||
2569 port->ip_srights > 0) {
2570 ip_mq_unlock(port);
2571 itk_unlock(task);
2572 task_deallocate(task);
2573 return;
2574 }
2575
2576 assert(task->itk_task_ports[flavor] == port);
2577 task->itk_task_ports[flavor] = IP_NULL;
2578 itk_unlock(task);
2579
2580 ipc_kobject_dealloc_port_and_unlock(port, 0, kotype);
2581
2582 task_deallocate(task);
2583 }
2584
2585 /*
2586 * task_wait_till_threads_terminate_locked
2587 *
2588 * Wait till all the threads in the task are terminated.
2589 * Might release the task lock and re-acquire it.
2590 */
2591 void
task_wait_till_threads_terminate_locked(task_t task)2592 task_wait_till_threads_terminate_locked(task_t task)
2593 {
2594 /* wait for all the threads in the task to terminate */
2595 while (task->active_thread_count != 0) {
2596 assert_wait((event_t)&task->active_thread_count, THREAD_UNINT);
2597 task_unlock(task);
2598 thread_block(THREAD_CONTINUE_NULL);
2599
2600 task_lock(task);
2601 }
2602 }
2603
2604 /*
2605 * task_duplicate_map_and_threads
2606 *
2607 * Copy vmmap of source task.
2608 * Copy active threads from source task to destination task.
2609 * Source task would be suspended during the copy.
2610 */
2611 kern_return_t
task_duplicate_map_and_threads(task_t task,void * p,task_t new_task,thread_t * thread_ret,uint64_t ** udata_buffer,int * size,int * num_udata,bool for_exception)2612 task_duplicate_map_and_threads(
2613 task_t task,
2614 void *p,
2615 task_t new_task,
2616 thread_t *thread_ret,
2617 uint64_t **udata_buffer,
2618 int *size,
2619 int *num_udata,
2620 bool for_exception)
2621 {
2622 kern_return_t kr = KERN_SUCCESS;
2623 int active;
2624 thread_t thread, self, thread_return = THREAD_NULL;
2625 thread_t new_thread = THREAD_NULL, first_thread = THREAD_NULL;
2626 thread_t *thread_array;
2627 uint32_t active_thread_count = 0, array_count = 0, i;
2628 vm_map_t oldmap;
2629 uint64_t *buffer = NULL;
2630 int buf_size = 0;
2631 int est_knotes = 0, num_knotes = 0;
2632
2633 self = current_thread();
2634
2635 /*
2636 * Suspend the task to copy thread state, use the internal
2637 * variant so that no user-space process can resume
2638 * the task from under us
2639 */
2640 kr = task_suspend_internal(task);
2641 if (kr != KERN_SUCCESS) {
2642 return kr;
2643 }
2644
2645 if (task->map->disable_vmentry_reuse == TRUE) {
2646 /*
2647 * Quite likely GuardMalloc (or some debugging tool)
2648 * is being used on this task. And it has gone through
2649 * its limit. Making a corpse will likely encounter
2650 * a lot of VM entries that will need COW.
2651 *
2652 * Skip it.
2653 */
2654 #if DEVELOPMENT || DEBUG
2655 memorystatus_abort_vm_map_fork(task);
2656 #endif
2657 task_resume_internal(task);
2658 return KERN_FAILURE;
2659 }
2660
2661 /* Check with VM if vm_map_fork is allowed for this task */
2662 bool is_large = false;
2663 if (memorystatus_allowed_vm_map_fork(task, &is_large)) {
2664 /* Setup new task's vmmap, switch from parent task's map to it COW map */
2665 oldmap = new_task->map;
2666 new_task->map = vm_map_fork(new_task->ledger,
2667 task->map,
2668 (VM_MAP_FORK_SHARE_IF_INHERIT_NONE |
2669 VM_MAP_FORK_PRESERVE_PURGEABLE |
2670 VM_MAP_FORK_CORPSE_FOOTPRINT));
2671 if (new_task->map) {
2672 new_task->is_large_corpse = is_large;
2673 vm_map_deallocate(oldmap);
2674
2675 /* copy ledgers that impact the memory footprint */
2676 vm_map_copy_footprint_ledgers(task, new_task);
2677
2678 /* Get all the udata pointers from kqueue */
2679 est_knotes = kevent_proc_copy_uptrs(p, NULL, 0);
2680 if (est_knotes > 0) {
2681 buf_size = (est_knotes + 32) * sizeof(uint64_t);
2682 buffer = kalloc_data(buf_size, Z_WAITOK);
2683 num_knotes = kevent_proc_copy_uptrs(p, buffer, buf_size);
2684 if (num_knotes > est_knotes + 32) {
2685 num_knotes = est_knotes + 32;
2686 }
2687 }
2688 } else {
2689 if (is_large) {
2690 assert(large_corpse_count > 0);
2691 OSDecrementAtomic(&large_corpse_count);
2692 }
2693 new_task->map = oldmap;
2694 #if DEVELOPMENT || DEBUG
2695 memorystatus_abort_vm_map_fork(task);
2696 #endif
2697 task_resume_internal(task);
2698 return KERN_NO_SPACE;
2699 }
2700 } else if (!for_exception) {
2701 #if DEVELOPMENT || DEBUG
2702 memorystatus_abort_vm_map_fork(task);
2703 #endif
2704 task_resume_internal(task);
2705 return KERN_NO_SPACE;
2706 }
2707
2708 active_thread_count = task->active_thread_count;
2709 if (active_thread_count == 0) {
2710 kfree_data(buffer, buf_size);
2711 task_resume_internal(task);
2712 return KERN_FAILURE;
2713 }
2714
2715 thread_array = kalloc_type(thread_t, active_thread_count, Z_WAITOK);
2716
2717 /* Iterate all the threads and drop the task lock before calling thread_create_with_continuation */
2718 task_lock(task);
2719 queue_iterate(&task->threads, thread, thread_t, task_threads) {
2720 /* Skip inactive threads */
2721 active = thread->active;
2722 if (!active) {
2723 continue;
2724 }
2725
2726 if (array_count >= active_thread_count) {
2727 break;
2728 }
2729
2730 thread_array[array_count++] = thread;
2731 thread_reference(thread);
2732 }
2733 task_unlock(task);
2734
2735 for (i = 0; i < array_count; i++) {
2736 kr = thread_create_with_continuation(new_task, &new_thread, (thread_continue_t)thread_corpse_continue);
2737 if (kr != KERN_SUCCESS) {
2738 break;
2739 }
2740
2741 /* Equivalent of current thread in corpse */
2742 if (thread_array[i] == self) {
2743 thread_return = new_thread;
2744 new_task->crashed_thread_id = thread_tid(new_thread);
2745 } else if (first_thread == NULL) {
2746 first_thread = new_thread;
2747 } else {
2748 /* drop the extra ref returned by thread_create_with_continuation */
2749 thread_deallocate(new_thread);
2750 }
2751
2752 kr = thread_dup2(thread_array[i], new_thread);
2753 if (kr != KERN_SUCCESS) {
2754 thread_mtx_lock(new_thread);
2755 new_thread->corpse_dup = TRUE;
2756 thread_mtx_unlock(new_thread);
2757 continue;
2758 }
2759
2760 /* Copy thread name */
2761 bsd_copythreadname(get_bsdthread_info(new_thread),
2762 get_bsdthread_info(thread_array[i]));
2763 new_thread->thread_tag = thread_array[i]->thread_tag &
2764 ~THREAD_TAG_USER_JOIN;
2765 thread_copy_resource_info(new_thread, thread_array[i]);
2766 }
2767
2768 /* return the first thread if we couldn't find the equivalent of current */
2769 if (thread_return == THREAD_NULL) {
2770 thread_return = first_thread;
2771 } else if (first_thread != THREAD_NULL) {
2772 /* drop the extra ref returned by thread_create_with_continuation */
2773 thread_deallocate(first_thread);
2774 }
2775
2776 task_resume_internal(task);
2777
2778 for (i = 0; i < array_count; i++) {
2779 thread_deallocate(thread_array[i]);
2780 }
2781 kfree_type(thread_t, active_thread_count, thread_array);
2782
2783 if (kr == KERN_SUCCESS) {
2784 *thread_ret = thread_return;
2785 *udata_buffer = buffer;
2786 *size = buf_size;
2787 *num_udata = num_knotes;
2788 } else {
2789 if (thread_return != THREAD_NULL) {
2790 thread_deallocate(thread_return);
2791 }
2792 kfree_data(buffer, buf_size);
2793 }
2794
2795 return kr;
2796 }
2797
2798 #if CONFIG_SECLUDED_MEMORY
2799 extern void task_set_can_use_secluded_mem_locked(
2800 task_t task,
2801 boolean_t can_use_secluded_mem);
2802 #endif /* CONFIG_SECLUDED_MEMORY */
2803
2804 #if MACH_ASSERT
2805 int debug4k_panic_on_terminate = 0;
2806 #endif /* MACH_ASSERT */
2807 kern_return_t
task_terminate_internal(task_t task)2808 task_terminate_internal(
2809 task_t task)
2810 {
2811 thread_t thread, self;
2812 task_t self_task;
2813 boolean_t interrupt_save;
2814 int pid = 0;
2815
2816 assert(task != kernel_task);
2817
2818 self = current_thread();
2819 self_task = current_task();
2820
2821 /*
2822 * Get the task locked and make sure that we are not racing
2823 * with someone else trying to terminate us.
2824 */
2825 if (task == self_task) {
2826 task_lock(task);
2827 } else if (task < self_task) {
2828 task_lock(task);
2829 task_lock(self_task);
2830 } else {
2831 task_lock(self_task);
2832 task_lock(task);
2833 }
2834
2835 #if CONFIG_SECLUDED_MEMORY
2836 if (task->task_can_use_secluded_mem) {
2837 task_set_can_use_secluded_mem_locked(task, FALSE);
2838 }
2839 task->task_could_use_secluded_mem = FALSE;
2840 task->task_could_also_use_secluded_mem = FALSE;
2841
2842 if (task->task_suppressed_secluded) {
2843 stop_secluded_suppression(task);
2844 }
2845 #endif /* CONFIG_SECLUDED_MEMORY */
2846
2847 if (!task->active) {
2848 /*
2849 * Task is already being terminated.
2850 * Just return an error. If we are dying, this will
2851 * just get us to our AST special handler and that
2852 * will get us to finalize the termination of ourselves.
2853 */
2854 task_unlock(task);
2855 if (self_task != task) {
2856 task_unlock(self_task);
2857 }
2858
2859 return KERN_FAILURE;
2860 }
2861
2862 if (task_corpse_pending_report(task)) {
2863 /*
2864 * Task is marked for reporting as corpse.
2865 * Just return an error. This will
2866 * just get us to our AST special handler and that
2867 * will get us to finish the path to death
2868 */
2869 task_unlock(task);
2870 if (self_task != task) {
2871 task_unlock(self_task);
2872 }
2873
2874 return KERN_FAILURE;
2875 }
2876
2877 if (self_task != task) {
2878 task_unlock(self_task);
2879 }
2880
2881 /*
2882 * Make sure the current thread does not get aborted out of
2883 * the waits inside these operations.
2884 */
2885 interrupt_save = thread_interrupt_level(THREAD_UNINT);
2886
2887 /*
2888 * Indicate that we want all the threads to stop executing
2889 * at user space by holding the task (we would have held
2890 * each thread independently in thread_terminate_internal -
2891 * but this way we may be more likely to already find it
2892 * held there). Mark the task inactive, and prevent
2893 * further task operations via the task port.
2894 *
2895 * The vm_map and ipc_space must exist until this function returns,
2896 * convert_port_to_{map,space}_with_flavor relies on this behavior.
2897 */
2898 task_hold_locked(task);
2899 task->active = FALSE;
2900 ipc_task_disable(task);
2901
2902 #if CONFIG_TELEMETRY
2903 /*
2904 * Notify telemetry that this task is going away.
2905 */
2906 telemetry_task_ctl_locked(task, TF_TELEMETRY, 0);
2907 #endif
2908
2909 /*
2910 * Terminate each thread in the task.
2911 */
2912 queue_iterate(&task->threads, thread, thread_t, task_threads) {
2913 thread_terminate_internal(thread);
2914 }
2915
2916 #ifdef MACH_BSD
2917 void *bsd_info = get_bsdtask_info(task);
2918 if (bsd_info != NULL) {
2919 pid = proc_pid(bsd_info);
2920 }
2921 #endif /* MACH_BSD */
2922
2923 task_unlock(task);
2924
2925 proc_set_task_policy(task, TASK_POLICY_ATTRIBUTE,
2926 TASK_POLICY_TERMINATED, TASK_POLICY_ENABLE);
2927
2928 /* Early object reap phase */
2929
2930 // PR-17045188: Revisit implementation
2931 // task_partial_reap(task, pid);
2932
2933 #if CONFIG_TASKWATCH
2934 /*
2935 * remove all task watchers
2936 */
2937 task_removewatchers(task);
2938
2939 #endif /* CONFIG_TASKWATCH */
2940
2941 /*
2942 * Destroy all synchronizers owned by the task.
2943 */
2944 task_synchronizer_destroy_all(task);
2945
2946 /*
2947 * Clear the watchport boost on the task.
2948 */
2949 task_remove_turnstile_watchports(task);
2950
2951 /*
2952 * Destroy the IPC space, leaving just a reference for it.
2953 */
2954 ipc_space_terminate(task->itk_space);
2955
2956 #if 00
2957 /* if some ledgers go negative on tear-down again... */
2958 ledger_disable_panic_on_negative(task->map->pmap->ledger,
2959 task_ledgers.phys_footprint);
2960 ledger_disable_panic_on_negative(task->map->pmap->ledger,
2961 task_ledgers.internal);
2962 ledger_disable_panic_on_negative(task->map->pmap->ledger,
2963 task_ledgers.iokit_mapped);
2964 ledger_disable_panic_on_negative(task->map->pmap->ledger,
2965 task_ledgers.alternate_accounting);
2966 ledger_disable_panic_on_negative(task->map->pmap->ledger,
2967 task_ledgers.alternate_accounting_compressed);
2968 #endif
2969
2970 /*
2971 * If the current thread is a member of the task
2972 * being terminated, then the last reference to
2973 * the task will not be dropped until the thread
2974 * is finally reaped. To avoid incurring the
2975 * expense of removing the address space regions
2976 * at reap time, we do it explictly here.
2977 */
2978
2979 #if MACH_ASSERT
2980 /*
2981 * Identify the pmap's process, in case the pmap ledgers drift
2982 * and we have to report it.
2983 */
2984 char procname[17];
2985 void *proc = get_bsdtask_info(task);
2986 if (proc) {
2987 pid = proc_pid(proc);
2988 proc_name_kdp(proc, procname, sizeof(procname));
2989 } else {
2990 pid = 0;
2991 strlcpy(procname, "<unknown>", sizeof(procname));
2992 }
2993 pmap_set_process(task->map->pmap, pid, procname);
2994 if (vm_map_page_shift(task->map) < (int)PAGE_SHIFT) {
2995 DEBUG4K_LIFE("map %p procname: %s\n", task->map, procname);
2996 if (debug4k_panic_on_terminate) {
2997 panic("DEBUG4K: %s:%d %d[%s] map %p", __FUNCTION__, __LINE__, pid, procname, task->map);
2998 }
2999 }
3000 #endif /* MACH_ASSERT */
3001
3002 vm_map_terminate(task->map);
3003
3004 /* release our shared region */
3005 vm_shared_region_set(task, NULL);
3006
3007 #if __has_feature(ptrauth_calls)
3008 task_set_shared_region_id(task, NULL);
3009 #endif /* __has_feature(ptrauth_calls) */
3010
3011 lck_mtx_lock(&tasks_threads_lock);
3012 queue_remove(&tasks, task, task_t, tasks);
3013 queue_enter(&terminated_tasks, task, task_t, tasks);
3014 tasks_count--;
3015 terminated_tasks_count++;
3016 lck_mtx_unlock(&tasks_threads_lock);
3017
3018 /*
3019 * We no longer need to guard against being aborted, so restore
3020 * the previous interruptible state.
3021 */
3022 thread_interrupt_level(interrupt_save);
3023
3024 #if KPC
3025 /* force the task to release all ctrs */
3026 if (task->t_kpc & TASK_KPC_FORCED_ALL_CTRS) {
3027 kpc_force_all_ctrs(task, 0);
3028 }
3029 #endif /* KPC */
3030
3031 #if CONFIG_COALITIONS
3032 /*
3033 * Leave the coalition for corpse task or task that
3034 * never had any active threads (e.g. fork, exec failure).
3035 * For task with active threads, the task will be removed
3036 * from coalition by last terminating thread.
3037 */
3038 if (task->active_thread_count == 0) {
3039 coalitions_remove_task(task);
3040 }
3041 #endif
3042
3043 #if CONFIG_FREEZE
3044 extern int vm_compressor_available;
3045 if (VM_CONFIG_FREEZER_SWAP_IS_ACTIVE && vm_compressor_available) {
3046 task_disown_frozen_csegs(task);
3047 assert(queue_empty(&task->task_frozen_cseg_q));
3048 }
3049 #endif /* CONFIG_FREEZE */
3050
3051
3052 /*
3053 * Get rid of the task active reference on itself.
3054 */
3055 task_deallocate_grp(task, TASK_GRP_INTERNAL);
3056
3057 return KERN_SUCCESS;
3058 }
3059
3060 void
tasks_system_suspend(boolean_t suspend)3061 tasks_system_suspend(boolean_t suspend)
3062 {
3063 task_t task;
3064
3065 KDBG(MACHDBG_CODE(DBG_MACH_SCHED, MACH_SUSPEND_USERSPACE) |
3066 (suspend ? DBG_FUNC_START : DBG_FUNC_END));
3067
3068 lck_mtx_lock(&tasks_threads_lock);
3069 assert(tasks_suspend_state != suspend);
3070 tasks_suspend_state = suspend;
3071 queue_iterate(&tasks, task, task_t, tasks) {
3072 if (task == kernel_task) {
3073 continue;
3074 }
3075 suspend ? task_suspend_internal(task) : task_resume_internal(task);
3076 }
3077 lck_mtx_unlock(&tasks_threads_lock);
3078 }
3079
3080 /*
3081 * task_start_halt:
3082 *
3083 * Shut the current task down (except for the current thread) in
3084 * preparation for dramatic changes to the task (probably exec).
3085 * We hold the task and mark all other threads in the task for
3086 * termination.
3087 */
3088 kern_return_t
task_start_halt(task_t task)3089 task_start_halt(task_t task)
3090 {
3091 kern_return_t kr = KERN_SUCCESS;
3092 task_lock(task);
3093 kr = task_start_halt_locked(task, FALSE);
3094 task_unlock(task);
3095 return kr;
3096 }
3097
3098 static kern_return_t
task_start_halt_locked(task_t task,boolean_t should_mark_corpse)3099 task_start_halt_locked(task_t task, boolean_t should_mark_corpse)
3100 {
3101 thread_t thread, self;
3102 uint64_t dispatchqueue_offset;
3103
3104 assert(task != kernel_task);
3105
3106 self = current_thread();
3107
3108 if (task != get_threadtask(self) && !task_is_a_corpse_fork(task)) {
3109 return KERN_INVALID_ARGUMENT;
3110 }
3111
3112 if (!should_mark_corpse &&
3113 (task->halting || !task->active || !self->active)) {
3114 /*
3115 * Task or current thread is already being terminated.
3116 * Hurry up and return out of the current kernel context
3117 * so that we run our AST special handler to terminate
3118 * ourselves. If should_mark_corpse is set, the corpse
3119 * creation might have raced with exec, let the corpse
3120 * creation continue, once the current thread reaches AST
3121 * thread in exec will be woken up from task_complete_halt.
3122 * Exec will fail cause the proc was marked for exit.
3123 * Once the thread in exec reaches AST, it will call proc_exit
3124 * and deliver the EXC_CORPSE_NOTIFY.
3125 */
3126 return KERN_FAILURE;
3127 }
3128
3129 /* Thread creation will fail after this point of no return. */
3130 task->halting = TRUE;
3131
3132 /*
3133 * Mark all the threads to keep them from starting any more
3134 * user-level execution. The thread_terminate_internal code
3135 * would do this on a thread by thread basis anyway, but this
3136 * gives us a better chance of not having to wait there.
3137 */
3138 task_hold_locked(task);
3139 dispatchqueue_offset = get_dispatchqueue_offset_from_proc(get_bsdtask_info(task));
3140
3141 /*
3142 * Terminate all the other threads in the task.
3143 */
3144 queue_iterate(&task->threads, thread, thread_t, task_threads)
3145 {
3146 /*
3147 * Remove priority throttles for threads to terminate timely. This has
3148 * to be done after task_hold_locked() traps all threads to AST, but before
3149 * threads are marked inactive in thread_terminate_internal(). Takes thread
3150 * mutex lock.
3151 *
3152 * We need task_is_a_corpse() check so that we don't accidently update policy
3153 * for tasks that are doing posix_spawn().
3154 *
3155 * See: thread_policy_update_tasklocked().
3156 */
3157 if (task_is_a_corpse(task)) {
3158 proc_set_thread_policy(thread, TASK_POLICY_ATTRIBUTE,
3159 TASK_POLICY_TERMINATED, TASK_POLICY_ENABLE);
3160 }
3161
3162 if (should_mark_corpse) {
3163 thread_mtx_lock(thread);
3164 thread->inspection = TRUE;
3165 thread_mtx_unlock(thread);
3166 }
3167 if (thread != self) {
3168 thread_terminate_internal(thread);
3169 }
3170 }
3171 task->dispatchqueue_offset = dispatchqueue_offset;
3172
3173 task_release_locked(task);
3174
3175 return KERN_SUCCESS;
3176 }
3177
3178
3179 /*
3180 * task_complete_halt:
3181 *
3182 * Complete task halt by waiting for threads to terminate, then clean
3183 * up task resources (VM, port namespace, etc...) and then let the
3184 * current thread go in the (practically empty) task context.
3185 *
3186 * Note: task->halting flag is not cleared in order to avoid creation
3187 * of new thread in old exec'ed task.
3188 */
3189 void
task_complete_halt(task_t task)3190 task_complete_halt(task_t task)
3191 {
3192 task_lock(task);
3193 assert(task->halting);
3194 assert(task == current_task());
3195
3196 /*
3197 * Wait for the other threads to get shut down.
3198 * When the last other thread is reaped, we'll be
3199 * woken up.
3200 */
3201 if (task->thread_count > 1) {
3202 assert_wait((event_t)&task->halting, THREAD_UNINT);
3203 task_unlock(task);
3204 thread_block(THREAD_CONTINUE_NULL);
3205 } else {
3206 task_unlock(task);
3207 }
3208
3209 /*
3210 * Give the machine dependent code a chance
3211 * to perform cleanup of task-level resources
3212 * associated with the current thread before
3213 * ripping apart the task.
3214 */
3215 machine_task_terminate(task);
3216
3217 /*
3218 * Destroy all synchronizers owned by the task.
3219 */
3220 task_synchronizer_destroy_all(task);
3221
3222 /*
3223 * Terminate the IPC space. A long time ago,
3224 * this used to be ipc_space_clean() which would
3225 * keep the space active but hollow it.
3226 *
3227 * We really do not need this semantics given
3228 * tasks die with exec now.
3229 */
3230 ipc_space_terminate(task->itk_space);
3231
3232 /*
3233 * Clean out the address space, as we are going to be
3234 * getting a new one.
3235 */
3236 vm_map_terminate(task->map);
3237
3238 /*
3239 * Kick out any IOKitUser handles to the task. At best they're stale,
3240 * at worst someone is racing a SUID exec.
3241 */
3242 iokit_task_terminate(task);
3243 }
3244
3245 /*
3246 * task_hold_locked:
3247 *
3248 * Suspend execution of the specified task.
3249 * This is a recursive-style suspension of the task, a count of
3250 * suspends is maintained.
3251 *
3252 * CONDITIONS: the task is locked and active.
3253 */
3254 void
task_hold_locked(task_t task)3255 task_hold_locked(
3256 task_t task)
3257 {
3258 thread_t thread;
3259 void *bsd_info = get_bsdtask_info(task);
3260
3261 assert(task->active);
3262
3263 if (task->suspend_count++ > 0) {
3264 return;
3265 }
3266
3267 if (bsd_info) {
3268 workq_proc_suspended(bsd_info);
3269 }
3270
3271 /*
3272 * Iterate through all the threads and hold them.
3273 */
3274 queue_iterate(&task->threads, thread, thread_t, task_threads) {
3275 thread_mtx_lock(thread);
3276 thread_hold(thread);
3277 thread_mtx_unlock(thread);
3278 }
3279 }
3280
3281 /*
3282 * task_hold:
3283 *
3284 * Same as the internal routine above, except that is must lock
3285 * and verify that the task is active. This differs from task_suspend
3286 * in that it places a kernel hold on the task rather than just a
3287 * user-level hold. This keeps users from over resuming and setting
3288 * it running out from under the kernel.
3289 *
3290 * CONDITIONS: the caller holds a reference on the task
3291 */
3292 kern_return_t
task_hold(task_t task)3293 task_hold(
3294 task_t task)
3295 {
3296 if (task == TASK_NULL) {
3297 return KERN_INVALID_ARGUMENT;
3298 }
3299
3300 task_lock(task);
3301
3302 if (!task->active) {
3303 task_unlock(task);
3304
3305 return KERN_FAILURE;
3306 }
3307
3308 task_hold_locked(task);
3309 task_unlock(task);
3310
3311 return KERN_SUCCESS;
3312 }
3313
3314 kern_return_t
task_wait(task_t task,boolean_t until_not_runnable)3315 task_wait(
3316 task_t task,
3317 boolean_t until_not_runnable)
3318 {
3319 if (task == TASK_NULL) {
3320 return KERN_INVALID_ARGUMENT;
3321 }
3322
3323 task_lock(task);
3324
3325 if (!task->active) {
3326 task_unlock(task);
3327
3328 return KERN_FAILURE;
3329 }
3330
3331 task_wait_locked(task, until_not_runnable);
3332 task_unlock(task);
3333
3334 return KERN_SUCCESS;
3335 }
3336
3337 /*
3338 * task_wait_locked:
3339 *
3340 * Wait for all threads in task to stop.
3341 *
3342 * Conditions:
3343 * Called with task locked, active, and held.
3344 */
3345 void
task_wait_locked(task_t task,boolean_t until_not_runnable)3346 task_wait_locked(
3347 task_t task,
3348 boolean_t until_not_runnable)
3349 {
3350 thread_t thread, self;
3351
3352 assert(task->active);
3353 assert(task->suspend_count > 0);
3354
3355 self = current_thread();
3356
3357 /*
3358 * Iterate through all the threads and wait for them to
3359 * stop. Do not wait for the current thread if it is within
3360 * the task.
3361 */
3362 queue_iterate(&task->threads, thread, thread_t, task_threads) {
3363 if (thread != self) {
3364 thread_wait(thread, until_not_runnable);
3365 }
3366 }
3367 }
3368
3369 boolean_t
task_is_app_suspended(task_t task)3370 task_is_app_suspended(task_t task)
3371 {
3372 return task->pidsuspended;
3373 }
3374
3375 /*
3376 * task_release_locked:
3377 *
3378 * Release a kernel hold on a task.
3379 *
3380 * CONDITIONS: the task is locked and active
3381 */
3382 void
task_release_locked(task_t task)3383 task_release_locked(
3384 task_t task)
3385 {
3386 thread_t thread;
3387 void *bsd_info = get_bsdtask_info(task);
3388
3389 assert(task->active);
3390 assert(task->suspend_count > 0);
3391
3392 if (--task->suspend_count > 0) {
3393 return;
3394 }
3395
3396 if (bsd_info) {
3397 workq_proc_resumed(bsd_info);
3398 }
3399
3400 queue_iterate(&task->threads, thread, thread_t, task_threads) {
3401 thread_mtx_lock(thread);
3402 thread_release(thread);
3403 thread_mtx_unlock(thread);
3404 }
3405 }
3406
3407 /*
3408 * task_release:
3409 *
3410 * Same as the internal routine above, except that it must lock
3411 * and verify that the task is active.
3412 *
3413 * CONDITIONS: The caller holds a reference to the task
3414 */
3415 kern_return_t
task_release(task_t task)3416 task_release(
3417 task_t task)
3418 {
3419 if (task == TASK_NULL) {
3420 return KERN_INVALID_ARGUMENT;
3421 }
3422
3423 task_lock(task);
3424
3425 if (!task->active) {
3426 task_unlock(task);
3427
3428 return KERN_FAILURE;
3429 }
3430
3431 task_release_locked(task);
3432 task_unlock(task);
3433
3434 return KERN_SUCCESS;
3435 }
3436
3437 static kern_return_t
task_threads_internal(task_t task,thread_act_array_t * threads_out,mach_msg_type_number_t * countp,mach_thread_flavor_t flavor)3438 task_threads_internal(
3439 task_t task,
3440 thread_act_array_t *threads_out,
3441 mach_msg_type_number_t *countp,
3442 mach_thread_flavor_t flavor)
3443 {
3444 mach_msg_type_number_t actual, count, count_needed;
3445 thread_t *thread_list;
3446 thread_t thread;
3447 unsigned int i;
3448
3449 count = 0;
3450 thread_list = NULL;
3451
3452 if (task == TASK_NULL) {
3453 return KERN_INVALID_ARGUMENT;
3454 }
3455
3456 assert(flavor <= THREAD_FLAVOR_INSPECT);
3457
3458 for (;;) {
3459 task_lock(task);
3460 if (!task->active) {
3461 task_unlock(task);
3462
3463 kfree_type(thread_t, count, thread_list);
3464 return KERN_FAILURE;
3465 }
3466
3467 count_needed = actual = task->thread_count;
3468 if (count_needed <= count) {
3469 break;
3470 }
3471
3472 /* unlock the task and allocate more memory */
3473 task_unlock(task);
3474
3475 kfree_type(thread_t, count, thread_list);
3476 count = count_needed;
3477 thread_list = kalloc_type(thread_t, count, Z_WAITOK);
3478
3479 if (thread_list == NULL) {
3480 return KERN_RESOURCE_SHORTAGE;
3481 }
3482 }
3483
3484 i = 0;
3485 queue_iterate(&task->threads, thread, thread_t, task_threads) {
3486 assert(i < actual);
3487 thread_reference(thread);
3488 thread_list[i++] = thread;
3489 }
3490
3491 count_needed = actual;
3492
3493 /* can unlock task now that we've got the thread refs */
3494 task_unlock(task);
3495
3496 if (actual == 0) {
3497 /* no threads, so return null pointer and deallocate memory */
3498
3499 *threads_out = NULL;
3500 *countp = 0;
3501 kfree_type(thread_t, count, thread_list);
3502 } else {
3503 /* if we allocated too much, must copy */
3504 if (count_needed < count) {
3505 void *newaddr;
3506
3507 newaddr = kalloc_type(thread_t, count_needed, Z_WAITOK);
3508 if (newaddr == NULL) {
3509 for (i = 0; i < actual; ++i) {
3510 thread_deallocate(thread_list[i]);
3511 }
3512 kfree_type(thread_t, count, thread_list);
3513 return KERN_RESOURCE_SHORTAGE;
3514 }
3515
3516 bcopy(thread_list, newaddr, count_needed * sizeof(thread_t));
3517 kfree_type(thread_t, count, thread_list);
3518 thread_list = (thread_t *)newaddr;
3519 }
3520
3521 *threads_out = thread_list;
3522 *countp = actual;
3523
3524 /* do the conversion that Mig should handle */
3525
3526 switch (flavor) {
3527 case THREAD_FLAVOR_CONTROL:
3528 if (task == current_task()) {
3529 for (i = 0; i < actual; ++i) {
3530 ((ipc_port_t *) thread_list)[i] = convert_thread_to_port_pinned(thread_list[i]);
3531 }
3532 } else {
3533 for (i = 0; i < actual; ++i) {
3534 ((ipc_port_t *) thread_list)[i] = convert_thread_to_port(thread_list[i]);
3535 }
3536 }
3537 break;
3538 case THREAD_FLAVOR_READ:
3539 for (i = 0; i < actual; ++i) {
3540 ((ipc_port_t *) thread_list)[i] = convert_thread_read_to_port(thread_list[i]);
3541 }
3542 break;
3543 case THREAD_FLAVOR_INSPECT:
3544 for (i = 0; i < actual; ++i) {
3545 ((ipc_port_t *) thread_list)[i] = convert_thread_inspect_to_port(thread_list[i]);
3546 }
3547 break;
3548 }
3549 }
3550
3551 return KERN_SUCCESS;
3552 }
3553
3554 kern_return_t
task_threads(task_t task,thread_act_array_t * threads_out,mach_msg_type_number_t * count)3555 task_threads(
3556 task_t task,
3557 thread_act_array_t *threads_out,
3558 mach_msg_type_number_t *count)
3559 {
3560 return task_threads_internal(task, threads_out, count, THREAD_FLAVOR_CONTROL);
3561 }
3562
3563
3564 kern_return_t
task_threads_from_user(mach_port_t port,thread_act_array_t * threads_out,mach_msg_type_number_t * count)3565 task_threads_from_user(
3566 mach_port_t port,
3567 thread_act_array_t *threads_out,
3568 mach_msg_type_number_t *count)
3569 {
3570 ipc_kobject_type_t kotype;
3571 kern_return_t kr;
3572
3573 task_t task = convert_port_to_task_inspect_no_eval(port);
3574
3575 if (task == TASK_NULL) {
3576 return KERN_INVALID_ARGUMENT;
3577 }
3578
3579 kotype = ip_kotype(port);
3580
3581 switch (kotype) {
3582 case IKOT_TASK_CONTROL:
3583 kr = task_threads_internal(task, threads_out, count, THREAD_FLAVOR_CONTROL);
3584 break;
3585 case IKOT_TASK_READ:
3586 kr = task_threads_internal(task, threads_out, count, THREAD_FLAVOR_READ);
3587 break;
3588 case IKOT_TASK_INSPECT:
3589 kr = task_threads_internal(task, threads_out, count, THREAD_FLAVOR_INSPECT);
3590 break;
3591 default:
3592 panic("strange kobject type");
3593 break;
3594 }
3595
3596 task_deallocate(task);
3597 return kr;
3598 }
3599
3600 #define TASK_HOLD_NORMAL 0
3601 #define TASK_HOLD_PIDSUSPEND 1
3602 #define TASK_HOLD_LEGACY 2
3603 #define TASK_HOLD_LEGACY_ALL 3
3604
3605 static kern_return_t
place_task_hold(task_t task,int mode)3606 place_task_hold(
3607 task_t task,
3608 int mode)
3609 {
3610 if (!task->active && !task_is_a_corpse(task)) {
3611 return KERN_FAILURE;
3612 }
3613
3614 /* Return success for corpse task */
3615 if (task_is_a_corpse(task)) {
3616 return KERN_SUCCESS;
3617 }
3618
3619 KDBG_RELEASE(MACHDBG_CODE(DBG_MACH_IPC, MACH_TASK_SUSPEND),
3620 task_pid(task),
3621 task->thread_count > 0 ?((thread_t)queue_first(&task->threads))->thread_id : 0,
3622 task->user_stop_count, task->user_stop_count + 1);
3623
3624 #if MACH_ASSERT
3625 current_task()->suspends_outstanding++;
3626 #endif
3627
3628 if (mode == TASK_HOLD_LEGACY) {
3629 task->legacy_stop_count++;
3630 }
3631
3632 if (task->user_stop_count++ > 0) {
3633 /*
3634 * If the stop count was positive, the task is
3635 * already stopped and we can exit.
3636 */
3637 return KERN_SUCCESS;
3638 }
3639
3640 /*
3641 * Put a kernel-level hold on the threads in the task (all
3642 * user-level task suspensions added together represent a
3643 * single kernel-level hold). We then wait for the threads
3644 * to stop executing user code.
3645 */
3646 task_hold_locked(task);
3647 task_wait_locked(task, FALSE);
3648
3649 return KERN_SUCCESS;
3650 }
3651
3652 static kern_return_t
release_task_hold(task_t task,int mode)3653 release_task_hold(
3654 task_t task,
3655 int mode)
3656 {
3657 boolean_t release = FALSE;
3658
3659 if (!task->active && !task_is_a_corpse(task)) {
3660 return KERN_FAILURE;
3661 }
3662
3663 /* Return success for corpse task */
3664 if (task_is_a_corpse(task)) {
3665 return KERN_SUCCESS;
3666 }
3667
3668 if (mode == TASK_HOLD_PIDSUSPEND) {
3669 if (task->pidsuspended == FALSE) {
3670 return KERN_FAILURE;
3671 }
3672 task->pidsuspended = FALSE;
3673 }
3674
3675 if (task->user_stop_count > (task->pidsuspended ? 1 : 0)) {
3676 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
3677 MACHDBG_CODE(DBG_MACH_IPC, MACH_TASK_RESUME) | DBG_FUNC_NONE,
3678 task_pid(task), ((thread_t)queue_first(&task->threads))->thread_id,
3679 task->user_stop_count, mode, task->legacy_stop_count);
3680
3681 #if MACH_ASSERT
3682 /*
3683 * This is obviously not robust; if we suspend one task and then resume a different one,
3684 * we'll fly under the radar. This is only meant to catch the common case of a crashed
3685 * or buggy suspender.
3686 */
3687 current_task()->suspends_outstanding--;
3688 #endif
3689
3690 if (mode == TASK_HOLD_LEGACY_ALL) {
3691 if (task->legacy_stop_count >= task->user_stop_count) {
3692 task->user_stop_count = 0;
3693 release = TRUE;
3694 } else {
3695 task->user_stop_count -= task->legacy_stop_count;
3696 }
3697 task->legacy_stop_count = 0;
3698 } else {
3699 if (mode == TASK_HOLD_LEGACY && task->legacy_stop_count > 0) {
3700 task->legacy_stop_count--;
3701 }
3702 if (--task->user_stop_count == 0) {
3703 release = TRUE;
3704 }
3705 }
3706 } else {
3707 return KERN_FAILURE;
3708 }
3709
3710 /*
3711 * Release the task if necessary.
3712 */
3713 if (release) {
3714 task_release_locked(task);
3715 }
3716
3717 return KERN_SUCCESS;
3718 }
3719
3720 boolean_t
get_task_suspended(task_t task)3721 get_task_suspended(task_t task)
3722 {
3723 return 0 != task->user_stop_count;
3724 }
3725
3726 /*
3727 * task_suspend:
3728 *
3729 * Implement an (old-fashioned) user-level suspension on a task.
3730 *
3731 * Because the user isn't expecting to have to manage a suspension
3732 * token, we'll track it for him in the kernel in the form of a naked
3733 * send right to the task's resume port. All such send rights
3734 * account for a single suspension against the task (unlike task_suspend2()
3735 * where each caller gets a unique suspension count represented by a
3736 * unique send-once right).
3737 *
3738 * Conditions:
3739 * The caller holds a reference to the task
3740 */
3741 kern_return_t
task_suspend(task_t task)3742 task_suspend(
3743 task_t task)
3744 {
3745 kern_return_t kr;
3746 mach_port_t port;
3747 mach_port_name_t name;
3748
3749 if (task == TASK_NULL || task == kernel_task) {
3750 return KERN_INVALID_ARGUMENT;
3751 }
3752
3753 /*
3754 * place a legacy hold on the task.
3755 */
3756 task_lock(task);
3757 kr = place_task_hold(task, TASK_HOLD_LEGACY);
3758 task_unlock(task);
3759
3760 if (kr != KERN_SUCCESS) {
3761 return kr;
3762 }
3763
3764 /*
3765 * Claim a send right on the task resume port, and request a no-senders
3766 * notification on that port (if none outstanding).
3767 */
3768 itk_lock(task);
3769 port = task->itk_resume;
3770 if (port == IP_NULL) {
3771 port = ipc_kobject_alloc_port(task, IKOT_TASK_RESUME,
3772 IPC_KOBJECT_ALLOC_NSREQUEST | IPC_KOBJECT_ALLOC_MAKE_SEND);
3773 task->itk_resume = port;
3774 } else {
3775 (void)ipc_kobject_make_send_nsrequest(port, task, IKOT_TASK_RESUME);
3776 }
3777 itk_unlock(task);
3778
3779 /*
3780 * Copyout the send right into the calling task's IPC space. It won't know it is there,
3781 * but we'll look it up when calling a traditional resume. Any IPC operations that
3782 * deallocate the send right will auto-release the suspension.
3783 */
3784 if (IP_VALID(port)) {
3785 kr = ipc_object_copyout(current_space(), ip_to_object(port),
3786 MACH_MSG_TYPE_MOVE_SEND, IPC_OBJECT_COPYOUT_FLAGS_NONE,
3787 NULL, NULL, &name);
3788 } else {
3789 kr = KERN_SUCCESS;
3790 }
3791 if (kr != KERN_SUCCESS) {
3792 printf("warning: %s(%d) failed to copyout suspension "
3793 "token for pid %d with error: %d\n",
3794 proc_name_address(get_bsdtask_info(current_task())),
3795 proc_pid(get_bsdtask_info(current_task())),
3796 task_pid(task), kr);
3797 }
3798
3799 return kr;
3800 }
3801
3802 /*
3803 * task_resume:
3804 * Release a user hold on a task.
3805 *
3806 * Conditions:
3807 * The caller holds a reference to the task
3808 */
3809 kern_return_t
task_resume(task_t task)3810 task_resume(
3811 task_t task)
3812 {
3813 kern_return_t kr;
3814 mach_port_name_t resume_port_name;
3815 ipc_entry_t resume_port_entry;
3816 ipc_space_t space = current_task()->itk_space;
3817
3818 if (task == TASK_NULL || task == kernel_task) {
3819 return KERN_INVALID_ARGUMENT;
3820 }
3821
3822 /* release a legacy task hold */
3823 task_lock(task);
3824 kr = release_task_hold(task, TASK_HOLD_LEGACY);
3825 task_unlock(task);
3826
3827 itk_lock(task); /* for itk_resume */
3828 is_write_lock(space); /* spin lock */
3829 if (is_active(space) && IP_VALID(task->itk_resume) &&
3830 ipc_hash_lookup(space, ip_to_object(task->itk_resume), &resume_port_name, &resume_port_entry) == TRUE) {
3831 /*
3832 * We found a suspension token in the caller's IPC space. Release a send right to indicate that
3833 * we are holding one less legacy hold on the task from this caller. If the release failed,
3834 * go ahead and drop all the rights, as someone either already released our holds or the task
3835 * is gone.
3836 */
3837 itk_unlock(task);
3838 if (kr == KERN_SUCCESS) {
3839 ipc_right_dealloc(space, resume_port_name, resume_port_entry);
3840 } else {
3841 ipc_right_destroy(space, resume_port_name, resume_port_entry, FALSE, 0);
3842 }
3843 /* space unlocked */
3844 } else {
3845 itk_unlock(task);
3846 is_write_unlock(space);
3847 if (kr == KERN_SUCCESS) {
3848 printf("warning: %s(%d) performed out-of-band resume on pid %d\n",
3849 proc_name_address(get_bsdtask_info(current_task())), proc_pid(get_bsdtask_info(current_task())),
3850 task_pid(task));
3851 }
3852 }
3853
3854 return kr;
3855 }
3856
3857 /*
3858 * Suspend the target task.
3859 * Making/holding a token/reference/port is the callers responsibility.
3860 */
3861 kern_return_t
task_suspend_internal(task_t task)3862 task_suspend_internal(task_t task)
3863 {
3864 kern_return_t kr;
3865
3866 if (task == TASK_NULL || task == kernel_task) {
3867 return KERN_INVALID_ARGUMENT;
3868 }
3869
3870 task_lock(task);
3871 kr = place_task_hold(task, TASK_HOLD_NORMAL);
3872 task_unlock(task);
3873 return kr;
3874 }
3875
3876 /*
3877 * Suspend the target task, and return a suspension token. The token
3878 * represents a reference on the suspended task.
3879 */
3880 static kern_return_t
task_suspend2_grp(task_t task,task_suspension_token_t * suspend_token,task_grp_t grp)3881 task_suspend2_grp(
3882 task_t task,
3883 task_suspension_token_t *suspend_token,
3884 task_grp_t grp)
3885 {
3886 kern_return_t kr;
3887
3888 kr = task_suspend_internal(task);
3889 if (kr != KERN_SUCCESS) {
3890 *suspend_token = TASK_NULL;
3891 return kr;
3892 }
3893
3894 /*
3895 * Take a reference on the target task and return that to the caller
3896 * as a "suspension token," which can be converted into an SO right to
3897 * the now-suspended task's resume port.
3898 */
3899 task_reference_grp(task, grp);
3900 *suspend_token = task;
3901
3902 return KERN_SUCCESS;
3903 }
3904
3905 kern_return_t
task_suspend2_mig(task_t task,task_suspension_token_t * suspend_token)3906 task_suspend2_mig(
3907 task_t task,
3908 task_suspension_token_t *suspend_token)
3909 {
3910 return task_suspend2_grp(task, suspend_token, TASK_GRP_MIG);
3911 }
3912
3913 kern_return_t
task_suspend2_external(task_t task,task_suspension_token_t * suspend_token)3914 task_suspend2_external(
3915 task_t task,
3916 task_suspension_token_t *suspend_token)
3917 {
3918 return task_suspend2_grp(task, suspend_token, TASK_GRP_EXTERNAL);
3919 }
3920
3921 /*
3922 * Resume the task
3923 * (reference/token/port management is caller's responsibility).
3924 */
3925 kern_return_t
task_resume_internal(task_suspension_token_t task)3926 task_resume_internal(
3927 task_suspension_token_t task)
3928 {
3929 kern_return_t kr;
3930
3931 if (task == TASK_NULL || task == kernel_task) {
3932 return KERN_INVALID_ARGUMENT;
3933 }
3934
3935 task_lock(task);
3936 kr = release_task_hold(task, TASK_HOLD_NORMAL);
3937 task_unlock(task);
3938 return kr;
3939 }
3940
3941 /*
3942 * Resume the task using a suspension token. Consumes the token's ref.
3943 */
3944 static kern_return_t
task_resume2_grp(task_suspension_token_t task,task_grp_t grp)3945 task_resume2_grp(
3946 task_suspension_token_t task,
3947 task_grp_t grp)
3948 {
3949 kern_return_t kr;
3950
3951 kr = task_resume_internal(task);
3952 task_suspension_token_deallocate_grp(task, grp);
3953
3954 return kr;
3955 }
3956
3957 kern_return_t
task_resume2_mig(task_suspension_token_t task)3958 task_resume2_mig(
3959 task_suspension_token_t task)
3960 {
3961 return task_resume2_grp(task, TASK_GRP_MIG);
3962 }
3963
3964 kern_return_t
task_resume2_external(task_suspension_token_t task)3965 task_resume2_external(
3966 task_suspension_token_t task)
3967 {
3968 return task_resume2_grp(task, TASK_GRP_EXTERNAL);
3969 }
3970
3971 static void
task_suspension_no_senders(ipc_port_t port,mach_port_mscount_t mscount)3972 task_suspension_no_senders(ipc_port_t port, mach_port_mscount_t mscount)
3973 {
3974 task_t task = convert_port_to_task_suspension_token(port);
3975 kern_return_t kr;
3976
3977 if (task == TASK_NULL) {
3978 return;
3979 }
3980
3981 if (task == kernel_task) {
3982 task_suspension_token_deallocate(task);
3983 return;
3984 }
3985
3986 task_lock(task);
3987
3988 kr = ipc_kobject_nsrequest(port, mscount, NULL);
3989 if (kr == KERN_FAILURE) {
3990 /* release all the [remaining] outstanding legacy holds */
3991 release_task_hold(task, TASK_HOLD_LEGACY_ALL);
3992 }
3993
3994 task_unlock(task);
3995
3996 task_suspension_token_deallocate(task); /* drop token reference */
3997 }
3998
3999 /*
4000 * Fires when a send once made
4001 * by convert_task_suspension_token_to_port() dies.
4002 */
4003 void
task_suspension_send_once(ipc_port_t port)4004 task_suspension_send_once(ipc_port_t port)
4005 {
4006 task_t task = convert_port_to_task_suspension_token(port);
4007
4008 if (task == TASK_NULL || task == kernel_task) {
4009 return; /* nothing to do */
4010 }
4011
4012 /* release the hold held by this specific send-once right */
4013 task_lock(task);
4014 release_task_hold(task, TASK_HOLD_NORMAL);
4015 task_unlock(task);
4016
4017 task_suspension_token_deallocate(task); /* drop token reference */
4018 }
4019
4020 static kern_return_t
task_pidsuspend_locked(task_t task)4021 task_pidsuspend_locked(task_t task)
4022 {
4023 kern_return_t kr;
4024
4025 if (task->pidsuspended) {
4026 kr = KERN_FAILURE;
4027 goto out;
4028 }
4029
4030 task->pidsuspended = TRUE;
4031
4032 kr = place_task_hold(task, TASK_HOLD_PIDSUSPEND);
4033 if (kr != KERN_SUCCESS) {
4034 task->pidsuspended = FALSE;
4035 }
4036 out:
4037 return kr;
4038 }
4039
4040
4041 /*
4042 * task_pidsuspend:
4043 *
4044 * Suspends a task by placing a hold on its threads.
4045 *
4046 * Conditions:
4047 * The caller holds a reference to the task
4048 */
4049 kern_return_t
task_pidsuspend(task_t task)4050 task_pidsuspend(
4051 task_t task)
4052 {
4053 kern_return_t kr;
4054
4055 if (task == TASK_NULL || task == kernel_task) {
4056 return KERN_INVALID_ARGUMENT;
4057 }
4058
4059 task_lock(task);
4060
4061 kr = task_pidsuspend_locked(task);
4062
4063 task_unlock(task);
4064
4065 if ((KERN_SUCCESS == kr) && task->message_app_suspended) {
4066 iokit_task_app_suspended_changed(task);
4067 }
4068
4069 return kr;
4070 }
4071
4072 /*
4073 * task_pidresume:
4074 * Resumes a previously suspended task.
4075 *
4076 * Conditions:
4077 * The caller holds a reference to the task
4078 */
4079 kern_return_t
task_pidresume(task_t task)4080 task_pidresume(
4081 task_t task)
4082 {
4083 kern_return_t kr;
4084
4085 if (task == TASK_NULL || task == kernel_task) {
4086 return KERN_INVALID_ARGUMENT;
4087 }
4088
4089 task_lock(task);
4090
4091 #if CONFIG_FREEZE
4092
4093 while (task->changing_freeze_state) {
4094 assert_wait((event_t)&task->changing_freeze_state, THREAD_UNINT);
4095 task_unlock(task);
4096 thread_block(THREAD_CONTINUE_NULL);
4097
4098 task_lock(task);
4099 }
4100 task->changing_freeze_state = TRUE;
4101 #endif
4102
4103 kr = release_task_hold(task, TASK_HOLD_PIDSUSPEND);
4104
4105 task_unlock(task);
4106
4107 if ((KERN_SUCCESS == kr) && task->message_app_suspended) {
4108 iokit_task_app_suspended_changed(task);
4109 }
4110
4111 #if CONFIG_FREEZE
4112
4113 task_lock(task);
4114
4115 if (kr == KERN_SUCCESS) {
4116 task->frozen = FALSE;
4117 }
4118 task->changing_freeze_state = FALSE;
4119 thread_wakeup(&task->changing_freeze_state);
4120
4121 task_unlock(task);
4122 #endif
4123
4124 return kr;
4125 }
4126
4127 os_refgrp_decl(static, task_watchports_refgrp, "task_watchports", NULL);
4128
4129 /*
4130 * task_add_turnstile_watchports:
4131 * Setup watchports to boost the main thread of the task.
4132 *
4133 * Arguments:
4134 * task: task being spawned
4135 * thread: main thread of task
4136 * portwatch_ports: array of watchports
4137 * portwatch_count: number of watchports
4138 *
4139 * Conditions:
4140 * Nothing locked.
4141 */
4142 void
task_add_turnstile_watchports(task_t task,thread_t thread,ipc_port_t * portwatch_ports,uint32_t portwatch_count)4143 task_add_turnstile_watchports(
4144 task_t task,
4145 thread_t thread,
4146 ipc_port_t *portwatch_ports,
4147 uint32_t portwatch_count)
4148 {
4149 struct task_watchports *watchports = NULL;
4150 struct task_watchport_elem *previous_elem_array[TASK_MAX_WATCHPORT_COUNT] = {};
4151 os_ref_count_t refs;
4152
4153 /* Check if the task has terminated */
4154 if (!task->active) {
4155 return;
4156 }
4157
4158 assert(portwatch_count <= TASK_MAX_WATCHPORT_COUNT);
4159
4160 watchports = task_watchports_alloc_init(task, thread, portwatch_count);
4161
4162 /* Lock the ipc space */
4163 is_write_lock(task->itk_space);
4164
4165 /* Setup watchports to boost the main thread */
4166 refs = task_add_turnstile_watchports_locked(task,
4167 watchports, previous_elem_array, portwatch_ports,
4168 portwatch_count);
4169
4170 /* Drop the space lock */
4171 is_write_unlock(task->itk_space);
4172
4173 if (refs == 0) {
4174 task_watchports_deallocate(watchports);
4175 }
4176
4177 /* Drop the ref on previous_elem_array */
4178 for (uint32_t i = 0; i < portwatch_count && previous_elem_array[i] != NULL; i++) {
4179 task_watchport_elem_deallocate(previous_elem_array[i]);
4180 }
4181 }
4182
4183 /*
4184 * task_remove_turnstile_watchports:
4185 * Clear all turnstile boost on the task from watchports.
4186 *
4187 * Arguments:
4188 * task: task being terminated
4189 *
4190 * Conditions:
4191 * Nothing locked.
4192 */
4193 void
task_remove_turnstile_watchports(task_t task)4194 task_remove_turnstile_watchports(
4195 task_t task)
4196 {
4197 os_ref_count_t refs = TASK_MAX_WATCHPORT_COUNT;
4198 struct task_watchports *watchports = NULL;
4199 ipc_port_t port_freelist[TASK_MAX_WATCHPORT_COUNT] = {};
4200 uint32_t portwatch_count;
4201
4202 /* Lock the ipc space */
4203 is_write_lock(task->itk_space);
4204
4205 /* Check if watchport boost exist */
4206 if (task->watchports == NULL) {
4207 is_write_unlock(task->itk_space);
4208 return;
4209 }
4210 watchports = task->watchports;
4211 portwatch_count = watchports->tw_elem_array_count;
4212
4213 refs = task_remove_turnstile_watchports_locked(task, watchports,
4214 port_freelist);
4215
4216 is_write_unlock(task->itk_space);
4217
4218 /* Drop all the port references */
4219 for (uint32_t i = 0; i < portwatch_count && port_freelist[i] != NULL; i++) {
4220 ip_release(port_freelist[i]);
4221 }
4222
4223 /* Clear the task and thread references for task_watchport */
4224 if (refs == 0) {
4225 task_watchports_deallocate(watchports);
4226 }
4227 }
4228
4229 /*
4230 * task_transfer_turnstile_watchports:
4231 * Transfer all watchport turnstile boost from old task to new task.
4232 *
4233 * Arguments:
4234 * old_task: task calling exec
4235 * new_task: new exec'ed task
4236 * thread: main thread of new task
4237 *
4238 * Conditions:
4239 * Nothing locked.
4240 */
4241 void
task_transfer_turnstile_watchports(task_t old_task,task_t new_task,thread_t new_thread)4242 task_transfer_turnstile_watchports(
4243 task_t old_task,
4244 task_t new_task,
4245 thread_t new_thread)
4246 {
4247 struct task_watchports *old_watchports = NULL;
4248 struct task_watchports *new_watchports = NULL;
4249 os_ref_count_t old_refs = TASK_MAX_WATCHPORT_COUNT;
4250 os_ref_count_t new_refs = TASK_MAX_WATCHPORT_COUNT;
4251 uint32_t portwatch_count;
4252
4253 if (old_task->watchports == NULL || !new_task->active) {
4254 return;
4255 }
4256
4257 /* Get the watch port count from the old task */
4258 is_write_lock(old_task->itk_space);
4259 if (old_task->watchports == NULL) {
4260 is_write_unlock(old_task->itk_space);
4261 return;
4262 }
4263
4264 portwatch_count = old_task->watchports->tw_elem_array_count;
4265 is_write_unlock(old_task->itk_space);
4266
4267 new_watchports = task_watchports_alloc_init(new_task, new_thread, portwatch_count);
4268
4269 /* Lock the ipc space for old task */
4270 is_write_lock(old_task->itk_space);
4271
4272 /* Lock the ipc space for new task */
4273 is_write_lock(new_task->itk_space);
4274
4275 /* Check if watchport boost exist */
4276 if (old_task->watchports == NULL || !new_task->active) {
4277 is_write_unlock(new_task->itk_space);
4278 is_write_unlock(old_task->itk_space);
4279 (void)task_watchports_release(new_watchports);
4280 task_watchports_deallocate(new_watchports);
4281 return;
4282 }
4283
4284 old_watchports = old_task->watchports;
4285 assert(portwatch_count == old_task->watchports->tw_elem_array_count);
4286
4287 /* Setup new task watchports */
4288 new_task->watchports = new_watchports;
4289
4290 for (uint32_t i = 0; i < portwatch_count; i++) {
4291 ipc_port_t port = old_watchports->tw_elem[i].twe_port;
4292
4293 if (port == NULL) {
4294 task_watchport_elem_clear(&new_watchports->tw_elem[i]);
4295 continue;
4296 }
4297
4298 /* Lock the port and check if it has the entry */
4299 ip_mq_lock(port);
4300
4301 task_watchport_elem_init(&new_watchports->tw_elem[i], new_task, port);
4302
4303 if (ipc_port_replace_watchport_elem_conditional_locked(port,
4304 &old_watchports->tw_elem[i], &new_watchports->tw_elem[i]) == KERN_SUCCESS) {
4305 task_watchport_elem_clear(&old_watchports->tw_elem[i]);
4306
4307 task_watchports_retain(new_watchports);
4308 old_refs = task_watchports_release(old_watchports);
4309
4310 /* Check if all ports are cleaned */
4311 if (old_refs == 0) {
4312 old_task->watchports = NULL;
4313 }
4314 } else {
4315 task_watchport_elem_clear(&new_watchports->tw_elem[i]);
4316 }
4317 /* port unlocked by ipc_port_replace_watchport_elem_conditional_locked */
4318 }
4319
4320 /* Drop the reference on new task_watchports struct returned by task_watchports_alloc_init */
4321 new_refs = task_watchports_release(new_watchports);
4322 if (new_refs == 0) {
4323 new_task->watchports = NULL;
4324 }
4325
4326 is_write_unlock(new_task->itk_space);
4327 is_write_unlock(old_task->itk_space);
4328
4329 /* Clear the task and thread references for old_watchport */
4330 if (old_refs == 0) {
4331 task_watchports_deallocate(old_watchports);
4332 }
4333
4334 /* Clear the task and thread references for new_watchport */
4335 if (new_refs == 0) {
4336 task_watchports_deallocate(new_watchports);
4337 }
4338 }
4339
4340 /*
4341 * task_add_turnstile_watchports_locked:
4342 * Setup watchports to boost the main thread of the task.
4343 *
4344 * Arguments:
4345 * task: task to boost
4346 * watchports: watchport structure to be attached to the task
4347 * previous_elem_array: an array of old watchport_elem to be returned to caller
4348 * portwatch_ports: array of watchports
4349 * portwatch_count: number of watchports
4350 *
4351 * Conditions:
4352 * ipc space of the task locked.
4353 * returns array of old watchport_elem in previous_elem_array
4354 */
4355 static os_ref_count_t
task_add_turnstile_watchports_locked(task_t task,struct task_watchports * watchports,struct task_watchport_elem ** previous_elem_array,ipc_port_t * portwatch_ports,uint32_t portwatch_count)4356 task_add_turnstile_watchports_locked(
4357 task_t task,
4358 struct task_watchports *watchports,
4359 struct task_watchport_elem **previous_elem_array,
4360 ipc_port_t *portwatch_ports,
4361 uint32_t portwatch_count)
4362 {
4363 os_ref_count_t refs = TASK_MAX_WATCHPORT_COUNT;
4364
4365 /* Check if the task is still active */
4366 if (!task->active) {
4367 refs = task_watchports_release(watchports);
4368 return refs;
4369 }
4370
4371 assert(task->watchports == NULL);
4372 task->watchports = watchports;
4373
4374 for (uint32_t i = 0, j = 0; i < portwatch_count; i++) {
4375 ipc_port_t port = portwatch_ports[i];
4376
4377 task_watchport_elem_init(&watchports->tw_elem[i], task, port);
4378 if (port == NULL) {
4379 task_watchport_elem_clear(&watchports->tw_elem[i]);
4380 continue;
4381 }
4382
4383 ip_mq_lock(port);
4384
4385 /* Check if port is in valid state to be setup as watchport */
4386 if (ipc_port_add_watchport_elem_locked(port, &watchports->tw_elem[i],
4387 &previous_elem_array[j]) != KERN_SUCCESS) {
4388 task_watchport_elem_clear(&watchports->tw_elem[i]);
4389 continue;
4390 }
4391 /* port unlocked on return */
4392
4393 ip_reference(port);
4394 task_watchports_retain(watchports);
4395 if (previous_elem_array[j] != NULL) {
4396 j++;
4397 }
4398 }
4399
4400 /* Drop the reference on task_watchport struct returned by os_ref_init */
4401 refs = task_watchports_release(watchports);
4402 if (refs == 0) {
4403 task->watchports = NULL;
4404 }
4405
4406 return refs;
4407 }
4408
4409 /*
4410 * task_remove_turnstile_watchports_locked:
4411 * Clear all turnstile boost on the task from watchports.
4412 *
4413 * Arguments:
4414 * task: task to remove watchports from
4415 * watchports: watchports structure for the task
4416 * port_freelist: array of ports returned with ref to caller
4417 *
4418 *
4419 * Conditions:
4420 * ipc space of the task locked.
4421 * array of ports with refs are returned in port_freelist
4422 */
4423 static os_ref_count_t
task_remove_turnstile_watchports_locked(task_t task,struct task_watchports * watchports,ipc_port_t * port_freelist)4424 task_remove_turnstile_watchports_locked(
4425 task_t task,
4426 struct task_watchports *watchports,
4427 ipc_port_t *port_freelist)
4428 {
4429 os_ref_count_t refs = TASK_MAX_WATCHPORT_COUNT;
4430
4431 for (uint32_t i = 0, j = 0; i < watchports->tw_elem_array_count; i++) {
4432 ipc_port_t port = watchports->tw_elem[i].twe_port;
4433 if (port == NULL) {
4434 continue;
4435 }
4436
4437 /* Lock the port and check if it has the entry */
4438 ip_mq_lock(port);
4439 if (ipc_port_clear_watchport_elem_internal_conditional_locked(port,
4440 &watchports->tw_elem[i]) == KERN_SUCCESS) {
4441 task_watchport_elem_clear(&watchports->tw_elem[i]);
4442 port_freelist[j++] = port;
4443 refs = task_watchports_release(watchports);
4444
4445 /* Check if all ports are cleaned */
4446 if (refs == 0) {
4447 task->watchports = NULL;
4448 break;
4449 }
4450 }
4451 /* mqueue and port unlocked by ipc_port_clear_watchport_elem_internal_conditional_locked */
4452 }
4453 return refs;
4454 }
4455
4456 /*
4457 * task_watchports_alloc_init:
4458 * Allocate and initialize task watchport struct.
4459 *
4460 * Conditions:
4461 * Nothing locked.
4462 */
4463 static struct task_watchports *
task_watchports_alloc_init(task_t task,thread_t thread,uint32_t count)4464 task_watchports_alloc_init(
4465 task_t task,
4466 thread_t thread,
4467 uint32_t count)
4468 {
4469 struct task_watchports *watchports = kalloc_type(struct task_watchports,
4470 struct task_watchport_elem, count, Z_WAITOK | Z_ZERO | Z_NOFAIL);
4471
4472 task_reference(task);
4473 thread_reference(thread);
4474 watchports->tw_task = task;
4475 watchports->tw_thread = thread;
4476 watchports->tw_elem_array_count = count;
4477 os_ref_init(&watchports->tw_refcount, &task_watchports_refgrp);
4478
4479 return watchports;
4480 }
4481
4482 /*
4483 * task_watchports_deallocate:
4484 * Deallocate task watchport struct.
4485 *
4486 * Conditions:
4487 * Nothing locked.
4488 */
4489 static void
task_watchports_deallocate(struct task_watchports * watchports)4490 task_watchports_deallocate(
4491 struct task_watchports *watchports)
4492 {
4493 uint32_t portwatch_count = watchports->tw_elem_array_count;
4494
4495 task_deallocate(watchports->tw_task);
4496 thread_deallocate(watchports->tw_thread);
4497 kfree_type(struct task_watchports, struct task_watchport_elem,
4498 portwatch_count, watchports);
4499 }
4500
4501 /*
4502 * task_watchport_elem_deallocate:
4503 * Deallocate task watchport element and release its ref on task_watchport.
4504 *
4505 * Conditions:
4506 * Nothing locked.
4507 */
4508 void
task_watchport_elem_deallocate(struct task_watchport_elem * watchport_elem)4509 task_watchport_elem_deallocate(
4510 struct task_watchport_elem *watchport_elem)
4511 {
4512 os_ref_count_t refs = TASK_MAX_WATCHPORT_COUNT;
4513 task_t task = watchport_elem->twe_task;
4514 struct task_watchports *watchports = NULL;
4515 ipc_port_t port = NULL;
4516
4517 assert(task != NULL);
4518
4519 /* Take the space lock to modify the elememt */
4520 is_write_lock(task->itk_space);
4521
4522 watchports = task->watchports;
4523 assert(watchports != NULL);
4524
4525 port = watchport_elem->twe_port;
4526 assert(port != NULL);
4527
4528 task_watchport_elem_clear(watchport_elem);
4529 refs = task_watchports_release(watchports);
4530
4531 if (refs == 0) {
4532 task->watchports = NULL;
4533 }
4534
4535 is_write_unlock(task->itk_space);
4536
4537 ip_release(port);
4538 if (refs == 0) {
4539 task_watchports_deallocate(watchports);
4540 }
4541 }
4542
4543 /*
4544 * task_has_watchports:
4545 * Return TRUE if task has watchport boosts.
4546 *
4547 * Conditions:
4548 * Nothing locked.
4549 */
4550 boolean_t
task_has_watchports(task_t task)4551 task_has_watchports(task_t task)
4552 {
4553 return task->watchports != NULL;
4554 }
4555
4556 #if DEVELOPMENT || DEBUG
4557
4558 extern void IOSleep(int);
4559
4560 kern_return_t
task_disconnect_page_mappings(task_t task)4561 task_disconnect_page_mappings(task_t task)
4562 {
4563 int n;
4564
4565 if (task == TASK_NULL || task == kernel_task) {
4566 return KERN_INVALID_ARGUMENT;
4567 }
4568
4569 /*
4570 * this function is used to strip all of the mappings from
4571 * the pmap for the specified task to force the task to
4572 * re-fault all of the pages it is actively using... this
4573 * allows us to approximate the true working set of the
4574 * specified task. We only engage if at least 1 of the
4575 * threads in the task is runnable, but we want to continuously
4576 * sweep (at least for a while - I've arbitrarily set the limit at
4577 * 100 sweeps to be re-looked at as we gain experience) to get a better
4578 * view into what areas within a page are being visited (as opposed to only
4579 * seeing the first fault of a page after the task becomes
4580 * runnable)... in the future I may
4581 * try to block until awakened by a thread in this task
4582 * being made runnable, but for now we'll periodically poll from the
4583 * user level debug tool driving the sysctl
4584 */
4585 for (n = 0; n < 100; n++) {
4586 thread_t thread;
4587 boolean_t runnable;
4588 boolean_t do_unnest;
4589 int page_count;
4590
4591 runnable = FALSE;
4592 do_unnest = FALSE;
4593
4594 task_lock(task);
4595
4596 queue_iterate(&task->threads, thread, thread_t, task_threads) {
4597 if (thread->state & TH_RUN) {
4598 runnable = TRUE;
4599 break;
4600 }
4601 }
4602 if (n == 0) {
4603 task->task_disconnected_count++;
4604 }
4605
4606 if (task->task_unnested == FALSE) {
4607 if (runnable == TRUE) {
4608 task->task_unnested = TRUE;
4609 do_unnest = TRUE;
4610 }
4611 }
4612 task_unlock(task);
4613
4614 if (runnable == FALSE) {
4615 break;
4616 }
4617
4618 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, (MACHDBG_CODE(DBG_MACH_WORKINGSET, VM_DISCONNECT_TASK_PAGE_MAPPINGS)) | DBG_FUNC_START,
4619 task, do_unnest, task->task_disconnected_count, 0, 0);
4620
4621 page_count = vm_map_disconnect_page_mappings(task->map, do_unnest);
4622
4623 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, (MACHDBG_CODE(DBG_MACH_WORKINGSET, VM_DISCONNECT_TASK_PAGE_MAPPINGS)) | DBG_FUNC_END,
4624 task, page_count, 0, 0, 0);
4625
4626 if ((n % 5) == 4) {
4627 IOSleep(1);
4628 }
4629 }
4630 return KERN_SUCCESS;
4631 }
4632
4633 #endif
4634
4635
4636 #if CONFIG_FREEZE
4637
4638 /*
4639 * task_freeze:
4640 *
4641 * Freeze a task.
4642 *
4643 * Conditions:
4644 * The caller holds a reference to the task
4645 */
4646 extern void vm_wake_compactor_swapper(void);
4647 extern struct freezer_context freezer_context_global;
4648
4649 kern_return_t
task_freeze(task_t task,uint32_t * purgeable_count,uint32_t * wired_count,uint32_t * clean_count,uint32_t * dirty_count,uint32_t dirty_budget,uint32_t * shared_count,int * freezer_error_code,boolean_t eval_only)4650 task_freeze(
4651 task_t task,
4652 uint32_t *purgeable_count,
4653 uint32_t *wired_count,
4654 uint32_t *clean_count,
4655 uint32_t *dirty_count,
4656 uint32_t dirty_budget,
4657 uint32_t *shared_count,
4658 int *freezer_error_code,
4659 boolean_t eval_only)
4660 {
4661 kern_return_t kr = KERN_SUCCESS;
4662
4663 if (task == TASK_NULL || task == kernel_task) {
4664 return KERN_INVALID_ARGUMENT;
4665 }
4666
4667 task_lock(task);
4668
4669 while (task->changing_freeze_state) {
4670 assert_wait((event_t)&task->changing_freeze_state, THREAD_UNINT);
4671 task_unlock(task);
4672 thread_block(THREAD_CONTINUE_NULL);
4673
4674 task_lock(task);
4675 }
4676 if (task->frozen) {
4677 task_unlock(task);
4678 return KERN_FAILURE;
4679 }
4680 task->changing_freeze_state = TRUE;
4681
4682 freezer_context_global.freezer_ctx_task = task;
4683
4684 task_unlock(task);
4685
4686 kr = vm_map_freeze(task,
4687 purgeable_count,
4688 wired_count,
4689 clean_count,
4690 dirty_count,
4691 dirty_budget,
4692 shared_count,
4693 freezer_error_code,
4694 eval_only);
4695
4696 task_lock(task);
4697
4698 if ((kr == KERN_SUCCESS) && (eval_only == FALSE)) {
4699 task->frozen = TRUE;
4700
4701 freezer_context_global.freezer_ctx_task = NULL;
4702 freezer_context_global.freezer_ctx_uncompressed_pages = 0;
4703
4704 if (VM_CONFIG_FREEZER_SWAP_IS_ACTIVE) {
4705 /*
4706 * reset the counter tracking the # of swapped compressed pages
4707 * because we are now done with this freeze session and task.
4708 */
4709
4710 *dirty_count = (uint32_t) (freezer_context_global.freezer_ctx_swapped_bytes / PAGE_SIZE_64); /*used to track pageouts*/
4711 }
4712
4713 freezer_context_global.freezer_ctx_swapped_bytes = 0;
4714 }
4715
4716 task->changing_freeze_state = FALSE;
4717 thread_wakeup(&task->changing_freeze_state);
4718
4719 task_unlock(task);
4720
4721 if (VM_CONFIG_COMPRESSOR_IS_PRESENT &&
4722 (kr == KERN_SUCCESS) &&
4723 (eval_only == FALSE)) {
4724 vm_wake_compactor_swapper();
4725 /*
4726 * We do an explicit wakeup of the swapout thread here
4727 * because the compact_and_swap routines don't have
4728 * knowledge about these kind of "per-task packed c_segs"
4729 * and so will not be evaluating whether we need to do
4730 * a wakeup there.
4731 */
4732 thread_wakeup((event_t)&vm_swapout_thread);
4733 }
4734
4735 return kr;
4736 }
4737
4738 /*
4739 * task_thaw:
4740 *
4741 * Thaw a currently frozen task.
4742 *
4743 * Conditions:
4744 * The caller holds a reference to the task
4745 */
4746 kern_return_t
task_thaw(task_t task)4747 task_thaw(
4748 task_t task)
4749 {
4750 if (task == TASK_NULL || task == kernel_task) {
4751 return KERN_INVALID_ARGUMENT;
4752 }
4753
4754 task_lock(task);
4755
4756 while (task->changing_freeze_state) {
4757 assert_wait((event_t)&task->changing_freeze_state, THREAD_UNINT);
4758 task_unlock(task);
4759 thread_block(THREAD_CONTINUE_NULL);
4760
4761 task_lock(task);
4762 }
4763 if (!task->frozen) {
4764 task_unlock(task);
4765 return KERN_FAILURE;
4766 }
4767 task->frozen = FALSE;
4768
4769 task_unlock(task);
4770
4771 return KERN_SUCCESS;
4772 }
4773
4774 void
task_update_frozen_to_swap_acct(task_t task,int64_t amount,freezer_acct_op_t op)4775 task_update_frozen_to_swap_acct(task_t task, int64_t amount, freezer_acct_op_t op)
4776 {
4777 /*
4778 * We don't assert that the task lock is held because we call this
4779 * routine from the decompression path and we won't be holding the
4780 * task lock. However, since we are in the context of the task we are
4781 * safe.
4782 * In the case of the task_freeze path, we call it from behind the task
4783 * lock but we don't need to because we have a reference on the proc
4784 * being frozen.
4785 */
4786
4787 assert(task);
4788 if (amount == 0) {
4789 return;
4790 }
4791
4792 if (op == CREDIT_TO_SWAP) {
4793 ledger_credit_nocheck(task->ledger, task_ledgers.frozen_to_swap, amount);
4794 } else if (op == DEBIT_FROM_SWAP) {
4795 ledger_debit_nocheck(task->ledger, task_ledgers.frozen_to_swap, amount);
4796 } else {
4797 panic("task_update_frozen_to_swap_acct: Invalid ledger op");
4798 }
4799 }
4800 #endif /* CONFIG_FREEZE */
4801
4802 kern_return_t
task_set_security_tokens(task_t task,security_token_t sec_token,audit_token_t audit_token,host_priv_t host_priv)4803 task_set_security_tokens(
4804 task_t task,
4805 security_token_t sec_token,
4806 audit_token_t audit_token,
4807 host_priv_t host_priv)
4808 {
4809 ipc_port_t host_port;
4810 kern_return_t kr;
4811
4812 if (task == TASK_NULL) {
4813 return KERN_INVALID_ARGUMENT;
4814 }
4815
4816 task_lock(task);
4817 task_set_tokens(task, &sec_token, &audit_token);
4818 task_unlock(task);
4819
4820 if (host_priv != HOST_PRIV_NULL) {
4821 kr = host_get_host_priv_port(host_priv, &host_port);
4822 } else {
4823 kr = host_get_host_port(host_priv_self(), &host_port);
4824 }
4825 assert(kr == KERN_SUCCESS);
4826
4827 kr = task_set_special_port_internal(task, TASK_HOST_PORT, host_port);
4828 return kr;
4829 }
4830
4831 kern_return_t
task_send_trace_memory(__unused task_t target_task,__unused uint32_t pid,__unused uint64_t uniqueid)4832 task_send_trace_memory(
4833 __unused task_t target_task,
4834 __unused uint32_t pid,
4835 __unused uint64_t uniqueid)
4836 {
4837 return KERN_INVALID_ARGUMENT;
4838 }
4839
4840 /*
4841 * This routine was added, pretty much exclusively, for registering the
4842 * RPC glue vector for in-kernel short circuited tasks. Rather than
4843 * removing it completely, I have only disabled that feature (which was
4844 * the only feature at the time). It just appears that we are going to
4845 * want to add some user data to tasks in the future (i.e. bsd info,
4846 * task names, etc...), so I left it in the formal task interface.
4847 */
4848 kern_return_t
task_set_info(task_t task,task_flavor_t flavor,__unused task_info_t task_info_in,__unused mach_msg_type_number_t task_info_count)4849 task_set_info(
4850 task_t task,
4851 task_flavor_t flavor,
4852 __unused task_info_t task_info_in, /* pointer to IN array */
4853 __unused mach_msg_type_number_t task_info_count)
4854 {
4855 if (task == TASK_NULL) {
4856 return KERN_INVALID_ARGUMENT;
4857 }
4858 switch (flavor) {
4859 #if CONFIG_ATM
4860 case TASK_TRACE_MEMORY_INFO:
4861 return KERN_NOT_SUPPORTED;
4862 #endif // CONFIG_ATM
4863 default:
4864 return KERN_INVALID_ARGUMENT;
4865 }
4866 }
4867
4868 static void
_task_fill_times(task_t task,time_value_t * user_time,time_value_t * sys_time)4869 _task_fill_times(task_t task, time_value_t *user_time, time_value_t *sys_time)
4870 {
4871 clock_sec_t sec;
4872 clock_usec_t usec;
4873
4874 struct recount_times_mach times = recount_task_terminated_times(task);
4875 absolutetime_to_microtime(times.rtm_user, &sec, &usec);
4876 user_time->seconds = (typeof(user_time->seconds))sec;
4877 user_time->microseconds = usec;
4878 absolutetime_to_microtime(times.rtm_system, &sec, &usec);
4879 sys_time->seconds = (typeof(sys_time->seconds))sec;
4880 sys_time->microseconds = usec;
4881 }
4882
4883 int radar_20146450 = 1;
4884 kern_return_t
task_info(task_t task,task_flavor_t flavor,task_info_t task_info_out,mach_msg_type_number_t * task_info_count)4885 task_info(
4886 task_t task,
4887 task_flavor_t flavor,
4888 task_info_t task_info_out,
4889 mach_msg_type_number_t *task_info_count)
4890 {
4891 kern_return_t error = KERN_SUCCESS;
4892 mach_msg_type_number_t original_task_info_count;
4893 bool is_kernel_task = (task == kernel_task);
4894
4895 if (task == TASK_NULL) {
4896 return KERN_INVALID_ARGUMENT;
4897 }
4898
4899 original_task_info_count = *task_info_count;
4900 task_lock(task);
4901
4902 if (task != current_task() && !task->active) {
4903 task_unlock(task);
4904 return KERN_INVALID_ARGUMENT;
4905 }
4906
4907
4908 switch (flavor) {
4909 case TASK_BASIC_INFO_32:
4910 case TASK_BASIC2_INFO_32:
4911 #if defined(__arm64__)
4912 case TASK_BASIC_INFO_64:
4913 #endif
4914 {
4915 task_basic_info_32_t basic_info;
4916 ledger_amount_t tmp;
4917
4918 if (*task_info_count < TASK_BASIC_INFO_32_COUNT) {
4919 error = KERN_INVALID_ARGUMENT;
4920 break;
4921 }
4922
4923 basic_info = (task_basic_info_32_t)task_info_out;
4924
4925 basic_info->virtual_size = (typeof(basic_info->virtual_size))
4926 vm_map_adjusted_size(is_kernel_task ? kernel_map : task->map);
4927 if (flavor == TASK_BASIC2_INFO_32) {
4928 /*
4929 * The "BASIC2" flavor gets the maximum resident
4930 * size instead of the current resident size...
4931 */
4932 ledger_get_lifetime_max(task->ledger, task_ledgers.phys_mem, &tmp);
4933 } else {
4934 ledger_get_balance(task->ledger, task_ledgers.phys_mem, &tmp);
4935 }
4936 basic_info->resident_size = (natural_t) MIN((ledger_amount_t) UINT32_MAX, tmp);
4937
4938 _task_fill_times(task, &basic_info->user_time,
4939 &basic_info->system_time);
4940
4941 basic_info->policy = is_kernel_task ? POLICY_RR : POLICY_TIMESHARE;
4942 basic_info->suspend_count = task->user_stop_count;
4943
4944 *task_info_count = TASK_BASIC_INFO_32_COUNT;
4945 break;
4946 }
4947
4948 #if defined(__arm64__)
4949 case TASK_BASIC_INFO_64_2:
4950 {
4951 task_basic_info_64_2_t basic_info;
4952
4953 if (*task_info_count < TASK_BASIC_INFO_64_2_COUNT) {
4954 error = KERN_INVALID_ARGUMENT;
4955 break;
4956 }
4957
4958 basic_info = (task_basic_info_64_2_t)task_info_out;
4959
4960 basic_info->virtual_size = vm_map_adjusted_size(is_kernel_task ?
4961 kernel_map : task->map);
4962 ledger_get_balance(task->ledger, task_ledgers.phys_mem,
4963 (ledger_amount_t *)&basic_info->resident_size);
4964 basic_info->policy = is_kernel_task ? POLICY_RR : POLICY_TIMESHARE;
4965 basic_info->suspend_count = task->user_stop_count;
4966 _task_fill_times(task, &basic_info->user_time,
4967 &basic_info->system_time);
4968
4969 *task_info_count = TASK_BASIC_INFO_64_2_COUNT;
4970 break;
4971 }
4972
4973 #else /* defined(__arm64__) */
4974 case TASK_BASIC_INFO_64:
4975 {
4976 task_basic_info_64_t basic_info;
4977
4978 if (*task_info_count < TASK_BASIC_INFO_64_COUNT) {
4979 error = KERN_INVALID_ARGUMENT;
4980 break;
4981 }
4982
4983 basic_info = (task_basic_info_64_t)task_info_out;
4984
4985 basic_info->virtual_size = vm_map_adjusted_size(is_kernel_task ?
4986 kernel_map : task->map);
4987 ledger_get_balance(task->ledger, task_ledgers.phys_mem, (ledger_amount_t *)&basic_info->resident_size);
4988 basic_info->policy = is_kernel_task ? POLICY_RR : POLICY_TIMESHARE;
4989 basic_info->suspend_count = task->user_stop_count;
4990 _task_fill_times(task, &basic_info->user_time,
4991 &basic_info->system_time);
4992
4993 *task_info_count = TASK_BASIC_INFO_64_COUNT;
4994 break;
4995 }
4996 #endif /* defined(__arm64__) */
4997
4998 case MACH_TASK_BASIC_INFO:
4999 {
5000 mach_task_basic_info_t basic_info;
5001
5002 if (*task_info_count < MACH_TASK_BASIC_INFO_COUNT) {
5003 error = KERN_INVALID_ARGUMENT;
5004 break;
5005 }
5006
5007 basic_info = (mach_task_basic_info_t)task_info_out;
5008
5009 basic_info->virtual_size = vm_map_adjusted_size(is_kernel_task ?
5010 kernel_map : task->map);
5011 ledger_get_balance(task->ledger, task_ledgers.phys_mem, (ledger_amount_t *) &basic_info->resident_size);
5012 ledger_get_lifetime_max(task->ledger, task_ledgers.phys_mem, (ledger_amount_t *) &basic_info->resident_size_max);
5013 basic_info->policy = is_kernel_task ? POLICY_RR : POLICY_TIMESHARE;
5014 basic_info->suspend_count = task->user_stop_count;
5015 _task_fill_times(task, &basic_info->user_time,
5016 &basic_info->system_time);
5017
5018 *task_info_count = MACH_TASK_BASIC_INFO_COUNT;
5019 break;
5020 }
5021
5022 case TASK_THREAD_TIMES_INFO:
5023 {
5024 task_thread_times_info_t times_info;
5025 thread_t thread;
5026
5027 if (*task_info_count < TASK_THREAD_TIMES_INFO_COUNT) {
5028 error = KERN_INVALID_ARGUMENT;
5029 break;
5030 }
5031
5032 times_info = (task_thread_times_info_t)task_info_out;
5033 times_info->user_time = (time_value_t){ 0 };
5034 times_info->system_time = (time_value_t){ 0 };
5035
5036 queue_iterate(&task->threads, thread, thread_t, task_threads) {
5037 if ((thread->options & TH_OPT_IDLE_THREAD) == 0) {
5038 time_value_t user_time, system_time;
5039
5040 thread_read_times(thread, &user_time, &system_time, NULL);
5041 time_value_add(×_info->user_time, &user_time);
5042 time_value_add(×_info->system_time, &system_time);
5043 }
5044 }
5045
5046 *task_info_count = TASK_THREAD_TIMES_INFO_COUNT;
5047 break;
5048 }
5049
5050 case TASK_ABSOLUTETIME_INFO:
5051 {
5052 task_absolutetime_info_t info;
5053
5054 if (*task_info_count < TASK_ABSOLUTETIME_INFO_COUNT) {
5055 error = KERN_INVALID_ARGUMENT;
5056 break;
5057 }
5058
5059 info = (task_absolutetime_info_t)task_info_out;
5060
5061 struct recount_times_mach term_times =
5062 recount_task_terminated_times(task);
5063 struct recount_times_mach total_times = recount_task_times(task);
5064
5065 info->total_user = total_times.rtm_user;
5066 info->total_system = total_times.rtm_system;
5067 info->threads_user = total_times.rtm_user - term_times.rtm_user;
5068 info->threads_system += total_times.rtm_system - term_times.rtm_system;
5069
5070 *task_info_count = TASK_ABSOLUTETIME_INFO_COUNT;
5071 break;
5072 }
5073
5074 case TASK_DYLD_INFO:
5075 {
5076 task_dyld_info_t info;
5077
5078 /*
5079 * We added the format field to TASK_DYLD_INFO output. For
5080 * temporary backward compatibility, accept the fact that
5081 * clients may ask for the old version - distinquished by the
5082 * size of the expected result structure.
5083 */
5084 #define TASK_LEGACY_DYLD_INFO_COUNT \
5085 offsetof(struct task_dyld_info, all_image_info_format)/sizeof(natural_t)
5086
5087 if (*task_info_count < TASK_LEGACY_DYLD_INFO_COUNT) {
5088 error = KERN_INVALID_ARGUMENT;
5089 break;
5090 }
5091
5092 info = (task_dyld_info_t)task_info_out;
5093 info->all_image_info_addr = task->all_image_info_addr;
5094 info->all_image_info_size = task->all_image_info_size;
5095
5096 /* only set format on output for those expecting it */
5097 if (*task_info_count >= TASK_DYLD_INFO_COUNT) {
5098 info->all_image_info_format = task_has_64Bit_addr(task) ?
5099 TASK_DYLD_ALL_IMAGE_INFO_64 :
5100 TASK_DYLD_ALL_IMAGE_INFO_32;
5101 *task_info_count = TASK_DYLD_INFO_COUNT;
5102 } else {
5103 *task_info_count = TASK_LEGACY_DYLD_INFO_COUNT;
5104 }
5105 break;
5106 }
5107
5108 case TASK_EXTMOD_INFO:
5109 {
5110 task_extmod_info_t info;
5111 void *p;
5112
5113 if (*task_info_count < TASK_EXTMOD_INFO_COUNT) {
5114 error = KERN_INVALID_ARGUMENT;
5115 break;
5116 }
5117
5118 info = (task_extmod_info_t)task_info_out;
5119
5120 p = get_bsdtask_info(task);
5121 if (p) {
5122 proc_getexecutableuuid(p, info->task_uuid, sizeof(info->task_uuid));
5123 } else {
5124 bzero(info->task_uuid, sizeof(info->task_uuid));
5125 }
5126 info->extmod_statistics = task->extmod_statistics;
5127 *task_info_count = TASK_EXTMOD_INFO_COUNT;
5128
5129 break;
5130 }
5131
5132 case TASK_KERNELMEMORY_INFO:
5133 {
5134 task_kernelmemory_info_t tkm_info;
5135 ledger_amount_t credit, debit;
5136
5137 if (*task_info_count < TASK_KERNELMEMORY_INFO_COUNT) {
5138 error = KERN_INVALID_ARGUMENT;
5139 break;
5140 }
5141
5142 tkm_info = (task_kernelmemory_info_t) task_info_out;
5143 tkm_info->total_palloc = 0;
5144 tkm_info->total_pfree = 0;
5145 tkm_info->total_salloc = 0;
5146 tkm_info->total_sfree = 0;
5147
5148 if (task == kernel_task) {
5149 /*
5150 * All shared allocs/frees from other tasks count against
5151 * the kernel private memory usage. If we are looking up
5152 * info for the kernel task, gather from everywhere.
5153 */
5154 task_unlock(task);
5155
5156 /* start by accounting for all the terminated tasks against the kernel */
5157 tkm_info->total_palloc = tasks_tkm_private.alloc + tasks_tkm_shared.alloc;
5158 tkm_info->total_pfree = tasks_tkm_private.free + tasks_tkm_shared.free;
5159
5160 /* count all other task/thread shared alloc/free against the kernel */
5161 lck_mtx_lock(&tasks_threads_lock);
5162
5163 /* XXX this really shouldn't be using the function parameter 'task' as a local var! */
5164 queue_iterate(&tasks, task, task_t, tasks) {
5165 if (task == kernel_task) {
5166 if (ledger_get_entries(task->ledger,
5167 task_ledgers.tkm_private, &credit,
5168 &debit) == KERN_SUCCESS) {
5169 tkm_info->total_palloc += credit;
5170 tkm_info->total_pfree += debit;
5171 }
5172 }
5173 if (!ledger_get_entries(task->ledger,
5174 task_ledgers.tkm_shared, &credit, &debit)) {
5175 tkm_info->total_palloc += credit;
5176 tkm_info->total_pfree += debit;
5177 }
5178 }
5179 lck_mtx_unlock(&tasks_threads_lock);
5180 } else {
5181 if (!ledger_get_entries(task->ledger,
5182 task_ledgers.tkm_private, &credit, &debit)) {
5183 tkm_info->total_palloc = credit;
5184 tkm_info->total_pfree = debit;
5185 }
5186 if (!ledger_get_entries(task->ledger,
5187 task_ledgers.tkm_shared, &credit, &debit)) {
5188 tkm_info->total_salloc = credit;
5189 tkm_info->total_sfree = debit;
5190 }
5191 task_unlock(task);
5192 }
5193
5194 *task_info_count = TASK_KERNELMEMORY_INFO_COUNT;
5195 return KERN_SUCCESS;
5196 }
5197
5198 /* OBSOLETE */
5199 case TASK_SCHED_FIFO_INFO:
5200 {
5201 if (*task_info_count < POLICY_FIFO_BASE_COUNT) {
5202 error = KERN_INVALID_ARGUMENT;
5203 break;
5204 }
5205
5206 error = KERN_INVALID_POLICY;
5207 break;
5208 }
5209
5210 /* OBSOLETE */
5211 case TASK_SCHED_RR_INFO:
5212 {
5213 policy_rr_base_t rr_base;
5214 uint32_t quantum_time;
5215 uint64_t quantum_ns;
5216
5217 if (*task_info_count < POLICY_RR_BASE_COUNT) {
5218 error = KERN_INVALID_ARGUMENT;
5219 break;
5220 }
5221
5222 rr_base = (policy_rr_base_t) task_info_out;
5223
5224 if (task != kernel_task) {
5225 error = KERN_INVALID_POLICY;
5226 break;
5227 }
5228
5229 rr_base->base_priority = task->priority;
5230
5231 quantum_time = SCHED(initial_quantum_size)(THREAD_NULL);
5232 absolutetime_to_nanoseconds(quantum_time, &quantum_ns);
5233
5234 rr_base->quantum = (uint32_t)(quantum_ns / 1000 / 1000);
5235
5236 *task_info_count = POLICY_RR_BASE_COUNT;
5237 break;
5238 }
5239
5240 /* OBSOLETE */
5241 case TASK_SCHED_TIMESHARE_INFO:
5242 {
5243 policy_timeshare_base_t ts_base;
5244
5245 if (*task_info_count < POLICY_TIMESHARE_BASE_COUNT) {
5246 error = KERN_INVALID_ARGUMENT;
5247 break;
5248 }
5249
5250 ts_base = (policy_timeshare_base_t) task_info_out;
5251
5252 if (task == kernel_task) {
5253 error = KERN_INVALID_POLICY;
5254 break;
5255 }
5256
5257 ts_base->base_priority = task->priority;
5258
5259 *task_info_count = POLICY_TIMESHARE_BASE_COUNT;
5260 break;
5261 }
5262
5263 case TASK_SECURITY_TOKEN:
5264 {
5265 security_token_t *sec_token_p;
5266
5267 if (*task_info_count < TASK_SECURITY_TOKEN_COUNT) {
5268 error = KERN_INVALID_ARGUMENT;
5269 break;
5270 }
5271
5272 sec_token_p = (security_token_t *) task_info_out;
5273
5274 *sec_token_p = *task_get_sec_token(task);
5275
5276 *task_info_count = TASK_SECURITY_TOKEN_COUNT;
5277 break;
5278 }
5279
5280 case TASK_AUDIT_TOKEN:
5281 {
5282 audit_token_t *audit_token_p;
5283
5284 if (*task_info_count < TASK_AUDIT_TOKEN_COUNT) {
5285 error = KERN_INVALID_ARGUMENT;
5286 break;
5287 }
5288
5289 audit_token_p = (audit_token_t *) task_info_out;
5290
5291 *audit_token_p = *task_get_audit_token(task);
5292
5293 *task_info_count = TASK_AUDIT_TOKEN_COUNT;
5294 break;
5295 }
5296
5297 case TASK_SCHED_INFO:
5298 error = KERN_INVALID_ARGUMENT;
5299 break;
5300
5301 case TASK_EVENTS_INFO:
5302 {
5303 task_events_info_t events_info;
5304 thread_t thread;
5305 uint64_t n_syscalls_mach, n_syscalls_unix, n_csw;
5306
5307 if (*task_info_count < TASK_EVENTS_INFO_COUNT) {
5308 error = KERN_INVALID_ARGUMENT;
5309 break;
5310 }
5311
5312 events_info = (task_events_info_t) task_info_out;
5313
5314
5315 events_info->faults = (int32_t) MIN(counter_load(&task->faults), INT32_MAX);
5316 events_info->pageins = (int32_t) MIN(counter_load(&task->pageins), INT32_MAX);
5317 events_info->cow_faults = (int32_t) MIN(counter_load(&task->cow_faults), INT32_MAX);
5318 events_info->messages_sent = (int32_t) MIN(counter_load(&task->messages_sent), INT32_MAX);
5319 events_info->messages_received = (int32_t) MIN(counter_load(&task->messages_received), INT32_MAX);
5320
5321 n_syscalls_mach = task->syscalls_mach;
5322 n_syscalls_unix = task->syscalls_unix;
5323 n_csw = task->c_switch;
5324
5325 queue_iterate(&task->threads, thread, thread_t, task_threads) {
5326 n_csw += thread->c_switch;
5327 n_syscalls_mach += thread->syscalls_mach;
5328 n_syscalls_unix += thread->syscalls_unix;
5329 }
5330
5331 events_info->syscalls_mach = (int32_t) MIN(n_syscalls_mach, INT32_MAX);
5332 events_info->syscalls_unix = (int32_t) MIN(n_syscalls_unix, INT32_MAX);
5333 events_info->csw = (int32_t) MIN(n_csw, INT32_MAX);
5334
5335 *task_info_count = TASK_EVENTS_INFO_COUNT;
5336 break;
5337 }
5338 case TASK_AFFINITY_TAG_INFO:
5339 {
5340 if (*task_info_count < TASK_AFFINITY_TAG_INFO_COUNT) {
5341 error = KERN_INVALID_ARGUMENT;
5342 break;
5343 }
5344
5345 error = task_affinity_info(task, task_info_out, task_info_count);
5346 break;
5347 }
5348 case TASK_POWER_INFO:
5349 {
5350 if (*task_info_count < TASK_POWER_INFO_COUNT) {
5351 error = KERN_INVALID_ARGUMENT;
5352 break;
5353 }
5354
5355 task_power_info_locked(task, (task_power_info_t)task_info_out, NULL, NULL, NULL);
5356 break;
5357 }
5358
5359 case TASK_POWER_INFO_V2:
5360 {
5361 if (*task_info_count < TASK_POWER_INFO_V2_COUNT_OLD) {
5362 error = KERN_INVALID_ARGUMENT;
5363 break;
5364 }
5365 task_power_info_v2_t tpiv2 = (task_power_info_v2_t) task_info_out;
5366 task_power_info_locked(task, &tpiv2->cpu_energy, &tpiv2->gpu_energy, tpiv2, NULL);
5367 break;
5368 }
5369
5370 case TASK_VM_INFO:
5371 case TASK_VM_INFO_PURGEABLE:
5372 {
5373 task_vm_info_t vm_info;
5374 vm_map_t map;
5375 ledger_amount_t tmp_amount;
5376
5377 struct proc *p;
5378 uint32_t platform, sdk;
5379 p = current_proc();
5380 platform = proc_platform(p);
5381 sdk = proc_sdk(p);
5382 if (original_task_info_count > TASK_VM_INFO_COUNT) {
5383 /*
5384 * Some iOS apps pass an incorrect value for
5385 * task_info_count, expressed in number of bytes
5386 * instead of number of "natural_t" elements, which
5387 * can lead to binary compatibility issues (including
5388 * stack corruption) when the data structure is
5389 * expanded in the future.
5390 * Let's make this potential issue visible by
5391 * logging about it...
5392 */
5393 printf("%s:%d %d[%s] task_info(flavor=%d) possibly invalid "
5394 "task_info_count=%d > TASK_VM_INFO_COUNT=%d platform %d sdk "
5395 "%d.%d.%d - please use TASK_VM_INFO_COUNT.\n",
5396 __FUNCTION__, __LINE__, proc_pid(p), proc_name_address(p),
5397 flavor, original_task_info_count, TASK_VM_INFO_COUNT,
5398 platform, (sdk >> 16), ((sdk >> 8) & 0xff), (sdk & 0xff));
5399 DTRACE_VM4(suspicious_task_vm_info_count,
5400 mach_msg_type_number_t, original_task_info_count,
5401 mach_msg_type_number_t, TASK_VM_INFO_COUNT,
5402 uint32_t, platform,
5403 uint32_t, sdk);
5404 }
5405 #if __arm64__
5406 if (original_task_info_count > TASK_VM_INFO_REV2_COUNT &&
5407 platform == PLATFORM_IOS &&
5408 sdk != 0 &&
5409 (sdk >> 16) <= 12) {
5410 /*
5411 * Some iOS apps pass an incorrect value for
5412 * task_info_count, expressed in number of bytes
5413 * instead of number of "natural_t" elements.
5414 * For the sake of backwards binary compatibility
5415 * for apps built with an iOS12 or older SDK and using
5416 * the "rev2" data structure, let's fix task_info_count
5417 * for them, to avoid stomping past the actual end
5418 * of their buffer.
5419 */
5420 #if DEVELOPMENT || DEBUG
5421 printf("%s:%d %d[%s] rdar://49484582 task_info_count %d -> %d "
5422 "platform %d sdk %d.%d.%d\n", __FUNCTION__, __LINE__, proc_pid(p),
5423 proc_name_address(p), original_task_info_count,
5424 TASK_VM_INFO_REV2_COUNT, platform, (sdk >> 16),
5425 ((sdk >> 8) & 0xff), (sdk & 0xff));
5426 #endif /* DEVELOPMENT || DEBUG */
5427 DTRACE_VM4(workaround_task_vm_info_count,
5428 mach_msg_type_number_t, original_task_info_count,
5429 mach_msg_type_number_t, TASK_VM_INFO_REV2_COUNT,
5430 uint32_t, platform,
5431 uint32_t, sdk);
5432 original_task_info_count = TASK_VM_INFO_REV2_COUNT;
5433 *task_info_count = original_task_info_count;
5434 }
5435 if (original_task_info_count > TASK_VM_INFO_REV5_COUNT &&
5436 platform == PLATFORM_IOS &&
5437 sdk != 0 &&
5438 (sdk >> 16) <= 15) {
5439 /*
5440 * Some iOS apps pass an incorrect value for
5441 * task_info_count, expressed in number of bytes
5442 * instead of number of "natural_t" elements.
5443 */
5444 printf("%s:%d %d[%s] task_info_count=%d > TASK_VM_INFO_COUNT=%d "
5445 "platform %d sdk %d.%d.%d\n", __FUNCTION__, __LINE__, proc_pid(p),
5446 proc_name_address(p), original_task_info_count,
5447 TASK_VM_INFO_REV5_COUNT, platform, (sdk >> 16),
5448 ((sdk >> 8) & 0xff), (sdk & 0xff));
5449 DTRACE_VM4(workaround_task_vm_info_count,
5450 mach_msg_type_number_t, original_task_info_count,
5451 mach_msg_type_number_t, TASK_VM_INFO_REV5_COUNT,
5452 uint32_t, platform,
5453 uint32_t, sdk);
5454 #if DEVELOPMENT || DEBUG
5455 /*
5456 * For the sake of internal builds livability,
5457 * work around this user-space bug by capping the
5458 * buffer's size to what it was with the iOS15 SDK.
5459 */
5460 original_task_info_count = TASK_VM_INFO_REV5_COUNT;
5461 *task_info_count = original_task_info_count;
5462 #endif /* DEVELOPMENT || DEBUG */
5463 }
5464 #endif /* __arm64__ */
5465
5466 if (*task_info_count < TASK_VM_INFO_REV0_COUNT) {
5467 error = KERN_INVALID_ARGUMENT;
5468 break;
5469 }
5470
5471 vm_info = (task_vm_info_t)task_info_out;
5472
5473 /*
5474 * Do not hold both the task and map locks,
5475 * so convert the task lock into a map reference,
5476 * drop the task lock, then lock the map.
5477 */
5478 if (is_kernel_task) {
5479 map = kernel_map;
5480 task_unlock(task);
5481 /* no lock, no reference */
5482 } else {
5483 map = task->map;
5484 vm_map_reference(map);
5485 task_unlock(task);
5486 vm_map_lock_read(map);
5487 }
5488
5489 vm_info->virtual_size = (typeof(vm_info->virtual_size))vm_map_adjusted_size(map);
5490 vm_info->region_count = map->hdr.nentries;
5491 vm_info->page_size = vm_map_page_size(map);
5492
5493 ledger_get_balance(task->ledger, task_ledgers.phys_mem, (ledger_amount_t *) &vm_info->resident_size);
5494 ledger_get_lifetime_max(task->ledger, task_ledgers.phys_mem, (ledger_amount_t *) &vm_info->resident_size_peak);
5495
5496 vm_info->device = 0;
5497 vm_info->device_peak = 0;
5498 ledger_get_balance(task->ledger, task_ledgers.external, (ledger_amount_t *) &vm_info->external);
5499 ledger_get_lifetime_max(task->ledger, task_ledgers.external, (ledger_amount_t *) &vm_info->external_peak);
5500 ledger_get_balance(task->ledger, task_ledgers.internal, (ledger_amount_t *) &vm_info->internal);
5501 ledger_get_lifetime_max(task->ledger, task_ledgers.internal, (ledger_amount_t *) &vm_info->internal_peak);
5502 ledger_get_balance(task->ledger, task_ledgers.reusable, (ledger_amount_t *) &vm_info->reusable);
5503 ledger_get_lifetime_max(task->ledger, task_ledgers.reusable, (ledger_amount_t *) &vm_info->reusable_peak);
5504 ledger_get_balance(task->ledger, task_ledgers.internal_compressed, (ledger_amount_t*) &vm_info->compressed);
5505 ledger_get_lifetime_max(task->ledger, task_ledgers.internal_compressed, (ledger_amount_t*) &vm_info->compressed_peak);
5506 ledger_get_entries(task->ledger, task_ledgers.internal_compressed, (ledger_amount_t*) &vm_info->compressed_lifetime, &tmp_amount);
5507
5508 vm_info->purgeable_volatile_pmap = 0;
5509 vm_info->purgeable_volatile_resident = 0;
5510 vm_info->purgeable_volatile_virtual = 0;
5511 if (is_kernel_task) {
5512 /*
5513 * We do not maintain the detailed stats for the
5514 * kernel_pmap, so just count everything as
5515 * "internal"...
5516 */
5517 vm_info->internal = vm_info->resident_size;
5518 /*
5519 * ... but since the memory held by the VM compressor
5520 * in the kernel address space ought to be attributed
5521 * to user-space tasks, we subtract it from "internal"
5522 * to give memory reporting tools a more accurate idea
5523 * of what the kernel itself is actually using, instead
5524 * of making it look like the kernel is leaking memory
5525 * when the system is under memory pressure.
5526 */
5527 vm_info->internal -= (VM_PAGE_COMPRESSOR_COUNT *
5528 PAGE_SIZE);
5529 } else {
5530 mach_vm_size_t volatile_virtual_size;
5531 mach_vm_size_t volatile_resident_size;
5532 mach_vm_size_t volatile_compressed_size;
5533 mach_vm_size_t volatile_pmap_size;
5534 mach_vm_size_t volatile_compressed_pmap_size;
5535 kern_return_t kr;
5536
5537 if (flavor == TASK_VM_INFO_PURGEABLE) {
5538 kr = vm_map_query_volatile(
5539 map,
5540 &volatile_virtual_size,
5541 &volatile_resident_size,
5542 &volatile_compressed_size,
5543 &volatile_pmap_size,
5544 &volatile_compressed_pmap_size);
5545 if (kr == KERN_SUCCESS) {
5546 vm_info->purgeable_volatile_pmap =
5547 volatile_pmap_size;
5548 if (radar_20146450) {
5549 vm_info->compressed -=
5550 volatile_compressed_pmap_size;
5551 }
5552 vm_info->purgeable_volatile_resident =
5553 volatile_resident_size;
5554 vm_info->purgeable_volatile_virtual =
5555 volatile_virtual_size;
5556 }
5557 }
5558 }
5559 *task_info_count = TASK_VM_INFO_REV0_COUNT;
5560
5561 if (original_task_info_count >= TASK_VM_INFO_REV2_COUNT) {
5562 /* must be captured while we still have the map lock */
5563 vm_info->min_address = map->min_offset;
5564 vm_info->max_address = map->max_offset;
5565 }
5566
5567 /*
5568 * Done with vm map things, can drop the map lock and reference,
5569 * and take the task lock back.
5570 *
5571 * Re-validate that the task didn't die on us.
5572 */
5573 if (!is_kernel_task) {
5574 vm_map_unlock_read(map);
5575 vm_map_deallocate(map);
5576 }
5577 map = VM_MAP_NULL;
5578
5579 task_lock(task);
5580
5581 if ((task != current_task()) && (!task->active)) {
5582 error = KERN_INVALID_ARGUMENT;
5583 break;
5584 }
5585
5586 if (original_task_info_count >= TASK_VM_INFO_REV1_COUNT) {
5587 vm_info->phys_footprint =
5588 (mach_vm_size_t) get_task_phys_footprint(task);
5589 *task_info_count = TASK_VM_INFO_REV1_COUNT;
5590 }
5591 if (original_task_info_count >= TASK_VM_INFO_REV2_COUNT) {
5592 /* data was captured above */
5593 *task_info_count = TASK_VM_INFO_REV2_COUNT;
5594 }
5595
5596 if (original_task_info_count >= TASK_VM_INFO_REV3_COUNT) {
5597 ledger_get_lifetime_max(task->ledger,
5598 task_ledgers.phys_footprint,
5599 &vm_info->ledger_phys_footprint_peak);
5600 ledger_get_balance(task->ledger,
5601 task_ledgers.purgeable_nonvolatile,
5602 &vm_info->ledger_purgeable_nonvolatile);
5603 ledger_get_balance(task->ledger,
5604 task_ledgers.purgeable_nonvolatile_compressed,
5605 &vm_info->ledger_purgeable_novolatile_compressed);
5606 ledger_get_balance(task->ledger,
5607 task_ledgers.purgeable_volatile,
5608 &vm_info->ledger_purgeable_volatile);
5609 ledger_get_balance(task->ledger,
5610 task_ledgers.purgeable_volatile_compressed,
5611 &vm_info->ledger_purgeable_volatile_compressed);
5612 ledger_get_balance(task->ledger,
5613 task_ledgers.network_nonvolatile,
5614 &vm_info->ledger_tag_network_nonvolatile);
5615 ledger_get_balance(task->ledger,
5616 task_ledgers.network_nonvolatile_compressed,
5617 &vm_info->ledger_tag_network_nonvolatile_compressed);
5618 ledger_get_balance(task->ledger,
5619 task_ledgers.network_volatile,
5620 &vm_info->ledger_tag_network_volatile);
5621 ledger_get_balance(task->ledger,
5622 task_ledgers.network_volatile_compressed,
5623 &vm_info->ledger_tag_network_volatile_compressed);
5624 ledger_get_balance(task->ledger,
5625 task_ledgers.media_footprint,
5626 &vm_info->ledger_tag_media_footprint);
5627 ledger_get_balance(task->ledger,
5628 task_ledgers.media_footprint_compressed,
5629 &vm_info->ledger_tag_media_footprint_compressed);
5630 ledger_get_balance(task->ledger,
5631 task_ledgers.media_nofootprint,
5632 &vm_info->ledger_tag_media_nofootprint);
5633 ledger_get_balance(task->ledger,
5634 task_ledgers.media_nofootprint_compressed,
5635 &vm_info->ledger_tag_media_nofootprint_compressed);
5636 ledger_get_balance(task->ledger,
5637 task_ledgers.graphics_footprint,
5638 &vm_info->ledger_tag_graphics_footprint);
5639 ledger_get_balance(task->ledger,
5640 task_ledgers.graphics_footprint_compressed,
5641 &vm_info->ledger_tag_graphics_footprint_compressed);
5642 ledger_get_balance(task->ledger,
5643 task_ledgers.graphics_nofootprint,
5644 &vm_info->ledger_tag_graphics_nofootprint);
5645 ledger_get_balance(task->ledger,
5646 task_ledgers.graphics_nofootprint_compressed,
5647 &vm_info->ledger_tag_graphics_nofootprint_compressed);
5648 ledger_get_balance(task->ledger,
5649 task_ledgers.neural_footprint,
5650 &vm_info->ledger_tag_neural_footprint);
5651 ledger_get_balance(task->ledger,
5652 task_ledgers.neural_footprint_compressed,
5653 &vm_info->ledger_tag_neural_footprint_compressed);
5654 ledger_get_balance(task->ledger,
5655 task_ledgers.neural_nofootprint,
5656 &vm_info->ledger_tag_neural_nofootprint);
5657 ledger_get_balance(task->ledger,
5658 task_ledgers.neural_nofootprint_compressed,
5659 &vm_info->ledger_tag_neural_nofootprint_compressed);
5660 *task_info_count = TASK_VM_INFO_REV3_COUNT;
5661 }
5662 if (original_task_info_count >= TASK_VM_INFO_REV4_COUNT) {
5663 if (get_bsdtask_info(task)) {
5664 vm_info->limit_bytes_remaining =
5665 memorystatus_available_memory_internal(get_bsdtask_info(task));
5666 } else {
5667 vm_info->limit_bytes_remaining = 0;
5668 }
5669 *task_info_count = TASK_VM_INFO_REV4_COUNT;
5670 }
5671 if (original_task_info_count >= TASK_VM_INFO_REV5_COUNT) {
5672 thread_t thread;
5673 uint64_t total = task->decompressions;
5674 queue_iterate(&task->threads, thread, thread_t, task_threads) {
5675 total += thread->decompressions;
5676 }
5677 vm_info->decompressions = (int32_t) MIN(total, INT32_MAX);
5678 *task_info_count = TASK_VM_INFO_REV5_COUNT;
5679 }
5680 if (original_task_info_count >= TASK_VM_INFO_REV6_COUNT) {
5681 ledger_get_balance(task->ledger, task_ledgers.swapins,
5682 &vm_info->ledger_swapins);
5683 *task_info_count = TASK_VM_INFO_REV6_COUNT;
5684 }
5685
5686 break;
5687 }
5688
5689 case TASK_WAIT_STATE_INFO:
5690 {
5691 /*
5692 * Deprecated flavor. Currently allowing some results until all users
5693 * stop calling it. The results may not be accurate.
5694 */
5695 task_wait_state_info_t wait_state_info;
5696 uint64_t total_sfi_ledger_val = 0;
5697
5698 if (*task_info_count < TASK_WAIT_STATE_INFO_COUNT) {
5699 error = KERN_INVALID_ARGUMENT;
5700 break;
5701 }
5702
5703 wait_state_info = (task_wait_state_info_t) task_info_out;
5704
5705 wait_state_info->total_wait_state_time = 0;
5706 bzero(wait_state_info->_reserved, sizeof(wait_state_info->_reserved));
5707
5708 #if CONFIG_SCHED_SFI
5709 int i, prev_lentry = -1;
5710 int64_t val_credit, val_debit;
5711
5712 for (i = 0; i < MAX_SFI_CLASS_ID; i++) {
5713 val_credit = 0;
5714 /*
5715 * checking with prev_lentry != entry ensures adjacent classes
5716 * which share the same ledger do not add wait times twice.
5717 * Note: Use ledger() call to get data for each individual sfi class.
5718 */
5719 if (prev_lentry != task_ledgers.sfi_wait_times[i] &&
5720 KERN_SUCCESS == ledger_get_entries(task->ledger,
5721 task_ledgers.sfi_wait_times[i], &val_credit, &val_debit)) {
5722 total_sfi_ledger_val += val_credit;
5723 }
5724 prev_lentry = task_ledgers.sfi_wait_times[i];
5725 }
5726
5727 #endif /* CONFIG_SCHED_SFI */
5728 wait_state_info->total_wait_sfi_state_time = total_sfi_ledger_val;
5729 *task_info_count = TASK_WAIT_STATE_INFO_COUNT;
5730
5731 break;
5732 }
5733 case TASK_VM_INFO_PURGEABLE_ACCOUNT:
5734 {
5735 #if DEVELOPMENT || DEBUG
5736 pvm_account_info_t acnt_info;
5737
5738 if (*task_info_count < PVM_ACCOUNT_INFO_COUNT) {
5739 error = KERN_INVALID_ARGUMENT;
5740 break;
5741 }
5742
5743 if (task_info_out == NULL) {
5744 error = KERN_INVALID_ARGUMENT;
5745 break;
5746 }
5747
5748 acnt_info = (pvm_account_info_t) task_info_out;
5749
5750 error = vm_purgeable_account(task, acnt_info);
5751
5752 *task_info_count = PVM_ACCOUNT_INFO_COUNT;
5753
5754 break;
5755 #else /* DEVELOPMENT || DEBUG */
5756 error = KERN_NOT_SUPPORTED;
5757 break;
5758 #endif /* DEVELOPMENT || DEBUG */
5759 }
5760 case TASK_FLAGS_INFO:
5761 {
5762 task_flags_info_t flags_info;
5763
5764 if (*task_info_count < TASK_FLAGS_INFO_COUNT) {
5765 error = KERN_INVALID_ARGUMENT;
5766 break;
5767 }
5768
5769 flags_info = (task_flags_info_t)task_info_out;
5770
5771 /* only publish the 64-bit flag of the task */
5772 flags_info->flags = task->t_flags & (TF_64B_ADDR | TF_64B_DATA);
5773
5774 *task_info_count = TASK_FLAGS_INFO_COUNT;
5775 break;
5776 }
5777
5778 case TASK_DEBUG_INFO_INTERNAL:
5779 {
5780 #if DEVELOPMENT || DEBUG
5781 task_debug_info_internal_t dbg_info;
5782 ipc_space_t space = task->itk_space;
5783 if (*task_info_count < TASK_DEBUG_INFO_INTERNAL_COUNT) {
5784 error = KERN_NOT_SUPPORTED;
5785 break;
5786 }
5787
5788 if (task_info_out == NULL) {
5789 error = KERN_INVALID_ARGUMENT;
5790 break;
5791 }
5792 dbg_info = (task_debug_info_internal_t) task_info_out;
5793 dbg_info->ipc_space_size = 0;
5794
5795 if (space) {
5796 smr_global_enter();
5797 ipc_entry_table_t table = smr_entered_load(&space->is_table);
5798 if (table) {
5799 dbg_info->ipc_space_size =
5800 ipc_entry_table_count(table);
5801 }
5802 smr_global_leave();
5803 }
5804
5805 dbg_info->suspend_count = task->suspend_count;
5806
5807 error = KERN_SUCCESS;
5808 *task_info_count = TASK_DEBUG_INFO_INTERNAL_COUNT;
5809 break;
5810 #else /* DEVELOPMENT || DEBUG */
5811 error = KERN_NOT_SUPPORTED;
5812 break;
5813 #endif /* DEVELOPMENT || DEBUG */
5814 }
5815 default:
5816 error = KERN_INVALID_ARGUMENT;
5817 }
5818
5819 task_unlock(task);
5820 return error;
5821 }
5822
5823 /*
5824 * task_info_from_user
5825 *
5826 * When calling task_info from user space,
5827 * this function will be executed as mig server side
5828 * instead of calling directly into task_info.
5829 * This gives the possibility to perform more security
5830 * checks on task_port.
5831 *
5832 * In the case of TASK_DYLD_INFO, we require the more
5833 * privileged task_read_port not the less-privileged task_name_port.
5834 *
5835 */
5836 kern_return_t
task_info_from_user(mach_port_t task_port,task_flavor_t flavor,task_info_t task_info_out,mach_msg_type_number_t * task_info_count)5837 task_info_from_user(
5838 mach_port_t task_port,
5839 task_flavor_t flavor,
5840 task_info_t task_info_out,
5841 mach_msg_type_number_t *task_info_count)
5842 {
5843 task_t task;
5844 kern_return_t ret;
5845
5846 if (flavor == TASK_DYLD_INFO) {
5847 task = convert_port_to_task_read(task_port);
5848 } else {
5849 task = convert_port_to_task_name(task_port);
5850 }
5851
5852 ret = task_info(task, flavor, task_info_out, task_info_count);
5853
5854 task_deallocate(task);
5855
5856 return ret;
5857 }
5858
5859 /*
5860 * Routine: task_dyld_process_info_update_helper
5861 *
5862 * Release send rights in release_ports.
5863 *
5864 * If no active ports found in task's dyld notifier array, unset the magic value
5865 * in user space to indicate so.
5866 *
5867 * Condition:
5868 * task's itk_lock is locked, and is unlocked upon return.
5869 * Global g_dyldinfo_mtx is locked, and is unlocked upon return.
5870 */
5871 void
task_dyld_process_info_update_helper(task_t task,size_t active_count,vm_map_address_t magic_addr,ipc_port_t * release_ports,size_t release_count)5872 task_dyld_process_info_update_helper(
5873 task_t task,
5874 size_t active_count,
5875 vm_map_address_t magic_addr, /* a userspace address */
5876 ipc_port_t *release_ports,
5877 size_t release_count)
5878 {
5879 void *notifiers_ptr = NULL;
5880
5881 assert(release_count <= DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT);
5882
5883 if (active_count == 0) {
5884 assert(task->itk_dyld_notify != NULL);
5885 notifiers_ptr = task->itk_dyld_notify;
5886 task->itk_dyld_notify = NULL;
5887 itk_unlock(task);
5888
5889 kfree_type(ipc_port_t, DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT, notifiers_ptr);
5890 (void)copyoutmap_atomic32(task->map, MACH_PORT_NULL, magic_addr); /* unset magic */
5891 } else {
5892 itk_unlock(task);
5893 (void)copyoutmap_atomic32(task->map, (mach_port_name_t)DYLD_PROCESS_INFO_NOTIFY_MAGIC,
5894 magic_addr); /* reset magic */
5895 }
5896
5897 lck_mtx_unlock(&g_dyldinfo_mtx);
5898
5899 for (size_t i = 0; i < release_count; i++) {
5900 ipc_port_release_send(release_ports[i]);
5901 }
5902 }
5903
5904 /*
5905 * Routine: task_dyld_process_info_notify_register
5906 *
5907 * Insert a send right to target task's itk_dyld_notify array. Allocate kernel
5908 * memory for the array if it's the first port to be registered. Also cleanup
5909 * any dead rights found in the array.
5910 *
5911 * Consumes sright if returns KERN_SUCCESS, otherwise MIG will destroy it.
5912 *
5913 * Args:
5914 * task: Target task for the registration.
5915 * sright: A send right.
5916 *
5917 * Returns:
5918 * KERN_SUCCESS: Registration succeeded.
5919 * KERN_INVALID_TASK: task is invalid.
5920 * KERN_INVALID_RIGHT: sright is invalid.
5921 * KERN_DENIED: Security policy denied this call.
5922 * KERN_RESOURCE_SHORTAGE: Kernel memory allocation failed.
5923 * KERN_NO_SPACE: No available notifier port slot left for this task.
5924 * KERN_RIGHT_EXISTS: The notifier port is already registered and active.
5925 *
5926 * Other error code see task_info().
5927 *
5928 * See Also:
5929 * task_dyld_process_info_notify_get_trap() in mach_kernelrpc.c
5930 */
5931 kern_return_t
task_dyld_process_info_notify_register(task_t task,ipc_port_t sright)5932 task_dyld_process_info_notify_register(
5933 task_t task,
5934 ipc_port_t sright)
5935 {
5936 struct task_dyld_info dyld_info;
5937 mach_msg_type_number_t info_count = TASK_DYLD_INFO_COUNT;
5938 ipc_port_t release_ports[DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT];
5939 uint32_t release_count = 0, active_count = 0;
5940 mach_vm_address_t ports_addr; /* a user space address */
5941 kern_return_t kr;
5942 boolean_t right_exists = false;
5943 ipc_port_t *notifiers_ptr = NULL;
5944 ipc_port_t *portp;
5945
5946 if (task == TASK_NULL || task == kernel_task) {
5947 return KERN_INVALID_TASK;
5948 }
5949
5950 if (!IP_VALID(sright)) {
5951 return KERN_INVALID_RIGHT;
5952 }
5953
5954 #if CONFIG_MACF
5955 if (mac_task_check_dyld_process_info_notify_register()) {
5956 return KERN_DENIED;
5957 }
5958 #endif
5959
5960 kr = task_info(task, TASK_DYLD_INFO, (task_info_t)&dyld_info, &info_count);
5961 if (kr) {
5962 return kr;
5963 }
5964
5965 if (dyld_info.all_image_info_format == TASK_DYLD_ALL_IMAGE_INFO_32) {
5966 ports_addr = (mach_vm_address_t)(dyld_info.all_image_info_addr +
5967 offsetof(struct user32_dyld_all_image_infos, notifyMachPorts));
5968 } else {
5969 ports_addr = (mach_vm_address_t)(dyld_info.all_image_info_addr +
5970 offsetof(struct user64_dyld_all_image_infos, notifyMachPorts));
5971 }
5972
5973 if (task->itk_dyld_notify == NULL) {
5974 notifiers_ptr = kalloc_type(ipc_port_t,
5975 DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT,
5976 Z_WAITOK | Z_ZERO | Z_NOFAIL);
5977 }
5978
5979 lck_mtx_lock(&g_dyldinfo_mtx);
5980 itk_lock(task);
5981
5982 if (task->itk_dyld_notify == NULL) {
5983 task->itk_dyld_notify = notifiers_ptr;
5984 notifiers_ptr = NULL;
5985 }
5986
5987 assert(task->itk_dyld_notify != NULL);
5988 /* First pass: clear dead names and check for duplicate registration */
5989 for (int slot = 0; slot < DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT; slot++) {
5990 portp = &task->itk_dyld_notify[slot];
5991 if (*portp != IPC_PORT_NULL && !ip_active(*portp)) {
5992 release_ports[release_count++] = *portp;
5993 *portp = IPC_PORT_NULL;
5994 } else if (*portp == sright) {
5995 /* the port is already registered and is active */
5996 right_exists = true;
5997 }
5998
5999 if (*portp != IPC_PORT_NULL) {
6000 active_count++;
6001 }
6002 }
6003
6004 if (right_exists) {
6005 /* skip second pass */
6006 kr = KERN_RIGHT_EXISTS;
6007 goto out;
6008 }
6009
6010 /* Second pass: register the port */
6011 kr = KERN_NO_SPACE;
6012 for (int slot = 0; slot < DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT; slot++) {
6013 portp = &task->itk_dyld_notify[slot];
6014 if (*portp == IPC_PORT_NULL) {
6015 *portp = sright;
6016 active_count++;
6017 kr = KERN_SUCCESS;
6018 break;
6019 }
6020 }
6021
6022 out:
6023 assert(active_count > 0);
6024
6025 task_dyld_process_info_update_helper(task, active_count,
6026 (vm_map_address_t)ports_addr, release_ports, release_count);
6027 /* itk_lock, g_dyldinfo_mtx are unlocked upon return */
6028
6029 kfree_type(ipc_port_t, DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT, notifiers_ptr);
6030
6031 return kr;
6032 }
6033
6034 /*
6035 * Routine: task_dyld_process_info_notify_deregister
6036 *
6037 * Remove a send right in target task's itk_dyld_notify array matching the receive
6038 * right name passed in. Deallocate kernel memory for the array if it's the last port to
6039 * be deregistered, or all ports have died. Also cleanup any dead rights found in the array.
6040 *
6041 * Does not consume any reference.
6042 *
6043 * Args:
6044 * task: Target task for the deregistration.
6045 * rcv_name: The name denoting the receive right in caller's space.
6046 *
6047 * Returns:
6048 * KERN_SUCCESS: A matching entry found and degistration succeeded.
6049 * KERN_INVALID_TASK: task is invalid.
6050 * KERN_INVALID_NAME: name is invalid.
6051 * KERN_DENIED: Security policy denied this call.
6052 * KERN_FAILURE: A matching entry is not found.
6053 * KERN_INVALID_RIGHT: The name passed in does not represent a valid rcv right.
6054 *
6055 * Other error code see task_info().
6056 *
6057 * See Also:
6058 * task_dyld_process_info_notify_get_trap() in mach_kernelrpc.c
6059 */
6060 kern_return_t
task_dyld_process_info_notify_deregister(task_t task,mach_port_name_t rcv_name)6061 task_dyld_process_info_notify_deregister(
6062 task_t task,
6063 mach_port_name_t rcv_name)
6064 {
6065 struct task_dyld_info dyld_info;
6066 mach_msg_type_number_t info_count = TASK_DYLD_INFO_COUNT;
6067 ipc_port_t release_ports[DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT];
6068 uint32_t release_count = 0, active_count = 0;
6069 boolean_t port_found = false;
6070 mach_vm_address_t ports_addr; /* a user space address */
6071 ipc_port_t sright;
6072 kern_return_t kr;
6073 ipc_port_t *portp;
6074
6075 if (task == TASK_NULL || task == kernel_task) {
6076 return KERN_INVALID_TASK;
6077 }
6078
6079 if (!MACH_PORT_VALID(rcv_name)) {
6080 return KERN_INVALID_NAME;
6081 }
6082
6083 #if CONFIG_MACF
6084 if (mac_task_check_dyld_process_info_notify_register()) {
6085 return KERN_DENIED;
6086 }
6087 #endif
6088
6089 kr = task_info(task, TASK_DYLD_INFO, (task_info_t)&dyld_info, &info_count);
6090 if (kr) {
6091 return kr;
6092 }
6093
6094 if (dyld_info.all_image_info_format == TASK_DYLD_ALL_IMAGE_INFO_32) {
6095 ports_addr = (mach_vm_address_t)(dyld_info.all_image_info_addr +
6096 offsetof(struct user32_dyld_all_image_infos, notifyMachPorts));
6097 } else {
6098 ports_addr = (mach_vm_address_t)(dyld_info.all_image_info_addr +
6099 offsetof(struct user64_dyld_all_image_infos, notifyMachPorts));
6100 }
6101
6102 kr = ipc_port_translate_receive(current_space(), rcv_name, &sright); /* does not produce port ref */
6103 if (kr) {
6104 return KERN_INVALID_RIGHT;
6105 }
6106
6107 ip_reference(sright);
6108 ip_mq_unlock(sright);
6109
6110 assert(sright != IPC_PORT_NULL);
6111
6112 lck_mtx_lock(&g_dyldinfo_mtx);
6113 itk_lock(task);
6114
6115 if (task->itk_dyld_notify == NULL) {
6116 itk_unlock(task);
6117 lck_mtx_unlock(&g_dyldinfo_mtx);
6118 ip_release(sright);
6119 return KERN_FAILURE;
6120 }
6121
6122 for (int slot = 0; slot < DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT; slot++) {
6123 portp = &task->itk_dyld_notify[slot];
6124 if (*portp == sright) {
6125 release_ports[release_count++] = *portp;
6126 *portp = IPC_PORT_NULL;
6127 port_found = true;
6128 } else if ((*portp != IPC_PORT_NULL && !ip_active(*portp))) {
6129 release_ports[release_count++] = *portp;
6130 *portp = IPC_PORT_NULL;
6131 }
6132
6133 if (*portp != IPC_PORT_NULL) {
6134 active_count++;
6135 }
6136 }
6137
6138 task_dyld_process_info_update_helper(task, active_count,
6139 (vm_map_address_t)ports_addr, release_ports, release_count);
6140 /* itk_lock, g_dyldinfo_mtx are unlocked upon return */
6141
6142 ip_release(sright);
6143
6144 return port_found ? KERN_SUCCESS : KERN_FAILURE;
6145 }
6146
6147 /*
6148 * task_power_info
6149 *
6150 * Returns power stats for the task.
6151 * Note: Called with task locked.
6152 */
6153 void
task_power_info_locked(task_t task,task_power_info_t info,gpu_energy_data_t ginfo,task_power_info_v2_t infov2,struct task_power_info_extra * extra_info)6154 task_power_info_locked(
6155 task_t task,
6156 task_power_info_t info,
6157 gpu_energy_data_t ginfo,
6158 task_power_info_v2_t infov2,
6159 struct task_power_info_extra *extra_info)
6160 {
6161 thread_t thread;
6162 ledger_amount_t tmp;
6163
6164 uint64_t runnable_time_sum = 0;
6165
6166 task_lock_assert_owned(task);
6167
6168 ledger_get_entries(task->ledger, task_ledgers.interrupt_wakeups,
6169 (ledger_amount_t *)&info->task_interrupt_wakeups, &tmp);
6170 ledger_get_entries(task->ledger, task_ledgers.platform_idle_wakeups,
6171 (ledger_amount_t *)&info->task_platform_idle_wakeups, &tmp);
6172
6173 info->task_timer_wakeups_bin_1 = task->task_timer_wakeups_bin_1;
6174 info->task_timer_wakeups_bin_2 = task->task_timer_wakeups_bin_2;
6175
6176 struct recount_usage usage = { 0 };
6177 struct recount_usage usage_perf = { 0 };
6178 recount_task_usage_perf_only(task, &usage, &usage_perf);
6179
6180 info->total_user = usage.ru_user_time_mach;
6181 info->total_system = usage.ru_system_time_mach;
6182 runnable_time_sum = task->total_runnable_time;
6183
6184 if (ginfo) {
6185 ginfo->task_gpu_utilisation = task->task_gpu_ns;
6186 }
6187
6188 if (infov2) {
6189 infov2->task_ptime = usage_perf.ru_system_time_mach +
6190 usage_perf.ru_user_time_mach;
6191 infov2->task_pset_switches = task->ps_switch;
6192 #if CONFIG_PERVASIVE_ENERGY
6193 infov2->task_energy = usage.ru_energy_nj;
6194 #endif /* CONFIG_PERVASIVE_ENERGY */
6195 }
6196
6197 queue_iterate(&task->threads, thread, thread_t, task_threads) {
6198 spl_t x;
6199
6200 if (thread->options & TH_OPT_IDLE_THREAD) {
6201 continue;
6202 }
6203
6204 x = splsched();
6205 thread_lock(thread);
6206
6207 info->task_timer_wakeups_bin_1 += thread->thread_timer_wakeups_bin_1;
6208 info->task_timer_wakeups_bin_2 += thread->thread_timer_wakeups_bin_2;
6209
6210 if (infov2) {
6211 infov2->task_pset_switches += thread->ps_switch;
6212 }
6213
6214 runnable_time_sum += timer_grab(&thread->runnable_timer);
6215
6216 if (ginfo) {
6217 ginfo->task_gpu_utilisation += ml_gpu_stat(thread);
6218 }
6219 thread_unlock(thread);
6220 splx(x);
6221 }
6222
6223 if (extra_info) {
6224 extra_info->runnable_time = runnable_time_sum;
6225 #if CONFIG_PERVASIVE_CPI
6226 extra_info->cycles = usage.ru_cycles;
6227 extra_info->instructions = usage.ru_instructions;
6228 extra_info->pcycles = usage_perf.ru_cycles;
6229 extra_info->pinstructions = usage_perf.ru_instructions;
6230 extra_info->user_ptime = usage_perf.ru_user_time_mach;
6231 extra_info->system_ptime = usage_perf.ru_system_time_mach;
6232 #endif // CONFIG_PERVASIVE_CPI
6233 #if CONFIG_PERVASIVE_ENERGY
6234 extra_info->energy = usage.ru_energy_nj;
6235 extra_info->penergy = usage_perf.ru_energy_nj;
6236 #endif // CONFIG_PERVASIVE_ENERGY
6237 }
6238 }
6239
6240 /*
6241 * task_gpu_utilisation
6242 *
6243 * Returns the total gpu time used by the all the threads of the task
6244 * (both dead and alive)
6245 */
6246 uint64_t
task_gpu_utilisation(task_t task)6247 task_gpu_utilisation(
6248 task_t task)
6249 {
6250 uint64_t gpu_time = 0;
6251 #if defined(__x86_64__)
6252 thread_t thread;
6253
6254 task_lock(task);
6255 gpu_time += task->task_gpu_ns;
6256
6257 queue_iterate(&task->threads, thread, thread_t, task_threads) {
6258 spl_t x;
6259 x = splsched();
6260 thread_lock(thread);
6261 gpu_time += ml_gpu_stat(thread);
6262 thread_unlock(thread);
6263 splx(x);
6264 }
6265
6266 task_unlock(task);
6267 #else /* defined(__x86_64__) */
6268 /* silence compiler warning */
6269 (void)task;
6270 #endif /* defined(__x86_64__) */
6271 return gpu_time;
6272 }
6273
6274 /* This function updates the cpu time in the arrays for each
6275 * effective and requested QoS class
6276 */
6277 void
task_update_cpu_time_qos_stats(task_t task,uint64_t * eqos_stats,uint64_t * rqos_stats)6278 task_update_cpu_time_qos_stats(
6279 task_t task,
6280 uint64_t *eqos_stats,
6281 uint64_t *rqos_stats)
6282 {
6283 if (!eqos_stats && !rqos_stats) {
6284 return;
6285 }
6286
6287 task_lock(task);
6288 thread_t thread;
6289 queue_iterate(&task->threads, thread, thread_t, task_threads) {
6290 if (thread->options & TH_OPT_IDLE_THREAD) {
6291 continue;
6292 }
6293
6294 thread_update_qos_cpu_time(thread);
6295 }
6296
6297 if (eqos_stats) {
6298 eqos_stats[THREAD_QOS_DEFAULT] += task->cpu_time_eqos_stats.cpu_time_qos_default;
6299 eqos_stats[THREAD_QOS_MAINTENANCE] += task->cpu_time_eqos_stats.cpu_time_qos_maintenance;
6300 eqos_stats[THREAD_QOS_BACKGROUND] += task->cpu_time_eqos_stats.cpu_time_qos_background;
6301 eqos_stats[THREAD_QOS_UTILITY] += task->cpu_time_eqos_stats.cpu_time_qos_utility;
6302 eqos_stats[THREAD_QOS_LEGACY] += task->cpu_time_eqos_stats.cpu_time_qos_legacy;
6303 eqos_stats[THREAD_QOS_USER_INITIATED] += task->cpu_time_eqos_stats.cpu_time_qos_user_initiated;
6304 eqos_stats[THREAD_QOS_USER_INTERACTIVE] += task->cpu_time_eqos_stats.cpu_time_qos_user_interactive;
6305 }
6306
6307 if (rqos_stats) {
6308 rqos_stats[THREAD_QOS_DEFAULT] += task->cpu_time_rqos_stats.cpu_time_qos_default;
6309 rqos_stats[THREAD_QOS_MAINTENANCE] += task->cpu_time_rqos_stats.cpu_time_qos_maintenance;
6310 rqos_stats[THREAD_QOS_BACKGROUND] += task->cpu_time_rqos_stats.cpu_time_qos_background;
6311 rqos_stats[THREAD_QOS_UTILITY] += task->cpu_time_rqos_stats.cpu_time_qos_utility;
6312 rqos_stats[THREAD_QOS_LEGACY] += task->cpu_time_rqos_stats.cpu_time_qos_legacy;
6313 rqos_stats[THREAD_QOS_USER_INITIATED] += task->cpu_time_rqos_stats.cpu_time_qos_user_initiated;
6314 rqos_stats[THREAD_QOS_USER_INTERACTIVE] += task->cpu_time_rqos_stats.cpu_time_qos_user_interactive;
6315 }
6316
6317 task_unlock(task);
6318 }
6319
6320 kern_return_t
task_purgable_info(task_t task,task_purgable_info_t * stats)6321 task_purgable_info(
6322 task_t task,
6323 task_purgable_info_t *stats)
6324 {
6325 if (task == TASK_NULL || stats == NULL) {
6326 return KERN_INVALID_ARGUMENT;
6327 }
6328 /* Take task reference */
6329 task_reference(task);
6330 vm_purgeable_stats((vm_purgeable_info_t)stats, task);
6331 /* Drop task reference */
6332 task_deallocate(task);
6333 return KERN_SUCCESS;
6334 }
6335
6336 void
task_vtimer_set(task_t task,integer_t which)6337 task_vtimer_set(
6338 task_t task,
6339 integer_t which)
6340 {
6341 thread_t thread;
6342 spl_t x;
6343
6344 task_lock(task);
6345
6346 task->vtimers |= which;
6347
6348 switch (which) {
6349 case TASK_VTIMER_USER:
6350 queue_iterate(&task->threads, thread, thread_t, task_threads) {
6351 x = splsched();
6352 thread_lock(thread);
6353 struct recount_times_mach times = recount_thread_times(thread);
6354 thread->vtimer_user_save = times.rtm_user;
6355 thread_unlock(thread);
6356 splx(x);
6357 }
6358 break;
6359
6360 case TASK_VTIMER_PROF:
6361 queue_iterate(&task->threads, thread, thread_t, task_threads) {
6362 x = splsched();
6363 thread_lock(thread);
6364 thread->vtimer_prof_save = recount_thread_time_mach(thread);
6365 thread_unlock(thread);
6366 splx(x);
6367 }
6368 break;
6369
6370 case TASK_VTIMER_RLIM:
6371 queue_iterate(&task->threads, thread, thread_t, task_threads) {
6372 x = splsched();
6373 thread_lock(thread);
6374 thread->vtimer_rlim_save = recount_thread_time_mach(thread);
6375 thread_unlock(thread);
6376 splx(x);
6377 }
6378 break;
6379 }
6380
6381 task_unlock(task);
6382 }
6383
6384 void
task_vtimer_clear(task_t task,integer_t which)6385 task_vtimer_clear(
6386 task_t task,
6387 integer_t which)
6388 {
6389 task_lock(task);
6390
6391 task->vtimers &= ~which;
6392
6393 task_unlock(task);
6394 }
6395
6396 void
task_vtimer_update(__unused task_t task,integer_t which,uint32_t * microsecs)6397 task_vtimer_update(
6398 __unused
6399 task_t task,
6400 integer_t which,
6401 uint32_t *microsecs)
6402 {
6403 thread_t thread = current_thread();
6404 uint32_t tdelt = 0;
6405 clock_sec_t secs = 0;
6406 uint64_t tsum;
6407
6408 assert(task == current_task());
6409
6410 spl_t s = splsched();
6411 thread_lock(thread);
6412
6413 if ((task->vtimers & which) != (uint32_t)which) {
6414 thread_unlock(thread);
6415 splx(s);
6416 return;
6417 }
6418
6419 switch (which) {
6420 case TASK_VTIMER_USER:;
6421 struct recount_times_mach times = recount_thread_times(thread);
6422 tsum = times.rtm_user;
6423 tdelt = (uint32_t)(tsum - thread->vtimer_user_save);
6424 thread->vtimer_user_save = tsum;
6425 absolutetime_to_microtime(tdelt, &secs, microsecs);
6426 break;
6427
6428 case TASK_VTIMER_PROF:
6429 tsum = recount_current_thread_time_mach();
6430 tdelt = (uint32_t)(tsum - thread->vtimer_prof_save);
6431 absolutetime_to_microtime(tdelt, &secs, microsecs);
6432 /* if the time delta is smaller than a usec, ignore */
6433 if (*microsecs != 0) {
6434 thread->vtimer_prof_save = tsum;
6435 }
6436 break;
6437
6438 case TASK_VTIMER_RLIM:
6439 tsum = recount_current_thread_time_mach();
6440 tdelt = (uint32_t)(tsum - thread->vtimer_rlim_save);
6441 thread->vtimer_rlim_save = tsum;
6442 absolutetime_to_microtime(tdelt, &secs, microsecs);
6443 break;
6444 }
6445
6446 thread_unlock(thread);
6447 splx(s);
6448 }
6449
6450 uint64_t
get_task_dispatchqueue_offset(task_t task)6451 get_task_dispatchqueue_offset(
6452 task_t task)
6453 {
6454 return task->dispatchqueue_offset;
6455 }
6456
6457 void
task_synchronizer_destroy_all(task_t task)6458 task_synchronizer_destroy_all(task_t task)
6459 {
6460 /*
6461 * Destroy owned semaphores
6462 */
6463 semaphore_destroy_all(task);
6464 }
6465
6466 /*
6467 * Install default (machine-dependent) initial thread state
6468 * on the task. Subsequent thread creation will have this initial
6469 * state set on the thread by machine_thread_inherit_taskwide().
6470 * Flavors and structures are exactly the same as those to thread_set_state()
6471 */
6472 kern_return_t
task_set_state(task_t task,int flavor,thread_state_t state,mach_msg_type_number_t state_count)6473 task_set_state(
6474 task_t task,
6475 int flavor,
6476 thread_state_t state,
6477 mach_msg_type_number_t state_count)
6478 {
6479 kern_return_t ret;
6480
6481 if (task == TASK_NULL) {
6482 return KERN_INVALID_ARGUMENT;
6483 }
6484
6485 task_lock(task);
6486
6487 if (!task->active) {
6488 task_unlock(task);
6489 return KERN_FAILURE;
6490 }
6491
6492 ret = machine_task_set_state(task, flavor, state, state_count);
6493
6494 task_unlock(task);
6495 return ret;
6496 }
6497
6498 /*
6499 * Examine the default (machine-dependent) initial thread state
6500 * on the task, as set by task_set_state(). Flavors and structures
6501 * are exactly the same as those passed to thread_get_state().
6502 */
6503 kern_return_t
task_get_state(task_t task,int flavor,thread_state_t state,mach_msg_type_number_t * state_count)6504 task_get_state(
6505 task_t task,
6506 int flavor,
6507 thread_state_t state,
6508 mach_msg_type_number_t *state_count)
6509 {
6510 kern_return_t ret;
6511
6512 if (task == TASK_NULL) {
6513 return KERN_INVALID_ARGUMENT;
6514 }
6515
6516 task_lock(task);
6517
6518 if (!task->active) {
6519 task_unlock(task);
6520 return KERN_FAILURE;
6521 }
6522
6523 ret = machine_task_get_state(task, flavor, state, state_count);
6524
6525 task_unlock(task);
6526 return ret;
6527 }
6528
6529
6530 static kern_return_t __attribute__((noinline, not_tail_called))
PROC_VIOLATED_GUARD__SEND_EXC_GUARD(mach_exception_code_t code,mach_exception_subcode_t subcode,void * reason,boolean_t backtrace_only)6531 PROC_VIOLATED_GUARD__SEND_EXC_GUARD(
6532 mach_exception_code_t code,
6533 mach_exception_subcode_t subcode,
6534 void *reason,
6535 boolean_t backtrace_only)
6536 {
6537 #ifdef MACH_BSD
6538 if (1 == proc_selfpid()) {
6539 return KERN_NOT_SUPPORTED; // initproc is immune
6540 }
6541 #endif
6542 mach_exception_data_type_t codes[EXCEPTION_CODE_MAX] = {
6543 [0] = code,
6544 [1] = subcode,
6545 };
6546 task_t task = current_task();
6547 kern_return_t kr;
6548 void *bsd_info = get_bsdtask_info(task);
6549
6550 /* (See jetsam-related comments below) */
6551
6552 proc_memstat_skip(bsd_info, TRUE);
6553 kr = task_enqueue_exception_with_corpse(task, EXC_GUARD, codes, 2, reason, backtrace_only);
6554 proc_memstat_skip(bsd_info, FALSE);
6555 return kr;
6556 }
6557
6558 kern_return_t
task_violated_guard(mach_exception_code_t code,mach_exception_subcode_t subcode,void * reason,bool backtrace_only)6559 task_violated_guard(
6560 mach_exception_code_t code,
6561 mach_exception_subcode_t subcode,
6562 void *reason,
6563 bool backtrace_only)
6564 {
6565 return PROC_VIOLATED_GUARD__SEND_EXC_GUARD(code, subcode, reason, backtrace_only);
6566 }
6567
6568
6569 #if CONFIG_MEMORYSTATUS
6570
6571 boolean_t
task_get_memlimit_is_active(task_t task)6572 task_get_memlimit_is_active(task_t task)
6573 {
6574 assert(task != NULL);
6575
6576 if (task->memlimit_is_active == 1) {
6577 return TRUE;
6578 } else {
6579 return FALSE;
6580 }
6581 }
6582
6583 void
task_set_memlimit_is_active(task_t task,boolean_t memlimit_is_active)6584 task_set_memlimit_is_active(task_t task, boolean_t memlimit_is_active)
6585 {
6586 assert(task != NULL);
6587
6588 if (memlimit_is_active) {
6589 task->memlimit_is_active = 1;
6590 } else {
6591 task->memlimit_is_active = 0;
6592 }
6593 }
6594
6595 boolean_t
task_get_memlimit_is_fatal(task_t task)6596 task_get_memlimit_is_fatal(task_t task)
6597 {
6598 assert(task != NULL);
6599
6600 if (task->memlimit_is_fatal == 1) {
6601 return TRUE;
6602 } else {
6603 return FALSE;
6604 }
6605 }
6606
6607 void
task_set_memlimit_is_fatal(task_t task,boolean_t memlimit_is_fatal)6608 task_set_memlimit_is_fatal(task_t task, boolean_t memlimit_is_fatal)
6609 {
6610 assert(task != NULL);
6611
6612 if (memlimit_is_fatal) {
6613 task->memlimit_is_fatal = 1;
6614 } else {
6615 task->memlimit_is_fatal = 0;
6616 }
6617 }
6618
6619 uint64_t
task_get_dirty_start(task_t task)6620 task_get_dirty_start(task_t task)
6621 {
6622 return task->memstat_dirty_start;
6623 }
6624
6625 void
task_set_dirty_start(task_t task,uint64_t start)6626 task_set_dirty_start(task_t task, uint64_t start)
6627 {
6628 task_lock(task);
6629 task->memstat_dirty_start = start;
6630 task_unlock(task);
6631 }
6632
6633 boolean_t
task_has_triggered_exc_resource(task_t task,boolean_t memlimit_is_active)6634 task_has_triggered_exc_resource(task_t task, boolean_t memlimit_is_active)
6635 {
6636 boolean_t triggered = FALSE;
6637
6638 assert(task == current_task());
6639
6640 /*
6641 * Returns true, if task has already triggered an exc_resource exception.
6642 */
6643
6644 if (memlimit_is_active) {
6645 triggered = (task->memlimit_active_exc_resource ? TRUE : FALSE);
6646 } else {
6647 triggered = (task->memlimit_inactive_exc_resource ? TRUE : FALSE);
6648 }
6649
6650 return triggered;
6651 }
6652
6653 void
task_mark_has_triggered_exc_resource(task_t task,boolean_t memlimit_is_active)6654 task_mark_has_triggered_exc_resource(task_t task, boolean_t memlimit_is_active)
6655 {
6656 assert(task == current_task());
6657
6658 /*
6659 * We allow one exc_resource per process per active/inactive limit.
6660 * The limit's fatal attribute does not come into play.
6661 */
6662
6663 if (memlimit_is_active) {
6664 task->memlimit_active_exc_resource = 1;
6665 } else {
6666 task->memlimit_inactive_exc_resource = 1;
6667 }
6668 }
6669
6670 #define HWM_USERCORE_MINSPACE 250 // free space (in MB) required *after* core file creation
6671
6672 void __attribute__((noinline))
PROC_CROSSED_HIGH_WATERMARK__SEND_EXC_RESOURCE_AND_SUSPEND(int max_footprint_mb,boolean_t is_fatal)6673 PROC_CROSSED_HIGH_WATERMARK__SEND_EXC_RESOURCE_AND_SUSPEND(int max_footprint_mb, boolean_t is_fatal)
6674 {
6675 task_t task = current_task();
6676 int pid = 0;
6677 const char *procname = "unknown";
6678 mach_exception_data_type_t code[EXCEPTION_CODE_MAX];
6679 boolean_t send_sync_exc_resource = FALSE;
6680 void *cur_bsd_info = get_bsdtask_info(current_task());
6681
6682 #ifdef MACH_BSD
6683 pid = proc_selfpid();
6684
6685 if (pid == 1) {
6686 /*
6687 * Cannot have ReportCrash analyzing
6688 * a suspended initproc.
6689 */
6690 return;
6691 }
6692
6693 if (cur_bsd_info != NULL) {
6694 procname = proc_name_address(cur_bsd_info);
6695 send_sync_exc_resource = proc_send_synchronous_EXC_RESOURCE(cur_bsd_info);
6696 }
6697 #endif
6698 #if CONFIG_COREDUMP
6699 if (hwm_user_cores) {
6700 int error;
6701 uint64_t starttime, end;
6702 clock_sec_t secs = 0;
6703 uint32_t microsecs = 0;
6704
6705 starttime = mach_absolute_time();
6706 /*
6707 * Trigger a coredump of this process. Don't proceed unless we know we won't
6708 * be filling up the disk; and ignore the core size resource limit for this
6709 * core file.
6710 */
6711 if ((error = coredump(cur_bsd_info, HWM_USERCORE_MINSPACE, COREDUMP_IGNORE_ULIMIT)) != 0) {
6712 printf("couldn't take coredump of %s[%d]: %d\n", procname, pid, error);
6713 }
6714 /*
6715 * coredump() leaves the task suspended.
6716 */
6717 task_resume_internal(current_task());
6718
6719 end = mach_absolute_time();
6720 absolutetime_to_microtime(end - starttime, &secs, µsecs);
6721 printf("coredump of %s[%d] taken in %d secs %d microsecs\n",
6722 proc_name_address(cur_bsd_info), pid, (int)secs, microsecs);
6723 }
6724 #endif /* CONFIG_COREDUMP */
6725
6726 if (disable_exc_resource) {
6727 printf("process %s[%d] crossed memory high watermark (%d MB); EXC_RESOURCE "
6728 "supressed by a boot-arg.\n", procname, pid, max_footprint_mb);
6729 return;
6730 }
6731
6732 /*
6733 * A task that has triggered an EXC_RESOURCE, should not be
6734 * jetsammed when the device is under memory pressure. Here
6735 * we set the P_MEMSTAT_SKIP flag so that the process
6736 * will be skipped if the memorystatus_thread wakes up.
6737 *
6738 * This is a debugging aid to ensure we can get a corpse before
6739 * the jetsam thread kills the process.
6740 * Note that proc_memstat_skip is a no-op on release kernels.
6741 */
6742 proc_memstat_skip(cur_bsd_info, TRUE);
6743
6744 code[0] = code[1] = 0;
6745 EXC_RESOURCE_ENCODE_TYPE(code[0], RESOURCE_TYPE_MEMORY);
6746 EXC_RESOURCE_ENCODE_FLAVOR(code[0], FLAVOR_HIGH_WATERMARK);
6747 EXC_RESOURCE_HWM_ENCODE_LIMIT(code[0], max_footprint_mb);
6748
6749 /*
6750 * Do not generate a corpse fork if the violation is a fatal one
6751 * or the process wants synchronous EXC_RESOURCE exceptions.
6752 */
6753 if (is_fatal || send_sync_exc_resource || !exc_via_corpse_forking) {
6754 /* Do not send a EXC_RESOURCE if corpse_for_fatal_memkill is set */
6755 if (send_sync_exc_resource || !corpse_for_fatal_memkill) {
6756 /*
6757 * Use the _internal_ variant so that no user-space
6758 * process can resume our task from under us.
6759 */
6760 task_suspend_internal(task);
6761 exception_triage(EXC_RESOURCE, code, EXCEPTION_CODE_MAX);
6762 task_resume_internal(task);
6763 }
6764 } else {
6765 if (audio_active) {
6766 printf("process %s[%d] crossed memory high watermark (%d MB); EXC_RESOURCE "
6767 "supressed due to audio playback.\n", procname, pid, max_footprint_mb);
6768 } else {
6769 task_enqueue_exception_with_corpse(task, EXC_RESOURCE,
6770 code, EXCEPTION_CODE_MAX, NULL, FALSE);
6771 }
6772 }
6773
6774 /*
6775 * After the EXC_RESOURCE has been handled, we must clear the
6776 * P_MEMSTAT_SKIP flag so that the process can again be
6777 * considered for jetsam if the memorystatus_thread wakes up.
6778 */
6779 proc_memstat_skip(cur_bsd_info, FALSE); /* clear the flag */
6780 }
6781
6782 /*
6783 * Callback invoked when a task exceeds its physical footprint limit.
6784 */
6785 void
task_footprint_exceeded(int warning,__unused const void * param0,__unused const void * param1)6786 task_footprint_exceeded(int warning, __unused const void *param0, __unused const void *param1)
6787 {
6788 ledger_amount_t max_footprint, max_footprint_mb;
6789 #if CONFIG_DEFERRED_RECLAIM
6790 ledger_amount_t current_footprint;
6791 #endif /* CONFIG_DEFERRED_RECLAIM */
6792 task_t task;
6793 boolean_t is_warning;
6794 boolean_t memlimit_is_active;
6795 boolean_t memlimit_is_fatal;
6796
6797 if (warning == LEDGER_WARNING_DIPPED_BELOW) {
6798 /*
6799 * Task memory limits only provide a warning on the way up.
6800 */
6801 return;
6802 } else if (warning == LEDGER_WARNING_ROSE_ABOVE) {
6803 /*
6804 * This task is in danger of violating a memory limit,
6805 * It has exceeded a percentage level of the limit.
6806 */
6807 is_warning = TRUE;
6808 } else {
6809 /*
6810 * The task has exceeded the physical footprint limit.
6811 * This is not a warning but a true limit violation.
6812 */
6813 is_warning = FALSE;
6814 }
6815
6816 task = current_task();
6817
6818 ledger_get_limit(task->ledger, task_ledgers.phys_footprint, &max_footprint);
6819 #if CONFIG_DEFERRED_RECLAIM
6820 if (task->deferred_reclamation_metadata != NULL) {
6821 /*
6822 * Task is enrolled in deferred reclamation.
6823 * Do a reclaim to ensure it's really over its limit.
6824 */
6825 vm_deferred_reclamation_reclaim_from_task_sync(task, UINT64_MAX);
6826 ledger_get_balance(task->ledger, task_ledgers.phys_footprint, ¤t_footprint);
6827 if (current_footprint < max_footprint) {
6828 return;
6829 }
6830 }
6831 #endif /* CONFIG_DEFERRED_RECLAIM */
6832 max_footprint_mb = max_footprint >> 20;
6833
6834 memlimit_is_active = task_get_memlimit_is_active(task);
6835 memlimit_is_fatal = task_get_memlimit_is_fatal(task);
6836
6837 /*
6838 * If this is an actual violation (not a warning), then generate EXC_RESOURCE exception.
6839 * We only generate the exception once per process per memlimit (active/inactive limit).
6840 * To enforce this, we monitor state based on the memlimit's active/inactive attribute
6841 * and we disable it by marking that memlimit as exception triggered.
6842 */
6843 if ((is_warning == FALSE) && (!task_has_triggered_exc_resource(task, memlimit_is_active))) {
6844 PROC_CROSSED_HIGH_WATERMARK__SEND_EXC_RESOURCE_AND_SUSPEND((int)max_footprint_mb, memlimit_is_fatal);
6845 memorystatus_log_exception((int)max_footprint_mb, memlimit_is_active, memlimit_is_fatal);
6846 task_mark_has_triggered_exc_resource(task, memlimit_is_active);
6847 }
6848
6849 memorystatus_on_ledger_footprint_exceeded(is_warning, memlimit_is_active, memlimit_is_fatal);
6850 }
6851
6852 extern int proc_check_footprint_priv(void);
6853
6854 kern_return_t
task_set_phys_footprint_limit(task_t task,int new_limit_mb,int * old_limit_mb)6855 task_set_phys_footprint_limit(
6856 task_t task,
6857 int new_limit_mb,
6858 int *old_limit_mb)
6859 {
6860 kern_return_t error;
6861
6862 boolean_t memlimit_is_active;
6863 boolean_t memlimit_is_fatal;
6864
6865 if ((error = proc_check_footprint_priv())) {
6866 return KERN_NO_ACCESS;
6867 }
6868
6869 /*
6870 * This call should probably be obsoleted.
6871 * But for now, we default to current state.
6872 */
6873 memlimit_is_active = task_get_memlimit_is_active(task);
6874 memlimit_is_fatal = task_get_memlimit_is_fatal(task);
6875
6876 return task_set_phys_footprint_limit_internal(task, new_limit_mb, old_limit_mb, memlimit_is_active, memlimit_is_fatal);
6877 }
6878
6879 kern_return_t
task_convert_phys_footprint_limit(int limit_mb,int * converted_limit_mb)6880 task_convert_phys_footprint_limit(
6881 int limit_mb,
6882 int *converted_limit_mb)
6883 {
6884 if (limit_mb == -1) {
6885 /*
6886 * No limit
6887 */
6888 if (max_task_footprint != 0) {
6889 *converted_limit_mb = (int)(max_task_footprint / 1024 / 1024); /* bytes to MB */
6890 } else {
6891 *converted_limit_mb = (int)(LEDGER_LIMIT_INFINITY >> 20);
6892 }
6893 } else {
6894 /* nothing to convert */
6895 *converted_limit_mb = limit_mb;
6896 }
6897 return KERN_SUCCESS;
6898 }
6899
6900
6901 kern_return_t
task_set_phys_footprint_limit_internal(task_t task,int new_limit_mb,int * old_limit_mb,boolean_t memlimit_is_active,boolean_t memlimit_is_fatal)6902 task_set_phys_footprint_limit_internal(
6903 task_t task,
6904 int new_limit_mb,
6905 int *old_limit_mb,
6906 boolean_t memlimit_is_active,
6907 boolean_t memlimit_is_fatal)
6908 {
6909 ledger_amount_t old;
6910 kern_return_t ret;
6911
6912 ret = ledger_get_limit(task->ledger, task_ledgers.phys_footprint, &old);
6913
6914 if (ret != KERN_SUCCESS) {
6915 return ret;
6916 }
6917
6918 /*
6919 * Check that limit >> 20 will not give an "unexpected" 32-bit
6920 * result. There are, however, implicit assumptions that -1 mb limit
6921 * equates to LEDGER_LIMIT_INFINITY.
6922 */
6923 assert(((old & 0xFFF0000000000000LL) == 0) || (old == LEDGER_LIMIT_INFINITY));
6924
6925 if (old_limit_mb) {
6926 *old_limit_mb = (int)(old >> 20);
6927 }
6928
6929 if (new_limit_mb == -1) {
6930 /*
6931 * Caller wishes to remove the limit.
6932 */
6933 ledger_set_limit(task->ledger, task_ledgers.phys_footprint,
6934 max_task_footprint ? max_task_footprint : LEDGER_LIMIT_INFINITY,
6935 max_task_footprint ? (uint8_t)max_task_footprint_warning_level : 0);
6936
6937 task_lock(task);
6938 task_set_memlimit_is_active(task, memlimit_is_active);
6939 task_set_memlimit_is_fatal(task, memlimit_is_fatal);
6940 task_unlock(task);
6941
6942 return KERN_SUCCESS;
6943 }
6944
6945 #ifdef CONFIG_NOMONITORS
6946 return KERN_SUCCESS;
6947 #endif /* CONFIG_NOMONITORS */
6948
6949 task_lock(task);
6950
6951 if ((memlimit_is_active == task_get_memlimit_is_active(task)) &&
6952 (memlimit_is_fatal == task_get_memlimit_is_fatal(task)) &&
6953 (((ledger_amount_t)new_limit_mb << 20) == old)) {
6954 /*
6955 * memlimit state is not changing
6956 */
6957 task_unlock(task);
6958 return KERN_SUCCESS;
6959 }
6960
6961 task_set_memlimit_is_active(task, memlimit_is_active);
6962 task_set_memlimit_is_fatal(task, memlimit_is_fatal);
6963
6964 ledger_set_limit(task->ledger, task_ledgers.phys_footprint,
6965 (ledger_amount_t)new_limit_mb << 20, PHYS_FOOTPRINT_WARNING_LEVEL);
6966
6967 if (task == current_task()) {
6968 ledger_check_new_balance(current_thread(), task->ledger,
6969 task_ledgers.phys_footprint);
6970 }
6971
6972 task_unlock(task);
6973
6974 return KERN_SUCCESS;
6975 }
6976
6977 kern_return_t
task_get_phys_footprint_limit(task_t task,int * limit_mb)6978 task_get_phys_footprint_limit(
6979 task_t task,
6980 int *limit_mb)
6981 {
6982 ledger_amount_t limit;
6983 kern_return_t ret;
6984
6985 ret = ledger_get_limit(task->ledger, task_ledgers.phys_footprint, &limit);
6986 if (ret != KERN_SUCCESS) {
6987 return ret;
6988 }
6989
6990 /*
6991 * Check that limit >> 20 will not give an "unexpected" signed, 32-bit
6992 * result. There are, however, implicit assumptions that -1 mb limit
6993 * equates to LEDGER_LIMIT_INFINITY.
6994 */
6995 assert(((limit & 0xFFF0000000000000LL) == 0) || (limit == LEDGER_LIMIT_INFINITY));
6996 *limit_mb = (int)(limit >> 20);
6997
6998 return KERN_SUCCESS;
6999 }
7000 #else /* CONFIG_MEMORYSTATUS */
7001 kern_return_t
task_set_phys_footprint_limit(__unused task_t task,__unused int new_limit_mb,__unused int * old_limit_mb)7002 task_set_phys_footprint_limit(
7003 __unused task_t task,
7004 __unused int new_limit_mb,
7005 __unused int *old_limit_mb)
7006 {
7007 return KERN_FAILURE;
7008 }
7009
7010 kern_return_t
task_get_phys_footprint_limit(__unused task_t task,__unused int * limit_mb)7011 task_get_phys_footprint_limit(
7012 __unused task_t task,
7013 __unused int *limit_mb)
7014 {
7015 return KERN_FAILURE;
7016 }
7017 #endif /* CONFIG_MEMORYSTATUS */
7018
7019 security_token_t *
task_get_sec_token(task_t task)7020 task_get_sec_token(task_t task)
7021 {
7022 return &task_get_ro(task)->task_tokens.sec_token;
7023 }
7024
7025 void
task_set_sec_token(task_t task,security_token_t * token)7026 task_set_sec_token(task_t task, security_token_t *token)
7027 {
7028 zalloc_ro_update_field(ZONE_ID_PROC_RO, task_get_ro(task),
7029 task_tokens.sec_token, token);
7030 }
7031
7032 audit_token_t *
task_get_audit_token(task_t task)7033 task_get_audit_token(task_t task)
7034 {
7035 return &task_get_ro(task)->task_tokens.audit_token;
7036 }
7037
7038 void
task_set_audit_token(task_t task,audit_token_t * token)7039 task_set_audit_token(task_t task, audit_token_t *token)
7040 {
7041 zalloc_ro_update_field(ZONE_ID_PROC_RO, task_get_ro(task),
7042 task_tokens.audit_token, token);
7043 }
7044
7045 void
task_set_tokens(task_t task,security_token_t * sec_token,audit_token_t * audit_token)7046 task_set_tokens(task_t task, security_token_t *sec_token, audit_token_t *audit_token)
7047 {
7048 struct task_token_ro_data tokens;
7049
7050 tokens = task_get_ro(task)->task_tokens;
7051 tokens.sec_token = *sec_token;
7052 tokens.audit_token = *audit_token;
7053
7054 zalloc_ro_update_field(ZONE_ID_PROC_RO, task_get_ro(task), task_tokens,
7055 &tokens);
7056 }
7057
7058 boolean_t
task_is_privileged(task_t task)7059 task_is_privileged(task_t task)
7060 {
7061 return task_get_sec_token(task)->val[0] == 0;
7062 }
7063
7064 #ifdef CONFIG_MACF
7065 uint8_t *
task_get_mach_trap_filter_mask(task_t task)7066 task_get_mach_trap_filter_mask(task_t task)
7067 {
7068 return task_get_ro(task)->task_filters.mach_trap_filter_mask;
7069 }
7070
7071 void
task_set_mach_trap_filter_mask(task_t task,uint8_t * mask)7072 task_set_mach_trap_filter_mask(task_t task, uint8_t *mask)
7073 {
7074 zalloc_ro_update_field(ZONE_ID_PROC_RO, task_get_ro(task),
7075 task_filters.mach_trap_filter_mask, &mask);
7076 }
7077
7078 uint8_t *
task_get_mach_kobj_filter_mask(task_t task)7079 task_get_mach_kobj_filter_mask(task_t task)
7080 {
7081 return task_get_ro(task)->task_filters.mach_kobj_filter_mask;
7082 }
7083
7084 mach_vm_address_t
task_get_all_image_info_addr(task_t task)7085 task_get_all_image_info_addr(task_t task)
7086 {
7087 return task->all_image_info_addr;
7088 }
7089
7090 void
task_set_mach_kobj_filter_mask(task_t task,uint8_t * mask)7091 task_set_mach_kobj_filter_mask(task_t task, uint8_t *mask)
7092 {
7093 zalloc_ro_update_field(ZONE_ID_PROC_RO, task_get_ro(task),
7094 task_filters.mach_kobj_filter_mask, &mask);
7095 }
7096
7097 void
task_copy_filter_masks(task_t new_task,task_t old_task)7098 task_copy_filter_masks(task_t new_task, task_t old_task)
7099 {
7100 struct task_filter_ro_data filters;
7101
7102 filters = task_get_ro(new_task)->task_filters;
7103 filters.mach_trap_filter_mask = task_get_mach_trap_filter_mask(old_task);
7104 filters.mach_kobj_filter_mask = task_get_mach_kobj_filter_mask(old_task);
7105
7106 zalloc_ro_update_field(ZONE_ID_PROC_RO, task_get_ro(new_task),
7107 task_filters, &filters);
7108 }
7109 #endif /* CONFIG_MACF */
7110
7111 void
task_set_thread_limit(task_t task,uint16_t thread_limit)7112 task_set_thread_limit(task_t task, uint16_t thread_limit)
7113 {
7114 assert(task != kernel_task);
7115 if (thread_limit <= TASK_MAX_THREAD_LIMIT) {
7116 task_lock(task);
7117 task->task_thread_limit = thread_limit;
7118 task_unlock(task);
7119 }
7120 }
7121
7122 #if CONFIG_PROC_RESOURCE_LIMITS
7123 kern_return_t
task_set_port_space_limits(task_t task,uint32_t soft_limit,uint32_t hard_limit)7124 task_set_port_space_limits(task_t task, uint32_t soft_limit, uint32_t hard_limit)
7125 {
7126 return ipc_space_set_table_size_limits(task->itk_space, soft_limit, hard_limit);
7127 }
7128 #endif /* CONFIG_PROC_RESOURCE_LIMITS */
7129
7130 #if XNU_TARGET_OS_OSX
7131 boolean_t
task_has_system_version_compat_enabled(task_t task)7132 task_has_system_version_compat_enabled(task_t task)
7133 {
7134 boolean_t enabled = FALSE;
7135
7136 task_lock(task);
7137 enabled = (task->t_flags & TF_SYS_VERSION_COMPAT);
7138 task_unlock(task);
7139
7140 return enabled;
7141 }
7142
7143 void
task_set_system_version_compat_enabled(task_t task,boolean_t enable_system_version_compat)7144 task_set_system_version_compat_enabled(task_t task, boolean_t enable_system_version_compat)
7145 {
7146 assert(task == current_task());
7147 assert(task != kernel_task);
7148
7149 task_lock(task);
7150 if (enable_system_version_compat) {
7151 task->t_flags |= TF_SYS_VERSION_COMPAT;
7152 } else {
7153 task->t_flags &= ~TF_SYS_VERSION_COMPAT;
7154 }
7155 task_unlock(task);
7156 }
7157 #endif /* XNU_TARGET_OS_OSX */
7158
7159 /*
7160 * We need to export some functions to other components that
7161 * are currently implemented in macros within the osfmk
7162 * component. Just export them as functions of the same name.
7163 */
7164 boolean_t
is_kerneltask(task_t t)7165 is_kerneltask(task_t t)
7166 {
7167 if (t == kernel_task) {
7168 return TRUE;
7169 }
7170
7171 return FALSE;
7172 }
7173
7174 boolean_t
is_corpsetask(task_t t)7175 is_corpsetask(task_t t)
7176 {
7177 return task_is_a_corpse(t);
7178 }
7179
7180 boolean_t
is_corpsefork(task_t t)7181 is_corpsefork(task_t t)
7182 {
7183 return task_is_a_corpse_fork(t);
7184 }
7185
7186 task_t
current_task_early(void)7187 current_task_early(void)
7188 {
7189 if (__improbable(startup_phase < STARTUP_SUB_EARLY_BOOT)) {
7190 if (current_thread()->t_tro == NULL) {
7191 return TASK_NULL;
7192 }
7193 }
7194 return get_threadtask(current_thread());
7195 }
7196
7197 task_t
current_task(void)7198 current_task(void)
7199 {
7200 return get_threadtask(current_thread());
7201 }
7202
7203 /* defined in bsd/kern/kern_prot.c */
7204 extern int get_audit_token_pid(audit_token_t *audit_token);
7205
7206 int
task_pid(task_t task)7207 task_pid(task_t task)
7208 {
7209 if (task) {
7210 return get_audit_token_pid(task_get_audit_token(task));
7211 }
7212 return -1;
7213 }
7214
7215 #if __has_feature(ptrauth_calls)
7216 /*
7217 * Get the shared region id and jop signing key for the task.
7218 * The function will allocate a kalloc buffer and return
7219 * it to caller, the caller needs to free it. This is used
7220 * for getting the information via task port.
7221 */
7222 char *
task_get_vm_shared_region_id_and_jop_pid(task_t task,uint64_t * jop_pid)7223 task_get_vm_shared_region_id_and_jop_pid(task_t task, uint64_t *jop_pid)
7224 {
7225 size_t len;
7226 char *shared_region_id = NULL;
7227
7228 task_lock(task);
7229 if (task->shared_region_id == NULL) {
7230 task_unlock(task);
7231 return NULL;
7232 }
7233 len = strlen(task->shared_region_id) + 1;
7234
7235 /* don't hold task lock while allocating */
7236 task_unlock(task);
7237 shared_region_id = kalloc_data(len, Z_WAITOK);
7238 task_lock(task);
7239
7240 if (task->shared_region_id == NULL) {
7241 task_unlock(task);
7242 kfree_data(shared_region_id, len);
7243 return NULL;
7244 }
7245 assert(len == strlen(task->shared_region_id) + 1); /* should never change */
7246 strlcpy(shared_region_id, task->shared_region_id, len);
7247 task_unlock(task);
7248
7249 /* find key from its auth pager */
7250 if (jop_pid != NULL) {
7251 *jop_pid = shared_region_find_key(shared_region_id);
7252 }
7253
7254 return shared_region_id;
7255 }
7256
7257 /*
7258 * set the shared region id for a task
7259 */
7260 void
task_set_shared_region_id(task_t task,char * id)7261 task_set_shared_region_id(task_t task, char *id)
7262 {
7263 char *old_id;
7264
7265 task_lock(task);
7266 old_id = task->shared_region_id;
7267 task->shared_region_id = id;
7268 task->shared_region_auth_remapped = FALSE;
7269 task_unlock(task);
7270
7271 /* free any pre-existing shared region id */
7272 if (old_id != NULL) {
7273 shared_region_key_dealloc(old_id);
7274 kfree_data(old_id, strlen(old_id) + 1);
7275 }
7276 }
7277 #endif /* __has_feature(ptrauth_calls) */
7278
7279 /*
7280 * This routine finds a thread in a task by its unique id
7281 * Returns a referenced thread or THREAD_NULL if the thread was not found
7282 *
7283 * TODO: This is super inefficient - it's an O(threads in task) list walk!
7284 * We should make a tid hash, or transition all tid clients to thread ports
7285 *
7286 * Precondition: No locks held (will take task lock)
7287 */
7288 thread_t
task_findtid(task_t task,uint64_t tid)7289 task_findtid(task_t task, uint64_t tid)
7290 {
7291 thread_t self = current_thread();
7292 thread_t found_thread = THREAD_NULL;
7293 thread_t iter_thread = THREAD_NULL;
7294
7295 /* Short-circuit the lookup if we're looking up ourselves */
7296 if (tid == self->thread_id || tid == TID_NULL) {
7297 assert(get_threadtask(self) == task);
7298
7299 thread_reference(self);
7300
7301 return self;
7302 }
7303
7304 task_lock(task);
7305
7306 queue_iterate(&task->threads, iter_thread, thread_t, task_threads) {
7307 if (iter_thread->thread_id == tid) {
7308 found_thread = iter_thread;
7309 thread_reference(found_thread);
7310 break;
7311 }
7312 }
7313
7314 task_unlock(task);
7315
7316 return found_thread;
7317 }
7318
7319 int
pid_from_task(task_t task)7320 pid_from_task(task_t task)
7321 {
7322 int pid = -1;
7323 void *bsd_info = get_bsdtask_info(task);
7324
7325 if (bsd_info) {
7326 pid = proc_pid(bsd_info);
7327 } else {
7328 pid = task_pid(task);
7329 }
7330
7331 return pid;
7332 }
7333
7334 /*
7335 * Control the CPU usage monitor for a task.
7336 */
7337 kern_return_t
task_cpu_usage_monitor_ctl(task_t task,uint32_t * flags)7338 task_cpu_usage_monitor_ctl(task_t task, uint32_t *flags)
7339 {
7340 int error = KERN_SUCCESS;
7341
7342 if (*flags & CPUMON_MAKE_FATAL) {
7343 task->rusage_cpu_flags |= TASK_RUSECPU_FLAGS_FATAL_CPUMON;
7344 } else {
7345 error = KERN_INVALID_ARGUMENT;
7346 }
7347
7348 return error;
7349 }
7350
7351 /*
7352 * Control the wakeups monitor for a task.
7353 */
7354 kern_return_t
task_wakeups_monitor_ctl(task_t task,uint32_t * flags,int32_t * rate_hz)7355 task_wakeups_monitor_ctl(task_t task, uint32_t *flags, int32_t *rate_hz)
7356 {
7357 ledger_t ledger = task->ledger;
7358
7359 task_lock(task);
7360 if (*flags & WAKEMON_GET_PARAMS) {
7361 ledger_amount_t limit;
7362 uint64_t period;
7363
7364 ledger_get_limit(ledger, task_ledgers.interrupt_wakeups, &limit);
7365 ledger_get_period(ledger, task_ledgers.interrupt_wakeups, &period);
7366
7367 if (limit != LEDGER_LIMIT_INFINITY) {
7368 /*
7369 * An active limit means the wakeups monitor is enabled.
7370 */
7371 *rate_hz = (int32_t)(limit / (int64_t)(period / NSEC_PER_SEC));
7372 *flags = WAKEMON_ENABLE;
7373 if (task->rusage_cpu_flags & TASK_RUSECPU_FLAGS_FATAL_WAKEUPSMON) {
7374 *flags |= WAKEMON_MAKE_FATAL;
7375 }
7376 } else {
7377 *flags = WAKEMON_DISABLE;
7378 *rate_hz = -1;
7379 }
7380
7381 /*
7382 * If WAKEMON_GET_PARAMS is present in flags, all other flags are ignored.
7383 */
7384 task_unlock(task);
7385 return KERN_SUCCESS;
7386 }
7387
7388 if (*flags & WAKEMON_ENABLE) {
7389 if (*flags & WAKEMON_SET_DEFAULTS) {
7390 *rate_hz = task_wakeups_monitor_rate;
7391 }
7392
7393 #ifndef CONFIG_NOMONITORS
7394 if (*flags & WAKEMON_MAKE_FATAL) {
7395 task->rusage_cpu_flags |= TASK_RUSECPU_FLAGS_FATAL_WAKEUPSMON;
7396 }
7397 #endif /* CONFIG_NOMONITORS */
7398
7399 if (*rate_hz <= 0) {
7400 task_unlock(task);
7401 return KERN_INVALID_ARGUMENT;
7402 }
7403
7404 #ifndef CONFIG_NOMONITORS
7405 ledger_set_limit(ledger, task_ledgers.interrupt_wakeups, *rate_hz * task_wakeups_monitor_interval,
7406 (uint8_t)task_wakeups_monitor_ustackshots_trigger_pct);
7407 ledger_set_period(ledger, task_ledgers.interrupt_wakeups, task_wakeups_monitor_interval * NSEC_PER_SEC);
7408 ledger_enable_callback(ledger, task_ledgers.interrupt_wakeups);
7409 #endif /* CONFIG_NOMONITORS */
7410 } else if (*flags & WAKEMON_DISABLE) {
7411 /*
7412 * Caller wishes to disable wakeups monitor on the task.
7413 *
7414 * Disable telemetry if it was triggered by the wakeups monitor, and
7415 * remove the limit & callback on the wakeups ledger entry.
7416 */
7417 #if CONFIG_TELEMETRY
7418 telemetry_task_ctl_locked(task, TF_WAKEMON_WARNING, 0);
7419 #endif
7420 ledger_disable_refill(ledger, task_ledgers.interrupt_wakeups);
7421 ledger_disable_callback(ledger, task_ledgers.interrupt_wakeups);
7422 }
7423
7424 task_unlock(task);
7425 return KERN_SUCCESS;
7426 }
7427
7428 void
task_wakeups_rate_exceeded(int warning,__unused const void * param0,__unused const void * param1)7429 task_wakeups_rate_exceeded(int warning, __unused const void *param0, __unused const void *param1)
7430 {
7431 if (warning == LEDGER_WARNING_ROSE_ABOVE) {
7432 #if CONFIG_TELEMETRY
7433 /*
7434 * This task is in danger of violating the wakeups monitor. Enable telemetry on this task
7435 * so there are micro-stackshots available if and when EXC_RESOURCE is triggered.
7436 */
7437 telemetry_task_ctl(current_task(), TF_WAKEMON_WARNING, 1);
7438 #endif
7439 return;
7440 }
7441
7442 #if CONFIG_TELEMETRY
7443 /*
7444 * If the balance has dipped below the warning level (LEDGER_WARNING_DIPPED_BELOW) or
7445 * exceeded the limit, turn telemetry off for the task.
7446 */
7447 telemetry_task_ctl(current_task(), TF_WAKEMON_WARNING, 0);
7448 #endif
7449
7450 if (warning == 0) {
7451 SENDING_NOTIFICATION__THIS_PROCESS_IS_CAUSING_TOO_MANY_WAKEUPS();
7452 }
7453 }
7454
7455 void __attribute__((noinline))
SENDING_NOTIFICATION__THIS_PROCESS_IS_CAUSING_TOO_MANY_WAKEUPS(void)7456 SENDING_NOTIFICATION__THIS_PROCESS_IS_CAUSING_TOO_MANY_WAKEUPS(void)
7457 {
7458 task_t task = current_task();
7459 int pid = 0;
7460 const char *procname = "unknown";
7461 boolean_t fatal;
7462 kern_return_t kr;
7463 #ifdef EXC_RESOURCE_MONITORS
7464 mach_exception_data_type_t code[EXCEPTION_CODE_MAX];
7465 #endif /* EXC_RESOURCE_MONITORS */
7466 struct ledger_entry_info lei;
7467
7468 #ifdef MACH_BSD
7469 pid = proc_selfpid();
7470 if (get_bsdtask_info(task) != NULL) {
7471 procname = proc_name_address(get_bsdtask_info(current_task()));
7472 }
7473 #endif
7474
7475 ledger_get_entry_info(task->ledger, task_ledgers.interrupt_wakeups, &lei);
7476
7477 /*
7478 * Disable the exception notification so we don't overwhelm
7479 * the listener with an endless stream of redundant exceptions.
7480 * TODO: detect whether another thread is already reporting the violation.
7481 */
7482 uint32_t flags = WAKEMON_DISABLE;
7483 task_wakeups_monitor_ctl(task, &flags, NULL);
7484
7485 fatal = task->rusage_cpu_flags & TASK_RUSECPU_FLAGS_FATAL_WAKEUPSMON;
7486 trace_resource_violation(RMON_CPUWAKES_VIOLATED, &lei);
7487 os_log(OS_LOG_DEFAULT, "process %s[%d] caught waking the CPU %llu times "
7488 "over ~%llu seconds, averaging %llu wakes / second and "
7489 "violating a %slimit of %llu wakes over %llu seconds.\n",
7490 procname, pid,
7491 lei.lei_balance, lei.lei_last_refill / NSEC_PER_SEC,
7492 lei.lei_last_refill == 0 ? 0 :
7493 (NSEC_PER_SEC * lei.lei_balance / lei.lei_last_refill),
7494 fatal ? "FATAL " : "",
7495 lei.lei_limit, lei.lei_refill_period / NSEC_PER_SEC);
7496
7497 kr = send_resource_violation(send_cpu_wakes_violation, task, &lei,
7498 fatal ? kRNFatalLimitFlag : 0);
7499 if (kr) {
7500 printf("send_resource_violation(CPU wakes, ...): error %#x\n", kr);
7501 }
7502
7503 #ifdef EXC_RESOURCE_MONITORS
7504 if (disable_exc_resource) {
7505 printf("process %s[%d] caught causing excessive wakeups. EXC_RESOURCE "
7506 "supressed by a boot-arg\n", procname, pid);
7507 return;
7508 }
7509 if (audio_active) {
7510 os_log(OS_LOG_DEFAULT, "process %s[%d] caught causing excessive wakeups. EXC_RESOURCE "
7511 "supressed due to audio playback\n", procname, pid);
7512 return;
7513 }
7514 if (lei.lei_last_refill == 0) {
7515 os_log(OS_LOG_DEFAULT, "process %s[%d] caught causing excessive wakeups. EXC_RESOURCE "
7516 "supressed due to lei.lei_last_refill = 0 \n", procname, pid);
7517 }
7518
7519 code[0] = code[1] = 0;
7520 EXC_RESOURCE_ENCODE_TYPE(code[0], RESOURCE_TYPE_WAKEUPS);
7521 EXC_RESOURCE_ENCODE_FLAVOR(code[0], FLAVOR_WAKEUPS_MONITOR);
7522 EXC_RESOURCE_CPUMONITOR_ENCODE_WAKEUPS_PERMITTED(code[0],
7523 NSEC_PER_SEC * lei.lei_limit / lei.lei_refill_period);
7524 EXC_RESOURCE_CPUMONITOR_ENCODE_OBSERVATION_INTERVAL(code[0],
7525 lei.lei_last_refill);
7526 EXC_RESOURCE_CPUMONITOR_ENCODE_WAKEUPS_OBSERVED(code[1],
7527 NSEC_PER_SEC * lei.lei_balance / lei.lei_last_refill);
7528 exception_triage(EXC_RESOURCE, code, EXCEPTION_CODE_MAX);
7529 #endif /* EXC_RESOURCE_MONITORS */
7530
7531 if (fatal) {
7532 task_terminate_internal(task);
7533 }
7534 }
7535
7536 static boolean_t
global_update_logical_writes(int64_t io_delta,int64_t * global_write_count)7537 global_update_logical_writes(int64_t io_delta, int64_t *global_write_count)
7538 {
7539 int64_t old_count, new_count;
7540 boolean_t needs_telemetry;
7541
7542 do {
7543 new_count = old_count = *global_write_count;
7544 new_count += io_delta;
7545 if (new_count >= io_telemetry_limit) {
7546 new_count = 0;
7547 needs_telemetry = TRUE;
7548 } else {
7549 needs_telemetry = FALSE;
7550 }
7551 } while (!OSCompareAndSwap64(old_count, new_count, global_write_count));
7552 return needs_telemetry;
7553 }
7554
7555 void
task_update_physical_writes(__unused task_t task,__unused task_physical_write_flavor_t flavor,__unused uint64_t io_size,__unused task_balance_flags_t flags)7556 task_update_physical_writes(__unused task_t task, __unused task_physical_write_flavor_t flavor, __unused uint64_t io_size, __unused task_balance_flags_t flags)
7557 {
7558 #if CONFIG_PHYS_WRITE_ACCT
7559 if (!io_size) {
7560 return;
7561 }
7562
7563 /*
7564 * task == NULL means that we have to update kernel_task ledgers
7565 */
7566 if (!task) {
7567 task = kernel_task;
7568 }
7569
7570 KERNEL_DEBUG_CONSTANT((MACHDBG_CODE(DBG_MACH_VM, VM_PHYS_WRITE_ACCT)) | DBG_FUNC_NONE,
7571 task_pid(task), flavor, io_size, flags, 0);
7572 DTRACE_IO4(physical_writes, struct task *, task, task_physical_write_flavor_t, flavor, uint64_t, io_size, task_balance_flags_t, flags);
7573
7574 if (flags & TASK_BALANCE_CREDIT) {
7575 if (flavor == TASK_PHYSICAL_WRITE_METADATA) {
7576 OSAddAtomic64(io_size, (SInt64 *)&(task->task_fs_metadata_writes));
7577 ledger_credit_nocheck(task->ledger, task_ledgers.fs_metadata_writes, io_size);
7578 }
7579 } else if (flags & TASK_BALANCE_DEBIT) {
7580 if (flavor == TASK_PHYSICAL_WRITE_METADATA) {
7581 OSAddAtomic64(-1 * io_size, (SInt64 *)&(task->task_fs_metadata_writes));
7582 ledger_debit_nocheck(task->ledger, task_ledgers.fs_metadata_writes, io_size);
7583 }
7584 }
7585 #endif /* CONFIG_PHYS_WRITE_ACCT */
7586 }
7587
7588 void
task_update_logical_writes(task_t task,uint32_t io_size,int flags,void * vp)7589 task_update_logical_writes(task_t task, uint32_t io_size, int flags, void *vp)
7590 {
7591 int64_t io_delta = 0;
7592 int64_t * global_counter_to_update;
7593 boolean_t needs_telemetry = FALSE;
7594 boolean_t is_external_device = FALSE;
7595 int ledger_to_update = 0;
7596 struct task_writes_counters * writes_counters_to_update;
7597
7598 if ((!task) || (!io_size) || (!vp)) {
7599 return;
7600 }
7601
7602 KERNEL_DEBUG_CONSTANT((MACHDBG_CODE(DBG_MACH_VM, VM_DATA_WRITE)) | DBG_FUNC_NONE,
7603 task_pid(task), io_size, flags, (uintptr_t)VM_KERNEL_ADDRPERM(vp), 0);
7604 DTRACE_IO4(logical_writes, struct task *, task, uint32_t, io_size, int, flags, vnode *, vp);
7605
7606 // Is the drive backing this vnode internal or external to the system?
7607 if (vnode_isonexternalstorage(vp) == false) {
7608 global_counter_to_update = &global_logical_writes_count;
7609 ledger_to_update = task_ledgers.logical_writes;
7610 writes_counters_to_update = &task->task_writes_counters_internal;
7611 is_external_device = FALSE;
7612 } else {
7613 global_counter_to_update = &global_logical_writes_to_external_count;
7614 ledger_to_update = task_ledgers.logical_writes_to_external;
7615 writes_counters_to_update = &task->task_writes_counters_external;
7616 is_external_device = TRUE;
7617 }
7618
7619 switch (flags) {
7620 case TASK_WRITE_IMMEDIATE:
7621 OSAddAtomic64(io_size, (SInt64 *)&(writes_counters_to_update->task_immediate_writes));
7622 ledger_credit(task->ledger, ledger_to_update, io_size);
7623 if (!is_external_device) {
7624 coalition_io_ledger_update(task, FLAVOR_IO_LOGICAL_WRITES, TRUE, io_size);
7625 }
7626 break;
7627 case TASK_WRITE_DEFERRED:
7628 OSAddAtomic64(io_size, (SInt64 *)&(writes_counters_to_update->task_deferred_writes));
7629 ledger_credit(task->ledger, ledger_to_update, io_size);
7630 if (!is_external_device) {
7631 coalition_io_ledger_update(task, FLAVOR_IO_LOGICAL_WRITES, TRUE, io_size);
7632 }
7633 break;
7634 case TASK_WRITE_INVALIDATED:
7635 OSAddAtomic64(io_size, (SInt64 *)&(writes_counters_to_update->task_invalidated_writes));
7636 ledger_debit(task->ledger, ledger_to_update, io_size);
7637 if (!is_external_device) {
7638 coalition_io_ledger_update(task, FLAVOR_IO_LOGICAL_WRITES, FALSE, io_size);
7639 }
7640 break;
7641 case TASK_WRITE_METADATA:
7642 OSAddAtomic64(io_size, (SInt64 *)&(writes_counters_to_update->task_metadata_writes));
7643 ledger_credit(task->ledger, ledger_to_update, io_size);
7644 if (!is_external_device) {
7645 coalition_io_ledger_update(task, FLAVOR_IO_LOGICAL_WRITES, TRUE, io_size);
7646 }
7647 break;
7648 }
7649
7650 io_delta = (flags == TASK_WRITE_INVALIDATED) ? ((int64_t)io_size * -1ll) : ((int64_t)io_size);
7651 if (io_telemetry_limit != 0) {
7652 /* If io_telemetry_limit is 0, disable global updates and I/O telemetry */
7653 needs_telemetry = global_update_logical_writes(io_delta, global_counter_to_update);
7654 if (needs_telemetry && !is_external_device) {
7655 act_set_io_telemetry_ast(current_thread());
7656 }
7657 }
7658 }
7659
7660 /*
7661 * Control the I/O monitor for a task.
7662 */
7663 kern_return_t
task_io_monitor_ctl(task_t task,uint32_t * flags)7664 task_io_monitor_ctl(task_t task, uint32_t *flags)
7665 {
7666 ledger_t ledger = task->ledger;
7667
7668 task_lock(task);
7669 if (*flags & IOMON_ENABLE) {
7670 /* Configure the physical I/O ledger */
7671 ledger_set_limit(ledger, task_ledgers.physical_writes, (task_iomon_limit_mb * 1024 * 1024), 0);
7672 ledger_set_period(ledger, task_ledgers.physical_writes, (task_iomon_interval_secs * NSEC_PER_SEC));
7673 } else if (*flags & IOMON_DISABLE) {
7674 /*
7675 * Caller wishes to disable I/O monitor on the task.
7676 */
7677 ledger_disable_refill(ledger, task_ledgers.physical_writes);
7678 ledger_disable_callback(ledger, task_ledgers.physical_writes);
7679 }
7680
7681 task_unlock(task);
7682 return KERN_SUCCESS;
7683 }
7684
7685 void
task_io_rate_exceeded(int warning,const void * param0,__unused const void * param1)7686 task_io_rate_exceeded(int warning, const void *param0, __unused const void *param1)
7687 {
7688 if (warning == 0) {
7689 SENDING_NOTIFICATION__THIS_PROCESS_IS_CAUSING_TOO_MUCH_IO((int)param0);
7690 }
7691 }
7692
7693 void __attribute__((noinline))
SENDING_NOTIFICATION__THIS_PROCESS_IS_CAUSING_TOO_MUCH_IO(int flavor)7694 SENDING_NOTIFICATION__THIS_PROCESS_IS_CAUSING_TOO_MUCH_IO(int flavor)
7695 {
7696 int pid = 0;
7697 task_t task = current_task();
7698 #ifdef EXC_RESOURCE_MONITORS
7699 mach_exception_data_type_t code[EXCEPTION_CODE_MAX];
7700 #endif /* EXC_RESOURCE_MONITORS */
7701 struct ledger_entry_info lei = {};
7702 kern_return_t kr;
7703
7704 #ifdef MACH_BSD
7705 pid = proc_selfpid();
7706 #endif
7707 /*
7708 * Get the ledger entry info. We need to do this before disabling the exception
7709 * to get correct values for all fields.
7710 */
7711 switch (flavor) {
7712 case FLAVOR_IO_PHYSICAL_WRITES:
7713 ledger_get_entry_info(task->ledger, task_ledgers.physical_writes, &lei);
7714 break;
7715 }
7716
7717
7718 /*
7719 * Disable the exception notification so we don't overwhelm
7720 * the listener with an endless stream of redundant exceptions.
7721 * TODO: detect whether another thread is already reporting the violation.
7722 */
7723 uint32_t flags = IOMON_DISABLE;
7724 task_io_monitor_ctl(task, &flags);
7725
7726 if (flavor == FLAVOR_IO_LOGICAL_WRITES) {
7727 trace_resource_violation(RMON_LOGWRITES_VIOLATED, &lei);
7728 }
7729 os_log(OS_LOG_DEFAULT, "process [%d] caught causing excessive I/O (flavor: %d). Task I/O: %lld MB. [Limit : %lld MB per %lld secs]\n",
7730 pid, flavor, (lei.lei_balance / (1024 * 1024)), (lei.lei_limit / (1024 * 1024)), (lei.lei_refill_period / NSEC_PER_SEC));
7731
7732 kr = send_resource_violation(send_disk_writes_violation, task, &lei, kRNFlagsNone);
7733 if (kr) {
7734 printf("send_resource_violation(disk_writes, ...): error %#x\n", kr);
7735 }
7736
7737 #ifdef EXC_RESOURCE_MONITORS
7738 code[0] = code[1] = 0;
7739 EXC_RESOURCE_ENCODE_TYPE(code[0], RESOURCE_TYPE_IO);
7740 EXC_RESOURCE_ENCODE_FLAVOR(code[0], flavor);
7741 EXC_RESOURCE_IO_ENCODE_INTERVAL(code[0], (lei.lei_refill_period / NSEC_PER_SEC));
7742 EXC_RESOURCE_IO_ENCODE_LIMIT(code[0], (lei.lei_limit / (1024 * 1024)));
7743 EXC_RESOURCE_IO_ENCODE_OBSERVED(code[1], (lei.lei_balance / (1024 * 1024)));
7744 exception_triage(EXC_RESOURCE, code, EXCEPTION_CODE_MAX);
7745 #endif /* EXC_RESOURCE_MONITORS */
7746 }
7747
7748 void
task_port_space_ast(__unused task_t task)7749 task_port_space_ast(__unused task_t task)
7750 {
7751 uint32_t current_size, soft_limit, hard_limit;
7752 assert(task == current_task());
7753 kern_return_t ret = ipc_space_get_table_size_and_limits(task->itk_space,
7754 ¤t_size, &soft_limit, &hard_limit);
7755 if (ret == KERN_SUCCESS) {
7756 SENDING_NOTIFICATION__THIS_PROCESS_HAS_TOO_MANY_MACH_PORTS(task, current_size, soft_limit, hard_limit);
7757 }
7758 }
7759
7760 #if CONFIG_PROC_RESOURCE_LIMITS
7761 static mach_port_t
task_allocate_fatal_port(void)7762 task_allocate_fatal_port(void)
7763 {
7764 mach_port_t task_fatal_port = MACH_PORT_NULL;
7765 task_id_token_t token;
7766
7767 kern_return_t kr = task_create_identity_token(current_task(), &token); /* Takes a reference on the token */
7768 if (kr) {
7769 return MACH_PORT_NULL;
7770 }
7771 task_fatal_port = ipc_kobject_alloc_port((ipc_kobject_t)token, IKOT_TASK_FATAL,
7772 IPC_KOBJECT_ALLOC_NSREQUEST | IPC_KOBJECT_ALLOC_MAKE_SEND);
7773
7774 task_id_token_set_port(token, task_fatal_port);
7775
7776 return task_fatal_port;
7777 }
7778
7779 static void
task_fatal_port_no_senders(ipc_port_t port,__unused mach_port_mscount_t mscount)7780 task_fatal_port_no_senders(ipc_port_t port, __unused mach_port_mscount_t mscount)
7781 {
7782 task_t task = TASK_NULL;
7783 kern_return_t kr;
7784
7785 task_id_token_t token = ipc_kobject_get_stable(port, IKOT_TASK_FATAL);
7786
7787 assert(token != NULL);
7788 if (token) {
7789 kr = task_identity_token_get_task_grp(token, &task, TASK_GRP_KERNEL); /* takes a reference on task */
7790 if (task) {
7791 task_bsdtask_kill(task);
7792 task_deallocate(task);
7793 }
7794 task_id_token_release(token); /* consumes ref given by notification */
7795 }
7796 }
7797 #endif /* CONFIG_PROC_RESOURCE_LIMITS */
7798
7799 void __attribute__((noinline))
SENDING_NOTIFICATION__THIS_PROCESS_HAS_TOO_MANY_MACH_PORTS(task_t task,uint32_t current_size,uint32_t soft_limit,uint32_t hard_limit)7800 SENDING_NOTIFICATION__THIS_PROCESS_HAS_TOO_MANY_MACH_PORTS(task_t task, uint32_t current_size, uint32_t soft_limit, uint32_t hard_limit)
7801 {
7802 int pid = 0;
7803 char *procname = (char *) "unknown";
7804 __unused kern_return_t kr;
7805 __unused resource_notify_flags_t flags = kRNFlagsNone;
7806 __unused uint32_t limit;
7807 __unused mach_port_t task_fatal_port = MACH_PORT_NULL;
7808 mach_exception_data_type_t code[EXCEPTION_CODE_MAX];
7809
7810 #ifdef MACH_BSD
7811 pid = proc_selfpid();
7812 if (get_bsdtask_info(task) != NULL) {
7813 procname = proc_name_address(get_bsdtask_info(task));
7814 }
7815 #endif
7816 /*
7817 * Only kernel_task and launchd may be allowed to
7818 * have really large ipc space.
7819 */
7820 if (pid == 0 || pid == 1) {
7821 return;
7822 }
7823
7824 os_log(OS_LOG_DEFAULT, "process %s[%d] caught allocating too many mach ports. \
7825 Num of ports allocated %u; \n", procname, pid, current_size);
7826
7827 /* Abort the process if it has hit the system-wide limit for ipc port table size */
7828 if (!hard_limit && !soft_limit) {
7829 code[0] = code[1] = 0;
7830 EXC_RESOURCE_ENCODE_TYPE(code[0], RESOURCE_TYPE_PORTS);
7831 EXC_RESOURCE_ENCODE_FLAVOR(code[0], FLAVOR_PORT_SPACE_FULL);
7832 EXC_RESOURCE_PORTS_ENCODE_PORTS(code[0], current_size);
7833
7834 exit_with_port_space_exception(current_proc(), code[0], code[1]);
7835
7836 return;
7837 }
7838
7839 #if CONFIG_PROC_RESOURCE_LIMITS
7840 if (hard_limit > 0) {
7841 flags |= kRNHardLimitFlag;
7842 limit = hard_limit;
7843 task_fatal_port = task_allocate_fatal_port();
7844 if (!task_fatal_port) {
7845 os_log(OS_LOG_DEFAULT, "process %s[%d] Unable to create task token ident object", procname, pid);
7846 task_bsdtask_kill(task);
7847 }
7848 } else {
7849 flags |= kRNSoftLimitFlag;
7850 limit = soft_limit;
7851 }
7852
7853 kr = send_resource_violation_with_fatal_port(send_port_space_violation, task, (int64_t)current_size, (int64_t)limit, task_fatal_port, flags);
7854 if (kr) {
7855 os_log(OS_LOG_DEFAULT, "send_resource_violation(ports, ...): error %#x\n", kr);
7856 }
7857 if (task_fatal_port) {
7858 ipc_port_release_send(task_fatal_port);
7859 }
7860 #endif /* CONFIG_PROC_RESOURCE_LIMITS */
7861 }
7862
7863 void
task_filedesc_ast(__unused task_t task,__unused int current_size,__unused int soft_limit,__unused int hard_limit)7864 task_filedesc_ast(__unused task_t task, __unused int current_size, __unused int soft_limit, __unused int hard_limit)
7865 {
7866 #if CONFIG_PROC_RESOURCE_LIMITS
7867 assert(task == current_task());
7868 SENDING_NOTIFICATION__THIS_PROCESS_HAS_TOO_MANY_FILE_DESCRIPTORS(task, current_size, soft_limit, hard_limit);
7869 #endif /* CONFIG_PROC_RESOURCE_LIMITS */
7870 }
7871
7872 #if CONFIG_PROC_RESOURCE_LIMITS
7873 void __attribute__((noinline))
SENDING_NOTIFICATION__THIS_PROCESS_HAS_TOO_MANY_FILE_DESCRIPTORS(task_t task,int current_size,int soft_limit,int hard_limit)7874 SENDING_NOTIFICATION__THIS_PROCESS_HAS_TOO_MANY_FILE_DESCRIPTORS(task_t task, int current_size, int soft_limit, int hard_limit)
7875 {
7876 int pid = 0;
7877 char *procname = (char *) "unknown";
7878 kern_return_t kr;
7879 resource_notify_flags_t flags = kRNFlagsNone;
7880 int limit;
7881 mach_port_t task_fatal_port = MACH_PORT_NULL;
7882
7883 #ifdef MACH_BSD
7884 pid = proc_selfpid();
7885 if (get_bsdtask_info(task) != NULL) {
7886 procname = proc_name_address(get_bsdtask_info(task));
7887 }
7888 #endif
7889 /*
7890 * Only kernel_task and launchd may be allowed to
7891 * have really large ipc space.
7892 */
7893 if (pid == 0 || pid == 1) {
7894 return;
7895 }
7896
7897 os_log(OS_LOG_DEFAULT, "process %s[%d] caught allocating too many file descriptors. \
7898 Num of fds allocated %u; \n", procname, pid, current_size);
7899
7900 if (hard_limit > 0) {
7901 flags |= kRNHardLimitFlag;
7902 limit = hard_limit;
7903 task_fatal_port = task_allocate_fatal_port();
7904 if (!task_fatal_port) {
7905 os_log(OS_LOG_DEFAULT, "process %s[%d] Unable to create task token ident object", procname, pid);
7906 task_bsdtask_kill(task);
7907 }
7908 } else {
7909 flags |= kRNSoftLimitFlag;
7910 limit = soft_limit;
7911 }
7912
7913 kr = send_resource_violation_with_fatal_port(send_file_descriptors_violation, task, (int64_t)current_size, (int64_t)limit, task_fatal_port, flags);
7914 if (kr) {
7915 os_log(OS_LOG_DEFAULT, "send_resource_violation_with_fatal_port(filedesc, ...): error %#x\n", kr);
7916 }
7917 if (task_fatal_port) {
7918 ipc_port_release_send(task_fatal_port);
7919 }
7920 }
7921 #endif /* CONFIG_PROC_RESOURCE_LIMITS */
7922
7923 /* Placeholders for the task set/get voucher interfaces */
7924 kern_return_t
task_get_mach_voucher(task_t task,mach_voucher_selector_t __unused which,ipc_voucher_t * voucher)7925 task_get_mach_voucher(
7926 task_t task,
7927 mach_voucher_selector_t __unused which,
7928 ipc_voucher_t *voucher)
7929 {
7930 if (TASK_NULL == task) {
7931 return KERN_INVALID_TASK;
7932 }
7933
7934 *voucher = NULL;
7935 return KERN_SUCCESS;
7936 }
7937
7938 kern_return_t
task_set_mach_voucher(task_t task,ipc_voucher_t __unused voucher)7939 task_set_mach_voucher(
7940 task_t task,
7941 ipc_voucher_t __unused voucher)
7942 {
7943 if (TASK_NULL == task) {
7944 return KERN_INVALID_TASK;
7945 }
7946
7947 return KERN_SUCCESS;
7948 }
7949
7950 kern_return_t
task_swap_mach_voucher(__unused task_t task,__unused ipc_voucher_t new_voucher,ipc_voucher_t * in_out_old_voucher)7951 task_swap_mach_voucher(
7952 __unused task_t task,
7953 __unused ipc_voucher_t new_voucher,
7954 ipc_voucher_t *in_out_old_voucher)
7955 {
7956 /*
7957 * Currently this function is only called from a MIG generated
7958 * routine which doesn't release the reference on the voucher
7959 * addressed by in_out_old_voucher. To avoid leaking this reference,
7960 * a call to release it has been added here.
7961 */
7962 ipc_voucher_release(*in_out_old_voucher);
7963 OS_ANALYZER_SUPPRESS("81787115") return KERN_NOT_SUPPORTED;
7964 }
7965
7966 void
task_set_gpu_denied(task_t task,boolean_t denied)7967 task_set_gpu_denied(task_t task, boolean_t denied)
7968 {
7969 task_lock(task);
7970
7971 if (denied) {
7972 task->t_flags |= TF_GPU_DENIED;
7973 } else {
7974 task->t_flags &= ~TF_GPU_DENIED;
7975 }
7976
7977 task_unlock(task);
7978 }
7979
7980 boolean_t
task_is_gpu_denied(task_t task)7981 task_is_gpu_denied(task_t task)
7982 {
7983 /* We don't need the lock to read this flag */
7984 return (task->t_flags & TF_GPU_DENIED) ? TRUE : FALSE;
7985 }
7986
7987
7988 uint64_t
get_task_memory_region_count(task_t task)7989 get_task_memory_region_count(task_t task)
7990 {
7991 vm_map_t map;
7992 map = (task == kernel_task) ? kernel_map: task->map;
7993 return (uint64_t)get_map_nentries(map);
7994 }
7995
7996 static void
kdebug_trace_dyld_internal(uint32_t base_code,struct dyld_kernel_image_info * info)7997 kdebug_trace_dyld_internal(uint32_t base_code,
7998 struct dyld_kernel_image_info *info)
7999 {
8000 static_assert(sizeof(info->uuid) >= 16);
8001
8002 #if defined(__LP64__)
8003 uint64_t *uuid = (uint64_t *)&(info->uuid);
8004
8005 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
8006 KDBG_EVENTID(DBG_DYLD, DBG_DYLD_UUID, base_code), uuid[0],
8007 uuid[1], info->load_addr,
8008 (uint64_t)info->fsid.val[0] | ((uint64_t)info->fsid.val[1] << 32),
8009 0);
8010 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
8011 KDBG_EVENTID(DBG_DYLD, DBG_DYLD_UUID, base_code + 1),
8012 (uint64_t)info->fsobjid.fid_objno |
8013 ((uint64_t)info->fsobjid.fid_generation << 32),
8014 0, 0, 0, 0);
8015 #else /* defined(__LP64__) */
8016 uint32_t *uuid = (uint32_t *)&(info->uuid);
8017
8018 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
8019 KDBG_EVENTID(DBG_DYLD, DBG_DYLD_UUID, base_code + 2), uuid[0],
8020 uuid[1], uuid[2], uuid[3], 0);
8021 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
8022 KDBG_EVENTID(DBG_DYLD, DBG_DYLD_UUID, base_code + 3),
8023 (uint32_t)info->load_addr, info->fsid.val[0], info->fsid.val[1],
8024 info->fsobjid.fid_objno, 0);
8025 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
8026 KDBG_EVENTID(DBG_DYLD, DBG_DYLD_UUID, base_code + 4),
8027 info->fsobjid.fid_generation, 0, 0, 0, 0);
8028 #endif /* !defined(__LP64__) */
8029 }
8030
8031 static kern_return_t
kdebug_trace_dyld(task_t task,uint32_t base_code,vm_map_copy_t infos_copy,mach_msg_type_number_t infos_len)8032 kdebug_trace_dyld(task_t task, uint32_t base_code,
8033 vm_map_copy_t infos_copy, mach_msg_type_number_t infos_len)
8034 {
8035 kern_return_t kr;
8036 dyld_kernel_image_info_array_t infos;
8037 vm_map_offset_t map_data;
8038 vm_offset_t data;
8039
8040 if (!infos_copy) {
8041 return KERN_INVALID_ADDRESS;
8042 }
8043
8044 if (!kdebug_enable ||
8045 !kdebug_debugid_enabled(KDBG_EVENTID(DBG_DYLD, DBG_DYLD_UUID, 0))) {
8046 vm_map_copy_discard(infos_copy);
8047 return KERN_SUCCESS;
8048 }
8049
8050 if (task == NULL || task != current_task()) {
8051 return KERN_INVALID_TASK;
8052 }
8053
8054 kr = vm_map_copyout(ipc_kernel_map, &map_data, (vm_map_copy_t)infos_copy);
8055 if (kr != KERN_SUCCESS) {
8056 return kr;
8057 }
8058
8059 infos = CAST_DOWN(dyld_kernel_image_info_array_t, map_data);
8060
8061 for (mach_msg_type_number_t i = 0; i < infos_len; i++) {
8062 kdebug_trace_dyld_internal(base_code, &(infos[i]));
8063 }
8064
8065 data = CAST_DOWN(vm_offset_t, map_data);
8066 mach_vm_deallocate(ipc_kernel_map, data, infos_len * sizeof(infos[0]));
8067 return KERN_SUCCESS;
8068 }
8069
8070 kern_return_t
task_register_dyld_image_infos(task_t task,dyld_kernel_image_info_array_t infos_copy,mach_msg_type_number_t infos_len)8071 task_register_dyld_image_infos(task_t task,
8072 dyld_kernel_image_info_array_t infos_copy,
8073 mach_msg_type_number_t infos_len)
8074 {
8075 return kdebug_trace_dyld(task, DBG_DYLD_UUID_MAP_A,
8076 (vm_map_copy_t)infos_copy, infos_len);
8077 }
8078
8079 kern_return_t
task_unregister_dyld_image_infos(task_t task,dyld_kernel_image_info_array_t infos_copy,mach_msg_type_number_t infos_len)8080 task_unregister_dyld_image_infos(task_t task,
8081 dyld_kernel_image_info_array_t infos_copy,
8082 mach_msg_type_number_t infos_len)
8083 {
8084 return kdebug_trace_dyld(task, DBG_DYLD_UUID_UNMAP_A,
8085 (vm_map_copy_t)infos_copy, infos_len);
8086 }
8087
8088 kern_return_t
task_get_dyld_image_infos(__unused task_t task,__unused dyld_kernel_image_info_array_t * dyld_images,__unused mach_msg_type_number_t * dyld_imagesCnt)8089 task_get_dyld_image_infos(__unused task_t task,
8090 __unused dyld_kernel_image_info_array_t * dyld_images,
8091 __unused mach_msg_type_number_t * dyld_imagesCnt)
8092 {
8093 return KERN_NOT_SUPPORTED;
8094 }
8095
8096 kern_return_t
task_register_dyld_shared_cache_image_info(task_t task,dyld_kernel_image_info_t cache_img,__unused boolean_t no_cache,__unused boolean_t private_cache)8097 task_register_dyld_shared_cache_image_info(task_t task,
8098 dyld_kernel_image_info_t cache_img,
8099 __unused boolean_t no_cache,
8100 __unused boolean_t private_cache)
8101 {
8102 if (task == NULL || task != current_task()) {
8103 return KERN_INVALID_TASK;
8104 }
8105
8106 kdebug_trace_dyld_internal(DBG_DYLD_UUID_SHARED_CACHE_A, &cache_img);
8107 return KERN_SUCCESS;
8108 }
8109
8110 kern_return_t
task_register_dyld_set_dyld_state(__unused task_t task,__unused uint8_t dyld_state)8111 task_register_dyld_set_dyld_state(__unused task_t task,
8112 __unused uint8_t dyld_state)
8113 {
8114 return KERN_NOT_SUPPORTED;
8115 }
8116
8117 kern_return_t
task_register_dyld_get_process_state(__unused task_t task,__unused dyld_kernel_process_info_t * dyld_process_state)8118 task_register_dyld_get_process_state(__unused task_t task,
8119 __unused dyld_kernel_process_info_t * dyld_process_state)
8120 {
8121 return KERN_NOT_SUPPORTED;
8122 }
8123
8124 kern_return_t
task_inspect(task_inspect_t task_insp,task_inspect_flavor_t flavor,task_inspect_info_t info_out,mach_msg_type_number_t * size_in_out)8125 task_inspect(task_inspect_t task_insp, task_inspect_flavor_t flavor,
8126 task_inspect_info_t info_out, mach_msg_type_number_t *size_in_out)
8127 {
8128 #if CONFIG_PERVASIVE_CPI
8129 task_t task = (task_t)task_insp;
8130 kern_return_t kr = KERN_SUCCESS;
8131 mach_msg_type_number_t size;
8132
8133 if (task == TASK_NULL) {
8134 return KERN_INVALID_ARGUMENT;
8135 }
8136
8137 size = *size_in_out;
8138
8139 switch (flavor) {
8140 case TASK_INSPECT_BASIC_COUNTS: {
8141 struct task_inspect_basic_counts *bc =
8142 (struct task_inspect_basic_counts *)info_out;
8143 struct recount_usage stats = { 0 };
8144 if (size < TASK_INSPECT_BASIC_COUNTS_COUNT) {
8145 kr = KERN_INVALID_ARGUMENT;
8146 break;
8147 }
8148
8149 recount_sum(&recount_task_plan, task->tk_recount.rtk_lifetime, &stats);
8150 bc->instructions = stats.ru_instructions;
8151 bc->cycles = stats.ru_cycles;
8152 size = TASK_INSPECT_BASIC_COUNTS_COUNT;
8153 break;
8154 }
8155 default:
8156 kr = KERN_INVALID_ARGUMENT;
8157 break;
8158 }
8159
8160 if (kr == KERN_SUCCESS) {
8161 *size_in_out = size;
8162 }
8163 return kr;
8164 #else /* CONFIG_PERVASIVE_CPI */
8165 #pragma unused(task_insp, flavor, info_out, size_in_out)
8166 return KERN_NOT_SUPPORTED;
8167 #endif /* !CONFIG_PERVASIVE_CPI */
8168 }
8169
8170 #if CONFIG_SECLUDED_MEMORY
8171 int num_tasks_can_use_secluded_mem = 0;
8172
8173 void
task_set_can_use_secluded_mem(task_t task,boolean_t can_use_secluded_mem)8174 task_set_can_use_secluded_mem(
8175 task_t task,
8176 boolean_t can_use_secluded_mem)
8177 {
8178 if (!task->task_could_use_secluded_mem) {
8179 return;
8180 }
8181 task_lock(task);
8182 task_set_can_use_secluded_mem_locked(task, can_use_secluded_mem);
8183 task_unlock(task);
8184 }
8185
8186 void
task_set_can_use_secluded_mem_locked(task_t task,boolean_t can_use_secluded_mem)8187 task_set_can_use_secluded_mem_locked(
8188 task_t task,
8189 boolean_t can_use_secluded_mem)
8190 {
8191 assert(task->task_could_use_secluded_mem);
8192 if (can_use_secluded_mem &&
8193 secluded_for_apps && /* global boot-arg */
8194 !task->task_can_use_secluded_mem) {
8195 assert(num_tasks_can_use_secluded_mem >= 0);
8196 OSAddAtomic(+1,
8197 (volatile SInt32 *)&num_tasks_can_use_secluded_mem);
8198 task->task_can_use_secluded_mem = TRUE;
8199 } else if (!can_use_secluded_mem &&
8200 task->task_can_use_secluded_mem) {
8201 assert(num_tasks_can_use_secluded_mem > 0);
8202 OSAddAtomic(-1,
8203 (volatile SInt32 *)&num_tasks_can_use_secluded_mem);
8204 task->task_can_use_secluded_mem = FALSE;
8205 }
8206 }
8207
8208 void
task_set_could_use_secluded_mem(task_t task,boolean_t could_use_secluded_mem)8209 task_set_could_use_secluded_mem(
8210 task_t task,
8211 boolean_t could_use_secluded_mem)
8212 {
8213 task->task_could_use_secluded_mem = !!could_use_secluded_mem;
8214 }
8215
8216 void
task_set_could_also_use_secluded_mem(task_t task,boolean_t could_also_use_secluded_mem)8217 task_set_could_also_use_secluded_mem(
8218 task_t task,
8219 boolean_t could_also_use_secluded_mem)
8220 {
8221 task->task_could_also_use_secluded_mem = !!could_also_use_secluded_mem;
8222 }
8223
8224 boolean_t
task_can_use_secluded_mem(task_t task,boolean_t is_alloc)8225 task_can_use_secluded_mem(
8226 task_t task,
8227 boolean_t is_alloc)
8228 {
8229 if (task->task_can_use_secluded_mem) {
8230 assert(task->task_could_use_secluded_mem);
8231 assert(num_tasks_can_use_secluded_mem > 0);
8232 return TRUE;
8233 }
8234 if (task->task_could_also_use_secluded_mem &&
8235 num_tasks_can_use_secluded_mem > 0) {
8236 assert(num_tasks_can_use_secluded_mem > 0);
8237 return TRUE;
8238 }
8239
8240 /*
8241 * If a single task is using more than some large amount of
8242 * memory (i.e. secluded_shutoff_trigger) and is approaching
8243 * its task limit, allow it to dip into secluded and begin
8244 * suppression of rebuilding secluded memory until that task exits.
8245 */
8246 if (is_alloc && secluded_shutoff_trigger != 0) {
8247 uint64_t phys_used = get_task_phys_footprint(task);
8248 uint64_t limit = get_task_phys_footprint_limit(task);
8249 if (phys_used > secluded_shutoff_trigger &&
8250 limit > secluded_shutoff_trigger &&
8251 phys_used > limit - secluded_shutoff_headroom) {
8252 start_secluded_suppression(task);
8253 return TRUE;
8254 }
8255 }
8256
8257 return FALSE;
8258 }
8259
8260 boolean_t
task_could_use_secluded_mem(task_t task)8261 task_could_use_secluded_mem(
8262 task_t task)
8263 {
8264 return task->task_could_use_secluded_mem;
8265 }
8266
8267 boolean_t
task_could_also_use_secluded_mem(task_t task)8268 task_could_also_use_secluded_mem(
8269 task_t task)
8270 {
8271 return task->task_could_also_use_secluded_mem;
8272 }
8273 #endif /* CONFIG_SECLUDED_MEMORY */
8274
8275 queue_head_t *
task_io_user_clients(task_t task)8276 task_io_user_clients(task_t task)
8277 {
8278 return &task->io_user_clients;
8279 }
8280
8281 void
task_set_message_app_suspended(task_t task,boolean_t enable)8282 task_set_message_app_suspended(task_t task, boolean_t enable)
8283 {
8284 task->message_app_suspended = enable;
8285 }
8286
8287 void
task_copy_fields_for_exec(task_t dst_task,task_t src_task)8288 task_copy_fields_for_exec(task_t dst_task, task_t src_task)
8289 {
8290 dst_task->vtimers = src_task->vtimers;
8291 }
8292
8293 #if DEVELOPMENT || DEBUG
8294 int vm_region_footprint = 0;
8295 #endif /* DEVELOPMENT || DEBUG */
8296
8297 boolean_t
task_self_region_footprint(void)8298 task_self_region_footprint(void)
8299 {
8300 #if DEVELOPMENT || DEBUG
8301 if (vm_region_footprint) {
8302 /* system-wide override */
8303 return TRUE;
8304 }
8305 #endif /* DEVELOPMENT || DEBUG */
8306 return current_task()->task_region_footprint;
8307 }
8308
8309 void
task_self_region_footprint_set(boolean_t newval)8310 task_self_region_footprint_set(
8311 boolean_t newval)
8312 {
8313 task_t curtask;
8314
8315 curtask = current_task();
8316 task_lock(curtask);
8317 if (newval) {
8318 curtask->task_region_footprint = TRUE;
8319 } else {
8320 curtask->task_region_footprint = FALSE;
8321 }
8322 task_unlock(curtask);
8323 }
8324
8325 void
task_set_darkwake_mode(task_t task,boolean_t set_mode)8326 task_set_darkwake_mode(task_t task, boolean_t set_mode)
8327 {
8328 assert(task);
8329
8330 task_lock(task);
8331
8332 if (set_mode) {
8333 task->t_flags |= TF_DARKWAKE_MODE;
8334 } else {
8335 task->t_flags &= ~(TF_DARKWAKE_MODE);
8336 }
8337
8338 task_unlock(task);
8339 }
8340
8341 boolean_t
task_get_darkwake_mode(task_t task)8342 task_get_darkwake_mode(task_t task)
8343 {
8344 assert(task);
8345 return (task->t_flags & TF_DARKWAKE_MODE) != 0;
8346 }
8347
8348 /*
8349 * Set default behavior for task's control port and EXC_GUARD variants that have
8350 * settable behavior.
8351 *
8352 * Platform binaries typically have one behavior, third parties another -
8353 * but there are special exception we may need to account for.
8354 */
8355 void
task_set_exc_guard_ctrl_port_default(task_t task,thread_t main_thread,const char * name,unsigned int namelen,boolean_t is_simulated,uint32_t platform,uint32_t sdk)8356 task_set_exc_guard_ctrl_port_default(
8357 task_t task,
8358 thread_t main_thread,
8359 const char *name,
8360 unsigned int namelen,
8361 boolean_t is_simulated,
8362 uint32_t platform,
8363 uint32_t sdk)
8364 {
8365 task_control_port_options_t opts = TASK_CONTROL_PORT_OPTIONS_NONE;
8366
8367 if (task_get_platform_binary(task)) {
8368 /* set exc guard default behavior for first-party code */
8369 task->task_exc_guard = (task_exc_guard_default & TASK_EXC_GUARD_ALL);
8370
8371 if (1 == task_pid(task)) {
8372 /* special flags for inittask - delivery every instance as corpse */
8373 task->task_exc_guard = _TASK_EXC_GUARD_ALL_CORPSE;
8374 } else if (task_exc_guard_default & TASK_EXC_GUARD_HONOR_NAMED_DEFAULTS) {
8375 /* honor by-name default setting overrides */
8376
8377 int count = sizeof(task_exc_guard_named_defaults) / sizeof(struct task_exc_guard_named_default);
8378
8379 for (int i = 0; i < count; i++) {
8380 const struct task_exc_guard_named_default *named_default =
8381 &task_exc_guard_named_defaults[i];
8382 if (strncmp(named_default->name, name, namelen) == 0 &&
8383 strlen(named_default->name) == namelen) {
8384 task->task_exc_guard = named_default->behavior;
8385 break;
8386 }
8387 }
8388 }
8389
8390 /* set control port options for 1p code, inherited from parent task by default */
8391 opts = ipc_control_port_options & ICP_OPTIONS_1P_MASK;
8392 } else {
8393 /* set exc guard default behavior for third-party code */
8394 task->task_exc_guard = ((task_exc_guard_default >> TASK_EXC_GUARD_THIRD_PARTY_DEFAULT_SHIFT) & TASK_EXC_GUARD_ALL);
8395 /* set control port options for 3p code, inherited from parent task by default */
8396 opts = (ipc_control_port_options & ICP_OPTIONS_3P_MASK) >> ICP_OPTIONS_3P_SHIFT;
8397 }
8398
8399 if (is_simulated) {
8400 /* If simulated and built against pre-iOS 15 SDK, disable all EXC_GUARD */
8401 if ((platform == PLATFORM_IOSSIMULATOR && sdk < 0xf0000) ||
8402 (platform == PLATFORM_TVOSSIMULATOR && sdk < 0xf0000) ||
8403 (platform == PLATFORM_WATCHOSSIMULATOR && sdk < 0x80000)) {
8404 task->task_exc_guard = TASK_EXC_GUARD_NONE;
8405 }
8406 /* Disable protection for control ports for simulated binaries */
8407 opts = TASK_CONTROL_PORT_OPTIONS_NONE;
8408 }
8409
8410
8411 task_set_control_port_options(task, opts);
8412
8413 task_set_immovable_pinned(task);
8414 main_thread_set_immovable_pinned(main_thread);
8415 }
8416
8417 kern_return_t
task_get_exc_guard_behavior(task_t task,task_exc_guard_behavior_t * behaviorp)8418 task_get_exc_guard_behavior(
8419 task_t task,
8420 task_exc_guard_behavior_t *behaviorp)
8421 {
8422 if (task == TASK_NULL) {
8423 return KERN_INVALID_TASK;
8424 }
8425 *behaviorp = task->task_exc_guard;
8426 return KERN_SUCCESS;
8427 }
8428
8429 kern_return_t
task_set_exc_guard_behavior(task_t task,task_exc_guard_behavior_t new_behavior)8430 task_set_exc_guard_behavior(
8431 task_t task,
8432 task_exc_guard_behavior_t new_behavior)
8433 {
8434 if (task == TASK_NULL) {
8435 return KERN_INVALID_TASK;
8436 }
8437 if (new_behavior & ~TASK_EXC_GUARD_ALL) {
8438 return KERN_INVALID_VALUE;
8439 }
8440
8441 /* limit setting to that allowed for this config */
8442 new_behavior = new_behavior & task_exc_guard_config_mask;
8443
8444 #if !defined (DEBUG) && !defined (DEVELOPMENT)
8445 /* On release kernels, only allow _upgrading_ exc guard behavior */
8446 task_exc_guard_behavior_t cur_behavior;
8447
8448 os_atomic_rmw_loop(&task->task_exc_guard, cur_behavior, new_behavior, relaxed, {
8449 if ((cur_behavior & task_exc_guard_no_unset_mask) & ~(new_behavior & task_exc_guard_no_unset_mask)) {
8450 os_atomic_rmw_loop_give_up(return KERN_DENIED);
8451 }
8452
8453 if ((new_behavior & task_exc_guard_no_set_mask) & ~(cur_behavior & task_exc_guard_no_set_mask)) {
8454 os_atomic_rmw_loop_give_up(return KERN_DENIED);
8455 }
8456
8457 /* no restrictions on CORPSE bit */
8458 });
8459 #else
8460 task->task_exc_guard = new_behavior;
8461 #endif
8462 return KERN_SUCCESS;
8463 }
8464
8465 kern_return_t
task_set_corpse_forking_behavior(task_t task,task_corpse_forking_behavior_t behavior)8466 task_set_corpse_forking_behavior(task_t task, task_corpse_forking_behavior_t behavior)
8467 {
8468 #if DEVELOPMENT || DEBUG
8469 if (task == TASK_NULL) {
8470 return KERN_INVALID_TASK;
8471 }
8472
8473 task_lock(task);
8474 if (behavior & TASK_CORPSE_FORKING_DISABLED_MEM_DIAG) {
8475 task->t_flags |= TF_NO_CORPSE_FORKING;
8476 } else {
8477 task->t_flags &= ~TF_NO_CORPSE_FORKING;
8478 }
8479 task_unlock(task);
8480
8481 return KERN_SUCCESS;
8482 #else
8483 (void)task;
8484 (void)behavior;
8485 return KERN_NOT_SUPPORTED;
8486 #endif
8487 }
8488
8489 boolean_t
task_corpse_forking_disabled(task_t task)8490 task_corpse_forking_disabled(task_t task)
8491 {
8492 boolean_t disabled = FALSE;
8493
8494 task_lock(task);
8495 disabled = (task->t_flags & TF_NO_CORPSE_FORKING);
8496 task_unlock(task);
8497
8498 return disabled;
8499 }
8500
8501 #if __arm64__
8502 extern int legacy_footprint_entitlement_mode;
8503 extern void memorystatus_act_on_legacy_footprint_entitlement(struct proc *, boolean_t);
8504 extern void memorystatus_act_on_ios13extended_footprint_entitlement(struct proc *);
8505
8506
8507 void
task_set_legacy_footprint(task_t task)8508 task_set_legacy_footprint(
8509 task_t task)
8510 {
8511 task_lock(task);
8512 task->task_legacy_footprint = TRUE;
8513 task_unlock(task);
8514 }
8515
8516 void
task_set_extra_footprint_limit(task_t task)8517 task_set_extra_footprint_limit(
8518 task_t task)
8519 {
8520 if (task->task_extra_footprint_limit) {
8521 return;
8522 }
8523 task_lock(task);
8524 if (task->task_extra_footprint_limit) {
8525 task_unlock(task);
8526 return;
8527 }
8528 task->task_extra_footprint_limit = TRUE;
8529 task_unlock(task);
8530 memorystatus_act_on_legacy_footprint_entitlement(get_bsdtask_info(task), TRUE);
8531 }
8532
8533 void
task_set_ios13extended_footprint_limit(task_t task)8534 task_set_ios13extended_footprint_limit(
8535 task_t task)
8536 {
8537 if (task->task_ios13extended_footprint_limit) {
8538 return;
8539 }
8540 task_lock(task);
8541 if (task->task_ios13extended_footprint_limit) {
8542 task_unlock(task);
8543 return;
8544 }
8545 task->task_ios13extended_footprint_limit = TRUE;
8546 task_unlock(task);
8547 memorystatus_act_on_ios13extended_footprint_entitlement(get_bsdtask_info(task));
8548 }
8549 #endif /* __arm64__ */
8550
8551 static inline ledger_amount_t
task_ledger_get_balance(ledger_t ledger,int ledger_idx)8552 task_ledger_get_balance(
8553 ledger_t ledger,
8554 int ledger_idx)
8555 {
8556 ledger_amount_t amount;
8557 amount = 0;
8558 ledger_get_balance(ledger, ledger_idx, &amount);
8559 return amount;
8560 }
8561
8562 /*
8563 * Gather the amount of memory counted in a task's footprint due to
8564 * being in a specific set of ledgers.
8565 */
8566 void
task_ledgers_footprint(ledger_t ledger,ledger_amount_t * ledger_resident,ledger_amount_t * ledger_compressed)8567 task_ledgers_footprint(
8568 ledger_t ledger,
8569 ledger_amount_t *ledger_resident,
8570 ledger_amount_t *ledger_compressed)
8571 {
8572 *ledger_resident = 0;
8573 *ledger_compressed = 0;
8574
8575 /* purgeable non-volatile memory */
8576 *ledger_resident += task_ledger_get_balance(ledger, task_ledgers.purgeable_nonvolatile);
8577 *ledger_compressed += task_ledger_get_balance(ledger, task_ledgers.purgeable_nonvolatile_compressed);
8578
8579 /* "default" tagged memory */
8580 *ledger_resident += task_ledger_get_balance(ledger, task_ledgers.tagged_footprint);
8581 *ledger_compressed += task_ledger_get_balance(ledger, task_ledgers.tagged_footprint_compressed);
8582
8583 /* "network" currently never counts in the footprint... */
8584
8585 /* "media" tagged memory */
8586 *ledger_resident += task_ledger_get_balance(ledger, task_ledgers.media_footprint);
8587 *ledger_compressed += task_ledger_get_balance(ledger, task_ledgers.media_footprint_compressed);
8588
8589 /* "graphics" tagged memory */
8590 *ledger_resident += task_ledger_get_balance(ledger, task_ledgers.graphics_footprint);
8591 *ledger_compressed += task_ledger_get_balance(ledger, task_ledgers.graphics_footprint_compressed);
8592
8593 /* "neural" tagged memory */
8594 *ledger_resident += task_ledger_get_balance(ledger, task_ledgers.neural_footprint);
8595 *ledger_compressed += task_ledger_get_balance(ledger, task_ledgers.neural_footprint_compressed);
8596 }
8597
8598 #if CONFIG_MEMORYSTATUS
8599 /*
8600 * Credit any outstanding task dirty time to the ledger.
8601 * memstat_dirty_start is pushed forward to prevent any possibility of double
8602 * counting, making it safe to call this as often as necessary to ensure that
8603 * anyone reading the ledger gets up-to-date information.
8604 */
8605 void
task_ledger_settle_dirty_time(task_t t)8606 task_ledger_settle_dirty_time(task_t t)
8607 {
8608 task_lock(t);
8609
8610 uint64_t start = t->memstat_dirty_start;
8611 if (start) {
8612 uint64_t now = mach_absolute_time();
8613
8614 uint64_t duration;
8615 absolutetime_to_nanoseconds(now - start, &duration);
8616
8617 ledger_t ledger = get_task_ledger(t);
8618 ledger_credit(ledger, task_ledgers.memorystatus_dirty_time, duration);
8619
8620 t->memstat_dirty_start = now;
8621 }
8622
8623 task_unlock(t);
8624 }
8625 #endif /* CONFIG_MEMORYSTATUS */
8626
8627 void
task_set_memory_ownership_transfer(task_t task,boolean_t value)8628 task_set_memory_ownership_transfer(
8629 task_t task,
8630 boolean_t value)
8631 {
8632 task_lock(task);
8633 task->task_can_transfer_memory_ownership = !!value;
8634 task_unlock(task);
8635 }
8636
8637 #if DEVELOPMENT || DEBUG
8638
8639 void
task_set_no_footprint_for_debug(task_t task,boolean_t value)8640 task_set_no_footprint_for_debug(task_t task, boolean_t value)
8641 {
8642 task_lock(task);
8643 task->task_no_footprint_for_debug = !!value;
8644 task_unlock(task);
8645 }
8646
8647 int
task_get_no_footprint_for_debug(task_t task)8648 task_get_no_footprint_for_debug(task_t task)
8649 {
8650 return task->task_no_footprint_for_debug;
8651 }
8652
8653 #endif /* DEVELOPMENT || DEBUG */
8654
8655 void
task_copy_vmobjects(task_t task,vm_object_query_t query,size_t len,size_t * num)8656 task_copy_vmobjects(task_t task, vm_object_query_t query, size_t len, size_t *num)
8657 {
8658 vm_object_t find_vmo;
8659 size_t size = 0;
8660
8661 task_objq_lock(task);
8662 if (query != NULL) {
8663 queue_iterate(&task->task_objq, find_vmo, vm_object_t, task_objq)
8664 {
8665 vm_object_query_t p = &query[size++];
8666
8667 /* make sure to not overrun */
8668 if (size * sizeof(vm_object_query_data_t) > len) {
8669 --size;
8670 break;
8671 }
8672
8673 bzero(p, sizeof(*p));
8674 p->object_id = (vm_object_id_t) VM_KERNEL_ADDRPERM(find_vmo);
8675 p->virtual_size = find_vmo->internal ? find_vmo->vo_size : 0;
8676 p->resident_size = find_vmo->resident_page_count * PAGE_SIZE;
8677 p->wired_size = find_vmo->wired_page_count * PAGE_SIZE;
8678 p->reusable_size = find_vmo->reusable_page_count * PAGE_SIZE;
8679 p->vo_no_footprint = find_vmo->vo_no_footprint;
8680 p->vo_ledger_tag = find_vmo->vo_ledger_tag;
8681 p->purgable = find_vmo->purgable;
8682
8683 if (find_vmo->internal && find_vmo->pager_created && find_vmo->pager != NULL) {
8684 p->compressed_size = vm_compressor_pager_get_count(find_vmo->pager) * PAGE_SIZE;
8685 } else {
8686 p->compressed_size = 0;
8687 }
8688 }
8689 } else {
8690 size = (size_t)task->task_owned_objects;
8691 }
8692 task_objq_unlock(task);
8693
8694 *num = size;
8695 }
8696
8697 void
task_get_owned_vmobjects(task_t task,size_t buffer_size,vmobject_list_output_t buffer,size_t * output_size,size_t * entries)8698 task_get_owned_vmobjects(task_t task, size_t buffer_size, vmobject_list_output_t buffer, size_t* output_size, size_t* entries)
8699 {
8700 assert(output_size);
8701 assert(entries);
8702
8703 /* copy the vmobjects and vmobject data out of the task */
8704 if (buffer_size == 0) {
8705 task_copy_vmobjects(task, NULL, 0, entries);
8706 *output_size = (*entries > 0) ? *entries * sizeof(vm_object_query_data_t) + sizeof(*buffer) : 0;
8707 } else {
8708 assert(buffer);
8709 task_copy_vmobjects(task, &buffer->data[0], buffer_size - sizeof(*buffer), entries);
8710 buffer->entries = (uint64_t)*entries;
8711 *output_size = *entries * sizeof(vm_object_query_data_t) + sizeof(*buffer);
8712 }
8713 }
8714
8715 void
task_store_owned_vmobject_info(task_t to_task,task_t from_task)8716 task_store_owned_vmobject_info(task_t to_task, task_t from_task)
8717 {
8718 size_t buffer_size;
8719 vmobject_list_output_t buffer;
8720 size_t output_size;
8721 size_t entries;
8722
8723 assert(to_task != from_task);
8724
8725 /* get the size, allocate a bufferr, and populate */
8726 entries = 0;
8727 output_size = 0;
8728 task_get_owned_vmobjects(from_task, 0, NULL, &output_size, &entries);
8729
8730 if (output_size) {
8731 buffer_size = output_size;
8732 buffer = kalloc_data(buffer_size, Z_WAITOK);
8733
8734 if (buffer) {
8735 entries = 0;
8736 output_size = 0;
8737
8738 task_get_owned_vmobjects(from_task, buffer_size, buffer, &output_size, &entries);
8739
8740 if (entries) {
8741 to_task->corpse_vmobject_list = buffer;
8742 to_task->corpse_vmobject_list_size = buffer_size;
8743 }
8744 }
8745 }
8746 }
8747
8748 void
task_set_filter_msg_flag(task_t task,boolean_t flag)8749 task_set_filter_msg_flag(
8750 task_t task,
8751 boolean_t flag)
8752 {
8753 assert(task != TASK_NULL);
8754
8755 if (flag) {
8756 task_ro_flags_set(task, TFRO_FILTER_MSG);
8757 } else {
8758 task_ro_flags_clear(task, TFRO_FILTER_MSG);
8759 }
8760 }
8761
8762 boolean_t
task_get_filter_msg_flag(task_t task)8763 task_get_filter_msg_flag(
8764 task_t task)
8765 {
8766 if (!task) {
8767 return false;
8768 }
8769
8770 return (task_ro_flags_get(task) & TFRO_FILTER_MSG) ? TRUE : FALSE;
8771 }
8772 bool
task_is_exotic(task_t task)8773 task_is_exotic(
8774 task_t task)
8775 {
8776 if (task == TASK_NULL) {
8777 return false;
8778 }
8779 return vm_map_is_exotic(get_task_map(task));
8780 }
8781
8782 bool
task_is_alien(task_t task)8783 task_is_alien(
8784 task_t task)
8785 {
8786 if (task == TASK_NULL) {
8787 return false;
8788 }
8789 return vm_map_is_alien(get_task_map(task));
8790 }
8791
8792
8793
8794 #if CONFIG_MACF
8795 /* Set the filter mask for Mach traps. */
8796 void
mac_task_set_mach_filter_mask(task_t task,uint8_t * maskptr)8797 mac_task_set_mach_filter_mask(task_t task, uint8_t *maskptr)
8798 {
8799 assert(task);
8800
8801 task_set_mach_trap_filter_mask(task, maskptr);
8802 }
8803
8804 /* Set the filter mask for kobject msgs. */
8805 void
mac_task_set_kobj_filter_mask(task_t task,uint8_t * maskptr)8806 mac_task_set_kobj_filter_mask(task_t task, uint8_t *maskptr)
8807 {
8808 assert(task);
8809
8810 task_set_mach_kobj_filter_mask(task, maskptr);
8811 }
8812
8813 /* Hook for mach trap/sc filter evaluation policy. */
8814 mac_task_mach_filter_cbfunc_t mac_task_mach_trap_evaluate = NULL;
8815
8816 /* Hook for kobj message filter evaluation policy. */
8817 mac_task_kobj_filter_cbfunc_t mac_task_kobj_msg_evaluate = NULL;
8818
8819 /* Set the callback hooks for the filtering policy. */
8820 int
mac_task_register_filter_callbacks(const mac_task_mach_filter_cbfunc_t mach_cbfunc,const mac_task_kobj_filter_cbfunc_t kobj_cbfunc)8821 mac_task_register_filter_callbacks(
8822 const mac_task_mach_filter_cbfunc_t mach_cbfunc,
8823 const mac_task_kobj_filter_cbfunc_t kobj_cbfunc)
8824 {
8825 if (mach_cbfunc != NULL) {
8826 if (mac_task_mach_trap_evaluate != NULL) {
8827 return KERN_FAILURE;
8828 }
8829 mac_task_mach_trap_evaluate = mach_cbfunc;
8830 }
8831 if (kobj_cbfunc != NULL) {
8832 if (mac_task_kobj_msg_evaluate != NULL) {
8833 return KERN_FAILURE;
8834 }
8835 mac_task_kobj_msg_evaluate = kobj_cbfunc;
8836 }
8837
8838 return KERN_SUCCESS;
8839 }
8840 #endif /* CONFIG_MACF */
8841
8842 void
task_transfer_mach_filter_bits(task_t new_task,task_t old_task)8843 task_transfer_mach_filter_bits(
8844 task_t new_task,
8845 task_t old_task)
8846 {
8847 #ifdef CONFIG_MACF
8848 /* Copy mach trap and kernel object mask pointers to new task. */
8849 task_copy_filter_masks(new_task, old_task);
8850 #endif
8851 /* If filter message flag is set then set it in the new task. */
8852 if (task_get_filter_msg_flag(old_task)) {
8853 task_ro_flags_set(new_task, TFRO_FILTER_MSG);
8854 }
8855 }
8856
8857 #if CONFIG_ROSETTA
8858 bool
task_is_translated(task_t task)8859 task_is_translated(task_t task)
8860 {
8861 extern boolean_t proc_is_translated(struct proc* p);
8862 return task && proc_is_translated(get_bsdtask_info(task));
8863 }
8864 #endif
8865
8866
8867 #if __has_feature(ptrauth_calls)
8868 /* All pac violations will be delivered as fatal exceptions irrespective of
8869 * the enable_pac_exception boot-arg value.
8870 */
8871 #define PAC_EXCEPTION_ENTITLEMENT "com.apple.private.pac.exception"
8872 /*
8873 * When enable_pac_exception boot-arg is set to true, processes
8874 * can choose to get non-fatal pac exception delivery by setting
8875 * this entitlement.
8876 */
8877 #define SKIP_PAC_EXCEPTION_ENTITLEMENT "com.apple.private.skip.pac.exception"
8878
8879 void
task_set_pac_exception_fatal_flag(task_t task)8880 task_set_pac_exception_fatal_flag(
8881 task_t task)
8882 {
8883 assert(task != TASK_NULL);
8884 bool pac_entitlement = false;
8885 uint32_t set_flags = 0;
8886
8887 if (enable_pac_exception && IOTaskHasEntitlement(task, SKIP_PAC_EXCEPTION_ENTITLEMENT)) {
8888 return;
8889 }
8890
8891 if (IOTaskHasEntitlement(task, PAC_EXCEPTION_ENTITLEMENT)) {
8892 pac_entitlement = true;
8893 }
8894
8895 if (pac_entitlement) {
8896 set_flags |= TFRO_PAC_ENFORCE_USER_STATE;
8897 }
8898 if (pac_entitlement || (enable_pac_exception && task_get_platform_binary(task))) {
8899 set_flags |= TFRO_PAC_EXC_FATAL;
8900 }
8901 if (set_flags != 0) {
8902 task_ro_flags_set(task, set_flags);
8903 }
8904 }
8905
8906 bool
task_is_pac_exception_fatal(task_t task)8907 task_is_pac_exception_fatal(
8908 task_t task)
8909 {
8910 assert(task != TASK_NULL);
8911 return !!(task_ro_flags_get(task) & TFRO_PAC_EXC_FATAL);
8912 }
8913 #endif /* __has_feature(ptrauth_calls) */
8914
8915 bool
task_needs_user_signed_thread_state(task_t task)8916 task_needs_user_signed_thread_state(
8917 task_t task)
8918 {
8919 assert(task != TASK_NULL);
8920 return !!(task_ro_flags_get(task) & TFRO_PAC_ENFORCE_USER_STATE);
8921 }
8922
8923 void
task_set_tecs(task_t task)8924 task_set_tecs(task_t task)
8925 {
8926 if (task == TASK_NULL) {
8927 task = current_task();
8928 }
8929
8930 if (!machine_csv(CPUVN_CI)) {
8931 return;
8932 }
8933
8934 LCK_MTX_ASSERT(&task->lock, LCK_MTX_ASSERT_NOTOWNED);
8935
8936 task_lock(task);
8937
8938 task->t_flags |= TF_TECS;
8939
8940 thread_t thread;
8941 queue_iterate(&task->threads, thread, thread_t, task_threads) {
8942 machine_tecs(thread);
8943 }
8944 task_unlock(task);
8945 }
8946
8947 kern_return_t
task_test_sync_upcall(task_t task,ipc_port_t send_port)8948 task_test_sync_upcall(
8949 task_t task,
8950 ipc_port_t send_port)
8951 {
8952 #if DEVELOPMENT || DEBUG
8953 if (task != current_task() || !IPC_PORT_VALID(send_port)) {
8954 return KERN_INVALID_ARGUMENT;
8955 }
8956
8957 /* Block on sync kernel upcall on the given send port */
8958 mach_test_sync_upcall(send_port);
8959
8960 ipc_port_release_send(send_port);
8961 return KERN_SUCCESS;
8962 #else
8963 (void)task;
8964 (void)send_port;
8965 return KERN_NOT_SUPPORTED;
8966 #endif
8967 }
8968
8969 kern_return_t
task_test_async_upcall_propagation(task_t task,ipc_port_t send_port,int qos,int iotier)8970 task_test_async_upcall_propagation(
8971 task_t task,
8972 ipc_port_t send_port,
8973 int qos,
8974 int iotier)
8975 {
8976 #if DEVELOPMENT || DEBUG
8977 kern_return_t kr;
8978
8979 if (task != current_task() || !IPC_PORT_VALID(send_port)) {
8980 return KERN_INVALID_ARGUMENT;
8981 }
8982
8983 if (qos < THREAD_QOS_DEFAULT || qos > THREAD_QOS_USER_INTERACTIVE ||
8984 iotier < THROTTLE_LEVEL_START || iotier > THROTTLE_LEVEL_END) {
8985 return KERN_INVALID_ARGUMENT;
8986 }
8987
8988 struct thread_attr_for_ipc_propagation attr = {
8989 .tafip_iotier = iotier,
8990 .tafip_qos = qos
8991 };
8992
8993 /* Apply propagate attr to port */
8994 kr = ipc_port_propagate_thread_attr(send_port, attr);
8995 if (kr != KERN_SUCCESS) {
8996 return kr;
8997 }
8998
8999 thread_enable_send_importance(current_thread(), TRUE);
9000
9001 /* Perform an async kernel upcall on the given send port */
9002 mach_test_async_upcall(send_port);
9003 thread_enable_send_importance(current_thread(), FALSE);
9004
9005 ipc_port_release_send(send_port);
9006 return KERN_SUCCESS;
9007 #else
9008 (void)task;
9009 (void)send_port;
9010 (void)qos;
9011 (void)iotier;
9012 return KERN_NOT_SUPPORTED;
9013 #endif
9014 }
9015
9016 #if CONFIG_PROC_RESOURCE_LIMITS
9017 mach_port_name_t
current_task_get_fatal_port_name(void)9018 current_task_get_fatal_port_name(void)
9019 {
9020 mach_port_t task_fatal_port = MACH_PORT_NULL;
9021 mach_port_name_t port_name = 0;
9022
9023 task_fatal_port = task_allocate_fatal_port();
9024
9025 if (task_fatal_port) {
9026 ipc_object_copyout(current_space(), ip_to_object(task_fatal_port), MACH_MSG_TYPE_PORT_SEND,
9027 IPC_OBJECT_COPYOUT_FLAGS_NONE, NULL, NULL, &port_name);
9028 }
9029
9030 return port_name;
9031 }
9032 #endif /* CONFIG_PROC_RESOURCE_LIMITS */
9033
9034 #if defined(__x86_64__)
9035 bool
curtask_get_insn_copy_optout(void)9036 curtask_get_insn_copy_optout(void)
9037 {
9038 bool optout;
9039 task_t cur_task = current_task();
9040
9041 task_lock(cur_task);
9042 optout = (cur_task->t_flags & TF_INSN_COPY_OPTOUT) ? true : false;
9043 task_unlock(cur_task);
9044
9045 return optout;
9046 }
9047
9048 void
curtask_set_insn_copy_optout(void)9049 curtask_set_insn_copy_optout(void)
9050 {
9051 task_t cur_task = current_task();
9052
9053 task_lock(cur_task);
9054
9055 cur_task->t_flags |= TF_INSN_COPY_OPTOUT;
9056
9057 thread_t thread;
9058 queue_iterate(&cur_task->threads, thread, thread_t, task_threads) {
9059 machine_thread_set_insn_copy_optout(thread);
9060 }
9061 task_unlock(cur_task);
9062 }
9063 #endif /* defined(__x86_64__) */
9064
9065 void
task_get_corpse_vmobject_list(task_t task,vmobject_list_output_t * list,size_t * list_size)9066 task_get_corpse_vmobject_list(task_t task, vmobject_list_output_t* list, size_t* list_size)
9067 {
9068 assert(task);
9069 assert(list_size);
9070
9071 *list = task->corpse_vmobject_list;
9072 *list_size = (size_t)task->corpse_vmobject_list_size;
9073 }
9074
9075 __abortlike
9076 static void
panic_proc_ro_task_backref_mismatch(task_t t,proc_ro_t ro)9077 panic_proc_ro_task_backref_mismatch(task_t t, proc_ro_t ro)
9078 {
9079 panic("proc_ro->task backref mismatch: t=%p, ro=%p, "
9080 "proc_ro_task(ro)=%p", t, ro, proc_ro_task(ro));
9081 }
9082
9083 proc_ro_t
task_get_ro(task_t t)9084 task_get_ro(task_t t)
9085 {
9086 proc_ro_t ro = (proc_ro_t)t->bsd_info_ro;
9087
9088 zone_require_ro(ZONE_ID_PROC_RO, sizeof(struct proc_ro), ro);
9089 if (__improbable(proc_ro_task(ro) != t)) {
9090 panic_proc_ro_task_backref_mismatch(t, ro);
9091 }
9092
9093 return ro;
9094 }
9095
9096 uint32_t
task_ro_flags_get(task_t task)9097 task_ro_flags_get(task_t task)
9098 {
9099 return task_get_ro(task)->t_flags_ro;
9100 }
9101
9102 void
task_ro_flags_set(task_t task,uint32_t flags)9103 task_ro_flags_set(task_t task, uint32_t flags)
9104 {
9105 zalloc_ro_update_field_atomic(ZONE_ID_PROC_RO, task_get_ro(task),
9106 t_flags_ro, ZRO_ATOMIC_OR_32, flags);
9107 }
9108
9109 void
task_ro_flags_clear(task_t task,uint32_t flags)9110 task_ro_flags_clear(task_t task, uint32_t flags)
9111 {
9112 zalloc_ro_update_field_atomic(ZONE_ID_PROC_RO, task_get_ro(task),
9113 t_flags_ro, ZRO_ATOMIC_AND_32, ~flags);
9114 }
9115
9116 task_control_port_options_t
task_get_control_port_options(task_t task)9117 task_get_control_port_options(task_t task)
9118 {
9119 return task_get_ro(task)->task_control_port_options;
9120 }
9121
9122 void
task_set_control_port_options(task_t task,task_control_port_options_t opts)9123 task_set_control_port_options(task_t task, task_control_port_options_t opts)
9124 {
9125 zalloc_ro_update_field(ZONE_ID_PROC_RO, task_get_ro(task),
9126 task_control_port_options, &opts);
9127 }
9128
9129 /*!
9130 * @function kdp_task_is_locked
9131 *
9132 * @abstract
9133 * Checks if task is locked.
9134 *
9135 * @discussion
9136 * NOT SAFE: To be used only by kernel debugger.
9137 *
9138 * @param task task to check
9139 *
9140 * @returns TRUE if the task is locked.
9141 */
9142 boolean_t
kdp_task_is_locked(task_t task)9143 kdp_task_is_locked(task_t task)
9144 {
9145 return kdp_lck_mtx_lock_spin_is_acquired(&task->lock);
9146 }
9147