1 /* $NetBSD: kern_sysctl.c,v 1.74 2000/07/13 14:26:43 simonb Exp $ */ 2 3 /*- 4 * Copyright (c) 1982, 1986, 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Mike Karels at Berkeley Software Design, Inc. 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 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)kern_sysctl.c 8.9 (Berkeley) 5/20/95 39 */ 40 41 /* 42 * sysctl system call. 43 */ 44 45 #include "opt_ddb.h" 46 #include "opt_insecure.h" 47 #include "opt_defcorename.h" 48 #include "opt_sysv.h" 49 50 #include <sys/param.h> 51 #include <sys/systm.h> 52 #include <sys/kernel.h> 53 #include <sys/buf.h> 54 #include <sys/device.h> 55 #include <sys/disklabel.h> 56 #include <sys/dkstat.h> 57 #include <sys/exec.h> 58 #include <sys/file.h> 59 #include <sys/ioctl.h> 60 #include <sys/malloc.h> 61 #include <sys/mount.h> 62 #include <sys/msgbuf.h> 63 #include <sys/pool.h> 64 #include <sys/proc.h> 65 #include <sys/resource.h> 66 #include <sys/resourcevar.h> 67 #include <sys/syscallargs.h> 68 #include <sys/tty.h> 69 #include <sys/unistd.h> 70 #include <sys/vnode.h> 71 #include <sys/sysctl.h> 72 73 #if defined(SYSVMSG) || defined(SYSVSEM) || defined(SYSVSHM) 74 #include <sys/ipc.h> 75 #endif 76 #ifdef SYSVMSG 77 #include <sys/msg.h> 78 #endif 79 #ifdef SYSVSEM 80 #include <sys/sem.h> 81 #endif 82 #ifdef SYSVSHM 83 #include <sys/shm.h> 84 #endif 85 86 #include <dev/cons.h> 87 88 #if defined(DDB) 89 #include <ddb/ddbvar.h> 90 #endif 91 92 #define PTRTOINT64(foo) ((u_int64_t)(uintptr_t)(foo)) 93 94 /* 95 * Locking and stats 96 */ 97 static struct sysctl_lock { 98 int sl_lock; 99 int sl_want; 100 int sl_locked; 101 } memlock; 102 103 static int sysctl_file __P((void *, size_t *)); 104 #if defined(SYSVMSG) || defined(SYSVSEM) || defined(SYSVSHM) 105 static int sysctl_sysvipc __P((int *, u_int, void *, size_t *)); 106 #endif 107 static int sysctl_msgbuf __P((void *, size_t *)); 108 static int sysctl_doeproc __P((int *, u_int, void *, size_t *)); 109 static void fill_kproc2 __P((struct proc *, struct kinfo_proc2 *)); 110 static int sysctl_procargs __P((int *, u_int, void *, size_t *, struct proc *)); 111 112 int 113 sys___sysctl(p, v, retval) 114 struct proc *p; 115 void *v; 116 register_t *retval; 117 { 118 struct sys___sysctl_args /* { 119 syscallarg(int *) name; 120 syscallarg(u_int) namelen; 121 syscallarg(void *) old; 122 syscallarg(size_t *) oldlenp; 123 syscallarg(void *) new; 124 syscallarg(size_t) newlen; 125 } */ *uap = v; 126 int error, dolock = 1; 127 size_t savelen = 0, oldlen = 0; 128 sysctlfn *fn; 129 int name[CTL_MAXNAME]; 130 size_t *oldlenp; 131 132 /* 133 * all top-level sysctl names are non-terminal 134 */ 135 if (SCARG(uap, namelen) > CTL_MAXNAME || SCARG(uap, namelen) < 2) 136 return (EINVAL); 137 error = copyin(SCARG(uap, name), &name, 138 SCARG(uap, namelen) * sizeof(int)); 139 if (error) 140 return (error); 141 142 /* 143 * For all but CTL_PROC, must be root to change a value. 144 * For CTL_PROC, must be root, or owner of the proc (and not suid), 145 * this is checked in proc_sysctl() (once we know the targer proc). 146 */ 147 if (SCARG(uap, new) != NULL && name[0] != CTL_PROC && 148 (error = suser(p->p_ucred, &p->p_acflag))) 149 return error; 150 151 switch (name[0]) { 152 case CTL_KERN: 153 fn = kern_sysctl; 154 if (name[2] != KERN_VNODE) /* XXX */ 155 dolock = 0; 156 break; 157 case CTL_HW: 158 fn = hw_sysctl; 159 break; 160 case CTL_VM: 161 fn = uvm_sysctl; 162 break; 163 case CTL_NET: 164 fn = net_sysctl; 165 break; 166 case CTL_VFS: 167 fn = vfs_sysctl; 168 break; 169 case CTL_MACHDEP: 170 fn = cpu_sysctl; 171 break; 172 #ifdef DEBUG 173 case CTL_DEBUG: 174 fn = debug_sysctl; 175 break; 176 #endif 177 #ifdef DDB 178 case CTL_DDB: 179 fn = ddb_sysctl; 180 break; 181 #endif 182 case CTL_PROC: 183 fn = proc_sysctl; 184 break; 185 default: 186 return (EOPNOTSUPP); 187 } 188 189 oldlenp = SCARG(uap, oldlenp); 190 if (oldlenp) { 191 if ((error = copyin(oldlenp, &oldlen, sizeof(oldlen)))) 192 return (error); 193 oldlenp = &oldlen; 194 } 195 if (SCARG(uap, old) != NULL) { 196 if (!uvm_useracc(SCARG(uap, old), oldlen, B_WRITE)) 197 return (EFAULT); 198 while (memlock.sl_lock) { 199 memlock.sl_want = 1; 200 (void) tsleep(&memlock, PRIBIO+1, "memlock", 0); 201 memlock.sl_locked++; 202 } 203 memlock.sl_lock = 1; 204 if (dolock) { 205 /* 206 * XXX Um, this is kind of evil. What should we 207 * XXX be passing here? 208 */ 209 if (uvm_vslock(p, SCARG(uap, old), oldlen, 210 VM_PROT_NONE) != KERN_SUCCESS) { 211 memlock.sl_lock = 0; 212 if (memlock.sl_want) { 213 memlock.sl_want = 0; 214 wakeup((caddr_t)&memlock); 215 return (EFAULT); 216 } 217 } 218 } 219 savelen = oldlen; 220 } 221 error = (*fn)(name + 1, SCARG(uap, namelen) - 1, SCARG(uap, old), 222 oldlenp, SCARG(uap, new), SCARG(uap, newlen), p); 223 if (SCARG(uap, old) != NULL) { 224 if (dolock) 225 uvm_vsunlock(p, SCARG(uap, old), savelen); 226 memlock.sl_lock = 0; 227 if (memlock.sl_want) { 228 memlock.sl_want = 0; 229 wakeup((caddr_t)&memlock); 230 } 231 } 232 if (error) 233 return (error); 234 if (SCARG(uap, oldlenp)) 235 error = copyout(&oldlen, SCARG(uap, oldlenp), sizeof(oldlen)); 236 return (error); 237 } 238 239 /* 240 * Attributes stored in the kernel. 241 */ 242 char hostname[MAXHOSTNAMELEN]; 243 int hostnamelen; 244 char domainname[MAXHOSTNAMELEN]; 245 int domainnamelen; 246 long hostid; 247 #ifdef INSECURE 248 int securelevel = -1; 249 #else 250 int securelevel = 0; 251 #endif 252 #ifdef DEFCORENAME 253 char defcorename[MAXPATHLEN] = DEFCORENAME; 254 int defcorenamelen = sizeof(DEFCORENAME); 255 #else 256 char defcorename[MAXPATHLEN] = "%n.core"; 257 int defcorenamelen = sizeof("%n.core"); 258 #endif 259 extern int kern_logsigexit; 260 extern fixpt_t ccpu; 261 262 /* 263 * kernel related system variables. 264 */ 265 int 266 kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 267 int *name; 268 u_int namelen; 269 void *oldp; 270 size_t *oldlenp; 271 void *newp; 272 size_t newlen; 273 struct proc *p; 274 { 275 int error, level, inthostid; 276 int old_autonicetime; 277 int old_vnodes; 278 dev_t consdev; 279 280 /* All sysctl names at this level, except for a few, are terminal. */ 281 switch (name[0]) { 282 case KERN_PROC: 283 case KERN_PROC2: 284 case KERN_PROF: 285 case KERN_MBUF: 286 case KERN_PROC_ARGS: 287 case KERN_SYSVIPC_INFO: 288 /* Not terminal. */ 289 break; 290 default: 291 if (namelen != 1) 292 return (ENOTDIR); /* overloaded */ 293 } 294 295 switch (name[0]) { 296 case KERN_OSTYPE: 297 return (sysctl_rdstring(oldp, oldlenp, newp, ostype)); 298 case KERN_OSRELEASE: 299 return (sysctl_rdstring(oldp, oldlenp, newp, osrelease)); 300 case KERN_OSREV: 301 return (sysctl_rdint(oldp, oldlenp, newp, NetBSD)); 302 case KERN_VERSION: 303 return (sysctl_rdstring(oldp, oldlenp, newp, version)); 304 case KERN_MAXVNODES: 305 old_vnodes = desiredvnodes; 306 error = sysctl_int(oldp, oldlenp, newp, newlen, &desiredvnodes); 307 if (old_vnodes > desiredvnodes) { 308 desiredvnodes = old_vnodes; 309 return (EINVAL); 310 } 311 return (error); 312 case KERN_MAXPROC: 313 return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc)); 314 case KERN_MAXFILES: 315 return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles)); 316 case KERN_ARGMAX: 317 return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX)); 318 case KERN_SECURELVL: 319 level = securelevel; 320 if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) || 321 newp == NULL) 322 return (error); 323 if (level < securelevel && p->p_pid != 1) 324 return (EPERM); 325 securelevel = level; 326 return (0); 327 case KERN_HOSTNAME: 328 error = sysctl_string(oldp, oldlenp, newp, newlen, 329 hostname, sizeof(hostname)); 330 if (newp && !error) 331 hostnamelen = newlen; 332 return (error); 333 case KERN_DOMAINNAME: 334 error = sysctl_string(oldp, oldlenp, newp, newlen, 335 domainname, sizeof(domainname)); 336 if (newp && !error) 337 domainnamelen = newlen; 338 return (error); 339 case KERN_HOSTID: 340 inthostid = hostid; /* XXX assumes sizeof long <= sizeof int */ 341 error = sysctl_int(oldp, oldlenp, newp, newlen, &inthostid); 342 hostid = inthostid; 343 return (error); 344 case KERN_CLOCKRATE: 345 return (sysctl_clockrate(oldp, oldlenp)); 346 case KERN_BOOTTIME: 347 return (sysctl_rdstruct(oldp, oldlenp, newp, &boottime, 348 sizeof(struct timeval))); 349 case KERN_VNODE: 350 return (sysctl_vnode(oldp, oldlenp, p)); 351 case KERN_PROC: 352 case KERN_PROC2: 353 return (sysctl_doeproc(name, namelen, oldp, oldlenp)); 354 case KERN_PROC_ARGS: 355 return (sysctl_procargs(name + 1, namelen - 1, 356 oldp, oldlenp, p)); 357 case KERN_FILE: 358 return (sysctl_file(oldp, oldlenp)); 359 #ifdef GPROF 360 case KERN_PROF: 361 return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp, 362 newp, newlen)); 363 #endif 364 case KERN_POSIX1: 365 return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION)); 366 case KERN_NGROUPS: 367 return (sysctl_rdint(oldp, oldlenp, newp, NGROUPS_MAX)); 368 case KERN_JOB_CONTROL: 369 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 370 case KERN_SAVED_IDS: 371 #ifdef _POSIX_SAVED_IDS 372 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 373 #else 374 return (sysctl_rdint(oldp, oldlenp, newp, 0)); 375 #endif 376 case KERN_MAXPARTITIONS: 377 return (sysctl_rdint(oldp, oldlenp, newp, MAXPARTITIONS)); 378 case KERN_RAWPARTITION: 379 return (sysctl_rdint(oldp, oldlenp, newp, RAW_PART)); 380 #ifdef NTP 381 case KERN_NTPTIME: 382 return (sysctl_ntptime(oldp, oldlenp)); 383 #endif 384 case KERN_AUTONICETIME: 385 old_autonicetime = autonicetime; 386 error = sysctl_int(oldp, oldlenp, newp, newlen, &autonicetime); 387 if (autonicetime < 0) 388 autonicetime = old_autonicetime; 389 return (error); 390 case KERN_AUTONICEVAL: 391 error = sysctl_int(oldp, oldlenp, newp, newlen, &autoniceval); 392 if (autoniceval < PRIO_MIN) 393 autoniceval = PRIO_MIN; 394 if (autoniceval > PRIO_MAX) 395 autoniceval = PRIO_MAX; 396 return (error); 397 case KERN_RTC_OFFSET: 398 return (sysctl_rdint(oldp, oldlenp, newp, rtc_offset)); 399 case KERN_ROOT_DEVICE: 400 return (sysctl_rdstring(oldp, oldlenp, newp, 401 root_device->dv_xname)); 402 case KERN_MSGBUFSIZE: 403 /* 404 * deal with cases where the message buffer has 405 * become corrupted. 406 */ 407 if (!msgbufenabled || msgbufp->msg_magic != MSG_MAGIC) { 408 msgbufenabled = 0; 409 return (ENXIO); 410 } 411 return (sysctl_rdint(oldp, oldlenp, newp, msgbufp->msg_bufs)); 412 case KERN_FSYNC: 413 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 414 case KERN_SYSVMSG: 415 #ifdef SYSVMSG 416 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 417 #else 418 return (sysctl_rdint(oldp, oldlenp, newp, 0)); 419 #endif 420 case KERN_SYSVSEM: 421 #ifdef SYSVSEM 422 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 423 #else 424 return (sysctl_rdint(oldp, oldlenp, newp, 0)); 425 #endif 426 case KERN_SYSVSHM: 427 #ifdef SYSVSHM 428 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 429 #else 430 return (sysctl_rdint(oldp, oldlenp, newp, 0)); 431 #endif 432 case KERN_DEFCORENAME: 433 if (newp && newlen < 1) 434 return (EINVAL); 435 error = sysctl_string(oldp, oldlenp, newp, newlen, 436 defcorename, sizeof(defcorename)); 437 if (newp && !error) 438 defcorenamelen = newlen; 439 return (error); 440 case KERN_SYNCHRONIZED_IO: 441 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 442 case KERN_IOV_MAX: 443 return (sysctl_rdint(oldp, oldlenp, newp, IOV_MAX)); 444 case KERN_MBUF: 445 return (sysctl_dombuf(name + 1, namelen - 1, oldp, oldlenp, 446 newp, newlen)); 447 case KERN_MAPPED_FILES: 448 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 449 case KERN_MEMLOCK: 450 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 451 case KERN_MEMLOCK_RANGE: 452 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 453 case KERN_MEMORY_PROTECTION: 454 return (sysctl_rdint(oldp, oldlenp, newp, 1)); 455 case KERN_LOGIN_NAME_MAX: 456 return (sysctl_rdint(oldp, oldlenp, newp, LOGIN_NAME_MAX)); 457 case KERN_LOGSIGEXIT: 458 return (sysctl_int(oldp, oldlenp, newp, newlen, 459 &kern_logsigexit)); 460 case KERN_FSCALE: 461 return (sysctl_rdint(oldp, oldlenp, newp, FSCALE)); 462 case KERN_CCPU: 463 return (sysctl_rdint(oldp, oldlenp, newp, ccpu)); 464 case KERN_CP_TIME: 465 /* XXXSMP: WRONG! */ 466 return (sysctl_rdstruct(oldp, oldlenp, newp, 467 curcpu()->ci_schedstate.spc_cp_time, 468 sizeof(curcpu()->ci_schedstate.spc_cp_time))); 469 #if defined(SYSVMSG) || defined(SYSVSEM) || defined(SYSVSHM) 470 case KERN_SYSVIPC_INFO: 471 return (sysctl_sysvipc(name + 1, namelen - 1, oldp, oldlenp)); 472 #endif 473 case KERN_MSGBUF: 474 return (sysctl_msgbuf(oldp, oldlenp)); 475 case KERN_CONSDEV: 476 if (cn_tab != NULL) 477 consdev = cn_tab->cn_dev; 478 else 479 consdev = NODEV; 480 return (sysctl_rdstruct(oldp, oldlenp, newp, &consdev, 481 sizeof consdev)); 482 default: 483 return (EOPNOTSUPP); 484 } 485 /* NOTREACHED */ 486 } 487 488 /* 489 * hardware related system variables. 490 */ 491 int 492 hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 493 int *name; 494 u_int namelen; 495 void *oldp; 496 size_t *oldlenp; 497 void *newp; 498 size_t newlen; 499 struct proc *p; 500 { 501 502 /* all sysctl names at this level are terminal */ 503 if (namelen != 1) 504 return (ENOTDIR); /* overloaded */ 505 506 switch (name[0]) { 507 case HW_MACHINE: 508 return (sysctl_rdstring(oldp, oldlenp, newp, machine)); 509 case HW_MACHINE_ARCH: 510 return (sysctl_rdstring(oldp, oldlenp, newp, machine_arch)); 511 case HW_MODEL: 512 return (sysctl_rdstring(oldp, oldlenp, newp, cpu_model)); 513 case HW_NCPU: 514 return (sysctl_rdint(oldp, oldlenp, newp, 1)); /* XXX */ 515 case HW_BYTEORDER: 516 return (sysctl_rdint(oldp, oldlenp, newp, BYTE_ORDER)); 517 case HW_PHYSMEM: 518 return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem))); 519 case HW_USERMEM: 520 return (sysctl_rdint(oldp, oldlenp, newp, 521 ctob(physmem - uvmexp.wired))); 522 case HW_PAGESIZE: 523 return (sysctl_rdint(oldp, oldlenp, newp, PAGE_SIZE)); 524 case HW_ALIGNBYTES: 525 return (sysctl_rdint(oldp, oldlenp, newp, ALIGNBYTES)); 526 default: 527 return (EOPNOTSUPP); 528 } 529 /* NOTREACHED */ 530 } 531 532 #ifdef DEBUG 533 /* 534 * Debugging related system variables. 535 */ 536 struct ctldebug debug0, debug1, debug2, debug3, debug4; 537 struct ctldebug debug5, debug6, debug7, debug8, debug9; 538 struct ctldebug debug10, debug11, debug12, debug13, debug14; 539 struct ctldebug debug15, debug16, debug17, debug18, debug19; 540 static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = { 541 &debug0, &debug1, &debug2, &debug3, &debug4, 542 &debug5, &debug6, &debug7, &debug8, &debug9, 543 &debug10, &debug11, &debug12, &debug13, &debug14, 544 &debug15, &debug16, &debug17, &debug18, &debug19, 545 }; 546 int 547 debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 548 int *name; 549 u_int namelen; 550 void *oldp; 551 size_t *oldlenp; 552 void *newp; 553 size_t newlen; 554 struct proc *p; 555 { 556 struct ctldebug *cdp; 557 558 /* all sysctl names at this level are name and field */ 559 if (namelen != 2) 560 return (ENOTDIR); /* overloaded */ 561 cdp = debugvars[name[0]]; 562 if (name[0] >= CTL_DEBUG_MAXID || cdp->debugname == 0) 563 return (EOPNOTSUPP); 564 switch (name[1]) { 565 case CTL_DEBUG_NAME: 566 return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname)); 567 case CTL_DEBUG_VALUE: 568 return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar)); 569 default: 570 return (EOPNOTSUPP); 571 } 572 /* NOTREACHED */ 573 } 574 #endif /* DEBUG */ 575 576 int 577 proc_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 578 int *name; 579 u_int namelen; 580 void *oldp; 581 size_t *oldlenp; 582 void *newp; 583 size_t newlen; 584 struct proc *p; 585 { 586 struct proc *ptmp = NULL; 587 const struct proclist_desc *pd; 588 int error = 0; 589 struct rlimit alim; 590 struct plimit *newplim; 591 char *tmps = NULL; 592 int i, curlen, len; 593 594 if (namelen < 2) 595 return EINVAL; 596 597 if (name[0] == PROC_CURPROC) { 598 ptmp = p; 599 } else { 600 proclist_lock_read(); 601 for (pd = proclists; pd->pd_list != NULL; pd++) { 602 for (ptmp = LIST_FIRST(pd->pd_list); ptmp != NULL; 603 ptmp = LIST_NEXT(ptmp, p_list)) { 604 /* Skip embryonic processes. */ 605 if (ptmp->p_stat == SIDL) 606 continue; 607 if (ptmp->p_pid == (pid_t)name[0]) 608 break; 609 } 610 if (ptmp != NULL) 611 break; 612 } 613 proclist_unlock_read(); 614 if (ptmp == NULL) 615 return(ESRCH); 616 if (p->p_ucred->cr_uid != 0) { 617 if(p->p_cred->p_ruid != ptmp->p_cred->p_ruid || 618 p->p_cred->p_ruid != ptmp->p_cred->p_svuid) 619 return EPERM; 620 if (ptmp->p_cred->p_rgid != ptmp->p_cred->p_svgid) 621 return EPERM; /* sgid proc */ 622 for (i = 0; i < p->p_ucred->cr_ngroups; i++) { 623 if (p->p_ucred->cr_groups[i] == 624 ptmp->p_cred->p_rgid) 625 break; 626 } 627 if (i == p->p_ucred->cr_ngroups) 628 return EPERM; 629 } 630 } 631 if (name[1] == PROC_PID_CORENAME) { 632 if (namelen != 2) 633 return EINVAL; 634 /* 635 * Can't use sysctl_string() here because we may malloc a new 636 * area during the process, so we have to do it by hand. 637 */ 638 curlen = strlen(ptmp->p_limit->pl_corename) + 1; 639 if (oldlenp && *oldlenp < curlen) { 640 if (!oldp) 641 *oldlenp = curlen; 642 return (ENOMEM); 643 } 644 if (newp) { 645 if (securelevel > 2) 646 return EPERM; 647 if (newlen > MAXPATHLEN) 648 return ENAMETOOLONG; 649 tmps = malloc(newlen + 1, M_TEMP, M_WAITOK); 650 if (tmps == NULL) 651 return ENOMEM; 652 error = copyin(newp, tmps, newlen + 1); 653 tmps[newlen] = '\0'; 654 if (error) 655 goto cleanup; 656 /* Enforce to be either 'core' for end with '.core' */ 657 if (newlen < 4) { /* c.o.r.e */ 658 error = EINVAL; 659 goto cleanup; 660 } 661 len = newlen - 4; 662 if (len > 0) { 663 if (tmps[len - 1] != '.' && 664 tmps[len - 1] != '/') { 665 error = EINVAL; 666 goto cleanup; 667 } 668 } 669 if (strcmp(&tmps[len], "core") != 0) { 670 error = EINVAL; 671 goto cleanup; 672 } 673 } 674 if (oldp && oldlenp) { 675 *oldlenp = curlen; 676 error = copyout(ptmp->p_limit->pl_corename, oldp, 677 curlen); 678 } 679 if (newp && error == 0) { 680 /* if the 2 strings are identical, don't limcopy() */ 681 if (strcmp(tmps, ptmp->p_limit->pl_corename) == 0) { 682 error = 0; 683 goto cleanup; 684 } 685 if (ptmp->p_limit->p_refcnt > 1 && 686 (ptmp->p_limit->p_lflags & PL_SHAREMOD) == 0) { 687 newplim = limcopy(ptmp->p_limit); 688 limfree(ptmp->p_limit); 689 ptmp->p_limit = newplim; 690 } else if (ptmp->p_limit->pl_corename != defcorename) { 691 free(ptmp->p_limit->pl_corename, M_TEMP); 692 } 693 ptmp->p_limit->pl_corename = tmps; 694 return (0); 695 } 696 cleanup: 697 if (tmps) 698 free(tmps, M_TEMP); 699 return (error); 700 } 701 if (name[1] == PROC_PID_LIMIT) { 702 if (namelen != 4 || name[2] >= PROC_PID_LIMIT_MAXID) 703 return EINVAL; 704 memcpy(&alim, &ptmp->p_rlimit[name[2] - 1], sizeof(alim)); 705 if (name[3] == PROC_PID_LIMIT_TYPE_HARD) 706 error = sysctl_quad(oldp, oldlenp, newp, newlen, 707 &alim.rlim_max); 708 else if (name[3] == PROC_PID_LIMIT_TYPE_SOFT) 709 error = sysctl_quad(oldp, oldlenp, newp, newlen, 710 &alim.rlim_cur); 711 else 712 error = EINVAL; 713 714 if (error) 715 return error; 716 717 if (newp) 718 error = dosetrlimit(ptmp, p->p_cred, 719 name[2] - 1, &alim); 720 return error; 721 } 722 return (EINVAL); 723 } 724 725 /* 726 * Convenience macros. 727 */ 728 729 #define SYSCTL_SCALAR_CORE_LEN(oldp, oldlenp, valp, len) \ 730 if (oldlenp) { \ 731 if (!oldp) \ 732 *oldlenp = len; \ 733 else { \ 734 if (*oldlenp < len) \ 735 return(ENOMEM); \ 736 *oldlenp = len; \ 737 error = copyout((caddr_t)valp, oldp, len); \ 738 } \ 739 } 740 741 #define SYSCTL_SCALAR_CORE_TYP(oldp, oldlenp, valp, typ) \ 742 SYSCTL_SCALAR_CORE_LEN(oldp, oldlenp, valp, sizeof(typ)) 743 744 #define SYSCTL_SCALAR_NEWPCHECK_LEN(newp, newlen, len) \ 745 if (newp && newlen != len) \ 746 return (EINVAL); 747 748 #define SYSCTL_SCALAR_NEWPCHECK_TYP(newp, newlen, typ) \ 749 SYSCTL_SCALAR_NEWPCHECK_LEN(newp, newlen, sizeof(typ)) 750 751 #define SYSCTL_SCALAR_NEWPCOP_LEN(newp, valp, len) \ 752 if (error == 0 && newp) \ 753 error = copyin(newp, valp, len); 754 755 #define SYSCTL_SCALAR_NEWPCOP_TYP(newp, valp, typ) \ 756 SYSCTL_SCALAR_NEWPCOP_LEN(newp, valp, sizeof(typ)) 757 758 #define SYSCTL_STRING_CORE(oldp, oldlenp, str) \ 759 if (oldlenp) { \ 760 len = strlen(str) + 1; \ 761 if (!oldp) \ 762 *oldlenp = len; \ 763 else { \ 764 if (*oldlenp < len) { \ 765 err2 = ENOMEM; \ 766 len = *oldlenp; \ 767 } else \ 768 *oldlenp = len; \ 769 error = copyout(str, oldp, len);\ 770 if (error == 0) \ 771 error = err2; \ 772 } \ 773 } 774 775 /* 776 * Validate parameters and get old / set new parameters 777 * for an integer-valued sysctl function. 778 */ 779 int 780 sysctl_int(oldp, oldlenp, newp, newlen, valp) 781 void *oldp; 782 size_t *oldlenp; 783 void *newp; 784 size_t newlen; 785 int *valp; 786 { 787 int error = 0; 788 789 SYSCTL_SCALAR_NEWPCHECK_TYP(newp, newlen, int) 790 SYSCTL_SCALAR_CORE_TYP(oldp, oldlenp, valp, int) 791 SYSCTL_SCALAR_NEWPCOP_TYP(newp, valp, int) 792 793 return (error); 794 } 795 796 797 /* 798 * As above, but read-only. 799 */ 800 int 801 sysctl_rdint(oldp, oldlenp, newp, val) 802 void *oldp; 803 size_t *oldlenp; 804 void *newp; 805 int val; 806 { 807 int error = 0; 808 809 if (newp) 810 return (EPERM); 811 812 SYSCTL_SCALAR_CORE_TYP(oldp, oldlenp, &val, int) 813 814 return (error); 815 } 816 817 /* 818 * Validate parameters and get old / set new parameters 819 * for an quad-valued sysctl function. 820 */ 821 int 822 sysctl_quad(oldp, oldlenp, newp, newlen, valp) 823 void *oldp; 824 size_t *oldlenp; 825 void *newp; 826 size_t newlen; 827 quad_t *valp; 828 { 829 int error = 0; 830 831 SYSCTL_SCALAR_NEWPCHECK_TYP(newp, newlen, quad_t) 832 SYSCTL_SCALAR_CORE_TYP(oldp, oldlenp, valp, quad_t) 833 SYSCTL_SCALAR_NEWPCOP_TYP(newp, valp, quad_t) 834 835 return (error); 836 } 837 838 /* 839 * As above, but read-only. 840 */ 841 int 842 sysctl_rdquad(oldp, oldlenp, newp, val) 843 void *oldp; 844 size_t *oldlenp; 845 void *newp; 846 quad_t val; 847 { 848 int error = 0; 849 850 if (newp) 851 return (EPERM); 852 853 SYSCTL_SCALAR_CORE_TYP(oldp, oldlenp, &val, quad_t) 854 855 return (error); 856 } 857 858 /* 859 * Validate parameters and get old / set new parameters 860 * for a string-valued sysctl function. 861 */ 862 int 863 sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen) 864 void *oldp; 865 size_t *oldlenp; 866 void *newp; 867 size_t newlen; 868 char *str; 869 int maxlen; 870 { 871 int len, error = 0, err2 = 0; 872 873 if (newp && newlen >= maxlen) 874 return (EINVAL); 875 876 SYSCTL_STRING_CORE(oldp, oldlenp, str); 877 878 if (error == 0 && newp) { 879 error = copyin(newp, str, newlen); 880 str[newlen] = 0; 881 } 882 return (error); 883 } 884 885 /* 886 * As above, but read-only. 887 */ 888 int 889 sysctl_rdstring(oldp, oldlenp, newp, str) 890 void *oldp; 891 size_t *oldlenp; 892 void *newp; 893 char *str; 894 { 895 int len, error = 0, err2 = 0; 896 897 if (newp) 898 return (EPERM); 899 900 SYSCTL_STRING_CORE(oldp, oldlenp, str); 901 902 return (error); 903 } 904 905 /* 906 * Validate parameters and get old / set new parameters 907 * for a structure oriented sysctl function. 908 */ 909 int 910 sysctl_struct(oldp, oldlenp, newp, newlen, sp, len) 911 void *oldp; 912 size_t *oldlenp; 913 void *newp; 914 size_t newlen; 915 void *sp; 916 int len; 917 { 918 int error = 0; 919 920 SYSCTL_SCALAR_NEWPCHECK_LEN(newp, newlen, len) 921 SYSCTL_SCALAR_CORE_LEN(oldp, oldlenp, sp, len) 922 SYSCTL_SCALAR_NEWPCOP_LEN(newp, sp, len) 923 924 return (error); 925 } 926 927 /* 928 * Validate parameters and get old parameters 929 * for a structure oriented sysctl function. 930 */ 931 int 932 sysctl_rdstruct(oldp, oldlenp, newp, sp, len) 933 void *oldp; 934 size_t *oldlenp; 935 void *newp, *sp; 936 int len; 937 { 938 int error = 0; 939 940 if (newp) 941 return (EPERM); 942 943 SYSCTL_SCALAR_CORE_LEN(oldp, oldlenp, sp, len) 944 945 return (error); 946 } 947 948 /* 949 * Get file structures. 950 */ 951 static int 952 sysctl_file(vwhere, sizep) 953 void *vwhere; 954 size_t *sizep; 955 { 956 int buflen, error; 957 struct file *fp; 958 char *start, *where; 959 960 start = where = vwhere; 961 buflen = *sizep; 962 if (where == NULL) { 963 /* 964 * overestimate by 10 files 965 */ 966 *sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file); 967 return (0); 968 } 969 970 /* 971 * first copyout filehead 972 */ 973 if (buflen < sizeof(filehead)) { 974 *sizep = 0; 975 return (0); 976 } 977 error = copyout((caddr_t)&filehead, where, sizeof(filehead)); 978 if (error) 979 return (error); 980 buflen -= sizeof(filehead); 981 where += sizeof(filehead); 982 983 /* 984 * followed by an array of file structures 985 */ 986 for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) { 987 if (buflen < sizeof(struct file)) { 988 *sizep = where - start; 989 return (ENOMEM); 990 } 991 error = copyout((caddr_t)fp, where, sizeof(struct file)); 992 if (error) 993 return (error); 994 buflen -= sizeof(struct file); 995 where += sizeof(struct file); 996 } 997 *sizep = where - start; 998 return (0); 999 } 1000 1001 #if defined(SYSVMSG) || defined(SYSVSEM) || defined(SYSVSHM) 1002 #define FILL_PERM(src, dst) do { \ 1003 (dst)._key = (src)._key; \ 1004 (dst).uid = (src).uid; \ 1005 (dst).gid = (src).gid; \ 1006 (dst).cuid = (src).cuid; \ 1007 (dst).cgid = (src).cgid; \ 1008 (dst).mode = (src).mode; \ 1009 (dst)._seq = (src)._seq; \ 1010 } while (0); 1011 #define FILL_MSG(src, dst) do { \ 1012 FILL_PERM((src).msg_perm, (dst).msg_perm); \ 1013 (dst).msg_qnum = (src).msg_qnum; \ 1014 (dst).msg_qbytes = (src).msg_qbytes; \ 1015 (dst)._msg_cbytes = (src)._msg_cbytes; \ 1016 (dst).msg_lspid = (src).msg_lspid; \ 1017 (dst).msg_lrpid = (src).msg_lrpid; \ 1018 (dst).msg_stime = (src).msg_stime; \ 1019 (dst).msg_rtime = (src).msg_rtime; \ 1020 (dst).msg_ctime = (src).msg_ctime; \ 1021 } while (0) 1022 #define FILL_SEM(src, dst) do { \ 1023 FILL_PERM((src).sem_perm, (dst).sem_perm); \ 1024 (dst).sem_nsems = (src).sem_nsems; \ 1025 (dst).sem_otime = (src).sem_otime; \ 1026 (dst).sem_ctime = (src).sem_ctime; \ 1027 } while (0) 1028 #define FILL_SHM(src, dst) do { \ 1029 FILL_PERM((src).shm_perm, (dst).shm_perm); \ 1030 (dst).shm_segsz = (src).shm_segsz; \ 1031 (dst).shm_lpid = (src).shm_lpid; \ 1032 (dst).shm_cpid = (src).shm_cpid; \ 1033 (dst).shm_atime = (src).shm_atime; \ 1034 (dst).shm_dtime = (src).shm_dtime; \ 1035 (dst).shm_ctime = (src).shm_ctime; \ 1036 (dst).shm_nattch = (src).shm_nattch; \ 1037 } while (0) 1038 1039 static int 1040 sysctl_sysvipc(name, namelen, where, sizep) 1041 int *name; 1042 u_int namelen; 1043 void *where; 1044 size_t *sizep; 1045 { 1046 #ifdef SYSVMSG 1047 struct msg_sysctl_info *msgsi; 1048 #endif 1049 #ifdef SYSVSEM 1050 struct sem_sysctl_info *semsi; 1051 #endif 1052 #ifdef SYSVSHM 1053 struct shm_sysctl_info *shmsi; 1054 #endif 1055 size_t infosize, dssize, tsize, buflen; 1056 void *buf = NULL, *buf2; 1057 char *start; 1058 int32_t nds; 1059 int i, error, ret; 1060 1061 if (namelen != 1) 1062 return (EINVAL); 1063 1064 start = where; 1065 buflen = *sizep; 1066 1067 switch (*name) { 1068 case KERN_SYSVIPC_MSG_INFO: 1069 #ifdef SYSVMSG 1070 infosize = sizeof(msgsi->msginfo); 1071 nds = msginfo.msgmni; 1072 dssize = sizeof(msgsi->msgids[0]); 1073 break; 1074 #else 1075 return (EINVAL); 1076 #endif 1077 case KERN_SYSVIPC_SEM_INFO: 1078 #ifdef SYSVSEM 1079 infosize = sizeof(semsi->seminfo); 1080 nds = seminfo.semmni; 1081 dssize = sizeof(semsi->semids[0]); 1082 break; 1083 #else 1084 return (EINVAL); 1085 #endif 1086 case KERN_SYSVIPC_SHM_INFO: 1087 #ifdef SYSVSHM 1088 infosize = sizeof(shmsi->shminfo); 1089 nds = shminfo.shmmni; 1090 dssize = sizeof(shmsi->shmids[0]); 1091 break; 1092 #else 1093 return (EINVAL); 1094 #endif 1095 default: 1096 return (EINVAL); 1097 } 1098 /* 1099 * Round infosize to 64 bit boundary if requesting more than just 1100 * the info structure or getting the total data size. 1101 */ 1102 if (where == NULL || *sizep > infosize) 1103 infosize = ((infosize + 7) / 8) * 8; 1104 tsize = infosize + nds * dssize; 1105 1106 /* Return just the total size required. */ 1107 if (where == NULL) { 1108 *sizep = tsize; 1109 return (0); 1110 } 1111 1112 /* Not enough room for even the info struct. */ 1113 if (buflen < infosize) { 1114 *sizep = 0; 1115 return (ENOMEM); 1116 } 1117 buf = malloc(min(tsize, buflen), M_TEMP, M_WAITOK); 1118 memset(buf, 0, min(tsize, buflen)); 1119 1120 switch (*name) { 1121 #ifdef SYSVMSG 1122 case KERN_SYSVIPC_MSG_INFO: 1123 msgsi = (struct msg_sysctl_info *)buf; 1124 buf2 = &msgsi->msgids[0]; 1125 msgsi->msginfo = msginfo; 1126 break; 1127 #endif 1128 #ifdef SYSVSEM 1129 case KERN_SYSVIPC_SEM_INFO: 1130 semsi = (struct sem_sysctl_info *)buf; 1131 buf2 = &semsi->semids[0]; 1132 semsi->seminfo = seminfo; 1133 break; 1134 #endif 1135 #ifdef SYSVSHM 1136 case KERN_SYSVIPC_SHM_INFO: 1137 shmsi = (struct shm_sysctl_info *)buf; 1138 buf2 = &shmsi->shmids[0]; 1139 shmsi->shminfo = shminfo; 1140 break; 1141 #endif 1142 } 1143 buflen -= infosize; 1144 1145 ret = 0; 1146 if (buflen > 0) { 1147 /* Fill in the IPC data structures. */ 1148 for (i = 0; i < nds; i++) { 1149 if (buflen < dssize) { 1150 ret = ENOMEM; 1151 break; 1152 } 1153 switch (*name) { 1154 #ifdef SYSVMSG 1155 case KERN_SYSVIPC_MSG_INFO: 1156 FILL_MSG(msqids[i], msgsi->msgids[i]); 1157 break; 1158 #endif 1159 #ifdef SYSVSEM 1160 case KERN_SYSVIPC_SEM_INFO: 1161 FILL_SEM(sema[i], semsi->semids[i]); 1162 break; 1163 #endif 1164 #ifdef SYSVSHM 1165 case KERN_SYSVIPC_SHM_INFO: 1166 FILL_SHM(shmsegs[i], shmsi->shmids[i]); 1167 break; 1168 #endif 1169 } 1170 buflen -= dssize; 1171 } 1172 } 1173 *sizep -= buflen; 1174 error = copyout(buf, start, *sizep); 1175 /* If copyout succeeded, use return code set earlier. */ 1176 if (error == 0) 1177 error = ret; 1178 if (buf) 1179 free(buf, M_TEMP); 1180 return (error); 1181 } 1182 #endif /* SYSVMSG || SYSVSEM || SYSVSHM */ 1183 1184 static int 1185 sysctl_msgbuf(vwhere, sizep) 1186 void *vwhere; 1187 size_t *sizep; 1188 { 1189 char *where = vwhere; 1190 size_t len, maxlen = *sizep; 1191 long pos; 1192 int error; 1193 1194 /* 1195 * deal with cases where the message buffer has 1196 * become corrupted. 1197 */ 1198 if (!msgbufenabled || msgbufp->msg_magic != MSG_MAGIC) { 1199 msgbufenabled = 0; 1200 return (ENXIO); 1201 } 1202 1203 if (where == NULL) { 1204 /* always return full buffer size */ 1205 *sizep = msgbufp->msg_bufs; 1206 return (0); 1207 } 1208 1209 error = 0; 1210 maxlen = min(msgbufp->msg_bufs, maxlen); 1211 pos = msgbufp->msg_bufx; 1212 while (maxlen > 0) { 1213 len = pos == 0 ? msgbufp->msg_bufx : msgbufp->msg_bufs - msgbufp->msg_bufx; 1214 len = min(len, maxlen); 1215 if (len == 0) 1216 break; 1217 error = copyout(&msgbufp->msg_bufc[pos], where, len); 1218 if (error) 1219 break; 1220 where += len; 1221 maxlen -= len; 1222 pos = 0; 1223 } 1224 return (error); 1225 } 1226 1227 /* 1228 * try over estimating by 5 procs 1229 */ 1230 #define KERN_PROCSLOP (5 * sizeof(struct kinfo_proc)) 1231 1232 static int 1233 sysctl_doeproc(name, namelen, vwhere, sizep) 1234 int *name; 1235 u_int namelen; 1236 void *vwhere; 1237 size_t *sizep; 1238 { 1239 struct eproc eproc; 1240 struct kinfo_proc2 kproc2; 1241 struct kinfo_proc *dp; 1242 struct proc *p; 1243 const struct proclist_desc *pd; 1244 char *where, *dp2; 1245 int type, op, arg, elem_size, elem_count; 1246 int buflen, needed, error; 1247 1248 dp = vwhere; 1249 dp2 = where = vwhere; 1250 buflen = where != NULL ? *sizep : 0; 1251 error = needed = 0; 1252 type = name[0]; 1253 1254 if (type == KERN_PROC) { 1255 if (namelen != 3 && !(namelen == 2 && name[1] == KERN_PROC_ALL)) 1256 return (EINVAL); 1257 op = name[1]; 1258 if (op != KERN_PROC_ALL) 1259 arg = name[2]; 1260 } else { 1261 if (namelen != 5) 1262 return (EINVAL); 1263 op = name[1]; 1264 arg = name[2]; 1265 elem_size = name[3]; 1266 elem_count = name[4]; 1267 } 1268 1269 proclist_lock_read(); 1270 1271 pd = proclists; 1272 again: 1273 for (p = LIST_FIRST(pd->pd_list); p != NULL; p = LIST_NEXT(p, p_list)) { 1274 /* 1275 * Skip embryonic processes. 1276 */ 1277 if (p->p_stat == SIDL) 1278 continue; 1279 /* 1280 * TODO - make more efficient (see notes below). 1281 * do by session. 1282 */ 1283 switch (op) { 1284 1285 case KERN_PROC_PID: 1286 /* could do this with just a lookup */ 1287 if (p->p_pid != (pid_t)arg) 1288 continue; 1289 break; 1290 1291 case KERN_PROC_PGRP: 1292 /* could do this by traversing pgrp */ 1293 if (p->p_pgrp->pg_id != (pid_t)arg) 1294 continue; 1295 break; 1296 1297 case KERN_PROC_SESSION: 1298 if (p->p_session->s_sid != (pid_t)arg) 1299 continue; 1300 break; 1301 1302 case KERN_PROC_TTY: 1303 if (arg == KERN_PROC_TTY_REVOKE) { 1304 if ((p->p_flag & P_CONTROLT) == 0 || 1305 p->p_session->s_ttyp == NULL || 1306 p->p_session->s_ttyvp != NULL) 1307 continue; 1308 } else if ((p->p_flag & P_CONTROLT) == 0 || 1309 p->p_session->s_ttyp == NULL) { 1310 if ((dev_t)arg != KERN_PROC_TTY_NODEV) 1311 continue; 1312 } else if (p->p_session->s_ttyp->t_dev != (dev_t)arg) 1313 continue; 1314 break; 1315 1316 case KERN_PROC_UID: 1317 if (p->p_ucred->cr_uid != (uid_t)arg) 1318 continue; 1319 break; 1320 1321 case KERN_PROC_RUID: 1322 if (p->p_cred->p_ruid != (uid_t)arg) 1323 continue; 1324 break; 1325 1326 case KERN_PROC_GID: 1327 if (p->p_ucred->cr_gid != (uid_t)arg) 1328 continue; 1329 break; 1330 1331 case KERN_PROC_RGID: 1332 if (p->p_cred->p_rgid != (uid_t)arg) 1333 continue; 1334 break; 1335 1336 case KERN_PROC_ALL: 1337 /* allow everything */ 1338 break; 1339 1340 default: 1341 error = EINVAL; 1342 goto cleanup; 1343 } 1344 if (type == KERN_PROC) { 1345 if (buflen >= sizeof(struct kinfo_proc)) { 1346 fill_eproc(p, &eproc); 1347 error = copyout((caddr_t)p, &dp->kp_proc, 1348 sizeof(struct proc)); 1349 if (error) 1350 goto cleanup; 1351 error = copyout((caddr_t)&eproc, &dp->kp_eproc, 1352 sizeof(eproc)); 1353 if (error) 1354 goto cleanup; 1355 dp++; 1356 buflen -= sizeof(struct kinfo_proc); 1357 } 1358 needed += sizeof(struct kinfo_proc); 1359 } else { /* KERN_PROC2 */ 1360 if (buflen >= elem_size && elem_count > 0) { 1361 fill_kproc2(p, &kproc2); 1362 /* 1363 * Copy out elem_size, but not larger than 1364 * the size of a struct kinfo_proc2. 1365 */ 1366 error = copyout(&kproc2, dp2, 1367 min(sizeof(kproc2), elem_size)); 1368 if (error) 1369 goto cleanup; 1370 dp2 += elem_size; 1371 buflen -= elem_size; 1372 elem_count--; 1373 } 1374 needed += elem_size; 1375 } 1376 } 1377 pd++; 1378 if (pd->pd_list != NULL) 1379 goto again; 1380 proclist_unlock_read(); 1381 1382 if (where != NULL) { 1383 if (type == KERN_PROC) 1384 *sizep = (caddr_t)dp - where; 1385 else 1386 *sizep = dp2 - where; 1387 if (needed > *sizep) 1388 return (ENOMEM); 1389 } else { 1390 needed += KERN_PROCSLOP; 1391 *sizep = needed; 1392 } 1393 return (0); 1394 cleanup: 1395 proclist_unlock_read(); 1396 return (error); 1397 } 1398 1399 /* 1400 * Fill in an eproc structure for the specified process. 1401 */ 1402 void 1403 fill_eproc(p, ep) 1404 struct proc *p; 1405 struct eproc *ep; 1406 { 1407 struct tty *tp; 1408 1409 ep->e_paddr = p; 1410 ep->e_sess = p->p_session; 1411 ep->e_pcred = *p->p_cred; 1412 ep->e_ucred = *p->p_ucred; 1413 if (p->p_stat == SIDL || P_ZOMBIE(p)) { 1414 ep->e_vm.vm_rssize = 0; 1415 ep->e_vm.vm_tsize = 0; 1416 ep->e_vm.vm_dsize = 0; 1417 ep->e_vm.vm_ssize = 0; 1418 /* ep->e_vm.vm_pmap = XXX; */ 1419 } else { 1420 struct vmspace *vm = p->p_vmspace; 1421 1422 ep->e_vm.vm_rssize = vm_resident_count(vm); 1423 ep->e_vm.vm_tsize = vm->vm_tsize; 1424 ep->e_vm.vm_dsize = vm->vm_dsize; 1425 ep->e_vm.vm_ssize = vm->vm_ssize; 1426 } 1427 if (p->p_pptr) 1428 ep->e_ppid = p->p_pptr->p_pid; 1429 else 1430 ep->e_ppid = 0; 1431 ep->e_pgid = p->p_pgrp->pg_id; 1432 ep->e_sid = ep->e_sess->s_sid; 1433 ep->e_jobc = p->p_pgrp->pg_jobc; 1434 if ((p->p_flag & P_CONTROLT) && 1435 (tp = ep->e_sess->s_ttyp)) { 1436 ep->e_tdev = tp->t_dev; 1437 ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 1438 ep->e_tsess = tp->t_session; 1439 } else 1440 ep->e_tdev = NODEV; 1441 if (p->p_wmesg) 1442 strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN); 1443 ep->e_xsize = ep->e_xrssize = 0; 1444 ep->e_xccount = ep->e_xswrss = 0; 1445 ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0; 1446 if (SESS_LEADER(p)) 1447 ep->e_flag |= EPROC_SLEADER; 1448 strncpy(ep->e_login, ep->e_sess->s_login, MAXLOGNAME); 1449 } 1450 1451 /* 1452 * Fill in an eproc structure for the specified process. 1453 */ 1454 static void 1455 fill_kproc2(p, ki) 1456 struct proc *p; 1457 struct kinfo_proc2 *ki; 1458 { 1459 struct tty *tp; 1460 1461 memset(ki, 0, sizeof(*ki)); 1462 1463 ki->p_forw = PTRTOINT64(p->p_forw); 1464 ki->p_back = PTRTOINT64(p->p_back); 1465 ki->p_paddr = PTRTOINT64(p); 1466 1467 ki->p_addr = PTRTOINT64(p->p_addr); 1468 ki->p_fd = PTRTOINT64(p->p_fd); 1469 ki->p_cwdi = PTRTOINT64(p->p_cwdi); 1470 ki->p_stats = PTRTOINT64(p->p_stats); 1471 ki->p_limit = PTRTOINT64(p->p_limit); 1472 ki->p_vmspace = PTRTOINT64(p->p_vmspace); 1473 ki->p_sigacts = PTRTOINT64(p->p_sigacts); 1474 ki->p_sess = PTRTOINT64(p->p_session); 1475 ki->p_tsess = 0; /* may be changed if controlling tty below */ 1476 ki->p_ru = PTRTOINT64(p->p_ru); 1477 1478 ki->p_eflag = 0; 1479 ki->p_exitsig = p->p_exitsig; 1480 ki->p_flag = p->p_flag; 1481 1482 ki->p_pid = p->p_pid; 1483 if (p->p_pptr) 1484 ki->p_ppid = p->p_pptr->p_pid; 1485 else 1486 ki->p_ppid = 0; 1487 ki->p_sid = p->p_session->s_sid; 1488 ki->p__pgid = p->p_pgrp->pg_id; 1489 1490 ki->p_tpgid = NO_PID; /* may be changed if controlling tty below */ 1491 1492 ki->p_uid = p->p_ucred->cr_uid; 1493 ki->p_ruid = p->p_cred->p_ruid; 1494 ki->p_gid = p->p_ucred->cr_gid; 1495 ki->p_rgid = p->p_cred->p_rgid; 1496 1497 memcpy(ki->p_groups, p->p_cred->pc_ucred->cr_groups, 1498 min(sizeof(ki->p_groups), sizeof(p->p_cred->pc_ucred->cr_groups))); 1499 ki->p_ngroups = p->p_cred->pc_ucred->cr_ngroups; 1500 1501 ki->p_jobc = p->p_pgrp->pg_jobc; 1502 if ((p->p_flag & P_CONTROLT) && (tp = p->p_session->s_ttyp)) { 1503 ki->p_tdev = tp->t_dev; 1504 ki->p_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 1505 ki->p_tsess = PTRTOINT64(tp->t_session); 1506 } else { 1507 ki->p_tdev = NODEV; 1508 } 1509 1510 ki->p_estcpu = p->p_estcpu; 1511 ki->p_rtime_sec = p->p_rtime.tv_sec; 1512 ki->p_rtime_usec = p->p_rtime.tv_usec; 1513 ki->p_cpticks = p->p_cpticks; 1514 ki->p_pctcpu = p->p_pctcpu; 1515 ki->p_swtime = p->p_swtime; 1516 ki->p_slptime = p->p_slptime; 1517 if (p->p_stat == SONPROC) { 1518 KDASSERT(p->p_cpu != NULL); 1519 ki->p_schedflags = p->p_cpu->ci_schedstate.spc_flags; 1520 } else 1521 ki->p_schedflags = 0; 1522 1523 ki->p_uticks = p->p_uticks; 1524 ki->p_sticks = p->p_sticks; 1525 ki->p_iticks = p->p_iticks; 1526 1527 ki->p_tracep = PTRTOINT64(p->p_tracep); 1528 ki->p_traceflag = p->p_traceflag; 1529 1530 ki->p_holdcnt = p->p_holdcnt; 1531 1532 memcpy(&ki->p_siglist, &p->p_siglist, sizeof(ki_sigset_t)); 1533 memcpy(&ki->p_sigmask, &p->p_sigmask, sizeof(ki_sigset_t)); 1534 memcpy(&ki->p_sigignore, &p->p_sigignore, sizeof(ki_sigset_t)); 1535 memcpy(&ki->p_sigcatch, &p->p_sigcatch, sizeof(ki_sigset_t)); 1536 1537 ki->p_stat = p->p_stat; 1538 ki->p_priority = p->p_priority; 1539 ki->p_usrpri = p->p_usrpri; 1540 ki->p_nice = p->p_nice; 1541 1542 ki->p_xstat = p->p_xstat; 1543 ki->p_acflag = p->p_acflag; 1544 1545 strncpy(ki->p_comm, p->p_comm, 1546 min(sizeof(ki->p_comm), sizeof(p->p_comm))); 1547 1548 if (p->p_wmesg) 1549 strncpy(ki->p_wmesg, p->p_wmesg, sizeof(ki->p_wmesg)); 1550 ki->p_wchan = PTRTOINT64(p->p_wchan); 1551 1552 strncpy(ki->p_login, p->p_session->s_login, sizeof(ki->p_login)); 1553 1554 if (p->p_stat == SIDL || P_ZOMBIE(p)) { 1555 ki->p_vm_rssize = 0; 1556 ki->p_vm_tsize = 0; 1557 ki->p_vm_dsize = 0; 1558 ki->p_vm_ssize = 0; 1559 } else { 1560 struct vmspace *vm = p->p_vmspace; 1561 1562 ki->p_vm_rssize = vm_resident_count(vm); 1563 ki->p_vm_tsize = vm->vm_tsize; 1564 ki->p_vm_dsize = vm->vm_dsize; 1565 ki->p_vm_ssize = vm->vm_ssize; 1566 } 1567 1568 if (p->p_session->s_ttyvp) 1569 ki->p_eflag |= EPROC_CTTY; 1570 if (SESS_LEADER(p)) 1571 ki->p_eflag |= EPROC_SLEADER; 1572 1573 /* XXX Is this double check necessary? */ 1574 if (P_ZOMBIE(p) || p->p_addr == NULL) { 1575 ki->p_uvalid = 0; 1576 } else { 1577 ki->p_uvalid = 1; 1578 1579 ki->p_ustart_sec = p->p_stats->p_start.tv_sec; 1580 ki->p_ustart_usec = p->p_stats->p_start.tv_usec; 1581 1582 ki->p_uutime_sec = p->p_stats->p_ru.ru_utime.tv_sec; 1583 ki->p_uutime_usec = p->p_stats->p_ru.ru_utime.tv_usec; 1584 ki->p_ustime_sec = p->p_stats->p_ru.ru_stime.tv_sec; 1585 ki->p_ustime_usec = p->p_stats->p_ru.ru_stime.tv_usec; 1586 1587 ki->p_uru_maxrss = p->p_stats->p_ru.ru_maxrss; 1588 ki->p_uru_ixrss = p->p_stats->p_ru.ru_ixrss; 1589 ki->p_uru_idrss = p->p_stats->p_ru.ru_idrss; 1590 ki->p_uru_isrss = p->p_stats->p_ru.ru_isrss; 1591 ki->p_uru_minflt = p->p_stats->p_ru.ru_minflt; 1592 ki->p_uru_majflt = p->p_stats->p_ru.ru_majflt; 1593 ki->p_uru_nswap = p->p_stats->p_ru.ru_nswap; 1594 ki->p_uru_inblock = p->p_stats->p_ru.ru_inblock; 1595 ki->p_uru_oublock = p->p_stats->p_ru.ru_oublock; 1596 ki->p_uru_msgsnd = p->p_stats->p_ru.ru_msgsnd; 1597 ki->p_uru_msgrcv = p->p_stats->p_ru.ru_msgrcv; 1598 ki->p_uru_nsignals = p->p_stats->p_ru.ru_nsignals; 1599 ki->p_uru_nvcsw = p->p_stats->p_ru.ru_nvcsw; 1600 ki->p_uru_nivcsw = p->p_stats->p_ru.ru_nivcsw; 1601 1602 ki->p_uctime_sec = p->p_stats->p_cru.ru_utime.tv_sec + 1603 p->p_stats->p_cru.ru_stime.tv_sec; 1604 ki->p_uctime_usec = p->p_stats->p_cru.ru_utime.tv_usec + 1605 p->p_stats->p_cru.ru_stime.tv_usec; 1606 } 1607 } 1608 1609 int 1610 sysctl_procargs(name, namelen, where, sizep, up) 1611 int *name; 1612 u_int namelen; 1613 void *where; 1614 size_t *sizep; 1615 struct proc *up; 1616 { 1617 struct ps_strings pss; 1618 struct proc *p; 1619 size_t len, upper_bound, xlen; 1620 struct uio auio; 1621 struct iovec aiov; 1622 vaddr_t argv; 1623 pid_t pid; 1624 int nargv, type, error, i; 1625 char *arg; 1626 char *tmp; 1627 1628 if (namelen != 2) 1629 return (EINVAL); 1630 pid = name[0]; 1631 type = name[1]; 1632 1633 switch (type) { 1634 case KERN_PROC_ARGV: 1635 case KERN_PROC_NARGV: 1636 case KERN_PROC_ENV: 1637 case KERN_PROC_NENV: 1638 /* ok */ 1639 break; 1640 default: 1641 return (EINVAL); 1642 } 1643 1644 /* check pid */ 1645 if ((p = pfind(pid)) == NULL) 1646 return (EINVAL); 1647 1648 /* only root or same user change look at the environment */ 1649 if (type == KERN_PROC_ENV || type == KERN_PROC_NENV) { 1650 if (up->p_ucred->cr_uid != 0) { 1651 if (up->p_cred->p_ruid != p->p_cred->p_ruid || 1652 up->p_cred->p_ruid != p->p_cred->p_svuid) 1653 return (EPERM); 1654 } 1655 } 1656 1657 if (sizep != NULL && where == NULL) { 1658 if (type == KERN_PROC_NARGV || type == KERN_PROC_NENV) 1659 *sizep = sizeof (int); 1660 else 1661 *sizep = ARG_MAX; /* XXX XXX XXX */ 1662 return (0); 1663 } 1664 if (where == NULL || sizep == NULL) 1665 return (EINVAL); 1666 1667 /* 1668 * Zombies don't have a stack, so we can't read their psstrings. 1669 * System processes also don't have a user stack. 1670 */ 1671 if (P_ZOMBIE(p) || (p->p_flag & P_SYSTEM) != 0) 1672 return (EINVAL); 1673 1674 /* 1675 * Lock the process down in memory. 1676 */ 1677 /* XXXCDC: how should locking work here? */ 1678 if ((p->p_flag & P_WEXIT) || (p->p_vmspace->vm_refcnt < 1)) 1679 return (EFAULT); 1680 PHOLD(p); 1681 p->p_vmspace->vm_refcnt++; /* XXX */ 1682 1683 /* 1684 * Allocate a temporary buffer to hold the arguments. 1685 */ 1686 arg = malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 1687 1688 /* 1689 * Read in the ps_strings structure. 1690 */ 1691 aiov.iov_base = &pss; 1692 aiov.iov_len = sizeof(pss); 1693 auio.uio_iov = &aiov; 1694 auio.uio_iovcnt = 1; 1695 auio.uio_offset = (vaddr_t)p->p_psstr; 1696 auio.uio_resid = sizeof(pss); 1697 auio.uio_segflg = UIO_SYSSPACE; 1698 auio.uio_rw = UIO_READ; 1699 auio.uio_procp = NULL; 1700 error = uvm_io(&p->p_vmspace->vm_map, &auio); 1701 if (error) 1702 goto done; 1703 1704 if (type == KERN_PROC_ARGV || type == KERN_PROC_NARGV) 1705 memcpy(&nargv, (char *)&pss + p->p_psnargv, sizeof(nargv)); 1706 else 1707 memcpy(&nargv, (char *)&pss + p->p_psnenv, sizeof(nargv)); 1708 if (type == KERN_PROC_NARGV || type == KERN_PROC_NENV) { 1709 error = copyout(&nargv, where, sizeof(nargv)); 1710 *sizep = sizeof(nargv); 1711 goto done; 1712 } 1713 /* 1714 * Now read the address of the argument vector. 1715 */ 1716 switch (type) { 1717 case KERN_PROC_ARGV: 1718 /* XXX compat32 stuff here */ 1719 memcpy(&tmp, (char *)&pss + p->p_psargv, sizeof(tmp)); 1720 break; 1721 case KERN_PROC_ENV: 1722 memcpy(&tmp, (char *)&pss + p->p_psenv, sizeof(tmp)); 1723 break; 1724 default: 1725 return (EINVAL); 1726 } 1727 auio.uio_offset = (off_t)(long)tmp; 1728 aiov.iov_base = &argv; 1729 aiov.iov_len = sizeof(argv); 1730 auio.uio_iov = &aiov; 1731 auio.uio_iovcnt = 1; 1732 auio.uio_resid = sizeof(argv); 1733 auio.uio_segflg = UIO_SYSSPACE; 1734 auio.uio_rw = UIO_READ; 1735 auio.uio_procp = NULL; 1736 error = uvm_io(&p->p_vmspace->vm_map, &auio); 1737 if (error) 1738 goto done; 1739 1740 /* 1741 * Now copy in the actual argument vector, one page at a time, 1742 * since we don't know how long the vector is (though, we do 1743 * know how many NUL-terminated strings are in the vector). 1744 */ 1745 len = 0; 1746 upper_bound = *sizep; 1747 for (; nargv != 0 && len < upper_bound; len += xlen) { 1748 aiov.iov_base = arg; 1749 aiov.iov_len = PAGE_SIZE; 1750 auio.uio_iov = &aiov; 1751 auio.uio_iovcnt = 1; 1752 auio.uio_offset = argv + len; 1753 xlen = PAGE_SIZE - ((argv + len) & PAGE_MASK); 1754 auio.uio_resid = xlen; 1755 auio.uio_segflg = UIO_SYSSPACE; 1756 auio.uio_rw = UIO_READ; 1757 auio.uio_procp = NULL; 1758 error = uvm_io(&p->p_vmspace->vm_map, &auio); 1759 if (error) 1760 goto done; 1761 1762 for (i = 0; i < xlen && nargv != 0; i++) { 1763 if (arg[i] == '\0') 1764 nargv--; /* one full string */ 1765 } 1766 1767 /* make sure we don't copyout past the end of the user's buffer */ 1768 if (len + i > upper_bound) 1769 i = upper_bound - len; 1770 1771 error = copyout(arg, (char *)where + len, i); 1772 if (error) 1773 break; 1774 1775 if (nargv == 0) { 1776 len += i; 1777 break; 1778 } 1779 } 1780 *sizep = len; 1781 1782 done: 1783 PRELE(p); 1784 uvmspace_free(p->p_vmspace); 1785 1786 free(arg, M_TEMP); 1787 return (error); 1788 } 1789