xref: /xnu-8020.121.3/libsyscall/wrappers/libproc/libproc.c (revision fdd8201d7b966f0c3ea610489d29bd841d358941)
1 /*
2  * Copyright (c) 2006-2018 Apple Inc. All rights reserved.
3  *
4  * @APPLE_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. Please obtain a copy of the License at
10  * http://www.opensource.apple.com/apsl/ and read it before using this
11  * file.
12  *
13  * The Original Code and all software distributed under the License are
14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18  * Please see the License for the specific language governing rights and
19  * limitations under the License.
20  *
21  * @APPLE_LICENSE_HEADER_END@
22  */
23 
24 #include <sys/cdefs.h>
25 #include <unistd.h>
26 #include <errno.h>
27 #include <string.h>
28 #include <strings.h>
29 #include <stdlib.h>
30 #include <sys/errno.h>
31 #include <sys/msgbuf.h>
32 #include <sys/resource.h>
33 #include <sys/process_policy.h>
34 #include <sys/event.h>
35 #include <mach/message.h>
36 
37 #include "libproc_internal.h"
38 
39 int __proc_info(int callnum, int pid, int flavor, uint64_t arg, void * buffer, int buffersize);
40 int __proc_info_extended_id(int32_t callnum, int32_t pid, uint32_t flavor, uint32_t flags, uint64_t ext_id, uint64_t arg, user_addr_t buffer, int32_t buffersize);
41 __private_extern__ int proc_setthreadname(void * buffer, int buffersize);
42 int __process_policy(int scope, int action, int policy, int policy_subtype, proc_policy_attribute_t * attrp, pid_t target_pid, uint64_t target_threadid);
43 int proc_rlimit_control(pid_t pid, int flavor, void *arg);
44 
45 int
proc_listpids(uint32_t type,uint32_t typeinfo,void * buffer,int buffersize)46 proc_listpids(uint32_t type, uint32_t typeinfo, void *buffer, int buffersize)
47 {
48 	int retval;
49 
50 	if ((type >= PROC_ALL_PIDS) || (type <= PROC_PPID_ONLY)) {
51 		if ((retval = __proc_info(PROC_INFO_CALL_LISTPIDS, type, typeinfo, (uint64_t)0, buffer, buffersize)) == -1) {
52 			return 0;
53 		}
54 	} else {
55 		errno = EINVAL;
56 		retval = 0;
57 	}
58 	return retval;
59 }
60 
61 
62 int
proc_listallpids(void * buffer,int buffersize)63 proc_listallpids(void * buffer, int buffersize)
64 {
65 	int numpids;
66 	numpids = proc_listpids(PROC_ALL_PIDS, (uint32_t)0, buffer, buffersize);
67 
68 	if (numpids == -1) {
69 		return -1;
70 	} else {
71 		return numpids / sizeof(int);
72 	}
73 }
74 
75 int
proc_listpgrppids(pid_t pgrpid,void * buffer,int buffersize)76 proc_listpgrppids(pid_t pgrpid, void * buffer, int buffersize)
77 {
78 	int numpids;
79 	numpids = proc_listpids(PROC_PGRP_ONLY, (uint32_t)pgrpid, buffer, buffersize);
80 	if (numpids == -1) {
81 		return -1;
82 	} else {
83 		return numpids / sizeof(int);
84 	}
85 }
86 
87 int
proc_listchildpids(pid_t ppid,void * buffer,int buffersize)88 proc_listchildpids(pid_t ppid, void * buffer, int buffersize)
89 {
90 	int numpids;
91 	numpids = proc_listpids(PROC_PPID_ONLY, (uint32_t)ppid, buffer, buffersize);
92 	if (numpids == -1) {
93 		return -1;
94 	} else {
95 		return numpids / sizeof(int);
96 	}
97 }
98 
99 
100 int
proc_pidinfo(int pid,int flavor,uint64_t arg,void * buffer,int buffersize)101 proc_pidinfo(int pid, int flavor, uint64_t arg, void *buffer, int buffersize)
102 {
103 	int retval;
104 
105 	if ((retval = __proc_info(PROC_INFO_CALL_PIDINFO, pid, flavor, arg, buffer, buffersize)) == -1) {
106 		return 0;
107 	}
108 
109 	return retval;
110 }
111 
112 
113 int
proc_pidoriginatorinfo(int flavor,void * buffer,int buffersize)114 proc_pidoriginatorinfo(int flavor, void *buffer, int buffersize)
115 {
116 	int retval;
117 
118 	if ((retval = __proc_info(PROC_INFO_CALL_PIDORIGINATORINFO, getpid(), flavor, 0, buffer, buffersize)) == -1) {
119 		return 0;
120 	}
121 
122 	return retval;
123 }
124 
125 int
proc_listcoalitions(int flavor,int coaltype,void * buffer,int buffersize)126 proc_listcoalitions(int flavor, int coaltype, void *buffer, int buffersize)
127 {
128 	int retval;
129 
130 	if ((retval = __proc_info(PROC_INFO_CALL_LISTCOALITIONS, flavor, coaltype, 0, buffer, buffersize)) == -1) {
131 		return 0;
132 	}
133 
134 	return retval;
135 }
136 
137 int
proc_pid_rusage(int pid,int flavor,rusage_info_t * buffer)138 proc_pid_rusage(int pid, int flavor, rusage_info_t *buffer)
139 {
140 	return __proc_info(PROC_INFO_CALL_PIDRUSAGE, pid, flavor, 0, buffer, 0);
141 }
142 
143 int
proc_setthread_cpupercent(uint8_t percentage,uint32_t ms_refill)144 proc_setthread_cpupercent(uint8_t percentage, uint32_t ms_refill)
145 {
146 	uint32_t arg = 0;
147 
148 	/* Pack percentage and refill into a 32-bit number to match existing kernel implementation */
149 	if ((percentage >= 100) || (ms_refill & ~0xffffffU)) {
150 		errno = EINVAL;
151 		return -1;
152 	}
153 
154 	arg = ((ms_refill << 8) | percentage);
155 
156 	return proc_rlimit_control(-1, RLIMIT_THREAD_CPULIMITS, (void *)(uintptr_t)arg);
157 }
158 
159 int
proc_pidfdinfo(int pid,int fd,int flavor,void * buffer,int buffersize)160 proc_pidfdinfo(int pid, int fd, int flavor, void * buffer, int buffersize)
161 {
162 	int retval;
163 
164 	if ((retval = __proc_info(PROC_INFO_CALL_PIDFDINFO, pid, flavor, (uint64_t)fd, buffer, buffersize)) == -1) {
165 		return 0;
166 	}
167 
168 	return retval;
169 }
170 
171 
172 int
proc_pidfileportinfo(int pid,uint32_t fileport,int flavor,void * buffer,int buffersize)173 proc_pidfileportinfo(int pid, uint32_t fileport, int flavor, void *buffer, int buffersize)
174 {
175 	int retval;
176 
177 	if ((retval = __proc_info(PROC_INFO_CALL_PIDFILEPORTINFO, pid, flavor, (uint64_t)fileport, buffer, buffersize)) == -1) {
178 		return 0;
179 	}
180 	return retval;
181 }
182 
183 int
proc_piddynkqueueinfo(int pid,int flavor,kqueue_id_t kq_id,void * buffer,int buffersize)184 proc_piddynkqueueinfo(int pid, int flavor, kqueue_id_t kq_id, void *buffer, int buffersize)
185 {
186 	int ret;
187 
188 	if ((ret = __proc_info(PROC_INFO_CALL_PIDDYNKQUEUEINFO, pid, flavor, (uint64_t)kq_id, buffer, buffersize)) == -1) {
189 		return 0;
190 	}
191 
192 	return ret;
193 }
194 
195 int
proc_udata_info(int pid,int flavor,void * buffer,int buffersize)196 proc_udata_info(int pid, int flavor, void *buffer, int buffersize)
197 {
198 	return __proc_info(PROC_INFO_CALL_UDATA_INFO, pid, flavor, 0, buffer, buffersize);
199 }
200 
201 int
proc_name(int pid,void * buffer,uint32_t buffersize)202 proc_name(int pid, void * buffer, uint32_t buffersize)
203 {
204 	int retval = 0, len;
205 	struct proc_bsdinfo pbsd;
206 
207 
208 	if (buffersize < sizeof(pbsd.pbi_name)) {
209 		errno = ENOMEM;
210 		return 0;
211 	}
212 
213 	retval = proc_pidinfo(pid, PROC_PIDTBSDINFO, (uint64_t)0, &pbsd, sizeof(struct proc_bsdinfo));
214 	if (retval != 0) {
215 		if (pbsd.pbi_name[0]) {
216 			bcopy(&pbsd.pbi_name, buffer, sizeof(pbsd.pbi_name));
217 		} else {
218 			bcopy(&pbsd.pbi_comm, buffer, sizeof(pbsd.pbi_comm));
219 		}
220 		len = (int)strlen(buffer);
221 		return len;
222 	}
223 	return 0;
224 }
225 
226 int
proc_regionfilename(int pid,uint64_t address,void * buffer,uint32_t buffersize)227 proc_regionfilename(int pid, uint64_t address, void * buffer, uint32_t buffersize)
228 {
229 	int retval;
230 	struct proc_regionpath path;
231 
232 	if (buffersize < MAXPATHLEN) {
233 		errno = ENOMEM;
234 		return 0;
235 	}
236 
237 	retval = proc_pidinfo(pid, PROC_PIDREGIONPATH, (uint64_t)address, &path, sizeof(struct proc_regionpath));
238 	if (retval != 0) {
239 		return (int)(strlcpy(buffer, path.prpo_path, buffersize));
240 	}
241 	return 0;
242 }
243 
244 int
proc_kmsgbuf(void * buffer,uint32_t buffersize)245 proc_kmsgbuf(void * buffer, uint32_t  buffersize)
246 {
247 	int retval;
248 
249 	if ((retval = __proc_info(PROC_INFO_CALL_KERNMSGBUF, 0, 0, (uint64_t)0, buffer, buffersize)) == -1) {
250 		return 0;
251 	}
252 	return retval;
253 }
254 
255 int
proc_pidpath(int pid,void * buffer,uint32_t buffersize)256 proc_pidpath(int pid, void * buffer, uint32_t  buffersize)
257 {
258 	int retval, len;
259 
260 	if (buffersize < PROC_PIDPATHINFO_SIZE) {
261 		errno = ENOMEM;
262 		return 0;
263 	}
264 	if (buffersize > PROC_PIDPATHINFO_MAXSIZE) {
265 		errno = EOVERFLOW;
266 		return 0;
267 	}
268 
269 	retval = __proc_info(PROC_INFO_CALL_PIDINFO, pid, PROC_PIDPATHINFO, (uint64_t)0, buffer, buffersize);
270 	if (retval != -1) {
271 		len = (int)strlen(buffer);
272 		return len;
273 	}
274 	return 0;
275 }
276 
277 int
proc_pidpath_audittoken(audit_token_t * audittoken,void * buffer,uint32_t buffersize)278 proc_pidpath_audittoken(audit_token_t *audittoken, void * buffer, uint32_t buffersize)
279 {
280 	int retval, len;
281 
282 	if (buffersize < PROC_PIDPATHINFO_SIZE) {
283 		errno = ENOMEM;
284 		return 0;
285 	}
286 	if (buffersize > PROC_PIDPATHINFO_MAXSIZE) {
287 		errno = EOVERFLOW;
288 		return 0;
289 	}
290 
291 	int pid = audittoken->val[5];
292 	int idversion = audittoken->val[7];
293 
294 	retval = __proc_info_extended_id(PROC_INFO_CALL_PIDINFO, pid, PROC_PIDPATHINFO, PIF_COMPARE_IDVERSION, (uint64_t)idversion,
295 	    (uint64_t)0, buffer, buffersize);
296 	if (retval != -1) {
297 		len = (int)strlen(buffer);
298 		return len;
299 	}
300 	return 0;
301 }
302 
303 int
proc_current_thread_schedinfo(void * buffer,size_t buffersize)304 proc_current_thread_schedinfo(void *buffer, size_t buffersize)
305 {
306 	extern uint64_t __thread_selfid(void);
307 
308 	int retval;
309 
310 	if (buffersize < PROC_PIDTHREADSCHEDINFO_SIZE) {
311 		errno = ENOMEM;
312 		return errno;
313 	}
314 	if (buffersize > PROC_PIDTHREADSCHEDINFO_SIZE) {
315 		errno = EOVERFLOW;
316 		return errno;
317 	}
318 
319 	pid_t pid = getpid();
320 	uint64_t threadid = __thread_selfid();
321 
322 	retval = __proc_info(PROC_INFO_CALL_PIDINFO, pid, PROC_PIDTHREADSCHEDINFO, threadid, buffer, buffersize);
323 
324 	if (retval == -1) {
325 		return errno;
326 	}
327 	return 0;
328 }
329 
330 int
proc_libversion(int * major,int * minor)331 proc_libversion(int *major, int * minor)
332 {
333 	if (major != NULL) {
334 		*major = 1;
335 	}
336 	if (minor != NULL) {
337 		*minor = 1;
338 	}
339 	return 0;
340 }
341 
342 int
proc_setpcontrol(const int control)343 proc_setpcontrol(const int control)
344 {
345 	int retval;
346 
347 	if (control < PROC_SETPC_NONE || control > PROC_SETPC_TERMINATE) {
348 		return EINVAL;
349 	}
350 
351 	if ((retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_PCONTROL, (uint64_t)control, NULL, 0)) == -1) {
352 		return errno;
353 	}
354 
355 	return 0;
356 }
357 
358 
359 __private_extern__ int
proc_setthreadname(void * buffer,int buffersize)360 proc_setthreadname(void * buffer, int buffersize)
361 {
362 	int retval;
363 
364 	retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_THREADNAME, (uint64_t)0, buffer, buffersize);
365 
366 	if (retval == -1) {
367 		return errno;
368 	} else {
369 		return 0;
370 	}
371 }
372 
373 int
proc_track_dirty(pid_t pid,uint32_t flags)374 proc_track_dirty(pid_t pid, uint32_t flags)
375 {
376 	if (__proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_TRACK, flags, NULL, 0) == -1) {
377 		return errno;
378 	}
379 
380 	return 0;
381 }
382 
383 int
proc_set_dirty(pid_t pid,bool dirty)384 proc_set_dirty(pid_t pid, bool dirty)
385 {
386 	if (__proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_SET, dirty, NULL, 0) == -1) {
387 		return errno;
388 	}
389 
390 	return 0;
391 }
392 
393 int
proc_get_dirty(pid_t pid,uint32_t * flags)394 proc_get_dirty(pid_t pid, uint32_t *flags)
395 {
396 	int retval;
397 
398 	if (!flags) {
399 		return EINVAL;
400 	}
401 
402 	retval = __proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_GET, 0, NULL, 0);
403 	if (retval == -1) {
404 		return errno;
405 	}
406 
407 	*flags = retval;
408 
409 	return 0;
410 }
411 
412 int
proc_clear_dirty(pid_t pid,uint32_t flags)413 proc_clear_dirty(pid_t pid, uint32_t flags)
414 {
415 	if (__proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_CLEAR, flags, NULL, 0) == -1) {
416 		return errno;
417 	}
418 
419 	return 0;
420 }
421 
422 int
proc_terminate(pid_t pid,int * sig)423 proc_terminate(pid_t pid, int *sig)
424 {
425 	int retval;
426 
427 	if (!sig) {
428 		return EINVAL;
429 	}
430 
431 	retval = __proc_info(PROC_INFO_CALL_TERMINATE, pid, 0, 0, NULL, 0);
432 	if (retval == -1) {
433 		return errno;
434 	}
435 
436 	*sig = retval;
437 
438 	return 0;
439 }
440 
441 /*
442  * XXX the _fatal() variant both checks for an existing monitor
443  * (with important policy effects on first party background apps)
444  * and validates inputs.
445  */
446 int
proc_set_cpumon_params(pid_t pid,int percentage,int interval)447 proc_set_cpumon_params(pid_t pid, int percentage, int interval)
448 {
449 	proc_policy_cpuusage_attr_t attr;
450 
451 	/* no argument validation ...
452 	 * task_set_cpuusage() ignores 0 values and squashes negative
453 	 * values into uint32_t.
454 	 */
455 
456 	attr.ppattr_cpu_attr = PROC_POLICY_RSRCACT_NOTIFY_EXC;
457 	attr.ppattr_cpu_percentage = percentage;
458 	attr.ppattr_cpu_attr_interval = (uint64_t)interval;
459 	attr.ppattr_cpu_attr_deadline = 0;
460 
461 	return __process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_SET, PROC_POLICY_RESOURCE_USAGE,
462 	           PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0);
463 }
464 
465 int
proc_get_cpumon_params(pid_t pid,int * percentage,int * interval)466 proc_get_cpumon_params(pid_t pid, int *percentage, int *interval)
467 {
468 	proc_policy_cpuusage_attr_t attr;
469 	int ret;
470 
471 	ret = __process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_GET, PROC_POLICY_RESOURCE_USAGE,
472 	    PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0);
473 
474 	if ((ret == 0) && (attr.ppattr_cpu_attr == PROC_POLICY_RSRCACT_NOTIFY_EXC)) {
475 		*percentage = attr.ppattr_cpu_percentage;
476 		*interval = (int)attr.ppattr_cpu_attr_interval;
477 	} else {
478 		*percentage = 0;
479 		*interval = 0;
480 	}
481 
482 	return ret;
483 }
484 
485 int
proc_set_cpumon_defaults(pid_t pid)486 proc_set_cpumon_defaults(pid_t pid)
487 {
488 	proc_policy_cpuusage_attr_t attr;
489 
490 	attr.ppattr_cpu_attr = PROC_POLICY_RSRCACT_NOTIFY_EXC;
491 	attr.ppattr_cpu_percentage = PROC_POLICY_CPUMON_DEFAULTS;
492 	attr.ppattr_cpu_attr_interval = 0;
493 	attr.ppattr_cpu_attr_deadline = 0;
494 
495 	return __process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_SET, PROC_POLICY_RESOURCE_USAGE,
496 	           PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0);
497 }
498 
499 int
proc_resume_cpumon(pid_t pid)500 proc_resume_cpumon(pid_t pid)
501 {
502 	return __process_policy(PROC_POLICY_SCOPE_PROCESS,
503 	           PROC_POLICY_ACTION_ENABLE,
504 	           PROC_POLICY_RESOURCE_USAGE,
505 	           PROC_POLICY_RUSAGE_CPU,
506 	           NULL, pid, 0);
507 }
508 
509 int
proc_disable_cpumon(pid_t pid)510 proc_disable_cpumon(pid_t pid)
511 {
512 	proc_policy_cpuusage_attr_t attr;
513 
514 	attr.ppattr_cpu_attr = PROC_POLICY_RSRCACT_NOTIFY_EXC;
515 	attr.ppattr_cpu_percentage = PROC_POLICY_CPUMON_DISABLE;
516 	attr.ppattr_cpu_attr_interval = 0;
517 	attr.ppattr_cpu_attr_deadline = 0;
518 
519 	return __process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_SET, PROC_POLICY_RESOURCE_USAGE,
520 	           PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0);
521 }
522 
523 
524 /*
525  * Turn on the CPU usage monitor using the supplied parameters, and make
526  * violations of the monitor fatal.
527  *
528  * Returns:  0 on success;
529  *	    -1 on failure and sets errno
530  */
531 int
proc_set_cpumon_params_fatal(pid_t pid,int percentage,int interval)532 proc_set_cpumon_params_fatal(pid_t pid, int percentage, int interval)
533 {
534 	int current_percentage = 0;
535 	int current_interval = 0;   /* intervals are in seconds */
536 	int ret = 0;
537 
538 	if ((percentage <= 0) || (interval <= 0)) {
539 		errno = EINVAL;
540 		return -1;
541 	}
542 
543 	/*
544 	 * Do a simple query to see if CPU monitoring is
545 	 * already active.  If either the percentage or the
546 	 * interval is nonzero, then CPU monitoring is
547 	 * already in use for this process.
548 	 *
549 	 * XXX: need set...() and set..fatal() to behave similarly.
550 	 * Currently, this check prevents 1st party apps (which get a
551 	 * default non-fatal monitor) not to get a fatal monitor.
552 	 */
553 	(void)proc_get_cpumon_params(pid, &current_percentage, &current_interval);
554 	if (current_percentage || current_interval) {
555 		/*
556 		 * The CPU monitor appears to be active.
557 		 * We choose not to disturb those settings.
558 		 */
559 		errno = EBUSY;
560 		return -1;
561 	}
562 
563 	if ((ret = proc_set_cpumon_params(pid, percentage, interval)) != 0) {
564 		/* Failed to activate the CPU monitor */
565 		return ret;
566 	}
567 
568 	if ((ret = proc_rlimit_control(pid, RLIMIT_CPU_USAGE_MONITOR, (void *)(uintptr_t)CPUMON_MAKE_FATAL)) != 0) {
569 		/* Failed to set termination, back out the CPU monitor settings. */
570 		(void)proc_disable_cpumon(pid);
571 	}
572 
573 	return ret;
574 }
575 
576 int
proc_set_wakemon_params(pid_t pid,int rate_hz,int flags __unused)577 proc_set_wakemon_params(pid_t pid, int rate_hz, int flags __unused)
578 {
579 	struct proc_rlimit_control_wakeupmon params;
580 
581 	params.wm_flags = WAKEMON_ENABLE;
582 	params.wm_rate = rate_hz;
583 
584 	return proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, &params);
585 }
586 
587 #ifndef WAKEMON_GET_PARAMS
588 #define WAKEMON_GET_PARAMS 0x4
589 #define WAKEMON_SET_DEFAULTS 0x8
590 #endif
591 
592 int
proc_get_wakemon_params(pid_t pid,int * rate_hz,int * flags)593 proc_get_wakemon_params(pid_t pid, int *rate_hz, int *flags)
594 {
595 	struct proc_rlimit_control_wakeupmon params;
596 	int error;
597 
598 	params.wm_flags = WAKEMON_GET_PARAMS;
599 
600 	if ((error = proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, &params)) != 0) {
601 		return error;
602 	}
603 
604 	*rate_hz = params.wm_rate;
605 	*flags = params.wm_flags;
606 
607 	return 0;
608 }
609 
610 int
proc_set_wakemon_defaults(pid_t pid)611 proc_set_wakemon_defaults(pid_t pid)
612 {
613 	struct proc_rlimit_control_wakeupmon params;
614 
615 	params.wm_flags = WAKEMON_ENABLE | WAKEMON_SET_DEFAULTS;
616 	params.wm_rate = -1;
617 
618 	return proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, &params);
619 }
620 
621 int
proc_disable_wakemon(pid_t pid)622 proc_disable_wakemon(pid_t pid)
623 {
624 	struct proc_rlimit_control_wakeupmon params;
625 
626 	params.wm_flags = WAKEMON_DISABLE;
627 	params.wm_rate = -1;
628 
629 	return proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, &params);
630 }
631 
632 int
proc_list_uptrs(int pid,uint64_t * buf,uint32_t bufsz)633 proc_list_uptrs(int pid, uint64_t *buf, uint32_t bufsz)
634 {
635 	return __proc_info(PROC_INFO_CALL_PIDINFO, pid, PROC_PIDLISTUPTRS, 0,
636 	           buf, bufsz);
637 }
638 
639 int
proc_list_dynkqueueids(int pid,kqueue_id_t * buf,uint32_t bufsz)640 proc_list_dynkqueueids(int pid, kqueue_id_t *buf, uint32_t bufsz)
641 {
642 	return __proc_info(PROC_INFO_CALL_PIDINFO, pid, PROC_PIDLISTDYNKQUEUES, 0,
643 	           buf, bufsz);
644 }
645 
646 
647 int
proc_setcpu_percentage(pid_t pid,int action,int percentage)648 proc_setcpu_percentage(pid_t pid, int action, int percentage)
649 {
650 	proc_policy_cpuusage_attr_t attr;
651 
652 	bzero(&attr, sizeof(proc_policy_cpuusage_attr_t));
653 	attr.ppattr_cpu_attr = action;
654 	attr.ppattr_cpu_percentage = percentage;
655 	if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_APPLY, PROC_POLICY_RESOURCE_USAGE, PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, (uint64_t)0) != -1) {
656 		return 0;
657 	} else {
658 		return errno;
659 	}
660 }
661 
662 int
proc_reset_footprint_interval(pid_t pid)663 proc_reset_footprint_interval(pid_t pid)
664 {
665 	return proc_rlimit_control(pid, RLIMIT_FOOTPRINT_INTERVAL, (void *)(uintptr_t)FOOTPRINT_INTERVAL_RESET);
666 }
667 
668 int
proc_clear_cpulimits(pid_t pid)669 proc_clear_cpulimits(pid_t pid)
670 {
671 	if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_RESTORE, PROC_POLICY_RESOURCE_USAGE, PROC_POLICY_RUSAGE_CPU, NULL, pid, (uint64_t)0) != -1) {
672 		return 0;
673 	} else {
674 		return errno;
675 	}
676 }
677 
678 #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
679 
680 int
proc_setcpu_deadline(pid_t pid,int action,uint64_t deadline)681 proc_setcpu_deadline(pid_t pid, int action, uint64_t deadline)
682 {
683 	proc_policy_cpuusage_attr_t attr;
684 
685 	bzero(&attr, sizeof(proc_policy_cpuusage_attr_t));
686 	attr.ppattr_cpu_attr = action;
687 	attr.ppattr_cpu_attr_deadline = deadline;
688 	if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_APPLY, PROC_POLICY_RESOURCE_USAGE, PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, (uint64_t)0) != -1) {
689 		return 0;
690 	} else {
691 		return errno;
692 	}
693 }
694 
695 int
proc_setcpu_percentage_withdeadline(pid_t pid,int action,int percentage,uint64_t deadline)696 proc_setcpu_percentage_withdeadline(pid_t pid, int action, int percentage, uint64_t deadline)
697 {
698 	proc_policy_cpuusage_attr_t attr;
699 
700 	bzero(&attr, sizeof(proc_policy_cpuusage_attr_t));
701 	attr.ppattr_cpu_attr = action;
702 	attr.ppattr_cpu_percentage = percentage;
703 	attr.ppattr_cpu_attr_deadline = deadline;
704 	if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_APPLY, PROC_POLICY_RESOURCE_USAGE, PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, (uint64_t)0) != -1) {
705 		return 0;
706 	} else {
707 		return errno;
708 	}
709 }
710 
711 int
proc_appstate(int pid,int * appstatep)712 proc_appstate(int pid, int * appstatep)
713 {
714 	int state;
715 
716 	if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_GET, PROC_POLICY_APP_LIFECYCLE, PROC_POLICY_APPLIFE_STATE, (proc_policy_attribute_t*)&state, pid, (uint64_t)0) != -1) {
717 		if (appstatep != NULL) {
718 			*appstatep = state;
719 		}
720 		return 0;
721 	} else {
722 		return errno;
723 	}
724 }
725 
726 int
proc_setappstate(int pid,int appstate)727 proc_setappstate(int pid, int appstate)
728 {
729 	int state = appstate;
730 
731 	switch (state) {
732 	case PROC_APPSTATE_NONE:
733 	case PROC_APPSTATE_ACTIVE:
734 	case PROC_APPSTATE_INACTIVE:
735 	case PROC_APPSTATE_BACKGROUND:
736 	case PROC_APPSTATE_NONUI:
737 		break;
738 	default:
739 		return EINVAL;
740 	}
741 	if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_APPLY, PROC_POLICY_APP_LIFECYCLE, PROC_POLICY_APPLIFE_STATE, (proc_policy_attribute_t*)&state, pid, (uint64_t)0) != -1) {
742 		return 0;
743 	} else {
744 		return errno;
745 	}
746 }
747 
748 int
proc_devstatusnotify(int devicestatus)749 proc_devstatusnotify(int devicestatus)
750 {
751 	int state = devicestatus;
752 
753 	switch (devicestatus) {
754 	case PROC_DEVSTATUS_SHORTTERM:
755 	case PROC_DEVSTATUS_LONGTERM:
756 		break;
757 	default:
758 		return EINVAL;
759 	}
760 
761 	if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_APPLY, PROC_POLICY_APP_LIFECYCLE, PROC_POLICY_APPLIFE_DEVSTATUS, (proc_policy_attribute_t*)&state, getpid(), (uint64_t)0) != -1) {
762 		return 0;
763 	} else {
764 		return errno;
765 	}
766 }
767 
768 int
proc_pidbind(int pid,uint64_t threadid,int bind)769 proc_pidbind(int pid, uint64_t threadid, int bind)
770 {
771 	int state = bind;
772 	pid_t passpid = pid;
773 
774 	switch (bind) {
775 	case PROC_PIDBIND_CLEAR:
776 		passpid = getpid();             /* ignore pid on clear */
777 		break;
778 	case PROC_PIDBIND_SET:
779 		break;
780 	default:
781 		return EINVAL;
782 	}
783 	if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_APPLY, PROC_POLICY_APP_LIFECYCLE, PROC_POLICY_APPLIFE_PIDBIND, (proc_policy_attribute_t*)&state, passpid, threadid) != -1) {
784 		return 0;
785 	} else {
786 		return errno;
787 	}
788 }
789 
790 int
proc_can_use_foreground_hw(int pid,uint32_t * reason)791 proc_can_use_foreground_hw(int pid, uint32_t *reason)
792 {
793 	return __proc_info(PROC_INFO_CALL_CANUSEFGHW, pid, 0, 0, reason, sizeof(*reason));
794 }
795 #endif /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
796 
797 
798 /* Donate importance to adaptive processes from this process */
799 int
proc_donate_importance_boost()800 proc_donate_importance_boost()
801 {
802 	int rval;
803 
804 #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
805 	rval = __process_policy(PROC_POLICY_SCOPE_PROCESS,
806 	    PROC_POLICY_ACTION_ENABLE,
807 	    PROC_POLICY_APPTYPE,
808 	    PROC_POLICY_IOS_DONATEIMP,
809 	    NULL, getpid(), (uint64_t)0);
810 #else /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
811 	rval = __process_policy(PROC_POLICY_SCOPE_PROCESS,
812 	    PROC_POLICY_ACTION_SET,
813 	    PROC_POLICY_BOOST,
814 	    PROC_POLICY_IMP_DONATION,
815 	    NULL, getpid(), 0);
816 #endif /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
817 
818 	if (rval == 0) {
819 		return 0;
820 	} else {
821 		return errno;
822 	}
823 }
824 
825 static __attribute__((noinline)) void
proc_importance_bad_assertion(char * reason)826 proc_importance_bad_assertion(char *reason)
827 {
828 	(void)reason;
829 }
830 
831 /*
832  * Use the address of these variables as the token.  This way, they can be
833  * printed in the debugger as useful names.
834  */
835 uint64_t important_boost_assertion_token = 0xfafafafafafafafa;
836 uint64_t normal_boost_assertion_token    = 0xfbfbfbfbfbfbfbfb;
837 uint64_t non_boost_assertion_token       = 0xfcfcfcfcfcfcfcfc;
838 uint64_t denap_boost_assertion_token     = 0xfdfdfdfdfdfdfdfd;
839 
840 /*
841  * Accept the boost on a message, or request another boost assertion
842  * if we have already accepted the implicit boost for this message.
843  *
844  * Returns EOVERFLOW if an attempt is made to take an extra assertion when not boosted.
845  *
846  * Returns EIO if the message was not a boosting message.
847  * TODO: Return a 'non-boost' token instead.
848  */
849 int
proc_importance_assertion_begin_with_msg(mach_msg_header_t * msg,__unused mach_msg_trailer_t * trailer,uint64_t * assertion_token)850 proc_importance_assertion_begin_with_msg(mach_msg_header_t  *msg,
851     __unused mach_msg_trailer_t *trailer,
852     uint64_t           *assertion_token)
853 {
854 	int rval = 0;
855 
856 	if (assertion_token == NULL) {
857 		return EINVAL;
858 	}
859 
860 #define LEGACYBOOSTMASK (MACH_MSGH_BITS_VOUCHER_MASK | MACH_MSGH_BITS_RAISEIMP)
861 #define LEGACYBOOSTED(m) (((m)->msgh_bits & LEGACYBOOSTMASK) == MACH_MSGH_BITS_RAISEIMP)
862 
863 	/* Is this a legacy boosted message? */
864 	if (LEGACYBOOSTED(msg)) {
865 		/*
866 		 * Have we accepted the implicit boost for this message yet?
867 		 * If we haven't accepted it yet, no need to call into kernel.
868 		 */
869 		if ((msg->msgh_bits & MACH_MSGH_BITS_IMPHOLDASRT) == 0) {
870 			msg->msgh_bits |= MACH_MSGH_BITS_IMPHOLDASRT;
871 			*assertion_token = (uint64_t) &important_boost_assertion_token;
872 			return 0;
873 		}
874 
875 		/* Request an additional boost count */
876 		rval = __process_policy(PROC_POLICY_SCOPE_PROCESS,
877 		    PROC_POLICY_ACTION_HOLD,
878 		    PROC_POLICY_BOOST,
879 		    PROC_POLICY_IMP_IMPORTANT,
880 		    NULL, getpid(), 0);
881 		if (rval == 0) {
882 			*assertion_token = (uint64_t) &important_boost_assertion_token;
883 			return 0;
884 		} else if (errno == EOVERFLOW) {
885 			proc_importance_bad_assertion("Attempted to take assertion while not boosted");
886 			return errno;
887 		} else {
888 			return errno;
889 		}
890 	}
891 
892 	return EIO;
893 }
894 
895 
896 /*
897  * Drop a boost assertion.
898  * Returns EOVERFLOW on boost assertion underflow.
899  */
900 int
proc_importance_assertion_complete(uint64_t assertion_token)901 proc_importance_assertion_complete(uint64_t assertion_token)
902 {
903 	int rval = 0;
904 
905 	if (assertion_token == 0) {
906 		return 0;
907 	}
908 
909 	if (assertion_token == (uint64_t) &important_boost_assertion_token) {
910 		rval = __process_policy(PROC_POLICY_SCOPE_PROCESS,
911 		    PROC_POLICY_ACTION_DROP,
912 		    PROC_POLICY_BOOST,
913 		    PROC_POLICY_IMP_IMPORTANT,
914 		    NULL, getpid(), 0);
915 		if (rval == 0) {
916 			return 0;
917 		} else if (errno == EOVERFLOW) {
918 			proc_importance_bad_assertion("Attempted to drop too many assertions");
919 			return errno;
920 		} else {
921 			return errno;
922 		}
923 	} else {
924 		proc_importance_bad_assertion("Attempted to drop assertion with invalid token");
925 		return EIO;
926 	}
927 }
928 
929 /*
930  * Accept the De-Nap boost on a message, or request another boost assertion
931  * if we have already accepted the implicit boost for this message.
932  *
933  * Interface is deprecated before it really got started - just as synonym
934  * for proc_importance_assertion_begin_with_msg() now.
935  */
936 int
proc_denap_assertion_begin_with_msg(mach_msg_header_t * msg,uint64_t * assertion_token)937 proc_denap_assertion_begin_with_msg(mach_msg_header_t  *msg,
938     uint64_t           *assertion_token)
939 {
940 #pragma clang diagnostic push
941 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
942 	return proc_importance_assertion_begin_with_msg(msg, NULL, assertion_token);
943 #pragma clang diagnostic pop
944 }
945 
946 
947 /*
948  * Drop a denap boost assertion.
949  *
950  * Interface is deprecated before it really got started - just a synonym
951  * for proc_importance_assertion_complete() now.
952  */
953 int
proc_denap_assertion_complete(uint64_t assertion_token)954 proc_denap_assertion_complete(uint64_t assertion_token)
955 {
956 	return proc_importance_assertion_complete(assertion_token);
957 }
958 
959 #if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
960 
961 int
proc_clear_vmpressure(pid_t pid)962 proc_clear_vmpressure(pid_t pid)
963 {
964 	if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_RESTORE, PROC_POLICY_RESOURCE_STARVATION, PROC_POLICY_RS_VIRTUALMEM, NULL, pid, (uint64_t)0) != -1) {
965 		return 0;
966 	} else {
967 		return errno;
968 	}
969 }
970 
971 /* set the current process as one who can resume suspended processes due to low virtual memory. Need to be root */
972 int
proc_set_owner_vmpressure(void)973 proc_set_owner_vmpressure(void)
974 {
975 	int retval;
976 
977 	if ((retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_VMRSRCOWNER, (uint64_t)0, NULL, 0)) == -1) {
978 		return errno;
979 	}
980 
981 	return 0;
982 }
983 
984 /* mark yourself to delay idle sleep on disk IO */
985 int
proc_set_delayidlesleep(void)986 proc_set_delayidlesleep(void)
987 {
988 	int retval;
989 
990 	if ((retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_DELAYIDLESLEEP, (uint64_t)1, NULL, 0)) == -1) {
991 		return errno;
992 	}
993 
994 	return 0;
995 }
996 
997 /* Reset yourself to delay idle sleep on disk IO, if already set */
998 int
proc_clear_delayidlesleep(void)999 proc_clear_delayidlesleep(void)
1000 {
1001 	int retval;
1002 
1003 	if ((retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_DELAYIDLESLEEP, (uint64_t)0, NULL, 0)) == -1) {
1004 		return errno;
1005 	}
1006 
1007 	return 0;
1008 }
1009 
1010 /* disable the launch time backgroudn policy and restore the process to default group */
1011 int
proc_disable_apptype(pid_t pid,int apptype)1012 proc_disable_apptype(pid_t pid, int apptype)
1013 {
1014 	switch (apptype) {
1015 	case PROC_POLICY_OSX_APPTYPE_TAL:
1016 	case PROC_POLICY_OSX_APPTYPE_DASHCLIENT:
1017 		break;
1018 	default:
1019 		return EINVAL;
1020 	}
1021 
1022 	if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_DISABLE, PROC_POLICY_APPTYPE, apptype, NULL, pid, (uint64_t)0) != -1) {
1023 		return 0;
1024 	} else {
1025 		return errno;
1026 	}
1027 }
1028 
1029 /* re-enable the launch time background policy if it had been disabled. */
1030 int
proc_enable_apptype(pid_t pid,int apptype)1031 proc_enable_apptype(pid_t pid, int apptype)
1032 {
1033 	switch (apptype) {
1034 	case PROC_POLICY_OSX_APPTYPE_TAL:
1035 	case PROC_POLICY_OSX_APPTYPE_DASHCLIENT:
1036 		break;
1037 	default:
1038 		return EINVAL;
1039 	}
1040 
1041 	if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_ENABLE, PROC_POLICY_APPTYPE, apptype, NULL, pid, (uint64_t)0) != -1) {
1042 		return 0;
1043 	} else {
1044 		return errno;
1045 	}
1046 }
1047 
1048 #if !TARGET_OS_SIMULATOR
1049 
1050 int
proc_suppress(__unused pid_t pid,__unused uint64_t * generation)1051 proc_suppress(__unused pid_t pid, __unused uint64_t *generation)
1052 {
1053 	return 0;
1054 }
1055 
1056 #endif /* !TARGET_OS_SIMULATOR */
1057 
1058 #endif /* !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
1059 
1060 int
proc_set_no_smt(void)1061 proc_set_no_smt(void)
1062 {
1063 	if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_APPLY, PROC_POLICY_NO_SMT, 0, NULL, getpid(), (uint64_t)0) == -1) {
1064 		return errno;
1065 	}
1066 	return 0;
1067 }
1068 
1069 int
proc_setthread_no_smt(void)1070 proc_setthread_no_smt(void)
1071 {
1072 	extern uint64_t __thread_selfid(void);
1073 	if (__process_policy(PROC_POLICY_SCOPE_THREAD, PROC_POLICY_ACTION_APPLY, PROC_POLICY_NO_SMT, 0, NULL, 0, __thread_selfid()) == -1) {
1074 		return errno;
1075 	}
1076 	return 0;
1077 }
1078 
1079 int
proc_set_csm(uint32_t flags)1080 proc_set_csm(uint32_t flags)
1081 {
1082 	const uint32_t mask = PROC_CSM_ALL | PROC_CSM_TECS | PROC_CSM_NOSMT;
1083 	if ((flags & ~mask) != 0) {
1084 		return EINVAL;
1085 	}
1086 
1087 	if (flags & (PROC_CSM_NOSMT | PROC_CSM_ALL)) {
1088 		if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_APPLY, PROC_POLICY_NO_SMT, 0, NULL, getpid(), (uint64_t)0) == -1) {
1089 			return errno;
1090 		}
1091 	}
1092 
1093 	if (flags & (PROC_CSM_TECS | PROC_CSM_ALL)) {
1094 		if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_APPLY, PROC_POLICY_TECS, 0, NULL, getpid(), (uint64_t)0) == -1) {
1095 			return errno;
1096 		}
1097 	}
1098 
1099 	return 0;
1100 }
1101 
1102 int
proc_setthread_csm(uint32_t flags)1103 proc_setthread_csm(uint32_t flags)
1104 {
1105 	extern uint64_t __thread_selfid(void);
1106 	const uint32_t mask = PROC_CSM_ALL | PROC_CSM_TECS | PROC_CSM_NOSMT;
1107 	if ((flags & ~mask) != 0) {
1108 		return EINVAL;
1109 	}
1110 
1111 	if (flags & (PROC_CSM_NOSMT | PROC_CSM_ALL)) {
1112 		if (__process_policy(PROC_POLICY_SCOPE_THREAD, PROC_POLICY_ACTION_APPLY, PROC_POLICY_NO_SMT, 0, NULL, 0, __thread_selfid()) == -1) {
1113 			return errno;
1114 		}
1115 	}
1116 
1117 	if (flags & (PROC_CSM_TECS | PROC_CSM_ALL)) {
1118 		if (__process_policy(PROC_POLICY_SCOPE_THREAD, PROC_POLICY_ACTION_APPLY, PROC_POLICY_TECS, 0, NULL, 0, __thread_selfid()) == -1) {
1119 			return errno;
1120 		}
1121 	}
1122 
1123 	return 0;
1124 }
1125