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