1 /* $OpenBSD: kern_prot.c,v 1.18 2001/06/22 23:55:24 art Exp $ */ 2 /* $NetBSD: kern_prot.c,v 1.33 1996/02/09 18:59:42 christos Exp $ */ 3 4 /* 5 * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993 6 * The Regents of the University of California. All rights reserved. 7 * (c) UNIX System Laboratories, Inc. 8 * All or some portions of this file are derived from material licensed 9 * to the University of California by American Telephone and Telegraph 10 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 11 * the permission of UNIX System Laboratories, Inc. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. All advertising materials mentioning features or use of this software 22 * must display the following acknowledgement: 23 * This product includes software developed by the University of 24 * California, Berkeley and its contributors. 25 * 4. Neither the name of the University nor the names of its contributors 26 * may be used to endorse or promote products derived from this software 27 * without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39 * SUCH DAMAGE. 40 * 41 * @(#)kern_prot.c 8.6 (Berkeley) 1/21/94 42 */ 43 44 /* 45 * System calls related to processes and protection 46 */ 47 48 #include <sys/param.h> 49 #include <sys/acct.h> 50 #include <sys/systm.h> 51 #include <sys/ucred.h> 52 #include <sys/proc.h> 53 #include <sys/timeb.h> 54 #include <sys/times.h> 55 #include <sys/malloc.h> 56 #include <sys/filedesc.h> 57 58 #include <sys/mount.h> 59 #include <sys/syscallargs.h> 60 61 /* ARGSUSED */ 62 int 63 sys_getpid(p, v, retval) 64 struct proc *p; 65 void *v; 66 register_t *retval; 67 { 68 69 *retval = p->p_pid; 70 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2) || \ 71 defined(COMPAT_FREEBSD) || defined(COMPAT_BSDOS) 72 retval[1] = p->p_pptr->p_pid; 73 #endif 74 return (0); 75 } 76 77 /* ARGSUSED */ 78 int 79 sys_getppid(p, v, retval) 80 struct proc *p; 81 void *v; 82 register_t *retval; 83 { 84 85 *retval = p->p_pptr->p_pid; 86 return (0); 87 } 88 89 /* Get process group ID; note that POSIX getpgrp takes no parameter */ 90 int 91 sys_getpgrp(p, v, retval) 92 struct proc *p; 93 void *v; 94 register_t *retval; 95 { 96 97 *retval = p->p_pgrp->pg_id; 98 return (0); 99 } 100 101 /* 102 * SysVR.4 compatible getpgid() 103 */ 104 pid_t 105 sys_getpgid(curp, v, retval) 106 struct proc *curp; 107 void *v; 108 register_t *retval; 109 { 110 struct sys_getpgid_args /* { 111 syscallarg(pid_t) pid; 112 } */ *uap = v; 113 struct proc *targp = curp; 114 115 if (SCARG(uap, pid) == 0 || SCARG(uap, pid) == curp->p_pid) 116 goto found; 117 if ((targp = pfind(SCARG(uap, pid))) == NULL) 118 return (ESRCH); 119 if (targp->p_session != curp->p_session) 120 return (EPERM); 121 found: 122 *retval = targp->p_pgid; 123 return (0); 124 } 125 126 pid_t 127 sys_getsid(curp, v, retval) 128 struct proc *curp; 129 void *v; 130 register_t *retval; 131 { 132 struct sys_getsid_args /* { 133 syscallarg(pid_t) pid; 134 } */ *uap = v; 135 struct proc *targp = curp; 136 137 if (SCARG(uap, pid) == 0 || SCARG(uap, pid) == curp->p_pid) 138 goto found; 139 if ((targp = pfind(SCARG(uap, pid))) == NULL) 140 return (ESRCH); 141 if (targp->p_session != curp->p_session) 142 return (EPERM); 143 found: 144 /* Skip exiting processes */ 145 if (targp->p_pgrp->pg_session->s_leader == NULL) 146 return (ESRCH); 147 *retval = targp->p_pgrp->pg_session->s_leader->p_pid; 148 return (0); 149 } 150 151 /* ARGSUSED */ 152 int 153 sys_getuid(p, v, retval) 154 struct proc *p; 155 void *v; 156 register_t *retval; 157 { 158 159 *retval = p->p_cred->p_ruid; 160 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2) || \ 161 defined(COMPAT_FREEBSD) || defined(COMPAT_BSDOS) 162 retval[1] = p->p_ucred->cr_uid; 163 #endif 164 return (0); 165 } 166 167 /* ARGSUSED */ 168 int 169 sys_geteuid(p, v, retval) 170 struct proc *p; 171 void *v; 172 register_t *retval; 173 { 174 175 *retval = p->p_ucred->cr_uid; 176 return (0); 177 } 178 179 /* ARGSUSED */ 180 int 181 sys_issetugid(p, v, retval) 182 struct proc *p; 183 void *v; 184 register_t *retval; 185 { 186 if (p->p_flag & P_SUGIDEXEC) 187 *retval = 1; 188 else 189 *retval = 0; 190 return (0); 191 } 192 193 /* ARGSUSED */ 194 int 195 sys_getgid(p, v, retval) 196 struct proc *p; 197 void *v; 198 register_t *retval; 199 { 200 201 *retval = p->p_cred->p_rgid; 202 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_FREEBSD) || defined(COMPAT_BSDOS) 203 retval[1] = p->p_ucred->cr_gid; 204 #endif 205 return (0); 206 } 207 208 /* 209 * Get effective group ID. The "egid" is groups[0], and could be obtained 210 * via getgroups. This syscall exists because it is somewhat painful to do 211 * correctly in a library function. 212 */ 213 /* ARGSUSED */ 214 int 215 sys_getegid(p, v, retval) 216 struct proc *p; 217 void *v; 218 register_t *retval; 219 { 220 221 *retval = p->p_ucred->cr_gid; 222 return (0); 223 } 224 225 int 226 sys_getgroups(p, v, retval) 227 struct proc *p; 228 void *v; 229 register_t *retval; 230 { 231 struct sys_getgroups_args /* { 232 syscallarg(u_int) gidsetsize; 233 syscallarg(gid_t *) gidset; 234 } */ *uap = v; 235 struct pcred *pc = p->p_cred; 236 u_int ngrp; 237 int error; 238 239 if ((ngrp = SCARG(uap, gidsetsize)) == 0) { 240 *retval = pc->pc_ucred->cr_ngroups; 241 return (0); 242 } 243 if (ngrp < pc->pc_ucred->cr_ngroups) 244 return (EINVAL); 245 ngrp = pc->pc_ucred->cr_ngroups; 246 error = copyout((caddr_t)pc->pc_ucred->cr_groups, 247 (caddr_t)SCARG(uap, gidset), ngrp * sizeof(gid_t)); 248 if (error) 249 return (error); 250 *retval = ngrp; 251 return (0); 252 } 253 254 /* ARGSUSED */ 255 int 256 sys_setsid(p, v, retval) 257 struct proc *p; 258 void *v; 259 register_t *retval; 260 { 261 262 if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 263 return (EPERM); 264 } else { 265 (void)enterpgrp(p, p->p_pid, 1); 266 *retval = p->p_pid; 267 return (0); 268 } 269 } 270 271 /* 272 * set process group (setpgid/old setpgrp) 273 * 274 * caller does setpgid(targpid, targpgid) 275 * 276 * pid must be caller or child of caller (ESRCH) 277 * if a child 278 * pid must be in same session (EPERM) 279 * pid can't have done an exec (EACCES) 280 * if pgid != pid 281 * there must exist some pid in same session having pgid (EPERM) 282 * pid must not be session leader (EPERM) 283 */ 284 /* ARGSUSED */ 285 int 286 sys_setpgid(curp, v, retval) 287 struct proc *curp; 288 void *v; 289 register_t *retval; 290 { 291 struct sys_setpgid_args /* { 292 syscallarg(pid_t) pid; 293 syscallarg(int) pgid; 294 } */ *uap = v; 295 struct proc *targp; /* target process */ 296 struct pgrp *pgrp; /* target pgrp */ 297 pid_t pid; 298 int pgid; 299 300 pid = SCARG(uap, pid); 301 pgid = SCARG(uap, pgid); 302 303 if (pgid < 0) 304 return (EINVAL); 305 306 if (pid != 0 && pid != curp->p_pid) { 307 if ((targp = pfind(pid)) == 0 || !inferior(targp)) 308 return (ESRCH); 309 if (targp->p_session != curp->p_session) 310 return (EPERM); 311 if (targp->p_flag & P_EXEC) 312 return (EACCES); 313 } else 314 targp = curp; 315 if (SESS_LEADER(targp)) 316 return (EPERM); 317 if (pgid == 0) 318 pgid = targp->p_pid; 319 else if (pgid != targp->p_pid) 320 if ((pgrp = pgfind(pgid)) == 0 || 321 pgrp->pg_session != curp->p_session) 322 return (EPERM); 323 return (enterpgrp(targp, pgid, 0)); 324 } 325 326 /* ARGSUSED */ 327 int 328 sys_setuid(p, v, retval) 329 struct proc *p; 330 void *v; 331 register_t *retval; 332 { 333 struct sys_setuid_args /* { 334 syscallarg(uid_t) uid; 335 } */ *uap = v; 336 struct pcred *pc = p->p_cred; 337 uid_t uid; 338 int error; 339 340 uid = SCARG(uap, uid); 341 342 if (pc->pc_ucred->cr_uid == uid && 343 pc->p_ruid == uid && 344 pc->p_svuid == uid) 345 return (0); 346 347 if (uid != pc->p_ruid && 348 uid != pc->p_svuid && 349 uid != pc->pc_ucred->cr_uid && 350 (error = suser(pc->pc_ucred, &p->p_acflag))) 351 return (error); 352 353 /* 354 * Everything's okay, do it. 355 */ 356 if (uid == pc->pc_ucred->cr_uid || 357 suser(pc->pc_ucred, &p->p_acflag) == 0) { 358 /* 359 * Transfer proc count to new user. 360 */ 361 if (uid != pc->p_ruid) { 362 (void)chgproccnt(pc->p_ruid, -1); 363 (void)chgproccnt(uid, 1); 364 } 365 pc->p_ruid = uid; 366 pc->p_svuid = uid; 367 } 368 369 /* 370 * Copy credentials so other references do not see our changes. 371 */ 372 pc->pc_ucred = crcopy(pc->pc_ucred); 373 pc->pc_ucred->cr_uid = uid; 374 p->p_flag |= P_SUGID; 375 return (0); 376 } 377 378 /* ARGSUSED */ 379 int 380 sys_seteuid(p, v, retval) 381 struct proc *p; 382 void *v; 383 register_t *retval; 384 { 385 struct sys_seteuid_args /* { 386 syscallarg(uid_t) euid; 387 } */ *uap = v; 388 struct pcred *pc = p->p_cred; 389 uid_t euid; 390 int error; 391 392 euid = SCARG(uap, euid); 393 394 if (pc->pc_ucred->cr_uid == euid) 395 return (0); 396 397 if (euid != pc->p_ruid && euid != pc->p_svuid && 398 (error = suser(pc->pc_ucred, &p->p_acflag))) 399 return (error); 400 401 /* 402 * Copy credentials so other references do not see our changes. 403 */ 404 pc->pc_ucred = crcopy(pc->pc_ucred); 405 pc->pc_ucred->cr_uid = euid; 406 p->p_flag |= P_SUGID; 407 return (0); 408 } 409 410 /* ARGSUSED */ 411 int 412 sys_setgid(p, v, retval) 413 struct proc *p; 414 void *v; 415 register_t *retval; 416 { 417 struct sys_setgid_args /* { 418 syscallarg(gid_t) gid; 419 } */ *uap = v; 420 struct pcred *pc = p->p_cred; 421 gid_t gid; 422 int error; 423 424 gid = SCARG(uap, gid); 425 426 if (pc->pc_ucred->cr_gid == gid && 427 pc->p_rgid == gid && 428 pc->p_svgid == gid) 429 return (0); 430 431 if (gid != pc->p_rgid && 432 gid != pc->p_svgid && 433 gid != pc->pc_ucred->cr_gid && 434 (error = suser(pc->pc_ucred, &p->p_acflag))) 435 return (error); 436 437 if (gid == pc->pc_ucred->cr_gid || 438 suser(pc->pc_ucred, &p->p_acflag) == 0) { 439 pc->p_rgid = gid; 440 pc->p_svgid = gid; 441 } 442 443 /* 444 * Copy credentials so other references do not see our changes. 445 */ 446 pc->pc_ucred = crcopy(pc->pc_ucred); 447 pc->pc_ucred->cr_gid = gid; 448 p->p_flag |= P_SUGID; 449 return (0); 450 } 451 452 /* ARGSUSED */ 453 int 454 sys_setegid(p, v, retval) 455 struct proc *p; 456 void *v; 457 register_t *retval; 458 { 459 struct sys_setegid_args /* { 460 syscallarg(gid_t) egid; 461 } */ *uap = v; 462 struct pcred *pc = p->p_cred; 463 gid_t egid; 464 int error; 465 466 egid = SCARG(uap, egid); 467 468 if (pc->pc_ucred->cr_gid == egid) 469 return (0); 470 471 if (egid != pc->p_rgid && egid != pc->p_svgid && 472 (error = suser(pc->pc_ucred, &p->p_acflag))) 473 return (error); 474 475 /* 476 * Copy credentials so other references do not see our changes. 477 */ 478 pc->pc_ucred = crcopy(pc->pc_ucred); 479 pc->pc_ucred->cr_gid = egid; 480 p->p_flag |= P_SUGID; 481 return (0); 482 } 483 484 /* ARGSUSED */ 485 int 486 sys_setgroups(p, v, retval) 487 struct proc *p; 488 void *v; 489 register_t *retval; 490 { 491 struct sys_setgroups_args /* { 492 syscallarg(u_int) gidsetsize; 493 syscallarg(gid_t *) gidset; 494 } */ *uap = v; 495 struct pcred *pc = p->p_cred; 496 u_int ngrp; 497 int error; 498 499 if ((error = suser(pc->pc_ucred, &p->p_acflag)) != 0) 500 return (error); 501 ngrp = SCARG(uap, gidsetsize); 502 if (ngrp > NGROUPS) 503 return (EINVAL); 504 pc->pc_ucred = crcopy(pc->pc_ucred); 505 error = copyin((caddr_t)SCARG(uap, gidset), 506 (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t)); 507 if (error) 508 return (error); 509 pc->pc_ucred->cr_ngroups = ngrp; 510 p->p_flag |= P_SUGID; 511 return (0); 512 } 513 514 /* 515 * Check if gid is a member of the group set. 516 */ 517 int 518 groupmember(gid, cred) 519 gid_t gid; 520 struct ucred *cred; 521 { 522 gid_t *gp; 523 gid_t *egp; 524 525 egp = &(cred->cr_groups[cred->cr_ngroups]); 526 for (gp = cred->cr_groups; gp < egp; gp++) 527 if (*gp == gid) 528 return (1); 529 return (0); 530 } 531 532 /* 533 * Test whether the specified credentials imply "super-user" 534 * privilege; if so, and we have accounting info, set the flag 535 * indicating use of super-powers. 536 * Returns 0 or error. 537 */ 538 int 539 suser(cred, acflag) 540 struct ucred *cred; 541 u_short *acflag; 542 { 543 if (cred->cr_uid == 0) { 544 if (acflag) 545 *acflag |= ASU; 546 return (0); 547 } 548 return (EPERM); 549 } 550 551 /* 552 * Allocate a zeroed cred structure. 553 */ 554 struct ucred * 555 crget() 556 { 557 struct ucred *cr; 558 559 MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 560 bzero((caddr_t)cr, sizeof(*cr)); 561 cr->cr_ref = 1; 562 return (cr); 563 } 564 565 /* 566 * Free a cred structure. 567 * Throws away space when ref count gets to 0. 568 */ 569 void 570 crfree(cr) 571 struct ucred *cr; 572 { 573 int s; 574 575 s = splimp(); /* ??? */ 576 if (--cr->cr_ref == 0) 577 FREE((caddr_t)cr, M_CRED); 578 (void) splx(s); 579 } 580 581 /* 582 * Copy cred structure to a new one and free the old one. 583 */ 584 struct ucred * 585 crcopy(cr) 586 struct ucred *cr; 587 { 588 struct ucred *newcr; 589 590 if (cr->cr_ref == 1) 591 return (cr); 592 newcr = crget(); 593 *newcr = *cr; 594 crfree(cr); 595 newcr->cr_ref = 1; 596 return (newcr); 597 } 598 599 /* 600 * Dup cred struct to a new held one. 601 */ 602 struct ucred * 603 crdup(cr) 604 struct ucred *cr; 605 { 606 struct ucred *newcr; 607 608 newcr = crget(); 609 *newcr = *cr; 610 newcr->cr_ref = 1; 611 return (newcr); 612 } 613 614 /* 615 * Get login name, if available. 616 */ 617 /* ARGSUSED */ 618 int 619 sys_getlogin(p, v, retval) 620 struct proc *p; 621 void *v; 622 register_t *retval; 623 { 624 struct sys_getlogin_args /* { 625 syscallarg(char *) namebuf; 626 syscallarg(u_int) namelen; 627 } */ *uap = v; 628 629 if (SCARG(uap, namelen) > sizeof (p->p_pgrp->pg_session->s_login)) 630 SCARG(uap, namelen) = sizeof (p->p_pgrp->pg_session->s_login); 631 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 632 (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen))); 633 } 634 635 /* 636 * Set login name. 637 */ 638 /* ARGSUSED */ 639 int 640 sys_setlogin(p, v, retval) 641 struct proc *p; 642 void *v; 643 register_t *retval; 644 { 645 struct sys_setlogin_args /* { 646 syscallarg(char *) namebuf; 647 } */ *uap = v; 648 int error; 649 650 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 651 return (error); 652 error = copyinstr((caddr_t) SCARG(uap, namebuf), 653 (caddr_t) p->p_pgrp->pg_session->s_login, 654 sizeof (p->p_pgrp->pg_session->s_login), (size_t *)0); 655 if (error == ENAMETOOLONG) 656 error = EINVAL; 657 return (error); 658 } 659 660 /* 661 * Check if a process is allowed to raise its privileges. 662 */ 663 int 664 proc_cansugid(struct proc *p) 665 { 666 /* ptrace(2)d processes shouldn't. */ 667 if ((p->p_flag & P_TRACED) != 0) 668 return (0); 669 670 /* proceses with shared filedescriptors shouldn't. */ 671 if (p->p_fd->fd_refcnt > 1) 672 return (0); 673 674 /* Allow. */ 675 return (1); 676 } 677