1 /* $NetBSD: kern_prot.c,v 1.104 2007/06/30 21:31:41 dsl 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. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)kern_prot.c 8.9 (Berkeley) 2/14/95 37 */ 38 39 /* 40 * System calls related to processes and protection 41 */ 42 43 #include <sys/cdefs.h> 44 __KERNEL_RCSID(0, "$NetBSD: kern_prot.c,v 1.104 2007/06/30 21:31:41 dsl Exp $"); 45 46 #include "opt_compat_43.h" 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/pool.h> 56 #include <sys/prot.h> 57 #include <sys/syslog.h> 58 #include <sys/resourcevar.h> 59 #include <sys/kauth.h> 60 61 #include <sys/mount.h> 62 #include <sys/syscallargs.h> 63 64 int sys_getpid(struct lwp *, void *, register_t *); 65 int sys_getpid_with_ppid(struct lwp *, void *, register_t *); 66 int sys_getuid(struct lwp *, void *, register_t *); 67 int sys_getuid_with_euid(struct lwp *, void *, register_t *); 68 int sys_getgid(struct lwp *, void *, register_t *); 69 int sys_getgid_with_egid(struct lwp *, void *, register_t *); 70 71 /* ARGSUSED */ 72 int 73 sys_getpid(struct lwp *l, void *v, register_t *retval) 74 { 75 struct proc *p = l->l_proc; 76 77 *retval = p->p_pid; 78 return (0); 79 } 80 81 /* ARGSUSED */ 82 int 83 sys_getpid_with_ppid(struct lwp *l, void *v, register_t *retval) 84 { 85 struct proc *p = l->l_proc; 86 87 retval[0] = p->p_pid; 88 mutex_enter(&proclist_lock); 89 retval[1] = p->p_pptr->p_pid; 90 mutex_exit(&proclist_lock); 91 return (0); 92 } 93 94 /* ARGSUSED */ 95 int 96 sys_getppid(struct lwp *l, void *v, register_t *retval) 97 { 98 struct proc *p = l->l_proc; 99 100 mutex_enter(&proclist_lock); 101 *retval = p->p_pptr->p_pid; 102 mutex_exit(&proclist_lock); 103 return (0); 104 } 105 106 /* Get process group ID; note that POSIX getpgrp takes no parameter */ 107 int 108 sys_getpgrp(struct lwp *l, void *v, register_t *retval) 109 { 110 struct proc *p = l->l_proc; 111 112 mutex_enter(&proclist_lock); 113 *retval = p->p_pgrp->pg_id; 114 mutex_exit(&proclist_lock); 115 return (0); 116 } 117 118 /* 119 * Return the process group ID of the session leader (session ID) 120 * for the specified process. 121 */ 122 int 123 sys_getsid(struct lwp *l, void *v, register_t *retval) 124 { 125 struct sys_getsid_args /* { 126 syscalldarg(pid_t) pid; 127 } */ *uap = v; 128 pid_t pid = SCARG(uap, pid); 129 struct proc *p; 130 int error = 0; 131 132 mutex_enter(&proclist_lock); 133 if (pid == 0) 134 *retval = l->l_proc->p_session->s_sid; 135 else if ((p = p_find(pid, PFIND_LOCKED)) != NULL) 136 *retval = p->p_session->s_sid; 137 else 138 error = ESRCH; 139 mutex_exit(&proclist_lock); 140 141 return error; 142 } 143 144 int 145 sys_getpgid(struct lwp *l, void *v, register_t *retval) 146 { 147 struct sys_getpgid_args /* { 148 syscallarg(pid_t) pid; 149 } */ *uap = v; 150 pid_t pid = SCARG(uap, pid); 151 struct proc *p; 152 int error = 0; 153 154 mutex_enter(&proclist_lock); 155 if (pid == 0) 156 *retval = l->l_proc->p_pgid; 157 else if ((p = p_find(pid, PFIND_LOCKED)) != NULL) 158 *retval = p->p_pgid; 159 else 160 error = ESRCH; 161 mutex_exit(&proclist_lock); 162 163 return error; 164 } 165 166 /* ARGSUSED */ 167 int 168 sys_getuid(struct lwp *l, void *v, register_t *retval) 169 { 170 171 *retval = kauth_cred_getuid(l->l_cred); 172 return (0); 173 } 174 175 /* ARGSUSED */ 176 int 177 sys_getuid_with_euid(struct lwp *l, void *v, register_t *retval) 178 { 179 180 retval[0] = kauth_cred_getuid(l->l_cred); 181 retval[1] = kauth_cred_geteuid(l->l_cred); 182 return (0); 183 } 184 185 /* ARGSUSED */ 186 int 187 sys_geteuid(struct lwp *l, void *v, register_t *retval) 188 { 189 190 *retval = kauth_cred_geteuid(l->l_cred); 191 return (0); 192 } 193 194 /* ARGSUSED */ 195 int 196 sys_getgid(struct lwp *l, void *v, register_t *retval) 197 { 198 199 *retval = kauth_cred_getgid(l->l_cred); 200 return (0); 201 } 202 203 /* ARGSUSED */ 204 int 205 sys_getgid_with_egid(struct lwp *l, void *v, register_t *retval) 206 { 207 208 retval[0] = kauth_cred_getgid(l->l_cred); 209 retval[1] = kauth_cred_getegid(l->l_cred); 210 return (0); 211 } 212 213 /* 214 * Get effective group ID. The "egid" is groups[0], and could be obtained 215 * via getgroups. This syscall exists because it is somewhat painful to do 216 * correctly in a library function. 217 */ 218 /* ARGSUSED */ 219 int 220 sys_getegid(struct lwp *l, void *v, register_t *retval) 221 { 222 223 *retval = kauth_cred_getegid(l->l_cred); 224 return (0); 225 } 226 227 int 228 sys_getgroups(struct lwp *l, void *v, register_t *retval) 229 { 230 struct sys_getgroups_args /* { 231 syscallarg(int) gidsetsize; 232 syscallarg(gid_t *) gidset; 233 } */ *uap = v; 234 235 *retval = kauth_cred_ngroups(l->l_cred); 236 if (SCARG(uap, gidsetsize) == 0) 237 return 0; 238 if (SCARG(uap, gidsetsize) < *retval) 239 return EINVAL; 240 241 return kauth_cred_getgroups(l->l_cred, SCARG(uap, gidset), *retval, 242 UIO_USERSPACE); 243 } 244 245 /* ARGSUSED */ 246 int 247 sys_setsid(struct lwp *l, void *v, register_t *retval) 248 { 249 struct proc *p = l->l_proc; 250 int error; 251 252 error = enterpgrp(p, p->p_pid, p->p_pid, 1); 253 *retval = p->p_pid; 254 return (error); 255 } 256 257 258 /* 259 * set process group (setpgid/old setpgrp) 260 * 261 * caller does setpgid(targpid, targpgid) 262 * 263 * pgid must be in valid range (EINVAL) 264 * pid must be caller or child of caller (ESRCH) 265 * if a child 266 * pid must be in same session (EPERM) 267 * pid can't have done an exec (EACCES) 268 * if pgid != pid 269 * there must exist some pid in same session having pgid (EPERM) 270 * pid must not be session leader (EPERM) 271 * 272 * Permission checks now in enterpgrp() 273 */ 274 /* ARGSUSED */ 275 int 276 sys_setpgid(struct lwp *l, void *v, register_t *retval) 277 { 278 struct sys_setpgid_args /* { 279 syscallarg(int) pid; 280 syscallarg(int) pgid; 281 } */ *uap = v; 282 struct proc *p = l->l_proc; 283 pid_t targp, pgid; 284 285 if (SCARG(uap, pgid) < 0) 286 return EINVAL; 287 if ((targp = SCARG(uap, pid)) == 0) 288 targp = p->p_pid; 289 if ((pgid = SCARG(uap, pgid)) == 0) 290 pgid = targp; 291 292 return enterpgrp(p, targp, pgid, 0); 293 } 294 295 /* 296 * Set real, effective and saved uids to the requested values. 297 * non-root callers can only ever change uids to values that match 298 * one of the processes current uid values. 299 * This is further restricted by the flags argument. 300 */ 301 302 int 303 do_setresuid(struct lwp *l, uid_t r, uid_t e, uid_t sv, u_int flags) 304 { 305 struct proc *p = l->l_proc; 306 kauth_cred_t cred, ncred; 307 308 ncred = kauth_cred_alloc(); 309 310 /* Get a write lock on the process credential. */ 311 proc_crmod_enter(); 312 cred = p->p_cred; 313 314 /* 315 * Check that the new value is one of the allowed existing values, 316 * or that we have root privilege. 317 */ 318 if ((r != -1 319 && !((flags & ID_R_EQ_R) && r == kauth_cred_getuid(cred)) 320 && !((flags & ID_R_EQ_E) && r == kauth_cred_geteuid(cred)) 321 && !((flags & ID_R_EQ_S) && r == kauth_cred_getsvuid(cred))) || 322 (e != -1 323 && !((flags & ID_E_EQ_R) && e == kauth_cred_getuid(cred)) 324 && !((flags & ID_E_EQ_E) && e == kauth_cred_geteuid(cred)) 325 && !((flags & ID_E_EQ_S) && e == kauth_cred_getsvuid(cred))) || 326 (sv != -1 327 && !((flags & ID_S_EQ_R) && sv == kauth_cred_getuid(cred)) 328 && !((flags & ID_S_EQ_E) && sv == kauth_cred_geteuid(cred)) 329 && !((flags & ID_S_EQ_S) && sv == kauth_cred_getsvuid(cred)))) { 330 int error; 331 332 error = kauth_authorize_process(cred, KAUTH_PROCESS_SETID, 333 p, NULL, NULL, NULL); 334 if (error != 0) { 335 proc_crmod_leave(cred, ncred, false); 336 return error; 337 } 338 } 339 340 /* If nothing has changed, short circuit the request */ 341 if ((r == -1 || r == kauth_cred_getuid(cred)) 342 && (e == -1 || e == kauth_cred_geteuid(cred)) 343 && (sv == -1 || sv == kauth_cred_getsvuid(cred))) { 344 proc_crmod_leave(cred, ncred, false); 345 return 0; 346 } 347 348 kauth_cred_clone(cred, ncred); 349 350 if (r != -1 && r != kauth_cred_getuid(ncred)) { 351 /* Update count of processes for this user */ 352 (void)chgproccnt(kauth_cred_getuid(ncred), -1); 353 (void)chgproccnt(r, 1); 354 kauth_cred_setuid(ncred, r); 355 } 356 if (sv != -1) 357 kauth_cred_setsvuid(ncred, sv); 358 if (e != -1) 359 kauth_cred_seteuid(ncred, e); 360 361 /* Broadcast our credentials to the process and other LWPs. */ 362 proc_crmod_leave(ncred, cred, true); 363 364 return 0; 365 } 366 367 /* 368 * Set real, effective and saved gids to the requested values. 369 * non-root callers can only ever change gids to values that match 370 * one of the processes current gid values. 371 * This is further restricted by the flags argument. 372 */ 373 374 int 375 do_setresgid(struct lwp *l, gid_t r, gid_t e, gid_t sv, u_int flags) 376 { 377 struct proc *p = l->l_proc; 378 kauth_cred_t cred, ncred; 379 380 ncred = kauth_cred_alloc(); 381 382 /* Get a write lock on the process credential. */ 383 proc_crmod_enter(); 384 cred = p->p_cred; 385 386 /* 387 * check new value is one of the allowed existing values. 388 * otherwise, check if we have root privilege. 389 */ 390 if ((r != -1 391 && !((flags & ID_R_EQ_R) && r == kauth_cred_getgid(cred)) 392 && !((flags & ID_R_EQ_E) && r == kauth_cred_getegid(cred)) 393 && !((flags & ID_R_EQ_S) && r == kauth_cred_getsvgid(cred))) || 394 (e != -1 395 && !((flags & ID_E_EQ_R) && e == kauth_cred_getgid(cred)) 396 && !((flags & ID_E_EQ_E) && e == kauth_cred_getegid(cred)) 397 && !((flags & ID_E_EQ_S) && e == kauth_cred_getsvgid(cred))) || 398 (sv != -1 399 && !((flags & ID_S_EQ_R) && sv == kauth_cred_getgid(cred)) 400 && !((flags & ID_S_EQ_E) && sv == kauth_cred_getegid(cred)) 401 && !((flags & ID_S_EQ_S) && sv == kauth_cred_getsvgid(cred)))) { 402 int error; 403 404 error = kauth_authorize_process(cred, KAUTH_PROCESS_SETID, 405 p, NULL, NULL, NULL); 406 if (error != 0) { 407 proc_crmod_leave(cred, ncred, false); 408 return error; 409 } 410 } 411 412 /* If nothing has changed, short circuit the request */ 413 if ((r == -1 || r == kauth_cred_getgid(cred)) 414 && (e == -1 || e == kauth_cred_getegid(cred)) 415 && (sv == -1 || sv == kauth_cred_getsvgid(cred))) { 416 proc_crmod_leave(cred, ncred, false); 417 return 0; 418 } 419 420 kauth_cred_clone(cred, ncred); 421 422 if (r != -1) 423 kauth_cred_setgid(ncred, r); 424 if (sv != -1) 425 kauth_cred_setsvgid(ncred, sv); 426 if (e != -1) 427 kauth_cred_setegid(ncred, e); 428 429 /* Broadcast our credentials to the process and other LWPs. */ 430 proc_crmod_leave(ncred, cred, true); 431 432 return 0; 433 } 434 435 /* ARGSUSED */ 436 int 437 sys_setuid(struct lwp *l, void *v, register_t *retval) 438 { 439 struct sys_setuid_args /* { 440 syscallarg(uid_t) uid; 441 } */ *uap = v; 442 uid_t uid = SCARG(uap, uid); 443 444 return do_setresuid(l, uid, uid, uid, 445 ID_R_EQ_R | ID_E_EQ_R | ID_S_EQ_R); 446 } 447 448 /* ARGSUSED */ 449 int 450 sys_seteuid(struct lwp *l, void *v, register_t *retval) 451 { 452 struct sys_seteuid_args /* { 453 syscallarg(uid_t) euid; 454 } */ *uap = v; 455 456 return do_setresuid(l, -1, SCARG(uap, euid), -1, ID_E_EQ_R | ID_E_EQ_S); 457 } 458 459 int 460 sys_setreuid(struct lwp *l, void *v, register_t *retval) 461 { 462 struct sys_setreuid_args /* { 463 syscallarg(uid_t) ruid; 464 syscallarg(uid_t) euid; 465 } */ *uap = v; 466 kauth_cred_t cred = l->l_cred; 467 uid_t ruid, euid, svuid; 468 469 ruid = SCARG(uap, ruid); 470 euid = SCARG(uap, euid); 471 472 if (ruid == -1) 473 ruid = kauth_cred_getuid(cred); 474 if (euid == -1) 475 euid = kauth_cred_geteuid(cred); 476 477 /* Saved uid is set to the new euid if the ruid changed */ 478 svuid = (ruid == kauth_cred_getuid(cred)) ? -1 : euid; 479 480 return do_setresuid(l, ruid, euid, svuid, 481 ID_R_EQ_R | ID_R_EQ_E | 482 ID_E_EQ_R | ID_E_EQ_E | ID_E_EQ_S | 483 ID_S_EQ_R | ID_S_EQ_E | ID_S_EQ_S); 484 } 485 486 /* ARGSUSED */ 487 int 488 sys_setgid(struct lwp *l, void *v, register_t *retval) 489 { 490 struct sys_setgid_args /* { 491 syscallarg(gid_t) gid; 492 } */ *uap = v; 493 gid_t gid = SCARG(uap, gid); 494 495 return do_setresgid(l, gid, gid, gid, 496 ID_R_EQ_R | ID_E_EQ_R | ID_S_EQ_R); 497 } 498 499 /* ARGSUSED */ 500 int 501 sys_setegid(struct lwp *l, void *v, register_t *retval) 502 { 503 struct sys_setegid_args /* { 504 syscallarg(gid_t) egid; 505 } */ *uap = v; 506 507 return do_setresgid(l, -1, SCARG(uap, egid), -1, ID_E_EQ_R | ID_E_EQ_S); 508 } 509 510 int 511 sys_setregid(struct lwp *l, void *v, register_t *retval) 512 { 513 struct sys_setregid_args /* { 514 syscallarg(gid_t) rgid; 515 syscallarg(gid_t) egid; 516 } */ *uap = v; 517 kauth_cred_t cred = l->l_cred; 518 gid_t rgid, egid, svgid; 519 520 rgid = SCARG(uap, rgid); 521 egid = SCARG(uap, egid); 522 523 if (rgid == -1) 524 rgid = kauth_cred_getgid(cred); 525 if (egid == -1) 526 egid = kauth_cred_getegid(cred); 527 528 /* Saved gid is set to the new egid if the rgid changed */ 529 svgid = rgid == kauth_cred_getgid(cred) ? -1 : egid; 530 531 return do_setresgid(l, rgid, egid, svgid, 532 ID_R_EQ_R | ID_R_EQ_E | 533 ID_E_EQ_R | ID_E_EQ_E | ID_E_EQ_S | 534 ID_S_EQ_R | ID_S_EQ_E | ID_S_EQ_S); 535 } 536 537 int 538 sys_issetugid(struct lwp *l, void *v, register_t *retval) 539 { 540 struct proc *p = l->l_proc; 541 542 /* 543 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 544 * we use PK_SUGID because we consider changing the owners as 545 * "tainting" as well. 546 * This is significant for procs that start as root and "become" 547 * a user without an exec - programs cannot know *everything* 548 * that libc *might* have put in their data segment. 549 */ 550 *retval = (p->p_flag & PK_SUGID) != 0; 551 return (0); 552 } 553 554 /* ARGSUSED */ 555 int 556 sys_setgroups(struct lwp *l, void *v, register_t *retval) 557 { 558 struct sys_setgroups_args /* { 559 syscallarg(int) gidsetsize; 560 syscallarg(const gid_t *) gidset; 561 } */ *uap = v; 562 kauth_cred_t ncred; 563 int error; 564 565 ncred = kauth_cred_alloc(); 566 error = kauth_cred_setgroups(ncred, SCARG(uap, gidset), 567 SCARG(uap, gidsetsize), -1, UIO_USERSPACE); 568 if (error != 0) { 569 kauth_cred_free(ncred); 570 return error; 571 } 572 573 return kauth_proc_setgroups(l, ncred); 574 } 575 576 /* 577 * Get login name, if available. 578 */ 579 /* ARGSUSED */ 580 int 581 sys___getlogin(struct lwp *l, void *v, register_t *retval) 582 { 583 struct sys___getlogin_args /* { 584 syscallarg(char *) namebuf; 585 syscallarg(size_t) namelen; 586 } */ *uap = v; 587 struct proc *p = l->l_proc; 588 char login[sizeof(p->p_session->s_login)]; 589 int namelen = SCARG(uap, namelen); 590 591 if (namelen > sizeof(login)) 592 namelen = sizeof(login); 593 mutex_enter(&proclist_lock); 594 memcpy(login, p->p_session->s_login, namelen); 595 mutex_exit(&proclist_lock); 596 return (copyout(login, (void *)SCARG(uap, namebuf), namelen)); 597 } 598 599 /* 600 * Set login name. 601 */ 602 /* ARGSUSED */ 603 int 604 sys___setlogin(struct lwp *l, void *v, register_t *retval) 605 { 606 struct sys___setlogin_args /* { 607 syscallarg(const char *) namebuf; 608 } */ *uap = v; 609 struct proc *p = l->l_proc; 610 struct session *sp; 611 char newname[sizeof sp->s_login + 1]; 612 int error; 613 614 if ((error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_SETID, 615 p, NULL, NULL, NULL)) != 0) 616 return (error); 617 error = copyinstr(SCARG(uap, namebuf), &newname, sizeof newname, NULL); 618 if (error != 0) 619 return (error == ENAMETOOLONG ? EINVAL : error); 620 621 mutex_enter(&proclist_lock); 622 sp = p->p_session; 623 if (sp->s_flags & S_LOGIN_SET && p->p_pid != sp->s_sid && 624 strncmp(newname, sp->s_login, sizeof sp->s_login) != 0) 625 log(LOG_WARNING, "%s (pid %d) changing logname from " 626 "%.*s to %s\n", p->p_comm, p->p_pid, 627 (int)sizeof sp->s_login, sp->s_login, newname); 628 sp->s_flags |= S_LOGIN_SET; 629 strncpy(sp->s_login, newname, sizeof sp->s_login); 630 mutex_exit(&proclist_lock); 631 return (0); 632 } 633 634