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