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