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