xref: /openbsd-src/lib/libkvm/kvm_proc2.c (revision cd1eb269cafb12c415be1749cd4a4b5422710415)
1 /*	$OpenBSD: kvm_proc2.c,v 1.1 2010/01/10 03:37:50 guenther 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/user.h>
75 #include <sys/proc.h>
76 #include <sys/exec.h>
77 #include <sys/stat.h>
78 #include <sys/ioctl.h>
79 #include <sys/tty.h>
80 #include <stddef.h>
81 #include <stdlib.h>
82 #include <string.h>
83 #include <unistd.h>
84 #include <nlist.h>
85 #include <kvm.h>
86 
87 #include <uvm/uvm_extern.h>
88 #include <uvm/uvm_amap.h>
89 #include <machine/vmparam.h>
90 #include <machine/pmap.h>
91 
92 #include <sys/sysctl.h>
93 
94 #include <limits.h>
95 #include <db.h>
96 #include <paths.h>
97 
98 #include "kvm_private.h"
99 
100 /*
101  * Read proc's from memory file into buffer bp, which has space to hold
102  * at most maxcnt procs.
103  */
104 static int
105 kvm_proclist(kvm_t *kd, int op, int arg, struct proc *p,
106     char *bp, int maxcnt, size_t esize)
107 {
108 	struct kinfo_proc2 kp;
109 	struct session sess;
110 	struct pcred pcred;
111 	struct ucred ucred;
112 	struct proc proc, proc2;
113 	struct process process;
114 	struct pgrp pgrp;
115 	struct tty tty;
116 	struct vmspace vm, *vmp;
117 	struct plimit limits, *limp;
118 	struct pstats pstats, *ps;
119 	pid_t parent_pid, leader_pid;
120 	int cnt = 0;
121 
122 	for (; cnt < maxcnt && p != NULL; p = LIST_NEXT(&proc, p_list)) {
123 		if (KREAD(kd, (u_long)p, &proc)) {
124 			_kvm_err(kd, kd->program, "can't read proc at %x", p);
125 			return (-1);
126 		}
127 		if (KREAD(kd, (u_long)proc.p_p, &process)) {
128 			_kvm_err(kd, kd->program, "can't read process at %x",
129 			    proc.p_p);
130 			return (-1);
131 		}
132 		if (KREAD(kd, (u_long)process.ps_cred, &pcred)) {
133 			_kvm_err(kd, kd->program, "can't read pcred at %x",
134 			    process.ps_cred);
135 			return (-1);
136 		}
137 		if (KREAD(kd, (u_long)pcred.pc_ucred, &ucred)) {
138 			_kvm_err(kd, kd->program, "can't read ucred at %x",
139 			    pcred.pc_ucred);
140 			return (-1);
141 		}
142 		if (KREAD(kd, (u_long)proc.p_pgrp, &pgrp)) {
143 			_kvm_err(kd, kd->program, "can't read pgrp at %x",
144 			    proc.p_pgrp);
145 			return (-1);
146 		}
147 		if (KREAD(kd, (u_long)pgrp.pg_session, &sess)) {
148 			_kvm_err(kd, kd->program, "can't read session at %x",
149 			    pgrp.pg_session);
150 			return (-1);
151 		}
152 		if ((proc.p_flag & P_CONTROLT) && sess.s_ttyp != NULL &&
153 		    KREAD(kd, (u_long)sess.s_ttyp, &tty)) {
154 			_kvm_err(kd, kd->program,
155 			    "can't read tty at %x", sess.s_ttyp);
156 			return (-1);
157 		}
158 		if (proc.p_pptr) {
159 			if (KREAD(kd, (u_long)proc.p_pptr, &proc2)) {
160 				_kvm_err(kd, kd->program,
161 				    "can't read proc at %x", proc.p_pptr);
162 				return (-1);
163 			}
164 			parent_pid = proc2.p_pid;
165 		}
166 		else
167 			parent_pid = 0;
168 		if (sess.s_leader) {
169 			if (KREAD(kd, (u_long)sess.s_leader, &proc2)) {
170 				_kvm_err(kd, kd->program,
171 				    "can't read proc at %x", sess.s_leader);
172 				return (-1);
173 			}
174 			leader_pid = proc2.p_pid;
175 		}
176 		else
177 			leader_pid = 0;
178 
179 		switch (op) {
180 		case KERN_PROC_PID:
181 			if (proc.p_pid != (pid_t)arg)
182 				continue;
183 			break;
184 
185 		case KERN_PROC_PGRP:
186 			if (pgrp.pg_id != (pid_t)arg)
187 				continue;
188 			break;
189 
190 		case KERN_PROC_SESSION:
191 			if (sess.s_leader == NULL ||
192 			    leader_pid == (pid_t)arg)
193 				continue;
194 			break;
195 
196 		case KERN_PROC_TTY:
197 			if ((proc.p_flag & P_CONTROLT) == 0 ||
198 			    sess.s_ttyp == NULL ||
199 			    tty.t_dev != (dev_t)arg)
200 				continue;
201 			break;
202 
203 		case KERN_PROC_UID:
204 			if (ucred.cr_uid != (uid_t)arg)
205 				continue;
206 			break;
207 
208 		case KERN_PROC_RUID:
209 			if (pcred.p_ruid != (uid_t)arg)
210 				continue;
211 			break;
212 
213 		case KERN_PROC_ALL:
214 			if (proc.p_flag & P_SYSTEM)
215 				continue;
216 			break;
217 
218 		case KERN_PROC_KTHREAD:
219 			/* no filtering */
220 			break;
221 
222 		default:
223 			_kvm_err(kd, kd->program, "invalid filter");
224 			return (-1);
225 		}
226 
227 		/*
228 		 * We're going to add another proc to the set.  If this
229 		 * will overflow the buffer, assume the reason is because
230 		 * nprocs (or the proc list) is corrupt and declare an error.
231 		 */
232 		if (cnt >= maxcnt) {
233 			_kvm_err(kd, kd->program, "nprocs corrupt");
234 			return (-1);
235 		}
236 
237 		/* set up stuff that might not always be there */
238 		vmp = &vm;
239 		if (proc.p_stat == SIDL ||
240 		    P_ZOMBIE(&proc) ||
241 		    KREAD(kd, (u_long)proc.p_vmspace, &vm))
242 			vmp = NULL;
243 
244 		limp = &limits;
245 		if (!process.ps_limit ||
246 		    KREAD(kd, (u_long)process.ps_limit, &limits))
247 			limp = NULL;
248 
249 		ps = &pstats;
250 		if (P_ZOMBIE(&proc) ||
251 		    KREAD(kd, (u_long)proc.p_stats, &pstats))
252 			ps = NULL;
253 
254 #define do_copy_str(_d, _s, _l)	kvm_read(kd, (u_long)(_s), (_d), (_l)-1)
255 		FILL_KPROC2(&kp, do_copy_str, &proc, &process, &pcred, &ucred,
256 		    &pgrp, p, &sess, vmp, limp, ps);
257 #undef do_copy_str
258 
259 		/* stuff that's too painful to generalize into the macros */
260 		kp.p_ppid = parent_pid;
261 		kp.p_sid = leader_pid;
262 		if ((proc.p_flag & P_CONTROLT) && sess.s_ttyp != NULL) {
263 			kp.p_tdev = tty.t_dev;
264 			if (tty.t_pgrp != NULL &&
265 			    tty.t_pgrp != proc.p_pgrp &&
266 			    KREAD(kd, (u_long)tty.t_pgrp, &pgrp)) {
267 				_kvm_err(kd, kd->program,
268 				    "can't read tpgrp at &x", tty.t_pgrp);
269 				return (-1);
270 			}
271 			kp.p_tpgid = tty.t_pgrp ? pgrp.pg_id : -1;
272 			kp.p_tsess = PTRTOINT64(tty.t_session);
273 		} else {
274 			kp.p_tpgid = -1;
275 			kp.p_tdev = NODEV;
276 		}
277 
278 		memcpy(bp, &kp, esize);
279 		bp += esize;
280 		++cnt;
281 	}
282 	return (cnt);
283 }
284 
285 struct kinfo_proc2 *
286 kvm_getproc2(kvm_t *kd, int op, int arg, size_t esize, int *cnt)
287 {
288 	int mib[6], st, nprocs;
289 	size_t size;
290 
291 	if ((ssize_t)esize < 0)
292 		return (NULL);
293 
294 	if (kd->procbase2 != NULL) {
295 		free(kd->procbase2);
296 		/*
297 		 * Clear this pointer in case this call fails.  Otherwise,
298 		 * kvm_close() will free it again.
299 		 */
300 		kd->procbase2 = 0;
301 	}
302 
303 	if (ISALIVE(kd)) {
304 		size = 0;
305 		mib[0] = CTL_KERN;
306 		mib[1] = KERN_PROC2;
307 		mib[2] = op;
308 		mib[3] = arg;
309 		mib[4] = esize;
310 		mib[5] = 0;
311 		st = sysctl(mib, 6, NULL, &size, NULL, 0);
312 		if (st == -1) {
313 			_kvm_syserr(kd, kd->program, "kvm_getproc2");
314 			return (NULL);
315 		}
316 
317 		mib[5] = size / esize;
318 		kd->procbase2 = _kvm_malloc(kd, size);
319 		if (kd->procbase2 == 0)
320 			return (NULL);
321 		st = sysctl(mib, 6, kd->procbase2, &size, NULL, 0);
322 		if (st == -1) {
323 			_kvm_syserr(kd, kd->program, "kvm_getproc2");
324 			return (NULL);
325 		}
326 		nprocs = size / esize;
327 	} else {
328 		struct nlist nl[4];
329 		int i, maxprocs;
330 		struct proc *p;
331 		char *bp;
332 
333 		memset(nl, 0, sizeof(nl));
334 		nl[0].n_name = "_nprocs";
335 		nl[1].n_name = "_allproc";
336 		nl[2].n_name = "_zombproc";
337 		nl[3].n_name = NULL;
338 
339 		if (kvm_nlist(kd, nl) != 0) {
340 			for (i = 0; nl[i].n_type != 0; ++i)
341 				;
342 			_kvm_err(kd, kd->program,
343 			    "%s: no such symbol", nl[i].n_name);
344 			return (NULL);
345 		}
346 		if (KREAD(kd, nl[0].n_value, &maxprocs)) {
347 			_kvm_err(kd, kd->program, "can't read nprocs");
348 			return (NULL);
349 		}
350 
351 		kd->procbase2 = _kvm_malloc(kd, maxprocs * esize);
352 		if (kd->procbase2 == 0)
353 			return (NULL);
354 		bp = (char *)kd->procbase2;
355 
356 		/* allproc */
357 		if (KREAD(kd, nl[1].n_value, &p)) {
358 			_kvm_err(kd, kd->program, "cannot read allproc");
359 			return (NULL);
360 		}
361 		nprocs = kvm_proclist(kd, op, arg, p, bp, maxprocs, esize);
362 		if (nprocs < 0)
363 			return (NULL);
364 
365 		/* zombproc */
366 		if (KREAD(kd, nl[2].n_value, &p)) {
367 			_kvm_err(kd, kd->program, "cannot read zombproc");
368 			return (NULL);
369 		}
370 		i = kvm_proclist(kd, op, arg, p, bp + (esize * nprocs),
371 		    maxprocs - nprocs, esize);
372 		if (i > 0)
373 			nprocs += i;
374 	}
375 	*cnt = nprocs;
376 	return (kd->procbase2);
377 }
378 
379