aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/kern_jail.c
diff options
context:
space:
mode:
authorEdward Tomasz Napierala <trasz@FreeBSD.org>2011-05-03 07:32:58 +0000
committerEdward Tomasz Napierala <trasz@FreeBSD.org>2011-05-03 07:32:58 +0000
commita7ad07bff3f0501e3ea483955122f5da37519674 (patch)
tree83f996220eb5127d50beee996ac337678876fccc /sys/kern/kern_jail.c
parent74ff69fe440970de0ca87411a48ea7aa78182a8a (diff)
downloadsrc-a7ad07bff3f0501e3ea483955122f5da37519674.tar.gz
src-a7ad07bff3f0501e3ea483955122f5da37519674.zip
Change the way rctl interfaces with jails by introducing prison_racct
structure, which acts as a proxy between them. This makes jail rules persistent, i.e. they can be added before jail gets created, and they don't disappear when the jail gets destroyed.
Notes
Notes: svn path=/head/; revision=221362
Diffstat (limited to 'sys/kern/kern_jail.c')
-rw-r--r--sys/kern/kern_jail.c116
1 files changed, 107 insertions, 9 deletions
diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c
index 22b97e854ad1..5850ad1b512b 100644
--- a/sys/kern/kern_jail.c
+++ b/sys/kern/kern_jail.c
@@ -50,7 +50,7 @@ __FBSDID("$FreeBSD$");
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/racct.h>
-#include <sys/rctl.h>
+#include <sys/refcount.h>
#include <sys/sx.h>
#include <sys/sysent.h>
#include <sys/namei.h>
@@ -78,6 +78,7 @@ __FBSDID("$FreeBSD$");
#define DEFAULT_HOSTUUID "00000000-0000-0000-0000-000000000000"
MALLOC_DEFINE(M_PRISON, "prison", "Prison structures");
+MALLOC_DEFINE(M_PRISON_RACCT, "prison_racct", "Prison racct structures");
/* Keep struct prison prison0 and some code in kern_jail_set() readable. */
#ifdef INET
@@ -114,10 +115,11 @@ struct prison prison0 = {
};
MTX_SYSINIT(prison0, &prison0.pr_mtx, "jail mutex", MTX_DEF);
-/* allprison and lastprid are protected by allprison_lock. */
+/* allprison, allprison_racct and lastprid are protected by allprison_lock. */
struct sx allprison_lock;
SX_SYSINIT(allprison_lock, &allprison_lock, "allprison");
struct prisonlist allprison = TAILQ_HEAD_INITIALIZER(allprison);
+LIST_HEAD(, prison_racct) allprison_racct;
int lastprid = 0;
static int do_jail_attach(struct thread *td, struct prison *pr);
@@ -125,6 +127,10 @@ static void prison_complete(void *context, int pending);
static void prison_deref(struct prison *pr, int flags);
static char *prison_path(struct prison *pr1, struct prison *pr2);
static void prison_remove_one(struct prison *pr);
+#ifdef RACCT
+static void prison_racct_attach(struct prison *pr);
+static void prison_racct_detach(struct prison *pr);
+#endif
#ifdef INET
static int _prison_check_ip4(struct prison *pr, struct in_addr *ia);
static int prison_restrict_ip4(struct prison *pr, struct in_addr *newip4);
@@ -1197,7 +1203,6 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
root = mypr->pr_root;
vref(root);
}
- racct_create(&pr->pr_racct);
strlcpy(pr->pr_hostuuid, DEFAULT_HOSTUUID, HOSTUUIDLEN);
pr->pr_flags |= PR_HOST;
#if defined(INET) || defined(INET6)
@@ -1657,6 +1662,11 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
pr->pr_flags = (pr->pr_flags & ~ch_flags) | pr_flags;
mtx_unlock(&pr->pr_mtx);
+#ifdef RACCT
+ if (created)
+ prison_racct_attach(pr);
+#endif
+
/* Locks may have prevented a complete restriction of child IP
* addresses. If so, allocate some more memory and try again.
*/
@@ -2533,10 +2543,9 @@ prison_deref(struct prison *pr, int flags)
if (pr->pr_cpuset != NULL)
cpuset_rel(pr->pr_cpuset);
osd_jail_exit(pr);
-#ifdef RCTL
- rctl_racct_release(pr->pr_racct);
+#ifdef RACCT
+ prison_racct_detach(pr);
#endif
- racct_destroy(&pr->pr_racct);
free(pr, M_PRISON);
/* Removing a prison frees a reference on its parent. */
@@ -4277,14 +4286,103 @@ void
prison_racct_foreach(void (*callback)(struct racct *racct,
void *arg2, void *arg3), void *arg2, void *arg3)
{
- struct prison *pr;
+ struct prison_racct *prr;
sx_slock(&allprison_lock);
- TAILQ_FOREACH(pr, &allprison, pr_list)
- (callback)(pr->pr_racct, arg2, arg3);
+ LIST_FOREACH(prr, &allprison_racct, prr_next)
+ (callback)(prr->prr_racct, arg2, arg3);
sx_sunlock(&allprison_lock);
}
+static struct prison_racct *
+prison_racct_find_locked(const char *name)
+{
+ struct prison_racct *prr;
+
+ sx_assert(&allprison_lock, SA_XLOCKED);
+
+ if (name[0] == '\0' || strlen(name) >= MAXHOSTNAMELEN)
+ return (NULL);
+
+ LIST_FOREACH(prr, &allprison_racct, prr_next) {
+ if (strcmp(name, prr->prr_name) != 0)
+ continue;
+
+ /* Found prison_racct with a matching name? */
+ prison_racct_hold(prr);
+ return (prr);
+ }
+
+ /* Add new prison_racct. */
+ prr = malloc(sizeof(*prr), M_PRISON_RACCT, M_ZERO | M_WAITOK);
+ racct_create(&prr->prr_racct);
+
+ strcpy(prr->prr_name, name);
+ refcount_init(&prr->prr_refcount, 1);
+ LIST_INSERT_HEAD(&allprison_racct, prr, prr_next);
+
+ return (prr);
+}
+
+struct prison_racct *
+prison_racct_find(const char *name)
+{
+ struct prison_racct *prr;
+
+ sx_xlock(&allprison_lock);
+ prr = prison_racct_find_locked(name);
+ sx_xunlock(&allprison_lock);
+ return (prr);
+}
+
+void
+prison_racct_hold(struct prison_racct *prr)
+{
+
+ refcount_acquire(&prr->prr_refcount);
+}
+
+void
+prison_racct_free(struct prison_racct *prr)
+{
+ int old;
+
+ old = prr->prr_refcount;
+ if (old > 1 && atomic_cmpset_int(&prr->prr_refcount, old, old - 1))
+ return;
+
+ sx_xlock(&allprison_lock);
+ if (refcount_release(&prr->prr_refcount)) {
+ racct_destroy(&prr->prr_racct);
+ LIST_REMOVE(prr, prr_next);
+ sx_xunlock(&allprison_lock);
+ free(prr, M_PRISON_RACCT);
+
+ return;
+ }
+ sx_xunlock(&allprison_lock);
+}
+
+#ifdef RACCT
+static void
+prison_racct_attach(struct prison *pr)
+{
+ struct prison_racct *prr;
+
+ prr = prison_racct_find_locked(pr->pr_name);
+ KASSERT(prr != NULL, ("cannot find prison_racct"));
+
+ pr->pr_prison_racct = prr;
+}
+
+static void
+prison_racct_detach(struct prison *pr)
+{
+ prison_racct_free(pr->pr_prison_racct);
+ pr->pr_prison_racct = NULL;
+}
+#endif /* RACCT */
+
#ifdef DDB
static void