xref: /openbsd-src/lib/libkvm/kvm_proc2.c (revision 8e0c768258d4632c51876b4397034bc3152bf8db)
1 /*	$OpenBSD: kvm_proc2.c,v 1.30 2019/10/22 21:19:22 cheloha 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 <stddef.h>
85 #include <stdlib.h>
86 #include <string.h>
87 #include <unistd.h>
88 #include <nlist.h>
89 #include <kvm.h>
90 
91 #include <uvm/uvm_extern.h>
92 #include <uvm/uvm_amap.h>
93 #include <machine/vmparam.h>
94 #include <machine/pmap.h>
95 
96 #include <sys/sysctl.h>
97 
98 #include <limits.h>
99 #include <errno.h>
100 #include <db.h>
101 #include <paths.h>
102 
103 #include "kvm_private.h"
104 
105 /*
106  * Read proc's from memory file into buffer bp, which has space to hold
107  * at most maxcnt procs.
108  */
109 static int
110 kvm_proclist(kvm_t *kd, int op, int arg, struct process *pr,
111     char *bp, int maxcnt, size_t esize)
112 {
113 	struct kinfo_proc kp;
114 	struct session sess;
115 	struct ucred ucred;
116 	struct proc proc, *p;
117 	struct process process, process2;
118 	struct pgrp pgrp;
119 	struct tty tty;
120 	struct timeval elapsed, monostart, monostop, realstart, realstop;
121 	struct nlist nl[3];
122 	struct sigacts sa, *sap;
123 	struct vmspace vm, *vmp;
124 	struct plimit limits, *limp;
125 	pid_t parent_pid, leader_pid;
126 	int cnt = 0;
127 	int dothreads = 0;
128 	int i;
129 
130 	dothreads = op & KERN_PROC_SHOW_THREADS;
131 	op &= ~KERN_PROC_SHOW_THREADS;
132 
133 	/* Anchor a time to compare process starting times from. */
134 	nl[0].n_name = "_time_second";
135 	nl[1].n_name = "_time_uptime";
136 	nl[2].n_name = NULL;
137 	if (kvm_nlist(kd, nl) != 0) {
138 		for (i = 0; nl[i].n_type != 0; ++i)
139 			continue;
140 		_kvm_err(kd, kd->program, "%s: no such symbol", nl[i].n_name);
141 		return (-1);
142 	}
143 	timerclear(&realstop);
144 	timerclear(&monostop);
145 	if (KREAD(kd, nl[0].n_value, &realstop.tv_sec)) {
146 		_kvm_err(kd, kd->program, "cannot read time_second");
147 		return (-1);
148 	}
149 	if (KREAD(kd, nl[1].n_value, &monostop.tv_sec)) {
150 		_kvm_err(kd, kd->program, "cannot read time_uptime");
151 		return (-1);
152 	}
153 
154 	/*
155 	 * Modelled on sysctl_doproc() in sys/kern/kern_sysctl.c
156 	 */
157 	for (; cnt < maxcnt && pr != NULL; pr = LIST_NEXT(&process, ps_list)) {
158 		if (KREAD(kd, (u_long)pr, &process)) {
159 			_kvm_err(kd, kd->program, "can't read process at %lx",
160 			    (u_long)pr);
161 			return (-1);
162 		}
163 		if (process.ps_pgrp == NULL)
164 			continue;
165 		if (process.ps_flags & PS_EMBRYO)
166 			continue;
167 		if (KREAD(kd, (u_long)process.ps_ucred, &ucred)) {
168 			_kvm_err(kd, kd->program, "can't read ucred at %lx",
169 			    (u_long)process.ps_ucred);
170 			return (-1);
171 		}
172 		if (KREAD(kd, (u_long)process.ps_pgrp, &pgrp)) {
173 			_kvm_err(kd, kd->program, "can't read pgrp at %lx",
174 			    (u_long)process.ps_pgrp);
175 			return (-1);
176 		}
177 		if (KREAD(kd, (u_long)pgrp.pg_session, &sess)) {
178 			_kvm_err(kd, kd->program, "can't read session at %lx",
179 			    (u_long)pgrp.pg_session);
180 			return (-1);
181 		}
182 		if ((process.ps_flags & PS_CONTROLT) && sess.s_ttyp != NULL &&
183 		    KREAD(kd, (u_long)sess.s_ttyp, &tty)) {
184 			_kvm_err(kd, kd->program, "can't read tty at %lx",
185 			    (u_long)sess.s_ttyp);
186 			return (-1);
187 		}
188 		if (process.ps_pptr) {
189 			if (KREAD(kd, (u_long)process.ps_pptr, &process2)) {
190 				_kvm_err(kd, kd->program,
191 				    "can't read process at %lx",
192 				    (u_long)process.ps_pptr);
193 				return (-1);
194 			}
195 			parent_pid = process2.ps_pid;
196 		}
197 		else
198 			parent_pid = 0;
199 		if (sess.s_leader) {
200 			if (KREAD(kd, (u_long)sess.s_leader, &process2)) {
201 				_kvm_err(kd, kd->program,
202 				    "can't read proc at %lx",
203 				    (u_long)sess.s_leader);
204 				return (-1);
205 			}
206 			leader_pid = process2.ps_pid;
207 		}
208 		else
209 			leader_pid = 0;
210 		if (process.ps_sigacts) {
211 			if (KREAD(kd, (u_long)process.ps_sigacts, &sa)) {
212 				_kvm_err(kd, kd->program,
213 				    "can't read sigacts at %lx",
214 				    (u_long)process.ps_sigacts);
215 				return (-1);
216 			}
217 			sap = &sa;
218 		}
219 		else
220 			sap = NULL;
221 
222 		switch (op) {
223 		case KERN_PROC_PID:
224 			if (process.ps_pid != (pid_t)arg)
225 				continue;
226 			break;
227 
228 		case KERN_PROC_PGRP:
229 			if (pgrp.pg_id != (pid_t)arg)
230 				continue;
231 			break;
232 
233 		case KERN_PROC_SESSION:
234 			if (sess.s_leader == NULL ||
235 			    leader_pid != (pid_t)arg)
236 				continue;
237 			break;
238 
239 		case KERN_PROC_TTY:
240 			if ((process.ps_flags & PS_CONTROLT) == 0 ||
241 			    sess.s_ttyp == NULL ||
242 			    tty.t_dev != (dev_t)arg)
243 				continue;
244 			break;
245 
246 		case KERN_PROC_UID:
247 			if (ucred.cr_uid != (uid_t)arg)
248 				continue;
249 			break;
250 
251 		case KERN_PROC_RUID:
252 			if (ucred.cr_ruid != (uid_t)arg)
253 				continue;
254 			break;
255 
256 		case KERN_PROC_ALL:
257 			if (process.ps_flags & PS_SYSTEM)
258 				continue;
259 			break;
260 
261 		case KERN_PROC_KTHREAD:
262 			/* no filtering */
263 			break;
264 
265 		default:
266 			_kvm_err(kd, kd->program, "invalid filter");
267 			return (-1);
268 		}
269 
270 		/*
271 		 * We're going to add another proc to the set.  If this
272 		 * will overflow the buffer, assume the reason is because
273 		 * nthreads (or the proc list) is corrupt and declare an error.
274 		 */
275 		if (cnt >= maxcnt) {
276 			_kvm_err(kd, kd->program, "nthreads corrupt");
277 			return (-1);
278 		}
279 
280 		/* set up stuff that might not always be there */
281 		limp = &limits;
282 		if (!process.ps_limit ||
283 		    KREAD(kd, (u_long)process.ps_limit, &limits))
284 			limp = NULL;
285 
286 		vmp = NULL;
287 
288 		if ((process.ps_flags & PS_ZOMBIE) == 0 &&
289 		    !KREAD(kd, (u_long)process.ps_vmspace, &vm))
290 			vmp = &vm;
291 
292 #define do_copy_str(_d, _s, _l)	kvm_read(kd, (u_long)(_s), (_d), (_l)-1)
293 		FILL_KPROC(&kp, do_copy_str, &proc, &process,
294 		    &ucred, &pgrp, process.ps_mainproc, pr, &sess,
295 		    vmp, limp, sap, 0, 1);
296 
297 		/* stuff that's too painful to generalize */
298 		kp.p_ppid = parent_pid;
299 		kp.p_sid = leader_pid;
300 		if ((process.ps_flags & PS_CONTROLT) && sess.s_ttyp != NULL) {
301 			kp.p_tdev = tty.t_dev;
302 			if (tty.t_pgrp != NULL &&
303 			    tty.t_pgrp != process.ps_pgrp &&
304 			    KREAD(kd, (u_long)tty.t_pgrp, &pgrp)) {
305 				_kvm_err(kd, kd->program,
306 				    "can't read tpgrp at %lx",
307 				    (u_long)tty.t_pgrp);
308 				return (-1);
309 			}
310 			kp.p_tpgid = tty.t_pgrp ? pgrp.pg_id : -1;
311 			kp.p_tsess = PTRTOINT64(tty.t_session);
312 		} else {
313 			kp.p_tpgid = -1;
314 			kp.p_tdev = NODEV;
315 		}
316 
317 		/* Convert the starting uptime to a starting UTC time. */
318 		if ((process.ps_flags & PS_ZOMBIE) == 0) {
319 			monostart.tv_sec = kp.p_ustart_sec;
320 			monostart.tv_usec = kp.p_ustart_usec;
321 			timersub(&monostop, &monostart, &elapsed);
322 			if (elapsed.tv_sec < 0)
323 				timerclear(&elapsed);
324 			timersub(&realstop, &elapsed, &realstart);
325 			kp.p_ustart_sec = realstart.tv_sec;
326 			kp.p_ustart_usec = realstart.tv_usec;
327 		}
328 
329 		/* update %cpu for all threads */
330 		if (dothreads) {
331 			if (KREAD(kd, (u_long)process.ps_mainproc, &proc)) {
332 				_kvm_err(kd, kd->program,
333 				    "can't read proc at %lx",
334 				    (u_long)process.ps_mainproc);
335 				return (-1);
336 			}
337 			kp.p_pctcpu = proc.p_pctcpu;
338 			kp.p_stat   = proc.p_stat;
339 		} else {
340 			kp.p_pctcpu = 0;
341 			kp.p_stat = (process.ps_flags & PS_ZOMBIE) ? SDEAD :
342 			    SIDL;
343 			for (p = TAILQ_FIRST(&process.ps_threads); p != NULL;
344 			    p = TAILQ_NEXT(&proc, p_thr_link)) {
345 				if (KREAD(kd, (u_long)p, &proc)) {
346 					_kvm_err(kd, kd->program,
347 					    "can't read proc at %lx",
348 					    (u_long)p);
349 					return (-1);
350 				}
351 				kp.p_pctcpu += proc.p_pctcpu;
352 				/*
353 				 * find best state:
354 				 * ONPROC > RUN > STOP > SLEEP > ...
355 				 */
356 				if (proc.p_stat == SONPROC ||
357 				    kp.p_stat == SONPROC)
358 					kp.p_stat = SONPROC;
359 				else if (proc.p_stat == SRUN ||
360 				    kp.p_stat == SRUN)
361 					kp.p_stat = SRUN;
362 				else if (proc.p_stat == SSTOP ||
363 				    kp.p_stat == SSTOP)
364 					kp.p_stat = SSTOP;
365 				else if (proc.p_stat == SSLEEP)
366 					kp.p_stat = SSLEEP;
367 			}
368                 }
369 
370 		memcpy(bp, &kp, esize);
371 		bp += esize;
372 		++cnt;
373 
374 		/* Skip per-thread entries if not required by op */
375 		if (!dothreads)
376 			continue;
377 
378 		for (p = TAILQ_FIRST(&process.ps_threads); p != NULL;
379 		    p = TAILQ_NEXT(&proc, p_thr_link)) {
380 			if (KREAD(kd, (u_long)p, &proc)) {
381 				_kvm_err(kd, kd->program,
382 				    "can't read proc at %lx",
383 				    (u_long)p);
384 				return (-1);
385 			}
386 			FILL_KPROC(&kp, do_copy_str, &proc, &process,
387 			    &ucred, &pgrp, p, pr, &sess, vmp, limp, sap,
388 			    1, 1);
389 
390 			/* see above */
391 			kp.p_ppid = parent_pid;
392 			kp.p_sid = leader_pid;
393 			if ((process.ps_flags & PS_CONTROLT) &&
394 			    sess.s_ttyp != NULL) {
395 				kp.p_tdev = tty.t_dev;
396 				if (tty.t_pgrp != NULL &&
397 				    tty.t_pgrp != process.ps_pgrp &&
398 				    KREAD(kd, (u_long)tty.t_pgrp, &pgrp)) {
399 					_kvm_err(kd, kd->program,
400 					    "can't read tpgrp at %lx",
401 					    (u_long)tty.t_pgrp);
402 					return (-1);
403 				}
404 				kp.p_tpgid = tty.t_pgrp ? pgrp.pg_id : -1;
405 				kp.p_tsess = PTRTOINT64(tty.t_session);
406 			} else {
407 				kp.p_tpgid = -1;
408 				kp.p_tdev = NODEV;
409 			}
410 		}
411 
412 		memcpy(bp, &kp, esize);
413 		bp += esize;
414 		++cnt;
415 #undef do_copy_str
416 	}
417 	return (cnt);
418 }
419 
420 struct kinfo_proc *
421 kvm_getprocs(kvm_t *kd, int op, int arg, size_t esize, int *cnt)
422 {
423 	int mib[6], st, nthreads;
424 	void *procbase;
425 	size_t size;
426 
427 	if ((ssize_t)esize < 0)
428 		return (NULL);
429 
430 	if (ISALIVE(kd)) {
431 		size = 0;
432 		mib[0] = CTL_KERN;
433 		mib[1] = KERN_PROC;
434 		mib[2] = op;
435 		mib[3] = arg;
436 		mib[4] = esize;
437 
438 		do {
439 			mib[5] = 0;
440 			st = sysctl(mib, 6, NULL, &size, NULL, 0);
441 			if (st == -1) {
442 				_kvm_syserr(kd, kd->program, "kvm_getprocs");
443 				return (NULL);
444 			}
445 
446 			size += size / 8; /* add ~10% */
447 
448 			procbase = _kvm_realloc(kd, kd->procbase, size);
449 			if (procbase == NULL)
450 				return (NULL);
451 
452 			kd->procbase = procbase;
453 
454 			mib[5] = size / esize;
455 			st = sysctl(mib, 6, kd->procbase, &size, NULL, 0);
456 			if (st == -1 && errno != ENOMEM) {
457 				_kvm_syserr(kd, kd->program, "kvm_getprocs");
458 				return (NULL);
459 			}
460 		} while (st == -1);
461 
462 		nthreads = size / esize;
463 	} else {
464 		struct nlist nl[5];
465 		int i, maxthread, maxprocess;
466 		struct process *pr;
467 		char *bp;
468 
469 		if (esize > sizeof(struct kinfo_proc)) {
470 			_kvm_syserr(kd, kd->program,
471 			    "kvm_getprocs: unknown fields requested: libkvm out of date?");
472 			return (NULL);
473 		}
474 
475 		memset(nl, 0, sizeof(nl));
476 		nl[0].n_name = "_nthreads";
477 		nl[1].n_name = "_nprocesses";
478 		nl[2].n_name = "_allprocess";
479 		nl[3].n_name = "_zombprocess";
480 		nl[4].n_name = NULL;
481 
482 		if (kvm_nlist(kd, nl) != 0) {
483 			for (i = 0; nl[i].n_type != 0; ++i)
484 				;
485 			_kvm_err(kd, kd->program,
486 			    "%s: no such symbol", nl[i].n_name);
487 			return (NULL);
488 		}
489 		if (KREAD(kd, nl[0].n_value, &maxthread)) {
490 			_kvm_err(kd, kd->program, "can't read nthreads");
491 			return (NULL);
492 		}
493 		if (KREAD(kd, nl[1].n_value, &maxprocess)) {
494 			_kvm_err(kd, kd->program, "can't read nprocesses");
495 			return (NULL);
496 		}
497 		maxthread += maxprocess;
498 
499 		kd->procbase = _kvm_reallocarray(kd, NULL, maxthread, esize);
500 		if (kd->procbase == 0)
501 			return (NULL);
502 		bp = (char *)kd->procbase;
503 
504 		/* allprocess */
505 		if (KREAD(kd, nl[2].n_value, &pr)) {
506 			_kvm_err(kd, kd->program, "cannot read allprocess");
507 			return (NULL);
508 		}
509 		nthreads = kvm_proclist(kd, op, arg, pr, bp, maxthread, esize);
510 		if (nthreads < 0)
511 			return (NULL);
512 
513 		/* zombprocess */
514 		if (KREAD(kd, nl[3].n_value, &pr)) {
515 			_kvm_err(kd, kd->program, "cannot read zombprocess");
516 			return (NULL);
517 		}
518 		i = kvm_proclist(kd, op, arg, pr, bp + (esize * nthreads),
519 		    maxthread - nthreads, esize);
520 		if (i > 0)
521 			nthreads += i;
522 	}
523 	if (kd->procbase != NULL)
524 		*cnt = nthreads;
525 	return (kd->procbase);
526 }
527