1 /* $OpenBSD: kern_prot.c,v 1.83 2024/10/08 09:05:40 claudio 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. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * @(#)kern_prot.c 8.6 (Berkeley) 1/21/94 38 */ 39 40 /* 41 * System calls related to processes and protection 42 */ 43 44 #include <sys/param.h> 45 #include <sys/atomic.h> 46 #include <sys/systm.h> 47 #include <sys/ucred.h> 48 #include <sys/proc.h> 49 #include <sys/filedesc.h> 50 #include <sys/pool.h> 51 52 #include <sys/mount.h> 53 #include <sys/syscallargs.h> 54 #include <machine/tcb.h> 55 56 inline void 57 crset(struct ucred *newcr, const struct ucred *cr) 58 { 59 KASSERT(cr->cr_refcnt.r_refs > 0); 60 memcpy( 61 (char *)newcr + offsetof(struct ucred, cr_startcopy), 62 (const char *)cr + offsetof(struct ucred, cr_startcopy), 63 sizeof(*cr) - offsetof(struct ucred, cr_startcopy)); 64 } 65 66 int 67 sys_getpid(struct proc *p, void *v, register_t *retval) 68 { 69 70 *retval = p->p_p->ps_pid; 71 return (0); 72 } 73 74 int 75 sys_getthrid(struct proc *p, void *v, register_t *retval) 76 { 77 78 *retval = p->p_tid + THREAD_PID_OFFSET; 79 return (0); 80 } 81 82 int 83 sys_getppid(struct proc *p, void *v, register_t *retval) 84 { 85 86 mtx_enter(&p->p_p->ps_mtx); 87 *retval = p->p_p->ps_ppid; 88 mtx_leave(&p->p_p->ps_mtx); 89 return (0); 90 } 91 92 /* Get process group ID; note that POSIX getpgrp takes no parameter */ 93 int 94 sys_getpgrp(struct proc *p, void *v, register_t *retval) 95 { 96 97 *retval = p->p_p->ps_pgrp->pg_id; 98 return (0); 99 } 100 101 /* 102 * SysVR.4 compatible getpgid() 103 */ 104 int 105 sys_getpgid(struct proc *curp, void *v, register_t *retval) 106 { 107 struct sys_getpgid_args /* { 108 syscallarg(pid_t) pid; 109 } */ *uap = v; 110 struct process *targpr = curp->p_p; 111 112 if (SCARG(uap, pid) == 0 || SCARG(uap, pid) == targpr->ps_pid) 113 goto found; 114 if ((targpr = prfind(SCARG(uap, pid))) == NULL) 115 return (ESRCH); 116 if (targpr->ps_session != curp->p_p->ps_session) 117 return (EPERM); 118 found: 119 *retval = targpr->ps_pgid; 120 return (0); 121 } 122 123 int 124 sys_getsid(struct proc *curp, void *v, register_t *retval) 125 { 126 struct sys_getsid_args /* { 127 syscallarg(pid_t) pid; 128 } */ *uap = v; 129 struct process *targpr = curp->p_p; 130 131 if (SCARG(uap, pid) == 0 || SCARG(uap, pid) == targpr->ps_pid) 132 goto found; 133 if ((targpr = prfind(SCARG(uap, pid))) == NULL) 134 return (ESRCH); 135 if (targpr->ps_session != curp->p_p->ps_session) 136 return (EPERM); 137 found: 138 /* Skip exiting processes */ 139 if (targpr->ps_pgrp->pg_session->s_leader == NULL) 140 return (ESRCH); 141 *retval = targpr->ps_pgrp->pg_session->s_leader->ps_pid; 142 return (0); 143 } 144 145 int 146 sys_getuid(struct proc *p, void *v, register_t *retval) 147 { 148 149 *retval = p->p_ucred->cr_ruid; 150 return (0); 151 } 152 153 int 154 sys_geteuid(struct proc *p, void *v, register_t *retval) 155 { 156 157 *retval = p->p_ucred->cr_uid; 158 return (0); 159 } 160 161 int 162 sys_issetugid(struct proc *p, void *v, register_t *retval) 163 { 164 if (p->p_p->ps_flags & PS_SUGIDEXEC) 165 *retval = 1; 166 else 167 *retval = 0; 168 return (0); 169 } 170 171 int 172 sys_getgid(struct proc *p, void *v, register_t *retval) 173 { 174 175 *retval = p->p_ucred->cr_rgid; 176 return (0); 177 } 178 179 /* 180 * Get effective group ID. The "egid" is groups[0], and could be obtained 181 * via getgroups. This syscall exists because it is somewhat painful to do 182 * correctly in a library function. 183 */ 184 int 185 sys_getegid(struct proc *p, void *v, register_t *retval) 186 { 187 188 *retval = p->p_ucred->cr_gid; 189 return (0); 190 } 191 192 int 193 sys_getgroups(struct proc *p, void *v, register_t *retval) 194 { 195 struct sys_getgroups_args /* { 196 syscallarg(int) gidsetsize; 197 syscallarg(gid_t *) gidset; 198 } */ *uap = v; 199 struct ucred *uc = p->p_ucred; 200 int ngrp; 201 int error; 202 203 if ((ngrp = SCARG(uap, gidsetsize)) == 0) { 204 *retval = uc->cr_ngroups; 205 return (0); 206 } 207 if (ngrp < uc->cr_ngroups) 208 return (EINVAL); 209 ngrp = uc->cr_ngroups; 210 error = copyout(uc->cr_groups, SCARG(uap, gidset), 211 ngrp * sizeof(gid_t)); 212 if (error) 213 return (error); 214 *retval = ngrp; 215 return (0); 216 } 217 218 int 219 sys_setsid(struct proc *p, void *v, register_t *retval) 220 { 221 struct session *newsess; 222 struct pgrp *newpgrp; 223 struct process *pr = p->p_p; 224 pid_t pid = pr->ps_pid; 225 226 newsess = pool_get(&session_pool, PR_WAITOK); 227 newpgrp = pool_get(&pgrp_pool, PR_WAITOK); 228 229 if (pr->ps_pgid == pid || pgfind(pid) != NULL) { 230 pool_put(&pgrp_pool, newpgrp); 231 pool_put(&session_pool, newsess); 232 return (EPERM); 233 } else { 234 enternewpgrp(pr, newpgrp, newsess); 235 *retval = pid; 236 return (0); 237 } 238 } 239 240 /* 241 * set process group (setpgid/old setpgrp) 242 * 243 * caller does setpgid(targpid, targpgid) 244 * 245 * pid must be caller or child of caller (ESRCH) 246 * if a child 247 * pid must be in same session (EPERM) 248 * pid can't have done an exec (EACCES) 249 * if pgid != pid 250 * there must exist some pid in same session having pgid (EPERM) 251 * pid must not be session leader (EPERM) 252 */ 253 int 254 sys_setpgid(struct proc *curp, void *v, register_t *retval) 255 { 256 struct sys_setpgid_args /* { 257 syscallarg(pid_t) pid; 258 syscallarg(pid_t) pgid; 259 } */ *uap = v; 260 struct process *curpr = curp->p_p; 261 struct process *targpr; /* target process */ 262 struct pgrp *pgrp, *newpgrp; /* target pgrp */ 263 pid_t pid, pgid; 264 int error; 265 266 pid = SCARG(uap, pid); 267 pgid = SCARG(uap, pgid); 268 269 if (pgid < 0) 270 return (EINVAL); 271 272 newpgrp = pool_get(&pgrp_pool, PR_WAITOK); 273 274 if (pid != 0 && pid != curpr->ps_pid) { 275 if ((targpr = prfind(pid)) == NULL || 276 !inferior(targpr, curpr)) { 277 error = ESRCH; 278 goto out; 279 } 280 if (targpr->ps_session != curpr->ps_session) { 281 error = EPERM; 282 goto out; 283 } 284 if (targpr->ps_flags & PS_EXEC) { 285 error = EACCES; 286 goto out; 287 } 288 } else 289 targpr = curpr; 290 if (SESS_LEADER(targpr)) { 291 error = EPERM; 292 goto out; 293 } 294 if (pgid == 0) 295 pgid = targpr->ps_pid; 296 297 error = 0; 298 if ((pgrp = pgfind(pgid)) == NULL) { 299 /* can only create a new process group with pgid == pid */ 300 if (pgid != targpr->ps_pid) 301 error = EPERM; 302 else { 303 enternewpgrp(targpr, newpgrp, NULL); 304 newpgrp = NULL; 305 } 306 } else if (pgrp != targpr->ps_pgrp) { /* anything to do? */ 307 if (pgid != targpr->ps_pid && 308 pgrp->pg_session != curpr->ps_session) 309 error = EPERM; 310 else 311 enterthispgrp(targpr, pgrp); 312 } 313 out: 314 if (newpgrp != NULL) 315 pool_put(&pgrp_pool, newpgrp); 316 return (error); 317 } 318 319 int 320 sys_getresuid(struct proc *p, void *v, register_t *retval) 321 { 322 struct sys_getresuid_args /* { 323 syscallarg(uid_t *) ruid; 324 syscallarg(uid_t *) euid; 325 syscallarg(uid_t *) suid; 326 } */ *uap = v; 327 struct ucred *uc = p->p_ucred; 328 uid_t *ruid, *euid, *suid; 329 int error1 = 0, error2 = 0, error3 = 0; 330 331 ruid = SCARG(uap, ruid); 332 euid = SCARG(uap, euid); 333 suid = SCARG(uap, suid); 334 335 if (ruid != NULL) 336 error1 = copyout(&uc->cr_ruid, ruid, sizeof(*ruid)); 337 if (euid != NULL) 338 error2 = copyout(&uc->cr_uid, euid, sizeof(*euid)); 339 if (suid != NULL) 340 error3 = copyout(&uc->cr_svuid, suid, sizeof(*suid)); 341 342 return (error1 ? error1 : error2 ? error2 : error3); 343 } 344 345 int 346 sys_setresuid(struct proc *p, void *v, register_t *retval) 347 { 348 struct sys_setresuid_args /* { 349 syscallarg(uid_t) ruid; 350 syscallarg(uid_t) euid; 351 syscallarg(uid_t) suid; 352 } */ *uap = v; 353 struct process *pr = p->p_p; 354 struct ucred *pruc, *newcred, *uc = p->p_ucred; 355 uid_t ruid, euid, suid; 356 int error; 357 358 ruid = SCARG(uap, ruid); 359 euid = SCARG(uap, euid); 360 suid = SCARG(uap, suid); 361 362 /* 363 * make permission checks against the thread's ucred, 364 * but the actual changes will be to the process's ucred 365 */ 366 pruc = pr->ps_ucred; 367 if ((ruid == (uid_t)-1 || ruid == pruc->cr_ruid) && 368 (euid == (uid_t)-1 || euid == pruc->cr_uid) && 369 (suid == (uid_t)-1 || suid == pruc->cr_svuid)) 370 return (0); /* no change */ 371 372 /* 373 * Any of the real, effective, and saved uids may be changed 374 * to the current value of one of the three (root is not limited). 375 */ 376 if (ruid != (uid_t)-1 && 377 ruid != uc->cr_ruid && 378 ruid != uc->cr_uid && 379 ruid != uc->cr_svuid && 380 (error = suser(p))) 381 return (error); 382 383 if (euid != (uid_t)-1 && 384 euid != uc->cr_ruid && 385 euid != uc->cr_uid && 386 euid != uc->cr_svuid && 387 (error = suser(p))) 388 return (error); 389 390 if (suid != (uid_t)-1 && 391 suid != uc->cr_ruid && 392 suid != uc->cr_uid && 393 suid != uc->cr_svuid && 394 (error = suser(p))) 395 return (error); 396 397 /* 398 * Copy credentials so other references do not see our changes. 399 * ps_ucred may change during the crget(). 400 */ 401 newcred = crget(); 402 pruc = pr->ps_ucred; 403 crset(newcred, pruc); 404 405 /* 406 * Note that unlike the other set*uid() calls, each 407 * uid type is set independently of the others. 408 */ 409 if (ruid != (uid_t)-1) 410 newcred->cr_ruid = ruid; 411 if (euid != (uid_t)-1) 412 newcred->cr_uid = euid; 413 if (suid != (uid_t)-1) 414 newcred->cr_svuid = suid; 415 pr->ps_ucred = newcred; 416 atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID); 417 418 /* now that we can sleep, transfer proc count to new user */ 419 if (ruid != (uid_t)-1 && ruid != pruc->cr_ruid) { 420 chgproccnt(pruc->cr_ruid, -1); 421 chgproccnt(ruid, 1); 422 } 423 crfree(pruc); 424 425 return (0); 426 } 427 428 int 429 sys_getresgid(struct proc *p, void *v, register_t *retval) 430 { 431 struct sys_getresgid_args /* { 432 syscallarg(gid_t *) rgid; 433 syscallarg(gid_t *) egid; 434 syscallarg(gid_t *) sgid; 435 } */ *uap = v; 436 struct ucred *uc = p->p_ucred; 437 gid_t *rgid, *egid, *sgid; 438 int error1 = 0, error2 = 0, error3 = 0; 439 440 rgid = SCARG(uap, rgid); 441 egid = SCARG(uap, egid); 442 sgid = SCARG(uap, sgid); 443 444 if (rgid != NULL) 445 error1 = copyout(&uc->cr_rgid, rgid, sizeof(*rgid)); 446 if (egid != NULL) 447 error2 = copyout(&uc->cr_gid, egid, sizeof(*egid)); 448 if (sgid != NULL) 449 error3 = copyout(&uc->cr_svgid, sgid, sizeof(*sgid)); 450 451 return (error1 ? error1 : error2 ? error2 : error3); 452 } 453 454 int 455 sys_setresgid(struct proc *p, void *v, register_t *retval) 456 { 457 struct sys_setresgid_args /* { 458 syscallarg(gid_t) rgid; 459 syscallarg(gid_t) egid; 460 syscallarg(gid_t) sgid; 461 } */ *uap = v; 462 struct process *pr = p->p_p; 463 struct ucred *pruc, *newcred, *uc = p->p_ucred; 464 gid_t rgid, egid, sgid; 465 int error; 466 467 rgid = SCARG(uap, rgid); 468 egid = SCARG(uap, egid); 469 sgid = SCARG(uap, sgid); 470 471 /* 472 * make permission checks against the thread's ucred, 473 * but the actual changes will be to the process's ucred 474 */ 475 pruc = pr->ps_ucred; 476 if ((rgid == (gid_t)-1 || rgid == pruc->cr_rgid) && 477 (egid == (gid_t)-1 || egid == pruc->cr_gid) && 478 (sgid == (gid_t)-1 || sgid == pruc->cr_svgid)) 479 return (0); /* no change */ 480 481 /* 482 * Any of the real, effective, and saved gids may be changed 483 * to the current value of one of the three (root is not limited). 484 */ 485 if (rgid != (gid_t)-1 && 486 rgid != uc->cr_rgid && 487 rgid != uc->cr_gid && 488 rgid != uc->cr_svgid && 489 (error = suser(p))) 490 return (error); 491 492 if (egid != (gid_t)-1 && 493 egid != uc->cr_rgid && 494 egid != uc->cr_gid && 495 egid != uc->cr_svgid && 496 (error = suser(p))) 497 return (error); 498 499 if (sgid != (gid_t)-1 && 500 sgid != uc->cr_rgid && 501 sgid != uc->cr_gid && 502 sgid != uc->cr_svgid && 503 (error = suser(p))) 504 return (error); 505 506 /* 507 * Copy credentials so other references do not see our changes. 508 * ps_ucred may change during the crget(). 509 */ 510 newcred = crget(); 511 pruc = pr->ps_ucred; 512 crset(newcred, pruc); 513 514 /* 515 * Note that unlike the other set*gid() calls, each 516 * gid type is set independently of the others. 517 */ 518 if (rgid != (gid_t)-1) 519 newcred->cr_rgid = rgid; 520 if (egid != (gid_t)-1) 521 newcred->cr_gid = egid; 522 if (sgid != (gid_t)-1) 523 newcred->cr_svgid = sgid; 524 pr->ps_ucred = newcred; 525 atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID); 526 crfree(pruc); 527 return (0); 528 } 529 530 int 531 sys_setregid(struct proc *p, void *v, register_t *retval) 532 { 533 struct sys_setregid_args /* { 534 syscallarg(gid_t) rgid; 535 syscallarg(gid_t) egid; 536 } */ *uap = v; 537 struct process *pr = p->p_p; 538 struct ucred *pruc, *newcred, *uc = p->p_ucred; 539 gid_t rgid, egid; 540 int error; 541 542 rgid = SCARG(uap, rgid); 543 egid = SCARG(uap, egid); 544 545 /* 546 * make permission checks against the thread's ucred, 547 * but the actual changes will be to the process's ucred 548 * 549 * The saved gid check here is complicated: we reset the 550 * saved gid to the real gid if the real gid is specified 551 * *and* either it's changing _or_ the saved gid won't equal 552 * the effective gid. So, the svgid *won't* change when 553 * the rgid isn't specified or when the rgid isn't changing 554 * and the svgid equals the requested egid. 555 */ 556 pruc = pr->ps_ucred; 557 if ((rgid == (gid_t)-1 || rgid == pruc->cr_rgid) && 558 (egid == (gid_t)-1 || egid == pruc->cr_gid) && 559 (rgid == (gid_t)-1 || (rgid == pruc->cr_rgid && 560 pruc->cr_svgid == (egid != (gid_t)-1 ? egid : pruc->cr_gid)))) 561 return (0); /* no change */ 562 563 /* 564 * Any of the real, effective, and saved gids may be changed 565 * to the current value of one of the three (root is not limited). 566 */ 567 if (rgid != (gid_t)-1 && 568 rgid != uc->cr_rgid && 569 rgid != uc->cr_gid && 570 rgid != uc->cr_svgid && 571 (error = suser(p))) 572 return (error); 573 574 if (egid != (gid_t)-1 && 575 egid != uc->cr_rgid && 576 egid != uc->cr_gid && 577 egid != uc->cr_svgid && 578 (error = suser(p))) 579 return (error); 580 581 /* 582 * Copy credentials so other references do not see our changes. 583 * ps_ucred may change during the crget(). 584 */ 585 newcred = crget(); 586 pruc = pr->ps_ucred; 587 crset(newcred, pruc); 588 589 if (rgid != (gid_t)-1) 590 newcred->cr_rgid = rgid; 591 if (egid != (gid_t)-1) 592 newcred->cr_gid = egid; 593 594 /* 595 * The saved gid presents a bit of a dilemma, as it did not 596 * exist when setregid(2) was conceived. We only set the saved 597 * gid when the real gid is specified and either its value would 598 * change, or where the saved and effective gids are different. 599 */ 600 if (rgid != (gid_t)-1 && (rgid != pruc->cr_rgid || 601 pruc->cr_svgid != (egid != (gid_t)-1 ? egid : pruc->cr_gid))) 602 newcred->cr_svgid = rgid; 603 pr->ps_ucred = newcred; 604 atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID); 605 crfree(pruc); 606 return (0); 607 } 608 609 int 610 sys_setreuid(struct proc *p, void *v, register_t *retval) 611 { 612 struct sys_setreuid_args /* { 613 syscallarg(uid_t) ruid; 614 syscallarg(uid_t) euid; 615 } */ *uap = v; 616 struct process *pr = p->p_p; 617 struct ucred *pruc, *newcred, *uc = p->p_ucred; 618 uid_t ruid, euid; 619 int error; 620 621 ruid = SCARG(uap, ruid); 622 euid = SCARG(uap, euid); 623 624 /* 625 * make permission checks against the thread's ucred, 626 * but the actual changes will be to the process's ucred 627 * 628 * The saved uid check here is complicated: we reset the 629 * saved uid to the real uid if the real uid is specified 630 * *and* either it's changing _or_ the saved uid won't equal 631 * the effective uid. So, the svuid *won't* change when 632 * the ruid isn't specified or when the ruid isn't changing 633 * and the svuid equals the requested euid. 634 */ 635 pruc = pr->ps_ucred; 636 if ((ruid == (uid_t)-1 || ruid == pruc->cr_ruid) && 637 (euid == (uid_t)-1 || euid == pruc->cr_uid) && 638 (ruid == (uid_t)-1 || (ruid == pruc->cr_ruid && 639 pruc->cr_svuid == (euid != (uid_t)-1 ? euid : pruc->cr_uid)))) 640 return (0); /* no change */ 641 642 /* 643 * Any of the real, effective, and saved uids may be changed 644 * to the current value of one of the three (root is not limited). 645 */ 646 if (ruid != (uid_t)-1 && 647 ruid != uc->cr_ruid && 648 ruid != uc->cr_uid && 649 ruid != uc->cr_svuid && 650 (error = suser(p))) 651 return (error); 652 653 if (euid != (uid_t)-1 && 654 euid != uc->cr_ruid && 655 euid != uc->cr_uid && 656 euid != uc->cr_svuid && 657 (error = suser(p))) 658 return (error); 659 660 /* 661 * Copy credentials so other references do not see our changes. 662 * ps_ucred may change during the crget(). 663 */ 664 newcred = crget(); 665 pruc = pr->ps_ucred; 666 crset(newcred, pruc); 667 668 if (ruid != (uid_t)-1) 669 newcred->cr_ruid = ruid; 670 if (euid != (uid_t)-1) 671 newcred->cr_uid = euid; 672 673 /* 674 * The saved uid presents a bit of a dilemma, as it did not 675 * exist when setreuid(2) was conceived. We only set the saved 676 * uid when the real uid is specified and either its value would 677 * change, or where the saved and effective uids are different. 678 */ 679 if (ruid != (uid_t)-1 && (ruid != pruc->cr_ruid || 680 pruc->cr_svuid != (euid != (uid_t)-1 ? euid : pruc->cr_uid))) 681 newcred->cr_svuid = ruid; 682 pr->ps_ucred = newcred; 683 atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID); 684 685 /* now that we can sleep, transfer proc count to new user */ 686 if (ruid != (uid_t)-1 && ruid != pruc->cr_ruid) { 687 chgproccnt(pruc->cr_ruid, -1); 688 chgproccnt(ruid, 1); 689 } 690 crfree(pruc); 691 692 return (0); 693 } 694 695 int 696 sys_setuid(struct proc *p, void *v, register_t *retval) 697 { 698 struct sys_setuid_args /* { 699 syscallarg(uid_t) uid; 700 } */ *uap = v; 701 struct process *pr = p->p_p; 702 struct ucred *pruc, *newcred, *uc = p->p_ucred; 703 uid_t uid; 704 int did_real, error; 705 706 uid = SCARG(uap, uid); 707 708 pruc = pr->ps_ucred; 709 if (pruc->cr_uid == uid && 710 pruc->cr_ruid == uid && 711 pruc->cr_svuid == uid) 712 return (0); 713 714 if (uid != uc->cr_ruid && 715 uid != uc->cr_svuid && 716 uid != uc->cr_uid && 717 (error = suser(p))) 718 return (error); 719 720 /* 721 * Copy credentials so other references do not see our changes. 722 * ps_ucred may change during the crget(). 723 */ 724 newcred = crget(); 725 pruc = pr->ps_ucred; 726 crset(newcred, pruc); 727 728 /* 729 * Everything's okay, do it. 730 */ 731 if (uid == pruc->cr_uid || suser(p) == 0) { 732 did_real = 1; 733 newcred->cr_ruid = uid; 734 newcred->cr_svuid = uid; 735 } else 736 did_real = 0; 737 newcred->cr_uid = uid; 738 pr->ps_ucred = newcred; 739 atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID); 740 741 /* 742 * Transfer proc count to new user. 743 */ 744 if (did_real && uid != pruc->cr_ruid) { 745 chgproccnt(pruc->cr_ruid, -1); 746 chgproccnt(uid, 1); 747 } 748 crfree(pruc); 749 750 return (0); 751 } 752 753 int 754 sys_seteuid(struct proc *p, void *v, register_t *retval) 755 { 756 struct sys_seteuid_args /* { 757 syscallarg(uid_t) euid; 758 } */ *uap = v; 759 struct process *pr = p->p_p; 760 struct ucred *pruc, *newcred, *uc = p->p_ucred; 761 uid_t euid; 762 int error; 763 764 euid = SCARG(uap, euid); 765 766 if (pr->ps_ucred->cr_uid == euid) 767 return (0); 768 769 if (euid != uc->cr_ruid && euid != uc->cr_svuid && 770 (error = suser(p))) 771 return (error); 772 773 /* 774 * Copy credentials so other references do not see our changes. 775 * ps_ucred may change during the crget(). 776 */ 777 newcred = crget(); 778 pruc = pr->ps_ucred; 779 crset(newcred, pruc); 780 newcred->cr_uid = euid; 781 pr->ps_ucred = newcred; 782 atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID); 783 crfree(pruc); 784 return (0); 785 } 786 787 int 788 sys_setgid(struct proc *p, void *v, register_t *retval) 789 { 790 struct sys_setgid_args /* { 791 syscallarg(gid_t) gid; 792 } */ *uap = v; 793 struct process *pr = p->p_p; 794 struct ucred *pruc, *newcred, *uc = p->p_ucred; 795 gid_t gid; 796 int error; 797 798 gid = SCARG(uap, gid); 799 800 pruc = pr->ps_ucred; 801 if (pruc->cr_gid == gid && 802 pruc->cr_rgid == gid && 803 pruc->cr_svgid == gid) 804 return (0); 805 806 if (gid != uc->cr_rgid && 807 gid != uc->cr_svgid && 808 gid != uc->cr_gid && 809 (error = suser(p))) 810 return (error); 811 812 /* 813 * Copy credentials so other references do not see our changes. 814 * ps_ucred may change during the crget(). 815 */ 816 newcred = crget(); 817 pruc = pr->ps_ucred; 818 crset(newcred, pruc); 819 820 if (gid == pruc->cr_gid || suser(p) == 0) { 821 newcred->cr_rgid = gid; 822 newcred->cr_svgid = gid; 823 } 824 newcred->cr_gid = gid; 825 pr->ps_ucred = newcred; 826 atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID); 827 crfree(pruc); 828 return (0); 829 } 830 831 int 832 sys_setegid(struct proc *p, void *v, register_t *retval) 833 { 834 struct sys_setegid_args /* { 835 syscallarg(gid_t) egid; 836 } */ *uap = v; 837 struct process *pr = p->p_p; 838 struct ucred *pruc, *newcred, *uc = p->p_ucred; 839 gid_t egid; 840 int error; 841 842 egid = SCARG(uap, egid); 843 844 if (pr->ps_ucred->cr_gid == egid) 845 return (0); 846 847 if (egid != uc->cr_rgid && egid != uc->cr_svgid && 848 (error = suser(p))) 849 return (error); 850 851 /* 852 * Copy credentials so other references do not see our changes. 853 * ps_ucred may change during the crget(). 854 */ 855 newcred = crget(); 856 pruc = pr->ps_ucred; 857 crset(newcred, pruc); 858 newcred->cr_gid = egid; 859 pr->ps_ucred = newcred; 860 atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID); 861 crfree(pruc); 862 return (0); 863 } 864 865 int 866 sys_setgroups(struct proc *p, void *v, register_t *retval) 867 { 868 struct sys_setgroups_args /* { 869 syscallarg(int) gidsetsize; 870 syscallarg(const gid_t *) gidset; 871 } */ *uap = v; 872 struct process *pr = p->p_p; 873 struct ucred *pruc, *newcred; 874 gid_t groups[NGROUPS_MAX]; 875 int ngrp; 876 int error; 877 878 if ((error = suser(p)) != 0) 879 return (error); 880 ngrp = SCARG(uap, gidsetsize); 881 if (ngrp > NGROUPS_MAX || ngrp < 0) 882 return (EINVAL); 883 error = copyin(SCARG(uap, gidset), groups, ngrp * sizeof(gid_t)); 884 if (error == 0) { 885 newcred = crget(); 886 pruc = pr->ps_ucred; 887 crset(newcred, pruc); 888 memcpy(newcred->cr_groups, groups, ngrp * sizeof(gid_t)); 889 newcred->cr_ngroups = ngrp; 890 pr->ps_ucred = newcred; 891 atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID); 892 crfree(pruc); 893 } 894 return (error); 895 } 896 897 /* 898 * Check if gid is a member of the group set. 899 */ 900 int 901 groupmember(gid_t gid, struct ucred *cred) 902 { 903 gid_t *gp; 904 gid_t *egp; 905 906 if (cred->cr_gid == gid) 907 return (1); 908 egp = &(cred->cr_groups[cred->cr_ngroups]); 909 for (gp = cred->cr_groups; gp < egp; gp++) 910 if (*gp == gid) 911 return (1); 912 return (0); 913 } 914 915 /* 916 * Test whether this process has special user powers. 917 * Returns 0 or error. 918 */ 919 int 920 suser(struct proc *p) 921 { 922 struct ucred *cred = p->p_ucred; 923 924 if (cred->cr_uid == 0) 925 return (0); 926 return (EPERM); 927 } 928 929 /* 930 * replacement for old suser, for callers who don't have a process 931 */ 932 int 933 suser_ucred(struct ucred *cred) 934 { 935 if (cred->cr_uid == 0) 936 return (0); 937 return (EPERM); 938 } 939 940 /* 941 * Allocate a zeroed cred structure. 942 */ 943 struct ucred * 944 crget(void) 945 { 946 struct ucred *cr; 947 948 cr = pool_get(&ucred_pool, PR_WAITOK|PR_ZERO); 949 refcnt_init(&cr->cr_refcnt); 950 return (cr); 951 } 952 953 /* 954 * Increment the reference count of a cred structure. 955 * Returns the passed structure. 956 */ 957 struct ucred * 958 crhold(struct ucred *cr) 959 { 960 refcnt_take(&cr->cr_refcnt); 961 return (cr); 962 } 963 964 /* 965 * Free a cred structure. 966 * Throws away space when ref count gets to 0. 967 */ 968 void 969 crfree(struct ucred *cr) 970 { 971 if (refcnt_rele(&cr->cr_refcnt)) 972 pool_put(&ucred_pool, cr); 973 } 974 975 /* 976 * Copy cred structure to a new one and free the old one. 977 */ 978 struct ucred * 979 crcopy(struct ucred *cr) 980 { 981 struct ucred *newcr; 982 983 if (!refcnt_shared(&cr->cr_refcnt)) 984 return (cr); 985 newcr = crget(); 986 *newcr = *cr; 987 crfree(cr); 988 refcnt_init(&newcr->cr_refcnt); 989 return (newcr); 990 } 991 992 /* 993 * Dup cred struct to a new held one. 994 */ 995 struct ucred * 996 crdup(struct ucred *cr) 997 { 998 struct ucred *newcr; 999 1000 newcr = crget(); 1001 *newcr = *cr; 1002 refcnt_init(&newcr->cr_refcnt); 1003 return (newcr); 1004 } 1005 1006 /* 1007 * Convert the userspace xucred to a kernel ucred 1008 */ 1009 int 1010 crfromxucred(struct ucred *cr, const struct xucred *xcr) 1011 { 1012 if (xcr->cr_ngroups < 0 || xcr->cr_ngroups > NGROUPS_MAX) 1013 return (EINVAL); 1014 refcnt_init(&cr->cr_refcnt); 1015 cr->cr_uid = xcr->cr_uid; 1016 cr->cr_gid = xcr->cr_gid; 1017 cr->cr_ngroups = xcr->cr_ngroups; 1018 memcpy(cr->cr_groups, xcr->cr_groups, 1019 sizeof(cr->cr_groups[0]) * xcr->cr_ngroups); 1020 return (0); 1021 } 1022 1023 /* 1024 * Get login name, if available. 1025 */ 1026 int 1027 sys_getlogin_r(struct proc *p, void *v, register_t *retval) 1028 { 1029 struct sys_getlogin_r_args /* { 1030 syscallarg(char *) namebuf; 1031 syscallarg(size_t) namelen; 1032 } */ *uap = v; 1033 size_t namelen = SCARG(uap, namelen); 1034 struct session *s = p->p_p->ps_pgrp->pg_session; 1035 int error; 1036 1037 if (namelen > sizeof(s->s_login)) 1038 namelen = sizeof(s->s_login); 1039 error = copyoutstr(s->s_login, SCARG(uap, namebuf), namelen, NULL); 1040 if (error == ENAMETOOLONG) 1041 error = ERANGE; 1042 *retval = error; 1043 return (0); 1044 } 1045 1046 /* 1047 * Set login name. 1048 */ 1049 int 1050 sys_setlogin(struct proc *p, void *v, register_t *retval) 1051 { 1052 struct sys_setlogin_args /* { 1053 syscallarg(const char *) namebuf; 1054 } */ *uap = v; 1055 struct session *s = p->p_p->ps_pgrp->pg_session; 1056 char buf[sizeof(s->s_login)]; 1057 int error; 1058 1059 if ((error = suser(p)) != 0) 1060 return (error); 1061 error = copyinstr(SCARG(uap, namebuf), buf, sizeof(buf), NULL); 1062 if (error == 0) 1063 strlcpy(s->s_login, buf, sizeof(s->s_login)); 1064 else if (error == ENAMETOOLONG) 1065 error = EINVAL; 1066 return (error); 1067 } 1068 1069 /* 1070 * Check if a process is allowed to raise its privileges. 1071 */ 1072 int 1073 proc_cansugid(struct proc *p) 1074 { 1075 /* ptrace(2)d processes shouldn't. */ 1076 if ((p->p_p->ps_flags & PS_TRACED) != 0) 1077 return (0); 1078 1079 /* processes with shared filedescriptors shouldn't. */ 1080 if (p->p_fd->fd_refcnt > 1) 1081 return (0); 1082 1083 /* Allow. */ 1084 return (1); 1085 } 1086 1087 /* 1088 * Set address of the proc's thread-control-block 1089 */ 1090 int 1091 sys___set_tcb(struct proc *p, void *v, register_t *retval) 1092 { 1093 struct sys___set_tcb_args /* { 1094 syscallarg(void *) tcb; 1095 } */ *uap = v; 1096 void *tcb = SCARG(uap, tcb); 1097 1098 #ifdef TCB_INVALID 1099 if (TCB_INVALID(tcb)) 1100 return EINVAL; 1101 #endif /* TCB_INVALID */ 1102 TCB_SET(p, tcb); 1103 return (0); 1104 } 1105 1106 /* 1107 * Get address of the proc's thread-control-block 1108 */ 1109 int 1110 sys___get_tcb(struct proc *p, void *v, register_t *retval) 1111 { 1112 *retval = (register_t)TCB_GET(p); 1113 return (0); 1114 } 1115 1116 int 1117 sys_getthrname(struct proc *curp, void *v, register_t *retval) 1118 { 1119 struct sys_getthrname_args /* { 1120 syscallarg(pid_t) tid; 1121 syscallarg(char *) name; 1122 syscallarg(size_t) len; 1123 } */ *uap = v; 1124 struct proc *p; 1125 size_t len; 1126 int tid = SCARG(uap, tid); 1127 int error; 1128 1129 p = tid ? tfind_user(tid, curp->p_p) : curp; 1130 if (p == NULL) 1131 return ESRCH; 1132 1133 len = SCARG(uap, len); 1134 if (len > sizeof(p->p_name)) 1135 len = sizeof(p->p_name); 1136 error = copyoutstr(p->p_name, SCARG(uap, name), len, NULL); 1137 if (error == ENAMETOOLONG) 1138 error = ERANGE; 1139 *retval = error; 1140 return 0; 1141 } 1142 1143 int 1144 sys_setthrname(struct proc *curp, void *v, register_t *retval) 1145 { 1146 struct sys_setthrname_args /* { 1147 syscallarg(pid_t) tid; 1148 syscallarg(const char *) name; 1149 } */ *uap = v; 1150 struct proc *p; 1151 char buf[sizeof p->p_name]; 1152 int tid = SCARG(uap, tid); 1153 int error; 1154 1155 p = tid ? tfind_user(tid, curp->p_p) : curp; 1156 if (p == NULL) 1157 return ESRCH; 1158 1159 error = copyinstr(SCARG(uap, name), buf, sizeof buf, NULL); 1160 if (error == 0) 1161 strlcpy(p->p_name, buf, sizeof(p->p_name)); 1162 else if (error == ENAMETOOLONG) 1163 error = EINVAL; 1164 *retval = error; 1165 return 0; 1166 } 1167 1168 /* 1169 * Refresh the thread's reference to the process's credentials 1170 */ 1171 void 1172 dorefreshcreds(struct process *pr, struct proc *p) 1173 { 1174 struct ucred *uc = p->p_ucred; 1175 1176 KERNEL_LOCK(); /* XXX should be PROCESS_RLOCK(pr) */ 1177 if (uc != pr->ps_ucred) { 1178 p->p_ucred = pr->ps_ucred; 1179 crhold(p->p_ucred); 1180 crfree(uc); 1181 } 1182 KERNEL_UNLOCK(); 1183 } 1184