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