]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_prot.c
xnu-344.tar.gz
[apple/xnu.git] / bsd / kern / kern_prot.c
CommitLineData
1c79356b 1/*
9bccf70c 2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
1c79356b
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
23/*
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.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
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.
47 *
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
58 * SUCH DAMAGE.
59 *
60 * @(#)kern_prot.c 8.9 (Berkeley) 2/14/95
61 */
62
63/*
64 * System calls related to processes and protection
65 */
66
67#include <sys/param.h>
68#include <sys/acct.h>
69#include <sys/systm.h>
70#include <sys/ucred.h>
71#include <sys/proc.h>
72#include <sys/timeb.h>
73#include <sys/times.h>
74#include <sys/malloc.h>
75
76#include <sys/mount.h>
77#include <mach/message.h>
9bccf70c
A
78#include <mach/host_security.h>
79
1c79356b
A
80#include <kern/host.h>
81
82/*
83 * setprivexec: (dis)allow this process to hold
84 * task, thread, or execption ports of processes about to exec.
85 */
86struct setprivexec_args {
87 int flag;
88};
89int
90setprivexec(p, uap, retval)
91 struct proc *p;
92 register struct setprivexec_args *uap;
93 register_t *retval;
94{
95 *retval = p->p_debugger;
96 p->p_debugger = (uap->flag != 0);
97 return(0);
98}
99
100/* ARGSUSED */
101getpid(p, uap, retval)
102 struct proc *p;
103 void *uap;
104 register_t *retval;
105{
106
107 *retval = p->p_pid;
108#if COMPAT_43
109 retval[1] = p->p_pptr->p_pid;
110#endif
111 return (0);
112}
113
114/* ARGSUSED */
115getppid(p, uap, retval)
116 struct proc *p;
117 void *uap;
118 register_t *retval;
119{
120
121 *retval = p->p_pptr->p_pid;
122 return (0);
123}
124
125/* Get process group ID; note that POSIX getpgrp takes no parameter */
126getpgrp(p, uap, retval)
127 struct proc *p;
128 void *uap;
129 register_t *retval;
130{
131
132 *retval = p->p_pgrp->pg_id;
133 return (0);
134}
135
9bccf70c
A
136/* Get an arbitary pid's process group id */
137struct getpgid_args {
138 pid_t pid;
139};
140
141int
142getpgid(p, uap, retval)
143 struct proc *p;
144 struct getpgid_args *uap;
145 register_t *retval;
146{
147 struct proc *pt;
148
149 pt = p;
150 if (uap->pid == 0)
151 goto found;
152
153 if ((pt = pfind(uap->pid)) == 0)
154 return (ESRCH);
155found:
156 *retval = pt->p_pgrp->pg_id;
157 return (0);
158}
159
160/*
161 * Get an arbitary pid's session id.
162 */
163struct getsid_args {
164 pid_t pid;
165};
166
167int
168getsid(p, uap, retval)
169 struct proc *p;
170 struct getsid_args *uap;
171 register_t *retval;
172{
173 struct proc *pt;
174
175 pt = p;
176 if (uap->pid == 0)
177 goto found;
178
179 if ((pt = pfind(uap->pid)) == 0)
180 return (ESRCH);
181found:
182 *retval = pt->p_session->s_sid;
183 return (0);
184}
185
1c79356b
A
186/* ARGSUSED */
187getuid(p, uap, retval)
188 struct proc *p;
189 void *uap;
190 register_t *retval;
191{
192
193 *retval = p->p_cred->p_ruid;
194#if COMPAT_43
195 retval[1] = p->p_ucred->cr_uid;
196#endif
197 return (0);
198}
199
200/* ARGSUSED */
201geteuid(p, uap, retval)
202 struct proc *p;
203 void *uap;
204 register_t *retval;
205{
206
207 *retval = p->p_ucred->cr_uid;
208 return (0);
209}
210
211/* ARGSUSED */
212getgid(p, uap, retval)
213 struct proc *p;
214 void *uap;
215 register_t *retval;
216{
217
218 *retval = p->p_cred->p_rgid;
219#if COMPAT_43
220 retval[1] = p->p_ucred->cr_groups[0];
221#endif
222 return (0);
223}
224
225/*
226 * Get effective group ID. The "egid" is groups[0], and could be obtained
227 * via getgroups. This syscall exists because it is somewhat painful to do
228 * correctly in a library function.
229 */
230/* ARGSUSED */
231getegid(p, uap, retval)
232 struct proc *p;
233 void *uap;
234 register_t *retval;
235{
236
237 *retval = p->p_ucred->cr_groups[0];
238 return (0);
239}
240
241struct getgroups_args {
242 u_int gidsetsize;
243 gid_t *gidset;
244};
245getgroups(p, uap, retval)
246 struct proc *p;
247 register struct getgroups_args *uap;
248 register_t *retval;
249{
250 register struct pcred *pc = p->p_cred;
251 register u_int ngrp;
252 int error;
253
254 if ((ngrp = uap->gidsetsize) == 0) {
255 *retval = pc->pc_ucred->cr_ngroups;
256 return (0);
257 }
258 if (ngrp < pc->pc_ucred->cr_ngroups)
259 return (EINVAL);
260 pcred_readlock(p);
261 ngrp = pc->pc_ucred->cr_ngroups;
262 if (error = copyout((caddr_t)pc->pc_ucred->cr_groups,
263 (caddr_t)uap->gidset, ngrp * sizeof(gid_t))) {
264 pcred_unlock(p);
265 return (error);
266 }
267 pcred_unlock(p);
268 *retval = ngrp;
269 return (0);
270}
271
272/* ARGSUSED */
273setsid(p, uap, retval)
274 register struct proc *p;
275 void *uap;
276 register_t *retval;
277{
278
279 if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
280 return (EPERM);
281 } else {
282 (void)enterpgrp(p, p->p_pid, 1);
283 *retval = p->p_pid;
284 return (0);
285 }
286}
287
288/*
289 * set process group (setpgid/old setpgrp)
290 *
291 * caller does setpgid(targpid, targpgid)
292 *
293 * pid must be caller or child of caller (ESRCH)
294 * if a child
295 * pid must be in same session (EPERM)
296 * pid can't have done an exec (EACCES)
297 * if pgid != pid
298 * there must exist some pid in same session having pgid (EPERM)
299 * pid must not be session leader (EPERM)
300 */
301struct setpgid_args {
302 int pid;
303 int pgid;
304};
305/* ARGSUSED */
306setpgid(curp, uap, retval)
307 struct proc *curp;
308 register struct setpgid_args *uap;
309 register_t *retval;
310{
311 register struct proc *targp; /* target process */
312 register struct pgrp *pgrp; /* target pgrp */
313
314 if (uap->pid != 0 && uap->pid != curp->p_pid) {
315 if ((targp = pfind(uap->pid)) == 0 || !inferior(targp))
316 return (ESRCH);
317 if (targp->p_session != curp->p_session)
318 return (EPERM);
319 if (targp->p_flag & P_EXEC)
320 return (EACCES);
321 } else
322 targp = curp;
323 if (SESS_LEADER(targp))
324 return (EPERM);
325 if (uap->pgid == 0)
326 uap->pgid = targp->p_pid;
327 else if (uap->pgid != targp->p_pid)
328 if ((pgrp = pgfind(uap->pgid)) == 0 ||
329 pgrp->pg_session != curp->p_session)
330 return (EPERM);
331 return (enterpgrp(targp, uap->pgid, 0));
332}
333
0b4e3aa0
A
334struct issetugid_args {
335 int dummy;
336};
337issetugid(p, uap, retval)
338 struct proc *p;
339 struct issetugid_args *uap;
340 register_t *retval;
341{
342 /*
343 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
344 * we use P_SUGID because we consider changing the owners as
345 * "tainting" as well.
346 * This is significant for procs that start as root and "become"
347 * a user without an exec - programs cannot know *everything*
348 * that libc *might* have put in their data segment.
349 */
350
351 *retval = (p->p_flag & P_SUGID) ? 1 : 0;
352 return (0);
353}
354
1c79356b
A
355struct setuid_args {
356 uid_t uid;
357};
358/* ARGSUSED */
359setuid(p, uap, retval)
360 struct proc *p;
361 struct setuid_args *uap;
362 register_t *retval;
363{
364 register struct pcred *pc = p->p_cred;
365 register uid_t uid;
366 int error;
367
368 uid = uap->uid;
369 if (uid != pc->p_ruid &&
370 (error = suser(pc->pc_ucred, &p->p_acflag)))
371 return (error);
372 /*
373 * Everything's okay, do it.
374 * Transfer proc count to new user.
375 * Copy credentials so other references do not see our changes.
376 */
9bccf70c
A
377
378 /* prepare app access profile files */
379 prepare_profile_database(uap->uid);
1c79356b
A
380 pcred_writelock(p);
381 (void)chgproccnt(pc->p_ruid, -1);
382 (void)chgproccnt(uid, 1);
383 pc->pc_ucred = crcopy(pc->pc_ucred);
384 pc->pc_ucred->cr_uid = uid;
385 pc->p_ruid = uid;
386 pc->p_svuid = uid;
387 pcred_unlock(p);
388 set_security_token(p);
389 p->p_flag |= P_SUGID;
390 return (0);
391}
392
393struct seteuid_args {
394 uid_t euid;
395};
396/* ARGSUSED */
397seteuid(p, uap, retval)
398 struct proc *p;
399 struct seteuid_args *uap;
400 register_t *retval;
401{
402 register struct pcred *pc = p->p_cred;
403 register uid_t euid;
404 int error;
405
406 euid = uap->euid;
407 if (euid != pc->p_ruid && euid != pc->p_svuid &&
408 (error = suser(pc->pc_ucred, &p->p_acflag)))
409 return (error);
410 /*
411 * Everything's okay, do it. Copy credentials so other references do
412 * not see our changes.
413 */
414 pcred_writelock(p);
415 pc->pc_ucred = crcopy(pc->pc_ucred);
416 pc->pc_ucred->cr_uid = euid;
417 pcred_unlock(p);
418 set_security_token(p);
419 p->p_flag |= P_SUGID;
420 return (0);
421}
422
423struct setgid_args {
424 gid_t gid;
425};
426/* ARGSUSED */
427setgid(p, uap, retval)
428 struct proc *p;
429 struct setgid_args *uap;
430 register_t *retval;
431{
432 register struct pcred *pc = p->p_cred;
433 register gid_t gid;
434 int error;
435
436 gid = uap->gid;
437 if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag)))
438 return (error);
439 pcred_writelock(p);
440 pc->pc_ucred = crcopy(pc->pc_ucred);
441 pc->pc_ucred->cr_groups[0] = gid;
442 pc->p_rgid = gid;
443 pc->p_svgid = gid; /* ??? */
444 pcred_unlock(p);
445 set_security_token(p);
446 p->p_flag |= P_SUGID;
447 return (0);
448}
449
450struct setegid_args {
451 gid_t egid;
452};
453/* ARGSUSED */
454setegid(p, uap, retval)
455 struct proc *p;
456 struct setegid_args *uap;
457 register_t *retval;
458{
459 register struct pcred *pc = p->p_cred;
460 register gid_t egid;
461 int error;
462
463 egid = uap->egid;
464 if (egid != pc->p_rgid && egid != pc->p_svgid &&
465 (error = suser(pc->pc_ucred, &p->p_acflag)))
466 return (error);
467 pcred_writelock(p);
468 pc->pc_ucred = crcopy(pc->pc_ucred);
469 pc->pc_ucred->cr_groups[0] = egid;
470 pcred_unlock(p);
471 set_security_token(p);
472 p->p_flag |= P_SUGID;
473 return (0);
474}
475
476struct setgroups_args{
477 u_int gidsetsize;
478 gid_t *gidset;
479};
480
481/* ARGSUSED */
482setgroups(p, uap, retval)
483 struct proc *p;
484 struct setgroups_args *uap;
485 register_t *retval;
486{
487 register struct pcred *pc = p->p_cred;
488 struct ucred *new, *old;
489 register u_int ngrp;
490 int error;
491
492 if (error = suser(pc->pc_ucred, &p->p_acflag))
493 return (error);
494 ngrp = uap->gidsetsize;
495 if (ngrp < 1 || ngrp > NGROUPS)
496 return (EINVAL);
497 new = crget();
498 error = copyin((caddr_t)uap->gidset,
499 (caddr_t)new->cr_groups, ngrp * sizeof(gid_t));
500 if (error) {
501 crfree(new);
502 return (error);
503 }
504 new->cr_ngroups = ngrp;
505 pcred_writelock(p);
506 old = pc->pc_ucred;
507 new->cr_uid = old->cr_uid;
508 pc->pc_ucred = new;
509 pcred_unlock(p);
510 set_security_token(p);
511 p->p_flag |= P_SUGID;
512 if (old != NOCRED)
513 crfree(old);
514 return (0);
515}
516
517#if COMPAT_43
518struct osetreuid_args{
519 int ruid;
520 int euid;
521};
522/* ARGSUSED */
523osetreuid(p, uap, retval)
524 register struct proc *p;
525 struct osetreuid_args *uap;
526 register_t *retval;
527{
528 struct seteuid_args seuidargs;
529 struct setuid_args suidargs;
530
531 /*
532 * There are five cases, and we attempt to emulate them in
533 * the following fashion:
534 * -1, -1: return 0. This is correct emulation.
535 * -1, N: call seteuid(N). This is correct emulation.
536 * N, -1: if we called setuid(N), our euid would be changed
537 * to N as well. the theory is that we don't want to
538 * revoke root access yet, so we call seteuid(N)
539 * instead. This is incorrect emulation, but often
540 * suffices enough for binary compatibility.
541 * N, N: call setuid(N). This is correct emulation.
542 * N, M: call setuid(N). This is close to correct emulation.
543 */
544 if (uap->ruid == (uid_t)-1) {
545 if (uap->euid == (uid_t)-1)
546 return (0); /* -1, -1 */
547 seuidargs.euid = uap->euid; /* -1, N */
548 return (seteuid(p, &seuidargs, retval));
549 }
550 if (uap->euid == (uid_t)-1) {
551 seuidargs.euid = uap->ruid; /* N, -1 */
552 return (seteuid(p, &seuidargs, retval));
553 }
554 suidargs.uid = uap->ruid; /* N, N and N, M */
555 return (setuid(p, &suidargs, retval));
556}
557
558struct osetregid_args {
559 int rgid;
560 int egid;
561};
562/* ARGSUSED */
563osetregid(p, uap, retval)
564 register struct proc *p;
565 struct osetregid_args *uap;
566 register_t *retval;
567{
568 struct setegid_args segidargs;
569 struct setgid_args sgidargs;
570
571 /*
572 * There are five cases, described above in osetreuid()
573 */
574 if (uap->rgid == (gid_t)-1) {
575 if (uap->egid == (gid_t)-1)
576 return (0); /* -1, -1 */
577 segidargs.egid = uap->egid; /* -1, N */
578 return (setegid(p, &segidargs, retval));
579 }
580 if (uap->egid == (gid_t)-1) {
581 segidargs.egid = uap->rgid; /* N, -1 */
582 return (setegid(p, &segidargs, retval));
583 }
584 sgidargs.gid = uap->rgid; /* N, N and N, M */
585 return (setgid(p, &sgidargs, retval));
586}
587#endif /* COMPAT_43 */
588
589/*
590 * Check if gid is a member of the group set.
591 */
592groupmember(gid, cred)
593 gid_t gid;
594 register struct ucred *cred;
595{
596 register gid_t *gp;
597 gid_t *egp;
598
599 egp = &(cred->cr_groups[cred->cr_ngroups]);
600 for (gp = cred->cr_groups; gp < egp; gp++)
601 if (*gp == gid)
602 return (1);
603 return (0);
604}
605
606/*
607 * Test whether the specified credentials imply "super-user"
608 * privilege; if so, and we have accounting info, set the flag
609 * indicating use of super-powers.
610 * Returns 0 or error.
611 */
612suser(cred, acflag)
613 struct ucred *cred;
614 u_short *acflag;
615{
616#if DIAGNOSTIC
617 if (cred == NOCRED || cred == FSCRED)
618 panic("suser");
619#endif
620 if (cred->cr_uid == 0) {
621 if (acflag)
622 *acflag |= ASU;
623 return (0);
624 }
625 return (EPERM);
626}
627
628int
629is_suser(void)
630{
631 struct proc *p = current_proc();
632
633 if (!p)
634 return (0);
635
636 return (suser(p->p_ucred, &p->p_acflag) == 0);
637}
638
639int
640is_suser1(void)
641{
642 struct proc *p = current_proc();
643
644 if (!p)
645 return (0);
646
647 return (suser(p->p_ucred, &p->p_acflag) == 0 ||
648 p->p_cred->p_ruid == 0 || p->p_cred->p_svuid == 0);
649}
650
651/*
652 * Allocate a zeroed cred structure.
653 */
654struct ucred *
655crget()
656{
657 register struct ucred *cr;
658
659 MALLOC_ZONE(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
660 bzero((caddr_t)cr, sizeof(*cr));
661 cr->cr_ref = 1;
662 return (cr);
663}
664
665/*
666 * Free a cred structure.
667 * Throws away space when ref count gets to 0.
668 */
669void
670crfree(cr)
671 struct ucred *cr;
672{
673#if DIAGNOSTIC
674 if (cr == NOCRED || cr == FSCRED)
675 panic("crfree");
676#endif
677 if (--cr->cr_ref == 0)
678 FREE_ZONE((caddr_t)cr, sizeof *cr, M_CRED);
679}
680
681/*
682 * Copy cred structure to a new one and free the old one.
683 */
684struct ucred *
685crcopy(cr)
686 struct ucred *cr;
687{
688 struct ucred *newcr;
689
690#if DIAGNOSTIC
691 if (cr == NOCRED || cr == FSCRED)
692 panic("crcopy");
693#endif
694 if (cr->cr_ref == 1)
695 return (cr);
696 newcr = crget();
697 *newcr = *cr;
698 crfree(cr);
699 newcr->cr_ref = 1;
700 return (newcr);
701}
702
703/*
704 * Dup cred struct to a new held one.
705 */
706struct ucred *
707crdup(cr)
708 struct ucred *cr;
709{
710 struct ucred *newcr;
711
712#if DIAGNOSTIC
713 if (cr == NOCRED || cr == FSCRED)
714 panic("crdup");
715#endif
716 newcr = crget();
717 *newcr = *cr;
718 newcr->cr_ref = 1;
719 return (newcr);
720}
721
722/*
723 * Get login name, if available.
724 */
725struct getlogin_args {
726 char *namebuf;
727 u_int namelen;
728};
729/* ARGSUSED */
730getlogin(p, uap, retval)
731 struct proc *p;
732 struct getlogin_args *uap;
733 register_t *retval;
734{
735
736 if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login))
737 uap->namelen = sizeof (p->p_pgrp->pg_session->s_login);
738 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
739 (caddr_t)uap->namebuf, uap->namelen));
740}
741
742/*
743 * Set login name.
744 */
745struct setlogin_args {
746 char *namebuf;
747};
748/* ARGSUSED */
749setlogin(p, uap, retval)
750 struct proc *p;
751 struct setlogin_args *uap;
752 register_t *retval;
753{
754 int error;
755 int dummy=0;
756
757 if (error = suser(p->p_ucred, &p->p_acflag))
758 return (error);
759
760 error = copyinstr((caddr_t) uap->namebuf,
761 (caddr_t) p->p_pgrp->pg_session->s_login,
762 sizeof (p->p_pgrp->pg_session->s_login) - 1, (size_t *)&dummy);
763 if (error == ENAMETOOLONG)
764 error = EINVAL;
765 return (error);
766}
767
768
769/* Set the secrity token of the task with current euid and eguid */
9bccf70c 770kern_return_t
1c79356b
A
771set_security_token(struct proc * p)
772{
773 security_token_t sec_token;
774
775 sec_token.val[0] = p->p_ucred->cr_uid;
776 sec_token.val[1] = p->p_ucred->cr_gid;
9bccf70c 777 return host_security_set_task_token(host_security_self(),
1c79356b
A
778 p->task,
779 sec_token,
780 (sec_token.val[0]) ?
781 HOST_PRIV_NULL :
782 host_priv_self());
783}