1/* $NetBSD: kern_prot.c,v 1.122 2020/05/23 23:42:43 ad 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.122 2020/05/23 23:42:43 ad 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 66int sys_getpid(struct lwp *, const void *, register_t *); 67int sys_getpid_with_ppid(struct lwp *, const void *, register_t *); 68int sys_getuid(struct lwp *, const void *, register_t *); 69int sys_getuid_with_euid(struct lwp *, const void *, register_t *); 70int sys_getgid(struct lwp *, const void *, register_t *); 71int sys_getgid_with_egid(struct lwp *, const void *, register_t *); 72 73/* ARGSUSED */ 74int 75sys_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 */ 84int 85sys_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 */ 95int 96sys_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 */ 105int 106sys_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 */ 120int 121sys_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 142int 143sys_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 */ 165int 166sys_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 */ 174int 175sys_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 */ 184int 185sys_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 */ 193int 194sys_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 */ 202int 203sys_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 */ 217int 218sys_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 225int 226sys_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 243int 244sys_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 */ 271int 272sys_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 299int 300do_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 380int 381do_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 */ 442int 443sys_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 */ 455int 456sys_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 465int 466sys_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 */ 493int 494sys_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 */ 506int 507sys_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 516int 517sys_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 543int 544sys_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 */ 561int 562sys_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 */ 586int 587sys___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 */ 609int 610sys___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