xref: /openbsd-src/sys/kern/kern_prot.c (revision f5d56f6d1abf3988ecad6e5bcc0d9e60de25e475)
1 /*	$OpenBSD: kern_prot.c,v 1.68 2017/04/13 03:52:25 guenther Exp $	*/
2 /*	$NetBSD: kern_prot.c,v 1.33 1996/02/09 18:59:42 christos Exp $	*/
3 
4 /*
5  * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  * (c) UNIX System Laboratories, Inc.
8  * All or some portions of this file are derived from material licensed
9  * to the University of California by American Telephone and Telegraph
10  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
11  * the permission of UNIX System Laboratories, Inc.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  *	@(#)kern_prot.c	8.6 (Berkeley) 1/21/94
38  */
39 
40 /*
41  * System calls related to processes and protection
42  */
43 
44 #include <sys/param.h>
45 #include <sys/acct.h>
46 #include <sys/systm.h>
47 #include <sys/ucred.h>
48 #include <sys/proc.h>
49 #include <sys/filedesc.h>
50 #include <sys/pool.h>
51 
52 #include <sys/mount.h>
53 #include <sys/syscallargs.h>
54 #include <machine/tcb.h>
55 
56 inline void
57 crset(struct ucred *newcr, const struct ucred *cr)
58 {
59 	KASSERT(cr->cr_ref > 0);
60 	memcpy(
61 	    (char *)newcr    + offsetof(struct ucred, cr_startcopy),
62 	    (const char *)cr + offsetof(struct ucred, cr_startcopy),
63 	    sizeof(*cr)      - offsetof(struct ucred, cr_startcopy));
64 }
65 
66 int
67 sys_getpid(struct proc *p, void *v, register_t *retval)
68 {
69 
70 	*retval = p->p_p->ps_pid;
71 	return (0);
72 }
73 
74 int
75 sys_getthrid(struct proc *p, void *v, register_t *retval)
76 {
77 
78 	*retval = p->p_tid + THREAD_PID_OFFSET;
79 	return (0);
80 }
81 
82 int
83 sys_getppid(struct proc *p, void *v, register_t *retval)
84 {
85 
86 	*retval = p->p_p->ps_pptr->ps_pid;
87 	return (0);
88 }
89 
90 /* Get process group ID; note that POSIX getpgrp takes no parameter */
91 int
92 sys_getpgrp(struct proc *p, void *v, register_t *retval)
93 {
94 
95 	*retval = p->p_p->ps_pgrp->pg_id;
96 	return (0);
97 }
98 
99 /*
100  * SysVR.4 compatible getpgid()
101  */
102 int
103 sys_getpgid(struct proc *curp, void *v, register_t *retval)
104 {
105 	struct sys_getpgid_args /* {
106 		syscallarg(pid_t) pid;
107 	} */ *uap = v;
108 	struct process *targpr = curp->p_p;
109 
110 	if (SCARG(uap, pid) == 0 || SCARG(uap, pid) == targpr->ps_pid)
111 		goto found;
112 	if ((targpr = prfind(SCARG(uap, pid))) == NULL)
113 		return (ESRCH);
114 	if (targpr->ps_session != curp->p_p->ps_session)
115 		return (EPERM);
116 found:
117 	*retval = targpr->ps_pgid;
118 	return (0);
119 }
120 
121 int
122 sys_getsid(struct proc *curp, void *v, register_t *retval)
123 {
124 	struct sys_getsid_args /* {
125 		syscallarg(pid_t) pid;
126 	} */ *uap = v;
127 	struct process *targpr = curp->p_p;
128 
129 	if (SCARG(uap, pid) == 0 || SCARG(uap, pid) == targpr->ps_pid)
130 		goto found;
131 	if ((targpr = prfind(SCARG(uap, pid))) == NULL)
132 		return (ESRCH);
133 	if (targpr->ps_session != curp->p_p->ps_session)
134 		return (EPERM);
135 found:
136 	/* Skip exiting processes */
137 	if (targpr->ps_pgrp->pg_session->s_leader == NULL)
138 		return (ESRCH);
139 	*retval = targpr->ps_pgrp->pg_session->s_leader->ps_pid;
140 	return (0);
141 }
142 
143 int
144 sys_getuid(struct proc *p, void *v, register_t *retval)
145 {
146 
147 	*retval = p->p_ucred->cr_ruid;
148 	return (0);
149 }
150 
151 int
152 sys_geteuid(struct proc *p, void *v, register_t *retval)
153 {
154 
155 	*retval = p->p_ucred->cr_uid;
156 	return (0);
157 }
158 
159 int
160 sys_issetugid(struct proc *p, void *v, register_t *retval)
161 {
162 	if (p->p_p->ps_flags & PS_SUGIDEXEC)
163 		*retval = 1;
164 	else
165 		*retval = 0;
166 	return (0);
167 }
168 
169 int
170 sys_getgid(struct proc *p, void *v, register_t *retval)
171 {
172 
173 	*retval = p->p_ucred->cr_rgid;
174 	return (0);
175 }
176 
177 /*
178  * Get effective group ID.  The "egid" is groups[0], and could be obtained
179  * via getgroups.  This syscall exists because it is somewhat painful to do
180  * correctly in a library function.
181  */
182 int
183 sys_getegid(struct proc *p, void *v, register_t *retval)
184 {
185 
186 	*retval = p->p_ucred->cr_gid;
187 	return (0);
188 }
189 
190 int
191 sys_getgroups(struct proc *p, void *v, register_t *retval)
192 {
193 	struct sys_getgroups_args /* {
194 		syscallarg(int) gidsetsize;
195 		syscallarg(gid_t *) gidset;
196 	} */ *uap = v;
197 	struct ucred *uc = p->p_ucred;
198 	u_int ngrp;
199 	int error;
200 
201 	if ((ngrp = SCARG(uap, gidsetsize)) == 0) {
202 		*retval = uc->cr_ngroups;
203 		return (0);
204 	}
205 	if (ngrp < uc->cr_ngroups)
206 		return (EINVAL);
207 	ngrp = uc->cr_ngroups;
208 	error = copyout(uc->cr_groups, SCARG(uap, gidset),
209 	    ngrp * sizeof(gid_t));
210 	if (error)
211 		return (error);
212 	*retval = ngrp;
213 	return (0);
214 }
215 
216 int
217 sys_setsid(struct proc *p, void *v, register_t *retval)
218 {
219 	struct session *newsess;
220 	struct pgrp *newpgrp;
221 	struct process *pr = p->p_p;
222 	pid_t pid = pr->ps_pid;
223 
224 	newsess = pool_get(&session_pool, PR_WAITOK);
225 	timeout_set(&newsess->s_verauthto, zapverauth, newsess);
226 	newpgrp = pool_get(&pgrp_pool, PR_WAITOK);
227 
228 	if (pr->ps_pgid == pid || pgfind(pid)) {
229 		pool_put(&pgrp_pool, newpgrp);
230 		pool_put(&session_pool, newsess);
231 		return (EPERM);
232 	} else {
233 		(void) enterpgrp(pr, pid, newpgrp, newsess);
234 		*retval = pid;
235 		return (0);
236 	}
237 }
238 
239 /*
240  * set process group (setpgid/old setpgrp)
241  *
242  * caller does setpgid(targpid, targpgid)
243  *
244  * pid must be caller or child of caller (ESRCH)
245  * if a child
246  *	pid must be in same session (EPERM)
247  *	pid can't have done an exec (EACCES)
248  * if pgid != pid
249  * 	there must exist some pid in same session having pgid (EPERM)
250  * pid must not be session leader (EPERM)
251  */
252 int
253 sys_setpgid(struct proc *curp, void *v, register_t *retval)
254 {
255 	struct sys_setpgid_args /* {
256 		syscallarg(pid_t) pid;
257 		syscallarg(pid_t) pgid;
258 	} */ *uap = v;
259 	struct process *curpr = curp->p_p;
260 	struct process *targpr;		/* target process */
261 	struct pgrp *pgrp, *newpgrp;	/* target pgrp */
262 	pid_t pid, pgid;
263 	int error;
264 
265 	pid = SCARG(uap, pid);
266 	pgid = SCARG(uap, pgid);
267 
268 	if (pgid < 0)
269 		return (EINVAL);
270 
271 	newpgrp = pool_get(&pgrp_pool, PR_WAITOK);
272 
273 	if (pid != 0 && pid != curpr->ps_pid) {
274 		if ((targpr = prfind(pid)) == 0 || !inferior(targpr, curpr)) {
275 			error = ESRCH;
276 			goto out;
277 		}
278 		if (targpr->ps_session != curpr->ps_session) {
279 			error = EPERM;
280 			goto out;
281 		}
282 		if (targpr->ps_flags & PS_EXEC) {
283 			error = EACCES;
284 			goto out;
285 		}
286 	} else
287 		targpr = curpr;
288 	if (SESS_LEADER(targpr)) {
289 		error = EPERM;
290 		goto out;
291 	}
292 	if (pgid == 0)
293 		pgid = targpr->ps_pid;
294 	else if (pgid != targpr->ps_pid)
295 		if ((pgrp = pgfind(pgid)) == 0 ||
296 		    pgrp->pg_session != curpr->ps_session) {
297 			error = EPERM;
298 			goto out;
299 		}
300 	return (enterpgrp(targpr, pgid, newpgrp, NULL));
301 out:
302 	pool_put(&pgrp_pool, newpgrp);
303 	return (error);
304 }
305 
306 int
307 sys_getresuid(struct proc *p, void *v, register_t *retval)
308 {
309 	struct sys_getresuid_args /* {
310 		syscallarg(uid_t *) ruid;
311 		syscallarg(uid_t *) euid;
312 		syscallarg(uid_t *) suid;
313 	} */ *uap = v;
314 	struct ucred *uc = p->p_ucred;
315 	uid_t *ruid, *euid, *suid;
316 	int error1 = 0, error2 = 0, error3 = 0;
317 
318 	ruid = SCARG(uap, ruid);
319 	euid = SCARG(uap, euid);
320 	suid = SCARG(uap, suid);
321 
322 	if (ruid != NULL)
323 		error1 = copyout(&uc->cr_ruid, ruid, sizeof(*ruid));
324 	if (euid != NULL)
325 		error2 = copyout(&uc->cr_uid, euid, sizeof(*euid));
326 	if (suid != NULL)
327 		error3 = copyout(&uc->cr_svuid, suid, sizeof(*suid));
328 
329 	return (error1 ? error1 : error2 ? error2 : error3);
330 }
331 
332 int
333 sys_setresuid(struct proc *p, void *v, register_t *retval)
334 {
335 	struct sys_setresuid_args /* {
336 		syscallarg(uid_t) ruid;
337 		syscallarg(uid_t) euid;
338 		syscallarg(uid_t) suid;
339 	} */ *uap = v;
340 	struct process *pr = p->p_p;
341 	struct ucred *pruc, *newcred, *uc = p->p_ucred;
342 	uid_t ruid, euid, suid;
343 	int error;
344 
345 	ruid = SCARG(uap, ruid);
346 	euid = SCARG(uap, euid);
347 	suid = SCARG(uap, suid);
348 
349 	/*
350 	 * make permission checks against the thread's ucred,
351 	 * but the actual changes will be to the process's ucred
352 	 */
353 	pruc = pr->ps_ucred;
354 	if ((ruid == (uid_t)-1 || ruid == pruc->cr_ruid) &&
355 	    (euid == (uid_t)-1 || euid == pruc->cr_uid) &&
356 	    (suid == (uid_t)-1 || suid == pruc->cr_svuid))
357 		return (0);			/* no change */
358 
359 	/*
360 	 * Any of the real, effective, and saved uids may be changed
361 	 * to the current value of one of the three (root is not limited).
362 	 */
363 	if (ruid != (uid_t)-1 &&
364 	    ruid != uc->cr_ruid &&
365 	    ruid != uc->cr_uid &&
366 	    ruid != uc->cr_svuid &&
367 	    (error = suser(p, 0)))
368 		return (error);
369 
370 	if (euid != (uid_t)-1 &&
371 	    euid != uc->cr_ruid &&
372 	    euid != uc->cr_uid &&
373 	    euid != uc->cr_svuid &&
374 	    (error = suser(p, 0)))
375 		return (error);
376 
377 	if (suid != (uid_t)-1 &&
378 	    suid != uc->cr_ruid &&
379 	    suid != uc->cr_uid &&
380 	    suid != uc->cr_svuid &&
381 	    (error = suser(p, 0)))
382 		return (error);
383 
384 	/*
385 	 * Copy credentials so other references do not see our changes.
386 	 * ps_ucred may change during the crget().
387 	 */
388 	newcred = crget();
389 	pruc = pr->ps_ucred;
390 	crset(newcred, pruc);
391 
392 	/*
393 	 * Note that unlike the other set*uid() calls, each
394 	 * uid type is set independently of the others.
395 	 */
396 	if (ruid != (uid_t)-1)
397 		newcred->cr_ruid = ruid;
398 	if (euid != (uid_t)-1)
399 		newcred->cr_uid = euid;
400 	if (suid != (uid_t)-1)
401 		newcred->cr_svuid = suid;
402 	pr->ps_ucred = newcred;
403 	atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
404 
405 	/* now that we can sleep, transfer proc count to new user */
406 	if (ruid != (uid_t)-1 && ruid != pruc->cr_ruid) {
407 		chgproccnt(pruc->cr_ruid, -1);
408 		chgproccnt(ruid, 1);
409 	}
410 	crfree(pruc);
411 
412 	return (0);
413 }
414 
415 int
416 sys_getresgid(struct proc *p, void *v, register_t *retval)
417 {
418 	struct sys_getresgid_args /* {
419 		syscallarg(gid_t *) rgid;
420 		syscallarg(gid_t *) egid;
421 		syscallarg(gid_t *) sgid;
422 	} */ *uap = v;
423 	struct ucred *uc = p->p_ucred;
424 	gid_t *rgid, *egid, *sgid;
425 	int error1 = 0, error2 = 0, error3 = 0;
426 
427 	rgid = SCARG(uap, rgid);
428 	egid = SCARG(uap, egid);
429 	sgid = SCARG(uap, sgid);
430 
431 	if (rgid != NULL)
432 		error1 = copyout(&uc->cr_rgid, rgid, sizeof(*rgid));
433 	if (egid != NULL)
434 		error2 = copyout(&uc->cr_gid, egid, sizeof(*egid));
435 	if (sgid != NULL)
436 		error3 = copyout(&uc->cr_svgid, sgid, sizeof(*sgid));
437 
438 	return (error1 ? error1 : error2 ? error2 : error3);
439 }
440 
441 int
442 sys_setresgid(struct proc *p, void *v, register_t *retval)
443 {
444 	struct sys_setresgid_args /* {
445 		syscallarg(gid_t) rgid;
446 		syscallarg(gid_t) egid;
447 		syscallarg(gid_t) sgid;
448 	} */ *uap = v;
449 	struct process *pr = p->p_p;
450 	struct ucred *pruc, *newcred, *uc = p->p_ucred;
451 	gid_t rgid, egid, sgid;
452 	int error;
453 
454 	rgid = SCARG(uap, rgid);
455 	egid = SCARG(uap, egid);
456 	sgid = SCARG(uap, sgid);
457 
458 	/*
459 	 * make permission checks against the thread's ucred,
460 	 * but the actual changes will be to the process's ucred
461 	 */
462 	pruc = pr->ps_ucred;
463 	if ((rgid == (gid_t)-1 || rgid == pruc->cr_rgid) &&
464 	    (egid == (gid_t)-1 || egid == pruc->cr_gid) &&
465 	    (sgid == (gid_t)-1 || sgid == pruc->cr_svgid))
466 		return (0);			/* no change */
467 
468 	/*
469 	 * Any of the real, effective, and saved gids may be changed
470 	 * to the current value of one of the three (root is not limited).
471 	 */
472 	if (rgid != (gid_t)-1 &&
473 	    rgid != uc->cr_rgid &&
474 	    rgid != uc->cr_gid &&
475 	    rgid != uc->cr_svgid &&
476 	    (error = suser(p, 0)))
477 		return (error);
478 
479 	if (egid != (gid_t)-1 &&
480 	    egid != uc->cr_rgid &&
481 	    egid != uc->cr_gid &&
482 	    egid != uc->cr_svgid &&
483 	    (error = suser(p, 0)))
484 		return (error);
485 
486 	if (sgid != (gid_t)-1 &&
487 	    sgid != uc->cr_rgid &&
488 	    sgid != uc->cr_gid &&
489 	    sgid != uc->cr_svgid &&
490 	    (error = suser(p, 0)))
491 		return (error);
492 
493 	/*
494 	 * Copy credentials so other references do not see our changes.
495 	 * ps_ucred may change during the crget().
496 	 */
497 	newcred = crget();
498 	pruc = pr->ps_ucred;
499 	crset(newcred, pruc);
500 
501 	/*
502 	 * Note that unlike the other set*gid() calls, each
503 	 * gid type is set independently of the others.
504 	 */
505 	if (rgid != (gid_t)-1)
506 		newcred->cr_rgid = rgid;
507 	if (egid != (gid_t)-1)
508 		newcred->cr_gid = egid;
509 	if (sgid != (gid_t)-1)
510 		newcred->cr_svgid = sgid;
511 	pr->ps_ucred = newcred;
512 	atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
513 	crfree(pruc);
514 	return (0);
515 }
516 
517 int
518 sys_setregid(struct proc *p, void *v, register_t *retval)
519 {
520 	struct sys_setregid_args /* {
521 		syscallarg(gid_t) rgid;
522 		syscallarg(gid_t) egid;
523 	} */ *uap = v;
524 	struct process *pr = p->p_p;
525 	struct ucred *pruc, *newcred, *uc = p->p_ucred;
526 	gid_t rgid, egid;
527 	int error;
528 
529 	rgid = SCARG(uap, rgid);
530 	egid = SCARG(uap, egid);
531 
532 	/*
533 	 * make permission checks against the thread's ucred,
534 	 * but the actual changes will be to the process's ucred
535 	 *
536 	 * The saved gid check here is complicated: we reset the
537 	 * saved gid to the real gid if the real gid is specified
538 	 * *and* either it's changing _or_ the saved gid won't equal
539 	 * the effective gid.  So, the svgid *won't* change when
540 	 * the rgid isn't specified or when the rgid isn't changing
541 	 * and the svgid equals the requested egid.
542 	 */
543 	pruc = pr->ps_ucred;
544 	if ((rgid == (gid_t)-1 || rgid == pruc->cr_rgid) &&
545 	    (egid == (gid_t)-1 || egid == pruc->cr_gid) &&
546 	    (rgid == (gid_t)-1 || (rgid == pruc->cr_rgid &&
547 	    pruc->cr_svgid == (egid != (gid_t)-1 ? egid : pruc->cr_gid))))
548 		return (0);			/* no change */
549 
550 	/*
551 	 * Any of the real, effective, and saved gids may be changed
552 	 * to the current value of one of the three (root is not limited).
553 	 */
554 	if (rgid != (gid_t)-1 &&
555 	    rgid != uc->cr_rgid &&
556 	    rgid != uc->cr_gid &&
557 	    rgid != uc->cr_svgid &&
558 	    (error = suser(p, 0)))
559 		return (error);
560 
561 	if (egid != (gid_t)-1 &&
562 	    egid != uc->cr_rgid &&
563 	    egid != uc->cr_gid &&
564 	    egid != uc->cr_svgid &&
565 	    (error = suser(p, 0)))
566 		return (error);
567 
568 	/*
569 	 * Copy credentials so other references do not see our changes.
570 	 * ps_ucred may change during the crget().
571 	 */
572 	newcred = crget();
573 	pruc = pr->ps_ucred;
574 	crset(newcred, pruc);
575 
576 	if (rgid != (gid_t)-1)
577 		newcred->cr_rgid = rgid;
578 	if (egid != (gid_t)-1)
579 		newcred->cr_gid = egid;
580 
581 	/*
582 	 * The saved gid presents a bit of a dilemma, as it did not
583 	 * exist when setregid(2) was conceived.  We only set the saved
584 	 * gid when the real gid is specified and either its value would
585 	 * change, or where the saved and effective gids are different.
586 	 */
587 	if (rgid != (gid_t)-1 && (rgid != pruc->cr_rgid ||
588 	    pruc->cr_svgid != (egid != (gid_t)-1 ? egid : pruc->cr_gid)))
589 		newcred->cr_svgid = rgid;
590 	pr->ps_ucred = newcred;
591 	atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
592 	crfree(pruc);
593 	return (0);
594 }
595 
596 int
597 sys_setreuid(struct proc *p, void *v, register_t *retval)
598 {
599 	struct sys_setreuid_args /* {
600 		syscallarg(uid_t) ruid;
601 		syscallarg(uid_t) euid;
602 	} */ *uap = v;
603 	struct process *pr = p->p_p;
604 	struct ucred *pruc, *newcred, *uc = p->p_ucred;
605 	uid_t ruid, euid;
606 	int error;
607 
608 	ruid = SCARG(uap, ruid);
609 	euid = SCARG(uap, euid);
610 
611 	/*
612 	 * make permission checks against the thread's ucred,
613 	 * but the actual changes will be to the process's ucred
614 	 *
615 	 * The saved uid check here is complicated: we reset the
616 	 * saved uid to the real uid if the real uid is specified
617 	 * *and* either it's changing _or_ the saved uid won't equal
618 	 * the effective uid.  So, the svuid *won't* change when
619 	 * the ruid isn't specified or when the ruid isn't changing
620 	 * and the svuid equals the requested euid.
621 	 */
622 	pruc = pr->ps_ucred;
623 	if ((ruid == (uid_t)-1 || ruid == pruc->cr_ruid) &&
624 	    (euid == (uid_t)-1 || euid == pruc->cr_uid) &&
625 	    (ruid == (uid_t)-1 || (ruid == pruc->cr_ruid &&
626 	    pruc->cr_svuid == (euid != (uid_t)-1 ? euid : pruc->cr_uid))))
627 		return (0);			/* no change */
628 
629 	/*
630 	 * Any of the real, effective, and saved uids may be changed
631 	 * to the current value of one of the three (root is not limited).
632 	 */
633 	if (ruid != (uid_t)-1 &&
634 	    ruid != uc->cr_ruid &&
635 	    ruid != uc->cr_uid &&
636 	    ruid != uc->cr_svuid &&
637 	    (error = suser(p, 0)))
638 		return (error);
639 
640 	if (euid != (uid_t)-1 &&
641 	    euid != uc->cr_ruid &&
642 	    euid != uc->cr_uid &&
643 	    euid != uc->cr_svuid &&
644 	    (error = suser(p, 0)))
645 		return (error);
646 
647 	/*
648 	 * Copy credentials so other references do not see our changes.
649 	 * ps_ucred may change during the crget().
650 	 */
651 	newcred = crget();
652 	pruc = pr->ps_ucred;
653 	crset(newcred, pruc);
654 
655 	if (ruid != (uid_t)-1)
656 		newcred->cr_ruid = ruid;
657 	if (euid != (uid_t)-1)
658 		newcred->cr_uid = euid;
659 
660 	/*
661 	 * The saved uid presents a bit of a dilemma, as it did not
662 	 * exist when setreuid(2) was conceived.  We only set the saved
663 	 * uid when the real uid is specified and either its value would
664 	 * change, or where the saved and effective uids are different.
665 	 */
666 	if (ruid != (uid_t)-1 && (ruid != pruc->cr_ruid ||
667 	    pruc->cr_svuid != (euid != (uid_t)-1 ? euid : pruc->cr_uid)))
668 		newcred->cr_svuid = ruid;
669 	pr->ps_ucred = newcred;
670 	atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
671 
672 	/* now that we can sleep, transfer proc count to new user */
673 	if (ruid != (uid_t)-1 && ruid != pruc->cr_ruid) {
674 		chgproccnt(pruc->cr_ruid, -1);
675 		chgproccnt(ruid, 1);
676 	}
677 	crfree(pruc);
678 
679 	return (0);
680 }
681 
682 int
683 sys_setuid(struct proc *p, void *v, register_t *retval)
684 {
685 	struct sys_setuid_args /* {
686 		syscallarg(uid_t) uid;
687 	} */ *uap = v;
688 	struct process *pr = p->p_p;
689 	struct ucred *pruc, *newcred, *uc = p->p_ucred;
690 	uid_t uid;
691 	int did_real, error;
692 
693 	uid = SCARG(uap, uid);
694 
695 	pruc = pr->ps_ucred;
696 	if (pruc->cr_uid == uid &&
697 	    pruc->cr_ruid == uid &&
698 	    pruc->cr_svuid == uid)
699 		return (0);
700 
701 	if (uid != uc->cr_ruid &&
702 	    uid != uc->cr_svuid &&
703 	    uid != uc->cr_uid &&
704 	    (error = suser(p, 0)))
705 		return (error);
706 
707 	/*
708 	 * Copy credentials so other references do not see our changes.
709 	 * ps_ucred may change during the crget().
710 	 */
711 	newcred = crget();
712 	pruc = pr->ps_ucred;
713 	crset(newcred, pruc);
714 
715 	/*
716 	 * Everything's okay, do it.
717 	 */
718 	if (uid == pruc->cr_uid || suser(p, 0) == 0) {
719 		did_real = 1;
720 		newcred->cr_ruid = uid;
721 		newcred->cr_svuid = uid;
722 	} else
723 		did_real = 0;
724 	newcred->cr_uid = uid;
725 	pr->ps_ucred = newcred;
726 	atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
727 
728 	/*
729 	 * Transfer proc count to new user.
730 	 */
731 	if (did_real && uid != pruc->cr_ruid) {
732 		chgproccnt(pruc->cr_ruid, -1);
733 		chgproccnt(uid, 1);
734 	}
735 	crfree(pruc);
736 
737 	return (0);
738 }
739 
740 int
741 sys_seteuid(struct proc *p, void *v, register_t *retval)
742 {
743 	struct sys_seteuid_args /* {
744 		syscallarg(uid_t) euid;
745 	} */ *uap = v;
746 	struct process *pr = p->p_p;
747 	struct ucred *pruc, *newcred, *uc = p->p_ucred;
748 	uid_t euid;
749 	int error;
750 
751 	euid = SCARG(uap, euid);
752 
753 	if (pr->ps_ucred->cr_uid == euid)
754 		return (0);
755 
756 	if (euid != uc->cr_ruid && euid != uc->cr_svuid &&
757 	    (error = suser(p, 0)))
758 		return (error);
759 
760 	/*
761 	 * Copy credentials so other references do not see our changes.
762 	 * ps_ucred may change during the crget().
763 	 */
764 	newcred = crget();
765 	pruc = pr->ps_ucred;
766 	crset(newcred, pruc);
767 	newcred->cr_uid = euid;
768 	pr->ps_ucred = newcred;
769 	atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
770 	crfree(pruc);
771 	return (0);
772 }
773 
774 int
775 sys_setgid(struct proc *p, void *v, register_t *retval)
776 {
777 	struct sys_setgid_args /* {
778 		syscallarg(gid_t) gid;
779 	} */ *uap = v;
780 	struct process *pr = p->p_p;
781 	struct ucred *pruc, *newcred, *uc = p->p_ucred;
782 	gid_t gid;
783 	int error;
784 
785 	gid = SCARG(uap, gid);
786 
787 	pruc = pr->ps_ucred;
788 	if (pruc->cr_gid == gid &&
789 	    pruc->cr_rgid == gid &&
790 	    pruc->cr_svgid == gid)
791 		return (0);
792 
793 	if (gid != uc->cr_rgid &&
794 	    gid != uc->cr_svgid &&
795 	    gid != uc->cr_gid &&
796 	    (error = suser(p, 0)))
797 		return (error);
798 
799 	/*
800 	 * Copy credentials so other references do not see our changes.
801 	 * ps_ucred may change during the crget().
802 	 */
803 	newcred = crget();
804 	pruc = pr->ps_ucred;
805 	crset(newcred, pruc);
806 
807 	if (gid == pruc->cr_gid || suser(p, 0) == 0) {
808 		newcred->cr_rgid = gid;
809 		newcred->cr_svgid = gid;
810 	}
811 	newcred->cr_gid = gid;
812 	pr->ps_ucred = newcred;
813 	atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
814 	crfree(pruc);
815 	return (0);
816 }
817 
818 int
819 sys_setegid(struct proc *p, void *v, register_t *retval)
820 {
821 	struct sys_setegid_args /* {
822 		syscallarg(gid_t) egid;
823 	} */ *uap = v;
824 	struct process *pr = p->p_p;
825 	struct ucred *pruc, *newcred, *uc = p->p_ucred;
826 	gid_t egid;
827 	int error;
828 
829 	egid = SCARG(uap, egid);
830 
831 	if (pr->ps_ucred->cr_gid == egid)
832 		return (0);
833 
834 	if (egid != uc->cr_rgid && egid != uc->cr_svgid &&
835 	    (error = suser(p, 0)))
836 		return (error);
837 
838 	/*
839 	 * Copy credentials so other references do not see our changes.
840 	 * ps_ucred may change during the crget().
841 	 */
842 	newcred = crget();
843 	pruc = pr->ps_ucred;
844 	crset(newcred, pruc);
845 	newcred->cr_gid = egid;
846 	pr->ps_ucred = newcred;
847 	atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
848 	crfree(pruc);
849 	return (0);
850 }
851 
852 int
853 sys_setgroups(struct proc *p, void *v, register_t *retval)
854 {
855 	struct sys_setgroups_args /* {
856 		syscallarg(int) gidsetsize;
857 		syscallarg(const gid_t *) gidset;
858 	} */ *uap = v;
859 	struct process *pr = p->p_p;
860 	struct ucred *pruc, *newcred;
861 	gid_t groups[NGROUPS_MAX];
862 	u_int ngrp;
863 	int error;
864 
865 	if ((error = suser(p, 0)) != 0)
866 		return (error);
867 	ngrp = SCARG(uap, gidsetsize);
868 	if (ngrp > NGROUPS_MAX)
869 		return (EINVAL);
870 	error = copyin(SCARG(uap, gidset), groups, ngrp * sizeof(gid_t));
871 	if (error == 0) {
872 		newcred = crget();
873 		pruc = pr->ps_ucred;
874 		crset(newcred, pruc);
875 		memcpy(newcred->cr_groups, groups, ngrp * sizeof(gid_t));
876 		newcred->cr_ngroups = ngrp;
877 		pr->ps_ucred = newcred;
878 		atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
879 		crfree(pruc);
880 	}
881 	return (error);
882 }
883 
884 /*
885  * Check if gid is a member of the group set.
886  */
887 int
888 groupmember(gid_t gid, struct ucred *cred)
889 {
890 	gid_t *gp;
891 	gid_t *egp;
892 
893 	if (cred->cr_gid == gid)
894 		return (1);
895 	egp = &(cred->cr_groups[cred->cr_ngroups]);
896 	for (gp = cred->cr_groups; gp < egp; gp++)
897 		if (*gp == gid)
898 			return (1);
899 	return (0);
900 }
901 
902 /*
903  * Test whether this process has special user powers.
904  * Returns 0 or error.
905  */
906 int
907 suser(struct proc *p, u_int flags)
908 {
909 	struct ucred *cred = p->p_ucred;
910 
911 	if (cred->cr_uid == 0) {
912 		if (!(flags & SUSER_NOACCT))
913 			p->p_p->ps_acflag |= ASU;
914 		return (0);
915 	}
916 	return (EPERM);
917 }
918 
919 /*
920  * replacement for old suser, for callers who don't have a process
921  */
922 int
923 suser_ucred(struct ucred *cred)
924 {
925 	if (cred->cr_uid == 0)
926 		return (0);
927 	return (EPERM);
928 }
929 
930 /*
931  * Allocate a zeroed cred structure.
932  */
933 struct ucred *
934 crget(void)
935 {
936 	struct ucred *cr;
937 
938 	cr = pool_get(&ucred_pool, PR_WAITOK|PR_ZERO);
939 	cr->cr_ref = 1;
940 	return (cr);
941 }
942 
943 /*
944  * Free a cred structure.
945  * Throws away space when ref count gets to 0.
946  */
947 void
948 crfree(struct ucred *cr)
949 {
950 
951 	if (--cr->cr_ref == 0)
952 		pool_put(&ucred_pool, cr);
953 }
954 
955 /*
956  * Copy cred structure to a new one and free the old one.
957  */
958 struct ucred *
959 crcopy(struct ucred *cr)
960 {
961 	struct ucred *newcr;
962 
963 	if (cr->cr_ref == 1)
964 		return (cr);
965 	newcr = crget();
966 	*newcr = *cr;
967 	crfree(cr);
968 	newcr->cr_ref = 1;
969 	return (newcr);
970 }
971 
972 /*
973  * Dup cred struct to a new held one.
974  */
975 struct ucred *
976 crdup(struct ucred *cr)
977 {
978 	struct ucred *newcr;
979 
980 	newcr = crget();
981 	*newcr = *cr;
982 	newcr->cr_ref = 1;
983 	return (newcr);
984 }
985 
986 /*
987  * Convert the userspace xucred to a kernel ucred
988  */
989 int
990 crfromxucred(struct ucred *cr, const struct xucred *xcr)
991 {
992 	if (xcr->cr_ngroups < 0 || xcr->cr_ngroups > NGROUPS_MAX)
993 		return (EINVAL);
994 	cr->cr_ref = 1;
995 	cr->cr_uid = xcr->cr_uid;
996 	cr->cr_gid = xcr->cr_gid;
997 	cr->cr_ngroups = xcr->cr_ngroups;
998 	memcpy(cr->cr_groups, xcr->cr_groups,
999 	    sizeof(cr->cr_groups[0]) * xcr->cr_ngroups);
1000 	return (0);
1001 }
1002 
1003 /*
1004  * Get login name, if available.
1005  */
1006 int
1007 sys_getlogin59(struct proc *p, void *v, register_t *retval)
1008 {
1009 	struct sys_getlogin59_args /* {
1010 		syscallarg(char *) namebuf;
1011 		syscallarg(u_int) namelen;
1012 	} */ *uap = v;
1013 	struct session *s = p->p_p->ps_pgrp->pg_session;
1014 
1015 	if (SCARG(uap, namelen) > sizeof(s->s_login))
1016 		SCARG(uap, namelen) = sizeof(s->s_login);
1017 	return (copyout((caddr_t)s->s_login,
1018 	    (caddr_t)SCARG(uap, namebuf), SCARG(uap, namelen)));
1019 }
1020 
1021 /*
1022  * Get login name, if available.
1023  */
1024 int
1025 sys_getlogin_r(struct proc *p, void *v, register_t *retval)
1026 {
1027 	struct sys_getlogin_r_args /* {
1028 		syscallarg(char *) namebuf;
1029 		syscallarg(size_t) namelen;
1030 	} */ *uap = v;
1031 	size_t namelen = SCARG(uap, namelen);
1032 	struct session *s = p->p_p->ps_pgrp->pg_session;
1033 	int error;
1034 
1035 	if (namelen > sizeof(s->s_login))
1036 		namelen = sizeof(s->s_login);
1037 	error = copyoutstr(s->s_login, SCARG(uap, namebuf), namelen, NULL);
1038 	if (error == ENAMETOOLONG)
1039 		error = ERANGE;
1040 	*retval = error;
1041 	return (0);
1042 }
1043 
1044 /*
1045  * Set login name.
1046  */
1047 int
1048 sys_setlogin(struct proc *p, void *v, register_t *retval)
1049 {
1050 	struct sys_setlogin_args /* {
1051 		syscallarg(const char *) namebuf;
1052 	} */ *uap = v;
1053 	struct session *s = p->p_p->ps_pgrp->pg_session;
1054 	char buf[sizeof(s->s_login)];
1055 	int error;
1056 
1057 	if ((error = suser(p, 0)) != 0)
1058 		return (error);
1059 	error = copyinstr(SCARG(uap, namebuf), buf, sizeof(buf), NULL);
1060 	if (error == 0)
1061 		strlcpy(s->s_login, buf, sizeof(s->s_login));
1062 	else if (error == ENAMETOOLONG)
1063 		error = EINVAL;
1064 	return (error);
1065 }
1066 
1067 /*
1068  * Check if a process is allowed to raise its privileges.
1069  */
1070 int
1071 proc_cansugid(struct proc *p)
1072 {
1073 	/* ptrace(2)d processes shouldn't. */
1074 	if ((p->p_p->ps_flags & PS_TRACED) != 0)
1075 		return (0);
1076 
1077 	/* processes with shared filedescriptors shouldn't. */
1078 	if (p->p_fd->fd_refcnt > 1)
1079 		return (0);
1080 
1081 	/* Allow. */
1082 	return (1);
1083 }
1084 
1085 /*
1086  * Set address of the proc's thread-control-block
1087  */
1088 int
1089 sys___set_tcb(struct proc *p, void *v, register_t *retval)
1090 {
1091 	struct sys___set_tcb_args /* {
1092 		syscallarg(void *) tcb;
1093 	} */ *uap = v;
1094 
1095 	TCB_SET(p, SCARG(uap, tcb));
1096 	return (0);
1097 }
1098 
1099 /*
1100  * Get address of the proc's thread-control-block
1101  */
1102 int
1103 sys___get_tcb(struct proc *p, void *v, register_t *retval)
1104 {
1105 	*retval = (register_t)TCB_GET(p);
1106 	return (0);
1107 }
1108 
1109 /*
1110  * Refresh the thread's reference to the process's credentials
1111  */
1112 void
1113 dorefreshcreds(struct process *pr, struct proc *p)
1114 {
1115 	struct ucred *uc = p->p_ucred;
1116 
1117 	KERNEL_LOCK();		/* XXX should be PROCESS_RLOCK(pr) */
1118 	if (uc != pr->ps_ucred) {
1119 		p->p_ucred = pr->ps_ucred;
1120 		crhold(p->p_ucred);
1121 		crfree(uc);
1122 	}
1123 	KERNEL_UNLOCK();
1124 }
1125