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