Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F131762706
D43696.id133680.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
25 KB
Referenced Files
None
Subscribers
None
D43696.id133680.diff
View Options
diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map
--- a/lib/libc/sys/Symbol.map
+++ b/lib/libc/sys/Symbol.map
@@ -416,6 +416,8 @@
FBSD_1.7 {
_Fork;
fspacectl;
+ jd_attach;
+ jd_remove;
kqueuex;
membarrier;
swapoff;
diff --git a/sys/bsm/audit_kevents.h b/sys/bsm/audit_kevents.h
--- a/sys/bsm/audit_kevents.h
+++ b/sys/bsm/audit_kevents.h
@@ -662,6 +662,8 @@
#define AUE_AIO_READV 43268 /* FreeBSD-specific. */
#define AUE_FSPACECTL 43269 /* FreeBSD-specific. */
#define AUE_TIMERFD 43270 /* FreeBSD/Linux. */
+#define AUE_JD_ATTACH 43271 /* FreeBSD-specific. */
+#define AUE_JD_REMOVE 43272 /* FreeBSD-specific. */
/*
* Darwin BSM uses a number of AUE_O_* definitions, which are aliased to the
diff --git a/sys/conf/files b/sys/conf/files
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -3766,6 +3766,7 @@
kern/kern_idle.c standard
kern/kern_intr.c standard
kern/kern_jail.c standard
+kern/kern_jaildesc.c standard
kern/kern_kcov.c optional kcov \
compile-with "${NORMAL_C:N-fsanitize*} ${NORMAL_C:M-fsanitize=kernel-memory}"
kern/kern_khelp.c standard
diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c
--- a/sys/kern/init_sysent.c
+++ b/sys/kern/init_sysent.c
@@ -649,4 +649,6 @@
{ .sy_narg = AS(timerfd_gettime_args), .sy_call = (sy_call_t *)sys_timerfd_gettime, .sy_auevent = AUE_TIMERFD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 586 = timerfd_gettime */
{ .sy_narg = AS(timerfd_settime_args), .sy_call = (sy_call_t *)sys_timerfd_settime, .sy_auevent = AUE_TIMERFD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 587 = timerfd_settime */
{ .sy_narg = AS(kcmp_args), .sy_call = (sy_call_t *)sys_kcmp, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 588 = kcmp */
+ { .sy_narg = AS(jd_attach_args), .sy_call = (sy_call_t *)sys_jd_attach, .sy_auevent = AUE_JD_ATTACH, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 589 = jd_attach */
+ { .sy_narg = AS(jd_remove_args), .sy_call = (sy_call_t *)sys_jd_remove, .sy_auevent = AUE_JD_REMOVE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 590 = jd_remove */
};
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -5037,6 +5037,8 @@
return ("eventfd");
case DTYPE_TIMERFD:
return ("timerfd");
+ case DTYPE_JAILDESC:
+ return ("jail");
default:
return ("unkn");
}
diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c
--- a/sys/kern/kern_jail.c
+++ b/sys/kern/kern_jail.c
@@ -39,6 +39,7 @@
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/errno.h>
+#include <sys/file.h>
#include <sys/sysproto.h>
#include <sys/malloc.h>
#include <sys/osd.h>
@@ -48,6 +49,7 @@
#include <sys/taskqueue.h>
#include <sys/fcntl.h>
#include <sys/jail.h>
+#include <sys/jaildesc.h>
#include <sys/linker.h>
#include <sys/lock.h>
#include <sys/mman.h>
@@ -970,6 +972,8 @@
int
kern_jail_set(struct thread *td, struct uio *optuio, int flags)
{
+ struct file *jfp;
+ struct jaildesc *desc;
struct nameidata nd;
#ifdef INET
struct prison_ip *ip4;
@@ -980,6 +984,7 @@
struct vfsopt *opt;
struct vfsoptlist *opts;
struct prison *pr, *deadpr, *dinspr, *inspr, *mypr, *ppr, *tpr;
+ struct ucred *jdcred;
struct vnode *root;
char *domain, *errmsg, *host, *name, *namelc, *p, *path, *uuid;
char *g_path, *osrelstr;
@@ -993,7 +998,7 @@
int created, cuflags, descend, drflags, enforce;
int error, errmsg_len, errmsg_pos;
int gotchildmax, gotenforce, gothid, gotrsnum, gotslevel;
- int deadid, jid, jsys, len, level;
+ int deadid, jfd_in, jfd_out, jid, jsys, len, level;
int childmax, osreldt, rsnum, slevel;
#ifdef INET
int ip4s;
@@ -1008,11 +1013,6 @@
unsigned tallow;
char numbuf[12];
- error = priv_check(td, PRIV_JAIL_SET);
- if (!error && (flags & JAIL_ATTACH))
- error = priv_check(td, PRIV_JAIL_ATTACH);
- if (error)
- return (error);
mypr = td->td_ucred->cr_prison;
if ((flags & JAIL_CREATE) && mypr->pr_childmax == 0)
return (EPERM);
@@ -1039,6 +1039,9 @@
ip6 = NULL;
#endif
g_path = NULL;
+ jfp = NULL;
+ desc = NULL;
+ jfd_out = -1;
cuflags = flags & (JAIL_CREATE | JAIL_UPDATE);
if (!cuflags) {
@@ -1047,6 +1050,30 @@
goto done_errmsg;
}
+ error = vfs_copyopt(opts, "desc", &jfd_in, sizeof(jfd_in));
+ if (error == ENOENT)
+ jfd_in = -1;
+ else if (error != 0)
+ goto done_free;
+ else if (jfd_in < 0) {
+ /* Allocate a jail descriptor to return later. */
+ error = jaildesc_alloc(td, &jfp, &jfd_out, &desc);
+ if (error)
+ goto done_free;
+ }
+
+ /*
+ * Skip the permission check if there's a jail descriptor,
+ * which uses different credentials.
+ */
+ if (jfd_in < 0) {
+ error = priv_check(td, PRIV_JAIL_SET);
+ if (!error && (flags & JAIL_ATTACH))
+ error = priv_check(td, PRIV_JAIL_ATTACH);
+ if (error)
+ goto done_free;
+ }
+
error = vfs_copyopt(opts, "jid", &jid, sizeof(jid));
if (error == ENOENT)
jid = 0;
@@ -1421,7 +1448,41 @@
error = EAGAIN;
goto done_deref;
}
- if (jid != 0) {
+ if (jfd_in >= 0) {
+ /* Get the jail from its descriptor. */
+ error = jaildesc_find(td, jfd_in, NULL, &pr, &jdcred);
+ if (error) {
+ vfs_opterror(opts, "not a jail descriptor");
+ goto done_deref;
+ }
+ drflags |= PD_LOCKED;
+ /* Check permissions using the descriptor's credentials. */
+ error = priv_check_cred(jdcred, PRIV_JAIL_SET);
+ if (!error && (flags & JAIL_ATTACH))
+ error = priv_check_cred(jdcred, PRIV_JAIL_ATTACH);
+ crfree(jdcred);
+ if (error)
+ goto done_deref;
+ if (cuflags == JAIL_CREATE) {
+ error = EEXIST;
+ vfs_opterror(opts, "jail %d already exists",
+ pr->pr_id);
+ goto done_deref;
+ }
+ if (!prison_isalive(pr)) {
+ /* While a jid can be resurrected, the prison
+ * itself cannot.
+ */
+ error = ENOENT;
+ vfs_opterror(opts, "jail %d is dying", jid);
+ goto done_deref;
+ }
+ if (jid != 0 && jid != pr->pr_id) {
+ error = EINVAL;
+ vfs_opterror(opts, "cannot change jid");
+ goto done_deref;
+ }
+ } else if (jid != 0) {
if (jid < 0) {
error = EINVAL;
vfs_opterror(opts, "negative jid");
@@ -1555,7 +1616,7 @@
}
}
}
- /* Update: must provide a jid or name. */
+ /* Update: must provide a desc, jid, or name. */
else if (cuflags == JAIL_UPDATE && pr == NULL) {
error = ENOENT;
vfs_opterror(opts, "update specified no jail");
@@ -1835,6 +1896,21 @@
goto done_deref;
}
+ /*
+ * Set the jail descriptor if one was requested. This is the
+ * only parameter that is returned to the caller (except the
+ * error message).
+ */
+ if (jfd_out >= 0) {
+ error = vfs_setopt(opts, "desc", &jfd_out, sizeof(jfd_out));
+ if (error != 0)
+ goto done_deref;
+ jaildesc_set_prison(jfp, desc, pr);
+ desc = NULL;
+ fdrop(jfp, td);
+ jfp = NULL;
+ }
+
/*
* Let modules check their parameters. This requires unlocking and
* then re-locking the prison, but this is still a valid state as long
@@ -2158,6 +2234,13 @@
#ifdef INET6
prison_ip_free(ip6);
#endif
+ /* Clean up other resources. */
+ if (jfp != NULL)
+ fdrop(jfp, td);
+ if (desc != NULL)
+ jaildesc_free(desc);
+ if (error && jfd_out >= 0)
+ (void)kern_close(td, jfd_out);
if (g_path != NULL)
free(g_path, M_TEMP);
vfs_freeopts(opts);
@@ -2305,12 +2388,15 @@
kern_jail_get(struct thread *td, struct uio *optuio, int flags)
{
struct bool_flags *bf;
+ struct file *jfp;
+ struct jaildesc *desc;
struct jailsys_flags *jsf;
struct prison *pr, *mypr;
struct vfsopt *opt;
struct vfsoptlist *opts;
char *errmsg, *name;
int drflags, error, errmsg_len, errmsg_pos, i, jid, len, pos;
+ int jfd_in, jfd_out;
unsigned f;
if (flags & ~JAIL_GET_MASK)
@@ -2323,12 +2409,41 @@
errmsg_pos = vfs_getopt_pos(opts, "errmsg");
mypr = td->td_ucred->cr_prison;
pr = NULL;
+ jfp = NULL;
+ desc = NULL;
+ jfd_out = -1;
/*
- * Find the prison specified by one of: lastjid, jid, name.
+ * Find the prison specified by one of: desc, lastjid, jid, name.
*/
sx_slock(&allprison_lock);
drflags = PD_LIST_SLOCKED;
+ error = vfs_copyopt(opts, "desc", &jfd_in, sizeof(jfd_in));
+ if (error == 0) {
+ if (jfd_in >= 0) {
+ /* Get the jail from its descriptor. */
+ error = jaildesc_find(td, jfd_in, NULL, &pr, NULL);
+ if (error) {
+ vfs_opterror(opts, "not a jail descriptor");
+ goto done;
+ }
+ drflags |= PD_LOCKED;
+ if (!(prison_isalive(pr) || (flags & JAIL_DYING))) {
+ error = ENOENT;
+ vfs_opterror(opts, "jail %d is dying",
+ pr->pr_id);
+ goto done;
+ }
+ goto found_prison;
+ } else {
+ /* Allocate a jail descriptor to return later. */
+ error = jaildesc_alloc(td, &jfp, &jfd_out, &desc);
+ if (error)
+ goto done;
+ }
+ } else if (error != ENOENT)
+ goto done;
+
error = vfs_copyopt(opts, "lastjid", &jid, sizeof(jid));
if (error == 0) {
TAILQ_FOREACH(pr, &allprison, pr_list) {
@@ -2400,6 +2515,15 @@
prison_hold(pr);
drflags |= PD_DEREF;
td->td_retval[0] = pr->pr_id;
+ if (jfd_out >= 0) {
+ error = vfs_setopt(opts, "desc", &jfd_out, sizeof(jfd_out));
+ if (error != 0)
+ goto done;
+ jaildesc_set_prison(jfp, desc, pr);
+ desc = NULL;
+ fdrop(jfp, td);
+ jfp = NULL;
+ }
error = vfs_setopt(opts, "jid", &pr->pr_id, sizeof(pr->pr_id));
if (error != 0 && error != ENOENT)
goto done;
@@ -2565,11 +2689,20 @@
}
done:
+ /* Clean up jail descriptor bits. */
+ if (jfp != NULL)
+ fdrop(jfp, td);
+ if (desc != NULL)
+ jaildesc_free(desc);
+ if (error && jfd_out >= 0)
+ (void)kern_close(td, jfd_out);
/* Release any temporary prison holds and/or locks. */
if (pr != NULL)
prison_deref(pr, drflags);
else if (drflags & PD_LIST_SLOCKED)
sx_sunlock(&allprison_lock);
+ else if (drflags & PD_LIST_XLOCKED)
+ sx_xunlock(&allprison_lock);
if (error && errmsg_pos >= 0) {
/* Write the error message back to userspace. */
vfs_getopt(opts, "errmsg", (void **)&errmsg, &errmsg_len);
@@ -2620,6 +2753,41 @@
return (0);
}
+/*
+ * struct jd_remove_args {
+ * int fd;
+ * };
+ */
+int
+sys_jd_remove(struct thread *td, struct jd_remove_args *uap)
+{
+ struct prison *pr;
+ struct ucred *jdcred;
+ int error;
+
+ sx_xlock(&allprison_lock);
+ error = jaildesc_find(td, uap->fd, NULL, &pr, &jdcred);
+ if (error)
+ goto fail_allprison;
+ error = priv_check_cred(jdcred, PRIV_JAIL_REMOVE);
+ crfree(jdcred);
+ if (error)
+ goto fail_prison;
+ if (!prison_isalive(pr)) {
+ /* Silently ignore already-dying prisons. */
+ goto fail_prison;
+ }
+
+ prison_deref(pr, PD_KILL | PD_LOCKED | PD_LIST_XLOCKED);
+ return (0);
+
+ fail_prison:
+ mtx_unlock(&pr->pr_mtx);
+ fail_allprison:
+ sx_xunlock(&allprison_lock);
+ return (error);
+}
+
/*
* struct jail_attach_args {
* int jid;
@@ -2652,6 +2820,42 @@
return (do_jail_attach(td, pr, PD_LOCKED | PD_LIST_SLOCKED));
}
+/*
+ * struct jd_attach_args {
+ * int fid;
+ * };
+ */
+int
+sys_jd_attach(struct thread *td, struct jd_attach_args *uap)
+{
+ struct prison *pr;
+ struct ucred *jdcred;
+ int error;
+
+ sx_slock(&allprison_lock);
+ error = jaildesc_find(td, uap->fd, NULL, &pr, &jdcred);
+ if (error)
+ goto fail_allprison;
+ error = priv_check_cred(jdcred, PRIV_JAIL_ATTACH);
+ crfree(jdcred);
+ if (error)
+ goto fail_prison;
+
+ /* Do not allow a process to attach to a prison that is not alive. */
+ if (!prison_isalive(pr)) {
+ error = EINVAL;
+ goto fail_prison;
+ }
+
+ return (do_jail_attach(td, pr, PD_LOCKED | PD_LIST_SLOCKED));
+
+ fail_prison:
+ mtx_unlock(&pr->pr_mtx);
+ fail_allprison:
+ sx_xunlock(&allprison_lock);
+ return (error);
+}
+
static int
do_jail_attach(struct thread *td, struct prison *pr, int drflags)
{
@@ -4542,6 +4746,7 @@
* jail creation time but cannot be changed in an existing jail.
*/
SYSCTL_JAIL_PARAM(, jid, CTLTYPE_INT | CTLFLAG_RDTUN, "I", "Jail ID");
+SYSCTL_JAIL_PARAM(, desc, CTLTYPE_INT | CTLFLAG_RW, "I", "Jail descriptor");
SYSCTL_JAIL_PARAM(, parent, CTLTYPE_INT | CTLFLAG_RD, "I", "Jail parent ID");
SYSCTL_JAIL_PARAM_STRING(, name, CTLFLAG_RW, MAXHOSTNAMELEN, "Jail name");
SYSCTL_JAIL_PARAM_STRING(, path, CTLFLAG_RDTUN, MAXPATHLEN, "Jail root path");
diff --git a/sys/kern/kern_jaildesc.c b/sys/kern/kern_jaildesc.c
--- a/sys/kern/kern_jaildesc.c
+++ b/sys/kern/kern_jaildesc.c
@@ -0,0 +1,180 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 James Gritton.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/fcntl.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
+#include <sys/kernel.h>
+#include <sys/jail.h>
+#include <sys/jaildesc.h>
+#include <sys/sysproto.h>
+#include <sys/systm.h>
+#include <sys/ucred.h>
+
+MALLOC_DEFINE(M_JAILDESC, "jaildesc", "jail descriptors");
+
+static fo_stat_t jaildesc_stat;
+static fo_close_t jaildesc_close;
+static fo_fill_kinfo_t jaildesc_fill_kinfo;
+
+static struct fileops jaildesc_ops = {
+ .fo_read = invfo_rdwr,
+ .fo_write = invfo_rdwr,
+ .fo_truncate = invfo_truncate,
+ .fo_ioctl = invfo_ioctl,
+ .fo_poll = invfo_poll,
+ .fo_kqfilter = invfo_kqfilter,
+ .fo_stat = jaildesc_stat,
+ .fo_close = jaildesc_close,
+ .fo_chmod = invfo_chmod,
+ .fo_chown = invfo_chown,
+ .fo_sendfile = invfo_sendfile,
+ .fo_fill_kinfo = jaildesc_fill_kinfo,
+ .fo_flags = DFLAG_PASSABLE,
+};
+
+/*
+ * Given a jail descriptor, return its prison and optionally its credential.
+ * The prison will be returned locked, and the credential returned held.
+ */
+int
+jaildesc_find(struct thread *td, int fd, cap_rights_t *rights,
+ struct prison **prp, struct ucred **ucredp)
+{
+ struct file *fp;
+ struct prison *pr;
+ int error;
+
+ error = fget(td, fd, rights, &fp);
+ if (error)
+ return (error);
+ if (fp->f_type != DTYPE_JAILDESC) {
+ error = EBADF;
+ goto out;
+ }
+ pr = ((struct jaildesc *)fp->f_data)->jd_prison;
+ MPASS(pr != NULL);
+ KASSERT(prison_isvalid(pr), ("jaildesc has invalid prison %p", pr));
+ *prp = pr;
+ prison_lock(pr);
+ if (ucredp)
+ *ucredp = crhold(fp->f_cred);
+out:
+ fdrop(fp, td);
+ return (error);
+}
+
+/*
+ * Allocate a new jail decriptor, not yet associated with a prison.
+ */
+int
+jaildesc_alloc(struct thread *td, struct file **fpp, int *fdp,
+ struct jaildesc **jdp)
+{
+ struct file *fp;
+ struct jaildesc *jd;
+ int error;
+
+ jd = malloc(sizeof(*jd), M_JAILDESC, M_WAITOK | M_ZERO);
+ error = falloc_caps(td, &fp, fdp, 0, NULL);
+ if (error) {
+ free(jd, M_JAILDESC);
+ return (error);
+ }
+ *fpp = fp;
+ *jdp = jd;
+ return (0);
+}
+
+/*
+ * Assocate a jail descriptor with its prison.
+ */
+void
+jaildesc_set_prison(struct file *fp, struct jaildesc *jd, struct prison *pr)
+{
+
+ mtx_assert(&pr->pr_mtx, MA_OWNED);
+ jd->jd_prison = pr;
+ LIST_INSERT_HEAD(&pr->pr_descs, jd, jd_list);
+ prison_hold(pr);
+ /*
+ * Now the file is ready to be a jail descriptor.
+ */
+ finit(fp, FREAD | FWRITE, DTYPE_JAILDESC, jd, &jaildesc_ops);
+}
+
+
+/*
+ * Detach the jail descriptor from its associated prison and free it.
+ */
+void
+jaildesc_free(struct jaildesc *jd)
+{
+ struct prison *pr;
+ int locked;
+
+ pr = jd->jd_prison;
+ if (pr != NULL)
+ {
+ locked = mtx_owned(&pr->pr_mtx);
+ if (!locked)
+ prison_lock(pr);
+ LIST_REMOVE(jd, jd_list);
+ prison_free(pr);
+ if (!locked)
+ prison_unlock(pr);
+ }
+ free(jd, M_JAILDESC);
+}
+
+static int
+jaildesc_close(struct file *fp, struct thread *td)
+{
+ struct jaildesc *jd;
+
+ jd = fp->f_data;
+ finit(fp, 0, DTYPE_NONE, NULL, &badfileops);
+ if (jd != NULL)
+ jaildesc_free(jd);
+ return (0);
+}
+
+static int
+jaildesc_stat(struct file *fp, struct stat *sb, struct ucred *active_cred)
+{
+
+ return (EINVAL);
+}
+
+static int
+jaildesc_fill_kinfo(struct file *fp, struct kinfo_file *kif,
+ struct filedesc *fdp)
+{
+
+ return (EINVAL);
+}
diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c
--- a/sys/kern/syscalls.c
+++ b/sys/kern/syscalls.c
@@ -594,4 +594,6 @@
"timerfd_gettime", /* 586 = timerfd_gettime */
"timerfd_settime", /* 587 = timerfd_settime */
"kcmp", /* 588 = kcmp */
+ "jd_attach", /* 589 = jd_attach */
+ "jd_remove", /* 590 = jd_remove */
};
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -2437,7 +2437,6 @@
_In_ void *value
);
}
-
457 AUE_MQ_OPEN NOSTD {
int kmq_open(
_In_z_ const char *path,
@@ -3338,5 +3337,15 @@
uintptr_t idx2
);
}
+589 AUE_JD_ATTACH STD|CAPENABLED {
+ int jd_attach(
+ int fd
+ );
+ }
+590 AUE_JD_REMOVE STD|CAPENABLED {
+ int jd_remove(
+ int fd
+ );
+ }
; vim: syntax=off
diff --git a/sys/kern/systrace_args.c b/sys/kern/systrace_args.c
--- a/sys/kern/systrace_args.c
+++ b/sys/kern/systrace_args.c
@@ -3455,6 +3455,20 @@
*n_args = 5;
break;
}
+ /* jd_attach */
+ case 589: {
+ struct jd_attach_args *p = params;
+ iarg[a++] = p->fd; /* int */
+ *n_args = 1;
+ break;
+ }
+ /* jd_remove */
+ case 590: {
+ struct jd_remove_args *p = params;
+ iarg[a++] = p->fd; /* int */
+ *n_args = 1;
+ break;
+ }
default:
*n_args = 0;
break;
@@ -9245,6 +9259,26 @@
break;
};
break;
+ /* jd_attach */
+ case 589:
+ switch (ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* jd_remove */
+ case 590:
+ switch (ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
default:
break;
};
@@ -11218,6 +11252,16 @@
if (ndx == 0 || ndx == 1)
p = "int";
break;
+ /* jd_attach */
+ case 589:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* jd_remove */
+ case 590:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
default:
break;
};
diff --git a/sys/sys/event.h b/sys/sys/event.h
--- a/sys/sys/event.h
+++ b/sys/sys/event.h
@@ -45,7 +45,8 @@
#define EVFILT_USER (-11) /* User events */
#define EVFILT_SENDFILE (-12) /* attached to sendfile requests */
#define EVFILT_EMPTY (-13) /* empty send socket buf */
-#define EVFILT_SYSCOUNT 13
+#define EVFILT_JAIL (-14) /* attached to jail descriptors */
+#define EVFILT_SYSCOUNT 14
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#define EV_SET(kevp_, a, b, c, d, e, f) do { \
diff --git a/sys/sys/file.h b/sys/sys/file.h
--- a/sys/sys/file.h
+++ b/sys/sys/file.h
@@ -68,6 +68,7 @@
#define DTYPE_PROCDESC 12 /* process descriptor */
#define DTYPE_EVENTFD 13 /* eventfd */
#define DTYPE_TIMERFD 14 /* timerfd */
+#define DTYPE_JAILDESC 15 /* jail descriptor */
#ifdef _KERNEL
diff --git a/sys/sys/jail.h b/sys/sys/jail.h
--- a/sys/sys/jail.h
+++ b/sys/sys/jail.h
@@ -116,6 +116,8 @@
int jail_get(struct iovec *, unsigned int, int);
int jail_attach(int);
int jail_remove(int);
+int jd_attach(int);
+int jd_remove(int);
__END_DECLS
#else /* _KERNEL */
@@ -141,6 +143,7 @@
#define DEFAULT_HOSTUUID "00000000-0000-0000-0000-000000000000"
#define OSRELEASELEN 32
+struct jaildesc;
struct racct;
struct prison_racct;
@@ -186,7 +189,8 @@
struct vnode *pr_root; /* (c) vnode to rdir */
struct prison_ip *pr_addrs[PR_FAMILY_MAX]; /* (p,n) IPs of jail */
struct prison_racct *pr_prison_racct; /* (c) racct jail proxy */
- void *pr_sparep[3];
+ LIST_HEAD(, jaildesc) pr_descs; /* (a) attached descriptors */
+ void *pr_sparep[2];
int pr_childcount; /* (a) number of child jails */
int pr_childmax; /* (p) maximum child jails */
unsigned pr_allow; /* (p) PR_ALLOW_* flags */
@@ -418,6 +422,8 @@
void getcredhostuuid(struct ucred *, char *, size_t);
void getcredhostid(struct ucred *, unsigned long *);
void getjailname(struct ucred *cred, char *name, size_t len);
+int kern_jail_attach(struct thread *td, struct prison *pr);
+int kern_jail_remove(struct prison *pr);
void prison0_init(void);
bool prison_allow(struct ucred *, unsigned);
int prison_check(struct ucred *cred1, struct ucred *cred2);
diff --git a/sys/sys/jaildesc.h b/sys/sys/jaildesc.h
--- a/sys/sys/jaildesc.h
+++ b/sys/sys/jaildesc.h
@@ -0,0 +1,64 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 James Gritton.
+ * All rights reserved.
+ *
+ * This software was developed at the University of Cambridge Computer
+ * Laboratory with support from a grant from Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _SYS_JAILDESC_H_
+#define _SYS_JAILDESC_H_
+
+#ifdef _KERNEL
+
+#include <sys/queue.h>
+
+struct prison;
+
+/*-
+ * struct jaildesc describes a jail descriptor, which points to a struct
+ * prison. struct prison in turn has a linked list of struct jaildesc.
+ *
+ * Locking key:
+ * (c) set on creation, remains unchanged
+ * (p) jd_prison->pr_mtx
+ */
+struct jaildesc {
+ LIST_ENTRY(jaildesc) jd_list; /* (c,p) this prison's descs */
+ struct prison *jd_prison; /* (c) the prison */
+};
+
+int jaildesc_find(struct thread *td, int fd, cap_rights_t *rights,
+ struct prison **prp, struct ucred **ucredp);
+int jaildesc_alloc(struct thread *td, struct file **fpp, int *fdp,
+ struct jaildesc **jdp);
+void jaildesc_set_prison(struct file *fp, struct jaildesc *jd,
+ struct prison *pr);
+void jaildesc_free(struct jaildesc *jd);
+
+#endif /* _KERNEL */
+
+#endif /* !_SYS_JAILDESC_H_ */
diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h
--- a/sys/sys/syscall.h
+++ b/sys/sys/syscall.h
@@ -525,4 +525,6 @@
#define SYS_timerfd_gettime 586
#define SYS_timerfd_settime 587
#define SYS_kcmp 588
-#define SYS_MAXSYSCALL 589
+#define SYS_jd_attach 589
+#define SYS_jd_remove 590
+#define SYS_MAXSYSCALL 591
diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk
--- a/sys/sys/syscall.mk
+++ b/sys/sys/syscall.mk
@@ -428,4 +428,6 @@
timerfd_create.o \
timerfd_gettime.o \
timerfd_settime.o \
- kcmp.o
+ kcmp.o \
+ jd_attach.o \
+ jd_remove.o
diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h
--- a/sys/sys/sysproto.h
+++ b/sys/sys/sysproto.h
@@ -1877,6 +1877,12 @@
char idx1_l_[PADL_(uintptr_t)]; uintptr_t idx1; char idx1_r_[PADR_(uintptr_t)];
char idx2_l_[PADL_(uintptr_t)]; uintptr_t idx2; char idx2_r_[PADR_(uintptr_t)];
};
+struct jd_attach_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+};
+struct jd_remove_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+};
int sys_exit(struct thread *, struct exit_args *);
int sys_fork(struct thread *, struct fork_args *);
int sys_read(struct thread *, struct read_args *);
@@ -2276,6 +2282,8 @@
int sys_timerfd_gettime(struct thread *, struct timerfd_gettime_args *);
int sys_timerfd_settime(struct thread *, struct timerfd_settime_args *);
int sys_kcmp(struct thread *, struct kcmp_args *);
+int sys_jd_attach(struct thread *, struct jd_attach_args *);
+int sys_jd_remove(struct thread *, struct jd_remove_args *);
#ifdef COMPAT_43
@@ -3255,6 +3263,8 @@
#define SYS_AUE_timerfd_gettime AUE_TIMERFD
#define SYS_AUE_timerfd_settime AUE_TIMERFD
#define SYS_AUE_kcmp AUE_NULL
+#define SYS_AUE_jd_attach AUE_JD_ATTACH
+#define SYS_AUE_jd_remove AUE_JD_REMOVE
#undef PAD_
#undef PADL_
diff --git a/sys/sys/user.h b/sys/sys/user.h
--- a/sys/sys/user.h
+++ b/sys/sys/user.h
@@ -263,6 +263,7 @@
#define KF_TYPE_DEV 12
#define KF_TYPE_EVENTFD 13
#define KF_TYPE_TIMERFD 14
+#define KF_TYPE_JAILDESC 15
#define KF_TYPE_UNKNOWN 255
#define KF_VTYPE_VNON 0
@@ -449,6 +450,10 @@
uint32_t kf_timerfd_flags;
uint64_t kf_timerfd_addr;
} kf_timerfd;
+ struct {
+ int32_t kf_jid;
+ int32_t kf_spareint[1];
+ } kf_jail;
struct {
uint64_t kf_kqueue_addr;
int32_t kf_kqueue_count;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Oct 11, 11:30 PM (3 h, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
23597580
Default Alt Text
D43696.id133680.diff (25 KB)
Attached To
Mode
D43696: Jail descriptors
Attached
Detach File
Event Timeline
Log In to Comment