]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_prot.c
xnu-124.13.tar.gz
[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 setuid_args {
283 uid_t uid;
284 };
285 /* ARGSUSED */
286 setuid(p, uap, retval)
287 struct proc *p;
288 struct setuid_args *uap;
289 register_t *retval;
290 {
291 register struct pcred *pc = p->p_cred;
292 register uid_t uid;
293 int error;
294
295 uid = uap->uid;
296 if (uid != pc->p_ruid &&
297 (error = suser(pc->pc_ucred, &p->p_acflag)))
298 return (error);
299 /*
300 * Everything's okay, do it.
301 * Transfer proc count to new user.
302 * Copy credentials so other references do not see our changes.
303 */
304 pcred_writelock(p);
305 (void)chgproccnt(pc->p_ruid, -1);
306 (void)chgproccnt(uid, 1);
307 pc->pc_ucred = crcopy(pc->pc_ucred);
308 pc->pc_ucred->cr_uid = uid;
309 pc->p_ruid = uid;
310 pc->p_svuid = uid;
311 pcred_unlock(p);
312 set_security_token(p);
313 p->p_flag |= P_SUGID;
314 return (0);
315 }
316
317 struct seteuid_args {
318 uid_t euid;
319 };
320 /* ARGSUSED */
321 seteuid(p, uap, retval)
322 struct proc *p;
323 struct seteuid_args *uap;
324 register_t *retval;
325 {
326 register struct pcred *pc = p->p_cred;
327 register uid_t euid;
328 int error;
329
330 euid = uap->euid;
331 if (euid != pc->p_ruid && euid != pc->p_svuid &&
332 (error = suser(pc->pc_ucred, &p->p_acflag)))
333 return (error);
334 /*
335 * Everything's okay, do it. Copy credentials so other references do
336 * not see our changes.
337 */
338 pcred_writelock(p);
339 pc->pc_ucred = crcopy(pc->pc_ucred);
340 pc->pc_ucred->cr_uid = euid;
341 pcred_unlock(p);
342 set_security_token(p);
343 p->p_flag |= P_SUGID;
344 return (0);
345 }
346
347 struct setgid_args {
348 gid_t gid;
349 };
350 /* ARGSUSED */
351 setgid(p, uap, retval)
352 struct proc *p;
353 struct setgid_args *uap;
354 register_t *retval;
355 {
356 register struct pcred *pc = p->p_cred;
357 register gid_t gid;
358 int error;
359
360 gid = uap->gid;
361 if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag)))
362 return (error);
363 pcred_writelock(p);
364 pc->pc_ucred = crcopy(pc->pc_ucred);
365 pc->pc_ucred->cr_groups[0] = gid;
366 pc->p_rgid = gid;
367 pc->p_svgid = gid; /* ??? */
368 pcred_unlock(p);
369 set_security_token(p);
370 p->p_flag |= P_SUGID;
371 return (0);
372 }
373
374 struct setegid_args {
375 gid_t egid;
376 };
377 /* ARGSUSED */
378 setegid(p, uap, retval)
379 struct proc *p;
380 struct setegid_args *uap;
381 register_t *retval;
382 {
383 register struct pcred *pc = p->p_cred;
384 register gid_t egid;
385 int error;
386
387 egid = uap->egid;
388 if (egid != pc->p_rgid && egid != pc->p_svgid &&
389 (error = suser(pc->pc_ucred, &p->p_acflag)))
390 return (error);
391 pcred_writelock(p);
392 pc->pc_ucred = crcopy(pc->pc_ucred);
393 pc->pc_ucred->cr_groups[0] = egid;
394 pcred_unlock(p);
395 set_security_token(p);
396 p->p_flag |= P_SUGID;
397 return (0);
398 }
399
400 struct setgroups_args{
401 u_int gidsetsize;
402 gid_t *gidset;
403 };
404
405 /* ARGSUSED */
406 setgroups(p, uap, retval)
407 struct proc *p;
408 struct setgroups_args *uap;
409 register_t *retval;
410 {
411 register struct pcred *pc = p->p_cred;
412 struct ucred *new, *old;
413 register u_int ngrp;
414 int error;
415
416 if (error = suser(pc->pc_ucred, &p->p_acflag))
417 return (error);
418 ngrp = uap->gidsetsize;
419 if (ngrp < 1 || ngrp > NGROUPS)
420 return (EINVAL);
421 new = crget();
422 error = copyin((caddr_t)uap->gidset,
423 (caddr_t)new->cr_groups, ngrp * sizeof(gid_t));
424 if (error) {
425 crfree(new);
426 return (error);
427 }
428 new->cr_ngroups = ngrp;
429 pcred_writelock(p);
430 old = pc->pc_ucred;
431 new->cr_uid = old->cr_uid;
432 pc->pc_ucred = new;
433 pcred_unlock(p);
434 set_security_token(p);
435 p->p_flag |= P_SUGID;
436 if (old != NOCRED)
437 crfree(old);
438 return (0);
439 }
440
441 #if COMPAT_43
442 struct osetreuid_args{
443 int ruid;
444 int euid;
445 };
446 /* ARGSUSED */
447 osetreuid(p, uap, retval)
448 register struct proc *p;
449 struct osetreuid_args *uap;
450 register_t *retval;
451 {
452 struct seteuid_args seuidargs;
453 struct setuid_args suidargs;
454
455 /*
456 * There are five cases, and we attempt to emulate them in
457 * the following fashion:
458 * -1, -1: return 0. This is correct emulation.
459 * -1, N: call seteuid(N). This is correct emulation.
460 * N, -1: if we called setuid(N), our euid would be changed
461 * to N as well. the theory is that we don't want to
462 * revoke root access yet, so we call seteuid(N)
463 * instead. This is incorrect emulation, but often
464 * suffices enough for binary compatibility.
465 * N, N: call setuid(N). This is correct emulation.
466 * N, M: call setuid(N). This is close to correct emulation.
467 */
468 if (uap->ruid == (uid_t)-1) {
469 if (uap->euid == (uid_t)-1)
470 return (0); /* -1, -1 */
471 seuidargs.euid = uap->euid; /* -1, N */
472 return (seteuid(p, &seuidargs, retval));
473 }
474 if (uap->euid == (uid_t)-1) {
475 seuidargs.euid = uap->ruid; /* N, -1 */
476 return (seteuid(p, &seuidargs, retval));
477 }
478 suidargs.uid = uap->ruid; /* N, N and N, M */
479 return (setuid(p, &suidargs, retval));
480 }
481
482 struct osetregid_args {
483 int rgid;
484 int egid;
485 };
486 /* ARGSUSED */
487 osetregid(p, uap, retval)
488 register struct proc *p;
489 struct osetregid_args *uap;
490 register_t *retval;
491 {
492 struct setegid_args segidargs;
493 struct setgid_args sgidargs;
494
495 /*
496 * There are five cases, described above in osetreuid()
497 */
498 if (uap->rgid == (gid_t)-1) {
499 if (uap->egid == (gid_t)-1)
500 return (0); /* -1, -1 */
501 segidargs.egid = uap->egid; /* -1, N */
502 return (setegid(p, &segidargs, retval));
503 }
504 if (uap->egid == (gid_t)-1) {
505 segidargs.egid = uap->rgid; /* N, -1 */
506 return (setegid(p, &segidargs, retval));
507 }
508 sgidargs.gid = uap->rgid; /* N, N and N, M */
509 return (setgid(p, &sgidargs, retval));
510 }
511 #endif /* COMPAT_43 */
512
513 /*
514 * Check if gid is a member of the group set.
515 */
516 groupmember(gid, cred)
517 gid_t gid;
518 register struct ucred *cred;
519 {
520 register gid_t *gp;
521 gid_t *egp;
522
523 egp = &(cred->cr_groups[cred->cr_ngroups]);
524 for (gp = cred->cr_groups; gp < egp; gp++)
525 if (*gp == gid)
526 return (1);
527 return (0);
528 }
529
530 /*
531 * Test whether the specified credentials imply "super-user"
532 * privilege; if so, and we have accounting info, set the flag
533 * indicating use of super-powers.
534 * Returns 0 or error.
535 */
536 suser(cred, acflag)
537 struct ucred *cred;
538 u_short *acflag;
539 {
540 #if DIAGNOSTIC
541 if (cred == NOCRED || cred == FSCRED)
542 panic("suser");
543 #endif
544 if (cred->cr_uid == 0) {
545 if (acflag)
546 *acflag |= ASU;
547 return (0);
548 }
549 return (EPERM);
550 }
551
552 int
553 is_suser(void)
554 {
555 struct proc *p = current_proc();
556
557 if (!p)
558 return (0);
559
560 return (suser(p->p_ucred, &p->p_acflag) == 0);
561 }
562
563 int
564 is_suser1(void)
565 {
566 struct proc *p = current_proc();
567
568 if (!p)
569 return (0);
570
571 return (suser(p->p_ucred, &p->p_acflag) == 0 ||
572 p->p_cred->p_ruid == 0 || p->p_cred->p_svuid == 0);
573 }
574
575 /*
576 * Allocate a zeroed cred structure.
577 */
578 struct ucred *
579 crget()
580 {
581 register struct ucred *cr;
582
583 MALLOC_ZONE(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
584 bzero((caddr_t)cr, sizeof(*cr));
585 cr->cr_ref = 1;
586 return (cr);
587 }
588
589 /*
590 * Free a cred structure.
591 * Throws away space when ref count gets to 0.
592 */
593 void
594 crfree(cr)
595 struct ucred *cr;
596 {
597 #if DIAGNOSTIC
598 if (cr == NOCRED || cr == FSCRED)
599 panic("crfree");
600 #endif
601 if (--cr->cr_ref == 0)
602 FREE_ZONE((caddr_t)cr, sizeof *cr, M_CRED);
603 }
604
605 /*
606 * Copy cred structure to a new one and free the old one.
607 */
608 struct ucred *
609 crcopy(cr)
610 struct ucred *cr;
611 {
612 struct ucred *newcr;
613
614 #if DIAGNOSTIC
615 if (cr == NOCRED || cr == FSCRED)
616 panic("crcopy");
617 #endif
618 if (cr->cr_ref == 1)
619 return (cr);
620 newcr = crget();
621 *newcr = *cr;
622 crfree(cr);
623 newcr->cr_ref = 1;
624 return (newcr);
625 }
626
627 /*
628 * Dup cred struct to a new held one.
629 */
630 struct ucred *
631 crdup(cr)
632 struct ucred *cr;
633 {
634 struct ucred *newcr;
635
636 #if DIAGNOSTIC
637 if (cr == NOCRED || cr == FSCRED)
638 panic("crdup");
639 #endif
640 newcr = crget();
641 *newcr = *cr;
642 newcr->cr_ref = 1;
643 return (newcr);
644 }
645
646 /*
647 * Get login name, if available.
648 */
649 struct getlogin_args {
650 char *namebuf;
651 u_int namelen;
652 };
653 /* ARGSUSED */
654 getlogin(p, uap, retval)
655 struct proc *p;
656 struct getlogin_args *uap;
657 register_t *retval;
658 {
659
660 if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login))
661 uap->namelen = sizeof (p->p_pgrp->pg_session->s_login);
662 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
663 (caddr_t)uap->namebuf, uap->namelen));
664 }
665
666 /*
667 * Set login name.
668 */
669 struct setlogin_args {
670 char *namebuf;
671 };
672 /* ARGSUSED */
673 setlogin(p, uap, retval)
674 struct proc *p;
675 struct setlogin_args *uap;
676 register_t *retval;
677 {
678 int error;
679 int dummy=0;
680
681 if (error = suser(p->p_ucred, &p->p_acflag))
682 return (error);
683
684 error = copyinstr((caddr_t) uap->namebuf,
685 (caddr_t) p->p_pgrp->pg_session->s_login,
686 sizeof (p->p_pgrp->pg_session->s_login) - 1, (size_t *)&dummy);
687 if (error == ENAMETOOLONG)
688 error = EINVAL;
689 return (error);
690 }
691
692
693 /* Set the secrity token of the task with current euid and eguid */
694 void
695 set_security_token(struct proc * p)
696 {
697 security_token_t sec_token;
698
699 sec_token.val[0] = p->p_ucred->cr_uid;
700 sec_token.val[1] = p->p_ucred->cr_gid;
701 (void)host_security_set_task_token(host_security_self(),
702 p->task,
703 sec_token,
704 (sec_token.val[0]) ?
705 HOST_PRIV_NULL :
706 host_priv_self());
707 }