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