1 /* $OpenBSD: kern_prot.c,v 1.12 1997/11/17 05:57:45 deraadt 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 57 #include <sys/mount.h> 58 #include <sys/syscallargs.h> 59 60 /* ARGSUSED */ 61 int 62 sys_getpid(p, v, retval) 63 struct proc *p; 64 void *v; 65 register_t *retval; 66 { 67 68 *retval = p->p_pid; 69 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2) || \ 70 defined(COMPAT_FREEBSD) || defined(COMPAT_BSDOS) 71 retval[1] = p->p_pptr->p_pid; 72 #endif 73 return (0); 74 } 75 76 /* ARGSUSED */ 77 int 78 sys_getppid(p, v, retval) 79 struct proc *p; 80 void *v; 81 register_t *retval; 82 { 83 84 *retval = p->p_pptr->p_pid; 85 return (0); 86 } 87 88 /* Get process group ID; note that POSIX getpgrp takes no parameter */ 89 int 90 sys_getpgrp(p, v, retval) 91 struct proc *p; 92 void *v; 93 register_t *retval; 94 { 95 96 *retval = p->p_pgrp->pg_id; 97 return (0); 98 } 99 100 /* 101 * SysVR.4 compatible getpgid() 102 */ 103 int 104 sys_getpgid(p, v, retval) 105 struct proc *p; 106 void *v; 107 register_t *retval; 108 { 109 register struct sys_getpgid_args /* { 110 syscallarg(pid_t) pid; 111 } */ *uap = v; 112 113 if (SCARG(uap, pid) == 0) 114 goto found; 115 if ((p = pfind(SCARG(uap, pid))) == 0) 116 return (ESRCH); 117 found: 118 *retval = p->p_pgid; 119 return 0; 120 } 121 122 int 123 sys_getsid(p, v, retval) 124 struct proc *p; 125 void *v; 126 register_t *retval; 127 { 128 register struct sys_getsid_args /* { 129 syscallarg(pid_t) pid; 130 } */ *uap = v; 131 132 if (SCARG(uap, pid) == 0) 133 goto found; 134 if ((p == pfind(SCARG(uap, pid))) == 0) 135 return (ESRCH); 136 found: 137 *retval = p->p_pgrp->pg_session->s_leader->p_pid; 138 return 0; 139 } 140 141 /* ARGSUSED */ 142 int 143 sys_getuid(p, v, retval) 144 struct proc *p; 145 void *v; 146 register_t *retval; 147 { 148 149 *retval = p->p_cred->p_ruid; 150 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2) || \ 151 defined(COMPAT_FREEBSD) || defined(COMPAT_BSDOS) 152 retval[1] = p->p_ucred->cr_uid; 153 #endif 154 return (0); 155 } 156 157 /* ARGSUSED */ 158 int 159 sys_geteuid(p, v, retval) 160 struct proc *p; 161 void *v; 162 register_t *retval; 163 { 164 165 *retval = p->p_ucred->cr_uid; 166 return (0); 167 } 168 169 /* ARGSUSED */ 170 int 171 sys_issetugid(p, v, retval) 172 struct proc *p; 173 void *v; 174 register_t *retval; 175 { 176 if (p->p_flag & P_SUGIDEXEC) 177 *retval = 1; 178 else 179 *retval = 0; 180 return (0); 181 } 182 183 /* ARGSUSED */ 184 int 185 sys_getgid(p, v, retval) 186 struct proc *p; 187 void *v; 188 register_t *retval; 189 { 190 191 *retval = p->p_cred->p_rgid; 192 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_FREEBSD) || defined(COMPAT_BSDOS) 193 retval[1] = p->p_ucred->cr_gid; 194 #endif 195 return (0); 196 } 197 198 /* 199 * Get effective group ID. The "egid" is groups[0], and could be obtained 200 * via getgroups. This syscall exists because it is somewhat painful to do 201 * correctly in a library function. 202 */ 203 /* ARGSUSED */ 204 int 205 sys_getegid(p, v, retval) 206 struct proc *p; 207 void *v; 208 register_t *retval; 209 { 210 211 *retval = p->p_ucred->cr_gid; 212 return (0); 213 } 214 215 int 216 sys_getgroups(p, v, retval) 217 struct proc *p; 218 void *v; 219 register_t *retval; 220 { 221 register struct sys_getgroups_args /* { 222 syscallarg(u_int) gidsetsize; 223 syscallarg(gid_t *) gidset; 224 } */ *uap = v; 225 register struct pcred *pc = p->p_cred; 226 register u_int ngrp; 227 int error; 228 229 if ((ngrp = SCARG(uap, gidsetsize)) == 0) { 230 *retval = pc->pc_ucred->cr_ngroups; 231 return (0); 232 } 233 if (ngrp < pc->pc_ucred->cr_ngroups) 234 return (EINVAL); 235 ngrp = pc->pc_ucred->cr_ngroups; 236 error = copyout((caddr_t)pc->pc_ucred->cr_groups, 237 (caddr_t)SCARG(uap, gidset), ngrp * sizeof(gid_t)); 238 if (error) 239 return (error); 240 *retval = ngrp; 241 return (0); 242 } 243 244 /* ARGSUSED */ 245 int 246 sys_setsid(p, v, retval) 247 register struct proc *p; 248 void *v; 249 register_t *retval; 250 { 251 252 if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 253 return (EPERM); 254 } else { 255 (void)enterpgrp(p, p->p_pid, 1); 256 *retval = p->p_pid; 257 return (0); 258 } 259 } 260 261 /* 262 * set process group (setpgid/old setpgrp) 263 * 264 * caller does setpgid(targpid, targpgid) 265 * 266 * pid must be caller or child of caller (ESRCH) 267 * if a child 268 * pid must be in same session (EPERM) 269 * pid can't have done an exec (EACCES) 270 * if pgid != pid 271 * there must exist some pid in same session having pgid (EPERM) 272 * pid must not be session leader (EPERM) 273 */ 274 /* ARGSUSED */ 275 int 276 sys_setpgid(curp, v, retval) 277 struct proc *curp; 278 void *v; 279 register_t *retval; 280 { 281 register struct sys_setpgid_args /* { 282 syscallarg(int) pid; 283 syscallarg(int) pgid; 284 } */ *uap = v; 285 register struct proc *targp; /* target process */ 286 register struct pgrp *pgrp; /* target pgrp */ 287 288 #ifdef COMPAT_09 289 SCARG(uap, pid) = (short) SCARG(uap, pid); /* XXX */ 290 SCARG(uap, pgid) = (short) SCARG(uap, pgid); /* XXX */ 291 #endif 292 293 if (SCARG(uap, pgid) < 0) 294 return (EINVAL); 295 296 if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != curp->p_pid) { 297 if ((targp = pfind(SCARG(uap, pid))) == 0 || !inferior(targp)) 298 return (ESRCH); 299 if (targp->p_session != curp->p_session) 300 return (EPERM); 301 if (targp->p_flag & P_EXEC) 302 return (EACCES); 303 } else 304 targp = curp; 305 if (SESS_LEADER(targp)) 306 return (EPERM); 307 if (SCARG(uap, pgid) == 0) 308 SCARG(uap, pgid) = targp->p_pid; 309 else if (SCARG(uap, pgid) != targp->p_pid) 310 if ((pgrp = pgfind(SCARG(uap, pgid))) == 0 || 311 pgrp->pg_session != curp->p_session) 312 return (EPERM); 313 return (enterpgrp(targp, SCARG(uap, pgid), 0)); 314 } 315 316 /* ARGSUSED */ 317 int 318 sys_setuid(p, v, retval) 319 struct proc *p; 320 void *v; 321 register_t *retval; 322 { 323 struct sys_setuid_args /* { 324 syscallarg(uid_t) uid; 325 } */ *uap = v; 326 register struct pcred *pc = p->p_cred; 327 register uid_t uid; 328 int error; 329 330 #ifdef COMPAT_09 /* XXX */ 331 uid = (u_short)SCARG(uap, uid); 332 #else 333 uid = SCARG(uap, uid); 334 #endif 335 if (uid != pc->p_ruid && 336 uid != pc->p_svuid && 337 uid != pc->pc_ucred->cr_uid && 338 (error = suser(pc->pc_ucred, &p->p_acflag))) 339 return (error); 340 /* 341 * Everything's okay, do it. 342 */ 343 if (uid == pc->pc_ucred->cr_uid || 344 suser(pc->pc_ucred, &p->p_acflag) == 0) { 345 /* 346 * Transfer proc count to new user. 347 */ 348 if (uid != pc->p_ruid) { 349 (void)chgproccnt(pc->p_ruid, -1); 350 (void)chgproccnt(uid, 1); 351 } 352 pc->p_ruid = uid; 353 pc->p_svuid = uid; 354 } 355 /* 356 * Copy credentials so other references do not see our changes. 357 */ 358 pc->pc_ucred = crcopy(pc->pc_ucred); 359 pc->pc_ucred->cr_uid = uid; 360 p->p_flag |= P_SUGID; 361 return (0); 362 } 363 364 /* ARGSUSED */ 365 int 366 sys_seteuid(p, v, retval) 367 struct proc *p; 368 void *v; 369 register_t *retval; 370 { 371 struct sys_seteuid_args /* { 372 syscallarg(uid_t) euid; 373 } */ *uap = v; 374 register struct pcred *pc = p->p_cred; 375 register uid_t euid; 376 int error; 377 378 #ifdef COMPAT_09 /* XXX */ 379 euid = (u_short)SCARG(uap, euid); 380 #else 381 euid = SCARG(uap, euid); 382 #endif 383 if (euid != pc->p_ruid && euid != pc->p_svuid && 384 (error = suser(pc->pc_ucred, &p->p_acflag))) 385 return (error); 386 /* 387 * Everything's okay, do it. Copy credentials so other references do 388 * not see our changes. 389 */ 390 pc->pc_ucred = crcopy(pc->pc_ucred); 391 pc->pc_ucred->cr_uid = euid; 392 p->p_flag |= P_SUGID; 393 return (0); 394 } 395 396 /* ARGSUSED */ 397 int 398 sys_setgid(p, v, retval) 399 struct proc *p; 400 void *v; 401 register_t *retval; 402 { 403 struct sys_setgid_args /* { 404 syscallarg(gid_t) gid; 405 } */ *uap = v; 406 register struct pcred *pc = p->p_cred; 407 register gid_t gid; 408 int error; 409 410 #ifdef COMPAT_09 /* XXX */ 411 gid = (u_short)SCARG(uap, gid); 412 #else 413 gid = SCARG(uap, gid); 414 #endif 415 if (gid != pc->p_rgid && 416 gid != pc->p_svgid && 417 gid != pc->pc_ucred->cr_gid && 418 (error = suser(pc->pc_ucred, &p->p_acflag))) 419 return (error); 420 if (gid == pc->pc_ucred->cr_gid || 421 suser(pc->pc_ucred, &p->p_acflag) == 0) { 422 pc->p_rgid = gid; 423 pc->p_svgid = gid; 424 } 425 pc->pc_ucred = crcopy(pc->pc_ucred); 426 pc->pc_ucred->cr_gid = gid; 427 p->p_flag |= P_SUGID; 428 return (0); 429 } 430 431 /* ARGSUSED */ 432 int 433 sys_setegid(p, v, retval) 434 struct proc *p; 435 void *v; 436 register_t *retval; 437 { 438 struct sys_setegid_args /* { 439 syscallarg(gid_t) egid; 440 } */ *uap = v; 441 register struct pcred *pc = p->p_cred; 442 register gid_t egid; 443 int error; 444 445 #ifdef COMPAT_09 /* XXX */ 446 egid = (u_short)SCARG(uap, egid); 447 #else 448 egid = SCARG(uap, egid); 449 #endif 450 if (egid != pc->p_rgid && egid != pc->p_svgid && 451 (error = suser(pc->pc_ucred, &p->p_acflag))) 452 return (error); 453 pc->pc_ucred = crcopy(pc->pc_ucred); 454 pc->pc_ucred->cr_gid = egid; 455 p->p_flag |= P_SUGID; 456 return (0); 457 } 458 459 /* ARGSUSED */ 460 int 461 sys_setgroups(p, v, retval) 462 struct proc *p; 463 void *v; 464 register_t *retval; 465 { 466 struct sys_setgroups_args /* { 467 syscallarg(u_int) gidsetsize; 468 syscallarg(gid_t *) gidset; 469 } */ *uap = v; 470 register struct pcred *pc = p->p_cred; 471 register u_int ngrp; 472 int error; 473 474 if ((error = suser(pc->pc_ucred, &p->p_acflag)) != 0) 475 return (error); 476 ngrp = SCARG(uap, gidsetsize); 477 if (ngrp > NGROUPS) 478 return (EINVAL); 479 pc->pc_ucred = crcopy(pc->pc_ucred); 480 error = copyin((caddr_t)SCARG(uap, gidset), 481 (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t)); 482 if (error) 483 return (error); 484 pc->pc_ucred->cr_ngroups = ngrp; 485 p->p_flag |= P_SUGID; 486 return (0); 487 } 488 489 /* 490 * Check if gid is a member of the group set. 491 */ 492 int 493 groupmember(gid, cred) 494 gid_t gid; 495 register struct ucred *cred; 496 { 497 register gid_t *gp; 498 gid_t *egp; 499 500 egp = &(cred->cr_groups[cred->cr_ngroups]); 501 for (gp = cred->cr_groups; gp < egp; gp++) 502 if (*gp == gid) 503 return (1); 504 return (0); 505 } 506 507 /* 508 * Test whether the specified credentials imply "super-user" 509 * privilege; if so, and we have accounting info, set the flag 510 * indicating use of super-powers. 511 * Returns 0 or error. 512 */ 513 int 514 suser(cred, acflag) 515 struct ucred *cred; 516 u_short *acflag; 517 { 518 if (cred->cr_uid == 0) { 519 if (acflag) 520 *acflag |= ASU; 521 return (0); 522 } 523 return (EPERM); 524 } 525 526 /* 527 * Allocate a zeroed cred structure. 528 */ 529 struct ucred * 530 crget() 531 { 532 register struct ucred *cr; 533 534 MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 535 bzero((caddr_t)cr, sizeof(*cr)); 536 cr->cr_ref = 1; 537 return (cr); 538 } 539 540 /* 541 * Free a cred structure. 542 * Throws away space when ref count gets to 0. 543 */ 544 void 545 crfree(cr) 546 struct ucred *cr; 547 { 548 int s; 549 550 s = splimp(); /* ??? */ 551 if (--cr->cr_ref == 0) 552 FREE((caddr_t)cr, M_CRED); 553 (void) splx(s); 554 } 555 556 /* 557 * Copy cred structure to a new one and free the old one. 558 */ 559 struct ucred * 560 crcopy(cr) 561 struct ucred *cr; 562 { 563 struct ucred *newcr; 564 565 if (cr->cr_ref == 1) 566 return (cr); 567 newcr = crget(); 568 *newcr = *cr; 569 crfree(cr); 570 newcr->cr_ref = 1; 571 return (newcr); 572 } 573 574 /* 575 * Dup cred struct to a new held one. 576 */ 577 struct ucred * 578 crdup(cr) 579 struct ucred *cr; 580 { 581 struct ucred *newcr; 582 583 newcr = crget(); 584 *newcr = *cr; 585 newcr->cr_ref = 1; 586 return (newcr); 587 } 588 589 /* 590 * Get login name, if available. 591 */ 592 /* ARGSUSED */ 593 int 594 sys_getlogin(p, v, retval) 595 struct proc *p; 596 void *v; 597 register_t *retval; 598 { 599 struct sys_getlogin_args /* { 600 syscallarg(char *) namebuf; 601 syscallarg(u_int) namelen; 602 } */ *uap = v; 603 604 if (SCARG(uap, namelen) > sizeof (p->p_pgrp->pg_session->s_login)) 605 SCARG(uap, namelen) = sizeof (p->p_pgrp->pg_session->s_login); 606 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 607 (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen))); 608 } 609 610 /* 611 * Set login name. 612 */ 613 /* ARGSUSED */ 614 int 615 sys_setlogin(p, v, retval) 616 struct proc *p; 617 void *v; 618 register_t *retval; 619 { 620 struct sys_setlogin_args /* { 621 syscallarg(char *) namebuf; 622 } */ *uap = v; 623 int error; 624 625 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 626 return (error); 627 error = copyinstr((caddr_t) SCARG(uap, namebuf), 628 (caddr_t) p->p_pgrp->pg_session->s_login, 629 sizeof (p->p_pgrp->pg_session->s_login), (size_t *)0); 630 if (error == ENAMETOOLONG) 631 error = EINVAL; 632 return (error); 633 } 634