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