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