2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
22 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
24 * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
25 * The Regents of the University of California. All rights reserved.
26 * (c) UNIX System Laboratories, Inc.
27 * All or some portions of this file are derived from material licensed
28 * to the University of California by American Telephone and Telegraph
29 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
30 * the permission of UNIX System Laboratories, Inc.
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * @(#)kern_prot.c 8.9 (Berkeley) 2/14/95
64 * System calls related to processes and protection
67 #include <sys/param.h>
69 #include <sys/systm.h>
70 #include <sys/ucred.h>
72 #include <sys/timeb.h>
73 #include <sys/times.h>
74 #include <sys/malloc.h>
76 #include <bsm/audit_kernel.h>
78 #include <sys/mount.h>
79 #include <mach/message.h>
80 #include <mach/host_security.h>
82 #include <kern/host.h>
85 * setprivexec: (dis)allow this process to hold
86 * task, thread, or execption ports of processes about to exec.
88 struct setprivexec_args
{
92 setprivexec(p
, uap
, retval
)
94 register struct setprivexec_args
*uap
;
97 AUDIT_ARG(value
, uap
->flag
);
98 *retval
= p
->p_debugger
;
99 p
->p_debugger
= (uap
->flag
!= 0);
104 getpid(p
, uap
, retval
)
112 retval
[1] = p
->p_pptr
->p_pid
;
118 getppid(p
, uap
, retval
)
124 *retval
= p
->p_pptr
->p_pid
;
128 /* Get process group ID; note that POSIX getpgrp takes no parameter */
129 getpgrp(p
, uap
, retval
)
135 *retval
= p
->p_pgrp
->pg_id
;
139 /* Get an arbitary pid's process group id */
140 struct getpgid_args
{
145 getpgid(p
, uap
, retval
)
147 struct getpgid_args
*uap
;
156 if ((pt
= pfind(uap
->pid
)) == 0)
159 *retval
= pt
->p_pgrp
->pg_id
;
164 * Get an arbitary pid's session id.
171 getsid(p
, uap
, retval
)
173 struct getsid_args
*uap
;
182 if ((pt
= pfind(uap
->pid
)) == 0)
185 *retval
= pt
->p_session
->s_sid
;
190 getuid(p
, uap
, retval
)
196 *retval
= p
->p_cred
->p_ruid
;
198 retval
[1] = p
->p_ucred
->cr_uid
;
204 geteuid(p
, uap
, retval
)
210 *retval
= p
->p_ucred
->cr_uid
;
215 getgid(p
, uap
, retval
)
221 *retval
= p
->p_cred
->p_rgid
;
223 retval
[1] = p
->p_ucred
->cr_groups
[0];
229 * Get effective group ID. The "egid" is groups[0], and could be obtained
230 * via getgroups. This syscall exists because it is somewhat painful to do
231 * correctly in a library function.
234 getegid(p
, uap
, retval
)
240 *retval
= p
->p_ucred
->cr_groups
[0];
244 struct getgroups_args
{
248 getgroups(p
, uap
, retval
)
250 register struct getgroups_args
*uap
;
253 register struct pcred
*pc
= p
->p_cred
;
257 if ((ngrp
= uap
->gidsetsize
) == 0) {
258 *retval
= pc
->pc_ucred
->cr_ngroups
;
261 if (ngrp
< pc
->pc_ucred
->cr_ngroups
)
264 ngrp
= pc
->pc_ucred
->cr_ngroups
;
265 if (error
= copyout((caddr_t
)pc
->pc_ucred
->cr_groups
,
266 (caddr_t
)uap
->gidset
, ngrp
* sizeof(gid_t
))) {
276 setsid(p
, uap
, retval
)
277 register struct proc
*p
;
282 if (p
->p_pgid
== p
->p_pid
|| pgfind(p
->p_pid
) || p
->p_flag
& P_INVFORK
) {
285 (void)enterpgrp(p
, p
->p_pid
, 1);
292 * set process group (setpgid/old setpgrp)
294 * caller does setpgid(targpid, targpgid)
296 * pid must be caller or child of caller (ESRCH)
298 * pid must be in same session (EPERM)
299 * pid can't have done an exec (EACCES)
301 * there must exist some pid in same session having pgid (EPERM)
302 * pid must not be session leader (EPERM)
304 struct setpgid_args
{
309 setpgid(curp
, uap
, retval
)
311 register struct setpgid_args
*uap
;
314 register struct proc
*targp
; /* target process */
315 register struct pgrp
*pgrp
; /* target pgrp */
317 if (uap
->pid
!= 0 && uap
->pid
!= curp
->p_pid
) {
318 if ((targp
= pfind(uap
->pid
)) == 0 || !inferior(targp
))
320 if (targp
->p_session
!= curp
->p_session
)
322 if (targp
->p_flag
& P_EXEC
)
326 if (SESS_LEADER(targp
))
329 uap
->pgid
= targp
->p_pid
;
330 else if (uap
->pgid
!= targp
->p_pid
)
331 if ((pgrp
= pgfind(uap
->pgid
)) == 0 ||
332 pgrp
->pg_session
!= curp
->p_session
)
334 return (enterpgrp(targp
, uap
->pgid
, 0));
337 struct issetugid_args
{
340 issetugid(p
, uap
, retval
)
342 struct issetugid_args
*uap
;
346 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
347 * we use P_SUGID because we consider changing the owners as
348 * "tainting" as well.
349 * This is significant for procs that start as root and "become"
350 * a user without an exec - programs cannot know *everything*
351 * that libc *might* have put in their data segment.
354 *retval
= (p
->p_flag
& P_SUGID
) ? 1 : 0;
362 setuid(p
, uap
, retval
)
364 struct setuid_args
*uap
;
367 register struct pcred
*pc
= p
->p_cred
;
372 AUDIT_ARG(uid
, uid
, 0, 0, 0);
373 if (uid
!= pc
->p_ruid
&&
374 (error
= suser(pc
->pc_ucred
, &p
->p_acflag
)))
377 * Everything's okay, do it.
378 * Transfer proc count to new user.
379 * Copy credentials so other references do not see our changes.
382 /* prepare app access profile files */
383 prepare_profile_database(uap
->uid
);
385 (void)chgproccnt(pc
->p_ruid
, -1);
386 (void)chgproccnt(uid
, 1);
387 pc
->pc_ucred
= crcopy(pc
->pc_ucred
);
388 pc
->pc_ucred
->cr_uid
= uid
;
392 set_security_token(p
);
393 p
->p_flag
|= P_SUGID
;
397 struct seteuid_args
{
401 seteuid(p
, uap
, retval
)
403 struct seteuid_args
*uap
;
406 register struct pcred
*pc
= p
->p_cred
;
411 AUDIT_ARG(uid
, 0, euid
, 0, 0);
412 if (euid
!= pc
->p_ruid
&& euid
!= pc
->p_svuid
&&
413 (error
= suser(pc
->pc_ucred
, &p
->p_acflag
)))
416 * Everything's okay, do it. Copy credentials so other references do
417 * not see our changes.
420 pc
->pc_ucred
= crcopy(pc
->pc_ucred
);
421 pc
->pc_ucred
->cr_uid
= euid
;
423 set_security_token(p
);
424 p
->p_flag
|= P_SUGID
;
432 setgid(p
, uap
, retval
)
434 struct setgid_args
*uap
;
437 register struct pcred
*pc
= p
->p_cred
;
442 AUDIT_ARG(gid
, gid
, 0, 0, 0);
443 if (gid
!= pc
->p_rgid
&& (error
= suser(pc
->pc_ucred
, &p
->p_acflag
)))
446 pc
->pc_ucred
= crcopy(pc
->pc_ucred
);
447 pc
->pc_ucred
->cr_groups
[0] = gid
;
449 pc
->p_svgid
= gid
; /* ??? */
451 set_security_token(p
);
452 p
->p_flag
|= P_SUGID
;
456 struct setegid_args
{
460 setegid(p
, uap
, retval
)
462 struct setegid_args
*uap
;
465 register struct pcred
*pc
= p
->p_cred
;
470 AUDIT_ARG(gid
, 0, egid
, 0, 0);
471 if (egid
!= pc
->p_rgid
&& egid
!= pc
->p_svgid
&&
472 (error
= suser(pc
->pc_ucred
, &p
->p_acflag
)))
475 pc
->pc_ucred
= crcopy(pc
->pc_ucred
);
476 pc
->pc_ucred
->cr_groups
[0] = egid
;
478 set_security_token(p
);
479 p
->p_flag
|= P_SUGID
;
483 struct setgroups_args
{
489 setgroups(p
, uap
, retval
)
491 struct setgroups_args
*uap
;
494 register struct pcred
*pc
= p
->p_cred
;
495 struct ucred
*new, *old
;
499 if (error
= suser(pc
->pc_ucred
, &p
->p_acflag
))
501 ngrp
= uap
->gidsetsize
;
510 error
= copyin((caddr_t
)uap
->gidset
,
511 (caddr_t
)new->cr_groups
, ngrp
* sizeof(gid_t
));
517 new->cr_ngroups
= ngrp
;
518 AUDIT_ARG(groupset
, new->cr_groups
, ngrp
);
521 new->cr_uid
= old
->cr_uid
;
524 set_security_token(p
);
525 p
->p_flag
|= P_SUGID
;
532 struct osetreuid_args
{
537 osetreuid(p
, uap
, retval
)
538 register struct proc
*p
;
539 struct osetreuid_args
*uap
;
542 struct seteuid_args seuidargs
;
543 struct setuid_args suidargs
;
546 * There are five cases, and we attempt to emulate them in
547 * the following fashion:
548 * -1, -1: return 0. This is correct emulation.
549 * -1, N: call seteuid(N). This is correct emulation.
550 * N, -1: if we called setuid(N), our euid would be changed
551 * to N as well. the theory is that we don't want to
552 * revoke root access yet, so we call seteuid(N)
553 * instead. This is incorrect emulation, but often
554 * suffices enough for binary compatibility.
555 * N, N: call setuid(N). This is correct emulation.
556 * N, M: call setuid(N). This is close to correct emulation.
558 if (uap
->ruid
== (uid_t
)-1) {
559 if (uap
->euid
== (uid_t
)-1)
560 return (0); /* -1, -1 */
561 seuidargs
.euid
= uap
->euid
; /* -1, N */
562 return (seteuid(p
, &seuidargs
, retval
));
564 if (uap
->euid
== (uid_t
)-1) {
565 seuidargs
.euid
= uap
->ruid
; /* N, -1 */
566 return (seteuid(p
, &seuidargs
, retval
));
568 suidargs
.uid
= uap
->ruid
; /* N, N and N, M */
569 return (setuid(p
, &suidargs
, retval
));
572 struct osetregid_args
{
577 osetregid(p
, uap
, retval
)
578 register struct proc
*p
;
579 struct osetregid_args
*uap
;
582 struct setegid_args segidargs
;
583 struct setgid_args sgidargs
;
586 * There are five cases, described above in osetreuid()
588 if (uap
->rgid
== (gid_t
)-1) {
589 if (uap
->egid
== (gid_t
)-1)
590 return (0); /* -1, -1 */
591 segidargs
.egid
= uap
->egid
; /* -1, N */
592 return (setegid(p
, &segidargs
, retval
));
594 if (uap
->egid
== (gid_t
)-1) {
595 segidargs
.egid
= uap
->rgid
; /* N, -1 */
596 return (setegid(p
, &segidargs
, retval
));
598 sgidargs
.gid
= uap
->rgid
; /* N, N and N, M */
599 return (setgid(p
, &sgidargs
, retval
));
601 #endif /* COMPAT_43 */
604 * Check if gid is a member of the group set.
606 groupmember(gid
, cred
)
608 register struct ucred
*cred
;
613 egp
= &(cred
->cr_groups
[cred
->cr_ngroups
]);
614 for (gp
= cred
->cr_groups
; gp
< egp
; gp
++)
621 * Test whether the specified credentials imply "super-user"
622 * privilege; if so, and we have accounting info, set the flag
623 * indicating use of super-powers.
624 * Returns 0 or error.
631 if (cred
== NOCRED
|| cred
== FSCRED
)
634 if (cred
->cr_uid
== 0) {
645 struct proc
*p
= current_proc();
650 return (suser(p
->p_ucred
, &p
->p_acflag
) == 0);
656 struct proc
*p
= current_proc();
661 return (suser(p
->p_ucred
, &p
->p_acflag
) == 0 ||
662 p
->p_cred
->p_ruid
== 0 || p
->p_cred
->p_svuid
== 0);
666 * Allocate a zeroed cred structure.
671 register struct ucred
*cr
;
673 MALLOC_ZONE(cr
, struct ucred
*, sizeof(*cr
), M_CRED
, M_WAITOK
);
674 bzero((caddr_t
)cr
, sizeof(*cr
));
680 * Free a cred structure.
681 * Throws away space when ref count gets to 0.
688 if (cr
== NOCRED
|| cr
== FSCRED
)
691 if (--cr
->cr_ref
== 0)
692 FREE_ZONE((caddr_t
)cr
, sizeof *cr
, M_CRED
);
696 * Copy cred structure to a new one and free the old one.
705 if (cr
== NOCRED
|| cr
== FSCRED
)
718 * Dup cred struct to a new held one.
727 if (cr
== NOCRED
|| cr
== FSCRED
)
737 * compare two cred structs
748 if (cr1
== NOCRED
|| cr1
== FSCRED
||
749 cr2
== NOCRED
|| cr2
== FSCRED
)
751 if (cr1
->cr_uid
!= cr2
->cr_uid
)
753 if (cr1
->cr_ngroups
!= cr2
->cr_ngroups
)
755 // XXX assumes groups will always be listed in some order
756 for (i
=0; i
< cr1
->cr_ngroups
; i
++)
757 if (cr1
->cr_groups
[i
] != cr2
->cr_groups
[i
])
763 * Get login name, if available.
765 struct getlogin_args
{
770 getlogin(p
, uap
, retval
)
772 struct getlogin_args
*uap
;
776 if (uap
->namelen
> sizeof (p
->p_pgrp
->pg_session
->s_login
))
777 uap
->namelen
= sizeof (p
->p_pgrp
->pg_session
->s_login
);
778 return (copyout((caddr_t
) p
->p_pgrp
->pg_session
->s_login
,
779 (caddr_t
)uap
->namebuf
, uap
->namelen
));
785 struct setlogin_args
{
789 setlogin(p
, uap
, retval
)
791 struct setlogin_args
*uap
;
797 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
800 error
= copyinstr((caddr_t
) uap
->namebuf
,
801 (caddr_t
) p
->p_pgrp
->pg_session
->s_login
,
802 sizeof (p
->p_pgrp
->pg_session
->s_login
) - 1, (size_t *)&dummy
);
804 AUDIT_ARG(text
, p
->p_pgrp
->pg_session
->s_login
);
805 else if (error
== ENAMETOOLONG
)
811 /* Set the secrity token of the task with current euid and eguid */
813 set_security_token(struct proc
* p
)
815 security_token_t sec_token
;
816 audit_token_t audit_token
;
818 sec_token
.val
[0] = p
->p_ucred
->cr_uid
;
819 sec_token
.val
[1] = p
->p_ucred
->cr_gid
;
822 * The current layout of the Mach audit token explicitly
823 * adds these fields. But nobody should rely on such
824 * a literal representation. Instead, the BSM library
825 * provides a function to convert an audit token into
826 * a BSM subject. Use of that mechanism will isolate
827 * the user of the trailer from future representation
830 audit_token
.val
[0] = p
->p_au
->ai_auid
;
831 audit_token
.val
[1] = p
->p_ucred
->cr_uid
;
832 audit_token
.val
[2] = p
->p_ucred
->cr_gid
;
833 audit_token
.val
[3] = p
->p_cred
->p_ruid
;
834 audit_token
.val
[4] = p
->p_cred
->p_rgid
;
835 audit_token
.val
[5] = p
->p_pid
;
836 audit_token
.val
[6] = p
->p_au
->ai_asid
;
837 audit_token
.val
[7] = p
->p_au
->ai_termid
.port
;
839 return host_security_set_task_token(host_security_self(),
850 * Fill in a struct xucred based on a struct ucred.
854 cru2x(struct ucred
*cr
, struct xucred
*xcr
)
857 bzero(xcr
, sizeof(*xcr
));
858 xcr
->cr_version
= XUCRED_VERSION
;
859 xcr
->cr_uid
= cr
->cr_uid
;
860 xcr
->cr_ngroups
= cr
->cr_ngroups
;
861 bcopy(cr
->cr_groups
, xcr
->cr_groups
, sizeof(xcr
->cr_groups
));