]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_prot.c
xnu-344.23.tar.gz
[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 * 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>
78 #include <mach/host_security.h>
79
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 */
86 struct setprivexec_args {
87 int flag;
88 };
89 int
90 setprivexec(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 */
101 getpid(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 */
115 getppid(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 */
126 getpgrp(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
136 /* Get an arbitary pid's process group id */
137 struct getpgid_args {
138 pid_t pid;
139 };
140
141 int
142 getpgid(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);
155 found:
156 *retval = pt->p_pgrp->pg_id;
157 return (0);
158 }
159
160 /*
161 * Get an arbitary pid's session id.
162 */
163 struct getsid_args {
164 pid_t pid;
165 };
166
167 int
168 getsid(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);
181 found:
182 *retval = pt->p_session->s_sid;
183 return (0);
184 }
185
186 /* ARGSUSED */
187 getuid(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 */
201 geteuid(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 */
212 getgid(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 */
231 getegid(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
241 struct getgroups_args {
242 u_int gidsetsize;
243 gid_t *gidset;
244 };
245 getgroups(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 */
273 setsid(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 */
301 struct setpgid_args {
302 int pid;
303 int pgid;
304 };
305 /* ARGSUSED */
306 setpgid(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
334 struct issetugid_args {
335 int dummy;
336 };
337 issetugid(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
355 struct setuid_args {
356 uid_t uid;
357 };
358 /* ARGSUSED */
359 setuid(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 */
377
378 /* prepare app access profile files */
379 prepare_profile_database(uap->uid);
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
393 struct seteuid_args {
394 uid_t euid;
395 };
396 /* ARGSUSED */
397 seteuid(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
423 struct setgid_args {
424 gid_t gid;
425 };
426 /* ARGSUSED */
427 setgid(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
450 struct setegid_args {
451 gid_t egid;
452 };
453 /* ARGSUSED */
454 setegid(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
476 struct setgroups_args{
477 u_int gidsetsize;
478 gid_t *gidset;
479 };
480
481 /* ARGSUSED */
482 setgroups(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
518 struct osetreuid_args{
519 int ruid;
520 int euid;
521 };
522 /* ARGSUSED */
523 osetreuid(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
558 struct osetregid_args {
559 int rgid;
560 int egid;
561 };
562 /* ARGSUSED */
563 osetregid(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 */
592 groupmember(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 */
612 suser(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
628 int
629 is_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
639 int
640 is_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 */
654 struct ucred *
655 crget()
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 */
669 void
670 crfree(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 */
684 struct ucred *
685 crcopy(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 */
706 struct ucred *
707 crdup(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 */
725 struct getlogin_args {
726 char *namebuf;
727 u_int namelen;
728 };
729 /* ARGSUSED */
730 getlogin(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 */
745 struct setlogin_args {
746 char *namebuf;
747 };
748 /* ARGSUSED */
749 setlogin(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 */
770 kern_return_t
771 set_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;
777 return host_security_set_task_token(host_security_self(),
778 p->task,
779 sec_token,
780 (sec_token.val[0]) ?
781 HOST_PRIV_NULL :
782 host_priv_self());
783 }