1/* 2 * dproc.c - Darwin process access functions for /dev/kmem-based lsof 3 */ 4 5 6/* 7 * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana 8 * 47907. All rights reserved. 9 * 10 * Written by Victor A. Abell 11 * 12 * This software is not subject to any license of the American Telephone 13 * and Telegraph Company or the Regents of the University of California. 14 * 15 * Permission is granted to anyone to use this software for any purpose on 16 * any computer system, and to alter it and redistribute it freely, subject 17 * to the following restrictions: 18 * 19 * 1. Neither the authors nor Purdue University are responsible for any 20 * consequences of the use of this software. 21 * 22 * 2. The origin of this software must not be misrepresented, either by 23 * explicit claim or by omission. Credit to the authors and Purdue 24 * University must appear in documentation and sources. 25 * 26 * 3. Altered versions must be plainly marked as such, and must not be 27 * misrepresented as being the original software. 28 * 29 * 4. This notice may not be removed or altered. 30 */ 31 32#ifndef lint 33static char copyright[] = 34"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; 35static char *rcsid = "$Id: dproc.c,v 1.8 2005/11/01 20:24:51 abe Exp $"; 36#endif 37 38#include "lsof.h" 39 40#include <mach/mach_traps.h> 41#include <mach/mach_init.h> 42#include <mach/message.h> 43#include <mach/vm_map.h> 44 45 46/* 47 * Local definitions 48 */ 49 50#define NPHASH 1024 /* Phash bucket count -- 51 * MUST BE A POWER OF 2!!! */ 52#define PHASH(a) (((int)((a * 31415) >> 3)) & (NPHASH - 1)) 53#define PINCRSZ 256 /* Proc[] size inrement */ 54 55 56/* 57 * Local structures 58 */ 59 60struct phash { 61 KA_T ka; /* kernel proc struct address */ 62 struct proc *la; /* local proc struct address */ 63 struct phash *next; /* next phash entry */ 64}; 65 66 67/* 68 * Local function prototypes 69 */ 70 71_PROTOTYPE(static pid_t get_parent_pid,(KA_T kpa)); 72_PROTOTYPE(static int read_procs,()); 73_PROTOTYPE(static void process_map,(pid_t pid)); 74_PROTOTYPE(static void enter_vn_text,(KA_T va, int *n)); 75 76#if DARWINV>=700 77_PROTOTYPE(static char *getcmdnm,(pid_t pid)); 78#endif /* DARWINV>=700 */ 79 80_PROTOTYPE(static void get_kernel_access,(void)); 81 82 83/* 84 * Local static values 85 */ 86 87static KA_T Akp = (KA_T)NULL; /* kernel allproc chain address */ 88static int Np = 0; /* PA[] and Proc[] entry count */ 89static int Npa = 0; /* Proc[] structure allocation count */ 90static MALLOC_S Nv = 0; /* allocated Vp[] entries */ 91static KA_T *Pa = (KA_T *)NULL; /* Proc[] addresses */ 92struct phash **Phash = (struct phash **)NULL; 93 /* kernel proc address hash pointers */ 94static struct proc *Proc = (struct proc *)NULL; 95 /* local copy of prc struct chain */ 96static KA_T *Vp = NULL; /* vnode address cache */ 97 98 99/* 100 * enter_vn_text() - enter a vnode text reference 101 */ 102 103static void 104enter_vn_text(va, n) 105 KA_T va; /* vnode address */ 106 int *n; /* Vp[] entries in use */ 107{ 108 int i; 109/* 110 * Ignore the request if the vnode has already been entered. 111 */ 112 for (i = 0; i < *n; i++) { 113 if (va == Vp[i]) 114 return; 115 } 116/* 117 * Save the text file information. 118 */ 119 alloc_lfile(" txt", -1); 120 Cfp = (struct file *)NULL; 121 process_node(va); 122 if (Lf->sf) 123 link_lfile(); 124 if (i >= Nv) { 125 126 /* 127 * Allocate space for remembering the vnode. 128 */ 129 Nv += 10; 130 if (!Vp) 131 Vp=(KA_T *)malloc((MALLOC_S)(sizeof(struct vnode *)*10)); 132 else 133 Vp=(KA_T *)realloc((MALLOC_P *)Vp,(MALLOC_S)(Nv*sizeof(KA_T))); 134 if (!Vp) { 135 (void) fprintf(stderr, "%s: no txt ptr space, PID %d\n", 136 Pn, Lp->pid); 137 Exit(1); 138 } 139 } 140/* 141 * Remember the vnode. 142 */ 143 Vp[*n] = va; 144 (*n)++; 145} 146 147 148/* 149 * gather_proc_info() -- gather process information 150 */ 151 152void 153gather_proc_info() 154{ 155 char *cmd; 156 struct filedesc fd; 157 int i, nf; 158 MALLOC_S nb; 159 static struct file **ofb = NULL; 160 static int ofbb = 0; 161 struct proc *p; 162 int pgid; 163 int ppid = 0; 164 static char *pof = (char *)NULL; 165 static int pofb = 0; 166 short pss, sf; 167 int px; 168 uid_t uid; 169 170#if DARWINV<800 171 struct pcred pc; 172#else /* DARWINV>=800 */ 173 struct ucred uc; 174#endif /* DARWINV<800 */ 175 176/* 177 * Read the process table. 178 */ 179 if (read_procs()) { 180 (void) fprintf(stderr, "%s: can't read process table\n", Pn); 181 Exit(1); 182 } 183/* 184 * Examine proc structures and their associated information. 185 */ 186 for (p = Proc, px = 0; px < Np; p++, px++) 187 { 188 189#if DARWINV<800 190 if (!p->p_cred || kread((KA_T)p->p_cred, (char *)&pc, sizeof(pc))) 191 continue; 192 pgid = pc.p_rgid; 193 uid = pc.p_ruid; 194#else /* DARWINV>=800 */ 195 if (!p->p_ucred || kread((KA_T)p->p_ucred, (char *)&uc, sizeof(uc))) 196 continue; 197 pgid = uc.cr_rgid; 198 uid = uc.cr_uid; 199#endif /* DARWINV<800 */ 200 201#if defined(HASPPID) 202 ppid = get_parent_pid((KA_T)p->p_pptr); 203#endif /* defined(HASPPID) */ 204 205 /* 206 * Get the command name. 207 */ 208 209#if DARWINV<700 210 cmd = p->P_COMM; 211#else /* DARWINV>=700 */ 212 if (!strcmp(p->p_comm, "LaunchCFMApp")) { 213 if (!(cmd = getcmdnm(p->p_pid))) 214 cmd = p->p_comm; 215 } else 216 cmd = p->p_comm; 217#endif /* DARWINV<700 */ 218 219 /* 220 * See if process is excluded. 221 * 222 * Read file structure pointers. 223 */ 224 if (is_proc_excl(p->p_pid, pgid, (UID_ARG)uid, &pss, &sf)) 225 continue; 226 if (!p->p_fd || kread((KA_T)p->p_fd, (char *)&fd, sizeof(fd))) 227 continue; 228 if (!fd.fd_refcnt || fd.fd_lastfile > fd.fd_nfiles) 229 continue; 230 /* 231 * Allocate a local process structure. 232 * 233 * Set kernel's proc structure address. 234 */ 235 if (is_cmd_excl(cmd, &pss, &sf)) 236 continue; 237 alloc_lproc(p->p_pid, pgid, ppid, (UID_ARG)uid, cmd, (int)pss, 238 (int)sf); 239 Plf = (struct lfile *)NULL; 240 Kpa = Pa[px]; 241 /* 242 * Save current working directory information. 243 */ 244 if (fd.fd_cdir) { 245 alloc_lfile(CWD, -1); 246 Cfp = (struct file *)NULL; 247 process_node((KA_T)fd.fd_cdir); 248 if (Lf->sf) 249 link_lfile(); 250 } 251 /* 252 * Save root directory information. 253 */ 254 if (fd.fd_rdir) { 255 alloc_lfile(RTD, -1); 256 Cfp = (struct file *)NULL; 257 process_node((KA_T)fd.fd_rdir); 258 if (Lf->sf) 259 link_lfile(); 260 } 261 /* 262 * Process the VM map. 263 */ 264 process_map(p->p_pid); 265 /* 266 * Read open file structure pointers. 267 */ 268 if (!fd.fd_ofiles || (nf = fd.fd_nfiles) <= 0) 269 continue; 270 nb = (MALLOC_S)(sizeof(struct file *) * nf); 271 if (nb > ofbb) { 272 if (!ofb) 273 ofb = (struct file **)malloc(nb); 274 else 275 ofb = (struct file **)realloc((MALLOC_P *)ofb, nb); 276 if (!ofb) { 277 (void) fprintf(stderr, "%s: PID %d, no file * space\n", 278 Pn, p->p_pid); 279 Exit(1); 280 } 281 ofbb = nb; 282 } 283 if (kread((KA_T)fd.fd_ofiles, (char *)ofb, nb)) 284 continue; 285 286 nb = (MALLOC_S)(sizeof(char) * nf); 287 if (nb > pofb) { 288 if (!pof) 289 pof = (char *)malloc(nb); 290 else 291 pof = (char *)realloc((MALLOC_P *)pof, nb); 292 if (!pof) { 293 (void) fprintf(stderr, "%s: PID %d, no file flag space\n", 294 Pn, p->p_pid); 295 Exit(1); 296 } 297 pofb = nb; 298 } 299 if (!fd.fd_ofileflags || kread((KA_T)fd.fd_ofileflags, pof, nb)) 300 zeromem(pof, nb); 301 302 /* 303 * Save information on file descriptors. 304 */ 305 for (i = 0; i < nf; i++) { 306 if (ofb[i] && !(pof[i] & UF_RESERVED)) { 307 alloc_lfile(NULL, i); 308 process_file((KA_T)(Cfp = ofb[i])); 309 if (Lf->sf) { 310 311#if defined(HASFSTRUCT) 312 if (Fsv & FSV_FG) 313 Lf->pof = (long)pof[i]; 314#endif /* defined(HASFSTRUCT) */ 315 316 link_lfile(); 317 } 318 } 319 } 320 /* 321 * Examine results. 322 */ 323 if (examine_lproc()) 324 return; 325 } 326} 327 328 329#if DARWINV>=700 330static char * 331getcmdnm(pid) 332 pid_t pid; /* process ID */ 333{ 334 static int am; 335 static char *ap = (char *)NULL; 336 char *cp, *ep, *sp; 337 int mib[3]; 338 size_t sz; 339 340 if (!ap) { 341 342 /* 343 * Allocate space for the maximum argument size. 344 */ 345 mib[0] = CTL_KERN; 346 mib[1] = KERN_ARGMAX; 347 sz = sizeof(am); 348 if (sysctl(mib, 2, &am, &sz, NULL, 0) == -1) { 349 (void) fprintf(stderr, "%s: can't get arg max, PID %d\n", 350 Pn, pid); 351 Exit(1); 352 } 353 if (!(ap = (char *)malloc((MALLOC_S)am))) { 354 (void) fprintf(stderr, "%s: no arg ptr (%d) space, PID %d\n", 355 Pn, am, pid); 356 Exit(1); 357 } 358 } 359/* 360 * Get the arguments for the process. 361 */ 362 mib[0] = CTL_KERN; 363 mib[1] = KERN_PROCARGS; 364 mib[2] = pid; 365 sz = (size_t)am; 366 if (sysctl(mib, 3, ap, &sz, NULL, 0) == -1) 367 return((char *)NULL); 368/* 369 * Skip to the first NUL character, which should end the saved exec path. 370 */ 371 for (cp = ap; *cp && (cp < (ap + sz)); cp++) { 372 ; 373 } 374 if (cp >= (ap + sz)) 375 return((char *)NULL); 376/* 377 * Skip trailing NULs, which should find the beginning of the command. 378 */ 379 while (!*cp && (cp < (ap + sz))) { 380 cp++; 381 } 382 if (cp >= (ap + sz)) 383 return((char *)NULL); 384/* 385 * Make sure that the command is NUL-terminated. 386 */ 387 for (sp = cp; *cp && (cp < (ap + sz)); cp++) { 388 ; 389 } 390 if (cp >= (ap + sz)) 391 return((char *)NULL); 392 ep = cp; 393/* 394 * Locate the start of the command's base name and return it. 395 */ 396 for (ep = cp, cp--; cp >= sp; cp--) { 397 if (*cp == '/') { 398 return(cp + 1); 399 } 400 } 401 return(sp); 402} 403#endif /* DARWINV>=700 */ 404 405 406/* 407 * get_kernel_access() - get access to kernel memory 408 */ 409 410static void 411get_kernel_access() 412{ 413 414/* 415 * Check kernel version. 416 */ 417 (void) ckkv("Darwin", LSOF_VSTR, (char *)NULL, (char *)NULL); 418/* 419 * Set name list file path. 420 */ 421 if (!Nmlst) 422 Nmlst = N_UNIX; 423 424#if defined(WILLDROPGID) 425/* 426 * If kernel memory isn't coming from KMEM, drop setgid permission 427 * before attempting to open the (Memory) file. 428 */ 429 if (Memory) 430 (void) dropgid(); 431#else /* !defined(WILLDROPGID) */ 432/* 433 * See if the non-KMEM memory and the name list files are readable. 434 */ 435 if ((Memory && !is_readable(Memory, 1)) 436 || (Nmlst && !is_readable(Nmlst, 1))) 437 Exit(1); 438#endif /* defined(WILLDROPGID) */ 439 440/* 441 * Open kernel memory access. 442 */ 443 if ((Kd = open(Memory ? Memory : KMEM, O_RDONLY, 0)) < 0) 444 { 445 (void) fprintf(stderr, "%s: open(%s): %s\n", Pn, 446 Memory ? Memory : KMEM, 447 strerror(errno)); 448 Exit(1); 449 } 450 (void) build_Nl(Drive_Nl); 451 if (nlist(Nmlst, Nl) < 0) { 452 (void) fprintf(stderr, "%s: can't read namelist from %s\n", 453 Pn, Nmlst); 454 Exit(1); 455 } 456 457#if defined(WILLDROPGID) 458/* 459 * Drop setgid permission, if necessary. 460 */ 461 if (!Memory) 462 (void) dropgid(); 463#endif /* defined(WILLDROPGID) */ 464 465} 466 467 468/* 469 * get_parent_pid() - get parent process PID 470 */ 471 472static pid_t 473get_parent_pid(kpa) 474 KA_T kpa; /* kernel parent process address */ 475{ 476 struct phash *ph; 477 478 if (kpa) { 479 for (ph = Phash[PHASH(kpa)]; ph; ph = ph->next) { 480 if (ph->ka == kpa) 481 return((pid_t)ph->la->p_pid); 482 } 483 } 484 return((pid_t)0); 485} 486 487 488/* 489 * initialize() - perform all initialization 490 */ 491 492void 493initialize() 494{ 495 get_kernel_access(); 496} 497 498 499/* 500 * kread() - read from kernel memory 501 */ 502 503int 504kread(addr, buf, len) 505 KA_T addr; /* kernel memory address */ 506 char *buf; /* buffer to receive data */ 507 READLEN_T len; /* length to read */ 508{ 509 int br; 510 511 if ((off_t)addr & (off_t)0x3) { 512 513 /* 514 * No read is possible if the address is not aligned on a word 515 * boundary. 516 */ 517 return(1); 518 } 519 if (lseek(Kd, (off_t)addr, SEEK_SET) == (off_t)-1) 520 return(1); 521 br = read(Kd, buf, len); 522 return((br == len) ? 0 : 1); 523} 524 525 526/* 527 * prcess_map() - process VM map 528 */ 529 530static void 531process_map(pid) 532 pid_t pid; /* process id */ 533{ 534 vm_address_t address = 0; 535 mach_msg_type_number_t count; 536 vm_region_extended_info_data_t e_info; 537 int n = 0; 538 mach_port_t object_name; 539 vm_size_t size = 0; 540 vm_map_t task; 541 vm_region_top_info_data_t t_info; 542 543 struct vm_object { /* should come from <vm/vm_object.h> */ 544 545#if DARWINV<800 546 KA_T Dummy1[15]; 547#else /* DARWINV>=800 */ 548 KA_T Dummy1[14]; 549#endif /* DARWINV>=800 */ 550 551 memory_object_t pager; 552 } vmo; 553 554 struct vnode_pager { /* from <osfmk/vm/bsd_vm.c> */ 555 KA_T Dummy1[4]; 556 struct vnode *vnode; 557 } vp; 558 559/* 560 * Get the task port associated with the process 561 */ 562 if (task_for_pid((mach_port_name_t)mach_task_self(), pid, 563 (mach_port_name_t *)&task) 564 != KERN_SUCCESS) { 565 return; 566 } 567/* 568 * Go through the task's address space, looking for blocks of memory 569 * backed by an external pager (i.e, a "vnode") 570 */ 571 for (address = 0;; address += size) { 572 count = VM_REGION_EXTENDED_INFO_COUNT; 573 if (vm_region(task, &address, &size, VM_REGION_EXTENDED_INFO, 574 (vm_region_info_t)&e_info, &count, &object_name) 575 != KERN_SUCCESS) { 576 break; 577 } 578 if (!e_info.external_pager) 579 continue; 580 count = VM_REGION_TOP_INFO_COUNT; 581 if (vm_region(task, &address, &size, VM_REGION_TOP_INFO, 582 (vm_region_info_t)&t_info, &count, &object_name) 583 != KERN_SUCCESS) { 584 break; 585 } 586 /* 587 * The returned "obj_id" is the "vm_object_t" address. 588 */ 589 if (!t_info.obj_id) 590 continue; 591 if (kread(t_info.obj_id, (char *)&vmo, sizeof(vmo))) 592 break; 593 /* 594 * If the "pager" is backed by a vnode then the "vm_object_t" 595 * "memory_object_t" address is actually a "struct vnode_pager *". 596 */ 597 if (!vmo.pager) 598 continue; 599 if (kread((KA_T)vmo.pager, (char *)&vp, sizeof(vp))) 600 break; 601 (void) enter_vn_text((KA_T)vp.vnode, &n); 602 } 603 return; 604} 605 606 607/* 608 * read_procs() - read proc structures 609 */ 610 611static int 612read_procs() 613{ 614 int h, i, np, pe; 615 KA_T kp, kpn; 616 MALLOC_S msz; 617 struct proc *p; 618 struct phash *ph, *phn; 619 620 if (!Akp) { 621 622 /* 623 * Get kernel allproc structure pointer once. 624 */ 625 if (get_Nl_value("aproc", Drive_Nl, &Akp) < 0 || !Akp) { 626 (void) fprintf(stderr, "%s: can't get proc table address\n", 627 Pn); 628 Exit(1); 629 } 630 } 631/* 632 * Get the current number of processes and calculate PA and Proc[] allocation 633 * sizes large enough to handle it. 634 */ 635 if (get_Nl_value("nproc", Drive_Nl, &kp) < 0 || !kp) { 636 (void) fprintf(stderr, "%s: can't get nproc address\n", Pn); 637 Exit(1); 638 } 639 if (kread(kp, (char *)&np, sizeof(np))) { 640 (void) fprintf(stderr, "%s: can't read process count from %s\n", 641 Pn, print_kptr(kp, (char *)NULL, 0)); 642 Exit(1); 643 } 644 for (np += np, pe = PINCRSZ; pe < np; pe += PINCRSZ) 645 ; 646/* 647 * Allocate or reallocate the Pa[] and Proc[] tables. 648 */ 649 msz = (MALLOC_S)(pe * sizeof(struct proc)); 650 if (!Proc) 651 Proc = (struct proc *)malloc(msz); 652 else if (pe > Npa) 653 Proc = (struct proc *)realloc((MALLOC_P *)Proc, msz); 654 if (!Proc) { 655 (void) fprintf(stderr, "%s: no space for proc table\n", Pn); 656 Exit(1); 657 } 658 msz = (MALLOC_S)(pe * sizeof(KA_T)); 659 if (!Pa) 660 Pa = (KA_T *)malloc(msz); 661 else if (pe > Npa) 662 Pa = (KA_T *)realloc((MALLOC_P *)Pa, msz); 663 if (!Pa) { 664 (void) fprintf(stderr, "%s: no space for proc addr table\n", Pn); 665 Exit(1); 666 } 667 Npa = pe; 668/* 669 * Allocate or reset the Phash[] table. 670 */ 671 if (!Phash) { 672 Phash = (struct phash **)calloc(NPHASH, sizeof(struct phash *)); 673 } else { 674 for (h = 0; h < NPHASH; h++) { 675 for (ph = Phash[h]; ph; ph = phn) { 676 phn = ph->next; 677 (void) free((MALLOC_P *)ph); 678 } 679 Phash[h] = (struct phash *)NULL; 680 } 681 } 682 if (!Phash) { 683 (void) fprintf(stderr, "%s: no space for proc address hash\n", Pn); 684 Exit(1); 685 } 686/* 687 * Read the proc structures on the kernel's chain. 688 */ 689 for (i = Np = 0, kp = Akp, p = Proc, pe += pe; 690 kp && i < pe; 691 i++, kp = kpn) 692 { 693 if (kread(kp, (char *)p, sizeof(struct proc))) 694 break; 695 kpn = (KA_T)(((KA_T)p->p_list.le_next == Akp) ? NULL 696 : p->p_list.le_next); 697 if (p->p_stat == 0 || p->p_stat == SZOMB) 698 continue; 699 /* 700 * Cache the proc structure's addresses. 701 */ 702 h = PHASH(kp); 703 if (!(ph = (struct phash *)malloc((MALLOC_S)sizeof(struct phash)))) 704 { 705 (void) fprintf(stderr, "%s: no space for phash struct\n", Pn); 706 Exit(1); 707 } 708 ph->ka = kp; 709 ph->la = p; 710 ph->next = Phash[h]; 711 Phash[h] = ph; 712 p++; 713 Pa[Np++] = kp; 714 if (Np >= Npa) { 715 716 /* 717 * Enlarge Pa[] and Proc[]. 718 */ 719 msz = (int)((Npa + PINCRSZ) * sizeof(struct proc)); 720 if (!(Proc = (struct proc *)realloc((MALLOC_P *)Proc, msz))) { 721 (void) fprintf(stderr, "%s: no additional proc space\n", 722 Pn); 723 Exit(1); 724 } 725 msz = (int)((Npa + PINCRSZ) * sizeof(KA_T)); 726 if (!(Pa = (KA_T *)realloc((MALLOC_P *)Pa, msz))) { 727 (void) fprintf(stderr, 728 "%s: no additional proc addr space\n", Pn); 729 Exit(1); 730 } 731 Npa += PINCRSZ; 732 } 733 } 734/* 735 * If too many processes were read, the chain following probably failed; 736 * report that and exit. 737 */ 738 if (i >= pe) { 739 (void) fprintf(stderr, "%s: can't follow kernel proc chain\n", Pn); 740 Exit(1); 741 } 742/* 743 * If not in repeat mode, reduce Pa[] and Proc[] to their minimums. 744 */ 745 if (Np < Npa && !RptTm) { 746 msz = (MALLOC_S)(Np * sizeof(struct proc)); 747 if (!(Proc = (struct proc *)realloc((MALLOC_P *)Proc, msz))) { 748 (void) fprintf(stderr, "%s: can't reduce proc table\n", Pn); 749 Exit(1); 750 } 751 msz = (MALLOC_S)(Np * sizeof(KA_T)); 752 if (!(Pa = (KA_T *)realloc((MALLOC_P *)Pa, msz))) { 753 (void) fprintf(stderr, "%s: can't reduce proc addr table\n", 754 Pn); 755 Exit(1); 756 } 757 Npa = Np; 758 } 759/* 760 * Return 0 if any processes were loaded; 1 if none were. 761 */ 762 return((Np > 0) ? 0 : 1); 763} 764