1/* 2 * Copyright (c) 2000-2008 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 * 28 * 29 * Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved 30 * 31 * 32 * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993 33 * The Regents of the University of California. All rights reserved. 34 * (c) UNIX System Laboratories, Inc. 35 * All or some portions of this file are derived from material licensed 36 * to the University of California by American Telephone and Telegraph 37 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 38 * the permission of UNIX System Laboratories, Inc. 39 * 40 * Redistribution and use in source and binary forms, with or without 41 * modification, are permitted provided that the following conditions 42 * are met: 43 * 1. Redistributions of source code must retain the above copyright 44 * notice, this list of conditions and the following disclaimer. 45 * 2. Redistributions in binary form must reproduce the above copyright 46 * notice, this list of conditions and the following disclaimer in the 47 * documentation and/or other materials provided with the distribution. 48 * 3. All advertising materials mentioning features or use of this software 49 * must display the following acknowledgement: 50 * This product includes software developed by the University of 51 * California, Berkeley and its contributors. 52 * 4. Neither the name of the University nor the names of its contributors 53 * may be used to endorse or promote products derived from this software 54 * without specific prior written permission. 55 * 56 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 57 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 58 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 59 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 60 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 61 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 62 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 63 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 64 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 65 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 66 * SUCH DAMAGE. 67 * 68 * @(#)kern_prot.c 8.9 (Berkeley) 2/14/95 69 * 70 * 71 * NOTICE: This file was modified by McAfee Research in 2004 to introduce 72 * support for mandatory and extensible security protections. This notice 73 * is included in support of clause 2.2 (b) of the Apple Public License, 74 * Version 2.0. 75 * 76 * 77 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce 78 * support for mandatory and extensible security protections. This notice 79 * is included in support of clause 2.2 (b) of the Apple Public License, 80 * Version 2.0. 81 * 82 */ 83 84/* 85 * System calls related to processes and protection 86 */ 87 88#include <sys/param.h> 89#include <sys/acct.h> 90#include <sys/systm.h> 91#include <sys/ucred.h> 92#include <sys/proc_internal.h> 93#include <sys/user.h> 94#include <sys/kauth.h> 95#include <sys/timeb.h> 96#include <sys/times.h> 97#include <sys/malloc.h> 98 99#include <security/audit/audit.h> 100 101#if CONFIG_LCTX 102#include <sys/lctx.h> 103#endif 104 105#if CONFIG_MACF 106#include <security/mac_framework.h> 107#endif 108 109#include <sys/mount_internal.h> 110#include <sys/sysproto.h> 111#include <mach/message.h> 112#include <mach/host_security.h> 113 114#include <kern/host.h> 115#include <kern/task.h> /* for current_task() */ 116#include <kern/assert.h> 117 118 119/* 120 * Credential debugging; we can track entry into a function that might 121 * change a credential, and we can track actual credential changes that 122 * result. 123 * 124 * Note: Does *NOT* currently include per-thread credential changes 125 * 126 * We don't use kauth_cred_print() in current debugging, but it 127 * can be used if needed when debugging is active. 128 */ 129#if DEBUG_CRED 130#define DEBUG_CRED_ENTER printf 131#define DEBUG_CRED_CHANGE printf 132extern void kauth_cred_print(kauth_cred_t cred); 133#else /* !DEBUG_CRED */ 134#define DEBUG_CRED_ENTER(fmt, ...) do {} while (0) 135#define DEBUG_CRED_CHANGE(fmt, ...) do {} while (0) 136#endif /* !DEBUG_CRED */ 137 138#if DEVELOPMENT || DEBUG 139extern void task_importance_update_owner_info(task_t); 140#endif 141 142 143/* 144 * setprivexec 145 * 146 * Description: (dis)allow this process to hold task, thread, or execption 147 * ports of processes about to exec. 148 * 149 * Parameters: uap->flag New value for flag 150 * 151 * Returns: int Previous value of flag 152 * 153 * XXX: Belongs in kern_proc.c 154 */ 155int 156setprivexec(proc_t p, struct setprivexec_args *uap, int32_t *retval) 157{ 158 AUDIT_ARG(value32, uap->flag); 159 *retval = p->p_debugger; 160 p->p_debugger = (uap->flag != 0); 161 return(0); 162} 163 164 165/* 166 * getpid 167 * 168 * Description: get the process ID 169 * 170 * Parameters: (void) 171 * 172 * Returns: pid_t Current process ID 173 * 174 * XXX: Belongs in kern_proc.c 175 */ 176int 177getpid(proc_t p, __unused struct getpid_args *uap, int32_t *retval) 178{ 179 180 *retval = p->p_pid; 181 return (0); 182} 183 184 185/* 186 * getppid 187 * 188 * Description: get the parent process ID 189 * 190 * Parameters: (void) 191 * 192 * Returns: pid_t Parent process ID 193 * 194 * XXX: Belongs in kern_proc.c 195 */ 196int 197getppid(proc_t p, __unused struct getppid_args *uap, int32_t *retval) 198{ 199 200 *retval = p->p_ppid; 201 return (0); 202} 203 204 205/* 206 * getpgrp 207 * 208 * Description: get the process group ID of the calling process 209 * 210 * Parameters: (void) 211 * 212 * Returns: pid_t Process group ID 213 * 214 * XXX: Belongs in kern_proc.c 215 */ 216int 217getpgrp(proc_t p, __unused struct getpgrp_args *uap, int32_t *retval) 218{ 219 220 *retval = p->p_pgrpid; 221 return (0); 222} 223 224 225/* 226 * getpgid 227 * 228 * Description: Get an arbitary pid's process group id 229 * 230 * Parameters: uap->pid The target pid 231 * 232 * Returns: 0 Success 233 * ESRCH No such process 234 * 235 * Notes: We are permitted to return EPERM in the case that the target 236 * process is not in the same session as the calling process, 237 * which could be a security consideration 238 * 239 * XXX: Belongs in kern_proc.c 240 */ 241int 242getpgid(proc_t p, struct getpgid_args *uap, int32_t *retval) 243{ 244 proc_t pt; 245 int refheld = 0; 246 247 pt = p; 248 if (uap->pid == 0) 249 goto found; 250 251 if ((pt = proc_find(uap->pid)) == 0) 252 return (ESRCH); 253 refheld = 1; 254found: 255 *retval = pt->p_pgrpid; 256 if (refheld != 0) 257 proc_rele(pt); 258 return (0); 259} 260 261 262/* 263 * getsid 264 * 265 * Description: Get an arbitary pid's session leaders process group ID 266 * 267 * Parameters: uap->pid The target pid 268 * 269 * Returns: 0 Success 270 * ESRCH No such process 271 * 272 * Notes: We are permitted to return EPERM in the case that the target 273 * process is not in the same session as the calling process, 274 * which could be a security consideration 275 * 276 * XXX: Belongs in kern_proc.c 277 */ 278int 279getsid(proc_t p, struct getsid_args *uap, int32_t *retval) 280{ 281 proc_t pt; 282 int refheld = 0; 283 struct session * sessp; 284 285 pt = p; 286 if (uap->pid == 0) 287 goto found; 288 289 if ((pt = proc_find(uap->pid)) == 0) 290 return (ESRCH); 291 refheld = 1; 292found: 293 sessp = proc_session(pt); 294 *retval = sessp->s_sid; 295 session_rele(sessp); 296 297 if (refheld != 0) 298 proc_rele(pt); 299 return (0); 300} 301 302 303/* 304 * getuid 305 * 306 * Description: get real user ID for caller 307 * 308 * Parameters: (void) 309 * 310 * Returns: uid_t The real uid of the caller 311 */ 312int 313getuid(__unused proc_t p, __unused struct getuid_args *uap, int32_t *retval) 314{ 315 316 *retval = kauth_getruid(); 317 return (0); 318} 319 320 321/* 322 * geteuid 323 * 324 * Description: get effective user ID for caller 325 * 326 * Parameters: (void) 327 * 328 * Returns: uid_t The effective uid of the caller 329 */ 330int 331geteuid(__unused proc_t p, __unused struct geteuid_args *uap, int32_t *retval) 332{ 333 334 *retval = kauth_getuid(); 335 return (0); 336} 337 338 339/* 340 * gettid 341 * 342 * Description: Return the per-thread override identity. 343 * 344 * Parameters: uap->uidp Address of uid_t to get uid 345 * uap->gidp Address of gid_t to get gid 346 * 347 * Returns: 0 Success 348 * ESRCH No per thread identity active 349 */ 350int 351gettid(__unused proc_t p, struct gettid_args *uap, int32_t *retval) 352{ 353 struct uthread *uthread = get_bsdthread_info(current_thread()); 354 int error; 355 356 /* 357 * If this thread is not running with an override identity, we can't 358 * return one to the caller, so return an error instead. 359 */ 360 if (!(uthread->uu_flag & UT_SETUID)) 361 return (ESRCH); 362 363 if ((error = suword(uap->uidp, kauth_cred_getruid(uthread->uu_ucred)))) 364 return (error); 365 if ((error = suword(uap->gidp, kauth_cred_getrgid(uthread->uu_ucred)))) 366 return (error); 367 368 *retval = 0; 369 return (0); 370} 371 372 373/* 374 * getgid 375 * 376 * Description: get the real group ID for the calling process 377 * 378 * Parameters: (void) 379 * 380 * Returns: gid_t The real gid of the caller 381 */ 382int 383getgid(__unused proc_t p, __unused struct getgid_args *uap, int32_t *retval) 384{ 385 386 *retval = kauth_getrgid(); 387 return (0); 388} 389 390 391/* 392 * getegid 393 * 394 * Description: get the effective group ID for the calling process 395 * 396 * Parameters: (void) 397 * 398 * Returns: gid_t The effective gid of the caller 399 * 400 * Notes: As an implementation detail, the effective gid is stored as 401 * the first element of the supplementary group list. 402 * 403 * This could be implemented in Libc instead because of the above 404 * detail. 405 */ 406int 407getegid(__unused proc_t p, __unused struct getegid_args *uap, int32_t *retval) 408{ 409 410 *retval = kauth_getgid(); 411 return (0); 412} 413 414 415/* 416 * getgroups 417 * 418 * Description: get the list of supplementary groups for the calling process 419 * 420 * Parameters: uap->gidsetsize # of gid_t's in user buffer 421 * uap->gidset Pointer to user buffer 422 * 423 * Returns: 0 Success 424 * EINVAL User buffer too small 425 * copyout:EFAULT User buffer invalid 426 * 427 * Retval: -1 Error 428 * !0 # of groups 429 * 430 * Notes: The caller may specify a 0 value for gidsetsize, and we will 431 * then return how large a buffer is required (in gid_t's) to 432 * contain the answer at the time of the call. Otherwise, we 433 * return the number of gid_t's catually copied to user space. 434 * 435 * When called with a 0 gidsetsize from a multithreaded program, 436 * there is no guarantee that another thread may not change the 437 * number of supplementary groups, and therefore a subsequent 438 * call could still fail, unless the maximum possible buffer 439 * size is supplied by the user. 440 * 441 * As an implementation detail, the effective gid is stored as 442 * the first element of the supplementary group list, and will 443 * be returned by this call. 444 */ 445int 446getgroups(__unused proc_t p, struct getgroups_args *uap, int32_t *retval) 447{ 448 int ngrp; 449 int error; 450 kauth_cred_t cred; 451 posix_cred_t pcred; 452 453 /* grab reference while we muck around with the credential */ 454 cred = kauth_cred_get_with_ref(); 455 pcred = posix_cred_get(cred); 456 457 if ((ngrp = uap->gidsetsize) == 0) { 458 *retval = pcred->cr_ngroups; 459 kauth_cred_unref(&cred); 460 return (0); 461 } 462 if (ngrp < pcred->cr_ngroups) { 463 kauth_cred_unref(&cred); 464 return (EINVAL); 465 } 466 ngrp = pcred->cr_ngroups; 467 if ((error = copyout((caddr_t)pcred->cr_groups, 468 uap->gidset, 469 ngrp * sizeof(gid_t)))) { 470 kauth_cred_unref(&cred); 471 return (error); 472 } 473 kauth_cred_unref(&cred); 474 *retval = ngrp; 475 return (0); 476} 477 478 479/* 480 * Return the per-thread/per-process supplementary groups list. 481 * 482 * XXX implement getsgroups 483 * 484 */ 485 486int 487getsgroups(__unused proc_t p, __unused struct getsgroups_args *uap, __unused int32_t *retval) 488{ 489 return(ENOTSUP); 490} 491 492/* 493 * Return the per-thread/per-process whiteout groups list. 494 * 495 * XXX implement getwgroups 496 * 497 */ 498 499int 500getwgroups(__unused proc_t p, __unused struct getwgroups_args *uap, __unused int32_t *retval) 501{ 502 return(ENOTSUP); 503} 504 505 506/* 507 * setsid 508 * 509 * Description: Create a new session and set the process group ID to the 510 * session ID 511 * 512 * Parameters: (void) 513 * 514 * Returns: 0 Success 515 * EPERM Permission denied 516 * 517 * Notes: If the calling process is not the process group leader; there 518 * is no existing process group with its ID, and we are not 519 * currently in vfork, then this function will create a new 520 * session, a new process group, and put the caller in the 521 * process group (as the sole member) and make it the session 522 * leader (as the sole process in the session). 523 * 524 * The existing controlling tty (if any) will be dissociated 525 * from the process, and the next non-O_NOCTTY open of a tty 526 * will establish a new controlling tty. 527 * 528 * XXX: Belongs in kern_proc.c 529 */ 530int 531setsid(proc_t p, __unused struct setsid_args *uap, int32_t *retval) 532{ 533 struct pgrp * pg = PGRP_NULL; 534 535 if (p->p_pgrpid == p->p_pid || (pg = pgfind(p->p_pid)) || p->p_lflag & P_LINVFORK) { 536 if (pg != PGRP_NULL) 537 pg_rele(pg); 538 return (EPERM); 539 } else { 540 /* enter pgrp works with its own pgrp refcount */ 541 (void)enterpgrp(p, p->p_pid, 1); 542 *retval = p->p_pid; 543 return (0); 544 } 545} 546 547 548/* 549 * setpgid 550 * 551 * Description: set process group ID for job control 552 * 553 * Parameters: uap->pid Process to change 554 * uap->pgid Process group to join or create 555 * 556 * Returns: 0 Success 557 * ESRCH pid is not the caller or a child of 558 * the caller 559 * enterpgrp:ESRCH No such process 560 * EACCES Permission denied due to exec 561 * EINVAL Invalid argument 562 * EPERM The target process is not in the same 563 * session as the calling process 564 * EPERM The target process is a session leader 565 * EPERM pid and pgid are not the same, and 566 * there is no process in the calling 567 * process whose process group ID matches 568 * pgid 569 * 570 * Notes: This function will cause the target process to either join 571 * an existing process process group, or create a new process 572 * group in the session of the calling process. It cannot be 573 * used to change the process group ID of a process which is 574 * already a session leader. 575 * 576 * If the target pid is 0, the pid of the calling process is 577 * substituted as the new target; if pgid is 0, the target pid 578 * is used as the target process group ID. 579 * 580 * Legacy: This system call entry point is also used to implement the 581 * legacy library routine setpgrp(), which under POSIX 582 * 583 * XXX: Belongs in kern_proc.c 584 */ 585int 586setpgid(proc_t curp, register struct setpgid_args *uap, __unused int32_t *retval) 587{ 588 proc_t targp = PROC_NULL; /* target process */ 589 struct pgrp *pg = PGRP_NULL; /* target pgrp */ 590 int error = 0; 591 int refheld = 0; 592 int samesess = 0; 593 struct session * curp_sessp = SESSION_NULL; 594 struct session * targp_sessp = SESSION_NULL; 595 596 curp_sessp = proc_session(curp); 597 598 if (uap->pid != 0 && uap->pid != curp->p_pid) { 599 if ((targp = proc_find(uap->pid)) == 0 || !inferior(targp)) { 600 if (targp != PROC_NULL) 601 refheld = 1; 602 error = ESRCH; 603 goto out; 604 } 605 refheld = 1; 606 targp_sessp = proc_session(targp); 607 if (targp_sessp != curp_sessp) { 608 error = EPERM; 609 goto out; 610 } 611 if (targp->p_flag & P_EXEC) { 612 error = EACCES; 613 goto out; 614 } 615 } else { 616 targp = curp; 617 targp_sessp = proc_session(targp); 618 } 619 620 if (SESS_LEADER(targp, targp_sessp)) { 621 error = EPERM; 622 goto out; 623 } 624 if (targp_sessp != SESSION_NULL) { 625 session_rele(targp_sessp); 626 targp_sessp = SESSION_NULL; 627 } 628 629 if (uap->pgid < 0) { 630 error = EINVAL; 631 goto out; 632 } 633 if (uap->pgid == 0) 634 uap->pgid = targp->p_pid; 635 else if (uap->pgid != targp->p_pid) { 636 if ((pg = pgfind(uap->pgid)) == 0){ 637 error = EPERM; 638 goto out; 639 } 640 samesess = (pg->pg_session != curp_sessp); 641 pg_rele(pg); 642 if (samesess != 0) { 643 error = EPERM; 644 goto out; 645 } 646 } 647 error = enterpgrp(targp, uap->pgid, 0); 648out: 649 if (targp_sessp != SESSION_NULL) 650 session_rele(targp_sessp); 651 if (curp_sessp != SESSION_NULL) 652 session_rele(curp_sessp); 653 if (refheld != 0) 654 proc_rele(targp); 655 return(error); 656} 657 658 659/* 660 * issetugid 661 * 662 * Description: Is current process tainted by uid or gid changes system call 663 * 664 * Parameters: (void) 665 * 666 * Returns: 0 Not tainted 667 * 1 Tainted 668 * 669 * Notes: A process is considered tainted if it was created as a retult 670 * of an execve call from an imnage that had either the SUID or 671 * SGID bit set on the executable, or if it has changed any of its 672 * real, effective, or saved user or group IDs since beginning 673 * execution. 674 */ 675int 676issetugid(proc_t p, __unused struct issetugid_args *uap, int32_t *retval) 677{ 678 /* 679 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 680 * we use P_SUGID because we consider changing the owners as 681 * "tainting" as well. 682 * This is significant for procs that start as root and "become" 683 * a user without an exec - programs cannot know *everything* 684 * that libc *might* have put in their data segment. 685 */ 686 687 *retval = (p->p_flag & P_SUGID) ? 1 : 0; 688 return (0); 689} 690 691 692/* 693 * setuid 694 * 695 * Description: Set user ID system call 696 * 697 * Parameters: uap->uid uid to set 698 * 699 * Returns: 0 Success 700 * suser:EPERM Permission denied 701 * 702 * Notes: If called by a privileged process, this function will set the 703 * real, effective, and saved uid to the requested value. 704 * 705 * If called from an unprivileged process, but uid is equal to the 706 * real or saved uid, then the effective uid will be set to the 707 * requested value, but the real and saved uid will not change. 708 * 709 * If the credential is changed as a result of this call, then we 710 * flag the process as having set privilege since the last exec. 711 */ 712int 713setuid(proc_t p, struct setuid_args *uap, __unused int32_t *retval) 714{ 715 uid_t uid; 716 uid_t svuid = KAUTH_UID_NONE; 717 uid_t ruid = KAUTH_UID_NONE; 718 uid_t gmuid = KAUTH_UID_NONE; 719 int error; 720 kauth_cred_t my_cred, my_new_cred; 721 posix_cred_t my_pcred; 722 723 724 uid = uap->uid; 725 726 my_cred = kauth_cred_proc_ref(p); 727 my_pcred = posix_cred_get(my_cred); 728 729 DEBUG_CRED_ENTER("setuid (%d/%d): %p %d\n", p->p_pid, (p->p_pptr ? p->p_pptr->p_pid : 0), my_cred, uap->uid); 730 AUDIT_ARG(uid, uid); 731 732 if (uid != my_pcred->cr_ruid && /* allow setuid(getuid()) */ 733 uid != my_pcred->cr_svuid && /* allow setuid(saved uid) */ 734 (error = suser(my_cred, &p->p_acflag))) { 735 kauth_cred_unref(&my_cred); 736 return (error); 737 } 738 /* 739 * Everything's okay, do it. 740 */ 741 742 /* 743 * If we are priviledged, then set the saved and real UID too; 744 * otherwise, just set the effective UID 745 */ 746 if (suser(my_cred, &p->p_acflag) == 0) { 747 svuid = uid; 748 ruid = uid; 749 /* 750 * Transfer proc count to new user. 751 * chgproccnt uses list lock for protection 752 */ 753 (void)chgproccnt(uid, 1); 754 (void)chgproccnt(my_pcred->cr_ruid, -1); 755 } 756 757 /* get current credential and take a reference while we muck with it */ 758 for (;;) { 759 /* 760 * Only set the gmuid if the current cred has not opt'ed out; 761 * this normally only happens when calling setgroups() instead 762 * of initgroups() to set an explicit group list, or one of the 763 * other group manipulation functions is invoked and results in 764 * a dislocation (i.e. the credential group membership changes 765 * to something other than the default list for the user, as 766 * in entering a group or leaving an exclusion group). 767 */ 768 if (!(my_pcred->cr_flags & CRF_NOMEMBERD)) 769 gmuid = uid; 770 771 /* 772 * Set the credential with new info. If there is no change, 773 * we get back the same credential we passed in; if there is 774 * a change, we drop the reference on the credential we 775 * passed in. The subsequent compare is safe, because it is 776 * a pointer compare rather than a contents compare. 777 */ 778 my_new_cred = kauth_cred_setresuid(my_cred, ruid, uid, svuid, gmuid); 779 if (my_cred != my_new_cred) { 780 781 DEBUG_CRED_CHANGE("setuid CH(%d): %p/0x%08x -> %p/0x%08x\n", p->p_pid, my_cred, my_pcred->cr_flags, my_new_cred, posix_cred_get(my_new_cred)->cr_flags); 782 783 proc_lock(p); 784 /* 785 * We need to protect for a race where another thread 786 * also changed the credential after we took our 787 * reference. If p_ucred has changed then we should 788 * restart this again with the new cred. 789 */ 790 if (p->p_ucred != my_cred) { 791 proc_unlock(p); 792 kauth_cred_unref(&my_new_cred); 793 my_cred = kauth_cred_proc_ref(p); 794 /* try again */ 795 continue; 796 } 797 p->p_ucred = my_new_cred; 798 /* update cred on proc */ 799 PROC_UPDATE_CREDS_ONPROC(p); 800 801 OSBitOrAtomic(P_SUGID, &p->p_flag); 802 proc_unlock(p); 803 } 804 break; 805 } 806 /* Drop old proc reference or our extra reference */ 807 kauth_cred_unref(&my_cred); 808 809 set_security_token(p); 810 return (0); 811} 812 813 814/* 815 * seteuid 816 * 817 * Description: Set effective user ID system call 818 * 819 * Parameters: uap->euid effective uid to set 820 * 821 * Returns: 0 Success 822 * suser:EPERM Permission denied 823 * 824 * Notes: If called by a privileged process, or called from an 825 * unprivileged process but euid is equal to the real or saved 826 * uid, then the effective uid will be set to the requested 827 * value, but the real and saved uid will not change. 828 * 829 * If the credential is changed as a result of this call, then we 830 * flag the process as having set privilege since the last exec. 831 */ 832int 833seteuid(proc_t p, struct seteuid_args *uap, __unused int32_t *retval) 834{ 835 uid_t euid; 836 int error; 837 kauth_cred_t my_cred, my_new_cred; 838 posix_cred_t my_pcred; 839 840 DEBUG_CRED_ENTER("seteuid: %d\n", uap->euid); 841 842 euid = uap->euid; 843 AUDIT_ARG(euid, euid); 844 845 my_cred = kauth_cred_proc_ref(p); 846 my_pcred = posix_cred_get(my_cred); 847 848 if (euid != my_pcred->cr_ruid && euid != my_pcred->cr_svuid && 849 (error = suser(my_cred, &p->p_acflag))) { 850 kauth_cred_unref(&my_cred); 851 return (error); 852 } 853 854 /* 855 * Everything's okay, do it. Copy credentials so other references do 856 * not see our changes. get current credential and take a reference 857 * while we muck with it 858 */ 859 for (;;) { 860 /* 861 * Set the credential with new info. If there is no change, 862 * we get back the same credential we passed in; if there is 863 * a change, we drop the reference on the credential we 864 * passed in. The subsequent compare is safe, because it is 865 * a pointer compare rather than a contents compare. 866 */ 867 my_new_cred = kauth_cred_setresuid(my_cred, KAUTH_UID_NONE, euid, KAUTH_UID_NONE, my_pcred->cr_gmuid); 868 869 if (my_cred != my_new_cred) { 870 871 DEBUG_CRED_CHANGE("seteuid CH(%d): %p/0x%08x -> %p/0x%08x\n", p->p_pid, my_cred, my_pcred->cr_flags, my_new_cred, posix_cred_get(my_new_cred)->cr_flags); 872 873 proc_lock(p); 874 /* 875 * We need to protect for a race where another thread 876 * also changed the credential after we took our 877 * reference. If p_ucred has changed then we 878 * should restart this again with the new cred. 879 */ 880 if (p->p_ucred != my_cred) { 881 proc_unlock(p); 882 kauth_cred_unref(&my_new_cred); 883 my_cred = kauth_cred_proc_ref(p); 884 /* try again */ 885 continue; 886 } 887 p->p_ucred = my_new_cred; 888 /* update cred on proc */ 889 PROC_UPDATE_CREDS_ONPROC(p); 890 OSBitOrAtomic(P_SUGID, &p->p_flag); 891 proc_unlock(p); 892 } 893 break; 894 } 895 /* drop old proc reference or our extra reference */ 896 kauth_cred_unref(&my_cred); 897 898 set_security_token(p); 899 return (0); 900} 901 902 903/* 904 * setreuid 905 * 906 * Description: Set real and effective user ID system call 907 * 908 * Parameters: uap->ruid real uid to set 909 * uap->euid effective uid to set 910 * 911 * Returns: 0 Success 912 * suser:EPERM Permission denied 913 * 914 * Notes: A value of -1 is a special case indicating that the uid for 915 * which that value is specified not be changed. If both values 916 * are specified as -1, no action is taken. 917 * 918 * If called by a privileged process, the real and effective uid 919 * will be set to the new value(s) specified. 920 * 921 * If called from an unprivileged process, the real uid may be 922 * set to the current value of the real uid, or to the current 923 * value of the saved uid. The effective uid may be set to the 924 * current value of any of the effective, real, or saved uid. 925 * 926 * If the newly requested real uid or effective uid does not 927 * match the saved uid, then set the saved uid to the new 928 * effective uid (potentially unrecoverably dropping saved 929 * privilege). 930 * 931 * If the credential is changed as a result of this call, then we 932 * flag the process as having set privilege since the last exec. 933 */ 934int 935setreuid(proc_t p, struct setreuid_args *uap, __unused int32_t *retval) 936{ 937 uid_t ruid, euid; 938 int error; 939 kauth_cred_t my_cred, my_new_cred; 940 posix_cred_t my_pcred; 941 942 DEBUG_CRED_ENTER("setreuid %d %d\n", uap->ruid, uap->euid); 943 944 ruid = uap->ruid; 945 euid = uap->euid; 946 if (ruid == (uid_t)-1) 947 ruid = KAUTH_UID_NONE; 948 if (euid == (uid_t)-1) 949 euid = KAUTH_UID_NONE; 950 AUDIT_ARG(euid, euid); 951 AUDIT_ARG(ruid, ruid); 952 953 my_cred = kauth_cred_proc_ref(p); 954 my_pcred = posix_cred_get(my_cred); 955 956 if (((ruid != KAUTH_UID_NONE && /* allow no change of ruid */ 957 ruid != my_pcred->cr_ruid && /* allow ruid = ruid */ 958 ruid != my_pcred->cr_uid && /* allow ruid = euid */ 959 ruid != my_pcred->cr_svuid) || /* allow ruid = svuid */ 960 (euid != KAUTH_UID_NONE && /* allow no change of euid */ 961 euid != my_pcred->cr_uid && /* allow euid = euid */ 962 euid != my_pcred->cr_ruid && /* allow euid = ruid */ 963 euid != my_pcred->cr_svuid)) && /* allow euid = svui */ 964 (error = suser(my_cred, &p->p_acflag))) { /* allow root user any */ 965 kauth_cred_unref(&my_cred); 966 return (error); 967 } 968 969 /* 970 * Everything's okay, do it. Copy credentials so other references do 971 * not see our changes. get current credential and take a reference 972 * while we muck with it 973 */ 974 for (;;) { 975 uid_t new_euid; 976 uid_t new_ruid; 977 uid_t svuid = KAUTH_UID_NONE; 978 979 new_euid = my_pcred->cr_uid; 980 new_ruid = my_pcred->cr_ruid; 981 982 /* 983 * Set the credential with new info. If there is no change, 984 * we get back the same credential we passed in; if there is 985 * a change, we drop the reference on the credential we 986 * passed in. The subsequent compare is safe, because it is 987 * a pointer compare rather than a contents compare. 988 */ 989 if (euid == KAUTH_UID_NONE && my_pcred->cr_uid != euid) { 990 /* changing the effective UID */ 991 new_euid = euid; 992 OSBitOrAtomic(P_SUGID, &p->p_flag); 993 } 994 if (ruid != KAUTH_UID_NONE && my_pcred->cr_ruid != ruid) { 995 /* changing the real UID; must do user accounting */ 996 /* chgproccnt uses list lock for protection */ 997 (void)chgproccnt(ruid, 1); 998 (void)chgproccnt(my_pcred->cr_ruid, -1); 999 new_ruid = ruid; 1000 OSBitOrAtomic(P_SUGID, &p->p_flag); 1001 } 1002 /* 1003 * If the newly requested real uid or effective uid does 1004 * not match the saved uid, then set the saved uid to the 1005 * new effective uid. We are protected from escalation 1006 * by the prechecking. 1007 */ 1008 if (my_pcred->cr_svuid != uap->ruid && 1009 my_pcred->cr_svuid != uap->euid) { 1010 svuid = new_euid; 1011 OSBitOrAtomic(P_SUGID, &p->p_flag); 1012 } 1013 1014 my_new_cred = kauth_cred_setresuid(my_cred, ruid, euid, svuid, my_pcred->cr_gmuid); 1015 1016 if (my_cred != my_new_cred) { 1017 1018 DEBUG_CRED_CHANGE("setreuid CH(%d): %p/0x%08x -> %p/0x%08x\n", p->p_pid, my_cred, my_pcred->cr_flags, my_new_cred, posix_cred_get(my_new_cred)->cr_flags); 1019 1020 proc_lock(p); 1021 /* 1022 * We need to protect for a race where another thread 1023 * also changed the credential after we took our 1024 * reference. If p_ucred has changed then we should 1025 * restart this again with the new cred. 1026 */ 1027 if (p->p_ucred != my_cred) { 1028 proc_unlock(p); 1029 kauth_cred_unref(&my_new_cred); 1030 my_cred = kauth_cred_proc_ref(p); 1031 /* try again */ 1032 continue; 1033 } 1034 p->p_ucred = my_new_cred; 1035 /* update cred on proc */ 1036 PROC_UPDATE_CREDS_ONPROC(p); 1037 OSBitOrAtomic(P_SUGID, &p->p_flag); /* XXX redundant? */ 1038 proc_unlock(p); 1039 } 1040 break; 1041 } 1042 /* drop old proc reference or our extra reference */ 1043 kauth_cred_unref(&my_cred); 1044 1045 set_security_token(p); 1046 return (0); 1047} 1048 1049 1050/* 1051 * setgid 1052 * 1053 * Description: Set group ID system call 1054 * 1055 * Parameters: uap->gid gid to set 1056 * 1057 * Returns: 0 Success 1058 * suser:EPERM Permission denied 1059 * 1060 * Notes: If called by a privileged process, this function will set the 1061 * real, effective, and saved gid to the requested value. 1062 * 1063 * If called from an unprivileged process, but gid is equal to the 1064 * real or saved gid, then the effective gid will be set to the 1065 * requested value, but the real and saved gid will not change. 1066 * 1067 * If the credential is changed as a result of this call, then we 1068 * flag the process as having set privilege since the last exec. 1069 * 1070 * As an implementation detail, the effective gid is stored as 1071 * the first element of the supplementary group list, and 1072 * therefore the effective group list may be reordered to keep 1073 * the supplementary group list unchanged. 1074 */ 1075int 1076setgid(proc_t p, struct setgid_args *uap, __unused int32_t *retval) 1077{ 1078 gid_t gid; 1079 gid_t rgid = KAUTH_GID_NONE; 1080 gid_t svgid = KAUTH_GID_NONE; 1081 int error; 1082 kauth_cred_t my_cred, my_new_cred; 1083 posix_cred_t my_pcred; 1084 1085 DEBUG_CRED_ENTER("setgid(%d/%d): %d\n", p->p_pid, (p->p_pptr ? p->p_pptr->p_pid : 0), uap->gid); 1086 1087 gid = uap->gid; 1088 AUDIT_ARG(gid, gid); 1089 1090 my_cred = kauth_cred_proc_ref(p); 1091 my_pcred = posix_cred_get(my_cred); 1092 1093 if (gid != my_pcred->cr_rgid && /* allow setgid(getgid()) */ 1094 gid != my_pcred->cr_svgid && /* allow setgid(saved gid) */ 1095 (error = suser(my_cred, &p->p_acflag))) { 1096 kauth_cred_unref(&my_cred); 1097 return (error); 1098 } 1099 1100 /* 1101 * If we are priviledged, then set the saved and real GID too; 1102 * otherwise, just set the effective GID 1103 */ 1104 if (suser(my_cred, &p->p_acflag) == 0) { 1105 svgid = gid; 1106 rgid = gid; 1107 } 1108 1109 /* get current credential and take a reference while we muck with it */ 1110 for (;;) { 1111 1112 /* 1113 * Set the credential with new info. If there is no change, 1114 * we get back the same credential we passed in; if there is 1115 * a change, we drop the reference on the credential we 1116 * passed in. The subsequent compare is safe, because it is 1117 * a pointer compare rather than a contents compare. 1118 */ 1119 my_new_cred = kauth_cred_setresgid(my_cred, rgid, gid, svgid); 1120 if (my_cred != my_new_cred) { 1121 1122 DEBUG_CRED_CHANGE("setgid(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_cred->cr_flags, my_new_cred, my_new_cred->cr_flags); 1123 1124 proc_lock(p); 1125 /* 1126 * We need to protect for a race where another thread 1127 * also changed the credential after we took our 1128 * reference. If p_ucred has changed then we 1129 * should restart this again with the new cred. 1130 */ 1131 if (p->p_ucred != my_cred) { 1132 proc_unlock(p); 1133 kauth_cred_unref(&my_new_cred); 1134 /* try again */ 1135 my_cred = kauth_cred_proc_ref(p); 1136 continue; 1137 } 1138 p->p_ucred = my_new_cred; 1139 /* update cred on proc */ 1140 PROC_UPDATE_CREDS_ONPROC(p); 1141 OSBitOrAtomic(P_SUGID, &p->p_flag); 1142 proc_unlock(p); 1143 } 1144 break; 1145 } 1146 /* Drop old proc reference or our extra reference */ 1147 kauth_cred_unref(&my_cred); 1148 1149 set_security_token(p); 1150 return (0); 1151} 1152 1153 1154/* 1155 * setegid 1156 * 1157 * Description: Set effective group ID system call 1158 * 1159 * Parameters: uap->egid effective gid to set 1160 * 1161 * Returns: 0 Success 1162 * suser:EPERM 1163 * 1164 * Notes: If called by a privileged process, or called from an 1165 * unprivileged process but egid is equal to the real or saved 1166 * gid, then the effective gid will be set to the requested 1167 * value, but the real and saved gid will not change. 1168 * 1169 * If the credential is changed as a result of this call, then we 1170 * flag the process as having set privilege since the last exec. 1171 * 1172 * As an implementation detail, the effective gid is stored as 1173 * the first element of the supplementary group list, and 1174 * therefore the effective group list may be reordered to keep 1175 * the supplementary group list unchanged. 1176 */ 1177int 1178setegid(proc_t p, struct setegid_args *uap, __unused int32_t *retval) 1179{ 1180 gid_t egid; 1181 int error; 1182 kauth_cred_t my_cred, my_new_cred; 1183 posix_cred_t my_pcred; 1184 1185 DEBUG_CRED_ENTER("setegid %d\n", uap->egid); 1186 1187 egid = uap->egid; 1188 AUDIT_ARG(egid, egid); 1189 1190 my_cred = kauth_cred_proc_ref(p); 1191 my_pcred = posix_cred_get(my_cred); 1192 1193 if (egid != my_pcred->cr_rgid && 1194 egid != my_pcred->cr_svgid && 1195 (error = suser(my_cred, &p->p_acflag))) { 1196 kauth_cred_unref(&my_cred); 1197 return (error); 1198 } 1199 1200 /* get current credential and take a reference while we muck with it */ 1201 for (;;) { 1202 /* 1203 * Set the credential with new info. If there is no change, 1204 * we get back the same credential we passed in; if there is 1205 * a change, we drop the reference on the credential we 1206 * passed in. The subsequent compare is safe, because it is 1207 * a pointer compare rather than a contents compare. 1208 */ 1209 my_new_cred = kauth_cred_setresgid(my_cred, KAUTH_GID_NONE, egid, KAUTH_GID_NONE); 1210 if (my_cred != my_new_cred) { 1211 1212 DEBUG_CRED_CHANGE("setegid(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_pcred->cr_flags, my_new_cred, posix_cred_get(my_new_cred)->cr_flags); 1213 1214 proc_lock(p); 1215 /* 1216 * We need to protect for a race where another thread 1217 * also changed the credential after we took our 1218 * reference. If p_ucred has changed then we 1219 * should restart this again with the new cred. 1220 */ 1221 if (p->p_ucred != my_cred) { 1222 proc_unlock(p); 1223 kauth_cred_unref(&my_new_cred); 1224 /* try again */ 1225 my_cred = kauth_cred_proc_ref(p); 1226 continue; 1227 } 1228 p->p_ucred = my_new_cred; 1229 /* update cred on proc */ 1230 PROC_UPDATE_CREDS_ONPROC(p); 1231 OSBitOrAtomic(P_SUGID, &p->p_flag); 1232 proc_unlock(p); 1233 } 1234 break; 1235 } 1236 1237 /* Drop old proc reference or our extra reference */ 1238 kauth_cred_unref(&my_cred); 1239 1240 set_security_token(p); 1241 return (0); 1242} 1243 1244/* 1245 * setregid 1246 * 1247 * Description: Set real and effective group ID system call 1248 * 1249 * Parameters: uap->rgid real gid to set 1250 * uap->egid effective gid to set 1251 * 1252 * Returns: 0 Success 1253 * suser:EPERM Permission denied 1254 * 1255 * Notes: A value of -1 is a special case indicating that the gid for 1256 * which that value is specified not be changed. If both values 1257 * are specified as -1, no action is taken. 1258 * 1259 * If called by a privileged process, the real and effective gid 1260 * will be set to the new value(s) specified. 1261 * 1262 * If called from an unprivileged process, the real gid may be 1263 * set to the current value of the real gid, or to the current 1264 * value of the saved gid. The effective gid may be set to the 1265 * current value of any of the effective, real, or saved gid. 1266 * 1267 * If the new real and effective gid will not be equal, or the 1268 * new real or effective gid is not the same as the saved gid, 1269 * then the saved gid will be updated to reflect the new 1270 * effective gid (potentially unrecoverably dropping saved 1271 * privilege). 1272 * 1273 * If the credential is changed as a result of this call, then we 1274 * flag the process as having set privilege since the last exec. 1275 * 1276 * As an implementation detail, the effective gid is stored as 1277 * the first element of the supplementary group list, and 1278 * therefore the effective group list may be reordered to keep 1279 * the supplementary group list unchanged. 1280 */ 1281int 1282setregid(proc_t p, struct setregid_args *uap, __unused int32_t *retval) 1283{ 1284 gid_t rgid, egid; 1285 int error; 1286 kauth_cred_t my_cred, my_new_cred; 1287 posix_cred_t my_pcred; 1288 1289 DEBUG_CRED_ENTER("setregid %d %d\n", uap->rgid, uap->egid); 1290 1291 rgid = uap->rgid; 1292 egid = uap->egid; 1293 1294 if (rgid == (uid_t)-1) 1295 rgid = KAUTH_GID_NONE; 1296 if (egid == (uid_t)-1) 1297 egid = KAUTH_GID_NONE; 1298 AUDIT_ARG(egid, egid); 1299 AUDIT_ARG(rgid, rgid); 1300 1301 my_cred = kauth_cred_proc_ref(p); 1302 my_pcred = posix_cred_get(my_cred); 1303 1304 if (((rgid != KAUTH_UID_NONE && /* allow no change of rgid */ 1305 rgid != my_pcred->cr_rgid && /* allow rgid = rgid */ 1306 rgid != my_pcred->cr_gid && /* allow rgid = egid */ 1307 rgid != my_pcred->cr_svgid) || /* allow rgid = svgid */ 1308 (egid != KAUTH_UID_NONE && /* allow no change of egid */ 1309 egid != my_pcred->cr_groups[0] && /* allow no change of egid */ 1310 egid != my_pcred->cr_gid && /* allow egid = egid */ 1311 egid != my_pcred->cr_rgid && /* allow egid = rgid */ 1312 egid != my_pcred->cr_svgid)) && /* allow egid = svgid */ 1313 (error = suser(my_cred, &p->p_acflag))) { /* allow root user any */ 1314 kauth_cred_unref(&my_cred); 1315 return (error); 1316 } 1317 1318 /* get current credential and take a reference while we muck with it */ 1319 for (;;) { 1320 uid_t new_egid = my_pcred->cr_gid; 1321 uid_t new_rgid = my_pcred->cr_rgid; 1322 uid_t svgid = KAUTH_UID_NONE; 1323 1324 1325 /* 1326 * Set the credential with new info. If there is no change, 1327 * we get back the same credential we passed in; if there is 1328 * a change, we drop the reference on the credential we 1329 * passed in. The subsequent compare is safe, because it is 1330 * a pointer compare rather than a contents compare. 1331 */ 1332 if (egid == KAUTH_UID_NONE && my_pcred->cr_gid != egid) { 1333 /* changing the effective GID */ 1334 new_egid = egid; 1335 OSBitOrAtomic(P_SUGID, &p->p_flag); 1336 } 1337 if (rgid != KAUTH_UID_NONE && my_pcred->cr_rgid != rgid) { 1338 /* changing the real GID */ 1339 new_rgid = rgid; 1340 OSBitOrAtomic(P_SUGID, &p->p_flag); 1341 } 1342 /* 1343 * If the newly requested real gid or effective gid does 1344 * not match the saved gid, then set the saved gid to the 1345 * new effective gid. We are protected from escalation 1346 * by the prechecking. 1347 */ 1348 if (my_pcred->cr_svgid != uap->rgid && 1349 my_pcred->cr_svgid != uap->egid) { 1350 svgid = new_egid; 1351 OSBitOrAtomic(P_SUGID, &p->p_flag); 1352 } 1353 1354 my_new_cred = kauth_cred_setresgid(my_cred, rgid, egid, svgid); 1355 if (my_cred != my_new_cred) { 1356 1357 DEBUG_CRED_CHANGE("setregid(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_pcred->cr_flags, my_new_cred, posix_cred_get(my_new_cred)->cr_flags); 1358 1359 proc_lock(p); 1360 /* need to protect for a race where another thread 1361 * also changed the credential after we took our 1362 * reference. If p_ucred has changed then we 1363 * should restart this again with the new cred. 1364 */ 1365 if (p->p_ucred != my_cred) { 1366 proc_unlock(p); 1367 kauth_cred_unref(&my_new_cred); 1368 /* try again */ 1369 my_cred = kauth_cred_proc_ref(p); 1370 continue; 1371 } 1372 p->p_ucred = my_new_cred; 1373 /* update cred on proc */ 1374 PROC_UPDATE_CREDS_ONPROC(p); 1375 OSBitOrAtomic(P_SUGID, &p->p_flag); /* XXX redundant? */ 1376 proc_unlock(p); 1377 } 1378 break; 1379 } 1380 /* Drop old proc reference or our extra reference */ 1381 kauth_cred_unref(&my_cred); 1382 1383 set_security_token(p); 1384 return (0); 1385} 1386 1387 1388/* 1389 * Set the per-thread override identity. The first parameter can be the 1390 * current real UID, KAUTH_UID_NONE, or, if the caller is priviledged, it 1391 * can be any UID. If it is KAUTH_UID_NONE, then as a special case, this 1392 * means "revert to the per process credential"; otherwise, if permitted, 1393 * it changes the effective, real, and saved UIDs and GIDs for the current 1394 * thread to the requested UID and single GID, and clears all other GIDs. 1395 */ 1396int 1397settid(proc_t p, struct settid_args *uap, __unused int32_t *retval) 1398{ 1399 kauth_cred_t uc; 1400 struct uthread *uthread = get_bsdthread_info(current_thread()); 1401 uid_t uid; 1402 gid_t gid; 1403 1404 uid = uap->uid; 1405 gid = uap->gid; 1406 AUDIT_ARG(uid, uid); 1407 AUDIT_ARG(gid, gid); 1408 1409 if (proc_suser(p) != 0) 1410 return (EPERM); 1411 1412 if (uid == KAUTH_UID_NONE) { 1413 1414 /* must already be assuming another identity in order to revert back */ 1415 if ((uthread->uu_flag & UT_SETUID) == 0) 1416 return (EPERM); 1417 1418 /* revert to delayed binding of process credential */ 1419 uc = kauth_cred_proc_ref(p); 1420 kauth_cred_unref(&uthread->uu_ucred); 1421 uthread->uu_ucred = uc; 1422 uthread->uu_flag &= ~UT_SETUID; 1423 } else { 1424 kauth_cred_t my_cred, my_new_cred; 1425 1426 /* cannot already be assuming another identity */ 1427 if ((uthread->uu_flag & UT_SETUID) != 0) { 1428 return (EPERM); 1429 } 1430 1431 /* 1432 * Get a new credential instance from the old if this one 1433 * changes; otherwise kauth_cred_setuidgid() returns the 1434 * same credential. We take an extra reference on the 1435 * current credential while we muck with it, so we can do 1436 * the post-compare for changes by pointer. 1437 */ 1438 kauth_cred_ref(uthread->uu_ucred); 1439 my_cred = uthread->uu_ucred; 1440 my_new_cred = kauth_cred_setuidgid(my_cred, uid, gid); 1441 if (my_cred != my_new_cred) 1442 uthread->uu_ucred = my_new_cred; 1443 uthread->uu_flag |= UT_SETUID; 1444 1445 /* Drop old uthread reference or our extra reference */ 1446 kauth_cred_unref(&my_cred); 1447 } 1448 /* 1449 * XXX should potentially set per thread security token (there is 1450 * XXX none). 1451 * XXX it is unclear whether P_SUGID should be st at this point; 1452 * XXX in theory, it is being deprecated. 1453 */ 1454 return (0); 1455} 1456 1457 1458/* 1459 * Set the per-thread override identity. Use this system call for a thread to 1460 * assume the identity of another process or to revert back to normal identity 1461 * of the current process. 1462 * 1463 * When the "assume" argument is non zero the current thread will assume the 1464 * identity of the process represented by the pid argument. 1465 * 1466 * When the assume argument is zero we revert back to our normal identity. 1467 */ 1468int 1469settid_with_pid(proc_t p, struct settid_with_pid_args *uap, __unused int32_t *retval) 1470{ 1471 proc_t target_proc; 1472 struct uthread *uthread = get_bsdthread_info(current_thread()); 1473 kauth_cred_t my_cred, my_target_cred, my_new_cred; 1474 posix_cred_t my_target_pcred; 1475 1476 AUDIT_ARG(pid, uap->pid); 1477 AUDIT_ARG(value32, uap->assume); 1478 1479 if (proc_suser(p) != 0) { 1480 return (EPERM); 1481 } 1482 1483 /* 1484 * XXX should potentially set per thread security token (there is 1485 * XXX none). 1486 * XXX it is unclear whether P_SUGID should be st at this point; 1487 * XXX in theory, it is being deprecated. 1488 */ 1489 1490 /* 1491 * assume argument tells us to assume the identity of the process with the 1492 * id passed in the pid argument. 1493 */ 1494 if (uap->assume != 0) { 1495 /* can't do this if we have already assumed an identity */ 1496 if ((uthread->uu_flag & UT_SETUID) != 0) 1497 return (EPERM); 1498 1499 target_proc = proc_find(uap->pid); 1500 /* can't assume the identity of the kernel process */ 1501 if (target_proc == NULL || target_proc == kernproc) { 1502 if (target_proc!= NULL) 1503 proc_rele(target_proc); 1504 return (ESRCH); 1505 } 1506 1507 /* 1508 * Take a reference on the credential used in our target 1509 * process then use it as the identity for our current 1510 * thread. We take an extra reference on the current 1511 * credential while we muck with it, so we can do the 1512 * post-compare for changes by pointer. 1513 * 1514 * The post-compare is needed for the case that our process 1515 * credential has been changed to be identical to our thread 1516 * credential following our assumption of a per-thread one, 1517 * since the credential cache will maintain a unique instance. 1518 */ 1519 kauth_cred_ref(uthread->uu_ucred); 1520 my_cred = uthread->uu_ucred; 1521 my_target_cred = kauth_cred_proc_ref(target_proc); 1522 my_target_pcred = posix_cred_get(my_target_cred); 1523 my_new_cred = kauth_cred_setuidgid(my_cred, my_target_pcred->cr_uid, my_target_pcred->cr_gid); 1524 if (my_cred != my_new_cred) 1525 uthread->uu_ucred = my_new_cred; 1526 1527 uthread->uu_flag |= UT_SETUID; 1528 1529 /* Drop old uthread reference or our extra reference */ 1530 proc_rele(target_proc); 1531 kauth_cred_unref(&my_cred); 1532 kauth_cred_unref(&my_target_cred); 1533 1534 return (0); 1535 } 1536 1537 /* 1538 * Otherwise, we are reverting back to normal mode of operation where 1539 * delayed binding of the process credential sets the credential in 1540 * the thread (uu_ucred) 1541 */ 1542 if ((uthread->uu_flag & UT_SETUID) == 0) 1543 return (EPERM); 1544 1545 /* revert to delayed binding of process credential */ 1546 my_new_cred = kauth_cred_proc_ref(p); 1547 kauth_cred_unref(&uthread->uu_ucred); 1548 uthread->uu_ucred = my_new_cred; 1549 uthread->uu_flag &= ~UT_SETUID; 1550 1551 return (0); 1552} 1553 1554 1555/* 1556 * setgroups1 1557 * 1558 * Description: Internal implementation for both the setgroups and initgroups 1559 * system calls 1560 * 1561 * Parameters: gidsetsize Number of groups in set 1562 * gidset Pointer to group list 1563 * gmuid Base gid (initgroups only!) 1564 * 1565 * Returns: 0 Success 1566 * suser:EPERM Permision denied 1567 * EINVAL Invalid gidsetsize value 1568 * copyin:EFAULT Bad gidset or gidsetsize is 1569 * too large 1570 * 1571 * Notes: When called from a thread running under an assumed per-thread 1572 * identity, this function will operate against the per-thread 1573 * credential, rather than against the process credential. In 1574 * this specific case, the process credential is verified to 1575 * still be privileged at the time of the call, rather than the 1576 * per-thread credential for this operation to be permitted. 1577 * 1578 * This effectively means that setgroups/initigroups calls in 1579 * a thread running a per-thread credential should occur *after* 1580 * the settid call that created it, not before (unlike setuid, 1581 * which must be called after, since it will result in privilege 1582 * being dropped). 1583 * 1584 * When called normally (i.e. no per-thread assumed identity), 1585 * the per process credential is updated per POSIX. 1586 * 1587 * If the credential is changed as a result of this call, then we 1588 * flag the process as having set privilege since the last exec. 1589 */ 1590static int 1591setgroups1(proc_t p, u_int gidsetsize, user_addr_t gidset, uid_t gmuid, __unused int32_t *retval) 1592{ 1593 u_int ngrp; 1594 gid_t newgroups[NGROUPS] = { 0 }; 1595 int error; 1596 kauth_cred_t my_cred, my_new_cred; 1597 struct uthread *uthread = get_bsdthread_info(current_thread()); 1598 1599 DEBUG_CRED_ENTER("setgroups1 (%d/%d): %d 0x%016x %d\n", p->p_pid, (p->p_pptr ? p->p_pptr->p_pid : 0), gidsetsize, gidset, gmuid); 1600 1601 ngrp = gidsetsize; 1602 if (ngrp > NGROUPS) 1603 return (EINVAL); 1604 1605 if ( ngrp < 1 ) { 1606 ngrp = 1; 1607 } else { 1608 error = copyin(gidset, 1609 (caddr_t)newgroups, ngrp * sizeof(gid_t)); 1610 if (error) { 1611 return (error); 1612 } 1613 } 1614 1615 my_cred = kauth_cred_proc_ref(p); 1616 if ((error = suser(my_cred, &p->p_acflag))) { 1617 kauth_cred_unref(&my_cred); 1618 return (error); 1619 } 1620 1621 if ((uthread->uu_flag & UT_SETUID) != 0) { 1622#if DEBUG_CRED 1623 int my_cred_flags = uthread->uu_ucred->cr_flags; 1624#endif /* DEBUG_CRED */ 1625 kauth_cred_unref(&my_cred); 1626 1627 /* 1628 * If this thread is under an assumed identity, set the 1629 * supplementary grouplist on the thread credential instead 1630 * of the process one. If we were the only reference holder, 1631 * the credential is updated in place, otherwise, our reference 1632 * is dropped and we get back a different cred with a reference 1633 * already held on it. Because this is per-thread, we don't 1634 * need the referencing/locking/retry required for per-process. 1635 */ 1636 my_cred = uthread->uu_ucred; 1637 uthread->uu_ucred = kauth_cred_setgroups(my_cred, &newgroups[0], ngrp, gmuid); 1638#if DEBUG_CRED 1639 if (my_cred != uthread->uu_ucred) { 1640 DEBUG_CRED_CHANGE("setgroups1(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_cred_flags, uthread->uu_ucred , uthread->uu_ucred ->cr_flags); 1641 } 1642#endif /* DEBUG_CRED */ 1643 } else { 1644 1645 /* 1646 * get current credential and take a reference while we muck 1647 * with it 1648 */ 1649 for (;;) { 1650 /* 1651 * Set the credential with new info. If there is no 1652 * change, we get back the same credential we passed 1653 * in; if there is a change, we drop the reference on 1654 * the credential we passed in. The subsequent 1655 * compare is safe, because it is a pointer compare 1656 * rather than a contents compare. 1657 */ 1658 my_new_cred = kauth_cred_setgroups(my_cred, &newgroups[0], ngrp, gmuid); 1659 if (my_cred != my_new_cred) { 1660 1661 DEBUG_CRED_CHANGE("setgroups1(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_cred->cr_flags, my_new_cred, my_new_cred->cr_flags); 1662 1663 proc_lock(p); 1664 /* 1665 * We need to protect for a race where another 1666 * thread also changed the credential after we 1667 * took our reference. If p_ucred has 1668 * changed then we should restart this again 1669 * with the new cred. 1670 */ 1671 if (p->p_ucred != my_cred) { 1672 proc_unlock(p); 1673 kauth_cred_unref(&my_new_cred); 1674 my_cred = kauth_cred_proc_ref(p); 1675 /* try again */ 1676 continue; 1677 } 1678 p->p_ucred = my_new_cred; 1679 /* update cred on proc */ 1680 PROC_UPDATE_CREDS_ONPROC(p); 1681 OSBitOrAtomic(P_SUGID, &p->p_flag); 1682 proc_unlock(p); 1683 } 1684 break; 1685 } 1686 /* Drop old proc reference or our extra reference */ 1687 AUDIT_ARG(groupset, posix_cred_get(my_cred)->cr_groups, ngrp); 1688 kauth_cred_unref(&my_cred); 1689 1690 1691 set_security_token(p); 1692 } 1693 1694 return (0); 1695} 1696 1697 1698/* 1699 * initgroups 1700 * 1701 * Description: Initialize the default supplementary groups list and set the 1702 * gmuid for use by the external group resolver (if any) 1703 * 1704 * Parameters: uap->gidsetsize Number of groups in set 1705 * uap->gidset Pointer to group list 1706 * uap->gmuid Base gid 1707 * 1708 * Returns: 0 Success 1709 * setgroups1:EPERM Permision denied 1710 * setgroups1:EINVAL Invalid gidsetsize value 1711 * setgroups1:EFAULT Bad gidset or gidsetsize is 1712 * 1713 * Notes: This function opts *IN* to memberd participation 1714 * 1715 * The normal purpose of this function is for a privileged 1716 * process to indicate supplementary groups and identity for 1717 * participation in extended group membership resolution prior 1718 * to dropping privilege by assuming a specific user identity. 1719 * 1720 * It is the first half of the primary mechanism whereby user 1721 * identity is established to the system by programs such as 1722 * /usr/bin/login. The second half is the drop of uid privilege 1723 * for a specific uid corresponding to the user. 1724 * 1725 * See also: setgroups1() 1726 */ 1727int 1728initgroups(proc_t p, struct initgroups_args *uap, __unused int32_t *retval) 1729{ 1730 DEBUG_CRED_ENTER("initgroups\n"); 1731 1732 return(setgroups1(p, uap->gidsetsize, uap->gidset, uap->gmuid, retval)); 1733} 1734 1735 1736/* 1737 * setgroups 1738 * 1739 * Description: Initialize the default supplementary groups list 1740 * 1741 * Parameters: gidsetsize Number of groups in set 1742 * gidset Pointer to group list 1743 * 1744 * Returns: 0 Success 1745 * setgroups1:EPERM Permision denied 1746 * setgroups1:EINVAL Invalid gidsetsize value 1747 * setgroups1:EFAULT Bad gidset or gidsetsize is 1748 * 1749 * Notes: This functions opts *OUT* of memberd participation. 1750 * 1751 * This function exists for compatibility with POSIX. Most user 1752 * programs should use initgroups() instead to ensure correct 1753 * participation in group membership resolution when utilizing 1754 * a directory service for authentication. 1755 * 1756 * It is identical to an initgroups() call with a gmuid argument 1757 * of KAUTH_UID_NONE. 1758 * 1759 * See also: setgroups1() 1760 */ 1761int 1762setgroups(proc_t p, struct setgroups_args *uap, __unused int32_t *retval) 1763{ 1764 DEBUG_CRED_ENTER("setgroups\n"); 1765 1766 return(setgroups1(p, uap->gidsetsize, uap->gidset, KAUTH_UID_NONE, retval)); 1767} 1768 1769 1770/* 1771 * Set the per-thread/per-process supplementary groups list. 1772 * 1773 * XXX implement setsgroups 1774 * 1775 */ 1776 1777int 1778setsgroups(__unused proc_t p, __unused struct setsgroups_args *uap, __unused int32_t *retval) 1779{ 1780 return(ENOTSUP); 1781} 1782 1783/* 1784 * Set the per-thread/per-process whiteout groups list. 1785 * 1786 * XXX implement setwgroups 1787 * 1788 */ 1789 1790int 1791setwgroups(__unused proc_t p, __unused struct setwgroups_args *uap, __unused int32_t *retval) 1792{ 1793 return(ENOTSUP); 1794} 1795 1796 1797/* 1798 * Check if gid is a member of the group set. 1799 * 1800 * XXX This interface is going away; use kauth_cred_ismember_gid() directly 1801 * XXX instead. 1802 */ 1803int 1804groupmember(gid_t gid, kauth_cred_t cred) 1805{ 1806 int is_member; 1807 1808 if (kauth_cred_ismember_gid(cred, gid, &is_member) == 0 && is_member) 1809 return (1); 1810 return (0); 1811} 1812 1813 1814/* 1815 * Test whether the specified credentials imply "super-user" 1816 * privilege; if so, and we have accounting info, set the flag 1817 * indicating use of super-powers. 1818 * Returns 0 or error. 1819 * 1820 * XXX This interface is going away; use kauth_cred_issuser() directly 1821 * XXX instead. 1822 * 1823 * Note: This interface exists to implement the "has used privilege" 1824 * bit (ASU) in the p_acflags field of the process, which is 1825 * only externalized via private sysctl and in process accounting 1826 * records. The flag is technically not required in either case. 1827 */ 1828int 1829suser(kauth_cred_t cred, u_short *acflag) 1830{ 1831#if DIAGNOSTIC 1832 if (!IS_VALID_CRED(cred)) 1833 panic("suser"); 1834#endif 1835 if (kauth_cred_getuid(cred) == 0) { 1836 if (acflag) 1837 *acflag |= ASU; 1838 return (0); 1839 } 1840 return (EPERM); 1841} 1842 1843 1844/* 1845 * getlogin 1846 * 1847 * Description: Get login name, if available. 1848 * 1849 * Parameters: uap->namebuf User buffer for return 1850 * uap->namelen User buffer length 1851 * 1852 * Returns: 0 Success 1853 * copyout:EFAULT 1854 * 1855 * Notes: Intended to obtain a string containing the user name of the 1856 * user associated with the controlling terminal for the calling 1857 * process. 1858 * 1859 * Not very useful on modern systems, due to inherent length 1860 * limitations for the static array in the session structure 1861 * which is used to store the login name. 1862 * 1863 * Permitted to return NULL 1864 * 1865 * XXX: Belongs in kern_proc.c 1866 */ 1867int 1868getlogin(proc_t p, struct getlogin_args *uap, __unused int32_t *retval) 1869{ 1870 char buffer[MAXLOGNAME+1]; 1871 struct session * sessp; 1872 1873 bzero(buffer, MAXLOGNAME+1); 1874 1875 sessp = proc_session(p); 1876 1877 if (uap->namelen > MAXLOGNAME) 1878 uap->namelen = MAXLOGNAME; 1879 1880 if(sessp != SESSION_NULL) { 1881 session_lock(sessp); 1882 bcopy( sessp->s_login, buffer, uap->namelen); 1883 session_unlock(sessp); 1884 } 1885 session_rele(sessp); 1886 1887 return (copyout((caddr_t)buffer, uap->namebuf, uap->namelen)); 1888} 1889 1890 1891/* 1892 * setlogin 1893 * 1894 * Description: Set login name. 1895 * 1896 * Parameters: uap->namebuf User buffer containing name 1897 * 1898 * Returns: 0 Success 1899 * suser:EPERM Permission denied 1900 * copyinstr:EFAULT User buffer invalid 1901 * copyinstr:EINVAL Supplied name was too long 1902 * 1903 * Notes: This is a utility system call to support getlogin(). 1904 * 1905 * XXX: Belongs in kern_proc.c 1906 */ 1907int 1908setlogin(proc_t p, struct setlogin_args *uap, __unused int32_t *retval) 1909{ 1910 int error; 1911 size_t dummy=0; 1912 char buffer[MAXLOGNAME+1]; 1913 struct session * sessp; 1914 1915 if ((error = proc_suser(p))) 1916 return (error); 1917 1918 bzero(&buffer[0], MAXLOGNAME+1); 1919 1920 1921 error = copyinstr(uap->namebuf, 1922 (caddr_t) &buffer[0], 1923 MAXLOGNAME - 1, (size_t *)&dummy); 1924 1925 sessp = proc_session(p); 1926 1927 if (sessp != SESSION_NULL) { 1928 session_lock(sessp); 1929 bcopy(buffer, sessp->s_login, MAXLOGNAME); 1930 session_unlock(sessp); 1931 session_rele(sessp); 1932 } 1933 1934 1935 if (!error) { 1936 AUDIT_ARG(text, buffer); 1937 } else if (error == ENAMETOOLONG) 1938 error = EINVAL; 1939 return (error); 1940} 1941 1942 1943/* Set the secrity token of the task with current euid and eguid */ 1944/* 1945 * XXX This needs to change to give the task a reference and/or an opaque 1946 * XXX identifier. 1947 */ 1948int 1949set_security_token(proc_t p) 1950{ 1951 security_token_t sec_token; 1952 audit_token_t audit_token; 1953 kauth_cred_t my_cred; 1954 posix_cred_t my_pcred; 1955 host_priv_t host_priv; 1956 1957 /* 1958 * Don't allow a vfork child to override the parent's token settings 1959 * (since they share a task). Instead, the child will just have to 1960 * suffer along using the parent's token until the exec(). It's all 1961 * undefined behavior anyway, right? 1962 */ 1963 if (p->task == current_task()) { 1964 uthread_t uthread; 1965 uthread = (uthread_t)get_bsdthread_info(current_thread()); 1966 if (uthread->uu_flag & UT_VFORK) 1967 return (1); 1968 } 1969 1970 my_cred = kauth_cred_proc_ref(p); 1971 my_pcred = posix_cred_get(my_cred); 1972 1973 /* XXX mach_init doesn't have a p_ucred when it calls this function */ 1974 if (IS_VALID_CRED(my_cred)) { 1975 sec_token.val[0] = kauth_cred_getuid(my_cred); 1976 sec_token.val[1] = kauth_cred_getgid(my_cred); 1977 } else { 1978 sec_token.val[0] = 0; 1979 sec_token.val[1] = 0; 1980 } 1981 1982 /* 1983 * The current layout of the Mach audit token explicitly 1984 * adds these fields. But nobody should rely on such 1985 * a literal representation. Instead, the BSM library 1986 * provides a function to convert an audit token into 1987 * a BSM subject. Use of that mechanism will isolate 1988 * the user of the trailer from future representation 1989 * changes. 1990 */ 1991 audit_token.val[0] = my_cred->cr_audit.as_aia_p->ai_auid; 1992 audit_token.val[1] = my_pcred->cr_uid; 1993 audit_token.val[2] = my_pcred->cr_gid; 1994 audit_token.val[3] = my_pcred->cr_ruid; 1995 audit_token.val[4] = my_pcred->cr_rgid; 1996 audit_token.val[5] = p->p_pid; 1997 audit_token.val[6] = my_cred->cr_audit.as_aia_p->ai_asid; 1998 audit_token.val[7] = p->p_idversion; 1999 2000 host_priv = (sec_token.val[0]) ? HOST_PRIV_NULL : host_priv_self(); 2001#if CONFIG_MACF 2002 if (host_priv != HOST_PRIV_NULL && mac_system_check_host_priv(my_cred)) 2003 host_priv = HOST_PRIV_NULL; 2004#endif 2005 kauth_cred_unref(&my_cred); 2006 2007#if DEVELOPMENT || DEBUG 2008 /* 2009 * Update the pid an proc name for importance base if any 2010 */ 2011 task_importance_update_owner_info(p->task); 2012#endif 2013 2014 return (host_security_set_task_token(host_security_self(), 2015 p->task, 2016 sec_token, 2017 audit_token, 2018 host_priv) != KERN_SUCCESS); 2019} 2020 2021 2022/* 2023 * Fill in a struct xucred based on a kauth_cred_t. 2024 */ 2025__private_extern__ 2026void 2027cru2x(kauth_cred_t cr, struct xucred *xcr) 2028{ 2029 posix_cred_t pcr = posix_cred_get(cr); 2030 2031 bzero(xcr, sizeof(*xcr)); 2032 xcr->cr_version = XUCRED_VERSION; 2033 xcr->cr_uid = kauth_cred_getuid(cr); 2034 xcr->cr_ngroups = pcr->cr_ngroups; 2035 bcopy(pcr->cr_groups, xcr->cr_groups, sizeof(xcr->cr_groups)); 2036} 2037 2038#if CONFIG_LCTX 2039 2040/* 2041 * Set Login Context ID 2042 */ 2043/* 2044 * MPSAFE - assignment of (visible) process to context protected by ALLLCTX_LOCK, 2045 * LCTX by its own locks. 2046 */ 2047int 2048setlcid(proc_t p0, struct setlcid_args *uap, __unused int32_t *retval) 2049{ 2050 proc_t p; 2051 struct lctx *l; 2052 int error = 0; 2053 int refheld = 0; 2054 2055 AUDIT_ARG(pid, uap->pid); 2056 AUDIT_ARG(value32, uap->lcid); 2057 if (uap->pid == LCID_PROC_SELF) { /* Create/Join/Leave */ 2058 p = p0; 2059 } else { /* Adopt/Orphan */ 2060 p = proc_find(uap->pid); 2061 if (p == NULL) 2062 return (ESRCH); 2063 refheld = 1; 2064 } 2065 2066#if CONFIG_MACF 2067 error = mac_proc_check_setlcid(p0, p, uap->pid, uap->lcid); 2068 if (error) 2069 goto out; 2070#endif 2071 2072 switch (uap->lcid) { 2073 /* Leave/Orphan */ 2074 case LCID_REMOVE: 2075 2076 /* Only root may Leave/Orphan. */ 2077 if (!kauth_cred_issuser(kauth_cred_get())) { 2078 error = EPERM; 2079 goto out; 2080 } 2081 2082 /* Process not in login context. */ 2083 if (p->p_lctx == NULL) { 2084 error = ENOATTR; 2085 goto out; 2086 } 2087 2088 l = NULL; 2089 2090 break; 2091 2092 /* Create */ 2093 case LCID_CREATE: 2094 2095 /* Create only valid for self! */ 2096 if (uap->pid != LCID_PROC_SELF) { 2097 error = EPERM; 2098 goto out; 2099 } 2100 2101 /* Already in a login context. */ 2102 if (p->p_lctx != NULL) { 2103 error = EPERM; 2104 goto out; 2105 } 2106 2107 l = lccreate(); 2108 if (l == NULL) { 2109 error = ENOMEM; 2110 goto out; 2111 } 2112 2113 LCTX_LOCK(l); 2114 2115 break; 2116 2117 /* Join/Adopt */ 2118 default: 2119 2120 /* Only root may Join/Adopt. */ 2121 if (!kauth_cred_issuser(kauth_cred_get())) { 2122 error = EPERM; 2123 goto out; 2124 } 2125 2126 l = lcfind(uap->lcid); 2127 if (l == NULL) { 2128 error = ENOATTR; 2129 goto out; 2130 } 2131 2132 break; 2133 } 2134 2135 ALLLCTX_LOCK; 2136 leavelctx(p); 2137 enterlctx(p, l, (uap->lcid == LCID_CREATE) ? 1 : 0); 2138 ALLLCTX_UNLOCK; 2139 2140out: 2141 if (refheld != 0) 2142 proc_rele(p); 2143 return (error); 2144} 2145 2146/* 2147 * Get Login Context ID 2148 */ 2149/* 2150 * MPSAFE - membership of (visible) process in a login context 2151 * protected by the all-context lock. 2152 */ 2153int 2154getlcid(proc_t p0, struct getlcid_args *uap, int32_t *retval) 2155{ 2156 proc_t p; 2157 int error = 0; 2158 int refheld = 0; 2159 2160 AUDIT_ARG(pid, uap->pid); 2161 if (uap->pid == LCID_PROC_SELF) { 2162 p = p0; 2163 } else { 2164 p = proc_find(uap->pid); 2165 if (p == NULL) 2166 return (ESRCH); 2167 refheld = 1; 2168 } 2169 2170#if CONFIG_MACF 2171 error = mac_proc_check_getlcid(p0, p, uap->pid); 2172 if (error) 2173 goto out; 2174#endif 2175 ALLLCTX_LOCK; 2176 if (p->p_lctx == NULL) { 2177 error = ENOATTR; 2178 ALLLCTX_UNLOCK; 2179 goto out; 2180 } 2181 *retval = p->p_lctx->lc_id; 2182 ALLLCTX_UNLOCK; 2183 out: 2184 if (refheld != 0) 2185 proc_rele(p); 2186 2187 return (error); 2188} 2189#else /* LCTX */ 2190int 2191setlcid(proc_t p0, struct setlcid_args *uap, int32_t *retval) 2192{ 2193 2194 return (ENOSYS); 2195} 2196 2197int 2198getlcid(proc_t p0, struct getlcid_args *uap, int32_t *retval) 2199{ 2200 2201 return (ENOSYS); 2202} 2203#endif /* !LCTX */ 2204