diff options
author | jamie <jamie@FreeBSD.org> | 2009-05-27 14:11:23 +0000 |
---|---|---|
committer | jamie <jamie@FreeBSD.org> | 2009-05-27 14:11:23 +0000 |
commit | a013e0afcbb44052a86a7977277d669d8883b7e7 (patch) | |
tree | b7f782d79e61a1bd80655a068684cb0fd9f39922 /sys/kern/kern_mib.c | |
parent | 6e53147404a7f4fb4173694bc812d9d23efd9fef (diff) | |
download | FreeBSD-src-a013e0afcbb44052a86a7977277d669d8883b7e7.zip FreeBSD-src-a013e0afcbb44052a86a7977277d669d8883b7e7.tar.gz |
Add hierarchical jails. A jail may further virtualize its environment
by creating a child jail, which is visible to that jail and to any
parent jails. Child jails may be restricted more than their parents,
but never less. Jail names reflect this hierarchy, being MIB-style
dot-separated strings.
Every thread now points to a jail, the default being prison0, which
contains information about the physical system. Prison0's root
directory is the same as rootvnode; its hostname is the same as the
global hostname, and its securelevel replaces the global securelevel.
Note that the variable "securelevel" has actually gone away, which
should not cause any problems for code that properly uses
securelevel_gt() and securelevel_ge().
Some jail-related permissions that were kept in global variables and
set via sysctls are now per-jail settings. The sysctls still exist for
backward compatibility, used only by the now-deprecated jail(2) system
call.
Approved by: bz (mentor)
Diffstat (limited to 'sys/kern/kern_mib.c')
-rw-r--r-- | sys/kern/kern_mib.c | 66 |
1 files changed, 29 insertions, 37 deletions
diff --git a/sys/kern/kern_mib.c b/sys/kern/kern_mib.c index 43fcfa4..38116d5 100644 --- a/sys/kern/kern_mib.c +++ b/sys/kern/kern_mib.c @@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$"); #include <sys/mutex.h> #include <sys/jail.h> #include <sys/smp.h> +#include <sys/sx.h> #include <sys/unistd.h> #include <sys/vimage.h> @@ -228,8 +229,8 @@ sysctl_hostname(SYSCTL_HANDLER_ARGS) int error; pr = req->td->td_ucred->cr_prison; - if (pr != NULL) { - if (!jail_set_hostname_allowed && req->newptr) + if (pr != &prison0) { + if (!(pr->pr_allow & PR_ALLOW_SET_HOSTNAME) && req->newptr) return (EPERM); /* * Process is in jail, so make a local copy of jail @@ -259,9 +260,12 @@ sysctl_hostname(SYSCTL_HANDLER_ARGS) error = sysctl_handle_string(oidp, tmphostname, sizeof tmphostname, req); if (req->newptr != NULL && error == 0) { + mtx_lock(&prison0.pr_mtx); mtx_lock(&hostname_mtx); + bcopy(tmphostname, prison0.pr_host, MAXHOSTNAMELEN); bcopy(tmphostname, V_hostname, MAXHOSTNAMELEN); mtx_unlock(&hostname_mtx); + mtx_unlock(&prison0.pr_mtx); } } return (error); @@ -278,55 +282,43 @@ SYSCTL_INT(_regression, OID_AUTO, securelevel_nonmonotonic, CTLFLAG_RW, ®ression_securelevel_nonmonotonic, 0, "securelevel may be lowered"); #endif -int securelevel = -1; -static struct mtx securelevel_mtx; - -MTX_SYSINIT(securelevel_lock, &securelevel_mtx, "securelevel mutex lock", - MTX_DEF); - static int sysctl_kern_securelvl(SYSCTL_HANDLER_ARGS) { - struct prison *pr; - int error, level; + struct prison *pr, *cpr; + int descend, error, level; pr = req->td->td_ucred->cr_prison; /* - * If the process is in jail, return the maximum of the global and - * local levels; otherwise, return the global level. Perform a - * lockless read since the securelevel is an integer. + * Reading the securelevel is easy, since the current jail's level + * is known to be at least as secure as any higher levels. Perform + * a lockless read since the securelevel is an integer. */ - if (pr != NULL) - level = imax(securelevel, pr->pr_securelevel); - else - level = securelevel; + level = pr->pr_securelevel; error = sysctl_handle_int(oidp, &level, 0, req); if (error || !req->newptr) return (error); + /* Permit update only if the new securelevel exceeds the old. */ + sx_slock(&allprison_lock); + mtx_lock(&pr->pr_mtx); + if (!regression_securelevel_nonmonotonic && + level < pr->pr_securelevel) { + mtx_unlock(&pr->pr_mtx); + sx_sunlock(&allprison_lock); + return (EPERM); + } + pr->pr_securelevel = level; /* - * Permit update only if the new securelevel exceeds the - * global level, and local level if any. + * Set all child jails to be at least this level, but do not lower + * them (even if regression_securelevel_nonmonotonic). */ - if (pr != NULL) { - mtx_lock(&pr->pr_mtx); - if (!regression_securelevel_nonmonotonic && - (level < imax(securelevel, pr->pr_securelevel))) { - mtx_unlock(&pr->pr_mtx); - return (EPERM); - } - pr->pr_securelevel = level; - mtx_unlock(&pr->pr_mtx); - } else { - mtx_lock(&securelevel_mtx); - if (!regression_securelevel_nonmonotonic && - (level < securelevel)) { - mtx_unlock(&securelevel_mtx); - return (EPERM); - } - securelevel = level; - mtx_unlock(&securelevel_mtx); + FOREACH_PRISON_DESCENDANT_LOCKED(pr, cpr, descend) { + if (cpr->pr_securelevel < level) + cpr->pr_securelevel = level; } + mtx_unlock(&pr->pr_mtx); + sx_sunlock(&allprison_lock); return (error); } |