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