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