1 /*
2 * Copyright (c) 2005-2021 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 /*
30 * proc_info system call.
31 */
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/malloc.h>
37 #include <sys/proc_internal.h>
38 #include <sys/kauth.h>
39 #include <sys/file_internal.h>
40 #include <sys/vnode_internal.h>
41 #include <sys/unistd.h>
42 #include <sys/buf.h>
43 #include <sys/ioctl.h>
44 #include <sys/namei.h>
45 #include <sys/tty.h>
46 #include <sys/disklabel.h>
47 #include <sys/vm.h>
48 #include <sys/reason.h>
49 #include <sys/sysctl.h>
50 #include <sys/user.h>
51 #include <sys/aio_kern.h>
52 #include <sys/kern_memorystatus.h>
53
54 #include <security/audit/audit.h>
55
56 #include <mach/machine.h>
57 #include <mach/mach_types.h>
58 #include <mach/vm_param.h>
59 #include <kern/task.h>
60 #include <kern/kalloc.h>
61 #include <kern/assert.h>
62 #include <kern/policy_internal.h>
63 #include <kern/exc_guard.h>
64 #include <kern/task.h>
65
66 #include <vm/vm_kern.h>
67 #include <vm/vm_map.h>
68 #include <mach/host_info.h>
69 #include <mach/task_info.h>
70 #include <mach/thread_info.h>
71 #include <mach/vm_region.h>
72 #include <mach/vm_types.h>
73
74 #include <sys/mount_internal.h>
75 #include <sys/proc_info.h>
76 #include <sys/bsdtask_info.h>
77 #include <sys/kdebug.h>
78 #include <sys/sysproto.h>
79 #include <sys/msgbuf.h>
80 #include <sys/priv.h>
81 #include <sys/syscall.h>
82 #include <IOKit/IOBSD.h>
83
84 #include <sys/guarded.h>
85
86 #include <machine/machine_routines.h>
87
88 #include <kern/ipc_misc.h>
89
90 #include <vm/vm_protos.h>
91
92 #include <corpses/task_corpse.h>
93
94 /* Needed by proc_pidnoteexit(), proc_pidlistuptrs() */
95 #include <sys/event.h>
96 #include <sys/codesign.h>
97
98 /* Needed by proc_listcoalitions() */
99 #ifdef CONFIG_COALITIONS
100 #include <sys/coalition.h>
101 #endif
102
103 #if CONFIG_MACF
104 #include <security/mac_framework.h>
105 #endif
106
107 #include <os/log.h>
108
109 struct pshmnode;
110 struct psemnode;
111 struct pipe;
112 struct kqueue;
113 struct atalk;
114
115 uint64_t get_dispatchqueue_offset_from_proc(void *);
116 uint64_t get_dispatchqueue_serialno_offset_from_proc(void *);
117 uint64_t get_dispatchqueue_label_offset_from_proc(void *p);
118 uint64_t get_return_to_kernel_offset_from_proc(void *p);
119 uint64_t get_wq_quantum_offset_from_proc(void *p);
120 int proc_info_internal(int callnum, int pid, uint32_t flags, uint64_t ext_id, int flavor, uint64_t arg, user_addr_t buffer, uint32_t buffersize, int32_t * retval);
121
122 /*
123 * TODO: Replace the noinline attribute below. Currently, it serves
124 * to avoid stack bloat caused by inlining multiple functions that
125 * have large stack footprints; when the functions are independent
126 * of each other (will not both be called in any given call to the
127 * caller), this only serves to bloat the stack, as we allocate
128 * space for both functions, despite the fact that we only need a
129 * fraction of that space.
130 *
131 * Long term, these functions should not be allocating everything on
132 * the stack, and should move large allocations (the huge structs
133 * that proc info deals in) to the heap, or eliminate them if
134 * possible.
135 *
136 * The functions that most desperately need to improve stack usage
137 * (starting with the worst offenders):
138 * proc_pidvnodepathinfo
139 * proc_pidinfo
140 * proc_pidregionpathinfo
141 * pid_vnodeinfopath
142 * pid_pshminfo
143 * pid_pseminfo
144 * pid_socketinfo
145 * proc_pid_rusage
146 * proc_pidoriginatorinfo
147 */
148
149 /* protos for proc_info calls */
150 static int __attribute__ ((noinline)) proc_listpids(uint32_t type, uint32_t tyoneinfo, user_addr_t buffer, uint32_t buffersize, int32_t * retval);
151 static int __attribute__ ((noinline)) proc_pidinfo(int pid, uint32_t flags, uint64_t ext_id, int flavor, uint64_t arg, user_addr_t buffer, uint32_t buffersize, int32_t * retval);
152 static int __attribute__ ((noinline)) proc_pidfdinfo(int pid, int flavor, int fd, user_addr_t buffer, uint32_t buffersize, int32_t * retval);
153 static int __attribute__ ((noinline)) proc_kernmsgbuf(user_addr_t buffer, uint32_t buffersize, int32_t * retval);
154 static int __attribute__ ((noinline)) proc_setcontrol(int pid, int flavor, uint64_t arg, user_addr_t buffer, uint32_t buffersize, int32_t * retval);
155 static int __attribute__ ((noinline)) proc_pidfileportinfo(int pid, int flavor, mach_port_name_t name, user_addr_t buffer, uint32_t buffersize, int32_t *retval);
156 static int __attribute__ ((noinline)) proc_dirtycontrol(int pid, int flavor, uint64_t arg, int32_t * retval);
157 static int __attribute__ ((noinline)) proc_terminate(int pid, int32_t * retval);
158 static int __attribute__ ((noinline)) proc_pid_rusage(int pid, int flavor, user_addr_t buffer, int32_t * retval);
159 static int __attribute__ ((noinline)) proc_pidoriginatorinfo(int pid, int flavor, user_addr_t buffer, uint32_t buffersize, int32_t * retval);
160 static int __attribute__ ((noinline)) proc_listcoalitions(int flavor, int coaltype, user_addr_t buffer, uint32_t buffersize, int32_t *retval);
161 static int __attribute__ ((noinline)) proc_can_use_foreground_hw(int pid, user_addr_t reason, uint32_t resonsize, int32_t *retval);
162 static int __attribute__ ((noinline)) proc_set_dyld_images(int pid, user_addr_t buffer, uint32_t buffersize, int32_t *retval);
163
164 /* protos for procpidinfo calls */
165 static int __attribute__ ((noinline)) proc_pidfdlist(proc_t p, user_addr_t buffer, uint32_t buffersize, int32_t *retval);
166 static int __attribute__ ((noinline)) proc_pidbsdinfo(proc_t p, struct proc_bsdinfo *pbsd, int zombie);
167 static int __attribute__ ((noinline)) proc_pidshortbsdinfo(proc_t p, struct proc_bsdshortinfo *pbsd_shortp, int zombie);
168 static int __attribute__ ((noinline)) proc_pidtaskinfo(proc_t p, struct proc_taskinfo *ptinfo);
169 static int __attribute__ ((noinline)) proc_pidthreadinfo(proc_t p, uint64_t arg, bool thuniqueid, struct proc_threadinfo *pthinfo);
170 static int __attribute__ ((noinline)) proc_pidthreadpathinfo(proc_t p, uint64_t arg, struct proc_threadwithpathinfo *pinfo);
171 static int __attribute__ ((noinline)) proc_pidthreadschedinfo(proc_t p, uint64_t arg, struct proc_threadschedinfo *schedinfo);
172 static int __attribute__ ((noinline)) proc_pidlistthreads(proc_t p, bool thuniqueid, user_addr_t buffer, uint32_t buffersize, int32_t *retval);
173 static int __attribute__ ((noinline)) proc_pidregioninfo(proc_t p, uint64_t arg, user_addr_t buffer, uint32_t buffersize, int32_t *retval);
174 static int __attribute__ ((noinline)) proc_pidregionpathinfo(proc_t p, uint64_t arg, user_addr_t buffer, uint32_t buffersize, int32_t *retval);
175 static int __attribute__ ((noinline)) proc_pidregionpathinfo2(proc_t p, uint64_t arg, user_addr_t buffer, uint32_t buffersize, int32_t *retval);
176 static int __attribute__ ((noinline)) proc_pidregionpathinfo3(proc_t p, uint64_t arg, user_addr_t buffer, uint32_t buffersize, int32_t *retval);
177 static int __attribute__ ((noinline)) proc_pidvnodepathinfo(proc_t p, uint64_t arg, user_addr_t buffer, uint32_t buffersize, int32_t *retval);
178 static int __attribute__ ((noinline)) proc_pidpathinfo(proc_t p, uint64_t arg, user_addr_t buffer, uint32_t buffersize, int32_t *retval);
179 static int __attribute__ ((noinline)) proc_pidworkqueueinfo(proc_t p, struct proc_workqueueinfo *pwqinfo);
180 static int __attribute__ ((noinline)) proc_pidfileportlist(proc_t p, user_addr_t buffer, size_t buffersize, int32_t *retval);
181 extern void __attribute__ ((noinline)) proc_piduniqidentifierinfo(proc_t p, struct proc_uniqidentifierinfo *p_uniqidinfo);
182 static void __attribute__ ((noinline)) proc_archinfo(proc_t p, struct proc_archinfo *pai);
183 static void __attribute__ ((noinline)) proc_pidcoalitioninfo(proc_t p, struct proc_pidcoalitioninfo *pci);
184 static int __attribute__ ((noinline)) proc_pidnoteexit(proc_t p, uint64_t arg, uint32_t *data);
185 static int __attribute__ ((noinline)) proc_pidexitreasoninfo(proc_t p, struct proc_exitreasoninfo *peri, struct proc_exitreasonbasicinfo *pberi);
186 static int __attribute__ ((noinline)) proc_pidlistuptrs(proc_t p, user_addr_t buffer, uint32_t buffersize, int32_t *retval);
187 static int __attribute__ ((noinline)) proc_piddynkqueueinfo(pid_t pid, int flavor, kqueue_id_t id, user_addr_t buffer, uint32_t buffersize, int32_t *retval);
188 static int __attribute__ ((noinline)) proc_pidregionpath(proc_t p, uint64_t arg, user_addr_t buffer, __unused uint32_t buffersize, int32_t *retval);
189 static int __attribute__ ((noinline)) proc_pidipctableinfo(proc_t p, struct proc_ipctableinfo *table_info);
190
191 #if CONFIG_PROC_UDATA_STORAGE
192 int __attribute__ ((noinline)) proc_udata_info(pid_t pid, int flavor, user_addr_t buffer, uint32_t buffersize, int32_t *retval);
193 #endif
194
195 /* protos for proc_pidfdinfo calls */
196 static int __attribute__ ((noinline)) pid_vnodeinfo(vnode_t vp, struct fileproc * fp, proc_t proc, user_addr_t buffer, uint32_t buffersize, int32_t * retval);
197 static int __attribute__ ((noinline)) pid_vnodeinfopath(vnode_t vp, struct fileproc * fp, proc_t proc, user_addr_t buffer, uint32_t buffersize, int32_t * retval);
198 static int __attribute__ ((noinline)) pid_socketinfo(socket_t so, struct fileproc *fp, proc_t proc, user_addr_t buffer, uint32_t buffersize, int32_t * retval);
199 static int __attribute__ ((noinline)) pid_channelinfo(struct kern_channel *chan, struct fileproc *fp, proc_t proc, user_addr_t buffer, uint32_t buffersize, int32_t * retval);
200 static int __attribute__ ((noinline)) pid_pseminfo(struct psemnode * psem, struct fileproc * fp, proc_t proc, user_addr_t buffer, uint32_t buffersize, int32_t * retval);
201 static int __attribute__ ((noinline)) pid_pshminfo(struct pshmnode * pshm, struct fileproc * fp, proc_t proc, user_addr_t buffer, uint32_t buffersize, int32_t * retval);
202 static int __attribute__ ((noinline)) pid_pipeinfo(struct pipe * p, struct fileproc * fp, proc_t proc, user_addr_t buffer, uint32_t buffersize, int32_t * retval);
203 static int __attribute__ ((noinline)) pid_kqueueinfo(struct kqueue * kq, struct fileproc * fp, proc_t proc, user_addr_t buffer, uint32_t buffersize, int32_t * retval);
204
205
206 /* protos for misc */
207
208 static int proc_terminate_all_rsr(__unused int pid, __unused int flavor, int arg, int32_t *retval);
209 static int proc_terminate_all_rsr_filter(proc_t p, __unused void *arg);
210 static int proc_terminate_all_rsr_callback(proc_t p, void *arg);
211 static int proc_signal_with_audittoken(user_addr_t buffer, size_t buffersize, int signum, int32_t *retval);
212 static int proc_terminate_with_audittoken(user_addr_t buffer, size_t buffersize, int32_t *retval);
213 static int proc_signal_delegate(user_addr_t buffer, size_t buffersize, int signum, int32_t *retval);
214 static int proc_terminate_delegate(user_addr_t buffer, size_t buffersize, int32_t *retval);
215 static int fill_vnodeinfo(vnode_t vp, struct vnode_info *vinfo, boolean_t check_fsgetpath);
216 static void fill_fileinfo(struct fileproc *fp, proc_t proc, struct proc_fileinfo * finfo);
217 static int proc_security_policy(proc_t targetp, int callnum, int flavor, boolean_t check_same_user);
218 static void munge_vinfo_stat(struct stat64 *sbp, struct vinfo_stat *vsbp);
219 static int proc_piduuidinfo(pid_t pid, uuid_t uuid_buf, uint32_t buffersize);
220
221 extern int proc_pidpathinfo_internal(proc_t p, __unused uint64_t arg, char *buf, uint32_t buffersize, __unused int32_t *retval);
222 extern int cansignal(struct proc *, kauth_cred_t, struct proc *, int);
223 extern int cansignal_nomac(proc_t src, kauth_cred_t uc_src, proc_t dst, int signum);
224 extern int proc_get_rusage(proc_t proc, int flavor, user_addr_t buffer, int is_zombie);
225
226 #define CHECK_SAME_USER TRUE
227 #define NO_CHECK_SAME_USER FALSE
228
229 uint64_t
get_dispatchqueue_offset_from_proc(void * p)230 get_dispatchqueue_offset_from_proc(void *p)
231 {
232 if (p != NULL) {
233 proc_t pself = (proc_t)p;
234 return pself->p_dispatchqueue_offset;
235 } else {
236 return (uint64_t)0;
237 }
238 }
239
240 uint64_t
get_wq_quantum_offset_from_proc(void * p)241 get_wq_quantum_offset_from_proc(void *p)
242 {
243 if (p != NULL) {
244 proc_t pself = (proc_t)p;
245 return pself->p_pthread_wq_quantum_offset;
246 } else {
247 return (uint64_t)0;
248 }
249 }
250
251 uint64_t
get_dispatchqueue_serialno_offset_from_proc(void * p)252 get_dispatchqueue_serialno_offset_from_proc(void *p)
253 {
254 if (p != NULL) {
255 proc_t pself = (proc_t)p;
256 return pself->p_dispatchqueue_serialno_offset;
257 } else {
258 return (uint64_t)0;
259 }
260 }
261
262 uint64_t
get_dispatchqueue_label_offset_from_proc(void * p)263 get_dispatchqueue_label_offset_from_proc(void *p)
264 {
265 if (p != NULL) {
266 proc_t pself = (proc_t)p;
267 return pself->p_dispatchqueue_label_offset;
268 } else {
269 return (uint64_t)0;
270 }
271 }
272
273 uint64_t
get_return_to_kernel_offset_from_proc(void * p)274 get_return_to_kernel_offset_from_proc(void *p)
275 {
276 if (p != NULL) {
277 proc_t pself = (proc_t)p;
278 return pself->p_return_to_kernel_offset;
279 } else {
280 return (uint64_t)0;
281 }
282 }
283
284 /***************************** proc_info ********************/
285
286 int
proc_info(__unused struct proc * p,struct proc_info_args * uap,int32_t * retval)287 proc_info(__unused struct proc *p, struct proc_info_args * uap, int32_t *retval)
288 {
289 return proc_info_internal(uap->callnum, uap->pid, 0, 0, uap->flavor, uap->arg, uap->buffer, uap->buffersize, retval);
290 }
291
292 int
proc_info_extended_id(__unused struct proc * p,struct proc_info_extended_id_args * uap,int32_t * retval)293 proc_info_extended_id(__unused struct proc *p, struct proc_info_extended_id_args *uap, int32_t *retval)
294 {
295 uint32_t flags = uap->flags;
296
297 if ((flags & (PIF_COMPARE_IDVERSION | PIF_COMPARE_UNIQUEID)) == (PIF_COMPARE_IDVERSION | PIF_COMPARE_UNIQUEID)) {
298 return EINVAL;
299 }
300
301 return proc_info_internal(uap->callnum, uap->pid, flags, uap->ext_id, uap->flavor, uap->arg, uap->buffer, uap->buffersize, retval);
302 }
303
304 int
proc_info_internal(int callnum,int pid,uint32_t flags,uint64_t ext_id,int flavor,uint64_t arg,user_addr_t buffer,uint32_t buffersize,int32_t * retval)305 proc_info_internal(int callnum, int pid, uint32_t flags, uint64_t ext_id, int flavor, uint64_t arg, user_addr_t buffer, uint32_t buffersize, int32_t * retval)
306 {
307 switch (callnum) {
308 case PROC_INFO_CALL_LISTPIDS:
309 /* pid contains type and flavor contains typeinfo */
310 return proc_listpids(pid, flavor, buffer, buffersize, retval);
311 case PROC_INFO_CALL_PIDINFO:
312 return proc_pidinfo(pid, flags, ext_id, flavor, arg, buffer, buffersize, retval);
313 case PROC_INFO_CALL_PIDFDINFO:
314 return proc_pidfdinfo(pid, flavor, (int)arg, buffer, buffersize, retval);
315 case PROC_INFO_CALL_KERNMSGBUF:
316 return proc_kernmsgbuf(buffer, buffersize, retval);
317 case PROC_INFO_CALL_SETCONTROL:
318 return proc_setcontrol(pid, flavor, arg, buffer, buffersize, retval);
319 case PROC_INFO_CALL_PIDFILEPORTINFO:
320 return proc_pidfileportinfo(pid, flavor, (mach_port_name_t)arg, buffer, buffersize, retval);
321 case PROC_INFO_CALL_TERMINATE:
322 return proc_terminate(pid, retval);
323 case PROC_INFO_CALL_DIRTYCONTROL:
324 return proc_dirtycontrol(pid, flavor, arg, retval);
325 case PROC_INFO_CALL_PIDRUSAGE:
326 return proc_pid_rusage(pid, flavor, buffer, retval);
327 case PROC_INFO_CALL_PIDORIGINATORINFO:
328 return proc_pidoriginatorinfo(pid, flavor, buffer, buffersize, retval);
329 case PROC_INFO_CALL_LISTCOALITIONS:
330 return proc_listcoalitions(pid /* flavor */, flavor /* coaltype */, buffer,
331 buffersize, retval);
332 case PROC_INFO_CALL_CANUSEFGHW:
333 return proc_can_use_foreground_hw(pid, buffer, buffersize, retval);
334 case PROC_INFO_CALL_PIDDYNKQUEUEINFO:
335 return proc_piddynkqueueinfo(pid, flavor, (kqueue_id_t)arg, buffer, buffersize, retval);
336 #if CONFIG_PROC_UDATA_STORAGE
337 case PROC_INFO_CALL_UDATA_INFO:
338 return proc_udata_info(pid, flavor, buffer, buffersize, retval);
339 #endif /* CONFIG_PROC_UDATA_STORAGE */
340 case PROC_INFO_CALL_SET_DYLD_IMAGES:
341 return proc_set_dyld_images(pid, buffer, buffersize, retval);
342 case PROC_INFO_CALL_TERMINATE_RSR:
343 return proc_terminate_all_rsr(pid, flavor, (int)arg, retval);
344 case PROC_INFO_CALL_SIGNAL_AUDITTOKEN:
345 return proc_signal_with_audittoken(buffer, buffersize, flavor, retval);
346 case PROC_INFO_CALL_TERMINATE_AUDITTOKEN:
347 return proc_terminate_with_audittoken(buffer, buffersize, retval);
348 case PROC_INFO_CALL_DELEGATE_SIGNAL:
349 return proc_signal_delegate(buffer, buffersize, flavor, retval);
350 case PROC_INFO_CALL_DELEGATE_TERMINATE:
351 return proc_terminate_delegate(buffer, buffersize, retval);
352 default:
353 return EINVAL;
354 }
355
356 return EINVAL;
357 }
358
359 /******************* proc_listpids routine ****************/
360 int
proc_listpids(uint32_t type,uint32_t typeinfo,user_addr_t buffer,uint32_t buffersize,int32_t * retval)361 proc_listpids(uint32_t type, uint32_t typeinfo, user_addr_t buffer, uint32_t buffersize, int32_t * retval)
362 {
363 uint32_t numprocs = 0;
364 uint32_t wantpids;
365 int *kbuf;
366 int *ptr;
367 uint32_t n;
368 int skip;
369 struct proc * p;
370 int error = 0;
371 struct proclist *current_list;
372 kauth_cred_t cred;
373
374 /* Do we have permission to look into this? */
375 if ((error = proc_security_policy(PROC_NULL, PROC_INFO_CALL_LISTPIDS, type, NO_CHECK_SAME_USER))) {
376 return error;
377 }
378
379 /* if the buffer is null, return num of procs */
380 if (buffer == (user_addr_t)0) {
381 *retval = ((nprocs + 20) * sizeof(int));
382 return 0;
383 }
384
385 if (buffersize < sizeof(int)) {
386 return ENOMEM;
387 }
388 wantpids = buffersize / sizeof(int);
389 if ((nprocs + 20) > 0) {
390 numprocs = (uint32_t)(nprocs + 20);
391 }
392 if (numprocs > wantpids) {
393 numprocs = wantpids;
394 }
395
396 kbuf = (int *)kalloc_data(numprocs * sizeof(int), Z_WAITOK | Z_ZERO);
397 if (kbuf == NULL) {
398 return ENOMEM;
399 }
400
401 proc_list_lock();
402
403 n = 0;
404 ptr = kbuf;
405 current_list = &allproc;
406 proc_loop:
407 LIST_FOREACH(p, current_list, p_list) {
408 if (proc_is_shadow(p)) {
409 continue;
410 }
411 skip = 0;
412 switch (type) {
413 case PROC_PGRP_ONLY:
414 if (p->p_pgrpid != (pid_t)typeinfo) {
415 skip = 1;
416 }
417 break;
418 case PROC_PPID_ONLY:
419 if ((p->p_ppid != (pid_t)typeinfo) && (((p->p_lflag & P_LTRACED) == 0) || (p->p_oppid != (pid_t)typeinfo))) {
420 skip = 1;
421 }
422 break;
423
424 case PROC_ALL_PIDS:
425 skip = 0;
426 break;
427 case PROC_TTY_ONLY:
428 if (p->p_flag & P_CONTROLT) {
429 struct pgrp *pg = smr_serialized_load(&p->p_pgrp);
430 skip = pg != PGRP_NULL &&
431 os_atomic_load(&pg->pg_session->s_ttydev, relaxed) != (dev_t)typeinfo;
432 } else {
433 skip = 1;
434 }
435 break;
436 case PROC_UID_ONLY:
437 smr_proc_task_enter();
438 cred = proc_ucred_smr(p);
439 skip = cred == NOCRED ||
440 kauth_cred_getuid(cred) != (uid_t)typeinfo;
441 smr_proc_task_leave();
442 break;
443 case PROC_RUID_ONLY:
444 smr_proc_task_enter();
445 cred = proc_ucred_smr(p);
446 skip = cred == NOCRED ||
447 kauth_cred_getruid(cred) != (uid_t)typeinfo;
448 smr_proc_task_leave();
449 break;
450 case PROC_KDBG_ONLY:
451 if (p->p_kdebug == 0) {
452 skip = 1;
453 }
454 break;
455 default:
456 skip = 1;
457 break;
458 }
459 ;
460
461 if (skip == 0) {
462 *ptr++ = proc_getpid(p);
463 n++;
464 }
465 if (n >= numprocs) {
466 break;
467 }
468 }
469
470 if ((n < numprocs) && (current_list == &allproc)) {
471 current_list = &zombproc;
472 goto proc_loop;
473 }
474
475 proc_list_unlock();
476
477 ptr = kbuf;
478 error = copyout((caddr_t)ptr, buffer, n * sizeof(int));
479 if (error == 0) {
480 *retval = (n * sizeof(int));
481 }
482 kfree_data(kbuf, numprocs * sizeof(int));
483
484 return error;
485 }
486
487
488 /********************************** proc_pidfdlist routines ********************************/
489
490 static size_t
proc_fdlist_internal(proc_t p,struct proc_fdinfo * pfd,size_t numfds)491 proc_fdlist_internal(proc_t p, struct proc_fdinfo *pfd, size_t numfds)
492 {
493 struct fileproc *fp;
494 size_t count = 0;
495
496 proc_fdlock(p);
497
498 fdt_foreach(fp, p) {
499 if (count >= numfds) {
500 break;
501 }
502 file_type_t fdtype = FILEGLOB_DTYPE(fp->fp_glob);
503 pfd[count].proc_fd = fdt_foreach_fd();
504 pfd[count].proc_fdtype = (fdtype != DTYPE_ATALK) ?
505 fdtype : PROX_FDTYPE_ATALK;
506 count++;
507 }
508
509 proc_fdunlock(p);
510 return count;
511 }
512
513 int
proc_pidfdlist(proc_t p,user_addr_t buffer,uint32_t buffersize,int32_t * retval)514 proc_pidfdlist(proc_t p, user_addr_t buffer, uint32_t buffersize, int32_t *retval)
515 {
516 uint32_t numfds = 0;
517 uint32_t needfds;
518 char * kbuf;
519 uint32_t count = 0;
520 int error = 0;
521
522 if (p->p_fd.fd_nfiles > 0) {
523 numfds = (uint32_t)p->p_fd.fd_nfiles;
524 }
525
526 if (buffer == (user_addr_t) 0) {
527 numfds += 20;
528 *retval = (numfds * sizeof(struct proc_fdinfo));
529 return 0;
530 }
531
532 /* buffersize is big enough atleast for one struct */
533 needfds = buffersize / sizeof(struct proc_fdinfo);
534
535 if (numfds > needfds) {
536 numfds = needfds;
537 }
538
539 kbuf = (char *)kalloc_data(numfds * sizeof(struct proc_fdinfo), Z_WAITOK | Z_ZERO);
540 if (kbuf == NULL) {
541 return ENOMEM;
542 }
543
544 /* cannot overflow due to count <= numfds */
545 count = (uint32_t)proc_fdlist_internal(p, (struct proc_fdinfo *)kbuf, (size_t)numfds);
546
547 error = copyout(kbuf, buffer, count * sizeof(struct proc_fdinfo));
548 kfree_data(kbuf, numfds * sizeof(struct proc_fdinfo));
549 if (error == 0) {
550 *retval = count * sizeof(struct proc_fdinfo);
551 }
552 return error;
553 }
554
555 /*
556 * KPI variant of proc_pidfdlist.
557 *
558 * Caller is responsible for adding margin to *count when calling this in
559 * circumstances where file descriptors can appear/disappear between the
560 * two calls to this function.
561 */
562 int
proc_fdlist(proc_t p,struct proc_fdinfo * buf,size_t * count)563 proc_fdlist(proc_t p, struct proc_fdinfo *buf, size_t *count)
564 {
565 if (p == NULL || count == NULL) {
566 return EINVAL;
567 }
568
569 if (buf == NULL) {
570 proc_fdlock(p);
571 *count = (size_t)p->p_fd.fd_afterlast;
572 proc_fdunlock(p);
573 return 0;
574 }
575
576 *count = proc_fdlist_internal(p, buf, *count);
577 return 0;
578 }
579
580 int
proc_pidfileportlist(proc_t p,user_addr_t buffer,size_t buffersize,int32_t * retval)581 proc_pidfileportlist(proc_t p,
582 user_addr_t buffer, size_t buffersize, int32_t *retval)
583 {
584 void *kbuf;
585 size_t kbufsize;
586 struct proc_fileportinfo *pfi;
587 size_t needfileports, numfileports;
588 int error;
589 kern_return_t kr;
590
591 needfileports = buffersize / sizeof(*pfi);
592 if ((user_addr_t)0 == buffer || needfileports > (size_t)maxfilesperproc) {
593 /*
594 * Either (i) the user is asking for a fileport count,
595 * or (ii) the number of fileports they're asking for is
596 * larger than the maximum number of open files (!); count
597 * them to bound subsequent heap allocations.
598 */
599 numfileports = 0;
600 switch (fileport_walk(proc_task(p), &numfileports, NULL)) {
601 case KERN_SUCCESS:
602 break;
603 case KERN_RESOURCE_SHORTAGE:
604 return ENOMEM;
605 case KERN_INVALID_TASK:
606 return ESRCH;
607 default:
608 return EINVAL;
609 }
610
611 if (numfileports == 0) {
612 *retval = 0; /* none at all, bail */
613 return 0;
614 }
615 if ((user_addr_t)0 == buffer) {
616 numfileports += 20; /* accelerate convergence */
617 *retval = (int32_t)MIN(numfileports * sizeof(*pfi), INT32_MAX);
618 return 0;
619 }
620 if (needfileports > numfileports) {
621 needfileports = numfileports;
622 }
623 }
624
625 assert(buffersize >= PROC_PIDLISTFILEPORTS_SIZE);
626
627 kbufsize = needfileports * sizeof(*pfi);
628 pfi = kbuf = kalloc_data(kbufsize, Z_WAITOK | Z_ZERO);
629 if (kbuf == NULL) {
630 return ENOMEM;
631 }
632
633 kr = fileport_walk(proc_task(p), &numfileports,
634 ^bool (size_t i, mach_port_name_t name, struct fileglob *fg) {
635 if (i < needfileports) {
636 file_type_t fdtype = FILEGLOB_DTYPE(fg);
637
638 pfi[i].proc_fdtype = (fdtype != DTYPE_ATALK) ?
639 fdtype : PROX_FDTYPE_ATALK;
640 pfi[i].proc_fileport = name;
641 return true;
642 }
643 return false; /* stop walking */
644 });
645 switch (kr) {
646 case KERN_SUCCESS:
647 if (numfileports) {
648 if (numfileports > needfileports) {
649 numfileports = needfileports;
650 }
651 error = copyout(kbuf, buffer, numfileports * sizeof(*pfi));
652 } else {
653 error = 0;
654 }
655 break;
656 case KERN_RESOURCE_SHORTAGE:
657 error = ENOMEM;
658 break;
659 case KERN_INVALID_TASK:
660 error = ESRCH;
661 break;
662 default:
663 error = EINVAL;
664 break;
665 }
666
667 kfree_data(kbuf, kbufsize);
668 if (error == 0) {
669 *retval = (int32_t)MIN(numfileports * sizeof(*pfi), INT32_MAX);
670 }
671 return error;
672 }
673
674 int
proc_pidbsdinfo(proc_t p,struct proc_bsdinfo * pbsd,int zombie)675 proc_pidbsdinfo(proc_t p, struct proc_bsdinfo * pbsd, int zombie)
676 {
677 struct pgrp *pg;
678 struct session *sessp;
679 kauth_cred_t my_cred;
680
681 pg = proc_pgrp(p, &sessp);
682
683 smr_proc_task_enter();
684
685 my_cred = proc_ucred_smr(p);
686
687 bzero(pbsd, sizeof(struct proc_bsdinfo));
688 pbsd->pbi_status = p->p_stat;
689 pbsd->pbi_xstatus = p->p_xstat;
690 pbsd->pbi_pid = proc_getpid(p);
691 pbsd->pbi_ppid = p->p_ppid;
692 pbsd->pbi_uid = kauth_cred_getuid(my_cred);
693 pbsd->pbi_gid = kauth_cred_getgid(my_cred);
694 pbsd->pbi_ruid = kauth_cred_getruid(my_cred);
695 pbsd->pbi_rgid = kauth_cred_getrgid(my_cred);
696 pbsd->pbi_svuid = kauth_cred_getsvuid(my_cred);
697 pbsd->pbi_svgid = kauth_cred_getsvgid(my_cred);
698
699 my_cred = NOCRED;
700 smr_proc_task_leave();
701
702 pbsd->pbi_nice = p->p_nice;
703 pbsd->pbi_start_tvsec = p->p_start.tv_sec;
704 pbsd->pbi_start_tvusec = p->p_start.tv_usec;
705 bcopy(&p->p_comm, &pbsd->pbi_comm[0], MAXCOMLEN);
706 pbsd->pbi_comm[MAXCOMLEN - 1] = '\0';
707 bcopy(&p->p_name, &pbsd->pbi_name[0], 2 * MAXCOMLEN);
708 pbsd->pbi_name[(2 * MAXCOMLEN) - 1] = '\0';
709
710 pbsd->pbi_flags = 0;
711 if ((p->p_flag & P_SYSTEM) == P_SYSTEM) {
712 pbsd->pbi_flags |= PROC_FLAG_SYSTEM;
713 }
714 if ((p->p_lflag & P_LTRACED) == P_LTRACED) {
715 pbsd->pbi_flags |= PROC_FLAG_TRACED;
716 }
717 if ((p->p_lflag & P_LEXIT) == P_LEXIT) {
718 pbsd->pbi_flags |= PROC_FLAG_INEXIT;
719 }
720 if ((p->p_lflag & P_LPPWAIT) == P_LPPWAIT) {
721 pbsd->pbi_flags |= PROC_FLAG_PPWAIT;
722 }
723 if ((p->p_flag & P_LP64) == P_LP64) {
724 pbsd->pbi_flags |= PROC_FLAG_LP64;
725 }
726 if ((p->p_flag & P_CONTROLT) == P_CONTROLT) {
727 pbsd->pbi_flags |= PROC_FLAG_CONTROLT;
728 }
729 if ((p->p_flag & P_THCWD) == P_THCWD) {
730 pbsd->pbi_flags |= PROC_FLAG_THCWD;
731 }
732 if ((p->p_flag & P_SUGID) == P_SUGID) {
733 pbsd->pbi_flags |= PROC_FLAG_PSUGID;
734 }
735 if ((p->p_flag & P_EXEC) == P_EXEC) {
736 pbsd->pbi_flags |= PROC_FLAG_EXEC;
737 }
738 if ((p->p_flag & P_TRANSLATED) == P_TRANSLATED) {
739 pbsd->pbi_flags |= PROC_FLAG_ROSETTA;
740 }
741
742 if (pg != PGRP_NULL) {
743 if (SESS_LEADER(p, pg->pg_session)) {
744 pbsd->pbi_flags |= PROC_FLAG_SLEADER;
745 }
746 if (pg->pg_session->s_ttyvp) {
747 pbsd->pbi_flags |= PROC_FLAG_CTTY;
748 }
749 }
750
751 #if CONFIG_DELAY_IDLE_SLEEP
752 if ((p->p_flag & P_DELAYIDLESLEEP) == P_DELAYIDLESLEEP) {
753 pbsd->pbi_flags |= PROC_FLAG_DELAYIDLESLEEP;
754 }
755 #endif /* CONFIG_DELAY_IDLE_SLEEP */
756
757 switch (PROC_CONTROL_STATE(p)) {
758 case P_PCTHROTTLE:
759 pbsd->pbi_flags |= PROC_FLAG_PC_THROTTLE;
760 break;
761 case P_PCSUSP:
762 pbsd->pbi_flags |= PROC_FLAG_PC_SUSP;
763 break;
764 case P_PCKILL:
765 pbsd->pbi_flags |= PROC_FLAG_PC_KILL;
766 break;
767 }
768 ;
769
770 switch (PROC_ACTION_STATE(p)) {
771 case P_PCTHROTTLE:
772 pbsd->pbi_flags |= PROC_FLAG_PA_THROTTLE;
773 break;
774 case P_PCSUSP:
775 pbsd->pbi_flags |= PROC_FLAG_PA_SUSP;
776 break;
777 }
778 ;
779
780 /* if process is a zombie skip bg state */
781 if ((zombie == 0) && (p->p_stat != SZOMB) && (proc_task(p) != TASK_NULL)) {
782 proc_get_darwinbgstate(proc_task(p), &pbsd->pbi_flags);
783 }
784
785 if (zombie == 0) {
786 pbsd->pbi_nfiles = p->p_fd.fd_nfiles;
787 }
788
789 pbsd->e_tdev = NODEV;
790 if (sessp != SESSION_NULL) {
791 pbsd->pbi_pgid = p->p_pgrpid;
792 pbsd->pbi_pjobc = pg->pg_jobc;
793 if (p->p_flag & P_CONTROLT) {
794 session_lock(sessp);
795 pbsd->e_tdev = os_atomic_load(&sessp->s_ttydev, relaxed);
796 pbsd->e_tpgid = sessp->s_ttypgrpid;
797 session_unlock(sessp);
798 }
799 }
800
801 pgrp_rele(pg);
802
803 return 0;
804 }
805
806
807 int
proc_pidshortbsdinfo(proc_t p,struct proc_bsdshortinfo * pbsd_shortp,int zombie)808 proc_pidshortbsdinfo(proc_t p, struct proc_bsdshortinfo * pbsd_shortp, int zombie)
809 {
810 bzero(pbsd_shortp, sizeof(struct proc_bsdshortinfo));
811 pbsd_shortp->pbsi_pid = proc_getpid(p);
812 pbsd_shortp->pbsi_ppid = p->p_ppid;
813 pbsd_shortp->pbsi_pgid = p->p_pgrpid;
814 pbsd_shortp->pbsi_status = p->p_stat;
815 bcopy(&p->p_comm, &pbsd_shortp->pbsi_comm[0], MAXCOMLEN);
816 pbsd_shortp->pbsi_comm[MAXCOMLEN - 1] = '\0';
817
818 pbsd_shortp->pbsi_flags = 0;
819 if ((p->p_flag & P_SYSTEM) == P_SYSTEM) {
820 pbsd_shortp->pbsi_flags |= PROC_FLAG_SYSTEM;
821 }
822 if ((p->p_lflag & P_LTRACED) == P_LTRACED) {
823 pbsd_shortp->pbsi_flags |= PROC_FLAG_TRACED;
824 }
825 if ((p->p_lflag & P_LEXIT) == P_LEXIT) {
826 pbsd_shortp->pbsi_flags |= PROC_FLAG_INEXIT;
827 }
828 if ((p->p_lflag & P_LPPWAIT) == P_LPPWAIT) {
829 pbsd_shortp->pbsi_flags |= PROC_FLAG_PPWAIT;
830 }
831 if ((p->p_flag & P_LP64) == P_LP64) {
832 pbsd_shortp->pbsi_flags |= PROC_FLAG_LP64;
833 }
834 if ((p->p_flag & P_CONTROLT) == P_CONTROLT) {
835 pbsd_shortp->pbsi_flags |= PROC_FLAG_CONTROLT;
836 }
837 if ((p->p_flag & P_THCWD) == P_THCWD) {
838 pbsd_shortp->pbsi_flags |= PROC_FLAG_THCWD;
839 }
840 if ((p->p_flag & P_SUGID) == P_SUGID) {
841 pbsd_shortp->pbsi_flags |= PROC_FLAG_PSUGID;
842 }
843 if ((p->p_flag & P_EXEC) == P_EXEC) {
844 pbsd_shortp->pbsi_flags |= PROC_FLAG_EXEC;
845 }
846 if ((p->p_flag & P_TRANSLATED) == P_TRANSLATED) {
847 pbsd_shortp->pbsi_flags |= PROC_FLAG_ROSETTA;
848 }
849 #if CONFIG_DELAY_IDLE_SLEEP
850 if ((p->p_flag & P_DELAYIDLESLEEP) == P_DELAYIDLESLEEP) {
851 pbsd_shortp->pbsi_flags |= PROC_FLAG_DELAYIDLESLEEP;
852 }
853 #endif /* CONFIG_DELAY_IDLE_SLEEP */
854
855 switch (PROC_CONTROL_STATE(p)) {
856 case P_PCTHROTTLE:
857 pbsd_shortp->pbsi_flags |= PROC_FLAG_PC_THROTTLE;
858 break;
859 case P_PCSUSP:
860 pbsd_shortp->pbsi_flags |= PROC_FLAG_PC_SUSP;
861 break;
862 case P_PCKILL:
863 pbsd_shortp->pbsi_flags |= PROC_FLAG_PC_KILL;
864 break;
865 }
866 ;
867
868 switch (PROC_ACTION_STATE(p)) {
869 case P_PCTHROTTLE:
870 pbsd_shortp->pbsi_flags |= PROC_FLAG_PA_THROTTLE;
871 break;
872 case P_PCSUSP:
873 pbsd_shortp->pbsi_flags |= PROC_FLAG_PA_SUSP;
874 break;
875 }
876 ;
877
878 /* if process is a zombie skip bg state */
879 if ((zombie == 0) && (p->p_stat != SZOMB) && (proc_task(p) != TASK_NULL)) {
880 proc_get_darwinbgstate(proc_task(p), &pbsd_shortp->pbsi_flags);
881 }
882
883 pbsd_shortp->pbsi_uid = p->p_uid;
884 pbsd_shortp->pbsi_gid = p->p_gid;
885 pbsd_shortp->pbsi_ruid = p->p_ruid;
886 pbsd_shortp->pbsi_rgid = p->p_rgid;
887 pbsd_shortp->pbsi_svuid = p->p_svuid;
888 pbsd_shortp->pbsi_svgid = p->p_svgid;
889
890 return 0;
891 }
892
893 int
proc_pidtaskinfo(proc_t p,struct proc_taskinfo * ptinfo)894 proc_pidtaskinfo(proc_t p, struct proc_taskinfo * ptinfo)
895 {
896 task_t task;
897
898 task = proc_task(p);
899
900 bzero(ptinfo, sizeof(struct proc_taskinfo));
901 fill_taskprocinfo(task, (struct proc_taskinfo_internal *)ptinfo);
902
903 return 0;
904 }
905
906 int
proc_pidthreadinfo(proc_t p,uint64_t arg,bool thuniqueid,struct proc_threadinfo * pthinfo)907 proc_pidthreadinfo(proc_t p, uint64_t arg, bool thuniqueid, struct proc_threadinfo *pthinfo)
908 {
909 int error = 0;
910 uint64_t threadaddr = (uint64_t)arg;
911
912 bzero(pthinfo, sizeof(struct proc_threadinfo));
913
914 error = fill_taskthreadinfo(proc_task(p), threadaddr, thuniqueid, (struct proc_threadinfo_internal *)pthinfo, NULL, NULL);
915 if (error) {
916 return ESRCH;
917 } else {
918 return 0;
919 }
920 }
921
922 boolean_t
bsd_hasthreadname(void * uth)923 bsd_hasthreadname(void *uth)
924 {
925 struct uthread *ut = (struct uthread*)uth;
926
927 /* This doesn't check for the empty string; do we care? */
928 if (ut->pth_name) {
929 return TRUE;
930 } else {
931 return FALSE;
932 }
933 }
934
935 void
bsd_getthreadname(void * uth,char * buffer)936 bsd_getthreadname(void *uth, char *buffer)
937 {
938 struct uthread *ut = (struct uthread *)uth;
939 if (ut->pth_name) {
940 bcopy(ut->pth_name, buffer, MAXTHREADNAMESIZE);
941 } else {
942 *buffer = '\0';
943 }
944 }
945
946 /*
947 * This is known to race with regards to the contents of the thread name; concurrent
948 * callers may result in a garbled name.
949 */
950 void
bsd_setthreadname(void * uth,uint64_t tid,const char * name)951 bsd_setthreadname(void *uth, uint64_t tid, const char *name)
952 {
953 struct uthread *ut = (struct uthread *)uth;
954 char * name_buf = NULL;
955 uint64_t current_tid = thread_tid(current_thread());
956
957 if (!ut->pth_name) {
958 /* If there is no existing thread name, allocate a buffer for one. */
959 name_buf = kalloc_data(MAXTHREADNAMESIZE,
960 Z_WAITOK | Z_ZERO | Z_NOFAIL);
961
962 /* Someone could conceivably have named the thread at the same time we did. */
963 if (!OSCompareAndSwapPtr(NULL, name_buf, &ut->pth_name)) {
964 kfree_data(name_buf, MAXTHREADNAMESIZE);
965 }
966 } else {
967 /*
968 * Simple strings lack a way to identify the thread being named,
969 * so only emit this if the current thread is renaming itself.
970 */
971 if (tid == current_tid) {
972 kernel_debug_string_simple(TRACE_STRING_THREADNAME_PREV, ut->pth_name);
973 }
974 }
975
976 strncpy(ut->pth_name, name, MAXTHREADNAMESIZE - 1);
977 if (tid == current_tid) {
978 kernel_debug_string_simple(TRACE_STRING_THREADNAME, ut->pth_name);
979 }
980 }
981
982 void
bsd_copythreadname(void * dst_uth,void * src_uth)983 bsd_copythreadname(void *dst_uth, void *src_uth)
984 {
985 struct uthread *dst_ut = (struct uthread *)dst_uth;
986 struct uthread *src_ut = (struct uthread *)src_uth;
987
988 if (src_ut->pth_name == NULL) {
989 return;
990 }
991
992 if (dst_ut->pth_name == NULL) {
993 dst_ut->pth_name = (char *)kalloc_data(MAXTHREADNAMESIZE, Z_WAITOK);
994 if (dst_ut->pth_name == NULL) {
995 return;
996 }
997 }
998
999 bcopy(src_ut->pth_name, dst_ut->pth_name, MAXTHREADNAMESIZE);
1000 return;
1001 }
1002
1003 void
bsd_threadcdir(void * uth,void * vptr,int * vidp)1004 bsd_threadcdir(void * uth, void *vptr, int *vidp)
1005 {
1006 struct uthread * ut = (struct uthread *)uth;
1007 vnode_t vp;
1008 vnode_t *vpp = (vnode_t *)vptr;
1009
1010 vp = ut->uu_cdir;
1011 if (vp != NULLVP) {
1012 if (vpp != NULL) {
1013 *vpp = vp;
1014 if (vidp != NULL) {
1015 *vidp = vp->v_id;
1016 }
1017 }
1018 }
1019 }
1020
1021
1022 int
proc_pidthreadpathinfo(proc_t p,uint64_t arg,struct proc_threadwithpathinfo * pinfo)1023 proc_pidthreadpathinfo(proc_t p, uint64_t arg, struct proc_threadwithpathinfo *pinfo)
1024 {
1025 vnode_t vp = NULLVP;
1026 int vid;
1027 int error = 0;
1028 uint64_t threadaddr = (uint64_t)arg;
1029 int count;
1030
1031 bzero(pinfo, sizeof(struct proc_threadwithpathinfo));
1032
1033 error = fill_taskthreadinfo(proc_task(p), threadaddr, 0, (struct proc_threadinfo_internal *)&pinfo->pt, (void *)&vp, &vid);
1034 if (error) {
1035 return ESRCH;
1036 }
1037
1038 if ((vp != NULLVP) && ((vnode_getwithvid(vp, vid)) == 0)) {
1039 error = fill_vnodeinfo(vp, &pinfo->pvip.vip_vi, FALSE);
1040 if (error == 0) {
1041 count = MAXPATHLEN;
1042 vn_getpath(vp, &pinfo->pvip.vip_path[0], &count);
1043 pinfo->pvip.vip_path[MAXPATHLEN - 1] = 0;
1044 }
1045 vnode_put(vp);
1046 }
1047 return error;
1048 }
1049
1050
1051
1052 int
proc_pidlistthreads(proc_t p,bool thuniqueid,user_addr_t buffer,uint32_t buffersize,int32_t * retval)1053 proc_pidlistthreads(proc_t p, bool thuniqueid, user_addr_t buffer, uint32_t buffersize, int32_t *retval)
1054 {
1055 uint32_t count = 0;
1056 int ret = 0;
1057 int error = 0;
1058 void * kbuf;
1059 uint32_t numthreads = 0;
1060
1061 int num = get_numthreads(proc_task(p)) + 10;
1062 if (num > 0) {
1063 numthreads = (uint32_t)num;
1064 }
1065
1066 count = buffersize / (sizeof(uint64_t));
1067
1068 if (numthreads > count) {
1069 numthreads = count;
1070 }
1071
1072 kbuf = kalloc_data(numthreads * sizeof(uint64_t), Z_WAITOK | Z_ZERO);
1073 if (kbuf == NULL) {
1074 return ENOMEM;
1075 }
1076
1077 ret = fill_taskthreadlist(proc_task(p), kbuf, numthreads, thuniqueid);
1078
1079 error = copyout(kbuf, buffer, ret);
1080 kfree_data(kbuf, numthreads * sizeof(uint64_t));
1081 if (error == 0) {
1082 *retval = ret;
1083 }
1084 return error;
1085 }
1086
1087
1088 int
proc_pidregioninfo(proc_t p,uint64_t arg,user_addr_t buffer,__unused uint32_t buffersize,int32_t * retval)1089 proc_pidregioninfo(proc_t p, uint64_t arg, user_addr_t buffer, __unused uint32_t buffersize, int32_t *retval)
1090 {
1091 struct proc_regioninfo preginfo;
1092 int ret, error = 0;
1093
1094 bzero(&preginfo, sizeof(struct proc_regioninfo));
1095 ret = fill_procregioninfo(proc_task(p), arg, (struct proc_regioninfo_internal *)&preginfo, (uintptr_t *)0, (uint32_t *)0);
1096 if (ret == 0) {
1097 return EINVAL;
1098 }
1099 error = copyout(&preginfo, buffer, sizeof(struct proc_regioninfo));
1100 if (error == 0) {
1101 *retval = sizeof(struct proc_regioninfo);
1102 }
1103 return error;
1104 }
1105
1106
1107 int
proc_pidregionpathinfo(proc_t p,uint64_t arg,user_addr_t buffer,__unused uint32_t buffersize,int32_t * retval)1108 proc_pidregionpathinfo(proc_t p, uint64_t arg, user_addr_t buffer, __unused uint32_t buffersize, int32_t *retval)
1109 {
1110 struct proc_regionwithpathinfo preginfo;
1111 int ret, error = 0;
1112 uintptr_t vnodeaddr = 0;
1113 uint32_t vnodeid = 0;
1114 vnode_t vp;
1115 int count;
1116
1117 bzero(&preginfo, sizeof(struct proc_regionwithpathinfo));
1118
1119 ret = fill_procregioninfo(proc_task(p), arg, (struct proc_regioninfo_internal *)&preginfo.prp_prinfo, (uintptr_t *)&vnodeaddr, (uint32_t *)&vnodeid);
1120 if (ret == 0) {
1121 return EINVAL;
1122 }
1123 if (vnodeaddr) {
1124 vp = (vnode_t)vnodeaddr;
1125 if ((vnode_getwithvid(vp, vnodeid)) == 0) {
1126 /* FILL THE VNODEINFO */
1127 error = fill_vnodeinfo(vp, &preginfo.prp_vip.vip_vi, FALSE);
1128 count = MAXPATHLEN;
1129 vn_getpath(vp, &preginfo.prp_vip.vip_path[0], &count);
1130 /* Always make sure it is null terminated */
1131 preginfo.prp_vip.vip_path[MAXPATHLEN - 1] = 0;
1132 vnode_put(vp);
1133 }
1134 }
1135 error = copyout(&preginfo, buffer, sizeof(struct proc_regionwithpathinfo));
1136 if (error == 0) {
1137 *retval = sizeof(struct proc_regionwithpathinfo);
1138 }
1139 return error;
1140 }
1141
1142 int
proc_pidregionpathinfo2(proc_t p,uint64_t arg,user_addr_t buffer,__unused uint32_t buffersize,int32_t * retval)1143 proc_pidregionpathinfo2(proc_t p, uint64_t arg, user_addr_t buffer, __unused uint32_t buffersize, int32_t *retval)
1144 {
1145 struct proc_regionwithpathinfo preginfo;
1146 int ret, error = 0;
1147 uintptr_t vnodeaddr = 0;
1148 uint32_t vnodeid = 0;
1149 vnode_t vp;
1150 int count;
1151
1152 bzero(&preginfo, sizeof(struct proc_regionwithpathinfo));
1153
1154 ret = fill_procregioninfo_onlymappedvnodes(proc_task(p), arg, (struct proc_regioninfo_internal *)&preginfo.prp_prinfo, (uintptr_t *)&vnodeaddr, (uint32_t *)&vnodeid);
1155 if (ret == 0) {
1156 return EINVAL;
1157 }
1158 if (!vnodeaddr) {
1159 return EINVAL;
1160 }
1161
1162 vp = (vnode_t)vnodeaddr;
1163 if ((vnode_getwithvid(vp, vnodeid)) == 0) {
1164 /* FILL THE VNODEINFO */
1165 error = fill_vnodeinfo(vp, &preginfo.prp_vip.vip_vi, FALSE);
1166 count = MAXPATHLEN;
1167 vn_getpath(vp, &preginfo.prp_vip.vip_path[0], &count);
1168 /* Always make sure it is null terminated */
1169 preginfo.prp_vip.vip_path[MAXPATHLEN - 1] = 0;
1170 vnode_put(vp);
1171 } else {
1172 return EINVAL;
1173 }
1174
1175 error = copyout(&preginfo, buffer, sizeof(struct proc_regionwithpathinfo));
1176 if (error == 0) {
1177 *retval = sizeof(struct proc_regionwithpathinfo);
1178 }
1179 return error;
1180 }
1181
1182 int
proc_pidregionpath(proc_t p,uint64_t arg,user_addr_t buffer,__unused uint32_t buffersize,int32_t * retval)1183 proc_pidregionpath(proc_t p, uint64_t arg, user_addr_t buffer, __unused uint32_t buffersize, int32_t *retval)
1184 {
1185 struct proc_regionpath path = {};
1186 int ret, error = 0;
1187 uintptr_t vnodeaddr = 0;
1188 uint32_t vnodeid = 0;
1189 vnode_t vp;
1190 bool is_map_shared;
1191
1192 ret = task_find_region_details(proc_task(p), (vm_map_offset_t) arg,
1193 FIND_REGION_DETAILS_OPTIONS_NONE,
1194 (uintptr_t *)&vnodeaddr, (uint32_t *)&vnodeid, &is_map_shared,
1195 &path.prpo_addr, &path.prpo_regionlength);
1196 if (ret == 0) {
1197 return EINVAL;
1198 }
1199 if (!vnodeaddr) {
1200 return EINVAL;
1201 }
1202
1203 vp = (vnode_t)vnodeaddr;
1204 if ((vnode_getwithvid(vp, vnodeid)) == 0) {
1205 int count = MAXPATHLEN;
1206 vn_getpath(vp, &path.prpo_path[0], &count);
1207 /* Always make sure it is null terminated */
1208 path.prpo_path[MAXPATHLEN - 1] = 0;
1209 vnode_put(vp);
1210 } else {
1211 return EINVAL;
1212 }
1213
1214 error = copyout(&path, buffer, sizeof(struct proc_regionpath));
1215 if (error == 0) {
1216 *retval = sizeof(struct proc_regionpath);
1217 }
1218 return error;
1219 }
1220
1221 int
proc_pidregionpathinfo3(proc_t p,uint64_t arg,user_addr_t buffer,__unused uint32_t buffersize,int32_t * retval)1222 proc_pidregionpathinfo3(proc_t p, uint64_t arg, user_addr_t buffer, __unused uint32_t buffersize, int32_t *retval)
1223 {
1224 struct proc_regionwithpathinfo preginfo;
1225 int ret, error = 0;
1226 uintptr_t vnodeaddr;
1227 uint32_t vnodeid;
1228 vnode_t vp;
1229 int count;
1230 uint64_t addr = 0;
1231
1232 /* Loop while looking for vnodes that match dev_t filter */
1233 do {
1234 bzero(&preginfo, sizeof(struct proc_regionwithpathinfo));
1235 vnodeaddr = 0;
1236 vnodeid = 0;
1237
1238 ret = fill_procregioninfo_onlymappedvnodes(proc_task(p), addr, (struct proc_regioninfo_internal *)&preginfo.prp_prinfo, (uintptr_t *)&vnodeaddr, (uint32_t *)&vnodeid);
1239 if (ret == 0) {
1240 return EINVAL;
1241 }
1242 if (!vnodeaddr) {
1243 return EINVAL;
1244 }
1245
1246 vp = (vnode_t)vnodeaddr;
1247 if ((vnode_getwithvid(vp, vnodeid)) == 0) {
1248 /* Check if the vnode matches the filter, otherwise loop looking for the next memory region backed by a vnode */
1249 struct vnode_attr va;
1250
1251 memset(&va, 0, sizeof(va));
1252 VATTR_INIT(&va);
1253 VATTR_WANTED(&va, va_fsid);
1254 VATTR_WANTED(&va, va_fsid64);
1255
1256 ret = vnode_getattr(vp, &va, vfs_context_current());
1257 if (ret) {
1258 vnode_put(vp);
1259 return EINVAL;
1260 }
1261
1262 if (vnode_get_va_fsid(&va) == arg) {
1263 /* FILL THE VNODEINFO */
1264 error = fill_vnodeinfo(vp, &preginfo.prp_vip.vip_vi, FALSE);
1265 count = MAXPATHLEN;
1266 vn_getpath(vp, &preginfo.prp_vip.vip_path[0], &count);
1267 /* Always make sure it is null terminated */
1268 preginfo.prp_vip.vip_path[MAXPATHLEN - 1] = 0;
1269 vnode_put(vp);
1270 break;
1271 }
1272 vnode_put(vp);
1273 } else {
1274 return EINVAL;
1275 }
1276
1277 addr = preginfo.prp_prinfo.pri_address + preginfo.prp_prinfo.pri_size;
1278 } while (1);
1279
1280 error = copyout(&preginfo, buffer, sizeof(struct proc_regionwithpathinfo));
1281 if (error == 0) {
1282 *retval = sizeof(struct proc_regionwithpathinfo);
1283 }
1284 return error;
1285 }
1286
1287 /*
1288 * Path is relative to current process directory; may different from current
1289 * thread directory.
1290 */
1291 int
proc_pidvnodepathinfo(proc_t p,__unused uint64_t arg,user_addr_t buffer,__unused uint32_t buffersize,int32_t * retval)1292 proc_pidvnodepathinfo(proc_t p, __unused uint64_t arg, user_addr_t buffer, __unused uint32_t buffersize, int32_t *retval)
1293 {
1294 struct proc_vnodepathinfo pvninfo;
1295 int error = 0;
1296 vnode_t vncdirvp = NULLVP;
1297 uint32_t vncdirid = 0;
1298 vnode_t vnrdirvp = NULLVP;
1299 uint32_t vnrdirid = 0;
1300 int count;
1301
1302 bzero(&pvninfo, sizeof(struct proc_vnodepathinfo));
1303
1304 proc_fdlock(p);
1305 if (p->p_fd.fd_cdir) {
1306 vncdirvp = p->p_fd.fd_cdir;
1307 vncdirid = p->p_fd.fd_cdir->v_id;
1308 }
1309 if (p->p_fd.fd_rdir) {
1310 vnrdirvp = p->p_fd.fd_rdir;
1311 vnrdirid = p->p_fd.fd_rdir->v_id;
1312 }
1313 proc_fdunlock(p);
1314
1315 if (vncdirvp != NULLVP) {
1316 if ((error = vnode_getwithvid(vncdirvp, vncdirid)) == 0) {
1317 /* FILL THE VNODEINFO */
1318 error = fill_vnodeinfo(vncdirvp, &pvninfo.pvi_cdir.vip_vi, TRUE);
1319 if (error == 0) {
1320 count = MAXPATHLEN;
1321 vn_getpath(vncdirvp, &pvninfo.pvi_cdir.vip_path[0], &count);
1322 pvninfo.pvi_cdir.vip_path[MAXPATHLEN - 1] = 0;
1323 }
1324 vnode_put(vncdirvp);
1325 } else {
1326 goto out;
1327 }
1328 }
1329
1330 if ((error == 0) && (vnrdirvp != NULLVP)) {
1331 if ((error = vnode_getwithvid(vnrdirvp, vnrdirid)) == 0) {
1332 /* FILL THE VNODEINFO */
1333 error = fill_vnodeinfo(vnrdirvp, &pvninfo.pvi_rdir.vip_vi, TRUE);
1334 if (error == 0) {
1335 count = MAXPATHLEN;
1336 vn_getpath(vnrdirvp, &pvninfo.pvi_rdir.vip_path[0], &count);
1337 pvninfo.pvi_rdir.vip_path[MAXPATHLEN - 1] = 0;
1338 }
1339 vnode_put(vnrdirvp);
1340 } else {
1341 goto out;
1342 }
1343 }
1344 if (error == 0) {
1345 error = copyout(&pvninfo, buffer, sizeof(struct proc_vnodepathinfo));
1346 if (error == 0) {
1347 *retval = sizeof(struct proc_vnodepathinfo);
1348 }
1349 }
1350 out:
1351 return error;
1352 }
1353
1354 int
proc_pidpathinfo(proc_t p,__unused uint64_t arg,user_addr_t buffer,uint32_t buffersize,__unused int32_t * retval)1355 proc_pidpathinfo(proc_t p, __unused uint64_t arg, user_addr_t buffer, uint32_t buffersize, __unused int32_t *retval)
1356 {
1357 int error;
1358 vnode_t tvp;
1359 int len = buffersize;
1360 char * buf;
1361
1362 tvp = p->p_textvp;
1363
1364 if (tvp == NULLVP) {
1365 return ESRCH;
1366 }
1367
1368 buf = (char *)kalloc_data(buffersize, Z_WAITOK | Z_ZERO);
1369 if (buf == NULL) {
1370 return ENOMEM;
1371 }
1372
1373 error = proc_pidpathinfo_internal(p, arg, buf, buffersize, retval);
1374 if (error == 0) {
1375 error = copyout(buf, buffer, len);
1376 }
1377 kfree_data(buf, buffersize);
1378 return error;
1379 }
1380
1381 int
proc_pidpathinfo_internal(proc_t p,__unused uint64_t arg,char * buf,uint32_t buffersize,__unused int32_t * retval)1382 proc_pidpathinfo_internal(proc_t p, __unused uint64_t arg, char *buf, uint32_t buffersize, __unused int32_t *retval)
1383 {
1384 vnode_t tvp;
1385 int vid, error;
1386 int len = buffersize;
1387
1388 tvp = p->p_textvp;
1389
1390 if (tvp == NULLVP) {
1391 return ESRCH;
1392 }
1393
1394 vid = vnode_vid(tvp);
1395 error = vnode_getwithvid(tvp, vid);
1396 if (error == 0) {
1397 error = vn_getpath_fsenter(tvp, buf, &len);
1398 if (!error) {
1399 error = vnode_ref_ext(tvp, O_EVTONLY, 0);
1400 }
1401 vnode_put(tvp);
1402 if (error == 0) {
1403 vnode_t nvp = NULLVP;
1404
1405 error = vnode_lookup(buf, 0, &nvp, vfs_context_current());
1406 if (error == 0) {
1407 vnode_put(nvp);
1408 nvp = NULLVP;
1409 } else if (vnode_isrecycled(tvp)) {
1410 error = ESRCH;
1411 } else {
1412 if (vnode_getwithvid(tvp, vid) == 0) {
1413 mount_t mp = vnode_mount(tvp);
1414
1415 if (vfs_isunmount(mp)) {
1416 error = ESRCH;
1417 }
1418 vnode_put(tvp);
1419 } else {
1420 error = ESRCH;
1421 }
1422 if (error == EACCES) {
1423 vfs_context_t ctx = vfs_context_current();
1424 #if DEVELOPMENT || DEBUG
1425 os_log(OS_LOG_DEFAULT, "%s : EACCES returned by vnode_lookup for path %s for uid %d\n", __FUNCTION__, buf, (int)kauth_cred_getuid(ctx->vc_ucred));
1426 #else
1427 os_log(OS_LOG_DEFAULT, "%s : EACCES returned by vnode_lookup for uid %d\n", __FUNCTION__, (int)kauth_cred_getuid(ctx->vc_ucred));
1428 #endif
1429
1430 nvp = NULLVP;
1431 error = vnode_lookup(buf, 0, &nvp, vfs_context_kernel());
1432
1433 if (error == 0) {
1434 vnode_put(nvp);
1435 nvp = NULLVP;
1436 } else if (error == EACCES) {
1437 #if DEVELOPMENT || DEBUG
1438 os_log(OS_LOG_DEFAULT, "%s : EACCES returned by vnode_lookup for path %s for uid 0\n", __FUNCTION__, buf);
1439 #else
1440 os_log(OS_LOG_DEFAULT, "%s : EACCES returned by vnode_lookup for uid 0\n", __FUNCTION__);
1441 #endif
1442 /* This should be a panic for a local FS */
1443 error = ENODEV;
1444 } else {
1445 #if DEVELOPMENT || DEBUG
1446 os_log(OS_LOG_DEFAULT, "%s : vnode_lookup for path %s returned error %d\n",
1447 __FUNCTION__, buf, error);
1448 #else
1449 os_log(OS_LOG_DEFAULT, "%s : vnode_lookup returned error %d\n",
1450 __FUNCTION__, error);
1451 #endif
1452 }
1453 }
1454 }
1455 vnode_rele_ext(tvp, O_EVTONLY, 0);
1456 } else {
1457 error = ESRCH;
1458 }
1459 } else {
1460 error = ESRCH;
1461 }
1462 return error;
1463 }
1464
1465
1466 int
proc_pidworkqueueinfo(proc_t p,struct proc_workqueueinfo * pwqinfo)1467 proc_pidworkqueueinfo(proc_t p, struct proc_workqueueinfo *pwqinfo)
1468 {
1469 int error = 0;
1470
1471 bzero(pwqinfo, sizeof(struct proc_workqueueinfo));
1472
1473 error = fill_procworkqueue(p, pwqinfo);
1474 if (error) {
1475 return ESRCH;
1476 } else {
1477 return 0;
1478 }
1479 }
1480
1481
1482 void
proc_piduniqidentifierinfo(proc_t p,struct proc_uniqidentifierinfo * p_uniqidinfo)1483 proc_piduniqidentifierinfo(proc_t p, struct proc_uniqidentifierinfo *p_uniqidinfo)
1484 {
1485 p_uniqidinfo->p_uniqueid = proc_uniqueid(p);
1486 proc_getexecutableuuid(p, (unsigned char *)&p_uniqidinfo->p_uuid, sizeof(p_uniqidinfo->p_uuid));
1487 p_uniqidinfo->p_puniqueid = proc_puniqueid(p);
1488 p_uniqidinfo->p_idversion = proc_pidversion(p);
1489 p_uniqidinfo->p_orig_ppidversion = proc_orig_ppidversion(p);
1490 p_uniqidinfo->p_reserve2 = 0;
1491 p_uniqidinfo->p_reserve3 = 0;
1492 }
1493
1494
1495 static int
proc_piduuidinfo(pid_t pid,uuid_t uuid_buf,uint32_t buffersize)1496 proc_piduuidinfo(pid_t pid, uuid_t uuid_buf, uint32_t buffersize)
1497 {
1498 struct proc * p = PROC_NULL;
1499 int zombref = 0;
1500
1501 if (buffersize < sizeof(uuid_t)) {
1502 return EINVAL;
1503 }
1504
1505 if ((p = proc_find(pid)) == PROC_NULL) {
1506 p = proc_find_zombref(pid);
1507 zombref = 1;
1508 }
1509 if (p == PROC_NULL) {
1510 return ESRCH;
1511 }
1512
1513 proc_getexecutableuuid(p, (unsigned char *)uuid_buf, buffersize);
1514
1515 if (zombref) {
1516 proc_drop_zombref(p);
1517 } else {
1518 proc_rele(p);
1519 }
1520
1521 return 0;
1522 }
1523
1524 /*
1525 * Function to get the uuid and pid of the originator of the voucher.
1526 */
1527 int
proc_pidoriginatorpid_uuid(uuid_t uuid,uint32_t buffersize,pid_t * pid)1528 proc_pidoriginatorpid_uuid(uuid_t uuid, uint32_t buffersize, pid_t *pid)
1529 {
1530 pid_t originator_pid;
1531 kern_return_t kr;
1532 int error;
1533
1534 /*
1535 * Get the current voucher origin pid. The pid returned here
1536 * might not be valid or may have been recycled.
1537 */
1538 kr = thread_get_current_voucher_origin_pid(&originator_pid);
1539 /* If errors, convert errors to appropriate format */
1540 if (kr) {
1541 if (kr == KERN_INVALID_TASK) {
1542 error = ESRCH;
1543 } else if (kr == KERN_INVALID_VALUE) {
1544 error = ENOATTR;
1545 } else {
1546 error = EINVAL;
1547 }
1548 return error;
1549 }
1550
1551 *pid = originator_pid;
1552 error = proc_piduuidinfo(originator_pid, uuid, buffersize);
1553 return error;
1554 }
1555
1556 /*
1557 * Function to get the uuid of the originator of the voucher.
1558 */
1559 int
proc_pidoriginatoruuid(uuid_t uuid,uint32_t buffersize)1560 proc_pidoriginatoruuid(uuid_t uuid, uint32_t buffersize)
1561 {
1562 pid_t originator_pid;
1563 return proc_pidoriginatorpid_uuid(uuid, buffersize, &originator_pid);
1564 }
1565
1566 /*
1567 * Function to get the task ipc table size.
1568 */
1569 int
proc_pidipctableinfo(proc_t p,struct proc_ipctableinfo * table_info)1570 proc_pidipctableinfo(proc_t p, struct proc_ipctableinfo *table_info)
1571 {
1572 task_t task;
1573 int error = 0;
1574
1575 task = proc_task(p);
1576
1577 bzero(table_info, sizeof(struct proc_ipctableinfo));
1578 error = fill_taskipctableinfo(task, &(table_info->table_size), &(table_info->table_free));
1579
1580 if (error) {
1581 error = EINVAL;
1582 }
1583
1584 return error;
1585 }
1586
1587 int
proc_pidthreadschedinfo(proc_t p,uint64_t arg,struct proc_threadschedinfo * sched_info)1588 proc_pidthreadschedinfo(proc_t p, uint64_t arg, struct proc_threadschedinfo *sched_info)
1589 {
1590 int error;
1591 uint64_t const thread_id = (uint64_t)arg;
1592 task_t const task = proc_task(p);
1593
1594 bzero(sched_info, sizeof(*sched_info));
1595 error = fill_taskthreadschedinfo(task, thread_id, (struct proc_threadschedinfo_internal*)sched_info);
1596
1597 if (error != 0) {
1598 error = EINVAL;
1599 }
1600
1601 return error;
1602 }
1603
1604 /***************************** proc_pidoriginatorinfo ***************************/
1605
1606 int
proc_pidoriginatorinfo(int pid,int flavor,user_addr_t buffer,uint32_t buffersize,int32_t * retval)1607 proc_pidoriginatorinfo(int pid, int flavor, user_addr_t buffer, uint32_t buffersize, int32_t * retval)
1608 {
1609 int error = ENOTSUP;
1610 uint32_t size;
1611
1612 switch (flavor) {
1613 case PROC_PIDORIGINATOR_UUID:
1614 size = PROC_PIDORIGINATOR_UUID_SIZE;
1615 break;
1616 case PROC_PIDORIGINATOR_BGSTATE:
1617 size = PROC_PIDORIGINATOR_BGSTATE_SIZE;
1618 break;
1619 case PROC_PIDORIGINATOR_PID_UUID:
1620 size = PROC_PIDORIGINATOR_PID_UUID_SIZE;
1621 break;
1622 default:
1623 return EINVAL;
1624 }
1625
1626 if (buffersize < size) {
1627 return ENOMEM;
1628 }
1629
1630 if (pid != 0 && pid != proc_selfpid()) {
1631 return EINVAL;
1632 }
1633
1634 switch (flavor) {
1635 case PROC_PIDORIGINATOR_UUID: {
1636 uuid_t uuid = {};
1637
1638 error = proc_pidoriginatoruuid(uuid, sizeof(uuid));
1639 if (error != 0) {
1640 goto out;
1641 }
1642
1643 error = copyout(uuid, buffer, size);
1644 if (error == 0) {
1645 *retval = size;
1646 }
1647 }
1648 break;
1649
1650 case PROC_PIDORIGINATOR_PID_UUID: {
1651 struct proc_originatorinfo originator_info;
1652 bzero(&originator_info, sizeof(originator_info));
1653
1654 error = proc_pidoriginatorpid_uuid(originator_info.originator_uuid,
1655 sizeof(uuid_t), &originator_info.originator_pid);
1656 if (error != 0) {
1657 goto out;
1658 }
1659
1660 error = copyout(&originator_info, buffer, size);
1661 if (error == 0) {
1662 *retval = size;
1663 }
1664 }
1665 break;
1666
1667 case PROC_PIDORIGINATOR_BGSTATE: {
1668 uint32_t is_backgrounded = 0;
1669 error = proc_get_originatorbgstate(&is_backgrounded);
1670 if (error) {
1671 goto out;
1672 }
1673
1674 error = copyout(&is_backgrounded, buffer, size);
1675 if (error == 0) {
1676 *retval = size;
1677 }
1678 }
1679 break;
1680
1681 default:
1682 error = ENOTSUP;
1683 }
1684 out:
1685 return error;
1686 }
1687
1688 /***************************** proc_listcoalitions ***************************/
1689 int
proc_listcoalitions(int flavor,int type,user_addr_t buffer,uint32_t buffersize,int32_t * retval)1690 proc_listcoalitions(int flavor, int type, user_addr_t buffer,
1691 uint32_t buffersize, int32_t *retval)
1692 {
1693 #if CONFIG_COALITIONS
1694 int error;
1695 int coal_type;
1696 size_t elem_size;
1697 void *coalinfo = NULL;
1698 size_t k_buffersize = 0;
1699 size_t copyoutsize = 0;
1700 size_t ncoals = 0;
1701 size_t ncoals2 = 0;
1702
1703 switch (flavor) {
1704 case LISTCOALITIONS_ALL_COALS:
1705 elem_size = LISTCOALITIONS_ALL_COALS_SIZE;
1706 coal_type = -1;
1707 break;
1708 case LISTCOALITIONS_SINGLE_TYPE:
1709 elem_size = LISTCOALITIONS_SINGLE_TYPE_SIZE;
1710 coal_type = type;
1711 break;
1712 default:
1713 return EINVAL;
1714 }
1715
1716 ncoals = coalitions_get_list(coal_type, NULL, 0);
1717
1718 if (ncoals == 0 || buffer == 0 || buffersize == 0) {
1719 *retval = (int32_t)(ncoals * elem_size);
1720 return 0;
1721 }
1722
1723 if (os_mul_overflow(ncoals, elem_size, &k_buffersize)) {
1724 return ENOMEM;
1725 }
1726
1727 coalinfo = kalloc_data(k_buffersize, Z_WAITOK | Z_ZERO);
1728 if (!coalinfo) {
1729 return ENOMEM;
1730 }
1731
1732 ncoals2 = coalitions_get_list(coal_type, coalinfo, ncoals);
1733
1734 copyoutsize = MIN(buffersize, MIN(ncoals2, ncoals) * elem_size);
1735
1736 if (!(error = copyout(coalinfo, buffer, copyoutsize))) {
1737 *retval = (int32_t)copyoutsize;
1738 }
1739
1740 kfree_data(coalinfo, k_buffersize);
1741 return error;
1742 #else
1743 /* no coalition support */
1744 (void)flavor;
1745 (void)type;
1746 (void)buffer;
1747 (void)buffersize;
1748 (void)retval;
1749 return ENOTSUP;
1750 #endif
1751 }
1752
1753
1754 /*************************** proc_can_use_forgeound_hw **************************/
1755 int
proc_can_use_foreground_hw(int pid,user_addr_t u_reason,uint32_t reasonsize,int32_t * retval)1756 proc_can_use_foreground_hw(int pid, user_addr_t u_reason, uint32_t reasonsize, int32_t *retval)
1757 {
1758 proc_t p = PROC_NULL;
1759 int error = 0;
1760 uint32_t reason = PROC_FGHW_ERROR;
1761 uint32_t isBG = 0;
1762 task_t task = TASK_NULL;
1763 #if CONFIG_COALITIONS
1764 coalition_t coal = COALITION_NULL;
1765 #endif
1766
1767 *retval = 0;
1768
1769 if (pid <= 0) {
1770 error = EINVAL;
1771 reason = PROC_FGHW_ERROR;
1772 goto out;
1773 }
1774
1775 p = proc_find(pid);
1776 if (p == PROC_NULL) {
1777 error = ESRCH;
1778 reason = PROC_FGHW_ERROR;
1779 goto out;
1780 }
1781
1782 #if CONFIG_COALITIONS
1783 if (p != current_proc() &&
1784 !kauth_cred_issuser(kauth_cred_get())) {
1785 error = EPERM;
1786 reason = PROC_FGHW_ERROR;
1787 goto out;
1788 }
1789
1790 task = proc_task(p);
1791 if (coalition_is_leader(task, task_get_coalition(task, COALITION_TYPE_JETSAM))) {
1792 task_reference(task);
1793 } else {
1794 /* current task is not a coalition leader: find the leader */
1795 task = coalition_get_leader(coal);
1796 }
1797
1798 if (task != TASK_NULL) {
1799 /*
1800 * If task is non-null, then it is the coalition leader of the
1801 * current process' coalition. This could be the same task as
1802 * the current_task, and that's OK.
1803 */
1804 uint32_t flags = 0;
1805 int role;
1806
1807 proc_get_darwinbgstate(task, &flags);
1808 if ((flags & PROC_FLAG_APPLICATION) != PROC_FLAG_APPLICATION) {
1809 /*
1810 * Coalition leader is not an application, continue
1811 * searching for other ways this task could gain
1812 * access to HW
1813 */
1814 reason = PROC_FGHW_DAEMON_LEADER;
1815 goto no_leader;
1816 }
1817
1818 if (proc_get_effective_task_policy(task, TASK_POLICY_DARWIN_BG)) {
1819 /*
1820 * If the leader of the current process' coalition has
1821 * been marked as DARWIN_BG, then it definitely should
1822 * not be using foreground hardware resources.
1823 */
1824 reason = PROC_FGHW_LEADER_BACKGROUND;
1825 goto out;
1826 }
1827
1828 role = proc_get_effective_task_policy(task, TASK_POLICY_ROLE);
1829 switch (role) {
1830 case TASK_FOREGROUND_APPLICATION: /* DARWIN_ROLE_UI_FOCAL */
1831 case TASK_BACKGROUND_APPLICATION: /* DARWIN_ROLE_UI */
1832 /*
1833 * The leader of this coalition is a focal, UI app:
1834 * access granted
1835 * TODO: should extensions/plugins be allowed to use
1836 * this hardware?
1837 */
1838 *retval = 1;
1839 reason = PROC_FGHW_OK;
1840 goto out;
1841 case TASK_DEFAULT_APPLICATION: /* DARWIN_ROLE_UI_NON_FOCAL */
1842 case TASK_NONUI_APPLICATION: /* DARWIN_ROLE_NON_UI */
1843 case TASK_THROTTLE_APPLICATION:
1844 case TASK_UNSPECIFIED:
1845 default:
1846 /* non-focal, non-ui apps don't get access */
1847 reason = PROC_FGHW_LEADER_NONUI;
1848 goto out;
1849 }
1850 }
1851
1852 no_leader:
1853 if (task != TASK_NULL) {
1854 task_deallocate(task);
1855 task = TASK_NULL;
1856 }
1857 #endif /* CONFIG_COALITIONS */
1858
1859 /*
1860 * There is no reasonable semantic to investigate the currently
1861 * adopted voucher of an arbitrary thread in a non-current process.
1862 * We return '0'
1863 */
1864 if (p != current_proc()) {
1865 error = EINVAL;
1866 goto out;
1867 }
1868
1869 /*
1870 * In the absence of coalitions, fall back to a voucher-based lookup
1871 * where a daemon can used foreground HW if it's operating on behalf
1872 * of a foreground application.
1873 * NOTE: this is equivalent to a call to
1874 * proc_pidoriginatorinfo(PROC_PIDORIGINATOR_BGSTATE, &isBG, sizeof(isBG))
1875 */
1876 isBG = 1;
1877 error = proc_get_originatorbgstate(&isBG);
1878 switch (error) {
1879 case 0:
1880 break;
1881 case ESRCH:
1882 reason = PROC_FGHW_NO_ORIGINATOR;
1883 error = 0;
1884 goto out;
1885 case ENOATTR:
1886 reason = PROC_FGHW_NO_VOUCHER_ATTR;
1887 error = 0;
1888 goto out;
1889 case EINVAL:
1890 reason = PROC_FGHW_DAEMON_NO_VOUCHER;
1891 error = 0;
1892 goto out;
1893 default:
1894 /* some other error occurred: report that to the caller */
1895 reason = PROC_FGHW_VOUCHER_ERROR;
1896 goto out;
1897 }
1898
1899 if (isBG) {
1900 reason = PROC_FGHW_ORIGINATOR_BACKGROUND;
1901 error = 0;
1902 } else {
1903 /*
1904 * The process itself is either a foreground app, or has
1905 * adopted a voucher originating from an app that's still in
1906 * the foreground
1907 */
1908 reason = PROC_FGHW_DAEMON_OK;
1909 *retval = 1;
1910 }
1911
1912 out:
1913 if (task != TASK_NULL) {
1914 task_deallocate(task);
1915 }
1916 if (p != PROC_NULL) {
1917 proc_rele(p);
1918 }
1919 if (reasonsize >= sizeof(reason) && u_reason != (user_addr_t)0) {
1920 (void)copyout(&reason, u_reason, sizeof(reason));
1921 }
1922 return error;
1923 }
1924
1925 #ifndef MIN_TO_SEC
1926 #define MIN_TO_SEC(x) ((x) * 60)
1927 #endif
1928 /**
1929 * Send a crash report for unpermitted proc_pidinfo calls on the kernel pid.
1930 * Throttles to one report every 10 minutes.
1931 */
1932 static void __attribute__((noinline))
PROC_UNPERMITTED_PIDINFO_FLAVOR(void)1933 PROC_UNPERMITTED_PIDINFO_FLAVOR(void)
1934 {
1935 static clock_sec_t before = 0;
1936 clock_sec_t now;
1937 clock_nsec_t nsec;
1938 mach_exception_data_type_t code[EXCEPTION_CODE_MAX] = {0};
1939
1940 clock_get_system_nanotime(&now, &nsec);
1941
1942 /**
1943 * This can race, and if it does, it means a crash report was very recently
1944 * sent in another thread, so return early.
1945 */
1946 if (now < before) {
1947 return;
1948 }
1949
1950 /**
1951 * If 10 minutes have not passed since the last time we sent a crash report,
1952 * do nothing.
1953 */
1954 if ((now - before) < MIN_TO_SEC(10)) {
1955 return;
1956 }
1957
1958 before = now;
1959
1960 /* We're rejecting the proc_info syscall */
1961 EXC_GUARD_ENCODE_TYPE(code[0], GUARD_TYPE_REJECTED_SC);
1962 code[1] = SYS_proc_info;
1963 task_enqueue_exception_with_corpse(current_task(), EXC_GUARD, code, EXCEPTION_CODE_MAX, NULL, TRUE);
1964 }
1965
1966 /********************************** proc_pidinfo ********************************/
1967
1968
1969 int
proc_pidinfo(int pid,uint32_t flags,uint64_t ext_id,int flavor,uint64_t arg,user_addr_t buffer,uint32_t buffersize,int32_t * retval)1970 proc_pidinfo(int pid, uint32_t flags, uint64_t ext_id, int flavor, uint64_t arg, user_addr_t buffer, uint32_t buffersize, int32_t * retval)
1971 {
1972 struct proc * p = PROC_NULL;
1973 int error = ENOTSUP;
1974 int gotref = 0;
1975 int findzomb = 0;
1976 int shortversion = 0;
1977 uint32_t size;
1978 int zombie = 0;
1979 bool thuniqueid = false;
1980 int uniqidversion = 0;
1981 bool check_same_user;
1982 pid_t current_pid = proc_pid(current_proc());
1983
1984 /**
1985 * Before we move forward, we should check if an unpermitted operation is
1986 * attempted on the kernel task.
1987 */
1988 if (pid == 0) {
1989 switch (flavor) {
1990 case PROC_PIDWORKQUEUEINFO:
1991 /* kernel does not have workq info */
1992 return EINVAL;
1993 case PROC_PIDREGIONPATH:
1994 case PROC_PIDREGIONINFO:
1995 case PROC_PIDREGIONPATHINFO:
1996 case PROC_PIDREGIONPATHINFO2:
1997 case PROC_PIDREGIONPATHINFO3:
1998 /* This operation is not permitted on the kernel */
1999 if (current_pid != pid) {
2000 PROC_UNPERMITTED_PIDINFO_FLAVOR();
2001 return EPERM;
2002 }
2003 break;
2004 }
2005 }
2006
2007 switch (flavor) {
2008 case PROC_PIDLISTFDS:
2009 size = PROC_PIDLISTFD_SIZE;
2010 if (buffer == USER_ADDR_NULL) {
2011 size = 0;
2012 }
2013 break;
2014 case PROC_PIDTBSDINFO:
2015 size = PROC_PIDTBSDINFO_SIZE;
2016 break;
2017 case PROC_PIDTASKINFO:
2018 size = PROC_PIDTASKINFO_SIZE;
2019 break;
2020 case PROC_PIDTASKALLINFO:
2021 size = PROC_PIDTASKALLINFO_SIZE;
2022 break;
2023 case PROC_PIDTHREADINFO:
2024 size = PROC_PIDTHREADINFO_SIZE;
2025 break;
2026 case PROC_PIDTHREADCOUNTS:
2027 size = PROC_PIDTHREADCOUNTS_SIZE;
2028 break;
2029 case PROC_PIDLISTTHREADIDS:
2030 size = PROC_PIDLISTTHREADIDS_SIZE;
2031 break;
2032 case PROC_PIDLISTTHREADS:
2033 size = PROC_PIDLISTTHREADS_SIZE;
2034 break;
2035 case PROC_PIDREGIONINFO:
2036 size = PROC_PIDREGIONINFO_SIZE;
2037 break;
2038 case PROC_PIDREGIONPATHINFO:
2039 size = PROC_PIDREGIONPATHINFO_SIZE;
2040 break;
2041 case PROC_PIDVNODEPATHINFO:
2042 size = PROC_PIDVNODEPATHINFO_SIZE;
2043 break;
2044 case PROC_PIDTHREADPATHINFO:
2045 size = PROC_PIDTHREADPATHINFO_SIZE;
2046 break;
2047 case PROC_PIDPATHINFO:
2048 size = MAXPATHLEN;
2049 break;
2050 case PROC_PIDWORKQUEUEINFO:
2051 size = PROC_PIDWORKQUEUEINFO_SIZE;
2052 break;
2053 case PROC_PIDT_SHORTBSDINFO:
2054 size = PROC_PIDT_SHORTBSDINFO_SIZE;
2055 break;
2056 case PROC_PIDLISTFILEPORTS:
2057 size = PROC_PIDLISTFILEPORTS_SIZE;
2058 if (buffer == (user_addr_t)0) {
2059 size = 0;
2060 }
2061 break;
2062 case PROC_PIDTHREADID64INFO:
2063 size = PROC_PIDTHREADID64INFO_SIZE;
2064 break;
2065 case PROC_PIDUNIQIDENTIFIERINFO:
2066 size = PROC_PIDUNIQIDENTIFIERINFO_SIZE;
2067 break;
2068 case PROC_PIDT_BSDINFOWITHUNIQID:
2069 size = PROC_PIDT_BSDINFOWITHUNIQID_SIZE;
2070 break;
2071 case PROC_PIDARCHINFO:
2072 size = PROC_PIDARCHINFO_SIZE;
2073 break;
2074 case PROC_PIDCOALITIONINFO:
2075 size = PROC_PIDCOALITIONINFO_SIZE;
2076 break;
2077 case PROC_PIDNOTEEXIT:
2078 /*
2079 * Set findzomb explicitly because arg passed
2080 * in is used as note exit status bits.
2081 */
2082 size = PROC_PIDNOTEEXIT_SIZE;
2083 findzomb = 1;
2084 break;
2085 case PROC_PIDEXITREASONINFO:
2086 size = PROC_PIDEXITREASONINFO_SIZE;
2087 findzomb = 1;
2088 break;
2089 case PROC_PIDEXITREASONBASICINFO:
2090 size = PROC_PIDEXITREASONBASICINFOSIZE;
2091 findzomb = 1;
2092 break;
2093 case PROC_PIDREGIONPATHINFO2:
2094 size = PROC_PIDREGIONPATHINFO2_SIZE;
2095 break;
2096 case PROC_PIDREGIONPATHINFO3:
2097 size = PROC_PIDREGIONPATHINFO3_SIZE;
2098 break;
2099 case PROC_PIDLISTUPTRS:
2100 size = PROC_PIDLISTUPTRS_SIZE;
2101 if (buffer == USER_ADDR_NULL) {
2102 size = 0;
2103 }
2104 break;
2105 case PROC_PIDLISTDYNKQUEUES:
2106 size = PROC_PIDLISTDYNKQUEUES_SIZE;
2107 if (buffer == USER_ADDR_NULL) {
2108 size = 0;
2109 }
2110 break;
2111 case PROC_PIDVMRTFAULTINFO:
2112 size = sizeof(vm_rtfault_record_t);
2113 if (buffer == USER_ADDR_NULL) {
2114 size = 0;
2115 }
2116 break;
2117 case PROC_PIDPLATFORMINFO:
2118 size = PROC_PIDPLATFORMINFO_SIZE;
2119 findzomb = 1;
2120 break;
2121 case PROC_PIDREGIONPATH:
2122 size = PROC_PIDREGIONPATH_SIZE;
2123 break;
2124 case PROC_PIDIPCTABLEINFO:
2125 size = PROC_PIDIPCTABLEINFO_SIZE;
2126 break;
2127 case PROC_PIDTHREADSCHEDINFO:
2128 size = PROC_PIDTHREADSCHEDINFO_SIZE;
2129 break;
2130 default:
2131 return EINVAL;
2132 }
2133
2134 if (buffersize < size) {
2135 return ENOMEM;
2136 }
2137
2138 if ((flavor == PROC_PIDPATHINFO) && (buffersize > PROC_PIDPATHINFO_MAXSIZE)) {
2139 return EOVERFLOW;
2140 }
2141
2142 /* Check if we need to look for zombies */
2143 if ((flavor == PROC_PIDTBSDINFO) || (flavor == PROC_PIDT_SHORTBSDINFO) || (flavor == PROC_PIDT_BSDINFOWITHUNIQID)
2144 || (flavor == PROC_PIDUNIQIDENTIFIERINFO)) {
2145 if (arg) {
2146 findzomb = 1;
2147 }
2148 }
2149
2150 if ((p = proc_find(pid)) == PROC_NULL) {
2151 if (findzomb) {
2152 p = proc_find_zombref(pid);
2153 }
2154 if (p == PROC_NULL) {
2155 error = ESRCH;
2156 goto out;
2157 }
2158 zombie = 1;
2159 } else {
2160 gotref = 1;
2161 }
2162
2163 if ((flags & PIF_COMPARE_IDVERSION) && (ext_id != proc_pidversion(p))) {
2164 error = ESRCH;
2165 goto out;
2166 }
2167 if ((flags & PIF_COMPARE_UNIQUEID) && (ext_id != proc_uniqueid(p))) {
2168 error = ESRCH;
2169 goto out;
2170 }
2171
2172 /* Certain operations don't require privileges */
2173 switch (flavor) {
2174 case PROC_PIDT_SHORTBSDINFO:
2175 case PROC_PIDUNIQIDENTIFIERINFO:
2176 case PROC_PIDPATHINFO:
2177 case PROC_PIDCOALITIONINFO:
2178 case PROC_PIDPLATFORMINFO:
2179 check_same_user = NO_CHECK_SAME_USER;
2180 break;
2181 default:
2182 check_same_user = CHECK_SAME_USER;
2183 break;
2184 }
2185
2186 /* Do we have permission to look into this? */
2187 if ((error = proc_security_policy(p, PROC_INFO_CALL_PIDINFO, flavor, check_same_user))) {
2188 goto out;
2189 }
2190
2191 switch (flavor) {
2192 case PROC_PIDLISTFDS: {
2193 if ((error = proc_security_policy(p, PROC_INFO_CALL_PIDFDINFO, flavor, check_same_user))) {
2194 goto out;
2195 }
2196 error = proc_pidfdlist(p, buffer, buffersize, retval);
2197 }
2198 break;
2199
2200 case PROC_PIDUNIQIDENTIFIERINFO: {
2201 struct proc_uniqidentifierinfo p_uniqidinfo;
2202 bzero(&p_uniqidinfo, sizeof(p_uniqidinfo));
2203 proc_piduniqidentifierinfo(p, &p_uniqidinfo);
2204 error = copyout(&p_uniqidinfo, buffer, sizeof(struct proc_uniqidentifierinfo));
2205 if (error == 0) {
2206 *retval = sizeof(struct proc_uniqidentifierinfo);
2207 }
2208 }
2209 break;
2210
2211 case PROC_PIDT_SHORTBSDINFO:
2212 shortversion = 1;
2213 OS_FALLTHROUGH;
2214 case PROC_PIDT_BSDINFOWITHUNIQID:
2215 case PROC_PIDTBSDINFO: {
2216 struct proc_bsdinfo pbsd;
2217 struct proc_bsdshortinfo pbsd_short;
2218 struct proc_bsdinfowithuniqid pbsd_uniqid;
2219
2220 if (flavor == PROC_PIDT_BSDINFOWITHUNIQID) {
2221 uniqidversion = 1;
2222 }
2223
2224 if (shortversion != 0) {
2225 error = proc_pidshortbsdinfo(p, &pbsd_short, zombie);
2226 } else {
2227 error = proc_pidbsdinfo(p, &pbsd, zombie);
2228 if (uniqidversion != 0) {
2229 bzero(&pbsd_uniqid, sizeof(pbsd_uniqid));
2230 proc_piduniqidentifierinfo(p, &pbsd_uniqid.p_uniqidentifier);
2231 pbsd_uniqid.pbsd = pbsd;
2232 }
2233 }
2234
2235 if (error == 0) {
2236 if (shortversion != 0) {
2237 error = copyout(&pbsd_short, buffer, sizeof(struct proc_bsdshortinfo));
2238 if (error == 0) {
2239 *retval = sizeof(struct proc_bsdshortinfo);
2240 }
2241 } else if (uniqidversion != 0) {
2242 error = copyout(&pbsd_uniqid, buffer, sizeof(struct proc_bsdinfowithuniqid));
2243 if (error == 0) {
2244 *retval = sizeof(struct proc_bsdinfowithuniqid);
2245 }
2246 } else {
2247 error = copyout(&pbsd, buffer, sizeof(struct proc_bsdinfo));
2248 if (error == 0) {
2249 *retval = sizeof(struct proc_bsdinfo);
2250 }
2251 }
2252 }
2253 }
2254 break;
2255
2256 case PROC_PIDTASKINFO: {
2257 struct proc_taskinfo ptinfo;
2258
2259 error = proc_pidtaskinfo(p, &ptinfo);
2260 if (error == 0) {
2261 error = copyout(&ptinfo, buffer, sizeof(struct proc_taskinfo));
2262 if (error == 0) {
2263 *retval = sizeof(struct proc_taskinfo);
2264 }
2265 }
2266 }
2267 break;
2268
2269 case PROC_PIDTASKALLINFO: {
2270 struct proc_taskallinfo pall;
2271 bzero(&pall, sizeof(pall));
2272 error = proc_pidbsdinfo(p, &pall.pbsd, 0);
2273 error = proc_pidtaskinfo(p, &pall.ptinfo);
2274 if (error == 0) {
2275 error = copyout(&pall, buffer, sizeof(struct proc_taskallinfo));
2276 if (error == 0) {
2277 *retval = sizeof(struct proc_taskallinfo);
2278 }
2279 }
2280 }
2281 break;
2282
2283 case PROC_PIDTHREADID64INFO:
2284 thuniqueid = true;
2285 OS_FALLTHROUGH;
2286 case PROC_PIDTHREADINFO:{
2287 struct proc_threadinfo pthinfo;
2288
2289 error = proc_pidthreadinfo(p, arg, thuniqueid, &pthinfo);
2290 if (error == 0) {
2291 error = copyout(&pthinfo, buffer, sizeof(struct proc_threadinfo));
2292 if (error == 0) {
2293 *retval = sizeof(struct proc_threadinfo);
2294 }
2295 }
2296 }
2297 break;
2298 case PROC_PIDTHREADCOUNTS: {
2299 error = proc_pidthreadcounts(p, arg, buffer, buffersize, retval);
2300 }
2301 break;
2302
2303 case PROC_PIDLISTTHREADIDS:
2304 thuniqueid = true;
2305 OS_FALLTHROUGH;
2306 case PROC_PIDLISTTHREADS:{
2307 error = proc_pidlistthreads(p, thuniqueid, buffer, buffersize, retval);
2308 }
2309 break;
2310
2311 case PROC_PIDREGIONINFO:{
2312 error = proc_pidregioninfo(p, arg, buffer, buffersize, retval);
2313 }
2314 break;
2315
2316
2317 case PROC_PIDREGIONPATHINFO:{
2318 error = proc_pidregionpathinfo(p, arg, buffer, buffersize, retval);
2319 }
2320 break;
2321
2322 case PROC_PIDREGIONPATHINFO2:{
2323 error = proc_pidregionpathinfo2(p, arg, buffer, buffersize, retval);
2324 }
2325 break;
2326
2327 case PROC_PIDREGIONPATHINFO3:{
2328 error = proc_pidregionpathinfo3(p, arg, buffer, buffersize, retval);
2329 }
2330 break;
2331
2332 case PROC_PIDVNODEPATHINFO:{
2333 error = proc_pidvnodepathinfo(p, arg, buffer, buffersize, retval);
2334 }
2335 break;
2336
2337
2338 case PROC_PIDTHREADPATHINFO:{
2339 struct proc_threadwithpathinfo pinfo;
2340
2341 error = proc_pidthreadpathinfo(p, arg, &pinfo);
2342 if (error == 0) {
2343 error = copyout((caddr_t)&pinfo, buffer, sizeof(struct proc_threadwithpathinfo));
2344 if (error == 0) {
2345 *retval = sizeof(struct proc_threadwithpathinfo);
2346 }
2347 }
2348 }
2349 break;
2350
2351 case PROC_PIDPATHINFO: {
2352 error = proc_pidpathinfo(p, arg, buffer, buffersize, retval);
2353 }
2354 break;
2355
2356
2357 case PROC_PIDWORKQUEUEINFO:{
2358 struct proc_workqueueinfo pwqinfo;
2359
2360 error = proc_pidworkqueueinfo(p, &pwqinfo);
2361 if (error == 0) {
2362 error = copyout(&pwqinfo, buffer, sizeof(struct proc_workqueueinfo));
2363 if (error == 0) {
2364 *retval = sizeof(struct proc_workqueueinfo);
2365 }
2366 }
2367 }
2368 break;
2369
2370 case PROC_PIDLISTFILEPORTS: {
2371 error = proc_pidfileportlist(p, buffer, buffersize, retval);
2372 }
2373 break;
2374
2375 case PROC_PIDARCHINFO: {
2376 struct proc_archinfo pai;
2377 bzero(&pai, sizeof(pai));
2378 proc_archinfo(p, &pai);
2379 error = copyout(&pai, buffer, sizeof(struct proc_archinfo));
2380 if (error == 0) {
2381 *retval = sizeof(struct proc_archinfo);
2382 }
2383 }
2384 break;
2385
2386 case PROC_PIDCOALITIONINFO: {
2387 struct proc_pidcoalitioninfo pci;
2388 proc_pidcoalitioninfo(p, &pci);
2389 error = copyout(&pci, buffer, sizeof(struct proc_pidcoalitioninfo));
2390 if (error == 0) {
2391 *retval = sizeof(struct proc_pidcoalitioninfo);
2392 }
2393 }
2394 break;
2395
2396 case PROC_PIDNOTEEXIT: {
2397 uint32_t data;
2398 error = proc_pidnoteexit(p, arg, &data);
2399 if (error == 0) {
2400 error = copyout(&data, buffer, sizeof(data));
2401 if (error == 0) {
2402 *retval = sizeof(data);
2403 }
2404 }
2405 }
2406 break;
2407
2408 case PROC_PIDEXITREASONINFO: {
2409 struct proc_exitreasoninfo eri;
2410
2411 error = copyin(buffer, &eri, sizeof(eri));
2412 if (error != 0) {
2413 break;
2414 }
2415
2416 error = proc_pidexitreasoninfo(p, &eri, NULL);
2417 if (error == 0) {
2418 error = copyout(&eri, buffer, sizeof(eri));
2419 if (error == 0) {
2420 *retval = sizeof(eri);
2421 }
2422 }
2423 }
2424 break;
2425
2426 case PROC_PIDEXITREASONBASICINFO: {
2427 struct proc_exitreasonbasicinfo beri;
2428
2429 bzero(&beri, sizeof(struct proc_exitreasonbasicinfo));
2430
2431 error = proc_pidexitreasoninfo(p, NULL, &beri);
2432 if (error == 0) {
2433 error = copyout(&beri, buffer, sizeof(beri));
2434 if (error == 0) {
2435 *retval = sizeof(beri);
2436 }
2437 }
2438 }
2439 break;
2440
2441 case PROC_PIDLISTUPTRS:
2442 error = proc_pidlistuptrs(p, buffer, buffersize, retval);
2443 break;
2444
2445 case PROC_PIDLISTDYNKQUEUES:
2446 error = kevent_copyout_proc_dynkqids(p, buffer, buffersize, retval);
2447 break;
2448 case PROC_PIDVMRTFAULTINFO: {
2449 /* This interface can only be employed on the current
2450 * process. We will eventually enforce an entitlement.
2451 */
2452 *retval = 0;
2453
2454 if (p != current_proc()) {
2455 error = EINVAL;
2456 break;
2457 }
2458
2459 size_t kbufsz = MIN(buffersize, vmrtfaultinfo_bufsz());
2460 void *vmrtfbuf = kalloc_data(kbufsz, Z_WAITOK | Z_ZERO);
2461
2462 if (vmrtfbuf == NULL) {
2463 error = ENOMEM;
2464 break;
2465 }
2466
2467 uint64_t effpid = get_current_unique_pid();
2468 /* The VM may choose to provide more comprehensive records
2469 * for root-privileged users on internal configurations.
2470 */
2471 boolean_t isroot = (suser(kauth_cred_get(), (u_short *)0) == 0);
2472 size_t num_extracted = 0;
2473 int vmf_residue = vmrtf_extract(effpid, isroot, kbufsz, vmrtfbuf, &num_extracted);
2474 size_t vmfsz = num_extracted * sizeof(vm_rtfault_record_t);
2475
2476 *retval = (int32_t)MIN(num_extracted, INT32_MAX);
2477
2478 error = 0;
2479 if (vmfsz) {
2480 error = copyout(vmrtfbuf, buffer, vmfsz);
2481 }
2482
2483 if (error == 0) {
2484 if (vmf_residue) {
2485 error = ENOMEM;
2486 }
2487 }
2488 kfree_data(vmrtfbuf, kbufsz);
2489 }
2490 break;
2491 case PROC_PIDPLATFORMINFO: {
2492 proc_lock(p);
2493 uint32_t platform = proc_platform(p);
2494 proc_unlock(p);
2495 error = copyout(&platform, buffer, sizeof(uint32_t));
2496 if (error == 0) {
2497 *retval = sizeof(uint32_t);
2498 }
2499 } break;
2500 case PROC_PIDREGIONPATH: {
2501 error = proc_pidregionpath(p, arg, buffer, buffersize, retval);
2502 }
2503 break;
2504 case PROC_PIDIPCTABLEINFO: {
2505 struct proc_ipctableinfo table_info;
2506
2507 error = proc_pidipctableinfo(p, &table_info);
2508 if (error == 0) {
2509 error = copyout(&table_info, buffer, sizeof(struct proc_ipctableinfo));
2510 if (error == 0) {
2511 *retval = sizeof(struct proc_ipctableinfo);
2512 }
2513 }
2514 }
2515 break;
2516 case PROC_PIDTHREADSCHEDINFO: {
2517 struct proc_threadschedinfo sched_info;
2518
2519 error = proc_pidthreadschedinfo(p, arg, &sched_info);
2520 if (error == 0) {
2521 error = copyout(&sched_info, buffer, sizeof(sched_info));
2522 if (error == 0) {
2523 *retval = sizeof(sched_info);
2524 }
2525 }
2526 }
2527 break;
2528 default:
2529 error = ENOTSUP;
2530 break;
2531 }
2532
2533 out:
2534 if (gotref) {
2535 proc_rele(p);
2536 } else if (zombie) {
2537 proc_drop_zombref(p);
2538 }
2539 return error;
2540 }
2541
2542
2543 int
pid_vnodeinfo(vnode_t vp,struct fileproc * fp,proc_t proc,user_addr_t buffer,__unused uint32_t buffersize,int32_t * retval)2544 pid_vnodeinfo(vnode_t vp, struct fileproc * fp, proc_t proc, user_addr_t buffer, __unused uint32_t buffersize, int32_t * retval)
2545 {
2546 struct vnode_fdinfo vfi;
2547 uint32_t vid = vnode_vid(vp);
2548 int error = 0;
2549
2550 if ((error = vnode_getwithvid(vp, vid)) != 0) {
2551 return error;
2552 }
2553 bzero(&vfi, sizeof(struct vnode_fdinfo));
2554 fill_fileinfo(fp, proc, &vfi.pfi);
2555 error = fill_vnodeinfo(vp, &vfi.pvi, FALSE);
2556 vnode_put(vp);
2557 if (error == 0) {
2558 error = copyout((caddr_t)&vfi, buffer, sizeof(struct vnode_fdinfo));
2559 if (error == 0) {
2560 *retval = sizeof(struct vnode_fdinfo);
2561 }
2562 }
2563 return error;
2564 }
2565
2566 int
pid_vnodeinfopath(vnode_t vp,struct fileproc * fp,proc_t proc,user_addr_t buffer,__unused uint32_t buffersize,int32_t * retval)2567 pid_vnodeinfopath(vnode_t vp, struct fileproc * fp, proc_t proc, user_addr_t buffer, __unused uint32_t buffersize, int32_t * retval)
2568 {
2569 struct vnode_fdinfowithpath vfip;
2570 uint32_t vid = vnode_vid(vp);
2571 int count, error = 0;
2572
2573 if ((error = vnode_getwithvid(vp, vid)) != 0) {
2574 return error;
2575 }
2576 bzero(&vfip, sizeof(struct vnode_fdinfowithpath));
2577 fill_fileinfo(fp, proc, &vfip.pfi);
2578 error = fill_vnodeinfo(vp, &vfip.pvip.vip_vi, TRUE);
2579 if (error == 0) {
2580 count = MAXPATHLEN;
2581 vn_getpath(vp, &vfip.pvip.vip_path[0], &count);
2582 vfip.pvip.vip_path[MAXPATHLEN - 1] = 0;
2583 vnode_put(vp);
2584 error = copyout((caddr_t)&vfip, buffer, sizeof(struct vnode_fdinfowithpath));
2585 if (error == 0) {
2586 *retval = sizeof(struct vnode_fdinfowithpath);
2587 }
2588 } else {
2589 vnode_put(vp);
2590 }
2591 return error;
2592 }
2593
2594 void
fill_fileinfo(struct fileproc * fp,proc_t proc,struct proc_fileinfo * fproc)2595 fill_fileinfo(struct fileproc * fp, proc_t proc, struct proc_fileinfo * fproc)
2596 {
2597 fproc->fi_openflags = fp->fp_glob->fg_flag;
2598 fproc->fi_status = 0;
2599 fproc->fi_offset = fp->fp_glob->fg_offset;
2600 fproc->fi_type = FILEGLOB_DTYPE(fp->fp_glob);
2601 if (os_ref_get_count_raw(&fp->fp_glob->fg_count) > 1) {
2602 fproc->fi_status |= PROC_FP_SHARED;
2603 }
2604 if (proc != PROC_NULL) {
2605 if (fp->fp_flags & FP_CLOEXEC) {
2606 fproc->fi_status |= PROC_FP_CLEXEC;
2607 }
2608 if (fp->fp_flags & FP_CLOFORK) {
2609 fproc->fi_status |= PROC_FP_CLFORK;
2610 }
2611 }
2612 if (fp->fp_guard_attrs) {
2613 fproc->fi_status |= PROC_FP_GUARDED;
2614 fproc->fi_guardflags = 0;
2615 if (fp_isguarded(fp, GUARD_CLOSE)) {
2616 fproc->fi_guardflags |= PROC_FI_GUARD_CLOSE;
2617 }
2618 if (fp_isguarded(fp, GUARD_DUP)) {
2619 fproc->fi_guardflags |= PROC_FI_GUARD_DUP;
2620 }
2621 if (fp_isguarded(fp, GUARD_SOCKET_IPC)) {
2622 fproc->fi_guardflags |= PROC_FI_GUARD_SOCKET_IPC;
2623 }
2624 if (fp_isguarded(fp, GUARD_FILEPORT)) {
2625 fproc->fi_guardflags |= PROC_FI_GUARD_FILEPORT;
2626 }
2627 }
2628 }
2629
2630
2631
2632 int
fill_vnodeinfo(vnode_t vp,struct vnode_info * vinfo,__unused boolean_t check_fsgetpath)2633 fill_vnodeinfo(vnode_t vp, struct vnode_info *vinfo, __unused boolean_t check_fsgetpath)
2634 {
2635 vfs_context_t context;
2636 struct stat64 sb;
2637 int error = 0;
2638
2639 bzero(&sb, sizeof(struct stat64));
2640 context = vfs_context_create((vfs_context_t)0);
2641 #if CONFIG_MACF
2642 /* Called when vnode info is used by the caller to get vnode's path */
2643 if (check_fsgetpath) {
2644 error = mac_vnode_check_fsgetpath(context, vp);
2645 }
2646 #endif
2647 if (!error) {
2648 error = vn_stat(vp, &sb, NULL, 1, 0, context);
2649 munge_vinfo_stat(&sb, &vinfo->vi_stat);
2650 }
2651 (void)vfs_context_rele(context);
2652 if (error != 0) {
2653 goto out;
2654 }
2655
2656 if (vp->v_mount != dead_mountp) {
2657 vinfo->vi_fsid = vp->v_mount->mnt_vfsstat.f_fsid;
2658 } else {
2659 vinfo->vi_fsid.val[0] = 0;
2660 vinfo->vi_fsid.val[1] = 0;
2661 }
2662 vinfo->vi_type = vp->v_type;
2663 out:
2664 return error;
2665 }
2666
2667 int
pid_socketinfo(socket_t so,struct fileproc * fp,proc_t proc,user_addr_t buffer,__unused uint32_t buffersize,int32_t * retval)2668 pid_socketinfo(socket_t so, struct fileproc *fp, proc_t proc, user_addr_t buffer, __unused uint32_t buffersize, int32_t * retval)
2669 {
2670 #if SOCKETS
2671 struct socket_fdinfo s;
2672 int error = 0;
2673
2674 bzero(&s, sizeof(struct socket_fdinfo));
2675 fill_fileinfo(fp, proc, &s.pfi);
2676 if ((error = fill_socketinfo(so, &s.psi)) == 0) {
2677 if ((error = copyout(&s, buffer, sizeof(struct socket_fdinfo))) == 0) {
2678 *retval = sizeof(struct socket_fdinfo);
2679 }
2680 }
2681 return error;
2682 #else
2683 #pragma unused(so, fp, proc, fd, buffer)
2684 *retval = 0;
2685 return ENOTSUP;
2686 #endif
2687 }
2688
2689 int
pid_pseminfo(struct psemnode * psem,struct fileproc * fp,proc_t proc,user_addr_t buffer,__unused uint32_t buffersize,int32_t * retval)2690 pid_pseminfo(struct psemnode *psem, struct fileproc *fp, proc_t proc, user_addr_t buffer, __unused uint32_t buffersize, int32_t * retval)
2691 {
2692 struct psem_fdinfo pseminfo;
2693 int error = 0;
2694
2695 bzero(&pseminfo, sizeof(struct psem_fdinfo));
2696 fill_fileinfo(fp, proc, &pseminfo.pfi);
2697
2698 if ((error = fill_pseminfo(psem, &pseminfo.pseminfo)) == 0) {
2699 if ((error = copyout(&pseminfo, buffer, sizeof(struct psem_fdinfo))) == 0) {
2700 *retval = sizeof(struct psem_fdinfo);
2701 }
2702 }
2703
2704 return error;
2705 }
2706
2707 int
pid_pshminfo(struct pshmnode * pshm,struct fileproc * fp,proc_t proc,user_addr_t buffer,__unused uint32_t buffersize,int32_t * retval)2708 pid_pshminfo(struct pshmnode *pshm, struct fileproc *fp, proc_t proc, user_addr_t buffer, __unused uint32_t buffersize, int32_t * retval)
2709 {
2710 struct pshm_fdinfo pshminfo;
2711 int error = 0;
2712
2713 bzero(&pshminfo, sizeof(struct pshm_fdinfo));
2714 fill_fileinfo(fp, proc, &pshminfo.pfi);
2715
2716 if ((error = fill_pshminfo(pshm, &pshminfo.pshminfo)) == 0) {
2717 if ((error = copyout(&pshminfo, buffer, sizeof(struct pshm_fdinfo))) == 0) {
2718 *retval = sizeof(struct pshm_fdinfo);
2719 }
2720 }
2721
2722 return error;
2723 }
2724
2725 int
pid_pipeinfo(struct pipe * p,struct fileproc * fp,proc_t proc,user_addr_t buffer,__unused uint32_t buffersize,int32_t * retval)2726 pid_pipeinfo(struct pipe * p, struct fileproc *fp, proc_t proc, user_addr_t buffer, __unused uint32_t buffersize, int32_t * retval)
2727 {
2728 struct pipe_fdinfo pipeinfo;
2729 int error = 0;
2730
2731 bzero(&pipeinfo, sizeof(struct pipe_fdinfo));
2732 fill_fileinfo(fp, proc, &pipeinfo.pfi);
2733 if ((error = fill_pipeinfo(p, &pipeinfo.pipeinfo)) == 0) {
2734 if ((error = copyout(&pipeinfo, buffer, sizeof(struct pipe_fdinfo))) == 0) {
2735 *retval = sizeof(struct pipe_fdinfo);
2736 }
2737 }
2738
2739 return error;
2740 }
2741
2742 int
pid_kqueueinfo(struct kqueue * kq,struct fileproc * fp,proc_t proc,user_addr_t buffer,__unused uint32_t buffersize,int32_t * retval)2743 pid_kqueueinfo(struct kqueue * kq, struct fileproc *fp, proc_t proc, user_addr_t buffer, __unused uint32_t buffersize, int32_t * retval)
2744 {
2745 struct kqueue_fdinfo kqinfo;
2746 int error = 0;
2747
2748 bzero(&kqinfo, sizeof(struct kqueue_fdinfo));
2749
2750 /* not all kq's are associated with a file (e.g. workqkq) */
2751 if (fp) {
2752 fill_fileinfo(fp, proc, &kqinfo.pfi);
2753 }
2754
2755 if ((error = fill_kqueueinfo(kq, &kqinfo.kqueueinfo)) == 0) {
2756 if ((error = copyout(&kqinfo, buffer, sizeof(struct kqueue_fdinfo))) == 0) {
2757 *retval = sizeof(struct kqueue_fdinfo);
2758 }
2759 }
2760
2761 return error;
2762 }
2763
2764 int
pid_channelinfo(struct kern_channel * chan,struct fileproc * fp,proc_t proc,user_addr_t buffer,__unused uint32_t buffersize,int32_t * retval)2765 pid_channelinfo(struct kern_channel * chan, struct fileproc *fp, proc_t proc, user_addr_t buffer, __unused uint32_t buffersize, int32_t * retval)
2766 {
2767 #if SKYWALK
2768 struct channel_fdinfo channel_info;
2769 int error = 0;
2770
2771 bzero(&channel_info, sizeof(struct channel_fdinfo));
2772 fill_fileinfo(fp, proc, &channel_info.pfi);
2773 if ((error = fill_channelinfo(chan, &channel_info.channelinfo)) == 0) {
2774 if ((error = copyout(&channel_info, buffer, sizeof(struct channel_fdinfo))) == 0) {
2775 *retval = sizeof(struct channel_fdinfo);
2776 }
2777 }
2778 return error;
2779 #else
2780 #pragma unused(chan, fp, proc, fd, buffer)
2781 *retval = 0;
2782 return ENOTSUP;
2783 #endif
2784 }
2785
2786 /************************** proc_pidfdinfo routine ***************************/
2787 int
proc_pidfdinfo(int pid,int flavor,int fd,user_addr_t buffer,uint32_t buffersize,int32_t * retval)2788 proc_pidfdinfo(int pid, int flavor, int fd, user_addr_t buffer, uint32_t buffersize, int32_t * retval)
2789 {
2790 proc_t p;
2791 int error = ENOTSUP;
2792 struct fileproc *fp = NULL;
2793 uint32_t size;
2794
2795 switch (flavor) {
2796 case PROC_PIDFDVNODEINFO:
2797 size = PROC_PIDFDVNODEINFO_SIZE;
2798 break;
2799 case PROC_PIDFDVNODEPATHINFO:
2800 size = PROC_PIDFDVNODEPATHINFO_SIZE;
2801 break;
2802 case PROC_PIDFDSOCKETINFO:
2803 size = PROC_PIDFDSOCKETINFO_SIZE;
2804 break;
2805 case PROC_PIDFDPSEMINFO:
2806 size = PROC_PIDFDPSEMINFO_SIZE;
2807 break;
2808 case PROC_PIDFDPSHMINFO:
2809 size = PROC_PIDFDPSHMINFO_SIZE;
2810 break;
2811 case PROC_PIDFDPIPEINFO:
2812 size = PROC_PIDFDPIPEINFO_SIZE;
2813 break;
2814 case PROC_PIDFDKQUEUEINFO:
2815 size = PROC_PIDFDKQUEUEINFO_SIZE;
2816 break;
2817 case PROC_PIDFDKQUEUE_EXTINFO:
2818 size = PROC_PIDFDKQUEUE_EXTINFO_SIZE;
2819 if (buffer == (user_addr_t)0) {
2820 size = 0;
2821 }
2822 break;
2823 case PROC_PIDFDATALKINFO:
2824 size = PROC_PIDFDATALKINFO_SIZE;
2825 break;
2826 case PROC_PIDFDCHANNELINFO:
2827 size = PROC_PIDFDCHANNELINFO_SIZE;
2828 break;
2829
2830 default:
2831 return EINVAL;
2832 }
2833
2834 if (buffersize < size) {
2835 return ENOMEM;
2836 }
2837
2838 if ((p = proc_find(pid)) == PROC_NULL) {
2839 error = ESRCH;
2840 goto out;
2841 }
2842
2843 /* Do we have permission to look into this? */
2844 if ((error = proc_security_policy(p, PROC_INFO_CALL_PIDFDINFO, flavor, CHECK_SAME_USER))) {
2845 goto out1;
2846 }
2847
2848 switch (flavor) {
2849 case PROC_PIDFDVNODEINFO: {
2850 if ((error = fp_get_ftype(p, fd, DTYPE_VNODE, EBADF, &fp)) != 0) {
2851 goto out1;
2852 }
2853 error = pid_vnodeinfo((vnode_t)fp_get_data(fp), fp, p, buffer, buffersize, retval);
2854 }
2855 break;
2856
2857 case PROC_PIDFDVNODEPATHINFO: {
2858 if ((error = fp_get_ftype(p, fd, DTYPE_VNODE, EBADF, &fp)) != 0) {
2859 goto out1;
2860 }
2861 error = pid_vnodeinfopath((vnode_t)fp_get_data(fp), fp, p, buffer, buffersize, retval);
2862 }
2863 break;
2864
2865 case PROC_PIDFDSOCKETINFO: {
2866 if ((error = fp_get_ftype(p, fd, DTYPE_SOCKET, ENOTSOCK, &fp)) != 0) {
2867 goto out1;
2868 }
2869 error = pid_socketinfo((socket_t)fp_get_data(fp), fp, p, buffer, buffersize, retval);
2870 }
2871 break;
2872
2873 case PROC_PIDFDPSEMINFO: {
2874 if ((error = fp_get_ftype(p, fd, DTYPE_PSXSEM, EBADF, &fp)) != 0) {
2875 goto out1;
2876 }
2877 error = pid_pseminfo((struct psemnode *)fp_get_data(fp), fp, p, buffer, buffersize, retval);
2878 }
2879 break;
2880
2881 case PROC_PIDFDPSHMINFO: {
2882 if ((error = fp_get_ftype(p, fd, DTYPE_PSXSHM, EBADF, &fp)) != 0) {
2883 goto out1;
2884 }
2885 error = pid_pshminfo((struct pshmnode *)fp_get_data(fp), fp, p, buffer, buffersize, retval);
2886 }
2887 break;
2888
2889 case PROC_PIDFDPIPEINFO: {
2890 if ((error = fp_get_ftype(p, fd, DTYPE_PIPE, EBADF, &fp)) != 0) {
2891 goto out1;
2892 }
2893 error = pid_pipeinfo((struct pipe *)fp_get_data(fp), fp, p, buffer, buffersize, retval);
2894 }
2895 break;
2896
2897 case PROC_PIDFDKQUEUEINFO: {
2898 kqueue_t kqu;
2899
2900 if (fd == -1) {
2901 if ((kqu.kqwq = p->p_fd.fd_wqkqueue) == NULL) {
2902 /* wqkqueue is initialized on-demand */
2903 error = 0;
2904 break;
2905 }
2906 } else if ((error = fp_get_ftype(p, fd, DTYPE_KQUEUE, EBADF, &fp)) != 0) {
2907 goto out1;
2908 } else {
2909 kqu.kq = (struct kqueue *)fp_get_data(fp);
2910 }
2911
2912 error = pid_kqueueinfo(kqu.kq, fp, p, buffer, buffersize, retval);
2913 }
2914 break;
2915
2916 case PROC_PIDFDKQUEUE_EXTINFO: {
2917 kqueue_t kqu;
2918
2919 if (fd == -1) {
2920 if ((kqu.kqwq = p->p_fd.fd_wqkqueue) == NULL) {
2921 /* wqkqueue is initialized on-demand */
2922 error = 0;
2923 break;
2924 }
2925 } else if ((error = fp_get_ftype(p, fd, DTYPE_KQUEUE, EBADF, &fp)) != 0) {
2926 goto out1;
2927 } else {
2928 kqu.kq = (struct kqueue *)fp_get_data(fp);
2929 }
2930 error = pid_kqueue_extinfo(p, kqu.kq, buffer, buffersize, retval);
2931 }
2932 break;
2933 case PROC_PIDFDCHANNELINFO: {
2934 if ((error = fp_get_ftype(p, fd, DTYPE_CHANNEL, EBADF, &fp)) != 0) {
2935 goto out1;
2936 }
2937 /* no need to be under the fdlock */
2938 error = pid_channelinfo((struct kern_channel *)fp_get_data(fp), fp, p, buffer, buffersize, retval);
2939 }
2940 break;
2941
2942 default: {
2943 error = EINVAL;
2944 goto out1;
2945 }
2946 }
2947
2948 if (fp) {
2949 fp_drop(p, fd, fp, 0);
2950 }
2951 out1:
2952 proc_rele(p);
2953 out:
2954 return error;
2955 }
2956
2957 #define MAX_UPTRS 16392
2958
2959 int
proc_pidlistuptrs(proc_t p,user_addr_t buffer,uint32_t buffersize,int32_t * retval)2960 proc_pidlistuptrs(proc_t p, user_addr_t buffer, uint32_t buffersize, int32_t *retval)
2961 {
2962 uint32_t count = 0;
2963 int error = 0;
2964 void *kbuf = NULL;
2965 int32_t nuptrs = 0;
2966
2967 if (buffer == USER_ADDR_NULL || buffersize < sizeof(uint64_t)) {
2968 buffersize = 0;
2969 } else {
2970 count = MIN(buffersize / sizeof(uint64_t), MAX_UPTRS);
2971 buffersize = count * sizeof(uint64_t);
2972 kbuf = kalloc_data(buffersize, Z_WAITOK);
2973 }
2974
2975 nuptrs = kevent_proc_copy_uptrs(p, kbuf, buffersize);
2976
2977 if (kbuf) {
2978 size_t copysize;
2979 if (os_mul_overflow(nuptrs, sizeof(uint64_t), ©size)) {
2980 error = ERANGE;
2981 goto out;
2982 }
2983 if (copysize > buffersize) {
2984 copysize = buffersize;
2985 }
2986 error = copyout(kbuf, buffer, copysize);
2987 }
2988
2989 out:
2990 *retval = nuptrs;
2991
2992 if (kbuf) {
2993 kfree_data(kbuf, buffersize);
2994 kbuf = NULL;
2995 }
2996
2997 return error;
2998 }
2999
3000 /*
3001 * Helper function for proc_pidfileportinfo
3002 */
3003
3004 struct fileport_info_args {
3005 int fia_flavor;
3006 user_addr_t fia_buffer;
3007 uint32_t fia_buffersize;
3008 int32_t *fia_retval;
3009 };
3010
3011 static kern_return_t
proc_fileport_info(__unused mach_port_name_t name,struct fileglob * fg,void * arg)3012 proc_fileport_info(__unused mach_port_name_t name,
3013 struct fileglob *fg, void *arg)
3014 {
3015 struct fileport_info_args *fia = arg;
3016 struct fileproc __fileproc, *fp = &__fileproc;
3017 int error;
3018
3019 bzero(fp, sizeof(*fp));
3020 fp->fp_glob = fg;
3021
3022 switch (fia->fia_flavor) {
3023 case PROC_PIDFILEPORTVNODEPATHINFO: {
3024 vnode_t vp;
3025
3026 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
3027 error = ENOTSUP;
3028 break;
3029 }
3030 vp = (struct vnode *)fg_get_data(fg);
3031 error = pid_vnodeinfopath(vp, fp, PROC_NULL,
3032 fia->fia_buffer, fia->fia_buffersize, fia->fia_retval);
3033 } break;
3034
3035 case PROC_PIDFILEPORTSOCKETINFO: {
3036 socket_t so;
3037
3038 if (FILEGLOB_DTYPE(fg) != DTYPE_SOCKET) {
3039 error = EOPNOTSUPP;
3040 break;
3041 }
3042 so = (socket_t)fg_get_data(fg);
3043 error = pid_socketinfo(so, fp, PROC_NULL,
3044 fia->fia_buffer, fia->fia_buffersize, fia->fia_retval);
3045 } break;
3046
3047 case PROC_PIDFILEPORTPSHMINFO: {
3048 struct pshmnode *pshm;
3049
3050 if (FILEGLOB_DTYPE(fg) != DTYPE_PSXSHM) {
3051 error = EBADF; /* ick - mirror fp_getfpshm */
3052 break;
3053 }
3054 pshm = (struct pshmnode *)fg_get_data(fg);
3055 error = pid_pshminfo(pshm, fp, PROC_NULL,
3056 fia->fia_buffer, fia->fia_buffersize, fia->fia_retval);
3057 } break;
3058
3059 case PROC_PIDFILEPORTPIPEINFO: {
3060 struct pipe *cpipe;
3061
3062 if (FILEGLOB_DTYPE(fg) != DTYPE_PIPE) {
3063 error = EBADF; /* ick - mirror fp_getfpipe */
3064 break;
3065 }
3066 cpipe = (struct pipe *)fg_get_data(fg);
3067 error = pid_pipeinfo(cpipe, fp, PROC_NULL,
3068 fia->fia_buffer, fia->fia_buffersize, fia->fia_retval);
3069 } break;
3070
3071 default:
3072 error = EINVAL;
3073 break;
3074 }
3075
3076 return error;
3077 }
3078
3079 /************************* proc_pidfileportinfo routine *********************/
3080 int
proc_pidfileportinfo(int pid,int flavor,mach_port_name_t name,user_addr_t buffer,uint32_t buffersize,int32_t * retval)3081 proc_pidfileportinfo(int pid, int flavor, mach_port_name_t name,
3082 user_addr_t buffer, uint32_t buffersize, int32_t *retval)
3083 {
3084 proc_t p;
3085 int error = ENOTSUP;
3086 uint32_t size;
3087 struct fileport_info_args fia;
3088
3089 /* fileport types are restricted by file_issendable() */
3090
3091 switch (flavor) {
3092 case PROC_PIDFILEPORTVNODEPATHINFO:
3093 size = PROC_PIDFILEPORTVNODEPATHINFO_SIZE;
3094 break;
3095 case PROC_PIDFILEPORTSOCKETINFO:
3096 size = PROC_PIDFILEPORTSOCKETINFO_SIZE;
3097 break;
3098 case PROC_PIDFILEPORTPSHMINFO:
3099 size = PROC_PIDFILEPORTPSHMINFO_SIZE;
3100 break;
3101 case PROC_PIDFILEPORTPIPEINFO:
3102 size = PROC_PIDFILEPORTPIPEINFO_SIZE;
3103 break;
3104 default:
3105 return EINVAL;
3106 }
3107
3108 if (buffersize < size) {
3109 return ENOMEM;
3110 }
3111 if ((p = proc_find(pid)) == PROC_NULL) {
3112 error = ESRCH;
3113 goto out;
3114 }
3115
3116 /* Do we have permission to look into this? */
3117 if ((error = proc_security_policy(p, PROC_INFO_CALL_PIDFILEPORTINFO, flavor, CHECK_SAME_USER))) {
3118 goto out1;
3119 }
3120
3121 fia.fia_flavor = flavor;
3122 fia.fia_buffer = buffer;
3123 fia.fia_buffersize = buffersize;
3124 fia.fia_retval = retval;
3125
3126 if (fileport_invoke(proc_task(p), name,
3127 proc_fileport_info, &fia, &error) != KERN_SUCCESS) {
3128 error = EINVAL;
3129 }
3130 out1:
3131 proc_rele(p);
3132 out:
3133 return error;
3134 }
3135
3136 int
proc_security_policy(proc_t targetp,__unused int callnum,__unused int flavor,boolean_t check_same_user)3137 proc_security_policy(proc_t targetp, __unused int callnum, __unused int flavor, boolean_t check_same_user)
3138 {
3139 #if CONFIG_MACF
3140 int error = 0;
3141
3142 if ((error = mac_proc_check_proc_info(current_proc(), targetp, callnum, flavor))) {
3143 return error;
3144 }
3145 #endif
3146
3147 /* The 'listpids' call doesn't have a target proc */
3148 if (targetp == PROC_NULL) {
3149 assert(callnum == PROC_INFO_CALL_LISTPIDS && check_same_user == NO_CHECK_SAME_USER);
3150 return 0;
3151 }
3152
3153 /*
3154 * Check for 'get information for processes owned by other users' privilege
3155 * root has this privilege by default
3156 */
3157 if (check_same_user) {
3158 kauth_cred_t my_cred = kauth_cred_get();
3159 kauth_cred_t tg_cred;
3160
3161 smr_proc_task_enter();
3162 tg_cred = proc_ucred_smr(targetp);
3163 if (kauth_cred_getuid(my_cred) != kauth_cred_getuid(tg_cred)) {
3164 error = EPERM;
3165 }
3166 tg_cred = NOCRED;
3167 smr_proc_task_leave();
3168
3169 /*
3170 * If uid doesn't match, check if the caller is specially entitled
3171 * to bypass the requirement.
3172 */
3173 if (error && priv_check_cred(my_cred, PRIV_GLOBAL_PROC_INFO, 0)) {
3174 return EPERM;
3175 }
3176 }
3177
3178 return 0;
3179 }
3180
3181 int
proc_kernmsgbuf(user_addr_t buffer,uint32_t buffersize,int32_t * retval)3182 proc_kernmsgbuf(user_addr_t buffer, uint32_t buffersize, int32_t * retval)
3183 {
3184 #if CONFIG_MACF
3185 int error = 0;
3186
3187 if ((error = mac_system_check_info(kauth_cred_get(), "kern.msgbuf"))) {
3188 return error;
3189 }
3190 #endif
3191
3192 if (suser(kauth_cred_get(), (u_short *)0) == 0) {
3193 return log_dmesg(buffer, buffersize, retval);
3194 } else {
3195 return EPERM;
3196 }
3197 }
3198
3199 /* ********* process control sets on self only */
3200 int
proc_setcontrol(int pid,int flavor,uint64_t arg,user_addr_t buffer,uint32_t buffersize,__unused int32_t * retval)3201 proc_setcontrol(int pid, int flavor, uint64_t arg, user_addr_t buffer, uint32_t buffersize, __unused int32_t * retval)
3202 {
3203 struct proc * pself = PROC_NULL;
3204 int error = 0;
3205 uint32_t pcontrol = (uint32_t)arg;
3206 struct uthread *ut = NULL;
3207 char name_buf[MAXTHREADNAMESIZE];
3208
3209 pself = current_proc();
3210 if (pid != proc_getpid(pself)) {
3211 return EINVAL;
3212 }
3213
3214 /* Do we have permission to look into this? */
3215 if ((error = proc_security_policy(pself, PROC_INFO_CALL_SETCONTROL, flavor, NO_CHECK_SAME_USER))) {
3216 goto out;
3217 }
3218
3219 switch (flavor) {
3220 case PROC_SELFSET_PCONTROL: {
3221 if (pcontrol > P_PCMAX) {
3222 return EINVAL;
3223 }
3224 proc_lock(pself);
3225 /* reset existing control setting while retaining action state */
3226 pself->p_pcaction &= PROC_ACTION_MASK;
3227 /* set new control state */
3228 pself->p_pcaction |= pcontrol;
3229 proc_unlock(pself);
3230 }
3231 break;
3232
3233 case PROC_SELFSET_THREADNAME: {
3234 /*
3235 * This is a bit ugly, as it copies the name into the kernel, and then
3236 * invokes bsd_setthreadname again to copy it into the uthread name
3237 * buffer. Hopefully this isn't such a hot codepath that an additional
3238 * MAXTHREADNAMESIZE copy is a big issue.
3239 */
3240 if (buffersize > (MAXTHREADNAMESIZE - 1)) {
3241 return ENAMETOOLONG;
3242 }
3243
3244 ut = current_uthread();
3245
3246 bzero(name_buf, MAXTHREADNAMESIZE);
3247 error = copyin(buffer, name_buf, buffersize);
3248
3249 if (!error) {
3250 bsd_setthreadname(ut, thread_tid(current_thread()), name_buf);
3251 }
3252 }
3253 break;
3254
3255 case PROC_SELFSET_VMRSRCOWNER: {
3256 /* need to to be superuser */
3257 if (suser(kauth_cred_get(), (u_short *)0) != 0) {
3258 error = EPERM;
3259 goto out;
3260 }
3261
3262 proc_lock(pself);
3263 /* reset existing control setting while retaining action state */
3264 pself->p_lflag |= P_LVMRSRCOWNER;
3265 proc_unlock(pself);
3266 }
3267 break;
3268
3269 case PROC_SELFSET_DELAYIDLESLEEP: {
3270 #if CONFIG_DELAY_IDLE_SLEEP
3271 /* mark or clear the process property to delay idle sleep disk IO */
3272 if (pcontrol != 0) {
3273 OSBitOrAtomic(P_DELAYIDLESLEEP, &pself->p_flag);
3274 } else {
3275 OSBitAndAtomic(~((uint32_t)P_DELAYIDLESLEEP), &pself->p_flag);
3276 }
3277 }
3278 break;
3279 #else
3280 error = ENOTSUP;
3281 goto out;
3282 }
3283 #endif
3284
3285 default:
3286 error = ENOTSUP;
3287 }
3288
3289 out:
3290 return error;
3291 }
3292
3293 #if CONFIG_MEMORYSTATUS
3294
3295 int
proc_dirtycontrol(int pid,int flavor,uint64_t arg,int32_t * retval)3296 proc_dirtycontrol(int pid, int flavor, uint64_t arg, int32_t *retval)
3297 {
3298 struct proc *target_p;
3299 int error = 0;
3300 uint32_t pcontrol = (uint32_t)arg;
3301 kauth_cred_t my_cred;
3302 boolean_t self = FALSE;
3303 boolean_t child = FALSE;
3304 boolean_t zombref = FALSE;
3305 pid_t selfpid;
3306
3307 target_p = proc_find(pid);
3308
3309 if (target_p == PROC_NULL) {
3310 if (flavor == PROC_DIRTYCONTROL_GET) {
3311 target_p = proc_find_zombref(pid);
3312 zombref = 1;
3313 }
3314
3315 if (target_p == PROC_NULL) {
3316 return ESRCH;
3317 }
3318 }
3319
3320 my_cred = kauth_cred_get();
3321
3322 /* Do we have permission to look into this? */
3323 if ((error = proc_security_policy(target_p, PROC_INFO_CALL_DIRTYCONTROL, flavor, NO_CHECK_SAME_USER))) {
3324 goto out;
3325 }
3326
3327 selfpid = proc_selfpid();
3328 if (pid == selfpid) {
3329 self = TRUE;
3330 } else if (target_p->p_ppid == selfpid) {
3331 child = TRUE;
3332 }
3333
3334 switch (flavor) {
3335 case PROC_DIRTYCONTROL_TRACK: {
3336 /* Only allow the process itself, its parent, or root */
3337 if ((self == FALSE) && (child == FALSE) && kauth_cred_issuser(kauth_cred_get()) != TRUE) {
3338 error = EPERM;
3339 goto out;
3340 }
3341
3342 error = memorystatus_dirty_track(target_p, pcontrol);
3343 }
3344 break;
3345
3346 case PROC_DIRTYCONTROL_SET: {
3347 /* Check privileges; use cansignal() here since the process could be terminated */
3348 if (!cansignal(current_proc(), my_cred, target_p, SIGKILL)) {
3349 error = EPERM;
3350 goto out;
3351 }
3352
3353 error = memorystatus_dirty_set(target_p, self, pcontrol);
3354 }
3355 break;
3356
3357 case PROC_DIRTYCONTROL_GET: {
3358 /* No permissions check - dirty state is freely available */
3359 if (retval) {
3360 *retval = memorystatus_dirty_get(target_p, FALSE);
3361 } else {
3362 error = EINVAL;
3363 }
3364 }
3365 break;
3366
3367 case PROC_DIRTYCONTROL_CLEAR: {
3368 /* Check privileges; use cansignal() here since the process could be terminated */
3369 if (!cansignal(current_proc(), my_cred, target_p, SIGKILL)) {
3370 error = EPERM;
3371 goto out;
3372 }
3373
3374 error = memorystatus_dirty_clear(target_p, pcontrol);
3375 }
3376 break;
3377 }
3378
3379 out:
3380 if (zombref) {
3381 proc_drop_zombref(target_p);
3382 } else {
3383 proc_rele(target_p);
3384 }
3385
3386 return error;
3387 }
3388 #else
3389
3390 int
proc_dirtycontrol(__unused int pid,__unused int flavor,__unused uint64_t arg,__unused int32_t * retval)3391 proc_dirtycontrol(__unused int pid, __unused int flavor, __unused uint64_t arg, __unused int32_t *retval)
3392 {
3393 return ENOTSUP;
3394 }
3395
3396 #endif /* CONFIG_MEMORYSTATUS */
3397
3398 /*
3399 * proc_terminate_with_proc() provides support for sudden termination by proc_t.
3400 * SIGKILL is issued to tracked, clean processes; otherwise,
3401 * SIGTERM is sent.
3402 */
3403 static int
proc_terminate_with_proc(proc_t p,int32_t * retval)3404 proc_terminate_with_proc(proc_t p, int32_t *retval)
3405 {
3406 int sig;
3407
3408 /* Not allowed to sudden terminate yourself */
3409 if (p == current_proc()) {
3410 return EPERM;
3411 }
3412
3413 #if CONFIG_MEMORYSTATUS
3414 /* Determine requisite signal to issue */
3415 sig = memorystatus_on_terminate(p);
3416 #else
3417 sig = SIGTERM;
3418 #endif
3419
3420 proc_set_task_policy(proc_task(p), TASK_POLICY_ATTRIBUTE,
3421 TASK_POLICY_TERMINATED, TASK_POLICY_ENABLE);
3422
3423 psignal(p, sig);
3424 *retval = sig;
3425
3426 return 0;
3427 }
3428
3429 /*
3430 * proc_terminate() provides support for sudden termination by PID.
3431 * SIGKILL is issued to tracked, clean processes; otherwise,
3432 * SIGTERM is sent.
3433 */
3434 int
proc_terminate(int pid,int32_t * retval)3435 proc_terminate(int pid, int32_t *retval)
3436 {
3437 int error = 0;
3438 proc_t p;
3439 kauth_cred_t uc = kauth_cred_get();
3440
3441 #if 0
3442 /* XXX: Check if these are necessary */
3443 AUDIT_ARG(pid, pid);
3444 #endif
3445
3446 if (pid <= 0 || retval == NULL) {
3447 return EINVAL;
3448 }
3449
3450 if ((p = proc_find(pid)) == NULL) {
3451 return ESRCH;
3452 }
3453
3454 #if 0
3455 /* XXX: Check if these are necessary */
3456 AUDIT_ARG(process, p);
3457 #endif
3458
3459 /* Check privileges; if SIGKILL can be issued, then SIGTERM is also OK */
3460 if (!cansignal(current_proc(), uc, p, SIGKILL)) {
3461 proc_rele(p);
3462 return EPERM;
3463 }
3464
3465 error = proc_terminate_with_proc(p, retval);
3466 proc_rele(p);
3467 return error;
3468 }
3469
3470 #define cryptexdrsrWriteEntitlement "com.apple.private.cryptexd-rsr-write"
3471
3472 int proc_rsr_in_progress = 0;
3473
3474 static int
3475 sysctl_proc_rsr_in_progress SYSCTL_HANDLER_ARGS
3476 {
3477 int error = 0;
3478
3479 if (req->newptr != 0) {
3480 /* Write entitlement is required for updating this sysctl */
3481 if (!IOCurrentTaskHasEntitlement(cryptexdrsrWriteEntitlement)) {
3482 return EPERM;
3483 }
3484 }
3485 error = sysctl_handle_int(oidp, arg1, arg2, req);
3486
3487 return error;
3488 }
3489
3490 SYSCTL_PROC(_kern, OID_AUTO, proc_rsr_in_progress,
3491 CTLTYPE_INT | CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
3492 &proc_rsr_in_progress, 0,
3493 sysctl_proc_rsr_in_progress, "I", "");
3494
3495 struct proc_terminate_all_rsr_struct {
3496 int ptss_sig;
3497 int32_t *ptss_retval;
3498 };
3499
3500 /**
3501 * @brief Helper to obtain the proc_ident for a process given its audit_token_t
3502 *
3503 * @param out The output struct proc_ident
3504 * @param token The audit token of the process to search for
3505 * @return 0 on success, non-zero failure
3506 */
3507 static int
proc_ident_for_audit_token(proc_ident_t out,audit_token_t token)3508 proc_ident_for_audit_token(proc_ident_t out, audit_token_t token)
3509 {
3510 int result = 0;
3511 proc_t p = PROC_NULL;
3512
3513 if ((p = proc_find_audit_token(token)) == PROC_NULL) {
3514 result = -ESRCH;
3515 goto out;
3516 }
3517
3518 *out = proc_ident(p);
3519 out:
3520 if (p != PROC_NULL) {
3521 proc_rele(p);
3522 p = PROC_NULL;
3523 }
3524 return result;
3525 }
3526
3527 /**
3528 * @brief Helper to signal a process by audit token.
3529 *
3530 * @note Invokes proc_terminate_with_proc if should_terminate is true, otherwise invokes
3531 * psignal with the signal.
3532 *
3533 * @param instigator The instigator process (if applicable, may be NULL)
3534 * @param target The target process audit token
3535 * @param signum Signal number to send
3536 * @param should_terminate Should the process be terminated
3537 * @param retval Return value for libproc callers
3538 */
3539 static int
psignal_by_audit_token(audit_token_t * instigator,audit_token_t target,int signum,bool should_terminate,int32_t * retval)3540 psignal_by_audit_token(audit_token_t *instigator, audit_token_t target, int signum, bool should_terminate, int32_t *retval)
3541 {
3542 int error = 0;
3543 proc_t target_proc = PROC_NULL;
3544 struct proc_ident i_ident;
3545 struct proc_ident t_ident;
3546 kauth_cred_t uc = kauth_cred_get();
3547
3548 // Check that the signal number is valid
3549 if (!((signum > 0) && (signum < NSIG)) || retval == NULL) {
3550 error = EINVAL;
3551 goto out;
3552 }
3553
3554 // If instigator is not NULL, successful lookup is required
3555 if (instigator != NULL && (proc_ident_for_audit_token(&i_ident, *instigator) != 0)) {
3556 error = ESRCH;
3557 goto out;
3558 }
3559
3560 // Lookup of target process must succeed
3561 if (proc_ident_for_audit_token(&t_ident, target) != 0) {
3562 error = ESRCH;
3563 goto out;
3564 }
3565
3566 // Check MACF policy without holding any refs, proceed if the signal is allowed to be sent.
3567 if (mac_proc_check_signal(current_proc(), instigator == NULL ? NULL : &i_ident, &t_ident, signum) != 0) {
3568 error = EPERM;
3569 goto out;
3570 }
3571
3572 // Acquire the target process ref to actually send the signal
3573 if ((target_proc = proc_find_ident(&t_ident)) == PROC_NULL) {
3574 error = ESRCH;
3575 goto out;
3576 }
3577
3578 // Check the calling process privileges
3579 if (!cansignal_nomac(current_proc(), uc, target_proc, signum)) {
3580 error = EPERM;
3581 goto out;
3582 }
3583
3584 // Determine if the process should be immediately terminated
3585 // proc_terminate_with_proc() sets retval to the signal that was
3586 // sent (either SIGTERM or SIGKILL).
3587 if (should_terminate) {
3588 error = proc_terminate_with_proc(target_proc, retval);
3589 goto out;
3590 }
3591
3592 /* Send the signal */
3593 psignal(target_proc, signum);
3594 *retval = 0;
3595 out:
3596 if (target_proc != PROC_NULL) {
3597 proc_rele(target_proc);
3598 target_proc = PROC_NULL;
3599 }
3600 return error;
3601 }
3602
3603 #define delegateSignalEntitlement "com.apple.private.delegate-signals"
3604 static int
proc_signal_delegate(user_addr_t buffer,size_t buffersize,int signum,int32_t * retval)3605 proc_signal_delegate(user_addr_t buffer, size_t buffersize, int signum, int32_t *retval)
3606 {
3607 int error = 0;
3608 struct proc_delegated_signal_info info = {0};
3609
3610 /* Enforce current proc is entitled to delegate signals */
3611 if (!IOCurrentTaskHasEntitlement(delegateSignalEntitlement)) {
3612 return EPERM;
3613 }
3614
3615 if (buffer == USER_ADDR_NULL || buffersize != sizeof(struct proc_delegated_signal_info)) {
3616 return EINVAL;
3617 }
3618
3619 error = copyin(buffer, &info, sizeof(struct proc_delegated_signal_info));
3620 if (error != 0) {
3621 return error;
3622 }
3623
3624 /* Final signal checks on current_proc */
3625 return psignal_by_audit_token(&info.instigator, info.target, signum, false, retval);
3626 }
3627
3628 static int
proc_terminate_delegate(user_addr_t buffer,size_t buffersize,int32_t * retval)3629 proc_terminate_delegate(user_addr_t buffer, size_t buffersize, int32_t *retval)
3630 {
3631 int error = 0;
3632 struct proc_delegated_signal_info info = {0};
3633
3634 /* Enforce current proc is entitled to delegate signals */
3635 if (!IOCurrentTaskHasEntitlement(delegateSignalEntitlement)) {
3636 return EPERM;
3637 }
3638
3639 if (buffer == USER_ADDR_NULL || buffersize != sizeof(struct proc_delegated_signal_info)) {
3640 return EINVAL;
3641 }
3642
3643 error = copyin(buffer, &info, sizeof(struct proc_delegated_signal_info));
3644 if (error != 0) {
3645 return error;
3646 }
3647
3648 /* Final signal checks on current_proc */
3649 return psignal_by_audit_token(&info.instigator, info.target, SIGTERM, true, retval);
3650 }
3651
3652 static int
proc_signal_with_audittoken(user_addr_t buffer,size_t buffersize,int signum,int32_t * retval)3653 proc_signal_with_audittoken(user_addr_t buffer, size_t buffersize, int signum, int32_t *retval)
3654 {
3655 int error = 0;
3656 audit_token_t target = INVALID_AUDIT_TOKEN_VALUE;
3657
3658 if (buffer == USER_ADDR_NULL || buffersize != sizeof(audit_token_t)) {
3659 error = EINVAL;
3660 goto out;
3661 }
3662
3663 error = copyin(buffer, &target, sizeof(audit_token_t));
3664 if (error != 0) {
3665 goto out;
3666 }
3667
3668 error = psignal_by_audit_token(NULL, target, signum, false, retval);
3669 out:
3670 return error;
3671 }
3672
3673 /*
3674 * proc_terminate_with_audittoken() provides support for sudden termination by audit token.
3675 * SIGKILL is issued to tracked, clean processes; otherwise,
3676 * SIGTERM is sent.
3677 */
3678 static int
proc_terminate_with_audittoken(user_addr_t buffer,size_t buffersize,int32_t * retval)3679 proc_terminate_with_audittoken(user_addr_t buffer, size_t buffersize, int32_t *retval)
3680 {
3681 int error = 0;
3682 audit_token_t target = INVALID_AUDIT_TOKEN_VALUE;
3683
3684 if (buffer == USER_ADDR_NULL || buffersize != sizeof(audit_token_t)) {
3685 error = EINVAL;
3686 goto out;
3687 }
3688
3689 error = copyin(buffer, &target, sizeof(audit_token_t));
3690 if (error != 0) {
3691 goto out;
3692 }
3693
3694 error = psignal_by_audit_token(NULL, target, SIGTERM, true, retval);
3695 out:
3696 return error;
3697 }
3698
3699 /*
3700 * proc_terminate_all_rsr() provides support for sudden termination of all
3701 * rsr processes. Based of user arguments, either a SIGKILL or SIGTERM is
3702 * sent to the process. EPERM would be returned if the current process
3703 * did not have privilege to send signal to a process that was marked as a
3704 * rsr process. Processes before that would have received the signal.
3705 */
3706
3707 static int
proc_terminate_all_rsr(__unused int pid,__unused int flavor,int arg,int32_t * retval)3708 proc_terminate_all_rsr(__unused int pid, __unused int flavor, int arg, int32_t *retval)
3709 {
3710 int error = 0;
3711
3712 if (arg != SIGKILL && arg != SIGTERM) {
3713 return EINVAL;
3714 }
3715
3716 if (retval == NULL) {
3717 return EINVAL;
3718 }
3719
3720 *retval = 0;
3721 struct proc_terminate_all_rsr_struct callback_arg = {
3722 .ptss_sig = arg, .ptss_retval = retval,
3723 };
3724 proc_iterate(PROC_ALLPROCLIST, proc_terminate_all_rsr_callback,
3725 (void *)&callback_arg, proc_terminate_all_rsr_filter, NULL);
3726
3727 if (*retval != 0) {
3728 error = *retval;
3729 *retval = 0;
3730 } else {
3731 *retval = arg;
3732 }
3733 return error;
3734 }
3735
3736 static int
proc_terminate_all_rsr_filter(proc_t p,__unused void * arg)3737 proc_terminate_all_rsr_filter(proc_t p, __unused void *arg)
3738 {
3739 return !!(p->p_ladvflag & P_RSR);
3740 }
3741
3742 static int
proc_terminate_all_rsr_callback(proc_t p,void * arg)3743 proc_terminate_all_rsr_callback(proc_t p, void *arg)
3744 {
3745 struct proc_terminate_all_rsr_struct *callback_arg = arg;
3746 kauth_cred_t uc = kauth_cred_get();
3747 int sig = callback_arg->ptss_sig;
3748 int32_t *retval = callback_arg->ptss_retval;
3749
3750 /* Check privileges; if SIGKILL can be issued, then SIGTERM is also OK */
3751 if (!cansignal(current_proc(), uc, p, SIGKILL)) {
3752 *retval = EPERM;
3753 return PROC_RETURNED_DONE;
3754 }
3755
3756 proc_set_task_policy(proc_task(p), TASK_POLICY_ATTRIBUTE,
3757 TASK_POLICY_TERMINATED, TASK_POLICY_ENABLE);
3758
3759 psignal(p, sig);
3760 return PROC_RETURNED;
3761 }
3762
3763 /*
3764 * copy stat64 structure into vinfo_stat structure.
3765 */
3766 static void
munge_vinfo_stat(struct stat64 * sbp,struct vinfo_stat * vsbp)3767 munge_vinfo_stat(struct stat64 *sbp, struct vinfo_stat *vsbp)
3768 {
3769 bzero(vsbp, sizeof(struct vinfo_stat));
3770
3771 vsbp->vst_dev = sbp->st_dev;
3772 vsbp->vst_mode = sbp->st_mode;
3773 vsbp->vst_nlink = sbp->st_nlink;
3774 vsbp->vst_ino = sbp->st_ino;
3775 vsbp->vst_uid = sbp->st_uid;
3776 vsbp->vst_gid = sbp->st_gid;
3777 vsbp->vst_atime = sbp->st_atimespec.tv_sec;
3778 vsbp->vst_atimensec = sbp->st_atimespec.tv_nsec;
3779 vsbp->vst_mtime = sbp->st_mtimespec.tv_sec;
3780 vsbp->vst_mtimensec = sbp->st_mtimespec.tv_nsec;
3781 vsbp->vst_ctime = sbp->st_ctimespec.tv_sec;
3782 vsbp->vst_ctimensec = sbp->st_ctimespec.tv_nsec;
3783 vsbp->vst_birthtime = sbp->st_birthtimespec.tv_sec;
3784 vsbp->vst_birthtimensec = sbp->st_birthtimespec.tv_nsec;
3785 vsbp->vst_size = sbp->st_size;
3786 vsbp->vst_blocks = sbp->st_blocks;
3787 vsbp->vst_blksize = sbp->st_blksize;
3788 vsbp->vst_flags = sbp->st_flags;
3789 vsbp->vst_gen = sbp->st_gen;
3790 vsbp->vst_rdev = sbp->st_rdev;
3791 vsbp->vst_qspare[0] = sbp->st_qspare[0];
3792 vsbp->vst_qspare[1] = sbp->st_qspare[1];
3793 }
3794
3795 int
proc_pid_rusage(int pid,int flavor,user_addr_t buffer,__unused int32_t * retval)3796 proc_pid_rusage(int pid, int flavor, user_addr_t buffer, __unused int32_t *retval)
3797 {
3798 proc_t p;
3799 int error;
3800 int zombie = 0;
3801
3802 if ((p = proc_find(pid)) == PROC_NULL) {
3803 if ((p = proc_find_zombref(pid)) == PROC_NULL) {
3804 return ESRCH;
3805 }
3806 zombie = 1;
3807 }
3808
3809 /* Do we have permission to look into this? */
3810 if ((error = proc_security_policy(p, PROC_INFO_CALL_PIDRUSAGE, flavor, CHECK_SAME_USER))) {
3811 goto out;
3812 }
3813
3814 error = proc_get_rusage(p, flavor, buffer, zombie);
3815
3816 out:
3817 if (zombie) {
3818 proc_drop_zombref(p);
3819 } else {
3820 proc_rele(p);
3821 }
3822
3823 return error;
3824 }
3825
3826 void
proc_archinfo(proc_t p,struct proc_archinfo * pai)3827 proc_archinfo(proc_t p, struct proc_archinfo *pai)
3828 {
3829 proc_lock(p);
3830 pai->p_cputype = p->p_cputype;
3831 pai->p_cpusubtype = p->p_cpusubtype;
3832 proc_unlock(p);
3833 }
3834
3835 void
proc_pidcoalitioninfo(proc_t p,struct proc_pidcoalitioninfo * ppci)3836 proc_pidcoalitioninfo(proc_t p, struct proc_pidcoalitioninfo *ppci)
3837 {
3838 bzero(ppci, sizeof(*ppci));
3839 proc_coalitionids(p, ppci->coalition_id);
3840 }
3841
3842 int
proc_pidexitreasoninfo(proc_t p,struct proc_exitreasoninfo * peri,struct proc_exitreasonbasicinfo * pberi)3843 proc_pidexitreasoninfo(proc_t p, struct proc_exitreasoninfo *peri, struct proc_exitreasonbasicinfo *pberi)
3844 {
3845 uint32_t reason_data_size = 0;
3846 int error = 0;
3847 pid_t selfpid = proc_selfpid();
3848
3849 proc_lock(p);
3850
3851 /*
3852 * One (and only one) of peri and pberi must be non-NULL.
3853 */
3854 assert((peri != NULL) || (pberi != NULL));
3855 assert((peri == NULL) || (pberi == NULL));
3856
3857 /*
3858 * Allow access to the parent of the exiting
3859 * child or the parent debugger only.
3860 */
3861 do {
3862 if (p->p_ppid == selfpid) {
3863 break; /* parent => ok */
3864 }
3865 if ((p->p_lflag & P_LTRACED) != 0 &&
3866 (p->p_oppid == selfpid)) {
3867 break; /* parent-in-waiting => ok */
3868 }
3869 proc_unlock(p);
3870 return EACCES;
3871 } while (0);
3872
3873 if (p->p_exit_reason == OS_REASON_NULL) {
3874 proc_unlock(p);
3875 return ENOENT;
3876 }
3877
3878 if (p->p_exit_reason->osr_kcd_buf != NULL) {
3879 reason_data_size = (uint32_t)kcdata_memory_get_used_bytes(&p->p_exit_reason->osr_kcd_descriptor);
3880 }
3881
3882 if (peri != NULL) {
3883 peri->eri_namespace = p->p_exit_reason->osr_namespace;
3884 peri->eri_code = p->p_exit_reason->osr_code;
3885 peri->eri_flags = p->p_exit_reason->osr_flags;
3886
3887 if ((peri->eri_kcd_buf == 0) || (peri->eri_reason_buf_size < reason_data_size)) {
3888 proc_unlock(p);
3889 return ENOMEM;
3890 }
3891
3892 peri->eri_reason_buf_size = reason_data_size;
3893 if (reason_data_size != 0) {
3894 error = copyout(p->p_exit_reason->osr_kcd_buf, (user_addr_t)peri->eri_kcd_buf, reason_data_size);
3895 }
3896 } else {
3897 pberi->beri_namespace = p->p_exit_reason->osr_namespace;
3898 pberi->beri_code = p->p_exit_reason->osr_code;
3899 pberi->beri_flags = p->p_exit_reason->osr_flags;
3900 pberi->beri_reason_buf_size = reason_data_size;
3901 }
3902
3903 proc_unlock(p);
3904
3905 return error;
3906 }
3907
3908 /*
3909 * Wrapper to provide NOTE_EXIT_DETAIL and NOTE_EXITSTATUS
3910 * It mimics the data that is typically captured by the
3911 * EVFILT_PROC, NOTE_EXIT event mechanism.
3912 * See filt_proc() in kern_event.c.
3913 */
3914 int
proc_pidnoteexit(proc_t p,uint64_t flags,uint32_t * data)3915 proc_pidnoteexit(proc_t p, uint64_t flags, uint32_t *data)
3916 {
3917 uint32_t exit_data = 0;
3918 uint32_t exit_flags = (uint32_t)flags;
3919
3920 proc_lock(p);
3921
3922 /*
3923 * Allow access to the parent of the exiting
3924 * child or the parent debugger only.
3925 */
3926 do {
3927 pid_t selfpid = proc_selfpid();
3928
3929 if (p->p_ppid == selfpid) {
3930 break; /* parent => ok */
3931 }
3932 if ((p->p_lflag & P_LTRACED) != 0 &&
3933 (p->p_oppid == selfpid)) {
3934 break; /* parent-in-waiting => ok */
3935 }
3936 proc_unlock(p);
3937 return EACCES;
3938 } while (0);
3939
3940 if ((exit_flags & NOTE_EXITSTATUS) != 0) {
3941 /* The signal and exit status */
3942 exit_data |= (p->p_xstat & NOTE_PDATAMASK);
3943 }
3944
3945 if ((exit_flags & NOTE_EXIT_DETAIL) != 0) {
3946 /* The exit detail */
3947 if ((p->p_lflag & P_LTERM_DECRYPTFAIL) != 0) {
3948 exit_data |= NOTE_EXIT_DECRYPTFAIL;
3949 }
3950
3951 if ((p->p_lflag & P_LTERM_JETSAM) != 0) {
3952 exit_data |= NOTE_EXIT_MEMORY;
3953
3954 switch (p->p_lflag & P_JETSAM_MASK) {
3955 case P_JETSAM_VMPAGESHORTAGE:
3956 exit_data |= NOTE_EXIT_MEMORY_VMPAGESHORTAGE;
3957 break;
3958 case P_JETSAM_VMTHRASHING:
3959 exit_data |= NOTE_EXIT_MEMORY_VMTHRASHING;
3960 break;
3961 case P_JETSAM_FCTHRASHING:
3962 exit_data |= NOTE_EXIT_MEMORY_FCTHRASHING;
3963 break;
3964 case P_JETSAM_VNODE:
3965 exit_data |= NOTE_EXIT_MEMORY_VNODE;
3966 break;
3967 case P_JETSAM_HIWAT:
3968 exit_data |= NOTE_EXIT_MEMORY_HIWAT;
3969 break;
3970 case P_JETSAM_PID:
3971 exit_data |= NOTE_EXIT_MEMORY_PID;
3972 break;
3973 case P_JETSAM_IDLEEXIT:
3974 exit_data |= NOTE_EXIT_MEMORY_IDLE;
3975 break;
3976 }
3977 }
3978
3979 if ((proc_getcsflags(p) & CS_KILLED) != 0) {
3980 exit_data |= NOTE_EXIT_CSERROR;
3981 }
3982 }
3983
3984 proc_unlock(p);
3985
3986 *data = exit_data;
3987
3988 return 0;
3989 }
3990
3991 int
proc_piddynkqueueinfo(int pid,int flavor,kqueue_id_t kq_id,user_addr_t ubuf,uint32_t bufsize,int32_t * retval)3992 proc_piddynkqueueinfo(int pid, int flavor, kqueue_id_t kq_id,
3993 user_addr_t ubuf, uint32_t bufsize, int32_t *retval)
3994 {
3995 proc_t p;
3996 int err;
3997
3998 if (ubuf == USER_ADDR_NULL) {
3999 return EFAULT;
4000 }
4001
4002 p = proc_find(pid);
4003 if (p == PROC_NULL) {
4004 return ESRCH;
4005 }
4006
4007 err = proc_security_policy(p, PROC_INFO_CALL_PIDDYNKQUEUEINFO, 0, CHECK_SAME_USER);
4008 if (err) {
4009 goto out;
4010 }
4011
4012 switch (flavor) {
4013 case PROC_PIDDYNKQUEUE_INFO:
4014 err = kevent_copyout_dynkqinfo(p, kq_id, ubuf, bufsize, retval);
4015 break;
4016 case PROC_PIDDYNKQUEUE_EXTINFO:
4017 err = kevent_copyout_dynkqextinfo(p, kq_id, ubuf, bufsize, retval);
4018 break;
4019 default:
4020 err = ENOTSUP;
4021 break;
4022 }
4023
4024 out:
4025 proc_rele(p);
4026
4027 return err;
4028 }
4029
4030 #if CONFIG_PROC_UDATA_STORAGE
4031 int
proc_udata_info(int pid,int flavor,user_addr_t buffer,uint32_t bufsize,int32_t * retval)4032 proc_udata_info(int pid, int flavor, user_addr_t buffer, uint32_t bufsize, int32_t *retval)
4033 {
4034 int err = 0;
4035 proc_t p;
4036
4037 p = proc_find(pid);
4038 if (p == PROC_NULL) {
4039 return ESRCH;
4040 }
4041
4042 /*
4043 * Only support calls against oneself for the moment.
4044 */
4045 if (proc_getpid(p) != proc_selfpid()) {
4046 err = EACCES;
4047 goto out;
4048 }
4049
4050 if (bufsize != sizeof(p->p_user_data)) {
4051 err = EINVAL;
4052 goto out;
4053 }
4054
4055 switch (flavor) {
4056 case PROC_UDATA_INFO_SET:
4057 err = copyin(buffer, &p->p_user_data, sizeof(p->p_user_data));
4058 break;
4059 case PROC_UDATA_INFO_GET:
4060 err = copyout(&p->p_user_data, buffer, sizeof(p->p_user_data));
4061 break;
4062 default:
4063 err = ENOTSUP;
4064 break;
4065 }
4066
4067 out:
4068 proc_rele(p);
4069
4070 if (err == 0) {
4071 *retval = 0;
4072 }
4073
4074 return err;
4075 }
4076 #endif /* CONFIG_PROC_UDATA_STORAGE */
4077
4078
4079 int
proc_set_dyld_images(int pid,user_addr_t buffer,uint32_t buffersize,int32_t * retval)4080 proc_set_dyld_images(int pid, user_addr_t buffer, uint32_t buffersize, int32_t *retval)
4081 {
4082 struct proc * pself = PROC_NULL;
4083 task_t task = TASK_NULL;
4084
4085 pself = current_proc();
4086 if (pid != proc_getpid(pself)) {
4087 *retval = -1;
4088 return EINVAL;
4089 }
4090
4091 if (buffer == 0) {
4092 *retval = -1;
4093 return EINVAL;
4094 }
4095
4096 task = proc_task(pself);
4097 if (task != TASK_NULL) {
4098 /* don't need to copyin the buffer. just setting the buffer range in the task struct */
4099 if (task_set_dyld_info(task, buffer, buffersize, false)) {
4100 *retval = -1;
4101 return EINVAL;
4102 }
4103 }
4104
4105 *retval = 0;
4106 return 0;
4107 }
4108