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