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