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