1 /* $NetBSD: kern_prot.c,v 1.108 2008/10/11 13:40:57 pooka Exp $ */
4 * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 * (c) UNIX System Laboratories, Inc.
7 * All or some portions of this file are derived from material licensed
8 * to the University of California by American Telephone and Telegraph
9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10 * the permission of UNIX System Laboratories, Inc.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * @(#)kern_prot.c 8.9 (Berkeley) 2/14/95
40 * System calls related to processes and protection
43 #include <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: kern_prot.c,v 1.108 2008/10/11 13:40:57 pooka Exp $");
46 #include "opt_compat_43.h"
48 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/ucred.h>
53 #include <sys/timeb.h>
54 #include <sys/times.h>
57 #include <sys/syslog.h>
58 #include <sys/uidinfo.h>
59 #include <sys/kauth.h>
61 #include <sys/mount.h>
62 #include <sys/syscallargs.h>
64 int sys_getpid(struct lwp
*, const void *, register_t
*);
65 int sys_getpid_with_ppid(struct lwp
*, const void *, register_t
*);
66 int sys_getuid(struct lwp
*, const void *, register_t
*);
67 int sys_getuid_with_euid(struct lwp
*, const void *, register_t
*);
68 int sys_getgid(struct lwp
*, const void *, register_t
*);
69 int sys_getgid_with_egid(struct lwp
*, const void *, register_t
*);
73 sys_getpid(struct lwp
*l
, const void *v
, register_t
*retval
)
75 struct proc
*p
= l
->l_proc
;
83 sys_getpid_with_ppid(struct lwp
*l
, const void *v
, register_t
*retval
)
85 struct proc
*p
= l
->l_proc
;
88 retval
[1] = p
->p_ppid
;
94 sys_getppid(struct lwp
*l
, const void *v
, register_t
*retval
)
96 struct proc
*p
= l
->l_proc
;
102 /* Get process group ID; note that POSIX getpgrp takes no parameter */
104 sys_getpgrp(struct lwp
*l
, const void *v
, register_t
*retval
)
106 struct proc
*p
= l
->l_proc
;
108 mutex_enter(proc_lock
);
109 *retval
= p
->p_pgrp
->pg_id
;
110 mutex_exit(proc_lock
);
115 * Return the process group ID of the session leader (session ID)
116 * for the specified process.
119 sys_getsid(struct lwp
*l
, const struct sys_getsid_args
*uap
, register_t
*retval
)
122 syscalldarg(pid_t) pid;
124 pid_t pid
= SCARG(uap
, pid
);
128 mutex_enter(proc_lock
);
130 *retval
= l
->l_proc
->p_session
->s_sid
;
131 else if ((p
= p_find(pid
, PFIND_LOCKED
)) != NULL
)
132 *retval
= p
->p_session
->s_sid
;
135 mutex_exit(proc_lock
);
141 sys_getpgid(struct lwp
*l
, const struct sys_getpgid_args
*uap
, register_t
*retval
)
144 syscallarg(pid_t) pid;
146 pid_t pid
= SCARG(uap
, pid
);
150 mutex_enter(proc_lock
);
152 *retval
= l
->l_proc
->p_pgid
;
153 else if ((p
= p_find(pid
, PFIND_LOCKED
)) != NULL
)
157 mutex_exit(proc_lock
);
164 sys_getuid(struct lwp
*l
, const void *v
, register_t
*retval
)
167 *retval
= kauth_cred_getuid(l
->l_cred
);
173 sys_getuid_with_euid(struct lwp
*l
, const void *v
, register_t
*retval
)
176 retval
[0] = kauth_cred_getuid(l
->l_cred
);
177 retval
[1] = kauth_cred_geteuid(l
->l_cred
);
183 sys_geteuid(struct lwp
*l
, const void *v
, register_t
*retval
)
186 *retval
= kauth_cred_geteuid(l
->l_cred
);
192 sys_getgid(struct lwp
*l
, const void *v
, register_t
*retval
)
195 *retval
= kauth_cred_getgid(l
->l_cred
);
201 sys_getgid_with_egid(struct lwp
*l
, const void *v
, register_t
*retval
)
204 retval
[0] = kauth_cred_getgid(l
->l_cred
);
205 retval
[1] = kauth_cred_getegid(l
->l_cred
);
210 * Get effective group ID. The "egid" is groups[0], and could be obtained
211 * via getgroups. This syscall exists because it is somewhat painful to do
212 * correctly in a library function.
216 sys_getegid(struct lwp
*l
, const void *v
, register_t
*retval
)
219 *retval
= kauth_cred_getegid(l
->l_cred
);
224 sys_getgroups(struct lwp
*l
, const struct sys_getgroups_args
*uap
, register_t
*retval
)
227 syscallarg(int) gidsetsize;
228 syscallarg(gid_t *) gidset;
231 *retval
= kauth_cred_ngroups(l
->l_cred
);
232 if (SCARG(uap
, gidsetsize
) == 0)
234 if (SCARG(uap
, gidsetsize
) < *retval
)
237 return kauth_cred_getgroups(l
->l_cred
, SCARG(uap
, gidset
), *retval
,
242 sys_setsid(struct lwp
*l
, const void *v
, register_t
*retval
)
244 struct proc
*p
= l
->l_proc
;
247 error
= proc_enterpgrp(p
, p
->p_pid
, p
->p_pid
, true);
254 * set process group (setpgid/old setpgrp)
256 * caller does setpgid(targpid, targpgid)
258 * pgid must be in valid range (EINVAL)
259 * pid must be caller or child of caller (ESRCH)
261 * pid must be in same session (EPERM)
262 * pid can't have done an exec (EACCES)
264 * there must exist some pid in same session having pgid (EPERM)
265 * pid must not be session leader (EPERM)
267 * Permission checks now in proc_enterpgrp()
270 sys_setpgid(struct lwp
*l
, const struct sys_setpgid_args
*uap
,
275 syscallarg(int) pgid;
277 struct proc
*p
= l
->l_proc
;
280 if (SCARG(uap
, pgid
) < 0)
282 if ((targp
= SCARG(uap
, pid
)) == 0)
284 if ((pgid
= SCARG(uap
, pgid
)) == 0)
287 return proc_enterpgrp(p
, targp
, pgid
, false);
291 * Set real, effective and saved uids to the requested values.
292 * non-root callers can only ever change uids to values that match
293 * one of the processes current uid values.
294 * This is further restricted by the flags argument.
298 do_setresuid(struct lwp
*l
, uid_t r
, uid_t e
, uid_t sv
, u_int flags
)
300 struct proc
*p
= l
->l_proc
;
301 kauth_cred_t cred
, ncred
;
303 ncred
= kauth_cred_alloc();
305 /* Get a write lock on the process credential. */
310 * Check that the new value is one of the allowed existing values,
311 * or that we have root privilege.
314 && !((flags
& ID_R_EQ_R
) && r
== kauth_cred_getuid(cred
))
315 && !((flags
& ID_R_EQ_E
) && r
== kauth_cred_geteuid(cred
))
316 && !((flags
& ID_R_EQ_S
) && r
== kauth_cred_getsvuid(cred
))) ||
318 && !((flags
& ID_E_EQ_R
) && e
== kauth_cred_getuid(cred
))
319 && !((flags
& ID_E_EQ_E
) && e
== kauth_cred_geteuid(cred
))
320 && !((flags
& ID_E_EQ_S
) && e
== kauth_cred_getsvuid(cred
))) ||
322 && !((flags
& ID_S_EQ_R
) && sv
== kauth_cred_getuid(cred
))
323 && !((flags
& ID_S_EQ_E
) && sv
== kauth_cred_geteuid(cred
))
324 && !((flags
& ID_S_EQ_S
) && sv
== kauth_cred_getsvuid(cred
)))) {
327 error
= kauth_authorize_process(cred
, KAUTH_PROCESS_SETID
,
328 p
, NULL
, NULL
, NULL
);
330 proc_crmod_leave(cred
, ncred
, false);
335 /* If nothing has changed, short circuit the request */
336 if ((r
== -1 || r
== kauth_cred_getuid(cred
))
337 && (e
== -1 || e
== kauth_cred_geteuid(cred
))
338 && (sv
== -1 || sv
== kauth_cred_getsvuid(cred
))) {
339 proc_crmod_leave(cred
, ncred
, false);
343 kauth_cred_clone(cred
, ncred
);
345 if (r
!= -1 && r
!= kauth_cred_getuid(ncred
)) {
346 /* Update count of processes for this user */
347 (void)chgproccnt(kauth_cred_getuid(ncred
), -1);
348 (void)chgproccnt(r
, 1);
349 kauth_cred_setuid(ncred
, r
);
352 kauth_cred_setsvuid(ncred
, sv
);
354 kauth_cred_seteuid(ncred
, e
);
356 /* Broadcast our credentials to the process and other LWPs. */
357 proc_crmod_leave(ncred
, cred
, true);
363 * Set real, effective and saved gids to the requested values.
364 * non-root callers can only ever change gids to values that match
365 * one of the processes current gid values.
366 * This is further restricted by the flags argument.
370 do_setresgid(struct lwp
*l
, gid_t r
, gid_t e
, gid_t sv
, u_int flags
)
372 struct proc
*p
= l
->l_proc
;
373 kauth_cred_t cred
, ncred
;
375 ncred
= kauth_cred_alloc();
377 /* Get a write lock on the process credential. */
382 * check new value is one of the allowed existing values.
383 * otherwise, check if we have root privilege.
386 && !((flags
& ID_R_EQ_R
) && r
== kauth_cred_getgid(cred
))
387 && !((flags
& ID_R_EQ_E
) && r
== kauth_cred_getegid(cred
))
388 && !((flags
& ID_R_EQ_S
) && r
== kauth_cred_getsvgid(cred
))) ||
390 && !((flags
& ID_E_EQ_R
) && e
== kauth_cred_getgid(cred
))
391 && !((flags
& ID_E_EQ_E
) && e
== kauth_cred_getegid(cred
))
392 && !((flags
& ID_E_EQ_S
) && e
== kauth_cred_getsvgid(cred
))) ||
394 && !((flags
& ID_S_EQ_R
) && sv
== kauth_cred_getgid(cred
))
395 && !((flags
& ID_S_EQ_E
) && sv
== kauth_cred_getegid(cred
))
396 && !((flags
& ID_S_EQ_S
) && sv
== kauth_cred_getsvgid(cred
)))) {
399 error
= kauth_authorize_process(cred
, KAUTH_PROCESS_SETID
,
400 p
, NULL
, NULL
, NULL
);
402 proc_crmod_leave(cred
, ncred
, false);
407 /* If nothing has changed, short circuit the request */
408 if ((r
== -1 || r
== kauth_cred_getgid(cred
))
409 && (e
== -1 || e
== kauth_cred_getegid(cred
))
410 && (sv
== -1 || sv
== kauth_cred_getsvgid(cred
))) {
411 proc_crmod_leave(cred
, ncred
, false);
415 kauth_cred_clone(cred
, ncred
);
418 kauth_cred_setgid(ncred
, r
);
420 kauth_cred_setsvgid(ncred
, sv
);
422 kauth_cred_setegid(ncred
, e
);
424 /* Broadcast our credentials to the process and other LWPs. */
425 proc_crmod_leave(ncred
, cred
, true);
432 sys_setuid(struct lwp
*l
, const struct sys_setuid_args
*uap
, register_t
*retval
)
435 syscallarg(uid_t) uid;
437 uid_t uid
= SCARG(uap
, uid
);
439 return do_setresuid(l
, uid
, uid
, uid
,
440 ID_R_EQ_R
| ID_E_EQ_R
| ID_S_EQ_R
);
445 sys_seteuid(struct lwp
*l
, const struct sys_seteuid_args
*uap
, register_t
*retval
)
448 syscallarg(uid_t) euid;
451 return do_setresuid(l
, -1, SCARG(uap
, euid
), -1, ID_E_EQ_R
| ID_E_EQ_S
);
455 sys_setreuid(struct lwp
*l
, const struct sys_setreuid_args
*uap
, register_t
*retval
)
458 syscallarg(uid_t) ruid;
459 syscallarg(uid_t) euid;
461 kauth_cred_t cred
= l
->l_cred
;
462 uid_t ruid
, euid
, svuid
;
464 ruid
= SCARG(uap
, ruid
);
465 euid
= SCARG(uap
, euid
);
468 ruid
= kauth_cred_getuid(cred
);
470 euid
= kauth_cred_geteuid(cred
);
472 /* Saved uid is set to the new euid if the ruid changed */
473 svuid
= (ruid
== kauth_cred_getuid(cred
)) ? -1 : euid
;
475 return do_setresuid(l
, ruid
, euid
, svuid
,
476 ID_R_EQ_R
| ID_R_EQ_E
|
477 ID_E_EQ_R
| ID_E_EQ_E
| ID_E_EQ_S
|
478 ID_S_EQ_R
| ID_S_EQ_E
| ID_S_EQ_S
);
483 sys_setgid(struct lwp
*l
, const struct sys_setgid_args
*uap
, register_t
*retval
)
486 syscallarg(gid_t) gid;
488 gid_t gid
= SCARG(uap
, gid
);
490 return do_setresgid(l
, gid
, gid
, gid
,
491 ID_R_EQ_R
| ID_E_EQ_R
| ID_S_EQ_R
);
496 sys_setegid(struct lwp
*l
, const struct sys_setegid_args
*uap
, register_t
*retval
)
499 syscallarg(gid_t) egid;
502 return do_setresgid(l
, -1, SCARG(uap
, egid
), -1, ID_E_EQ_R
| ID_E_EQ_S
);
506 sys_setregid(struct lwp
*l
, const struct sys_setregid_args
*uap
, register_t
*retval
)
509 syscallarg(gid_t) rgid;
510 syscallarg(gid_t) egid;
512 kauth_cred_t cred
= l
->l_cred
;
513 gid_t rgid
, egid
, svgid
;
515 rgid
= SCARG(uap
, rgid
);
516 egid
= SCARG(uap
, egid
);
519 rgid
= kauth_cred_getgid(cred
);
521 egid
= kauth_cred_getegid(cred
);
523 /* Saved gid is set to the new egid if the rgid changed */
524 svgid
= rgid
== kauth_cred_getgid(cred
) ? -1 : egid
;
526 return do_setresgid(l
, rgid
, egid
, svgid
,
527 ID_R_EQ_R
| ID_R_EQ_E
|
528 ID_E_EQ_R
| ID_E_EQ_E
| ID_E_EQ_S
|
529 ID_S_EQ_R
| ID_S_EQ_E
| ID_S_EQ_S
);
533 sys_issetugid(struct lwp
*l
, const void *v
, register_t
*retval
)
535 struct proc
*p
= l
->l_proc
;
538 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
539 * we use PK_SUGID because we consider changing the owners as
540 * "tainting" as well.
541 * This is significant for procs that start as root and "become"
542 * a user without an exec - programs cannot know *everything*
543 * that libc *might* have put in their data segment.
545 *retval
= (p
->p_flag
& PK_SUGID
) != 0;
551 sys_setgroups(struct lwp
*l
, const struct sys_setgroups_args
*uap
, register_t
*retval
)
554 syscallarg(int) gidsetsize;
555 syscallarg(const gid_t *) gidset;
560 ncred
= kauth_cred_alloc();
561 error
= kauth_cred_setgroups(ncred
, SCARG(uap
, gidset
),
562 SCARG(uap
, gidsetsize
), -1, UIO_USERSPACE
);
564 kauth_cred_free(ncred
);
568 return kauth_proc_setgroups(l
, ncred
);
572 * Get login name, if available.
576 sys___getlogin(struct lwp
*l
, const struct sys___getlogin_args
*uap
, register_t
*retval
)
579 syscallarg(char *) namebuf;
580 syscallarg(size_t) namelen;
582 struct proc
*p
= l
->l_proc
;
583 char login
[sizeof(p
->p_session
->s_login
)];
584 int namelen
= SCARG(uap
, namelen
);
586 if (namelen
> sizeof(login
))
587 namelen
= sizeof(login
);
588 mutex_enter(proc_lock
);
589 memcpy(login
, p
->p_session
->s_login
, namelen
);
590 mutex_exit(proc_lock
);
591 return (copyout(login
, (void *)SCARG(uap
, namebuf
), namelen
));
599 sys___setlogin(struct lwp
*l
, const struct sys___setlogin_args
*uap
, register_t
*retval
)
602 syscallarg(const char *) namebuf;
604 struct proc
*p
= l
->l_proc
;
606 char newname
[sizeof sp
->s_login
+ 1];
609 if ((error
= kauth_authorize_process(l
->l_cred
, KAUTH_PROCESS_SETID
,
610 p
, NULL
, NULL
, NULL
)) != 0)
612 error
= copyinstr(SCARG(uap
, namebuf
), &newname
, sizeof newname
, NULL
);
614 return (error
== ENAMETOOLONG
? EINVAL
: error
);
616 mutex_enter(proc_lock
);
618 if (sp
->s_flags
& S_LOGIN_SET
&& p
->p_pid
!= sp
->s_sid
&&
619 strncmp(newname
, sp
->s_login
, sizeof sp
->s_login
) != 0)
620 log(LOG_WARNING
, "%s (pid %d) changing logname from "
621 "%.*s to %s\n", p
->p_comm
, p
->p_pid
,
622 (int)sizeof sp
->s_login
, sp
->s_login
, newname
);
623 sp
->s_flags
|= S_LOGIN_SET
;
624 strncpy(sp
->s_login
, newname
, sizeof sp
->s_login
);
625 mutex_exit(proc_lock
);