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