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