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