summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authormike <mike@FreeBSD.org>2003-04-09 02:55:18 +0000
committermike <mike@FreeBSD.org>2003-04-09 02:55:18 +0000
commit75859ca578ff1bc109e1263e5c52d225315515e0 (patch)
treec6122edf636b885d1df318cda6d94636af3212f8 /sys
parent979ed3a82ea34d46466c4d6f755b15b85df66f15 (diff)
downloadFreeBSD-src-75859ca578ff1bc109e1263e5c52d225315515e0.zip
FreeBSD-src-75859ca578ff1bc109e1263e5c52d225315515e0.tar.gz
o In struct prison, add an allprison linked list of prisons (protected
by allprison_mtx), a unique prison/jail identifier field, two path fields (pr_path for reporting and pr_root vnode instance) to store the chroot() point of each jail. o Add jail_attach(2) to allow a process to bind to an existing jail. o Add change_root() to perform the chroot operation on a specified vnode. o Generalize change_dir() to accept a vnode, and move namei() calls to callers of change_dir(). o Add a new sysctl (security.jail.list) which is a group of struct xprison instances that represent a snapshot of active jails. Reviewed by: rwatson, tjr
Diffstat (limited to 'sys')
-rw-r--r--sys/amd64/ia32/syscalls.master1
-rw-r--r--sys/compat/freebsd32/syscalls.master1
-rw-r--r--sys/ia64/ia32/syscalls.master1
-rw-r--r--sys/kern/kern_jail.c238
-rw-r--r--sys/kern/subr_witness.c1
-rw-r--r--sys/kern/syscalls.master1
-rw-r--r--sys/kern/vfs_extattr.c109
-rw-r--r--sys/kern/vfs_syscalls.c109
-rw-r--r--sys/sys/jail.h20
9 files changed, 373 insertions, 108 deletions
diff --git a/sys/amd64/ia32/syscalls.master b/sys/amd64/ia32/syscalls.master
index 48ce6cf..e462377 100644
--- a/sys/amd64/ia32/syscalls.master
+++ b/sys/amd64/ia32/syscalls.master
@@ -607,4 +607,5 @@
433 STD BSD { int thr_kill(thr_id_t id, int sig); }
434 MSTD BSD { int _umtx_lock(struct umtx *umtx); }
435 MSTD BSD { int _umtx_unlock(struct umtx *umtx); }
+436 MSTD BSD { int jail_attach(int jid); }
diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master
index 48ce6cf..e462377 100644
--- a/sys/compat/freebsd32/syscalls.master
+++ b/sys/compat/freebsd32/syscalls.master
@@ -607,4 +607,5 @@
433 STD BSD { int thr_kill(thr_id_t id, int sig); }
434 MSTD BSD { int _umtx_lock(struct umtx *umtx); }
435 MSTD BSD { int _umtx_unlock(struct umtx *umtx); }
+436 MSTD BSD { int jail_attach(int jid); }
diff --git a/sys/ia64/ia32/syscalls.master b/sys/ia64/ia32/syscalls.master
index 48ce6cf..e462377 100644
--- a/sys/ia64/ia32/syscalls.master
+++ b/sys/ia64/ia32/syscalls.master
@@ -607,4 +607,5 @@
433 STD BSD { int thr_kill(thr_id_t id, int sig); }
434 MSTD BSD { int _umtx_lock(struct umtx *umtx); }
435 MSTD BSD { int _umtx_unlock(struct umtx *umtx); }
+436 MSTD BSD { int jail_attach(int jid); }
diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c
index 15f4b36..c4b1c94 100644
--- a/sys/kern/kern_jail.c
+++ b/sys/kern/kern_jail.c
@@ -21,8 +21,12 @@
#include <sys/jail.h>
#include <sys/lock.h>
#include <sys/mutex.h>
+#include <sys/namei.h>
+#include <sys/queue.h>
#include <sys/socket.h>
+#include <sys/syscallsubr.h>
#include <sys/sysctl.h>
+#include <sys/vnode.h>
#include <net/if.h>
#include <netinet/in.h>
@@ -49,6 +53,26 @@ SYSCTL_INT(_security_jail, OID_AUTO, sysvipc_allowed, CTLFLAG_RW,
&jail_sysvipc_allowed, 0,
"Processes in jail can use System V IPC primitives");
+/* allprison, lastprid, and prisoncount are protected by allprison_mtx. */
+struct prisonlist allprison;
+struct mtx allprison_mtx;
+int lastprid = 0;
+int prisoncount = 0;
+
+static void init_prison(void *);
+static struct prison *prison_find(int);
+static int sysctl_jail_list(SYSCTL_HANDLER_ARGS);
+
+static void
+init_prison(void *data __unused)
+{
+
+ mtx_init(&allprison_mtx, "allprison", NULL, MTX_DEF);
+ LIST_INIT(&allprison);
+}
+
+SYSINIT(prison, SI_SUB_INTRINSIC, SI_ORDER_ANY, init_prison, NULL);
+
/*
* MPSAFE
*/
@@ -59,12 +83,11 @@ jail(td, uap)
struct jail *jail;
} */ *uap;
{
- struct proc *p = td->td_proc;
- int error;
- struct prison *pr;
+ struct nameidata nd;
+ struct prison *pr, *tpr;
struct jail j;
- struct chroot_args ca;
- struct ucred *newcred = NULL, *oldcred;
+ struct jail_attach_args jaa;
+ int error, tryprid;
error = copyin(uap->jail, &j, sizeof j);
if (error)
@@ -74,48 +97,176 @@ jail(td, uap)
MALLOC(pr, struct prison *, sizeof *pr , M_PRISON, M_WAITOK | M_ZERO);
mtx_init(&pr->pr_mtx, "jail mutex", NULL, MTX_DEF);
- pr->pr_securelevel = securelevel;
+ pr->pr_ref = 1;
+ error = copyinstr(j.path, &pr->pr_path, sizeof pr->pr_path, 0);
+ if (error)
+ goto e_killmtx;
+ mtx_lock(&Giant);
+ NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, pr->pr_path, td);
+ error = namei(&nd);
+ if (error) {
+ mtx_unlock(&Giant);
+ goto e_killmtx;
+ }
+ pr->pr_root = nd.ni_vp;
+ VOP_UNLOCK(nd.ni_vp, 0, td);
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ mtx_unlock(&Giant);
error = copyinstr(j.hostname, &pr->pr_host, sizeof pr->pr_host, 0);
if (error)
- goto bail;
- ca.path = j.path;
+ goto e_dropvnref;
+ pr->pr_ip = j.ip_number;
+ pr->pr_linux = NULL;
+ pr->pr_securelevel = securelevel;
+
+ /* Determine next pr_id and add prison to allprison list. */
+ mtx_lock(&allprison_mtx);
+ tryprid = lastprid + 1;
+ if (tryprid == JAIL_MAX)
+ tryprid = 1;
+next:
+ LIST_FOREACH(tpr, &allprison, pr_list) {
+ if (tpr->pr_id == tryprid) {
+ tryprid++;
+ if (tryprid == JAIL_MAX) {
+ mtx_unlock(&allprison_mtx);
+ error = EAGAIN;
+ goto e_dropvnref;
+ }
+ goto next;
+ }
+ }
+ pr->pr_id = jaa.jid = lastprid = tryprid;
+ LIST_INSERT_HEAD(&allprison, pr, pr_list);
+ prisoncount++;
+ mtx_unlock(&allprison_mtx);
+
+ error = jail_attach(td, &jaa);
+ if (error)
+ goto e_dropprref;
+ mtx_lock(&pr->pr_mtx);
+ pr->pr_ref--;
+ mtx_unlock(&pr->pr_mtx);
+ td->td_retval[0] = jaa.jid;
+ return (0);
+e_dropprref:
+ mtx_lock(&allprison_mtx);
+ LIST_REMOVE(pr, pr_list);
+ prisoncount--;
+ mtx_unlock(&allprison_mtx);
+e_dropvnref:
mtx_lock(&Giant);
- error = chroot(td, &ca);
+ vrele(pr->pr_root);
mtx_unlock(&Giant);
+e_killmtx:
+ mtx_destroy(&pr->pr_mtx);
+ FREE(pr, M_PRISON);
+ return (error);
+}
+
+/*
+ * MPSAFE
+ */
+int
+jail_attach(td, uap)
+ struct thread *td;
+ struct jail_attach_args /* {
+ int jid;
+ } */ *uap;
+{
+ struct proc *p;
+ struct ucred *newcred, *oldcred;
+ struct prison *pr;
+ int error;
+
+ p = td->td_proc;
+
+ mtx_lock(&allprison_mtx);
+ pr = prison_find(uap->jid);
+ if (pr == NULL) {
+ mtx_unlock(&allprison_mtx);
+ return (EINVAL);
+ }
+ pr->pr_ref++;
+ mtx_unlock(&pr->pr_mtx);
+ mtx_unlock(&allprison_mtx);
+
+ error = suser_cred(td->td_ucred, PRISON_ROOT);
if (error)
- goto bail;
+ goto e_dropref;
+ mtx_lock(&Giant);
+ vn_lock(pr->pr_root, LK_EXCLUSIVE | LK_RETRY, td);
+ if ((error = change_dir(pr->pr_root, td)) != 0)
+ goto e_unlock;
+#ifdef MAC
+ if ((error = mac_check_vnode_chroot(td->td_ucred, pr->pr_root)))
+ goto e_unlock;
+#endif
+ VOP_UNLOCK(pr->pr_root, 0, td);
+ change_root(pr->pr_root, td);
+ mtx_unlock(&Giant);
+
newcred = crget();
- pr->pr_ip = j.ip_number;
PROC_LOCK(p);
/* Implicitly fail if already in jail. */
error = suser_cred(p->p_ucred, 0);
- if (error)
- goto badcred;
+ if (error) {
+ PROC_UNLOCK(p);
+ crfree(newcred);
+ goto e_dropref;
+ }
oldcred = p->p_ucred;
+ setsugid(p);
crcopy(newcred, oldcred);
p->p_ucred = newcred;
+ mtx_lock(&pr->pr_mtx);
p->p_ucred->cr_prison = pr;
- pr->pr_ref = 1;
+ mtx_unlock(&pr->pr_mtx);
PROC_UNLOCK(p);
crfree(oldcred);
return (0);
-badcred:
- PROC_UNLOCK(p);
- crfree(newcred);
-bail:
- mtx_destroy(&pr->pr_mtx);
- FREE(pr, M_PRISON);
+e_unlock:
+ VOP_UNLOCK(pr->pr_root, 0, td);
+ mtx_unlock(&Giant);
+e_dropref:
+ mtx_lock(&pr->pr_mtx);
+ pr->pr_ref--;
+ mtx_unlock(&pr->pr_mtx);
return (error);
}
+/*
+ * Returns a locked prison instance, or NULL on failure.
+ */
+static struct prison *
+prison_find(int prid)
+{
+ struct prison *pr;
+
+ mtx_assert(&allprison_mtx, MA_OWNED);
+ LIST_FOREACH(pr, &allprison, pr_list) {
+ if (pr->pr_id == prid) {
+ mtx_lock(&pr->pr_mtx);
+ return (pr);
+ }
+ }
+ return (NULL);
+}
+
void
prison_free(struct prison *pr)
{
+ mtx_assert(&Giant, MA_OWNED);
+ mtx_lock(&allprison_mtx);
mtx_lock(&pr->pr_mtx);
pr->pr_ref--;
if (pr->pr_ref == 0) {
+ LIST_REMOVE(pr, pr_list);
mtx_unlock(&pr->pr_mtx);
+ prisoncount--;
+ mtx_unlock(&allprison_mtx);
+ vrele(pr->pr_root);
mtx_destroy(&pr->pr_mtx);
if (pr->pr_linux != NULL)
FREE(pr->pr_linux, M_PRISON);
@@ -123,6 +274,7 @@ prison_free(struct prison *pr)
return;
}
mtx_unlock(&pr->pr_mtx);
+ mtx_unlock(&allprison_mtx);
}
void
@@ -256,3 +408,49 @@ getcredhostname(cred, buf, size)
else
strlcpy(buf, hostname, size);
}
+
+static int
+sysctl_jail_list(SYSCTL_HANDLER_ARGS)
+{
+ struct xprison *xp, *sxp;
+ struct prison *pr;
+ int count, error;
+
+ mtx_assert(&Giant, MA_OWNED);
+retry:
+ mtx_lock(&allprison_mtx);
+ count = prisoncount;
+ mtx_unlock(&allprison_mtx);
+
+ if (count == 0)
+ return (0);
+
+ sxp = xp = malloc(sizeof(*xp) * count, M_TEMP, M_WAITOK | M_ZERO);
+ mtx_lock(&allprison_mtx);
+ if (count != prisoncount) {
+ mtx_unlock(&allprison_mtx);
+ free(sxp, M_TEMP);
+ goto retry;
+ }
+
+ LIST_FOREACH(pr, &allprison, pr_list) {
+ mtx_lock(&pr->pr_mtx);
+ xp->pr_version = XPRISON_VERSION;
+ xp->pr_id = pr->pr_id;
+ strlcpy(xp->pr_path, pr->pr_path, sizeof(xp->pr_path));
+ strlcpy(xp->pr_host, pr->pr_host, sizeof(xp->pr_host));
+ xp->pr_ip = pr->pr_ip;
+ mtx_unlock(&pr->pr_mtx);
+ xp++;
+ }
+ mtx_unlock(&allprison_mtx);
+
+ error = SYSCTL_OUT(req, sxp, sizeof(*sxp) * count);
+ free(sxp, M_TEMP);
+ if (error)
+ return (error);
+ return (0);
+}
+
+SYSCTL_OID(_security_jail, OID_AUTO, list, CTLTYPE_STRUCT | CTLFLAG_RD,
+ NULL, 0, sysctl_jail_list, "S", "List of active jails");
diff --git a/sys/kern/subr_witness.c b/sys/kern/subr_witness.c
index 3b7526a..d89698b 100644
--- a/sys/kern/subr_witness.c
+++ b/sys/kern/subr_witness.c
@@ -266,6 +266,7 @@ static struct witness_order_list_entry order_lists[] = {
{ "session", &lock_class_mtx_sleep },
{ "uidinfo hash", &lock_class_mtx_sleep },
{ "uidinfo struct", &lock_class_mtx_sleep },
+ { "allprison", &lock_class_mtx_sleep },
{ NULL, NULL },
/*
* spin locks
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index b5c729b..cfb84f0 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -630,6 +630,7 @@
433 MSTD BSD { int thr_kill(thr_id_t id, int sig); }
434 MSTD BSD { int _umtx_lock(struct umtx *umtx); }
435 MSTD BSD { int _umtx_unlock(struct umtx *umtx); }
+436 MSTD BSD { int jail_attach(int jid); }
; Please copy any additions and changes to the following compatability tables:
; sys/ia64/ia32/syscalls.master (take a best guess)
diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c
index 6e8656b..45ba5a1 100644
--- a/sys/kern/vfs_extattr.c
+++ b/sys/kern/vfs_extattr.c
@@ -78,7 +78,6 @@
#include <vm/vm_page.h>
#include <vm/uma.h>
-static int change_dir(struct nameidata *ndp, struct thread *td);
static int chroot_refuse_vdir_fds(struct filedesc *fdp);
static int getutimes(const struct timeval *, enum uio_seg, struct timespec *);
static int setfown(struct thread *td, struct vnode *, uid_t, gid_t);
@@ -463,8 +462,13 @@ kern_chdir(struct thread *td, char *path, enum uio_seg pathseg)
struct vnode *vp;
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, pathseg, path, td);
- if ((error = change_dir(&nd, td)) != 0)
+ if ((error = namei(&nd)) != 0)
return (error);
+ if ((error = change_dir(nd.ni_vp, td)) != 0) {
+ vput(nd.ni_vp);
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ return (error);
+ }
VOP_UNLOCK(nd.ni_vp, 0, td);
NDFREE(&nd, NDF_ONLY_PNBUF);
FILEDESC_LOCK(fdp);
@@ -530,45 +534,31 @@ chroot(td, uap)
char *path;
} */ *uap;
{
- register struct filedesc *fdp = td->td_proc->p_fd;
int error;
struct nameidata nd;
- struct vnode *vp;
error = suser_cred(td->td_ucred, PRISON_ROOT);
if (error)
return (error);
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, td);
mtx_lock(&Giant);
- if ((error = change_dir(&nd, td)) != 0)
+ error = namei(&nd);
+ if (error)
goto error;
+ if ((error = change_dir(nd.ni_vp, td)) != 0)
+ goto e_vunlock;
#ifdef MAC
- if ((error = mac_check_vnode_chroot(td->td_ucred, nd.ni_vp))) {
- vput(nd.ni_vp);
- goto error;
- }
+ if ((error = mac_check_vnode_chroot(td->td_ucred, nd.ni_vp)))
+ goto e_vunlock;
#endif
VOP_UNLOCK(nd.ni_vp, 0, td);
- FILEDESC_LOCK(fdp);
- if (chroot_allow_open_directories == 0 ||
- (chroot_allow_open_directories == 1 && fdp->fd_rdir != rootvnode)) {
- error = chroot_refuse_vdir_fds(fdp);
- if (error)
- goto error_unlock;
- }
- vp = fdp->fd_rdir;
- fdp->fd_rdir = nd.ni_vp;
- if (!fdp->fd_jdir) {
- fdp->fd_jdir = nd.ni_vp;
- VREF(fdp->fd_jdir);
- }
- FILEDESC_UNLOCK(fdp);
+ error = change_root(nd.ni_vp, td);
+ vrele(nd.ni_vp);
NDFREE(&nd, NDF_ONLY_PNBUF);
- vrele(vp);
mtx_unlock(&Giant);
- return (0);
-error_unlock:
- FILEDESC_UNLOCK(fdp);
+ return (error);
+e_vunlock:
+ vput(nd.ni_vp);
error:
mtx_unlock(&Giant);
NDFREE(&nd, NDF_ONLY_PNBUF);
@@ -576,35 +566,66 @@ error:
}
/*
- * Common routine for chroot and chdir. On success, the directory vnode
- * is returned locked, and must be unlocked by the caller.
+ * Common routine for chroot and chdir. Callers must provide a locked vnode
+ * instance.
*/
-static int
-change_dir(ndp, td)
- register struct nameidata *ndp;
+int
+change_dir(vp, td)
+ struct vnode *vp;
struct thread *td;
{
- struct vnode *vp;
int error;
- error = namei(ndp);
- if (error)
- return (error);
- vp = ndp->ni_vp;
+ ASSERT_VOP_LOCKED(vp, "change_dir(): vp not locked");
if (vp->v_type != VDIR)
- error = ENOTDIR;
+ return (ENOTDIR);
#ifdef MAC
- if (error == 0)
- error = mac_check_vnode_chdir(td->td_ucred, vp);
-#endif
- if (error == 0)
- error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td);
+ error = mac_check_vnode_chdir(td->td_ucred, vp);
if (error)
- vput(vp);
+ return (error);
+#endif
+ error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td);
return (error);
}
/*
+ * Common routine for kern_chroot() and jail_attach(). The caller is
+ * responsible for invoking suser() and mac_check_chroot() to authorize this
+ * operation.
+ */
+int
+change_root(vp, td)
+ struct vnode *vp;
+ struct thread *td;
+{
+ struct filedesc *fdp;
+ struct vnode *oldvp;
+ int error;
+
+ mtx_assert(&Giant, MA_OWNED);
+ fdp = td->td_proc->p_fd;
+ FILEDESC_LOCK(fdp);
+ if (chroot_allow_open_directories == 0 ||
+ (chroot_allow_open_directories == 1 && fdp->fd_rdir != rootvnode)) {
+ error = chroot_refuse_vdir_fds(fdp);
+ if (error) {
+ FILEDESC_UNLOCK(fdp);
+ return (error);
+ }
+ }
+ oldvp = fdp->fd_rdir;
+ fdp->fd_rdir = vp;
+ VREF(fdp->fd_rdir);
+ if (!fdp->fd_jdir) {
+ fdp->fd_jdir = vp;
+ VREF(fdp->fd_jdir);
+ }
+ FILEDESC_UNLOCK(fdp);
+ vrele(oldvp);
+ return (0);
+}
+
+/*
* Check permissions, allocate an open file structure,
* and call the device open routine if any.
*/
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index 6e8656b..45ba5a1 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -78,7 +78,6 @@
#include <vm/vm_page.h>
#include <vm/uma.h>
-static int change_dir(struct nameidata *ndp, struct thread *td);
static int chroot_refuse_vdir_fds(struct filedesc *fdp);
static int getutimes(const struct timeval *, enum uio_seg, struct timespec *);
static int setfown(struct thread *td, struct vnode *, uid_t, gid_t);
@@ -463,8 +462,13 @@ kern_chdir(struct thread *td, char *path, enum uio_seg pathseg)
struct vnode *vp;
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, pathseg, path, td);
- if ((error = change_dir(&nd, td)) != 0)
+ if ((error = namei(&nd)) != 0)
return (error);
+ if ((error = change_dir(nd.ni_vp, td)) != 0) {
+ vput(nd.ni_vp);
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ return (error);
+ }
VOP_UNLOCK(nd.ni_vp, 0, td);
NDFREE(&nd, NDF_ONLY_PNBUF);
FILEDESC_LOCK(fdp);
@@ -530,45 +534,31 @@ chroot(td, uap)
char *path;
} */ *uap;
{
- register struct filedesc *fdp = td->td_proc->p_fd;
int error;
struct nameidata nd;
- struct vnode *vp;
error = suser_cred(td->td_ucred, PRISON_ROOT);
if (error)
return (error);
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, td);
mtx_lock(&Giant);
- if ((error = change_dir(&nd, td)) != 0)
+ error = namei(&nd);
+ if (error)
goto error;
+ if ((error = change_dir(nd.ni_vp, td)) != 0)
+ goto e_vunlock;
#ifdef MAC
- if ((error = mac_check_vnode_chroot(td->td_ucred, nd.ni_vp))) {
- vput(nd.ni_vp);
- goto error;
- }
+ if ((error = mac_check_vnode_chroot(td->td_ucred, nd.ni_vp)))
+ goto e_vunlock;
#endif
VOP_UNLOCK(nd.ni_vp, 0, td);
- FILEDESC_LOCK(fdp);
- if (chroot_allow_open_directories == 0 ||
- (chroot_allow_open_directories == 1 && fdp->fd_rdir != rootvnode)) {
- error = chroot_refuse_vdir_fds(fdp);
- if (error)
- goto error_unlock;
- }
- vp = fdp->fd_rdir;
- fdp->fd_rdir = nd.ni_vp;
- if (!fdp->fd_jdir) {
- fdp->fd_jdir = nd.ni_vp;
- VREF(fdp->fd_jdir);
- }
- FILEDESC_UNLOCK(fdp);
+ error = change_root(nd.ni_vp, td);
+ vrele(nd.ni_vp);
NDFREE(&nd, NDF_ONLY_PNBUF);
- vrele(vp);
mtx_unlock(&Giant);
- return (0);
-error_unlock:
- FILEDESC_UNLOCK(fdp);
+ return (error);
+e_vunlock:
+ vput(nd.ni_vp);
error:
mtx_unlock(&Giant);
NDFREE(&nd, NDF_ONLY_PNBUF);
@@ -576,35 +566,66 @@ error:
}
/*
- * Common routine for chroot and chdir. On success, the directory vnode
- * is returned locked, and must be unlocked by the caller.
+ * Common routine for chroot and chdir. Callers must provide a locked vnode
+ * instance.
*/
-static int
-change_dir(ndp, td)
- register struct nameidata *ndp;
+int
+change_dir(vp, td)
+ struct vnode *vp;
struct thread *td;
{
- struct vnode *vp;
int error;
- error = namei(ndp);
- if (error)
- return (error);
- vp = ndp->ni_vp;
+ ASSERT_VOP_LOCKED(vp, "change_dir(): vp not locked");
if (vp->v_type != VDIR)
- error = ENOTDIR;
+ return (ENOTDIR);
#ifdef MAC
- if (error == 0)
- error = mac_check_vnode_chdir(td->td_ucred, vp);
-#endif
- if (error == 0)
- error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td);
+ error = mac_check_vnode_chdir(td->td_ucred, vp);
if (error)
- vput(vp);
+ return (error);
+#endif
+ error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td);
return (error);
}
/*
+ * Common routine for kern_chroot() and jail_attach(). The caller is
+ * responsible for invoking suser() and mac_check_chroot() to authorize this
+ * operation.
+ */
+int
+change_root(vp, td)
+ struct vnode *vp;
+ struct thread *td;
+{
+ struct filedesc *fdp;
+ struct vnode *oldvp;
+ int error;
+
+ mtx_assert(&Giant, MA_OWNED);
+ fdp = td->td_proc->p_fd;
+ FILEDESC_LOCK(fdp);
+ if (chroot_allow_open_directories == 0 ||
+ (chroot_allow_open_directories == 1 && fdp->fd_rdir != rootvnode)) {
+ error = chroot_refuse_vdir_fds(fdp);
+ if (error) {
+ FILEDESC_UNLOCK(fdp);
+ return (error);
+ }
+ }
+ oldvp = fdp->fd_rdir;
+ fdp->fd_rdir = vp;
+ VREF(fdp->fd_rdir);
+ if (!fdp->fd_jdir) {
+ fdp->fd_jdir = vp;
+ VREF(fdp->fd_jdir);
+ }
+ FILEDESC_UNLOCK(fdp);
+ vrele(oldvp);
+ return (0);
+}
+
+/*
* Check permissions, allocate an open file structure,
* and call the device open routine if any.
*/
diff --git a/sys/sys/jail.h b/sys/sys/jail.h
index 016c75a..fbc8ba93 100644
--- a/sys/sys/jail.h
+++ b/sys/sys/jail.h
@@ -20,9 +20,19 @@ struct jail {
u_int32_t ip_number;
};
+struct xprison {
+ int pr_version;
+ int pr_id;
+ char pr_path[MAXPATHLEN];
+ char pr_host[MAXHOSTNAMELEN];
+ u_int32_t pr_ip;
+};
+#define XPRISON_VERSION 1
+
#ifndef _KERNEL
int jail(struct jail *);
+int jail_attach(int);
#else /* _KERNEL */
@@ -30,6 +40,8 @@ int jail(struct jail *);
#include <sys/_lock.h>
#include <sys/_mutex.h>
+#define JAIL_MAX 999999
+
#ifdef MALLOC_DECLARE
MALLOC_DECLARE(M_PRISON);
#endif
@@ -40,13 +52,18 @@ MALLOC_DECLARE(M_PRISON);
* delete the struture when the last inmate is dead.
*
* Lock key:
+ * (a) allprison_mutex
* (p) locked by pr_mutex
* (c) set only during creation before the structure is shared, no mutex
* required to read
*/
struct mtx;
struct prison {
+ LIST_ENTRY(prison) pr_list; /* (a) all prisons */
+ int pr_id; /* (c) prison id */
int pr_ref; /* (p) refcount */
+ char pr_path[MAXPATHLEN]; /* (c) chroot path */
+ struct vnode *pr_root; /* (c) vnode to rdir */
char pr_host[MAXHOSTNAMELEN]; /* (p) jail hostname */
u_int32_t pr_ip; /* (c) ip addr host */
void *pr_linux; /* (p) linux abi */
@@ -63,6 +80,9 @@ extern int jail_set_hostname_allowed;
extern int jail_socket_unixiproute_only;
extern int jail_sysvipc_allowed;
+LIST_HEAD(prisonlist, prison);
+extern struct prisonlist allprison;
+
/*
* Kernel support functions for jail().
*/
OpenPOWER on IntegriCloud