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