xref: /openbsd-src/lib/libkvm/kvm_proc2.c (revision 46035553bfdd96e63c94e32da0210227ec2e3cf1)
1 /*	$OpenBSD: kvm_proc2.c,v 1.32 2020/12/07 16:55:28 mpi Exp $	*/
2 /*	$NetBSD: kvm_proc.c,v 1.30 1999/03/24 05:50:50 mrg Exp $	*/
3 /*-
4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Charles M. Hannum.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 /*-
32  * Copyright (c) 1994, 1995 Charles M. Hannum.  All rights reserved.
33  * Copyright (c) 1989, 1992, 1993
34  *	The Regents of the University of California.  All rights reserved.
35  *
36  * This code is derived from software developed by the Computer Systems
37  * Engineering group at Lawrence Berkeley Laboratory under DARPA contract
38  * BG 91-66 and contributed to Berkeley.
39  *
40  * Redistribution and use in source and binary forms, with or without
41  * modification, are permitted provided that the following conditions
42  * are met:
43  * 1. Redistributions of source code must retain the above copyright
44  *    notice, this list of conditions and the following disclaimer.
45  * 2. Redistributions in binary form must reproduce the above copyright
46  *    notice, this list of conditions and the following disclaimer in the
47  *    documentation and/or other materials provided with the distribution.
48  * 3. Neither the name of the University nor the names of its contributors
49  *    may be used to endorse or promote products derived from this software
50  *    without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62  * SUCH DAMAGE.
63  */
64 
65 /*
66  * Proc traversal interface for kvm.  ps and w are (probably) the exclusive
67  * users of this code, so we've factored it out into a separate module.
68  * Thus, we keep this grunge out of the other kvm applications (i.e.,
69  * most other applications are interested only in open/close/read/nlist).
70  */
71 
72 #define __need_process
73 #include <sys/param.h>
74 #include <sys/proc.h>
75 #include <sys/exec.h>
76 #include <sys/stat.h>
77 #include <sys/ucred.h>
78 #include <sys/ioctl.h>
79 #include <sys/tty.h>
80 #include <sys/resource.h>
81 #include <sys/resourcevar.h>
82 #include <sys/signalvar.h>
83 #include <sys/pledge.h>
84 #include <sys/wait.h>
85 #include <stddef.h>
86 #include <stdlib.h>
87 #include <string.h>
88 #include <unistd.h>
89 #include <nlist.h>
90 #include <kvm.h>
91 
92 #include <uvm/uvm_extern.h>
93 #include <uvm/uvm_amap.h>
94 #include <machine/vmparam.h>
95 #include <machine/pmap.h>
96 
97 #include <sys/sysctl.h>
98 
99 #include <limits.h>
100 #include <errno.h>
101 #include <db.h>
102 #include <paths.h>
103 
104 #include "kvm_private.h"
105 
106 /*
107  * Read proc's from memory file into buffer bp, which has space to hold
108  * at most maxcnt procs.
109  */
110 static int
111 kvm_proclist(kvm_t *kd, int op, int arg, struct process *pr,
112     char *bp, int maxcnt, size_t esize)
113 {
114 	struct kinfo_proc kp;
115 	struct session sess;
116 	struct ucred ucred;
117 	struct proc proc, *p;
118 	struct process process, process2;
119 	struct pgrp pgrp;
120 	struct tty tty;
121 	struct timeval elapsed, monostart, monostop, realstart, realstop;
122 	struct nlist nl[3];
123 	struct sigacts sa, *sap;
124 	struct vmspace vm, *vmp;
125 	struct plimit limits, *limp;
126 	pid_t parent_pid, leader_pid;
127 	int cnt = 0;
128 	int dothreads = 0;
129 	int i;
130 
131 	dothreads = op & KERN_PROC_SHOW_THREADS;
132 	op &= ~KERN_PROC_SHOW_THREADS;
133 
134 	/* Anchor a time to compare process starting times from. */
135 	nl[0].n_name = "_time_second";
136 	nl[1].n_name = "_time_uptime";
137 	nl[2].n_name = NULL;
138 	if (kvm_nlist(kd, nl) != 0) {
139 		for (i = 0; nl[i].n_type != 0; ++i)
140 			continue;
141 		_kvm_err(kd, kd->program, "%s: no such symbol", nl[i].n_name);
142 		return (-1);
143 	}
144 	timerclear(&realstop);
145 	timerclear(&monostop);
146 	if (KREAD(kd, nl[0].n_value, &realstop.tv_sec)) {
147 		_kvm_err(kd, kd->program, "cannot read time_second");
148 		return (-1);
149 	}
150 	if (KREAD(kd, nl[1].n_value, &monostop.tv_sec)) {
151 		_kvm_err(kd, kd->program, "cannot read time_uptime");
152 		return (-1);
153 	}
154 
155 	/*
156 	 * Modelled on sysctl_doproc() in sys/kern/kern_sysctl.c
157 	 */
158 	for (; cnt < maxcnt && pr != NULL; pr = LIST_NEXT(&process, ps_list)) {
159 		if (KREAD(kd, (u_long)pr, &process)) {
160 			_kvm_err(kd, kd->program, "can't read process at %lx",
161 			    (u_long)pr);
162 			return (-1);
163 		}
164 		if (process.ps_pgrp == NULL)
165 			continue;
166 		if (process.ps_flags & PS_EMBRYO)
167 			continue;
168 		if (KREAD(kd, (u_long)process.ps_ucred, &ucred)) {
169 			_kvm_err(kd, kd->program, "can't read ucred at %lx",
170 			    (u_long)process.ps_ucred);
171 			return (-1);
172 		}
173 		if (KREAD(kd, (u_long)process.ps_pgrp, &pgrp)) {
174 			_kvm_err(kd, kd->program, "can't read pgrp at %lx",
175 			    (u_long)process.ps_pgrp);
176 			return (-1);
177 		}
178 		if (KREAD(kd, (u_long)pgrp.pg_session, &sess)) {
179 			_kvm_err(kd, kd->program, "can't read session at %lx",
180 			    (u_long)pgrp.pg_session);
181 			return (-1);
182 		}
183 		if ((process.ps_flags & PS_CONTROLT) && sess.s_ttyp != NULL &&
184 		    KREAD(kd, (u_long)sess.s_ttyp, &tty)) {
185 			_kvm_err(kd, kd->program, "can't read tty at %lx",
186 			    (u_long)sess.s_ttyp);
187 			return (-1);
188 		}
189 		if (process.ps_pptr) {
190 			if (KREAD(kd, (u_long)process.ps_pptr, &process2)) {
191 				_kvm_err(kd, kd->program,
192 				    "can't read process at %lx",
193 				    (u_long)process.ps_pptr);
194 				return (-1);
195 			}
196 			parent_pid = process2.ps_pid;
197 		}
198 		else
199 			parent_pid = 0;
200 		if (sess.s_leader) {
201 			if (KREAD(kd, (u_long)sess.s_leader, &process2)) {
202 				_kvm_err(kd, kd->program,
203 				    "can't read proc at %lx",
204 				    (u_long)sess.s_leader);
205 				return (-1);
206 			}
207 			leader_pid = process2.ps_pid;
208 		}
209 		else
210 			leader_pid = 0;
211 		if (process.ps_sigacts) {
212 			if (KREAD(kd, (u_long)process.ps_sigacts, &sa)) {
213 				_kvm_err(kd, kd->program,
214 				    "can't read sigacts at %lx",
215 				    (u_long)process.ps_sigacts);
216 				return (-1);
217 			}
218 			sap = &sa;
219 		}
220 		else
221 			sap = NULL;
222 
223 		switch (op) {
224 		case KERN_PROC_PID:
225 			if (process.ps_pid != (pid_t)arg)
226 				continue;
227 			break;
228 
229 		case KERN_PROC_PGRP:
230 			if (pgrp.pg_id != (pid_t)arg)
231 				continue;
232 			break;
233 
234 		case KERN_PROC_SESSION:
235 			if (sess.s_leader == NULL ||
236 			    leader_pid != (pid_t)arg)
237 				continue;
238 			break;
239 
240 		case KERN_PROC_TTY:
241 			if ((process.ps_flags & PS_CONTROLT) == 0 ||
242 			    sess.s_ttyp == NULL ||
243 			    tty.t_dev != (dev_t)arg)
244 				continue;
245 			break;
246 
247 		case KERN_PROC_UID:
248 			if (ucred.cr_uid != (uid_t)arg)
249 				continue;
250 			break;
251 
252 		case KERN_PROC_RUID:
253 			if (ucred.cr_ruid != (uid_t)arg)
254 				continue;
255 			break;
256 
257 		case KERN_PROC_ALL:
258 			if (process.ps_flags & PS_SYSTEM)
259 				continue;
260 			break;
261 
262 		case KERN_PROC_KTHREAD:
263 			/* no filtering */
264 			break;
265 
266 		default:
267 			_kvm_err(kd, kd->program, "invalid filter");
268 			return (-1);
269 		}
270 
271 		/*
272 		 * We're going to add another proc to the set.  If this
273 		 * will overflow the buffer, assume the reason is because
274 		 * nthreads (or the proc list) is corrupt and declare an error.
275 		 */
276 		if (cnt >= maxcnt) {
277 			_kvm_err(kd, kd->program, "nthreads corrupt");
278 			return (-1);
279 		}
280 
281 		/* set up stuff that might not always be there */
282 		limp = &limits;
283 		if (!process.ps_limit ||
284 		    KREAD(kd, (u_long)process.ps_limit, &limits))
285 			limp = NULL;
286 
287 		vmp = NULL;
288 
289 		if ((process.ps_flags & PS_ZOMBIE) == 0 &&
290 		    !KREAD(kd, (u_long)process.ps_vmspace, &vm))
291 			vmp = &vm;
292 
293 #define do_copy_str(_d, _s, _l)	kvm_read(kd, (u_long)(_s), (_d), (_l)-1)
294 		FILL_KPROC(&kp, do_copy_str, &proc, &process,
295 		    &ucred, &pgrp, process.ps_mainproc, pr, &sess,
296 		    vmp, limp, sap, 0, 1);
297 
298 		/* stuff that's too painful to generalize */
299 		kp.p_ppid = parent_pid;
300 		kp.p_sid = leader_pid;
301 		if ((process.ps_flags & PS_CONTROLT) && sess.s_ttyp != NULL) {
302 			kp.p_tdev = tty.t_dev;
303 			if (tty.t_pgrp != NULL &&
304 			    tty.t_pgrp != process.ps_pgrp &&
305 			    KREAD(kd, (u_long)tty.t_pgrp, &pgrp)) {
306 				_kvm_err(kd, kd->program,
307 				    "can't read tpgrp at %lx",
308 				    (u_long)tty.t_pgrp);
309 				return (-1);
310 			}
311 			kp.p_tpgid = tty.t_pgrp ? pgrp.pg_id : -1;
312 			kp.p_tsess = PTRTOINT64(tty.t_session);
313 		} else {
314 			kp.p_tpgid = -1;
315 			kp.p_tdev = NODEV;
316 		}
317 
318 		/* Convert the starting uptime to a starting UTC time. */
319 		if ((process.ps_flags & PS_ZOMBIE) == 0) {
320 			monostart.tv_sec = kp.p_ustart_sec;
321 			monostart.tv_usec = kp.p_ustart_usec;
322 			timersub(&monostop, &monostart, &elapsed);
323 			if (elapsed.tv_sec < 0)
324 				timerclear(&elapsed);
325 			timersub(&realstop, &elapsed, &realstart);
326 			kp.p_ustart_sec = realstart.tv_sec;
327 			kp.p_ustart_usec = realstart.tv_usec;
328 		}
329 
330 		/* update %cpu for all threads */
331 		if (dothreads) {
332 			if (KREAD(kd, (u_long)process.ps_mainproc, &proc)) {
333 				_kvm_err(kd, kd->program,
334 				    "can't read proc at %lx",
335 				    (u_long)process.ps_mainproc);
336 				return (-1);
337 			}
338 			kp.p_pctcpu = proc.p_pctcpu;
339 			kp.p_stat   = proc.p_stat;
340 		} else {
341 			kp.p_pctcpu = 0;
342 			kp.p_stat = (process.ps_flags & PS_ZOMBIE) ? SDEAD :
343 			    SIDL;
344 			for (p = SMR_TAILQ_FIRST_LOCKED(&process.ps_threads);
345 			    p != NULL;
346 			    p = SMR_TAILQ_NEXT_LOCKED(&proc, p_thr_link)) {
347 				if (KREAD(kd, (u_long)p, &proc)) {
348 					_kvm_err(kd, kd->program,
349 					    "can't read proc at %lx",
350 					    (u_long)p);
351 					return (-1);
352 				}
353 				kp.p_pctcpu += proc.p_pctcpu;
354 				/*
355 				 * find best state:
356 				 * ONPROC > RUN > STOP > SLEEP > ...
357 				 */
358 				if (proc.p_stat == SONPROC ||
359 				    kp.p_stat == SONPROC)
360 					kp.p_stat = SONPROC;
361 				else if (proc.p_stat == SRUN ||
362 				    kp.p_stat == SRUN)
363 					kp.p_stat = SRUN;
364 				else if (proc.p_stat == SSTOP ||
365 				    kp.p_stat == SSTOP)
366 					kp.p_stat = SSTOP;
367 				else if (proc.p_stat == SSLEEP)
368 					kp.p_stat = SSLEEP;
369 			}
370                 }
371 
372 		memcpy(bp, &kp, esize);
373 		bp += esize;
374 		++cnt;
375 
376 		/* Skip per-thread entries if not required by op */
377 		if (!dothreads)
378 			continue;
379 
380 		for (p = SMR_TAILQ_FIRST_LOCKED(&process.ps_threads); p != NULL;
381 		    p = SMR_TAILQ_NEXT_LOCKED(&proc, p_thr_link)) {
382 			if (KREAD(kd, (u_long)p, &proc)) {
383 				_kvm_err(kd, kd->program,
384 				    "can't read proc at %lx",
385 				    (u_long)p);
386 				return (-1);
387 			}
388 			FILL_KPROC(&kp, do_copy_str, &proc, &process,
389 			    &ucred, &pgrp, p, pr, &sess, vmp, limp, sap,
390 			    1, 1);
391 
392 			/* see above */
393 			kp.p_ppid = parent_pid;
394 			kp.p_sid = leader_pid;
395 			if ((process.ps_flags & PS_CONTROLT) &&
396 			    sess.s_ttyp != NULL) {
397 				kp.p_tdev = tty.t_dev;
398 				if (tty.t_pgrp != NULL &&
399 				    tty.t_pgrp != process.ps_pgrp &&
400 				    KREAD(kd, (u_long)tty.t_pgrp, &pgrp)) {
401 					_kvm_err(kd, kd->program,
402 					    "can't read tpgrp at %lx",
403 					    (u_long)tty.t_pgrp);
404 					return (-1);
405 				}
406 				kp.p_tpgid = tty.t_pgrp ? pgrp.pg_id : -1;
407 				kp.p_tsess = PTRTOINT64(tty.t_session);
408 			} else {
409 				kp.p_tpgid = -1;
410 				kp.p_tdev = NODEV;
411 			}
412 		}
413 
414 		memcpy(bp, &kp, esize);
415 		bp += esize;
416 		++cnt;
417 #undef do_copy_str
418 	}
419 	return (cnt);
420 }
421 
422 struct kinfo_proc *
423 kvm_getprocs(kvm_t *kd, int op, int arg, size_t esize, int *cnt)
424 {
425 	int mib[6], st, nthreads;
426 	void *procbase;
427 	size_t size;
428 
429 	if ((ssize_t)esize < 0)
430 		return (NULL);
431 
432 	if (ISALIVE(kd)) {
433 		size = 0;
434 		mib[0] = CTL_KERN;
435 		mib[1] = KERN_PROC;
436 		mib[2] = op;
437 		mib[3] = arg;
438 		mib[4] = esize;
439 
440 		do {
441 			mib[5] = 0;
442 			st = sysctl(mib, 6, NULL, &size, NULL, 0);
443 			if (st == -1) {
444 				_kvm_syserr(kd, kd->program, "kvm_getprocs");
445 				return (NULL);
446 			}
447 
448 			size += size / 8; /* add ~10% */
449 
450 			procbase = _kvm_realloc(kd, kd->procbase, size);
451 			if (procbase == NULL)
452 				return (NULL);
453 
454 			kd->procbase = procbase;
455 
456 			mib[5] = size / esize;
457 			st = sysctl(mib, 6, kd->procbase, &size, NULL, 0);
458 			if (st == -1 && errno != ENOMEM) {
459 				_kvm_syserr(kd, kd->program, "kvm_getprocs");
460 				return (NULL);
461 			}
462 		} while (st == -1);
463 
464 		nthreads = size / esize;
465 	} else {
466 		struct nlist nl[5];
467 		int i, maxthread, maxprocess;
468 		struct process *pr;
469 		char *bp;
470 
471 		if (esize > sizeof(struct kinfo_proc)) {
472 			_kvm_syserr(kd, kd->program,
473 			    "kvm_getprocs: unknown fields requested: libkvm out of date?");
474 			return (NULL);
475 		}
476 
477 		memset(nl, 0, sizeof(nl));
478 		nl[0].n_name = "_nthreads";
479 		nl[1].n_name = "_nprocesses";
480 		nl[2].n_name = "_allprocess";
481 		nl[3].n_name = "_zombprocess";
482 		nl[4].n_name = NULL;
483 
484 		if (kvm_nlist(kd, nl) != 0) {
485 			for (i = 0; nl[i].n_type != 0; ++i)
486 				;
487 			_kvm_err(kd, kd->program,
488 			    "%s: no such symbol", nl[i].n_name);
489 			return (NULL);
490 		}
491 		if (KREAD(kd, nl[0].n_value, &maxthread)) {
492 			_kvm_err(kd, kd->program, "can't read nthreads");
493 			return (NULL);
494 		}
495 		if (KREAD(kd, nl[1].n_value, &maxprocess)) {
496 			_kvm_err(kd, kd->program, "can't read nprocesses");
497 			return (NULL);
498 		}
499 		maxthread += maxprocess;
500 
501 		kd->procbase = _kvm_reallocarray(kd, NULL, maxthread, esize);
502 		if (kd->procbase == 0)
503 			return (NULL);
504 		bp = (char *)kd->procbase;
505 
506 		/* allprocess */
507 		if (KREAD(kd, nl[2].n_value, &pr)) {
508 			_kvm_err(kd, kd->program, "cannot read allprocess");
509 			return (NULL);
510 		}
511 		nthreads = kvm_proclist(kd, op, arg, pr, bp, maxthread, esize);
512 		if (nthreads < 0)
513 			return (NULL);
514 
515 		/* zombprocess */
516 		if (KREAD(kd, nl[3].n_value, &pr)) {
517 			_kvm_err(kd, kd->program, "cannot read zombprocess");
518 			return (NULL);
519 		}
520 		i = kvm_proclist(kd, op, arg, pr, bp + (esize * nthreads),
521 		    maxthread - nthreads, esize);
522 		if (i > 0)
523 			nthreads += i;
524 	}
525 	if (kd->procbase != NULL)
526 		*cnt = nthreads;
527 	return (kd->procbase);
528 }
529