1 /*-
2 * Copyright (c) 2014-2015, Matthew Macy <mmacy@nextbsd.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Neither the name of Matthew Macy nor the names of its
12 * contributors may be used to endorse or promote products derived from
13 * this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/filedesc.h>
34 #include <sys/lock.h>
35 #include <sys/malloc.h>
36 #include <sys/mutex.h>
37 #include <sys/priv.h>
38 #include <sys/proc.h>
39 #include <sys/procctl.h>
40 #include <sys/ptrace.h>
41 #include <sys/rwlock.h>
42 #include <sys/syscallsubr.h>
43 #include <sys/sysent.h>
44 #include <sys/sysproto.h>
45 #include <sys/vnode.h>
46 #include <sys/sx.h>
47 #include <sys/signalvar.h>
48 #include <sys/tty.h>
49
50 #include <vm/vm.h>
51 #include <vm/pmap.h>
52 #include <vm/vm_extern.h>
53 #include <vm/vm_map.h>
54 #include <vm/vm_kern.h>
55 #include <vm/vm_object.h>
56 #include <vm/vm_page.h>
57 #include <vm/vm_param.h>
58
59 #include <sys/mach/mach_types.h>
60 #include <sys/mach/ipc/ipc_kmsg.h>
61 #include <sys/mach/thread.h>
62 #define PRIVATE
63 #include <sys/proc_info.h>
64
65
66 int set_security_token(task_t);
67
68
69 static int
proc_terminate(int pid)70 proc_terminate(int pid)
71 {
72 int err;
73 struct proc *p;
74
75 err = 0;
76 if (pid <= 0)
77 return (EINVAL);
78 if (pid == curproc->p_pid)
79 return (EPERM);
80 if ((p = pfind(pid)) == NULL)
81 return (ESRCH);
82 if ((err = p_cansignal(curthread, p, SIGKILL)) == 0) {
83 /* p_cansignal returns 0 if you can, or an error if you can't. */
84 kern_psignal(p, SIGTERM);
85 }
86 PROC_UNLOCK(p);
87 return (err);
88 }
89
90 static int
proc_listpids(uint32_t type,uint32_t flavor,void * ubuffer,uint32_t buffersize)91 proc_listpids(uint32_t type, uint32_t flavor, void *ubuffer, uint32_t buffersize)
92 {
93 struct proc *p;
94 struct proclist *list;
95 struct pgrp *pgrpp;
96 int err, count, incr, maxpidcount, numpids;
97 pid_t *buf, *ptr;
98 uid_t uid;
99 struct thread *td;
100
101 if (type == PROC_TTY_ONLY)
102 return (EINVAL);
103
104 td = curthread;
105 if (ubuffer == NULL) {
106 td->td_retval[0] = (nprocs + 30)*sizeof(pid_t);
107 return (0);
108 }
109 if (buffersize < sizeof(pid_t))
110 return (ENOMEM);
111
112 maxpidcount = buffersize/sizeof(pid_t);
113 numpids = nprocs + 30;
114 err = count = 0;
115 if (numpids > maxpidcount)
116 numpids = maxpidcount;
117
118 buf = malloc(numpids *sizeof(pid_t), M_DEVBUF, M_WAITOK);
119
120 ptr = buf;
121 if (type == PROC_PGRP_ONLY) {
122 count = 0;
123 pgrpp = pgfind(flavor);
124 if (pgrpp == NULL)
125 return (ENOENT);
126 list = (struct proclist *)&pgrpp->pg_members;
127 LIST_FOREACH(p, list, p_pglist) {
128 if (count == numpids)
129 break;
130 *ptr++ = p->p_pid;
131 count++;
132 }
133 PGRP_UNLOCK(pgrpp);
134 goto done;
135 }
136
137 list = &allproc;
138 sx_slock(&allproc_lock);
139 scan_next:
140 LIST_FOREACH(p, list, p_list) {
141 incr = 0;
142 switch (type) {
143 case PROC_ALL_PIDS:
144 incr = 1;
145 break;
146 case PROC_PPID_ONLY:
147 if (((p->p_pptr && (p->p_pptr->p_pid == flavor)) &&
148 ((p->p_flag & P_TRACED) == 0)) ||
149 p->p_oppid == flavor)
150 incr = 1;
151 break;
152 case PROC_UID_ONLY:
153 if (p->p_ucred != NULL) {
154 uid = p->p_ucred->cr_uid;
155 if (uid == flavor)
156 incr = 1;
157 }
158 break;
159 case PROC_RUID_ONLY:
160 if (p->p_ucred != NULL) {
161 uid = p->p_ucred->cr_ruid;
162 if (uid == flavor)
163 incr = 1;
164 }
165 break;
166 default:
167 err = EINVAL;
168 goto done;
169 }
170 if (incr) {
171 *ptr++ = p->p_pid;
172 count++;
173 }
174 if (count >= numpids)
175 break;
176 }
177 if ((count < numpids) && (list == &allproc)) {
178 list = &zombproc;
179 goto scan_next;
180 }
181 done:
182 sx_sunlock(&allproc_lock);
183 if (err)
184 return (err);
185
186 err = copyout(buf, ubuffer, count * sizeof(pid_t));
187 if (err == 0)
188 td->td_retval[0] = count * sizeof(pid_t);
189 free(buf, M_DEVBUF);
190
191 return (err);
192 }
193
194 static int
proc_pidbsdinfo(struct proc * p,struct proc_bsdinfo * pbsd,int zombie)195 proc_pidbsdinfo(struct proc *p, struct proc_bsdinfo * pbsd, int zombie)
196 {
197 register struct tty *tp;
198 struct session *sessionp = NULL;
199 struct pgrp * pg;
200 struct ucred *cred;
201
202 pg = p->p_pgrp;
203 if (pg)
204 sessionp = pg->pg_session;
205
206 bzero(pbsd, sizeof(struct proc_bsdinfo));
207 pbsd->pbi_status = p->p_state;
208 pbsd->pbi_xstatus = KW_EXITCODE(p->p_xexit, p->p_xsig);
209 pbsd->pbi_pid = p->p_pid;
210 if (p->p_pptr)
211 pbsd->pbi_ppid = p->p_pptr->p_pid;
212 crhold(p->p_ucred);
213 cred = p->p_ucred;
214 pbsd->pbi_uid = cred->cr_uid;
215 pbsd->pbi_gid = cred->cr_gid;
216 pbsd->pbi_ruid = cred->cr_ruid;
217 pbsd->pbi_rgid = cred->cr_rgid;
218 pbsd->pbi_svuid = cred->cr_svuid;
219 pbsd->pbi_svgid = cred->cr_svgid;
220 crfree(cred);
221
222 pbsd->pbi_nice = p->p_nice;
223 #ifdef notyet
224 pbsd->pbi_start_tvsec = p->p_start.tv_sec;
225 pbsd->pbi_start_tvusec = p->p_start.tv_usec;
226 #endif
227 bcopy(&p->p_comm, &pbsd->pbi_comm[0], MAXCOMLEN);
228 pbsd->pbi_comm[MAXCOMLEN - 1] = '\0';
229 pbsd->pbi_flags = 0;
230 if ((p->p_flag & P_SYSTEM) == P_SYSTEM)
231 pbsd->pbi_flags |= PROC_FLAG_SYSTEM;
232 if ((p->p_flag & P_TRACED) == P_TRACED)
233 pbsd->pbi_flags |= PROC_FLAG_TRACED;
234 if ((p->p_flag & P_WEXIT) == P_WEXIT)
235 pbsd->pbi_flags |= PROC_FLAG_INEXIT;
236 if ((p->p_flag & P_PPWAIT) == P_PPWAIT)
237 pbsd->pbi_flags |= PROC_FLAG_PPWAIT;
238 #ifdef notyet
239 if ((p->p_flag & P_LP64) == P_LP64)
240 #endif
241 #ifdef __LP64__
242 pbsd->pbi_flags |= PROC_FLAG_LP64;
243 #endif
244 if ((p->p_flag & P_CONTROLT) == P_CONTROLT)
245 pbsd->pbi_flags |= PROC_FLAG_CONTROLT;
246 if ((p->p_flag & P_SUGID) == P_SUGID)
247 pbsd->pbi_flags |= PROC_FLAG_PSUGID;
248 if ((p->p_flag & P_EXEC) == P_EXEC)
249 pbsd->pbi_flags |= PROC_FLAG_EXEC;
250
251 if (sessionp != NULL) {
252 if (p == sessionp->s_leader)
253 pbsd->pbi_flags |= PROC_FLAG_SLEADER;
254 if (sessionp->s_ttyvp)
255 pbsd->pbi_flags |= PROC_FLAG_CTTY;
256 }
257
258 if (zombie == 0)
259 pbsd->pbi_nfiles = p->p_fd->fd_nfiles;
260
261 pbsd->e_tdev = NODEV;
262 if (pg != NULL) {
263 pbsd->pbi_pgid = pg->pg_id;
264 pbsd->pbi_pjobc = pg->pg_jobc;
265 if ((p->p_flag & P_CONTROLT) && (sessionp != NULL) && (tp = sessionp->s_ttyp)) {
266 #ifdef notyet
267 pbsd->e_tdev = tp->t_dev;
268 #endif
269 if (tp->t_pgrp)
270 pbsd->e_tpgid = tp->t_pgrp->pg_id;
271 }
272 }
273 return(0);
274 }
275
276 static int
proc_pidshortbsdinfo(struct proc * p,struct proc_bsdshortinfo * pbsd_shortp,int zombie)277 proc_pidshortbsdinfo(struct proc *p, struct proc_bsdshortinfo * pbsd_shortp, int zombie)
278 {
279 struct ucred *cred;
280
281 bzero(pbsd_shortp, sizeof(struct proc_bsdshortinfo));
282 pbsd_shortp->pbsi_pid = p->p_pid;
283 if (p->p_pptr)
284 pbsd_shortp->pbsi_ppid = p->p_pptr->p_pid;
285 if (p->p_pgrp)
286 pbsd_shortp->pbsi_pgid = p->p_pgrp->pg_id;
287 pbsd_shortp->pbsi_status = p->p_state;
288 bcopy(&p->p_comm, &pbsd_shortp->pbsi_comm[0], MAXCOMLEN);
289 pbsd_shortp->pbsi_comm[MAXCOMLEN - 1] = '\0';
290
291 pbsd_shortp->pbsi_flags = 0;
292 if ((p->p_flag & P_SYSTEM) == P_SYSTEM)
293 pbsd_shortp->pbsi_flags |= PROC_FLAG_SYSTEM;
294 if ((p->p_flag & P_TRACED) == P_TRACED)
295 pbsd_shortp->pbsi_flags |= PROC_FLAG_TRACED;
296 if ((p->p_flag & P_WEXIT) == P_WEXIT)
297 pbsd_shortp->pbsi_flags |= PROC_FLAG_INEXIT;
298 if ((p->p_flag & P_PPWAIT) == P_PPWAIT)
299 pbsd_shortp->pbsi_flags |= PROC_FLAG_PPWAIT;
300 #ifdef notyet
301 if ((p->p_flag & P_LP64) == P_LP64)
302 #endif
303 #ifdef __LP64__
304 pbsd_shortp->pbsi_flags |= PROC_FLAG_LP64;
305 #endif
306 if ((p->p_flag & P_CONTROLT) == P_CONTROLT)
307 pbsd_shortp->pbsi_flags |= PROC_FLAG_CONTROLT;
308 if ((p->p_flag & P_SUGID) == P_SUGID)
309 pbsd_shortp->pbsi_flags |= PROC_FLAG_PSUGID;
310 if ((p->p_flag & P_EXEC) == P_EXEC)
311 pbsd_shortp->pbsi_flags |= PROC_FLAG_EXEC;
312
313 crhold(p->p_ucred);
314 cred = p->p_ucred;
315 pbsd_shortp->pbsi_uid = cred->cr_uid;
316 pbsd_shortp->pbsi_gid = cred->cr_gid;
317 pbsd_shortp->pbsi_ruid = cred->cr_ruid;
318 pbsd_shortp->pbsi_rgid = cred->cr_rgid;
319 pbsd_shortp->pbsi_svuid = cred->cr_svuid;
320 pbsd_shortp->pbsi_svgid = cred->cr_svgid;
321 crfree(cred);
322
323 return(0);
324 }
325
326 static uint64_t
proc_puniqueid(struct proc * p)327 proc_puniqueid(struct proc *p)
328 {
329 task_t task;
330
331 task = p->p_machdata;
332 return (task->itk_puniqueid);
333 }
334
335 static uint64_t
proc_uniqueid(struct proc * p)336 proc_uniqueid(struct proc *p)
337 {
338 task_t task;
339
340 task = p->p_machdata;
341 return (task->itk_uniqueid);
342 }
343
344 static void
proc_getexecutableuuid(struct proc * p __unused,unsigned char * uuid,int size)345 proc_getexecutableuuid(struct proc *p __unused, unsigned char *uuid, int size)
346 {
347
348 bzero(uuid, size);
349 }
350
351 static void
proc_piduniqidentifierinfo(struct proc * p,struct proc_uniqidentifierinfo * p_uniqidinfo)352 proc_piduniqidentifierinfo(struct proc *p, struct proc_uniqidentifierinfo *p_uniqidinfo)
353 {
354 p_uniqidinfo->p_uniqueid = proc_uniqueid(p);
355 proc_getexecutableuuid(p, (unsigned char *)&p_uniqidinfo->p_uuid, sizeof(p_uniqidinfo->p_uuid));
356 p_uniqidinfo->p_puniqueid = proc_puniqueid(p);
357 p_uniqidinfo->p_reserve2 = 0;
358 p_uniqidinfo->p_reserve3 = 0;
359 p_uniqidinfo->p_reserve4 = 0;
360 }
361
362 static int
proc_pidinfo(int pid,int flavor,uint64_t arg,void * buffer,uint32_t buffersize)363 proc_pidinfo(int pid, int flavor, uint64_t arg, void *buffer, uint32_t buffersize)
364 {
365 struct proc *p;
366 int err, size, findzomb, iszomb, shortversion, uniqidversion;
367 void *kbuf;
368
369 switch (flavor) {
370 case PROC_PIDTBSDINFO:
371 size = PROC_PIDTBSDINFO_SIZE;
372 break;
373 case PROC_PIDT_SHORTBSDINFO:
374 size = PROC_PIDT_SHORTBSDINFO_SIZE;
375 break;
376 case PROC_PIDUNIQIDENTIFIERINFO:
377 size = PROC_PIDUNIQIDENTIFIERINFO_SIZE;
378 break;
379 case PROC_PIDT_BSDINFOWITHUNIQID:
380 size = PROC_PIDT_BSDINFOWITHUNIQID_SIZE;
381 break;
382 default:
383 return (EINVAL);
384 }
385
386 if (buffersize < size)
387 return (ENOMEM);
388
389 kbuf = malloc(size, M_DEVBUF, M_WAITOK);
390 uniqidversion = shortversion = err = findzomb = iszomb = 0;
391 if ((flavor == PROC_PIDTBSDINFO) || (flavor == PROC_PIDT_SHORTBSDINFO) || (flavor == PROC_PIDT_BSDINFOWITHUNIQID)
392 || (flavor == PROC_PIDUNIQIDENTIFIERINFO)) {
393 if (arg)
394 findzomb = 1;
395 }
396 if ((p = pfind(pid)) == NULL) {
397 if (!findzomb || ((p = zpfind(pid)) == NULL)) {
398 err = ESRCH;
399 goto done;
400 }
401 iszomb = 1;
402 }
403
404 switch (flavor) {
405 case PROC_PIDUNIQIDENTIFIERINFO: {
406 struct proc_uniqidentifierinfo p_uniqidinfo;
407
408 proc_piduniqidentifierinfo(p, &p_uniqidinfo);
409 bcopy(&p_uniqidinfo, kbuf, sizeof(struct proc_uniqidentifierinfo));
410 }
411 break;
412 case PROC_PIDT_SHORTBSDINFO:
413 shortversion = 1;
414 case PROC_PIDT_BSDINFOWITHUNIQID:
415 case PROC_PIDTBSDINFO: {
416 struct proc_bsdinfo pbsd;
417 struct proc_bsdshortinfo pbsd_short;
418 struct proc_bsdinfowithuniqid pbsd_uniqid;
419
420 if (flavor == PROC_PIDT_BSDINFOWITHUNIQID)
421 uniqidversion = 1;
422
423 if (shortversion != 0) {
424 err = proc_pidshortbsdinfo(p, &pbsd_short, iszomb);
425 } else {
426 err = proc_pidbsdinfo(p, &pbsd, iszomb);
427 if (uniqidversion != 0) {
428 proc_piduniqidentifierinfo(p, &pbsd_uniqid.p_uniqidentifier);
429 pbsd_uniqid.pbsd = pbsd;
430 }
431 }
432
433 if (err == 0) {
434 if (shortversion != 0) {
435 bcopy(&pbsd_short, kbuf, sizeof(struct proc_bsdshortinfo));
436 } else if (uniqidversion != 0) {
437 bcopy(&pbsd_uniqid, kbuf, sizeof(struct proc_bsdinfowithuniqid));
438 } else {
439 bcopy(&pbsd, kbuf, sizeof(struct proc_bsdinfo));
440 }
441 }
442 }
443 break;
444 default:
445 err = ENOTSUP;
446 }
447 PROC_UNLOCK(p);
448 if (err == 0)
449 err = copyout(kbuf, buffer, size);
450 if (err == 0)
451 curthread->td_retval[0] = size;
452 done:
453 free(kbuf, M_DEVBUF);
454 return (err);
455 }
456
457 static int
proc_info(int op,pid_t pid,uint32_t flavor,uint64_t arg,void * addr,uint32_t buffersize)458 proc_info(int op, pid_t pid, uint32_t flavor, uint64_t arg, void *addr,
459 uint32_t buffersize)
460 {
461
462 switch (op) {
463 case PROC_INFO_CALL_LISTPIDS:
464 return (proc_listpids(pid, flavor, addr, buffersize));
465 break;
466 case PROC_INFO_CALL_TERMINATE:
467 return (proc_terminate(pid));
468 break;
469 case PROC_INFO_CALL_PIDINFO:
470 return (proc_pidinfo(pid, flavor, arg, addr, buffersize));
471 break;
472 default:
473 return (EOPNOTSUPP);
474 }
475 /* NOT REACHED */
476 return (0);
477 }
478
479 int
set_security_token(task_t task)480 set_security_token(task_t task)
481 {
482 struct proc *p;
483 security_token_t sec_token;
484 audit_token_t audit_token;
485
486 p = task->itk_p;
487
488 sec_token.val[0] = sec_token.val[1] = 0;
489 audit_token.val[0] = 0; /* wat: p->p_ucred->cr_au.ai_auid; */
490 audit_token.val[1] = p->p_ucred->cr_uid;
491 audit_token.val[2] = p->p_ucred->cr_gid;
492 audit_token.val[3] = p->p_ucred->cr_ruid;
493 audit_token.val[4] = p->p_ucred->cr_rgid;
494 audit_token.val[5] = p->p_pid;
495 audit_token.val[6] = 0; /* wat: p->p_ucred->cr_au.ai_asid; */
496 audit_token.val[7] = 0; /* wat: p->p_ucred->cr_au.ai_termid.port; */
497
498 task->audit_token = audit_token;
499 task->sec_token = sec_token;
500
501 return (0);
502 }
503
504 int
sys___proc_info(struct thread * td __unused,struct __proc_info_args * uap)505 sys___proc_info(struct thread *td __unused, struct __proc_info_args *uap)
506 {
507
508 return (proc_info(uap->callnum, uap->pid, uap->flavor, uap->arg, uap->buffer,
509 uap->buffersize));
510 }
511
512
513 int
sys___iopolicysys(struct thread * td __unused,struct __iopolicysys_args * uap __unused)514 sys___iopolicysys(struct thread *td __unused, struct __iopolicysys_args *uap __unused)
515 {
516
517 return (ENOSYS);
518 }
519