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