xref: /netbsd-src/sys/kern/kern_prot.c (revision dc306354b0b29af51801a7632f1e95265a68cd81)
1 /*	$NetBSD: kern_prot.c,v 1.52 1998/12/18 14:10:06 drochner Exp $	*/
2 
3 /*
4  * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  * (c) UNIX System Laboratories, Inc.
7  * All or some portions of this file are derived from material licensed
8  * to the University of California by American Telephone and Telegraph
9  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10  * the permission of UNIX System Laboratories, Inc.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *	This product includes software developed by the University of
23  *	California, Berkeley and its contributors.
24  * 4. Neither the name of the University nor the names of its contributors
25  *    may be used to endorse or promote products derived from this software
26  *    without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  *
40  *	@(#)kern_prot.c	8.9 (Berkeley) 2/14/95
41  */
42 
43 /*
44  * System calls related to processes and protection
45  */
46 
47 #include "opt_compat_freebsd.h"
48 #include "opt_compat_ibcs2.h"
49 #include "opt_compat_sunos.h"
50 #include "opt_compat_linux.h"
51 #include "opt_compat_43.h"
52 
53 #include <sys/param.h>
54 #include <sys/acct.h>
55 #include <sys/systm.h>
56 #include <sys/ucred.h>
57 #include <sys/proc.h>
58 #include <sys/timeb.h>
59 #include <sys/times.h>
60 #include <sys/malloc.h>
61 
62 #include <sys/mount.h>
63 #include <sys/syscallargs.h>
64 
65 /* ARGSUSED */
66 int
67 sys_getpid(p, v, retval)
68 	struct proc *p;
69 	void *v;
70 	register_t *retval;
71 {
72 
73 	*retval = p->p_pid;
74 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2) || \
75     defined(COMPAT_FREEBSD) || (defined(COMPAT_LINUX) && defined(__alpha__))
76 	retval[1] = p->p_pptr->p_pid;
77 #endif
78 	return (0);
79 }
80 
81 /* ARGSUSED */
82 int
83 sys_getppid(p, v, retval)
84 	struct proc *p;
85 	void *v;
86 	register_t *retval;
87 {
88 
89 	*retval = p->p_pptr->p_pid;
90 	return (0);
91 }
92 
93 /* Get process group ID; note that POSIX getpgrp takes no parameter */
94 int
95 sys_getpgrp(p, v, retval)
96 	struct proc *p;
97 	void *v;
98 	register_t *retval;
99 {
100 
101 	*retval = p->p_pgrp->pg_id;
102 	return (0);
103 }
104 
105 /*
106  * Return the process group ID of the session leader (session ID)
107  * for the specified process.
108  */
109 int
110 sys_getsid(p, v, retval)
111 	struct proc *p;
112 	void *v;
113 	register_t *retval;
114 {
115 	struct sys_getsid_args /* {
116 		syscalldarg(pid_t) pid;
117 	} */ *uap = v;
118 
119 	if (SCARG(uap, pid) == 0)
120 		goto found;
121 	if ((p = pfind(SCARG(uap, pid))) == 0)
122 		return (ESRCH);
123 found:
124 	*retval = p->p_session->s_sid;
125 	return 0;
126 }
127 
128 int
129 sys_getpgid(p, v, retval)
130 	struct proc *p;
131 	void *v;
132 	register_t *retval;
133 {
134 	register struct sys_getpgid_args /* {
135 		syscallarg(pid_t) pid;
136 	} */ *uap = v;
137 
138 	if (SCARG(uap, pid) == 0)
139 		goto found;
140 	if ((p = pfind(SCARG(uap, pid))) == 0)
141 		return (ESRCH);
142 found:
143 	*retval = p->p_pgid;
144 	return 0;
145 }
146 
147 /* ARGSUSED */
148 int
149 sys_getuid(p, v, retval)
150 	struct proc *p;
151 	void *v;
152 	register_t *retval;
153 {
154 
155 	*retval = p->p_cred->p_ruid;
156 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2) || \
157     defined(COMPAT_FREEBSD) || (defined(COMPAT_LINUX) && defined(__alpha__))
158 	retval[1] = p->p_ucred->cr_uid;
159 #endif
160 	return (0);
161 }
162 
163 /* ARGSUSED */
164 int
165 sys_geteuid(p, v, retval)
166 	struct proc *p;
167 	void *v;
168 	register_t *retval;
169 {
170 
171 	*retval = p->p_ucred->cr_uid;
172 	return (0);
173 }
174 
175 /* ARGSUSED */
176 int
177 sys_getgid(p, v, retval)
178 	struct proc *p;
179 	void *v;
180 	register_t *retval;
181 {
182 
183 	*retval = p->p_cred->p_rgid;
184 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_FREEBSD) || \
185     (defined(COMPAT_LINUX) && defined(alpha))
186 	retval[1] = p->p_ucred->cr_gid;
187 #endif
188 	return (0);
189 }
190 
191 /*
192  * Get effective group ID.  The "egid" is groups[0], and could be obtained
193  * via getgroups.  This syscall exists because it is somewhat painful to do
194  * correctly in a library function.
195  */
196 /* ARGSUSED */
197 int
198 sys_getegid(p, v, retval)
199 	struct proc *p;
200 	void *v;
201 	register_t *retval;
202 {
203 
204 	*retval = p->p_ucred->cr_gid;
205 	return (0);
206 }
207 
208 int
209 sys_getgroups(p, v, retval)
210 	struct proc *p;
211 	void *v;
212 	register_t *retval;
213 {
214 	register struct sys_getgroups_args /* {
215 		syscallarg(int) gidsetsize;
216 		syscallarg(gid_t *) gidset;
217 	} */ *uap = v;
218 	register struct pcred *pc = p->p_cred;
219 	register int ngrp;
220 	int error;
221 
222 	ngrp = SCARG(uap, gidsetsize);
223 	if (ngrp == 0) {
224 		*retval = pc->pc_ucred->cr_ngroups;
225 		return (0);
226 	}
227 	if (ngrp < pc->pc_ucred->cr_ngroups)
228 		return (EINVAL);
229 	ngrp = pc->pc_ucred->cr_ngroups;
230 	error = copyout((caddr_t)pc->pc_ucred->cr_groups,
231 			(caddr_t)SCARG(uap, gidset), ngrp * sizeof(gid_t));
232 	if (error)
233 		return (error);
234 	*retval = ngrp;
235 	return (0);
236 }
237 
238 /* ARGSUSED */
239 int
240 sys_setsid(p, v, retval)
241 	register struct proc *p;
242 	void *v;
243 	register_t *retval;
244 {
245 
246 	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
247 		return (EPERM);
248 	} else {
249 		(void)enterpgrp(p, p->p_pid, 1);
250 		*retval = p->p_pid;
251 		return (0);
252 	}
253 }
254 
255 /*
256  * set process group (setpgid/old setpgrp)
257  *
258  * caller does setpgid(targpid, targpgid)
259  *
260  * pgid must be in valid range (EINVAL)
261  * pid must be caller or child of caller (ESRCH)
262  * if a child
263  *	pid must be in same session (EPERM)
264  *	pid can't have done an exec (EACCES)
265  * if pgid != pid
266  * 	there must exist some pid in same session having pgid (EPERM)
267  * pid must not be session leader (EPERM)
268  */
269 /* ARGSUSED */
270 int
271 sys_setpgid(curp, v, retval)
272 	struct proc *curp;
273 	void *v;
274 	register_t *retval;
275 {
276 	register struct sys_setpgid_args /* {
277 		syscallarg(int) pid;
278 		syscallarg(int) pgid;
279 	} */ *uap = v;
280 	register struct proc *targp;		/* target process */
281 	register struct pgrp *pgrp;		/* target pgrp */
282 
283 	if (SCARG(uap, pgid) < 0)
284 		return (EINVAL);
285 
286 	if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != curp->p_pid) {
287 		if ((targp = pfind(SCARG(uap, pid))) == 0 || !inferior(targp))
288 			return (ESRCH);
289 		if (targp->p_session != curp->p_session)
290 			return (EPERM);
291 		if (targp->p_flag & P_EXEC)
292 			return (EACCES);
293 	} else
294 		targp = curp;
295 	if (SESS_LEADER(targp))
296 		return (EPERM);
297 	if (SCARG(uap, pgid) == 0)
298 		SCARG(uap, pgid) = targp->p_pid;
299 	else if (SCARG(uap, pgid) != targp->p_pid)
300 		if ((pgrp = pgfind(SCARG(uap, pgid))) == 0 ||
301 	            pgrp->pg_session != curp->p_session)
302 			return (EPERM);
303 	return (enterpgrp(targp, SCARG(uap, pgid), 0));
304 }
305 
306 /* ARGSUSED */
307 int
308 sys_setuid(p, v, retval)
309 	struct proc *p;
310 	void *v;
311 	register_t *retval;
312 {
313 	struct sys_setuid_args /* {
314 		syscallarg(uid_t) uid;
315 	} */ *uap = v;
316 	register struct pcred *pc = p->p_cred;
317 	register uid_t uid;
318 	int error;
319 
320 	uid = SCARG(uap, uid);
321 	if (uid != pc->p_ruid &&
322 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
323 		return (error);
324 	/*
325 	 * Everything's okay, do it.
326 	 * Transfer proc count to new user.
327 	 * Copy credentials so other references do not see our changes.
328 	 */
329 	(void)chgproccnt(pc->p_ruid, -1);
330 	(void)chgproccnt(uid, 1);
331 	pc->pc_ucred = crcopy(pc->pc_ucred);
332 	pc->pc_ucred->cr_uid = uid;
333 	pc->p_ruid = uid;
334 	pc->p_svuid = uid;
335 	p->p_flag |= P_SUGID;
336 	return (0);
337 }
338 
339 /* ARGSUSED */
340 int
341 sys_seteuid(p, v, retval)
342 	struct proc *p;
343 	void *v;
344 	register_t *retval;
345 {
346 	struct sys_seteuid_args /* {
347 		syscallarg(uid_t) euid;
348 	} */ *uap = v;
349 	register struct pcred *pc = p->p_cred;
350 	register uid_t euid;
351 	int error;
352 
353 	euid = SCARG(uap, euid);
354 	if (euid != pc->p_ruid && euid != pc->p_svuid &&
355 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
356 		return (error);
357 	/*
358 	 * Everything's okay, do it.  Copy credentials so other references do
359 	 * not see our changes.
360 	 */
361 	pc->pc_ucred = crcopy(pc->pc_ucred);
362 	pc->pc_ucred->cr_uid = euid;
363 	p->p_flag |= P_SUGID;
364 	return (0);
365 }
366 
367 int
368 sys_setreuid(p, v, retval)
369 	struct proc *p;
370 	void *v;
371 	register_t *retval;
372 {
373 	struct sys_setreuid_args /* {
374 		syscallarg(uid_t) ruid;
375 		syscallarg(uid_t) euid;
376 	} */ *uap = v;
377 	register struct pcred *pc = p->p_cred;
378 	register uid_t ruid, euid;
379 	int error;
380 
381 	ruid = SCARG(uap, ruid);
382 	euid = SCARG(uap, euid);
383 
384 	if (ruid != (uid_t)-1 &&
385 	    ruid != pc->p_ruid && ruid != pc->pc_ucred->cr_uid &&
386 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
387 		return (error);
388 
389 	if (euid != (uid_t)-1 &&
390 	    euid != pc->p_ruid && euid != pc->pc_ucred->cr_uid &&
391 	    euid != pc->p_svuid &&
392 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
393 		return (error);
394 
395 	if (euid != (uid_t)-1) {
396 		pc->pc_ucred = crcopy(pc->pc_ucred);
397 		pc->pc_ucred->cr_uid = euid;
398 	}
399 
400 	if (ruid != (uid_t)-1) {
401 		(void)chgproccnt(pc->p_ruid, -1);
402 		(void)chgproccnt(ruid, 1);
403 		pc->p_ruid = ruid;
404 		pc->p_svuid = pc->pc_ucred->cr_uid;
405 	}
406 
407 	if (euid != (uid_t)-1 && ruid != (uid_t)-1)
408 		p->p_flag |= P_SUGID;
409 	return (0);
410 }
411 
412 /* ARGSUSED */
413 int
414 sys_setgid(p, v, retval)
415 	struct proc *p;
416 	void *v;
417 	register_t *retval;
418 {
419 	struct sys_setgid_args /* {
420 		syscallarg(gid_t) gid;
421 	} */ *uap = v;
422 	register struct pcred *pc = p->p_cred;
423 	register gid_t gid;
424 	int error;
425 
426 	gid = SCARG(uap, gid);
427 	if (gid != pc->p_rgid &&
428 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
429 		return (error);
430 	pc->pc_ucred = crcopy(pc->pc_ucred);
431 	pc->pc_ucred->cr_gid = gid;
432 	pc->p_rgid = gid;
433 	pc->p_svgid = gid;
434 	p->p_flag |= P_SUGID;
435 	return (0);
436 }
437 
438 /* ARGSUSED */
439 int
440 sys_setegid(p, v, retval)
441 	struct proc *p;
442 	void *v;
443 	register_t *retval;
444 {
445 	struct sys_setegid_args /* {
446 		syscallarg(gid_t) egid;
447 	} */ *uap = v;
448 	register struct pcred *pc = p->p_cred;
449 	register gid_t egid;
450 	int error;
451 
452 	egid = SCARG(uap, egid);
453 	if (egid != pc->p_rgid && egid != pc->p_svgid &&
454 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
455 		return (error);
456 	pc->pc_ucred = crcopy(pc->pc_ucred);
457 	pc->pc_ucred->cr_gid = egid;
458 	p->p_flag |= P_SUGID;
459 	return (0);
460 }
461 
462 int
463 sys_setregid(p, v, retval)
464 	struct proc *p;
465 	void *v;
466 	register_t *retval;
467 {
468 	struct sys_setregid_args /* {
469 		syscallarg(gid_t) rgid;
470 		syscallarg(gid_t) egid;
471 	} */ *uap = v;
472 	register struct pcred *pc = p->p_cred;
473 	register gid_t rgid, egid;
474 	int error;
475 
476 	rgid = SCARG(uap, rgid);
477 	egid = SCARG(uap, egid);
478 
479 	if (rgid != (gid_t)-1 &&
480 	    rgid != pc->p_rgid && rgid != pc->pc_ucred->cr_gid &&
481 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
482 		return (error);
483 
484 	if (egid != (gid_t)-1 &&
485 	    egid != pc->p_rgid && egid != pc->pc_ucred->cr_gid &&
486 	    egid != pc->p_svgid &&
487 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
488 		return (error);
489 
490 	if (egid != (gid_t)-1) {
491 		pc->pc_ucred = crcopy(pc->pc_ucred);
492 		pc->pc_ucred->cr_gid = egid;
493 	}
494 
495 	if (rgid != (gid_t)-1) {
496 		pc->p_rgid = rgid;
497 		pc->p_svgid = pc->pc_ucred->cr_gid;
498 	}
499 
500 	if (egid != (gid_t)-1 && rgid != (gid_t)-1)
501 		p->p_flag |= P_SUGID;
502 	return (0);
503 }
504 
505 /* ARGSUSED */
506 int
507 sys_setgroups(p, v, retval)
508 	struct proc *p;
509 	void *v;
510 	register_t *retval;
511 {
512 	struct sys_setgroups_args /* {
513 		syscallarg(int) gidsetsize;
514 		syscallarg(const gid_t *) gidset;
515 	} */ *uap = v;
516 	register struct pcred *pc = p->p_cred;
517 	register int ngrp;
518 	int error;
519 
520 	if ((error = suser(pc->pc_ucred, &p->p_acflag)) != 0)
521 		return (error);
522 	ngrp = SCARG(uap, gidsetsize);
523 	if ((u_int)ngrp > NGROUPS)
524 		return (EINVAL);
525 	pc->pc_ucred = crcopy(pc->pc_ucred);
526 	error = copyin(SCARG(uap, gidset), pc->pc_ucred->cr_groups,
527 	    ngrp * sizeof(gid_t));
528 	if (error)
529 		return (error);
530 	pc->pc_ucred->cr_ngroups = ngrp;
531 	p->p_flag |= P_SUGID;
532 	return (0);
533 }
534 
535 /*
536  * Check if gid is a member of the group set.
537  */
538 int
539 groupmember(gid, cred)
540 	gid_t gid;
541 	register struct ucred *cred;
542 {
543 	register gid_t *gp;
544 	gid_t *egp;
545 
546 	egp = &(cred->cr_groups[cred->cr_ngroups]);
547 	for (gp = cred->cr_groups; gp < egp; gp++)
548 		if (*gp == gid)
549 			return (1);
550 	return (0);
551 }
552 
553 /*
554  * Test whether the specified credentials imply "super-user"
555  * privilege; if so, and we have accounting info, set the flag
556  * indicating use of super-powers.
557  * Returns 0 or error.
558  */
559 int
560 suser(cred, acflag)
561 	struct ucred *cred;
562 	u_short *acflag;
563 {
564 	if (cred->cr_uid == 0) {
565 		if (acflag)
566 			*acflag |= ASU;
567 		return (0);
568 	}
569 	return (EPERM);
570 }
571 
572 /*
573  * Allocate a zeroed cred structure.
574  */
575 struct ucred *
576 crget()
577 {
578 	register struct ucred *cr;
579 
580 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
581 	memset((caddr_t)cr, 0, sizeof(*cr));
582 	cr->cr_ref = 1;
583 	return (cr);
584 }
585 
586 /*
587  * Free a cred structure.
588  * Throws away space when ref count gets to 0.
589  */
590 void
591 crfree(cr)
592 	struct ucred *cr;
593 {
594 	int s;
595 
596 	s = splimp();				/* ??? */
597 	if (--cr->cr_ref == 0)
598 		FREE((caddr_t)cr, M_CRED);
599 	(void) splx(s);
600 }
601 
602 /*
603  * Copy cred structure to a new one and free the old one.
604  */
605 struct ucred *
606 crcopy(cr)
607 	struct ucred *cr;
608 {
609 	struct ucred *newcr;
610 
611 	if (cr->cr_ref == 1)
612 		return (cr);
613 	newcr = crget();
614 	*newcr = *cr;
615 	crfree(cr);
616 	newcr->cr_ref = 1;
617 	return (newcr);
618 }
619 
620 /*
621  * Dup cred struct to a new held one.
622  */
623 struct ucred *
624 crdup(cr)
625 	struct ucred *cr;
626 {
627 	struct ucred *newcr;
628 
629 	newcr = crget();
630 	*newcr = *cr;
631 	newcr->cr_ref = 1;
632 	return (newcr);
633 }
634 
635 /*
636  * Get login name, if available.
637  */
638 /* ARGSUSED */
639 int
640 sys___getlogin(p, v, retval)
641 	struct proc *p;
642 	void *v;
643 	register_t *retval;
644 {
645 	struct sys___getlogin_args /* {
646 		syscallarg(char *) namebuf;
647 		syscallarg(u_int) namelen;
648 	} */ *uap = v;
649 
650 	if (SCARG(uap, namelen) > sizeof(p->p_pgrp->pg_session->s_login))
651 		SCARG(uap, namelen) = sizeof(p->p_pgrp->pg_session->s_login);
652 	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
653 	    (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen)));
654 }
655 
656 /*
657  * Set login name.
658  */
659 /* ARGSUSED */
660 int
661 sys_setlogin(p, v, retval)
662 	struct proc *p;
663 	void *v;
664 	register_t *retval;
665 {
666 	struct sys_setlogin_args /* {
667 		syscallarg(const char *) namebuf;
668 	} */ *uap = v;
669 	int error;
670 
671 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
672 		return (error);
673 	error = copyinstr(SCARG(uap, namebuf), p->p_pgrp->pg_session->s_login,
674 	    sizeof(p->p_pgrp->pg_session->s_login) - 1, (size_t *)0);
675 	if (error == ENAMETOOLONG)
676 		error = EINVAL;
677 	return (error);
678 }
679