xref: /openbsd-src/sys/kern/kern_prot.c (revision 897fc685943471cf985a0fe38ba076ea6fe74fa5)
1 /*	$OpenBSD: kern_prot.c,v 1.73 2018/02/20 12:38:58 mpi 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 	newpgrp = pool_get(&pgrp_pool, PR_WAITOK);
226 
227 	if (pr->ps_pgid == pid || pgfind(pid) != NULL) {
228 		pool_put(&pgrp_pool, newpgrp);
229 		pool_put(&session_pool, newsess);
230 		return (EPERM);
231 	} else {
232 		enternewpgrp(pr, newpgrp, newsess);
233 		*retval = pid;
234 		return (0);
235 	}
236 }
237 
238 /*
239  * set process group (setpgid/old setpgrp)
240  *
241  * caller does setpgid(targpid, targpgid)
242  *
243  * pid must be caller or child of caller (ESRCH)
244  * if a child
245  *	pid must be in same session (EPERM)
246  *	pid can't have done an exec (EACCES)
247  * if pgid != pid
248  * 	there must exist some pid in same session having pgid (EPERM)
249  * pid must not be session leader (EPERM)
250  */
251 int
252 sys_setpgid(struct proc *curp, void *v, register_t *retval)
253 {
254 	struct sys_setpgid_args /* {
255 		syscallarg(pid_t) pid;
256 		syscallarg(pid_t) pgid;
257 	} */ *uap = v;
258 	struct process *curpr = curp->p_p;
259 	struct process *targpr;		/* target process */
260 	struct pgrp *pgrp, *newpgrp;	/* target pgrp */
261 	pid_t pid, pgid;
262 	int error;
263 
264 	pid = SCARG(uap, pid);
265 	pgid = SCARG(uap, pgid);
266 
267 	if (pgid < 0)
268 		return (EINVAL);
269 
270 	newpgrp = pool_get(&pgrp_pool, PR_WAITOK);
271 
272 	if (pid != 0 && pid != curpr->ps_pid) {
273 		if ((targpr = prfind(pid)) == 0 || !inferior(targpr, curpr)) {
274 			error = ESRCH;
275 			goto out;
276 		}
277 		if (targpr->ps_session != curpr->ps_session) {
278 			error = EPERM;
279 			goto out;
280 		}
281 		if (targpr->ps_flags & PS_EXEC) {
282 			error = EACCES;
283 			goto out;
284 		}
285 	} else
286 		targpr = curpr;
287 	if (SESS_LEADER(targpr)) {
288 		error = EPERM;
289 		goto out;
290 	}
291 	if (pgid == 0)
292 		pgid = targpr->ps_pid;
293 
294 	error = 0;
295 	if ((pgrp = pgfind(pgid)) == NULL) {
296 		/* can only create a new process group with pgid == pid */
297 		if (pgid != targpr->ps_pid)
298 			error = EPERM;
299 		else {
300 			enternewpgrp(targpr, newpgrp, NULL);
301 			newpgrp = NULL;
302 		}
303 	} else if (pgrp != targpr->ps_pgrp) {		/* anything to do? */
304 		if (pgid != targpr->ps_pid &&
305 		    pgrp->pg_session != curpr->ps_session)
306 			error = EPERM;
307 		else
308 			enterthispgrp(targpr, pgrp);
309 	}
310  out:
311 	if (newpgrp != NULL)
312 		pool_put(&pgrp_pool, newpgrp);
313 	return (error);
314 }
315 
316 int
317 sys_getresuid(struct proc *p, void *v, register_t *retval)
318 {
319 	struct sys_getresuid_args /* {
320 		syscallarg(uid_t *) ruid;
321 		syscallarg(uid_t *) euid;
322 		syscallarg(uid_t *) suid;
323 	} */ *uap = v;
324 	struct ucred *uc = p->p_ucred;
325 	uid_t *ruid, *euid, *suid;
326 	int error1 = 0, error2 = 0, error3 = 0;
327 
328 	ruid = SCARG(uap, ruid);
329 	euid = SCARG(uap, euid);
330 	suid = SCARG(uap, suid);
331 
332 	if (ruid != NULL)
333 		error1 = copyout(&uc->cr_ruid, ruid, sizeof(*ruid));
334 	if (euid != NULL)
335 		error2 = copyout(&uc->cr_uid, euid, sizeof(*euid));
336 	if (suid != NULL)
337 		error3 = copyout(&uc->cr_svuid, suid, sizeof(*suid));
338 
339 	return (error1 ? error1 : error2 ? error2 : error3);
340 }
341 
342 int
343 sys_setresuid(struct proc *p, void *v, register_t *retval)
344 {
345 	struct sys_setresuid_args /* {
346 		syscallarg(uid_t) ruid;
347 		syscallarg(uid_t) euid;
348 		syscallarg(uid_t) suid;
349 	} */ *uap = v;
350 	struct process *pr = p->p_p;
351 	struct ucred *pruc, *newcred, *uc = p->p_ucred;
352 	uid_t ruid, euid, suid;
353 	int error;
354 
355 	ruid = SCARG(uap, ruid);
356 	euid = SCARG(uap, euid);
357 	suid = SCARG(uap, suid);
358 
359 	/*
360 	 * make permission checks against the thread's ucred,
361 	 * but the actual changes will be to the process's ucred
362 	 */
363 	pruc = pr->ps_ucred;
364 	if ((ruid == (uid_t)-1 || ruid == pruc->cr_ruid) &&
365 	    (euid == (uid_t)-1 || euid == pruc->cr_uid) &&
366 	    (suid == (uid_t)-1 || suid == pruc->cr_svuid))
367 		return (0);			/* no change */
368 
369 	/*
370 	 * Any of the real, effective, and saved uids may be changed
371 	 * to the current value of one of the three (root is not limited).
372 	 */
373 	if (ruid != (uid_t)-1 &&
374 	    ruid != uc->cr_ruid &&
375 	    ruid != uc->cr_uid &&
376 	    ruid != uc->cr_svuid &&
377 	    (error = suser(p)))
378 		return (error);
379 
380 	if (euid != (uid_t)-1 &&
381 	    euid != uc->cr_ruid &&
382 	    euid != uc->cr_uid &&
383 	    euid != uc->cr_svuid &&
384 	    (error = suser(p)))
385 		return (error);
386 
387 	if (suid != (uid_t)-1 &&
388 	    suid != uc->cr_ruid &&
389 	    suid != uc->cr_uid &&
390 	    suid != uc->cr_svuid &&
391 	    (error = suser(p)))
392 		return (error);
393 
394 	/*
395 	 * Copy credentials so other references do not see our changes.
396 	 * ps_ucred may change during the crget().
397 	 */
398 	newcred = crget();
399 	pruc = pr->ps_ucred;
400 	crset(newcred, pruc);
401 
402 	/*
403 	 * Note that unlike the other set*uid() calls, each
404 	 * uid type is set independently of the others.
405 	 */
406 	if (ruid != (uid_t)-1)
407 		newcred->cr_ruid = ruid;
408 	if (euid != (uid_t)-1)
409 		newcred->cr_uid = euid;
410 	if (suid != (uid_t)-1)
411 		newcred->cr_svuid = suid;
412 	pr->ps_ucred = newcred;
413 	atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
414 
415 	/* now that we can sleep, transfer proc count to new user */
416 	if (ruid != (uid_t)-1 && ruid != pruc->cr_ruid) {
417 		chgproccnt(pruc->cr_ruid, -1);
418 		chgproccnt(ruid, 1);
419 	}
420 	crfree(pruc);
421 
422 	return (0);
423 }
424 
425 int
426 sys_getresgid(struct proc *p, void *v, register_t *retval)
427 {
428 	struct sys_getresgid_args /* {
429 		syscallarg(gid_t *) rgid;
430 		syscallarg(gid_t *) egid;
431 		syscallarg(gid_t *) sgid;
432 	} */ *uap = v;
433 	struct ucred *uc = p->p_ucred;
434 	gid_t *rgid, *egid, *sgid;
435 	int error1 = 0, error2 = 0, error3 = 0;
436 
437 	rgid = SCARG(uap, rgid);
438 	egid = SCARG(uap, egid);
439 	sgid = SCARG(uap, sgid);
440 
441 	if (rgid != NULL)
442 		error1 = copyout(&uc->cr_rgid, rgid, sizeof(*rgid));
443 	if (egid != NULL)
444 		error2 = copyout(&uc->cr_gid, egid, sizeof(*egid));
445 	if (sgid != NULL)
446 		error3 = copyout(&uc->cr_svgid, sgid, sizeof(*sgid));
447 
448 	return (error1 ? error1 : error2 ? error2 : error3);
449 }
450 
451 int
452 sys_setresgid(struct proc *p, void *v, register_t *retval)
453 {
454 	struct sys_setresgid_args /* {
455 		syscallarg(gid_t) rgid;
456 		syscallarg(gid_t) egid;
457 		syscallarg(gid_t) sgid;
458 	} */ *uap = v;
459 	struct process *pr = p->p_p;
460 	struct ucred *pruc, *newcred, *uc = p->p_ucred;
461 	gid_t rgid, egid, sgid;
462 	int error;
463 
464 	rgid = SCARG(uap, rgid);
465 	egid = SCARG(uap, egid);
466 	sgid = SCARG(uap, sgid);
467 
468 	/*
469 	 * make permission checks against the thread's ucred,
470 	 * but the actual changes will be to the process's ucred
471 	 */
472 	pruc = pr->ps_ucred;
473 	if ((rgid == (gid_t)-1 || rgid == pruc->cr_rgid) &&
474 	    (egid == (gid_t)-1 || egid == pruc->cr_gid) &&
475 	    (sgid == (gid_t)-1 || sgid == pruc->cr_svgid))
476 		return (0);			/* no change */
477 
478 	/*
479 	 * Any of the real, effective, and saved gids may be changed
480 	 * to the current value of one of the three (root is not limited).
481 	 */
482 	if (rgid != (gid_t)-1 &&
483 	    rgid != uc->cr_rgid &&
484 	    rgid != uc->cr_gid &&
485 	    rgid != uc->cr_svgid &&
486 	    (error = suser(p)))
487 		return (error);
488 
489 	if (egid != (gid_t)-1 &&
490 	    egid != uc->cr_rgid &&
491 	    egid != uc->cr_gid &&
492 	    egid != uc->cr_svgid &&
493 	    (error = suser(p)))
494 		return (error);
495 
496 	if (sgid != (gid_t)-1 &&
497 	    sgid != uc->cr_rgid &&
498 	    sgid != uc->cr_gid &&
499 	    sgid != uc->cr_svgid &&
500 	    (error = suser(p)))
501 		return (error);
502 
503 	/*
504 	 * Copy credentials so other references do not see our changes.
505 	 * ps_ucred may change during the crget().
506 	 */
507 	newcred = crget();
508 	pruc = pr->ps_ucred;
509 	crset(newcred, pruc);
510 
511 	/*
512 	 * Note that unlike the other set*gid() calls, each
513 	 * gid type is set independently of the others.
514 	 */
515 	if (rgid != (gid_t)-1)
516 		newcred->cr_rgid = rgid;
517 	if (egid != (gid_t)-1)
518 		newcred->cr_gid = egid;
519 	if (sgid != (gid_t)-1)
520 		newcred->cr_svgid = sgid;
521 	pr->ps_ucred = newcred;
522 	atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
523 	crfree(pruc);
524 	return (0);
525 }
526 
527 int
528 sys_setregid(struct proc *p, void *v, register_t *retval)
529 {
530 	struct sys_setregid_args /* {
531 		syscallarg(gid_t) rgid;
532 		syscallarg(gid_t) egid;
533 	} */ *uap = v;
534 	struct process *pr = p->p_p;
535 	struct ucred *pruc, *newcred, *uc = p->p_ucred;
536 	gid_t rgid, egid;
537 	int error;
538 
539 	rgid = SCARG(uap, rgid);
540 	egid = SCARG(uap, egid);
541 
542 	/*
543 	 * make permission checks against the thread's ucred,
544 	 * but the actual changes will be to the process's ucred
545 	 *
546 	 * The saved gid check here is complicated: we reset the
547 	 * saved gid to the real gid if the real gid is specified
548 	 * *and* either it's changing _or_ the saved gid won't equal
549 	 * the effective gid.  So, the svgid *won't* change when
550 	 * the rgid isn't specified or when the rgid isn't changing
551 	 * and the svgid equals the requested egid.
552 	 */
553 	pruc = pr->ps_ucred;
554 	if ((rgid == (gid_t)-1 || rgid == pruc->cr_rgid) &&
555 	    (egid == (gid_t)-1 || egid == pruc->cr_gid) &&
556 	    (rgid == (gid_t)-1 || (rgid == pruc->cr_rgid &&
557 	    pruc->cr_svgid == (egid != (gid_t)-1 ? egid : pruc->cr_gid))))
558 		return (0);			/* no change */
559 
560 	/*
561 	 * Any of the real, effective, and saved gids may be changed
562 	 * to the current value of one of the three (root is not limited).
563 	 */
564 	if (rgid != (gid_t)-1 &&
565 	    rgid != uc->cr_rgid &&
566 	    rgid != uc->cr_gid &&
567 	    rgid != uc->cr_svgid &&
568 	    (error = suser(p)))
569 		return (error);
570 
571 	if (egid != (gid_t)-1 &&
572 	    egid != uc->cr_rgid &&
573 	    egid != uc->cr_gid &&
574 	    egid != uc->cr_svgid &&
575 	    (error = suser(p)))
576 		return (error);
577 
578 	/*
579 	 * Copy credentials so other references do not see our changes.
580 	 * ps_ucred may change during the crget().
581 	 */
582 	newcred = crget();
583 	pruc = pr->ps_ucred;
584 	crset(newcred, pruc);
585 
586 	if (rgid != (gid_t)-1)
587 		newcred->cr_rgid = rgid;
588 	if (egid != (gid_t)-1)
589 		newcred->cr_gid = egid;
590 
591 	/*
592 	 * The saved gid presents a bit of a dilemma, as it did not
593 	 * exist when setregid(2) was conceived.  We only set the saved
594 	 * gid when the real gid is specified and either its value would
595 	 * change, or where the saved and effective gids are different.
596 	 */
597 	if (rgid != (gid_t)-1 && (rgid != pruc->cr_rgid ||
598 	    pruc->cr_svgid != (egid != (gid_t)-1 ? egid : pruc->cr_gid)))
599 		newcred->cr_svgid = rgid;
600 	pr->ps_ucred = newcred;
601 	atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
602 	crfree(pruc);
603 	return (0);
604 }
605 
606 int
607 sys_setreuid(struct proc *p, void *v, register_t *retval)
608 {
609 	struct sys_setreuid_args /* {
610 		syscallarg(uid_t) ruid;
611 		syscallarg(uid_t) euid;
612 	} */ *uap = v;
613 	struct process *pr = p->p_p;
614 	struct ucred *pruc, *newcred, *uc = p->p_ucred;
615 	uid_t ruid, euid;
616 	int error;
617 
618 	ruid = SCARG(uap, ruid);
619 	euid = SCARG(uap, euid);
620 
621 	/*
622 	 * make permission checks against the thread's ucred,
623 	 * but the actual changes will be to the process's ucred
624 	 *
625 	 * The saved uid check here is complicated: we reset the
626 	 * saved uid to the real uid if the real uid is specified
627 	 * *and* either it's changing _or_ the saved uid won't equal
628 	 * the effective uid.  So, the svuid *won't* change when
629 	 * the ruid isn't specified or when the ruid isn't changing
630 	 * and the svuid equals the requested euid.
631 	 */
632 	pruc = pr->ps_ucred;
633 	if ((ruid == (uid_t)-1 || ruid == pruc->cr_ruid) &&
634 	    (euid == (uid_t)-1 || euid == pruc->cr_uid) &&
635 	    (ruid == (uid_t)-1 || (ruid == pruc->cr_ruid &&
636 	    pruc->cr_svuid == (euid != (uid_t)-1 ? euid : pruc->cr_uid))))
637 		return (0);			/* no change */
638 
639 	/*
640 	 * Any of the real, effective, and saved uids may be changed
641 	 * to the current value of one of the three (root is not limited).
642 	 */
643 	if (ruid != (uid_t)-1 &&
644 	    ruid != uc->cr_ruid &&
645 	    ruid != uc->cr_uid &&
646 	    ruid != uc->cr_svuid &&
647 	    (error = suser(p)))
648 		return (error);
649 
650 	if (euid != (uid_t)-1 &&
651 	    euid != uc->cr_ruid &&
652 	    euid != uc->cr_uid &&
653 	    euid != uc->cr_svuid &&
654 	    (error = suser(p)))
655 		return (error);
656 
657 	/*
658 	 * Copy credentials so other references do not see our changes.
659 	 * ps_ucred may change during the crget().
660 	 */
661 	newcred = crget();
662 	pruc = pr->ps_ucred;
663 	crset(newcred, pruc);
664 
665 	if (ruid != (uid_t)-1)
666 		newcred->cr_ruid = ruid;
667 	if (euid != (uid_t)-1)
668 		newcred->cr_uid = euid;
669 
670 	/*
671 	 * The saved uid presents a bit of a dilemma, as it did not
672 	 * exist when setreuid(2) was conceived.  We only set the saved
673 	 * uid when the real uid is specified and either its value would
674 	 * change, or where the saved and effective uids are different.
675 	 */
676 	if (ruid != (uid_t)-1 && (ruid != pruc->cr_ruid ||
677 	    pruc->cr_svuid != (euid != (uid_t)-1 ? euid : pruc->cr_uid)))
678 		newcred->cr_svuid = ruid;
679 	pr->ps_ucred = newcred;
680 	atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
681 
682 	/* now that we can sleep, transfer proc count to new user */
683 	if (ruid != (uid_t)-1 && ruid != pruc->cr_ruid) {
684 		chgproccnt(pruc->cr_ruid, -1);
685 		chgproccnt(ruid, 1);
686 	}
687 	crfree(pruc);
688 
689 	return (0);
690 }
691 
692 int
693 sys_setuid(struct proc *p, void *v, register_t *retval)
694 {
695 	struct sys_setuid_args /* {
696 		syscallarg(uid_t) uid;
697 	} */ *uap = v;
698 	struct process *pr = p->p_p;
699 	struct ucred *pruc, *newcred, *uc = p->p_ucred;
700 	uid_t uid;
701 	int did_real, error;
702 
703 	uid = SCARG(uap, uid);
704 
705 	pruc = pr->ps_ucred;
706 	if (pruc->cr_uid == uid &&
707 	    pruc->cr_ruid == uid &&
708 	    pruc->cr_svuid == uid)
709 		return (0);
710 
711 	if (uid != uc->cr_ruid &&
712 	    uid != uc->cr_svuid &&
713 	    uid != uc->cr_uid &&
714 	    (error = suser(p)))
715 		return (error);
716 
717 	/*
718 	 * Copy credentials so other references do not see our changes.
719 	 * ps_ucred may change during the crget().
720 	 */
721 	newcred = crget();
722 	pruc = pr->ps_ucred;
723 	crset(newcred, pruc);
724 
725 	/*
726 	 * Everything's okay, do it.
727 	 */
728 	if (uid == pruc->cr_uid || suser(p) == 0) {
729 		did_real = 1;
730 		newcred->cr_ruid = uid;
731 		newcred->cr_svuid = uid;
732 	} else
733 		did_real = 0;
734 	newcred->cr_uid = uid;
735 	pr->ps_ucred = newcred;
736 	atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
737 
738 	/*
739 	 * Transfer proc count to new user.
740 	 */
741 	if (did_real && uid != pruc->cr_ruid) {
742 		chgproccnt(pruc->cr_ruid, -1);
743 		chgproccnt(uid, 1);
744 	}
745 	crfree(pruc);
746 
747 	return (0);
748 }
749 
750 int
751 sys_seteuid(struct proc *p, void *v, register_t *retval)
752 {
753 	struct sys_seteuid_args /* {
754 		syscallarg(uid_t) euid;
755 	} */ *uap = v;
756 	struct process *pr = p->p_p;
757 	struct ucred *pruc, *newcred, *uc = p->p_ucred;
758 	uid_t euid;
759 	int error;
760 
761 	euid = SCARG(uap, euid);
762 
763 	if (pr->ps_ucred->cr_uid == euid)
764 		return (0);
765 
766 	if (euid != uc->cr_ruid && euid != uc->cr_svuid &&
767 	    (error = suser(p)))
768 		return (error);
769 
770 	/*
771 	 * Copy credentials so other references do not see our changes.
772 	 * ps_ucred may change during the crget().
773 	 */
774 	newcred = crget();
775 	pruc = pr->ps_ucred;
776 	crset(newcred, pruc);
777 	newcred->cr_uid = euid;
778 	pr->ps_ucred = newcred;
779 	atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
780 	crfree(pruc);
781 	return (0);
782 }
783 
784 int
785 sys_setgid(struct proc *p, void *v, register_t *retval)
786 {
787 	struct sys_setgid_args /* {
788 		syscallarg(gid_t) gid;
789 	} */ *uap = v;
790 	struct process *pr = p->p_p;
791 	struct ucred *pruc, *newcred, *uc = p->p_ucred;
792 	gid_t gid;
793 	int error;
794 
795 	gid = SCARG(uap, gid);
796 
797 	pruc = pr->ps_ucred;
798 	if (pruc->cr_gid == gid &&
799 	    pruc->cr_rgid == gid &&
800 	    pruc->cr_svgid == gid)
801 		return (0);
802 
803 	if (gid != uc->cr_rgid &&
804 	    gid != uc->cr_svgid &&
805 	    gid != uc->cr_gid &&
806 	    (error = suser(p)))
807 		return (error);
808 
809 	/*
810 	 * Copy credentials so other references do not see our changes.
811 	 * ps_ucred may change during the crget().
812 	 */
813 	newcred = crget();
814 	pruc = pr->ps_ucred;
815 	crset(newcred, pruc);
816 
817 	if (gid == pruc->cr_gid || suser(p) == 0) {
818 		newcred->cr_rgid = gid;
819 		newcred->cr_svgid = gid;
820 	}
821 	newcred->cr_gid = gid;
822 	pr->ps_ucred = newcred;
823 	atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
824 	crfree(pruc);
825 	return (0);
826 }
827 
828 int
829 sys_setegid(struct proc *p, void *v, register_t *retval)
830 {
831 	struct sys_setegid_args /* {
832 		syscallarg(gid_t) egid;
833 	} */ *uap = v;
834 	struct process *pr = p->p_p;
835 	struct ucred *pruc, *newcred, *uc = p->p_ucred;
836 	gid_t egid;
837 	int error;
838 
839 	egid = SCARG(uap, egid);
840 
841 	if (pr->ps_ucred->cr_gid == egid)
842 		return (0);
843 
844 	if (egid != uc->cr_rgid && egid != uc->cr_svgid &&
845 	    (error = suser(p)))
846 		return (error);
847 
848 	/*
849 	 * Copy credentials so other references do not see our changes.
850 	 * ps_ucred may change during the crget().
851 	 */
852 	newcred = crget();
853 	pruc = pr->ps_ucred;
854 	crset(newcred, pruc);
855 	newcred->cr_gid = egid;
856 	pr->ps_ucred = newcred;
857 	atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
858 	crfree(pruc);
859 	return (0);
860 }
861 
862 int
863 sys_setgroups(struct proc *p, void *v, register_t *retval)
864 {
865 	struct sys_setgroups_args /* {
866 		syscallarg(int) gidsetsize;
867 		syscallarg(const gid_t *) gidset;
868 	} */ *uap = v;
869 	struct process *pr = p->p_p;
870 	struct ucred *pruc, *newcred;
871 	gid_t groups[NGROUPS_MAX];
872 	u_int ngrp;
873 	int error;
874 
875 	if ((error = suser(p)) != 0)
876 		return (error);
877 	ngrp = SCARG(uap, gidsetsize);
878 	if (ngrp > NGROUPS_MAX)
879 		return (EINVAL);
880 	error = copyin(SCARG(uap, gidset), groups, ngrp * sizeof(gid_t));
881 	if (error == 0) {
882 		newcred = crget();
883 		pruc = pr->ps_ucred;
884 		crset(newcred, pruc);
885 		memcpy(newcred->cr_groups, groups, ngrp * sizeof(gid_t));
886 		newcred->cr_ngroups = ngrp;
887 		pr->ps_ucred = newcred;
888 		atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
889 		crfree(pruc);
890 	}
891 	return (error);
892 }
893 
894 /*
895  * Check if gid is a member of the group set.
896  */
897 int
898 groupmember(gid_t gid, struct ucred *cred)
899 {
900 	gid_t *gp;
901 	gid_t *egp;
902 
903 	if (cred->cr_gid == gid)
904 		return (1);
905 	egp = &(cred->cr_groups[cred->cr_ngroups]);
906 	for (gp = cred->cr_groups; gp < egp; gp++)
907 		if (*gp == gid)
908 			return (1);
909 	return (0);
910 }
911 
912 /*
913  * Test whether this process has special user powers.
914  * Returns 0 or error.
915  */
916 int
917 suser(struct proc *p)
918 {
919 	struct ucred *cred = p->p_ucred;
920 
921 	if (cred->cr_uid == 0)
922 		return (0);
923 	return (EPERM);
924 }
925 
926 /*
927  * replacement for old suser, for callers who don't have a process
928  */
929 int
930 suser_ucred(struct ucred *cred)
931 {
932 	if (cred->cr_uid == 0)
933 		return (0);
934 	return (EPERM);
935 }
936 
937 /*
938  * Allocate a zeroed cred structure.
939  */
940 struct ucred *
941 crget(void)
942 {
943 	struct ucred *cr;
944 
945 	cr = pool_get(&ucred_pool, PR_WAITOK|PR_ZERO);
946 	cr->cr_ref = 1;
947 	return (cr);
948 }
949 
950 /*
951  * Free a cred structure.
952  * Throws away space when ref count gets to 0.
953  */
954 void
955 crfree(struct ucred *cr)
956 {
957 
958 	if (--cr->cr_ref == 0)
959 		pool_put(&ucred_pool, cr);
960 }
961 
962 /*
963  * Copy cred structure to a new one and free the old one.
964  */
965 struct ucred *
966 crcopy(struct ucred *cr)
967 {
968 	struct ucred *newcr;
969 
970 	if (cr->cr_ref == 1)
971 		return (cr);
972 	newcr = crget();
973 	*newcr = *cr;
974 	crfree(cr);
975 	newcr->cr_ref = 1;
976 	return (newcr);
977 }
978 
979 /*
980  * Dup cred struct to a new held one.
981  */
982 struct ucred *
983 crdup(struct ucred *cr)
984 {
985 	struct ucred *newcr;
986 
987 	newcr = crget();
988 	*newcr = *cr;
989 	newcr->cr_ref = 1;
990 	return (newcr);
991 }
992 
993 /*
994  * Convert the userspace xucred to a kernel ucred
995  */
996 int
997 crfromxucred(struct ucred *cr, const struct xucred *xcr)
998 {
999 	if (xcr->cr_ngroups < 0 || xcr->cr_ngroups > NGROUPS_MAX)
1000 		return (EINVAL);
1001 	cr->cr_ref = 1;
1002 	cr->cr_uid = xcr->cr_uid;
1003 	cr->cr_gid = xcr->cr_gid;
1004 	cr->cr_ngroups = xcr->cr_ngroups;
1005 	memcpy(cr->cr_groups, xcr->cr_groups,
1006 	    sizeof(cr->cr_groups[0]) * xcr->cr_ngroups);
1007 	return (0);
1008 }
1009 
1010 /*
1011  * Get login name, if available.
1012  */
1013 int
1014 sys_getlogin_r(struct proc *p, void *v, register_t *retval)
1015 {
1016 	struct sys_getlogin_r_args /* {
1017 		syscallarg(char *) namebuf;
1018 		syscallarg(size_t) namelen;
1019 	} */ *uap = v;
1020 	size_t namelen = SCARG(uap, namelen);
1021 	struct session *s = p->p_p->ps_pgrp->pg_session;
1022 	int error;
1023 
1024 	if (namelen > sizeof(s->s_login))
1025 		namelen = sizeof(s->s_login);
1026 	error = copyoutstr(s->s_login, SCARG(uap, namebuf), namelen, NULL);
1027 	if (error == ENAMETOOLONG)
1028 		error = ERANGE;
1029 	*retval = error;
1030 	return (0);
1031 }
1032 
1033 /*
1034  * Set login name.
1035  */
1036 int
1037 sys_setlogin(struct proc *p, void *v, register_t *retval)
1038 {
1039 	struct sys_setlogin_args /* {
1040 		syscallarg(const char *) namebuf;
1041 	} */ *uap = v;
1042 	struct session *s = p->p_p->ps_pgrp->pg_session;
1043 	char buf[sizeof(s->s_login)];
1044 	int error;
1045 
1046 	if ((error = suser(p)) != 0)
1047 		return (error);
1048 	error = copyinstr(SCARG(uap, namebuf), buf, sizeof(buf), NULL);
1049 	if (error == 0)
1050 		strlcpy(s->s_login, buf, sizeof(s->s_login));
1051 	else if (error == ENAMETOOLONG)
1052 		error = EINVAL;
1053 	return (error);
1054 }
1055 
1056 /*
1057  * Check if a process is allowed to raise its privileges.
1058  */
1059 int
1060 proc_cansugid(struct proc *p)
1061 {
1062 	/* ptrace(2)d processes shouldn't. */
1063 	if ((p->p_p->ps_flags & PS_TRACED) != 0)
1064 		return (0);
1065 
1066 	/* processes with shared filedescriptors shouldn't. */
1067 	if (p->p_fd->fd_refcnt > 1)
1068 		return (0);
1069 
1070 	/* Allow. */
1071 	return (1);
1072 }
1073 
1074 /*
1075  * Set address of the proc's thread-control-block
1076  */
1077 int
1078 sys___set_tcb(struct proc *p, void *v, register_t *retval)
1079 {
1080 	struct sys___set_tcb_args /* {
1081 		syscallarg(void *) tcb;
1082 	} */ *uap = v;
1083 	void *tcb = SCARG(uap, tcb);
1084 
1085 #ifdef TCB_INVALID
1086 	if (TCB_INVALID(tcb))
1087 		return EINVAL;
1088 #endif /* TCB_INVALID */
1089 	TCB_SET(p, tcb);
1090 	return (0);
1091 }
1092 
1093 /*
1094  * Get address of the proc's thread-control-block
1095  */
1096 int
1097 sys___get_tcb(struct proc *p, void *v, register_t *retval)
1098 {
1099 	*retval = (register_t)TCB_GET(p);
1100 	return (0);
1101 }
1102 
1103 /*
1104  * Refresh the thread's reference to the process's credentials
1105  */
1106 void
1107 dorefreshcreds(struct process *pr, struct proc *p)
1108 {
1109 	struct ucred *uc = p->p_ucred;
1110 
1111 	KERNEL_LOCK();		/* XXX should be PROCESS_RLOCK(pr) */
1112 	if (uc != pr->ps_ucred) {
1113 		p->p_ucred = pr->ps_ucred;
1114 		crhold(p->p_ucred);
1115 		crfree(uc);
1116 	}
1117 	KERNEL_UNLOCK();
1118 }
1119