Home | History | Annotate | Line # | Download | only in kern
kern_prot.c revision 1.53
      1 /*	$NetBSD: kern_prot.c,v 1.53 1999/03/28 17:34:33 kleink 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(size_t) 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