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