diff options
author | rwatson <rwatson@FreeBSD.org> | 2006-11-06 13:42:10 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2006-11-06 13:42:10 +0000 |
commit | 10d0d9cf473dc5f0ce1bf263ead445ffe7819154 (patch) | |
tree | b9dd284620eeaddbff089cef10e4b1afb7918279 /sys/kern | |
parent | 7288104e2094825a9c98b9923f039817a76e2983 (diff) | |
download | FreeBSD-src-10d0d9cf473dc5f0ce1bf263ead445ffe7819154.zip FreeBSD-src-10d0d9cf473dc5f0ce1bf263ead445ffe7819154.tar.gz |
Sweep kernel replacing suser(9) calls with priv(9) calls, assigning
specific privilege names to a broad range of privileges. These may
require some future tweaking.
Sponsored by: nCircle Network Security, Inc.
Obtained from: TrustedBSD Project
Discussed on: arch@
Reviewed (at least in part) by: mlaier, jmg, pjd, bde, ceri,
Alex Lyashkov <umka at sevcity dot net>,
Skip Ford <skip dot ford at verizon dot net>,
Antoine Brodin <antoine dot brodin at laposte dot net>
Diffstat (limited to 'sys/kern')
33 files changed, 367 insertions, 248 deletions
diff --git a/sys/kern/kern_acct.c b/sys/kern/kern_acct.c index ec7289f..e3b108c 100644 --- a/sys/kern/kern_acct.c +++ b/sys/kern/kern_acct.c @@ -56,6 +56,7 @@ __FBSDID("$FreeBSD$"); #include <sys/mount.h> #include <sys/mutex.h> #include <sys/namei.h> +#include <sys/priv.h> #include <sys/proc.h> #include <sys/resourcevar.h> #include <sys/sched.h> @@ -166,8 +167,7 @@ acct(struct thread *td, struct acct_args *uap) struct nameidata nd; int error, flags, vfslocked; - /* Make sure that the caller is root. */ - error = suser(td); + error = priv_check(td, PRIV_ACCT); if (error) return (error); diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index b62c977..685222c 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -57,6 +57,7 @@ __FBSDID("$FreeBSD$"); #include <sys/mqueue.h> #include <sys/mutex.h> #include <sys/namei.h> +#include <sys/priv.h> #include <sys/proc.h> #include <sys/resourcevar.h> #include <sys/signalvar.h> @@ -1351,7 +1352,7 @@ falloc(struct thread *td, struct file **resultfp, int *resultfd) sx_xlock(&filelist_lock); if ((openfiles >= maxuserfiles && - suser_cred(td->td_ucred, SUSER_RUID) != 0) || + priv_check_cred(td->td_ucred, PRIV_MAXFILES, SUSER_RUID) != 0) || openfiles >= maxfiles) { if (ppsratecheck(&lastfail, &curfail, 1)) { printf("kern.maxfiles limit exceeded by uid %i, please see tuning(7).\n", diff --git a/sys/kern/kern_environment.c b/sys/kern/kern_environment.c index ff26529..1d33626 100644 --- a/sys/kern/kern_environment.c +++ b/sys/kern/kern_environment.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); #include <sys/lock.h> #include <sys/malloc.h> #include <sys/mutex.h> +#include <sys/priv.h> #include <sys/kernel.h> #include <sys/systm.h> #include <sys/sysent.h> @@ -125,11 +126,18 @@ kenv(td, uap) return (error); } - if ((uap->what == KENV_SET) || - (uap->what == KENV_UNSET)) { - error = suser(td); + switch (uap->what) { + case KENV_SET: + error = priv_check(td, PRIV_KENV_SET); + if (error) + return (error); + break; + + case KENV_UNSET: + error = priv_check(td, PRIV_KENV_UNSET); if (error) return (error); + break; } name = malloc(KENV_MNAMELEN, M_TEMP, M_WAITOK); diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index e513908..75843eb 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$"); #include <sys/imgact_elf.h> #include <sys/wait.h> #include <sys/malloc.h> +#include <sys/priv.h> #include <sys/proc.h> #include <sys/pioctl.h> #include <sys/namei.h> @@ -571,8 +572,11 @@ interpret: * we do not regain any tracing during a possible block. */ setsugid(p); + #ifdef KTRACE - if (p->p_tracevp != NULL && suser_cred(oldcred, SUSER_ALLOWJAIL)) { + if (p->p_tracevp != NULL && + priv_check_cred(oldcred, PRIV_DEBUG_DIFFCRED, + SUSER_ALLOWJAIL)) { mtx_lock(&ktrace_mtx); p->p_traceflag = 0; tracevp = p->p_tracevp; diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index e92720b..9c5597e 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include <sys/lock.h> #include <sys/malloc.h> #include <sys/mutex.h> +#include <sys/priv.h> #include <sys/proc.h> #include <sys/pioctl.h> #include <sys/resourcevar.h> @@ -310,7 +311,7 @@ fork1(td, flags, pages, procp) */ sx_xlock(&allproc_lock); if ((nprocs >= maxproc - 10 && - suser_cred(td->td_ucred, SUSER_RUID) != 0) || + priv_check_cred(td->td_ucred, PRIV_MAXPROC, SUSER_RUID) != 0) || nprocs >= maxproc) { error = EAGAIN; goto fail; @@ -319,8 +320,11 @@ fork1(td, flags, pages, procp) /* * Increment the count of procs running with this uid. Don't allow * a nonprivileged user to exceed their current limit. + * + * XXXRW: Can we avoid privilege here if it's not needed? */ - error = suser_cred(td->td_ucred, SUSER_RUID | SUSER_ALLOWJAIL); + error = priv_check_cred(td->td_ucred, PRIV_PROC_LIMIT, SUSER_RUID | + SUSER_ALLOWJAIL); if (error == 0) ok = chgproccnt(td->td_ucred->cr_ruidinfo, 1, 0); else { diff --git a/sys/kern/kern_ktrace.c b/sys/kern/kern_ktrace.c index e79fa7c..b5a4456 100644 --- a/sys/kern/kern_ktrace.c +++ b/sys/kern/kern_ktrace.c @@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$"); #include <sys/malloc.h> #include <sys/mount.h> #include <sys/namei.h> +#include <sys/priv.h> #include <sys/proc.h> #include <sys/unistd.h> #include <sys/vnode.h> @@ -807,7 +808,8 @@ ktrops(td, p, ops, facs, vp) p->p_tracecred = crhold(td->td_ucred); } p->p_traceflag |= facs; - if (suser_cred(td->td_ucred, SUSER_ALLOWJAIL) == 0) + if (priv_check_cred(td->td_ucred, PRIV_KTRACE, + SUSER_ALLOWJAIL) == 0) p->p_traceflag |= KTRFAC_ROOT; } else { /* KTROP_CLEAR */ @@ -1013,7 +1015,7 @@ ktrcanset(td, targetp) PROC_LOCK_ASSERT(targetp, MA_OWNED); if (targetp->p_traceflag & KTRFAC_ROOT && - suser_cred(td->td_ucred, SUSER_ALLOWJAIL)) + priv_check_cred(td->td_ucred, PRIV_KTRACE, SUSER_ALLOWJAIL)) return (0); if (p_candebug(td, targetp) != 0) diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c index 0bdd9f8..6d0dd0f 100644 --- a/sys/kern/kern_linker.c +++ b/sys/kern/kern_linker.c @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$"); #include <sys/malloc.h> #include <sys/sysproto.h> #include <sys/sysent.h> +#include <sys/priv.h> #include <sys/proc.h> #include <sys/lock.h> #include <sys/mutex.h> @@ -854,7 +855,7 @@ kern_kldload(struct thread *td, const char *file, int *fileid) if ((error = securelevel_gt(td->td_ucred, 0)) != 0) return (error); - if ((error = suser(td)) != 0) + if ((error = priv_check(td, PRIV_KLD_LOAD)) != 0) return (error); /* @@ -921,7 +922,7 @@ kern_kldunload(struct thread *td, int fileid, int flags) if ((error = securelevel_gt(td->td_ucred, 0)) != 0) return (error); - if ((error = suser(td)) != 0) + if ((error = priv_check(td, PRIV_KLD_UNLOAD)) != 0) return (error); KLD_LOCK(); diff --git a/sys/kern/kern_ntptime.c b/sys/kern/kern_ntptime.c index 53deb9f..87d10d7 100644 --- a/sys/kern/kern_ntptime.c +++ b/sys/kern/kern_ntptime.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/sysproto.h> #include <sys/kernel.h> +#include <sys/priv.h> #include <sys/proc.h> #include <sys/lock.h> #include <sys/mutex.h> @@ -333,7 +334,7 @@ ntp_adjtime(struct thread *td, struct ntp_adjtime_args *uap) mtx_lock(&Giant); modes = ntv.modes; if (modes) - error = suser(td); + error = priv_check(td, PRIV_NTP_ADJTIME); if (error) goto done2; s = splclock(); @@ -954,7 +955,7 @@ kern_adjtime(struct thread *td, struct timeval *delta, struct timeval *olddelta) struct timeval atv; int error; - if ((error = suser(td))) + if ((error = priv_check(td, PRIV_ADJTIME))) return (error); mtx_lock(&Giant); diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c index 524631f..3ba110f 100644 --- a/sys/kern/kern_resource.c +++ b/sys/kern/kern_resource.c @@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$"); #include <sys/lock.h> #include <sys/malloc.h> #include <sys/mutex.h> +#include <sys/priv.h> #include <sys/proc.h> #include <sys/refcount.h> #include <sys/resourcevar.h> @@ -264,7 +265,7 @@ donice(struct thread *td, struct proc *p, int n) n = PRIO_MAX; if (n < PRIO_MIN) n = PRIO_MIN; - if (n < p->p_nice && suser(td) != 0) + if (n < p->p_nice && priv_check(td, PRIV_SCHED_SETPRIORITY) != 0) return (EACCES); mtx_lock_spin(&sched_lock); sched_nice(p, n); @@ -468,7 +469,7 @@ rtprio(td, uap) break; /* Disallow setting rtprio in most cases if not superuser. */ - if (suser(td) != 0) { + if (priv_check(td, PRIV_SCHED_RTPRIO) != 0) { /* can't set someone else's */ if (uap->pid) { error = EPERM; @@ -754,7 +755,8 @@ kern_setrlimit(td, which, limp) alimp = &oldlim->pl_rlimit[which]; if (limp->rlim_cur > alimp->rlim_max || limp->rlim_max > alimp->rlim_max) - if ((error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL))) { + if ((error = priv_check_cred(td->td_ucred, + PRIV_PROC_SETRLIMIT, SUSER_ALLOWJAIL))) { PROC_UNLOCK(p); lim_free(newlim); return (error); diff --git a/sys/kern/kern_shutdown.c b/sys/kern/kern_shutdown.c index a5bcfa8..a20daa7 100644 --- a/sys/kern/kern_shutdown.c +++ b/sys/kern/kern_shutdown.c @@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$"); #include <sys/kthread.h> #include <sys/malloc.h> #include <sys/mount.h> +#include <sys/priv.h> #include <sys/proc.h> #include <sys/reboot.h> #include <sys/resourcevar.h> @@ -164,7 +165,7 @@ reboot(struct thread *td, struct reboot_args *uap) error = mac_check_system_reboot(td->td_ucred, uap->opt); #endif if (error == 0) - error = suser(td); + error = priv_check(td, PRIV_REBOOT); if (error == 0) { mtx_lock(&Giant); boot(uap->opt); diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c index a929291..6015551 100644 --- a/sys/kern/kern_sysctl.c +++ b/sys/kern/kern_sysctl.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); #include <sys/kernel.h> #include <sys/sysctl.h> #include <sys/malloc.h> +#include <sys/priv.h> #include <sys/proc.h> #include <sys/lock.h> #include <sys/mutex.h> @@ -512,7 +513,7 @@ sysctl_sysctl_debug(SYSCTL_HANDLER_ARGS) { int error; - error = suser(req->td); + error = priv_check(req->td, PRIV_SYSCTL_DEBUG); if (error) return (error); sysctl_sysctl_debug_dump_node(&sysctl__children, 0); @@ -1253,13 +1254,11 @@ sysctl_root(SYSCTL_HANDLER_ARGS) /* Is this sysctl writable by only privileged users? */ if (req->newptr && !(oid->oid_kind & CTLFLAG_ANYBODY)) { - int flags; - if (oid->oid_kind & CTLFLAG_PRISON) - flags = SUSER_ALLOWJAIL; + error = priv_check_cred(req->td->td_ucred, + PRIV_SYSCTL_WRITEJAIL, SUSER_ALLOWJAIL); else - flags = 0; - error = suser_cred(req->td->td_ucred, flags); + error = priv_check(req->td, PRIV_SYSCTL_WRITE); if (error) return (error); } diff --git a/sys/kern/kern_thr.c b/sys/kern/kern_thr.c index bfa1e2b..72798ac 100644 --- a/sys/kern/kern_thr.c +++ b/sys/kern/kern_thr.c @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include <sys/kernel.h> #include <sys/lock.h> #include <sys/mutex.h> +#include <sys/priv.h> #include <sys/proc.h> #include <sys/resourcevar.h> #include <sys/sched.h> @@ -164,7 +165,7 @@ create_thread(struct thread *td, mcontext_t *ctx, case RTP_PRIO_REALTIME: case RTP_PRIO_FIFO: /* Only root can set scheduler policy */ - if (suser(td) != 0) + if (priv_check(td, PRIV_SCHED_SETPOLICY) != 0) return (EPERM); if (rtp->prio > RTP_PRIO_MAX) return (EINVAL); diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c index 479348e..53ce9e4 100644 --- a/sys/kern/kern_time.c +++ b/sys/kern/kern_time.c @@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$"); #include <sys/syscallsubr.h> #include <sys/sysctl.h> #include <sys/sysent.h> +#include <sys/priv.h> #include <sys/proc.h> #include <sys/time.h> #include <sys/timers.h> @@ -286,7 +287,7 @@ kern_clock_settime(struct thread *td, clockid_t clock_id, struct timespec *ats) if (error) return (error); #endif - if ((error = suser(td)) != 0) + if ((error = priv_check(td, PRIV_CLOCK_SETTIME)) != 0) return (error); if (clock_id != CLOCK_REALTIME) return (EINVAL); @@ -504,7 +505,7 @@ kern_settimeofday(struct thread *td, struct timeval *tv, struct timezone *tzp) if (error) return (error); #endif - error = suser(td); + error = priv_check(td, PRIV_SETTIMEOFDAY); if (error) return (error); /* Verify all parameters before changing time. */ diff --git a/sys/kern/kern_umtx.c b/sys/kern/kern_umtx.c index d6c8c2d..e9513c8 100644 --- a/sys/kern/kern_umtx.c +++ b/sys/kern/kern_umtx.c @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include <sys/lock.h> #include <sys/malloc.h> #include <sys/mutex.h> +#include <sys/priv.h> #include <sys/proc.h> #include <sys/sched.h> #include <sys/sysctl.h> @@ -1813,7 +1814,7 @@ _do_lock_pp(struct thread *td, struct umutex *m, uint32_t flags, int timo, if ((error = umtx_key_get(m, TYPE_PP_UMUTEX, GET_SHARE(flags), &uq->uq_key)) != 0) return (error); - su = (suser(td) == 0); + su = (priv_check(td, PRIV_SCHED_RTPRIO) == 0); for (;;) { old_inherited_pri = uq->uq_inherited_pri; umtxq_lock(&uq->uq_key); @@ -1934,7 +1935,7 @@ do_unlock_pp(struct thread *td, struct umutex *m, uint32_t flags) id = td->td_tid; uq = td->td_umtxq; - su = (suser(td) == 0); + su = (priv_check(td, PRIV_SCHED_RTPRIO) == 0); /* * Make sure we own this mtx. diff --git a/sys/kern/kern_xxx.c b/sys/kern/kern_xxx.c index d93ba37..81c2df4 100644 --- a/sys/kern/kern_xxx.c +++ b/sys/kern/kern_xxx.c @@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/sysproto.h> #include <sys/kernel.h> +#include <sys/priv.h> #include <sys/proc.h> #include <sys/lock.h> #include <sys/mutex.h> @@ -139,7 +140,8 @@ osethostid(td, uap) { int error; - if ((error = suser(td))) + error = priv_check(td, PRIV_SETHOSTID); + if (error) return (error); mtx_lock(&Giant); hostid = uap->hostid; @@ -295,9 +297,10 @@ setdomainname(td, uap) { int error, domainnamelen; + error = priv_check(td, PRIV_SETDOMAINNAME); + if (error) + return (error); mtx_lock(&Giant); - if ((error = suser(td))) - goto done2; if ((u_int)uap->len > sizeof (domainname) - 1) { error = EINVAL; goto done2; @@ -309,4 +312,3 @@ done2: mtx_unlock(&Giant); return (error); } - diff --git a/sys/kern/p1003_1b.c b/sys/kern/p1003_1b.c index 189f593..8ed0de5 100644 --- a/sys/kern/p1003_1b.c +++ b/sys/kern/p1003_1b.c @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include <sys/lock.h> #include <sys/module.h> #include <sys/mutex.h> +#include <sys/priv.h> #include <sys/proc.h> #include <sys/syscallsubr.h> #include <sys/sysctl.h> @@ -186,9 +187,10 @@ sched_setscheduler(struct thread *td, struct sched_setscheduler_args *uap) struct thread *targettd; struct proc *targetp; - /* Don't allow non root user to set a scheduler policy */ - if (suser(td) != 0) - return (EPERM); + /* Don't allow non root user to set a scheduler policy. */ + e = priv_check(td, PRIV_SCHED_SET); + if (e) + return (e); e = copyin(uap->param, &sched_param, sizeof(sched_param)); if (e) diff --git a/sys/kern/subr_acl_posix1e.c b/sys/kern/subr_acl_posix1e.c index a3ea703..94c612f 100644 --- a/sys/kern/subr_acl_posix1e.c +++ b/sys/kern/subr_acl_posix1e.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> #include <sys/mount.h> +#include <sys/priv.h> #include <sys/vnode.h> #include <sys/errno.h> #include <sys/stat.h> @@ -46,9 +47,9 @@ __FBSDID("$FreeBSD$"); /* * Implement a version of vaccess() that understands POSIX.1e ACL semantics; - * the access ACL has already been prepared for evaluation by the file - * system and is passed via 'uid', 'gid', and 'acl'. Return 0 on success, - * else an errno value. + * the access ACL has already been prepared for evaluation by the file system + * and is passed via 'uid', 'gid', and 'acl'. Return 0 on success, else an + * errno value. */ int vaccess_acl_posix1e(enum vtype type, uid_t file_uid, gid_t file_gid, @@ -56,14 +57,14 @@ vaccess_acl_posix1e(enum vtype type, uid_t file_uid, gid_t file_gid, { struct acl_entry *acl_other, *acl_mask; mode_t dac_granted; - mode_t cap_granted; + mode_t priv_granted; mode_t acl_mask_granted; int group_matched, i; /* * Look for a normal, non-privileged way to access the file/directory * as requested. If it exists, go with that. Otherwise, attempt to - * use privileges granted via cap_granted. In some cases, which + * use privileges granted via priv_granted. In some cases, which * privileges to use may be ambiguous due to "best match", in which * case fall back on first match for the time being. */ @@ -72,40 +73,34 @@ vaccess_acl_posix1e(enum vtype type, uid_t file_uid, gid_t file_gid, /* * Determine privileges now, but don't apply until we've found a DAC - * entry that matches but has failed to allow access. POSIX.1e - * capabilities are not implemented, but we document how they would - * behave here if implemented. + * entry that matches but has failed to allow access. + * + * XXXRW: Ideally, we'd determine the privileges required before + * asking for them. */ -#ifndef CAPABILITIES - if (suser_cred(cred, SUSER_ALLOWJAIL) == 0) - cap_granted = VALLPERM; - else - cap_granted = 0; -#else - cap_granted = 0; + priv_granted = 0; if (type == VDIR) { - if ((acc_mode & VEXEC) && !cap_check(cred, NULL, - CAP_DAC_READ_SEARCH, SUSER_ALLOWJAIL)) - cap_granted |= VEXEC; + if ((acc_mode & VEXEC) && !priv_check_cred(cred, + PRIV_VFS_LOOKUP, SUSER_ALLOWJAIL)) + priv_granted |= VEXEC; } else { - if ((acc_mode & VEXEC) && !cap_check(cred, NULL, - CAP_DAC_EXECUTE, SUSER_ALLOWJAIL)) - cap_granted |= VEXEC; + if ((acc_mode & VEXEC) && !priv_check_cred(cred, + PRIV_VFS_EXEC, SUSER_ALLOWJAIL)) + priv_granted |= VEXEC; } - if ((acc_mode & VREAD) && !cap_check(cred, NULL, CAP_DAC_READ_SEARCH, + if ((acc_mode & VREAD) && !priv_check_cred(cred, PRIV_VFS_READ, SUSER_ALLOWJAIL)) - cap_granted |= VREAD; + priv_granted |= VREAD; if (((acc_mode & VWRITE) || (acc_mode & VAPPEND)) && - !cap_check(cred, NULL, CAP_DAC_WRITE, SUSER_ALLOWJAIL)) - cap_granted |= (VWRITE | VAPPEND); + !priv_check_cred(cred, PRIV_VFS_WRITE, SUSER_ALLOWJAIL)) + priv_granted |= (VWRITE | VAPPEND); - if ((acc_mode & VADMIN) && !cap_check(cred, NULL, CAP_FOWNER, + if ((acc_mode & VADMIN) && !priv_check_cred(cred, PRIV_VFS_ADMIN, SUSER_ALLOWJAIL)) - cap_granted |= VADMIN; -#endif /* CAPABILITIES */ + priv_granted |= VADMIN; /* * The owner matches if the effective uid associated with the @@ -129,7 +124,11 @@ vaccess_acl_posix1e(enum vtype type, uid_t file_uid, gid_t file_gid, dac_granted |= (VWRITE | VAPPEND); if ((acc_mode & dac_granted) == acc_mode) return (0); - if ((acc_mode & (dac_granted | cap_granted)) == + + /* + * XXXRW: Do privilege lookup here. + */ + if ((acc_mode & (dac_granted | priv_granted)) == acc_mode) { if (privused != NULL) *privused = 1; @@ -183,13 +182,9 @@ vaccess_acl_posix1e(enum vtype type, uid_t file_uid, gid_t file_gid, acl_mask_granted = VEXEC | VREAD | VWRITE | VAPPEND; /* - * Iterate through user ACL entries. Do checks twice, first without - * privilege, and then if a match is found but failed, a second time - * with privilege. - */ - - /* - * Check ACL_USER ACL entries. + * Check ACL_USER ACL entries. There will either be one or no + * matches; if there is one, we accept or rejected based on the + * match; otherwise, we continue on to groups. */ for (i = 0; i < acl->acl_cnt; i++) { switch (acl->acl_entry[i].ae_tag) { @@ -206,7 +201,10 @@ vaccess_acl_posix1e(enum vtype type, uid_t file_uid, gid_t file_gid, dac_granted &= acl_mask_granted; if ((acc_mode & dac_granted) == acc_mode) return (0); - if ((acc_mode & (dac_granted | cap_granted)) != + /* + * XXXRW: Do privilege lookup here. + */ + if ((acc_mode & (dac_granted | priv_granted)) != acc_mode) goto error; @@ -286,8 +284,11 @@ vaccess_acl_posix1e(enum vtype type, uid_t file_uid, gid_t file_gid, dac_granted |= (VWRITE | VAPPEND); dac_granted &= acl_mask_granted; - if ((acc_mode & (dac_granted | cap_granted)) != - acc_mode) + /* + * XXXRW: Do privilege lookup here. + */ + if ((acc_mode & (dac_granted | priv_granted)) + != acc_mode) break; if (privused != NULL) @@ -307,8 +308,11 @@ vaccess_acl_posix1e(enum vtype type, uid_t file_uid, gid_t file_gid, dac_granted |= (VWRITE | VAPPEND); dac_granted &= acl_mask_granted; - if ((acc_mode & (dac_granted | cap_granted)) != - acc_mode) + /* + * XXXRW: Do privilege lookup here. + */ + if ((acc_mode & (dac_granted | priv_granted)) + != acc_mode) break; if (privused != NULL) @@ -339,7 +343,10 @@ vaccess_acl_posix1e(enum vtype type, uid_t file_uid, gid_t file_gid, if ((acc_mode & dac_granted) == acc_mode) return (0); - if ((acc_mode & (dac_granted | cap_granted)) == acc_mode) { + /* + * XXXRW: Do privilege lookup here. + */ + if ((acc_mode & (dac_granted | priv_granted)) == acc_mode) { if (privused != NULL) *privused = 1; return (0); diff --git a/sys/kern/subr_firmware.c b/sys/kern/subr_firmware.c index 6de4fa4..a83e567 100644 --- a/sys/kern/subr_firmware.c +++ b/sys/kern/subr_firmware.c @@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include <sys/errno.h> #include <sys/linker.h> #include <sys/firmware.h> +#include <sys/priv.h> #include <sys/proc.h> #include <sys/module.h> @@ -190,7 +191,8 @@ again: return NULL; } td = curthread; - if (suser(td) != 0 || securelevel_gt(td->td_ucred, 0) != 0) { + if (priv_check(td, PRIV_FIRMWARE_LOAD) != 0 || + securelevel_gt(td->td_ucred, 0) != 0) { printf("%s: insufficient privileges to " "load firmware image %s\n", __func__, imagename); return NULL; diff --git a/sys/kern/subr_prf.c b/sys/kern/subr_prf.c index b6ffc91..c53bf98 100644 --- a/sys/kern/subr_prf.c +++ b/sys/kern/subr_prf.c @@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$"); #include <sys/kernel.h> #include <sys/msgbuf.h> #include <sys/malloc.h> +#include <sys/priv.h> #include <sys/proc.h> #include <sys/stddef.h> #include <sys/sysctl.h> @@ -925,7 +926,7 @@ sysctl_kern_msgbuf(SYSCTL_HANDLER_ARGS) int error, len; if (!unprivileged_read_msgbuf) { - error = suser(req->td); + error = priv_check(req->td, PRIV_MSGBUF); if (error) return (error); } diff --git a/sys/kern/subr_witness.c b/sys/kern/subr_witness.c index 4018d3f..a99172e 100644 --- a/sys/kern/subr_witness.c +++ b/sys/kern/subr_witness.c @@ -95,6 +95,7 @@ __FBSDID("$FreeBSD$"); #include <sys/lock.h> #include <sys/malloc.h> #include <sys/mutex.h> +#include <sys/priv.h> #include <sys/proc.h> #include <sys/sysctl.h> #include <sys/systm.h> @@ -533,7 +534,10 @@ sysctl_debug_witness_watch(SYSCTL_HANDLER_ARGS) error = sysctl_handle_int(oidp, &value, 0, req); if (error != 0 || req->newptr == NULL) return (error); - error = suser(req->td); + /* + * XXXRW: Why a priv check here? + */ + error = priv_check(req->td, PRIV_WITNESS); if (error != 0) return (error); if (value == witness_watch) diff --git a/sys/kern/sysv_ipc.c b/sys/kern/sysv_ipc.c index 8fec1da..0cbb4bb 100644 --- a/sys/kern/sysv_ipc.c +++ b/sys/kern/sysv_ipc.c @@ -1,8 +1,12 @@ /* $NetBSD: sysv_ipc.c,v 1.7 1994/06/29 06:33:11 cgd Exp $ */ /*- * Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca> + * Copyright (c) 2006 nCircle Network Security, Inc. * All rights reserved. * + * This software was developed by Robert N. M. Watson for the TrustedBSD + * Project under contract to nCircle Network Security, Inc. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -39,6 +43,7 @@ __FBSDID("$FreeBSD$"); #include <sys/sem.h> #include <sys/shm.h> #include <sys/ipc.h> +#include <sys/priv.h> #include <sys/proc.h> #include <sys/ucred.h> @@ -72,50 +77,73 @@ shmexit(struct vmspace *vm) * Note: The MAC Framework does not require any modifications to the * ipcperm() function, as access control checks are performed throughout the * implementation of each primitive. Those entry point calls complement the - * ipcperm() discertionary checks. + * ipcperm() discertionary checks. Unlike file system discretionary access + * control, the original create of an object is given the same rights as the + * current owner. */ int -ipcperm(td, perm, mode) - struct thread *td; - struct ipc_perm *perm; - int mode; +ipcperm(struct thread *td, struct ipc_perm *perm, int acc_mode) { struct ucred *cred = td->td_ucred; - int error; - - if (cred->cr_uid != perm->cuid && cred->cr_uid != perm->uid) { - /* - * For a non-create/owner, we require privilege to - * modify the object protections. Note: some other - * implementations permit IPC_M to be delegated to - * unprivileged non-creator/owner uids/gids. - */ - if (mode & IPC_M) { - error = suser(td); - if (error) - return (error); - } - /* - * Try to match against creator/owner group; if not, fall - * back on other. - */ - mode >>= 3; - if (!groupmember(perm->gid, cred) && - !groupmember(perm->cgid, cred)) - mode >>= 3; + int error, obj_mode, dac_granted, priv_granted; + + dac_granted = 0; + if (cred->cr_uid == perm->cuid || cred->cr_uid == perm->uid) { + obj_mode = perm->mode; + dac_granted |= IPC_M; + } else if (groupmember(perm->gid, cred) || + groupmember(perm->cgid, cred)) { + obj_mode = perm->mode; + obj_mode <<= 3; } else { - /* - * Always permit the creator/owner to update the object - * protections regardless of whether the object mode - * permits it. - */ - if (mode & IPC_M) - return (0); + obj_mode = perm->mode; + obj_mode <<= 6; } - if ((mode & perm->mode) != mode) { - if (suser(td) != 0) - return (EACCES); + /* + * While the System V IPC permission model allows IPC_M to be + * granted, as part of the mode, our implementation requires + * privilege to adminster the object if not the owner or creator. + */ +#if 0 + if (obj_mode & IPC_M) + dac_granted |= IPC_M; +#endif + if (obj_mode & IPC_R) + dac_granted |= IPC_R; + if (obj_mode & IPC_W) + dac_granted |= IPC_W; + + /* + * Simple case: all required rights are granted by DAC. + */ + if ((dac_granted & acc_mode) == acc_mode) + return (0); + + /* + * Privilege is required to satisfy the request. + */ + priv_granted = 0; + if ((acc_mode & IPC_M) && !(dac_granted & IPC_M)) { + error = priv_check(td, PRIV_IPC_ADMIN); + if (error == 0) + priv_granted |= IPC_M; } - return (0); + + if ((acc_mode & IPC_R) && !(dac_granted & IPC_R)) { + error = priv_check(td, PRIV_IPC_READ); + if (error == 0) + priv_granted |= IPC_R; + } + + if ((acc_mode & IPC_W) && !(dac_granted & IPC_W)) { + error = priv_check(td, PRIV_IPC_WRITE); + if (error == 0) + priv_granted |= IPC_W; + } + + if (((dac_granted | priv_granted) & acc_mode) == acc_mode) + return (0); + else + return (EACCES); } diff --git a/sys/kern/sysv_msg.c b/sys/kern/sysv_msg.c index 464a7e5..a3db14c 100644 --- a/sys/kern/sysv_msg.c +++ b/sys/kern/sysv_msg.c @@ -57,6 +57,7 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/sysproto.h> #include <sys/kernel.h> +#include <sys/priv.h> #include <sys/proc.h> #include <sys/lock.h> #include <sys/mutex.h> @@ -507,7 +508,7 @@ kern_msgctl(td, msqid, cmd, msqbuf) if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_M))) goto done2; if (msqbuf->msg_qbytes > msqkptr->u.msg_qbytes) { - error = suser(td); + error = priv_check(td, PRIV_IPC_MSGSIZE); if (error) goto done2; } diff --git a/sys/kern/tty.c b/sys/kern/tty.c index 29ddde3..17205f2 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -86,6 +86,7 @@ __FBSDID("$FreeBSD$"); #if defined(COMPAT_43TTY) #include <sys/ioctl_compat.h> #endif +#include <sys/priv.h> #include <sys/proc.h> #define TTYDEFCHARS #include <sys/tty.h> @@ -1020,7 +1021,7 @@ ttioctl(struct tty *tp, u_long cmd, void *data, int flag) break; case TIOCMSDTRWAIT: /* must be root since the wait applies to following logins */ - error = suser(td); + error = priv_check(td, PRIV_TTY_DTRWAIT); if (error) return (error); tp->t_dtr_wait = *(int *)data * hz / 100; @@ -1169,9 +1170,9 @@ ttioctl(struct tty *tp, u_long cmd, void *data, int flag) splx(s); break; case TIOCSTI: /* simulate terminal input */ - if ((flag & FREAD) == 0 && suser(td)) + if ((flag & FREAD) == 0 && priv_check(td, PRIV_TTY_STI)) return (EPERM); - if (!isctty(p, tp) && suser(td)) + if (!isctty(p, tp) && priv_check(td, PRIV_TTY_STI)) return (EACCES); s = spltty(); ttyld_rint(tp, *(u_char *)data); @@ -1244,7 +1245,7 @@ ttioctl(struct tty *tp, u_long cmd, void *data, int flag) } break; case TIOCSDRAINWAIT: - error = suser(td); + error = priv_check(td, PRIV_TTY_DRAINWAIT); if (error) return (error); tp->t_timeout = *(int *)data * hz; @@ -3114,7 +3115,8 @@ open_top: goto out; goto open_top; } - if (tp->t_state & TS_XCLUDE && suser(td)) + if (tp->t_state & TS_XCLUDE && priv_check(td, + PRIV_TTY_EXCLUSIVE)) return (EBUSY); } else { /* @@ -3340,7 +3342,7 @@ ttysioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *t ct = dev->si_drv2; switch (cmd) { case TIOCSETA: - error = suser(td); + error = priv_check(td, PRIV_TTY_SETA); if (error != 0) return (error); *ct = *(struct termios *)data; diff --git a/sys/kern/tty_cons.c b/sys/kern/tty_cons.c index 4472470..8e9e2a5 100644 --- a/sys/kern/tty_cons.c +++ b/sys/kern/tty_cons.c @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include <sys/malloc.h> #include <sys/msgbuf.h> #include <sys/namei.h> +#include <sys/priv.h> #include <sys/proc.h> #include <sys/queue.h> #include <sys/reboot.h> @@ -510,7 +511,7 @@ cnioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) * output from the "virtual" console. */ if (cmd == TIOCCONS && constty) { - error = suser(td); + error = priv_check(td, PRIV_TTY_CONSOLE); if (error) return (error); constty = NULL; diff --git a/sys/kern/tty_pts.c b/sys/kern/tty_pts.c index d5880a2..205cf57 100644 --- a/sys/kern/tty_pts.c +++ b/sys/kern/tty_pts.c @@ -56,6 +56,7 @@ __FBSDID("$FreeBSD$"); #if defined(COMPAT_43TTY) #include <sys/ioctl_compat.h> #endif +#include <sys/priv.h> #include <sys/proc.h> #include <sys/queue.h> #include <sys/tty.h> @@ -268,9 +269,11 @@ ptsopen(struct cdev *dev, int flag, int devtype, struct thread *td) tp = dev->si_tty; if ((tp->t_state & TS_ISOPEN) == 0) ttyinitmode(tp, 1, 0); - else if (tp->t_state & TS_XCLUDE && suser(td)) { + else if (tp->t_state & TS_XCLUDE && priv_check(td, + PRIV_TTY_EXCLUSIVE)) { return (EBUSY); - } else if (pt->pt_prison != td->td_ucred->cr_prison && suser(td)) { + } else if (pt->pt_prison != td->td_ucred->cr_prison && + priv_check(td, PRIV_TTY_PRISON)) { return (EBUSY); } if (tp->t_oproc) /* Ctrlr still around. */ diff --git a/sys/kern/tty_pty.c b/sys/kern/tty_pty.c index a973f6a..a59430f 100644 --- a/sys/kern/tty_pty.c +++ b/sys/kern/tty_pty.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); #if defined(COMPAT_43TTY) #include <sys/ioctl_compat.h> #endif +#include <sys/priv.h> #include <sys/proc.h> #include <sys/tty.h> #include <sys/conf.h> @@ -207,9 +208,11 @@ ptsopen(struct cdev *dev, int flag, int devtype, struct thread *td) if ((tp->t_state & TS_ISOPEN) == 0) { ttyinitmode(tp, 1, 0); - } else if (tp->t_state & TS_XCLUDE && suser(td)) + } else if (tp->t_state & TS_XCLUDE && priv_check(td, + PRIV_TTY_EXCLUSIVE)) return (EBUSY); - else if (pt->pt_prison != td->td_ucred->cr_prison && suser(td)) + else if (pt->pt_prison != td->td_ucred->cr_prison && + priv_check(td, PRIV_TTY_PRISON)) return (EBUSY); if (tp->t_oproc) /* Ctrlr still around. */ (void)ttyld_modem(tp, 1); diff --git a/sys/kern/uipc_mqueue.c b/sys/kern/uipc_mqueue.c index d6cf2e5..9185c0e 100644 --- a/sys/kern/uipc_mqueue.c +++ b/sys/kern/uipc_mqueue.c @@ -65,6 +65,7 @@ __FBSDID("$FreeBSD$"); #include <sys/mutex.h> #include <sys/namei.h> #include <sys/poll.h> +#include <sys/priv.h> #include <sys/proc.h> #include <sys/queue.h> #include <sys/sysproto.h> @@ -955,8 +956,12 @@ int do_unlink(struct mqfs_node *pn, struct ucred *ucred) sx_assert(&pn->mn_info->mi_lock, SX_LOCKED); + /* + * XXXRW: Other instances of the message queue primitive are + * allowed in jail? + */ if (ucred->cr_uid != pn->mn_uid && - (error = suser_cred(ucred, 0)) != 0) + (error = priv_check_cred(ucred, PRIV_MQ_ADMIN, 0)) != 0) error = EACCES; else if (!pn->mn_deleted) { parent = pn->mn_parent; @@ -1207,10 +1212,16 @@ mqfs_setattr(struct vop_setattr_args *ap) */ if ((error = VOP_ACCESS(vp, VADMIN, ap->a_cred, ap->a_td))) return (error); + + /* + * XXXRW: Why is there a privilege check here: shouldn't the + * check in VOP_ACCESS() be enough? Also, are the group bits + * below definitely right? + */ if (((ap->a_cred->cr_uid != pn->mn_uid) || uid != pn->mn_uid || (gid != pn->mn_gid && !groupmember(gid, ap->a_cred))) && - (error = suser_cred(ap->a_td->td_ucred, SUSER_ALLOWJAIL)) - != 0) + (error = priv_check_cred(ap->a_td->td_ucred, + PRIV_MQ_ADMIN, SUSER_ALLOWJAIL)) != 0) return (error); pn->mn_uid = uid; pn->mn_gid = gid; @@ -1219,7 +1230,8 @@ mqfs_setattr(struct vop_setattr_args *ap) if (vap->va_mode != (mode_t)VNOVAL) { if ((ap->a_cred->cr_uid != pn->mn_uid) && - (error = suser_cred(ap->a_td->td_ucred, SUSER_ALLOWJAIL))) + (error = priv_check_cred(ap->a_td->td_ucred, + PRIV_MQ_ADMIN, SUSER_ALLOWJAIL))) return (error); pn->mn_mode = vap->va_mode; c = 1; diff --git a/sys/kern/uipc_sem.c b/sys/kern/uipc_sem.c index 8de7d8f..340c1a6 100644 --- a/sys/kern/uipc_sem.c +++ b/sys/kern/uipc_sem.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include <sys/sysproto.h> #include <sys/eventhandler.h> #include <sys/kernel.h> +#include <sys/priv.h> #include <sys/proc.h> #include <sys/lock.h> #include <sys/mutex.h> @@ -419,15 +420,23 @@ sem_perm(struct thread *td, struct ksem *ks) { struct ucred *uc; + /* + * XXXRW: This permission routine appears to be incorrect. If the + * user matches, we shouldn't go on to the group if the user + * permissions don't allow the action? Not changed for now. To fix, + * change from a series of if (); if (); to if () else if () else... + */ uc = td->td_ucred; DP(("sem_perm: uc(%d,%d) ks(%d,%d,%o)\n", uc->cr_uid, uc->cr_gid, ks->ks_uid, ks->ks_gid, ks->ks_mode)); - if ((uc->cr_uid == ks->ks_uid && (ks->ks_mode & S_IWUSR) != 0) || - (uc->cr_gid == ks->ks_gid && (ks->ks_mode & S_IWGRP) != 0) || - (ks->ks_mode & S_IWOTH) != 0 || suser(td) == 0) + if ((uc->cr_uid == ks->ks_uid) && (ks->ks_mode & S_IWUSR) != 0) + return (0); + if ((uc->cr_gid == ks->ks_gid) && (ks->ks_mode & S_IWGRP) != 0) + return (0); + if ((ks->ks_mode & S_IWOTH) != 0) return (0); - return (EPERM); + return (priv_check(td, PRIV_SEM_WRITE)); } static void diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c index 8a57786..bb51d01 100644 --- a/sys/kern/vfs_extattr.c +++ b/sys/kern/vfs_extattr.c @@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$"); #include <sys/sx.h> #include <sys/unistd.h> #include <sys/vnode.h> +#include <sys/priv.h> #include <sys/proc.h> #include <sys/dirent.h> #include <sys/extattr.h> @@ -272,7 +273,7 @@ kern_statfs(struct thread *td, char *path, enum uio_seg pathseg, error = VFS_STATFS(mp, sp, td); if (error) goto out; - if (suser(td)) { + if (priv_check(td, PRIV_VFS_GENERATION)) { bcopy(sp, &sb, sizeof(sb)); sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; prison_enforce_statfs(td->td_ucred, mp, &sb); @@ -357,7 +358,7 @@ kern_fstatfs(struct thread *td, int fd, struct statfs *buf) error = VFS_STATFS(mp, sp, td); if (error) goto out; - if (suser(td)) { + if (priv_check(td, PRIV_VFS_GENERATION)) { bcopy(sp, &sb, sizeof(sb)); sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; prison_enforce_statfs(td->td_ucred, mp, &sb); @@ -468,7 +469,7 @@ kern_getfsstat(struct thread *td, struct statfs **buf, size_t bufsize, vfs_unbusy(mp, td); continue; } - if (suser(td)) { + if (priv_check(td, PRIV_VFS_GENERATION)) { bcopy(sp, &sb, sizeof(sb)); sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; prison_enforce_statfs(td->td_ucred, mp, &sb); @@ -842,7 +843,8 @@ chroot(td, uap) struct nameidata nd; int vfslocked; - error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL); + error = priv_check_cred(td->td_ucred, PRIV_VFS_CHROOT, + SUSER_ALLOWJAIL); if (error) return (error); NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1, @@ -896,8 +898,8 @@ change_dir(vp, td) /* * Common routine for kern_chroot() and jail_attach(). The caller is - * responsible for invoking suser() and mac_check_chroot() to authorize this - * operation. + * responsible for invoking priv_check() and mac_check_chroot() to authorize + * this operation. */ int change_root(vp, td) @@ -1186,10 +1188,16 @@ kern_mknod(struct thread *td, char *path, enum uio_seg pathseg, int mode, switch (mode & S_IFMT) { case S_IFCHR: case S_IFBLK: - error = suser(td); + error = priv_check(td, PRIV_VFS_MKNOD_DEV); + break; + case S_IFMT: + error = priv_check(td, PRIV_VFS_MKNOD_BAD); + break; + case S_IFWHT: + error = priv_check(td, PRIV_VFS_MKNOD_WHT); break; default: - error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL); + error = EINVAL; break; } if (error) @@ -1234,8 +1242,7 @@ restart: whiteout = 1; break; default: - error = EINVAL; - break; + panic("kern_mknod: invalid mode"); } } if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { @@ -1390,9 +1397,6 @@ can_hardlink(struct vnode *vp, struct thread *td, struct ucred *cred) struct vattr va; int error; - if (suser_cred(cred, SUSER_ALLOWJAIL) == 0) - return (0); - if (!hardlink_check_uid && !hardlink_check_gid) return (0); @@ -1400,14 +1404,18 @@ can_hardlink(struct vnode *vp, struct thread *td, struct ucred *cred) if (error != 0) return (error); - if (hardlink_check_uid) { - if (cred->cr_uid != va.va_uid) - return (EPERM); + if (hardlink_check_uid && cred->cr_uid != va.va_uid) { + error = priv_check_cred(cred, PRIV_VFS_LINK, + SUSER_ALLOWJAIL); + if (error) + return (error); } - if (hardlink_check_gid) { - if (!groupmember(va.va_gid, cred)) - return (EPERM); + if (hardlink_check_gid && !groupmember(va.va_gid, cred)) { + error = priv_check_cred(cred, PRIV_VFS_LINK, + SUSER_ALLOWJAIL); + if (error) + return (error); } return (0); @@ -2361,7 +2369,8 @@ setfflags(td, vp, flags) * chown can't fail when done as root. */ if (vp->v_type == VCHR || vp->v_type == VBLK) { - error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL); + error = priv_check_cred(td->td_ucred, PRIV_VFS_CHFLAGS_DEV, + SUSER_ALLOWJAIL); if (error) return (error); } @@ -3894,7 +3903,8 @@ revoke(td, uap) if (error) goto out; if (td->td_ucred->cr_uid != vattr.va_uid) { - error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL); + error = priv_check_cred(td->td_ucred, PRIV_VFS_ADMIN, + SUSER_ALLOWJAIL); if (error) goto out; } @@ -3960,7 +3970,7 @@ lgetfh(td, uap) int vfslocked; int error; - error = suser(td); + error = priv_check(td, PRIV_VFS_GETFH); if (error) return (error); NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1, @@ -3999,7 +4009,7 @@ getfh(td, uap) int vfslocked; int error; - error = suser(td); + error = priv_check(td, PRIV_VFS_GETFH); if (error) return (error); NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1, @@ -4022,10 +4032,10 @@ getfh(td, uap) } /* - * syscall for the rpc.lockd to use to translate a NFS file handle into - * an open descriptor. + * syscall for the rpc.lockd to use to translate a NFS file handle into an + * open descriptor. * - * warning: do not remove the suser() call or this becomes one giant + * warning: do not remove the priv_check() call or this becomes one giant * security hole. * * MP SAFE @@ -4058,7 +4068,7 @@ fhopen(td, uap) int vfslocked; int indx; - error = suser(td); + error = priv_check(td, PRIV_VFS_FHOPEN); if (error) return (error); fmode = FFLAGS(uap->flags); @@ -4242,7 +4252,7 @@ fhstat(td, uap) int vfslocked; int error; - error = suser(td); + error = priv_check(td, PRIV_VFS_FHSTAT); if (error) return (error); error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t)); @@ -4307,7 +4317,7 @@ kern_fhstatfs(struct thread *td, fhandle_t fh, struct statfs *buf) int vfslocked; int error; - error = suser(td); + error = priv_check(td, PRIV_VFS_FHSTATFS); if (error) return (error); if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c index af07f44..ef757b8 100644 --- a/sys/kern/vfs_mount.c +++ b/sys/kern/vfs_mount.c @@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$"); #include <sys/mount.h> #include <sys/mutex.h> #include <sys/namei.h> +#include <sys/priv.h> #include <sys/proc.h> #include <sys/filedesc.h> #include <sys/reboot.h> @@ -808,23 +809,31 @@ vfs_domount( if (jailed(td->td_ucred)) return (EPERM); if (usermount == 0) { - if ((error = suser(td)) != 0) + if ((error = priv_check(td, PRIV_VFS_MOUNT)) != 0) return (error); } /* * Do not allow NFS export or MNT_SUIDDIR by unprivileged users. */ - if (fsflags & (MNT_EXPORTED | MNT_SUIDDIR)) { - if ((error = suser(td)) != 0) + if (fsflags & MNT_EXPORTED) { + error = priv_check(td, PRIV_VFS_MOUNT_EXPORTED); + if (error) return (error); } + if (fsflags & MNT_SUIDDIR) { + error = priv_check(td, PRIV_VFS_MOUNT_SUIDDIR); + if (error) + return (error); + + } /* - * Silently enforce MNT_NOSUID and MNT_USER for - * unprivileged users. + * Silently enforce MNT_NOSUID and MNT_USER for unprivileged users. */ - if (suser(td) != 0) - fsflags |= MNT_NOSUID | MNT_USER; + if ((fsflags & (MNT_NOSUID | MNT_USER)) != (MNT_NOSUID | MNT_USER)) { + if (priv_check(td, PRIV_VFS_MOUNT_NONUSER) != 0) + fsflags |= MNT_NOSUID | MNT_USER; + } /* Load KLDs before we lock the covered vnode to avoid reversals. */ vfsp = NULL; @@ -906,7 +915,9 @@ vfs_domount( return (error); } if (va.va_uid != td->td_ucred->cr_uid) { - if ((error = suser(td)) != 0) { + error = priv_check_cred(td->td_ucred, PRIV_VFS_ADMIN, + SUSER_ALLOWJAIL); + if (error) { vput(vp); return (error); } @@ -1078,7 +1089,8 @@ unmount(td, uap) if (jailed(td->td_ucred)) return (EPERM); if (usermount == 0) { - if ((error = suser(td)) != 0) + error = priv_check(td, PRIV_VFS_UNMOUNT); + if (error) return (error); } diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 46ffd8f..d584606 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -61,6 +61,7 @@ __FBSDID("$FreeBSD$"); #include <sys/malloc.h> #include <sys/mount.h> #include <sys/namei.h> +#include <sys/priv.h> #include <sys/reboot.h> #include <sys/sleepqueue.h> #include <sys/stat.h> @@ -412,7 +413,7 @@ vfs_suser(struct mount *mp, struct thread *td) if ((mp->mnt_flag & MNT_USER) == 0 || mp->mnt_cred->cr_uid != td->td_ucred->cr_uid) { - if ((error = suser(td)) != 0) + if ((error = priv_check(td, PRIV_VFS_MOUNT_OWNER)) != 0) return (error); } return (0); @@ -3178,9 +3179,7 @@ vaccess(enum vtype type, mode_t file_mode, uid_t file_uid, gid_t file_gid, mode_t acc_mode, struct ucred *cred, int *privused) { mode_t dac_granted; -#ifdef CAPABILITIES - mode_t cap_granted; -#endif + mode_t priv_granted; /* * Look for a normal, non-privileged way to access the file/directory @@ -3234,59 +3233,46 @@ vaccess(enum vtype type, mode_t file_mode, uid_t file_uid, gid_t file_gid, return (0); privcheck: - if (!suser_cred(cred, SUSER_ALLOWJAIL)) { - /* XXX audit: privilege used */ - if (privused != NULL) - *privused = 1; - return (0); - } - -#ifdef CAPABILITIES /* - * Build a capability mask to determine if the set of capabilities + * Build a privilege mask to determine if the set of privileges * satisfies the requirements when combined with the granted mask - * from above. For each capability, if the capability is required, - * bitwise or the request type onto the cap_granted mask. - * - * Note: This is never actually used, but is here for reference - * purposes. + * from above. For each privilege, if the privilege is required, + * bitwise or the request type onto the priv_granted mask. */ - cap_granted = 0; + priv_granted = 0; if (type == VDIR) { /* - * For directories, use CAP_DAC_READ_SEARCH to satisfy - * VEXEC requests, instead of CAP_DAC_EXECUTE. + * For directories, use PRIV_VFS_LOOKUP to satisfy VEXEC + * requests, instead of PRIV_VFS_EXEC. */ if ((acc_mode & VEXEC) && ((dac_granted & VEXEC) == 0) && - !cap_check(cred, NULL, CAP_DAC_READ_SEARCH, - SUSER_ALLOWJAIL)) - cap_granted |= VEXEC; + !priv_check_cred(cred, PRIV_VFS_LOOKUP, SUSER_ALLOWJAIL)) + priv_granted |= VEXEC; } else { if ((acc_mode & VEXEC) && ((dac_granted & VEXEC) == 0) && - !cap_check(cred, NULL, CAP_DAC_EXECUTE, SUSER_ALLOWJAIL)) - cap_granted |= VEXEC; + !priv_check_cred(cred, PRIV_VFS_EXEC, SUSER_ALLOWJAIL)) + priv_granted |= VEXEC; } if ((acc_mode & VREAD) && ((dac_granted & VREAD) == 0) && - !cap_check(cred, NULL, CAP_DAC_READ_SEARCH, SUSER_ALLOWJAIL)) - cap_granted |= VREAD; + !priv_check_cred(cred, PRIV_VFS_READ, SUSER_ALLOWJAIL)) + priv_granted |= VREAD; if ((acc_mode & VWRITE) && ((dac_granted & VWRITE) == 0) && - !cap_check(cred, NULL, CAP_DAC_WRITE, SUSER_ALLOWJAIL)) - cap_granted |= (VWRITE | VAPPEND); + !priv_check_cred(cred, PRIV_VFS_WRITE, SUSER_ALLOWJAIL)) + priv_granted |= (VWRITE | VAPPEND); if ((acc_mode & VADMIN) && ((dac_granted & VADMIN) == 0) && - !cap_check(cred, NULL, CAP_FOWNER, SUSER_ALLOWJAIL)) - cap_granted |= VADMIN; + !priv_check_cred(cred, PRIV_VFS_ADMIN, SUSER_ALLOWJAIL)) + priv_granted |= VADMIN; - if ((acc_mode & (cap_granted | dac_granted)) == acc_mode) { + if ((acc_mode & (priv_granted | dac_granted)) == acc_mode) { /* XXX audit: privilege used */ if (privused != NULL) *privused = 1; return (0); } -#endif return ((acc_mode & VADMIN) ? EPERM : EACCES); } @@ -3307,16 +3293,13 @@ extattr_check_cred(struct vnode *vp, int attrnamespace, struct ucred *cred, return (0); /* - * Do not allow privileged processes in jail to directly - * manipulate system attributes. - * - * XXX What capability should apply here? - * Probably CAP_SYS_SETFFLAG. + * Do not allow privileged processes in jail to directly manipulate + * system attributes. */ switch (attrnamespace) { case EXTATTR_NAMESPACE_SYSTEM: /* Potentially should be: return (EPERM); */ - return (suser_cred(cred, 0)); + return (priv_check_cred(cred, PRIV_VFS_EXTATTR_SYSTEM, 0)); case EXTATTR_NAMESPACE_USER: return (VOP_ACCESS(vp, access, cred, td)); default: diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 8a57786..bb51d01 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$"); #include <sys/sx.h> #include <sys/unistd.h> #include <sys/vnode.h> +#include <sys/priv.h> #include <sys/proc.h> #include <sys/dirent.h> #include <sys/extattr.h> @@ -272,7 +273,7 @@ kern_statfs(struct thread *td, char *path, enum uio_seg pathseg, error = VFS_STATFS(mp, sp, td); if (error) goto out; - if (suser(td)) { + if (priv_check(td, PRIV_VFS_GENERATION)) { bcopy(sp, &sb, sizeof(sb)); sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; prison_enforce_statfs(td->td_ucred, mp, &sb); @@ -357,7 +358,7 @@ kern_fstatfs(struct thread *td, int fd, struct statfs *buf) error = VFS_STATFS(mp, sp, td); if (error) goto out; - if (suser(td)) { + if (priv_check(td, PRIV_VFS_GENERATION)) { bcopy(sp, &sb, sizeof(sb)); sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; prison_enforce_statfs(td->td_ucred, mp, &sb); @@ -468,7 +469,7 @@ kern_getfsstat(struct thread *td, struct statfs **buf, size_t bufsize, vfs_unbusy(mp, td); continue; } - if (suser(td)) { + if (priv_check(td, PRIV_VFS_GENERATION)) { bcopy(sp, &sb, sizeof(sb)); sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; prison_enforce_statfs(td->td_ucred, mp, &sb); @@ -842,7 +843,8 @@ chroot(td, uap) struct nameidata nd; int vfslocked; - error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL); + error = priv_check_cred(td->td_ucred, PRIV_VFS_CHROOT, + SUSER_ALLOWJAIL); if (error) return (error); NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1, @@ -896,8 +898,8 @@ change_dir(vp, td) /* * Common routine for kern_chroot() and jail_attach(). The caller is - * responsible for invoking suser() and mac_check_chroot() to authorize this - * operation. + * responsible for invoking priv_check() and mac_check_chroot() to authorize + * this operation. */ int change_root(vp, td) @@ -1186,10 +1188,16 @@ kern_mknod(struct thread *td, char *path, enum uio_seg pathseg, int mode, switch (mode & S_IFMT) { case S_IFCHR: case S_IFBLK: - error = suser(td); + error = priv_check(td, PRIV_VFS_MKNOD_DEV); + break; + case S_IFMT: + error = priv_check(td, PRIV_VFS_MKNOD_BAD); + break; + case S_IFWHT: + error = priv_check(td, PRIV_VFS_MKNOD_WHT); break; default: - error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL); + error = EINVAL; break; } if (error) @@ -1234,8 +1242,7 @@ restart: whiteout = 1; break; default: - error = EINVAL; - break; + panic("kern_mknod: invalid mode"); } } if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { @@ -1390,9 +1397,6 @@ can_hardlink(struct vnode *vp, struct thread *td, struct ucred *cred) struct vattr va; int error; - if (suser_cred(cred, SUSER_ALLOWJAIL) == 0) - return (0); - if (!hardlink_check_uid && !hardlink_check_gid) return (0); @@ -1400,14 +1404,18 @@ can_hardlink(struct vnode *vp, struct thread *td, struct ucred *cred) if (error != 0) return (error); - if (hardlink_check_uid) { - if (cred->cr_uid != va.va_uid) - return (EPERM); + if (hardlink_check_uid && cred->cr_uid != va.va_uid) { + error = priv_check_cred(cred, PRIV_VFS_LINK, + SUSER_ALLOWJAIL); + if (error) + return (error); } - if (hardlink_check_gid) { - if (!groupmember(va.va_gid, cred)) - return (EPERM); + if (hardlink_check_gid && !groupmember(va.va_gid, cred)) { + error = priv_check_cred(cred, PRIV_VFS_LINK, + SUSER_ALLOWJAIL); + if (error) + return (error); } return (0); @@ -2361,7 +2369,8 @@ setfflags(td, vp, flags) * chown can't fail when done as root. */ if (vp->v_type == VCHR || vp->v_type == VBLK) { - error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL); + error = priv_check_cred(td->td_ucred, PRIV_VFS_CHFLAGS_DEV, + SUSER_ALLOWJAIL); if (error) return (error); } @@ -3894,7 +3903,8 @@ revoke(td, uap) if (error) goto out; if (td->td_ucred->cr_uid != vattr.va_uid) { - error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL); + error = priv_check_cred(td->td_ucred, PRIV_VFS_ADMIN, + SUSER_ALLOWJAIL); if (error) goto out; } @@ -3960,7 +3970,7 @@ lgetfh(td, uap) int vfslocked; int error; - error = suser(td); + error = priv_check(td, PRIV_VFS_GETFH); if (error) return (error); NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1, @@ -3999,7 +4009,7 @@ getfh(td, uap) int vfslocked; int error; - error = suser(td); + error = priv_check(td, PRIV_VFS_GETFH); if (error) return (error); NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1, @@ -4022,10 +4032,10 @@ getfh(td, uap) } /* - * syscall for the rpc.lockd to use to translate a NFS file handle into - * an open descriptor. + * syscall for the rpc.lockd to use to translate a NFS file handle into an + * open descriptor. * - * warning: do not remove the suser() call or this becomes one giant + * warning: do not remove the priv_check() call or this becomes one giant * security hole. * * MP SAFE @@ -4058,7 +4068,7 @@ fhopen(td, uap) int vfslocked; int indx; - error = suser(td); + error = priv_check(td, PRIV_VFS_FHOPEN); if (error) return (error); fmode = FFLAGS(uap->flags); @@ -4242,7 +4252,7 @@ fhstat(td, uap) int vfslocked; int error; - error = suser(td); + error = priv_check(td, PRIV_VFS_FHSTAT); if (error) return (error); error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t)); @@ -4307,7 +4317,7 @@ kern_fhstatfs(struct thread *td, fhandle_t fh, struct statfs *buf) int vfslocked; int error; - error = suser(td); + error = priv_check(td, PRIV_VFS_FHSTATFS); if (error) return (error); if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index 4a516a7..3511044 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include <sys/file.h> #include <sys/kdb.h> #include <sys/stat.h> +#include <sys/priv.h> #include <sys/proc.h> #include <sys/limits.h> #include <sys/lock.h> @@ -709,7 +710,7 @@ vn_stat(vp, sb, active_cred, file_cred, td) sb->st_blksize = PAGE_SIZE; sb->st_flags = vap->va_flags; - if (suser(td)) + if (priv_check(td, PRIV_VFS_GENERATION)) sb->st_gen = 0; else sb->st_gen = vap->va_gen; |