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