PERFORCE change 166914 for review
Edward Tomasz Napierala
trasz at FreeBSD.org
Sun Aug 2 10:16:36 UTC 2009
http://perforce.freebsd.org/chv.cgi?CH=166914
Change 166914 by trasz at trasz_anger on 2009/08/02 10:16:29
Rework rule storage. It's not fully functional yet, but hey,
at least it doesn't panic :-)
Affected files ...
.. //depot/projects/soc2009/trasz_limits/TODO#6 edit
.. //depot/projects/soc2009/trasz_limits/sys/kern/init_main.c#8 edit
.. //depot/projects/soc2009/trasz_limits/sys/kern/kern_hrl.c#34 edit
.. //depot/projects/soc2009/trasz_limits/sys/kern/kern_loginclass.c#2 edit
.. //depot/projects/soc2009/trasz_limits/sys/kern/kern_resource.c#14 edit
.. //depot/projects/soc2009/trasz_limits/sys/sys/hrl.h#25 edit
.. //depot/projects/soc2009/trasz_limits/sys/sys/loginclass.h#1 add
.. //depot/projects/soc2009/trasz_limits/sys/sys/proc.h#10 edit
.. //depot/projects/soc2009/trasz_limits/usr.bin/id/id.c#4 edit
Differences ...
==== //depot/projects/soc2009/trasz_limits/TODO#6 (text+ko) ====
@@ -1,5 +1,8 @@
+ - Rework rule storage.
+
- Make sure we have all the gidinfos we need in the 'struct ucred'.
+
- Fix up (add/remove resource counters) when:
- Adding a group to a process,
- Removing a group from a process,
==== //depot/projects/soc2009/trasz_limits/sys/kern/init_main.c#8 (text+ko) ====
@@ -56,6 +56,7 @@
#include <sys/jail.h>
#include <sys/ktr.h>
#include <sys/lock.h>
+#include <sys/loginclass.h>
#include <sys/mount.h>
#include <sys/mutex.h>
#include <sys/syscallsubr.h>
==== //depot/projects/soc2009/trasz_limits/sys/kern/kern_hrl.c#34 (text+ko) ====
@@ -31,9 +31,11 @@
#include <sys/param.h>
#include <sys/malloc.h>
#include <sys/queue.h>
+#include <sys/refcount.h>
#include <sys/jail.h>
#include <sys/kernel.h>
#include <sys/limits.h>
+#include <sys/loginclass.h>
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/resourcevar.h>
@@ -58,11 +60,6 @@
TUNABLE_INT("kern.hrl_group_accounting", &hrl_group_accounting);
SYSCTL_INT(_kern, OID_AUTO, hrl_group_accounting, CTLFLAG_RD, &hrl_group_accounting, 0, "");
-struct hrl_node {
- struct hrl_rule hn_rule;
- RB_ENTRY(hrl_node) hn_next;
-};
-
struct dict {
const char *d_name;
int d_value;
@@ -104,57 +101,14 @@
{ "sigxfsz", HRL_ACTION_SIGXFSZ },
{ NULL, -1 }};
-/*
- * XXX: This is silly. Some better way of organising these
- * will be required.
- */
-static int
-hn_compare(const struct hrl_node *a, const struct hrl_node *b)
-{
- if (a->hn_rule.hr_subject < b->hn_rule.hr_subject)
- return (-1);
- else if (a->hn_rule.hr_subject > b->hn_rule.hr_subject)
- return (1);
-
- if (a->hn_rule.hr_subject_id < b->hn_rule.hr_subject_id)
- return (-1);
- else if (a->hn_rule.hr_subject_id > b->hn_rule.hr_subject_id)
- return (1);
-
- if (a->hn_rule.hr_per < b->hn_rule.hr_per)
- return (-1);
- else if (a->hn_rule.hr_per > b->hn_rule.hr_per)
- return (1);
-
- if (a->hn_rule.hr_resource < b->hn_rule.hr_resource)
- return (-1);
- else if (a->hn_rule.hr_resource > b->hn_rule.hr_resource)
- return (1);
-
- if (a->hn_rule.hr_action < b->hn_rule.hr_action)
- return (-1);
- else if (a->hn_rule.hr_action > b->hn_rule.hr_action)
- return (1);
-
- return (0);
-}
-
-/*
- * hrl_lock must be held during all operations on hrls.
- */
-RB_HEAD(hrl_tree, hrl_node) hrls = RB_INITIALIZER(hrls);
-RB_GENERATE_STATIC(hrl_tree, hrl_node, hn_next, hn_compare);
-
static const char * hrl_resource_name(int resource);
static void hrl_init(void);
SYSINIT(hrl, SI_SUB_CPU, SI_ORDER_FIRST, hrl_init, NULL);
-static uma_zone_t hrl_node_zone;
static uma_zone_t hrl_limit_zone;
+static uma_zone_t hrl_rule_zone;
static struct mtx hrl_lock;
-static void hrl_rule_remove_limits(struct hrl_rule *rule);
-static void hrl_rule_add_limits(struct hrl_rule *rule);
static void hrl_compute_available(struct proc *p, int64_t (*availablep)[],
struct hrl_rule *(*rulesp)[]);
static struct sbuf *hrl_rules_to_sbuf(struct hrl_rule *usage, int nrules);
@@ -184,10 +138,13 @@
cred = p->p_ucred;
mtx_assert(&hrl_lock, MA_OWNED);
for (resource = 0; resource < HRL_RESOURCE_MAX; resource++)
- KASSERT(p->p_usage.hu_resources[resource] >= 0, ("resource usage propagation meltdown"));
- KASSERT(cred->cr_ruidinfo->ui_usage.hu_resources[resource] >= 0, ("resource usage propagation meltdown"));
+ KASSERT(p->p_usage.hu_resources[resource] >= 0,
+ ("resource usage propagation meltdown"));
+ KASSERT(cred->cr_ruidinfo->ui_usage.hu_resources[resource] >= 0,
+ ("resource usage propagation meltdown"));
for (pr = cred->cr_prison; pr != NULL; pr = pr->pr_parent)
- KASSERT(pr->pr_usage.hu_resources[resource] >= 0, ("resource usage propagation meltdown"));
+ KASSERT(pr->pr_usage.hu_resources[resource] >= 0,
+ ("resource usage propagation meltdown"));
if (hrl_group_accounting) {
for (i = 0; i < cred->cr_ngroups; i++) {
for (resource = 0; resource < HRL_RESOURCE_MAX; resource++)
@@ -269,27 +226,6 @@
panic("hrl_resource_name: unknown resource");
}
-void
-hrl_proc_fork(struct proc *parent, struct proc *child)
-{
- int i;
-
- mtx_lock(&hrl_lock);
- /*
- * Inherit resources from the parent.
- */
- for (i = 0; i < HRL_RESOURCE_MAX; i++) {
- if (parent->p_usage.hu_resources[i] != 0 && hrl_resource_inheritable(i))
- hrl_allocated_proc(child, i, parent->p_usage.hu_resources[i]);
- }
-
- /*
- * Assign rules appropriate for the process.
- */
- LIST_INIT(&child->p_limits);
- mtx_unlock(&hrl_lock);
-}
-
static void
hrl_deferred_psignal(struct proc *p, int signum)
{
@@ -368,6 +304,46 @@
}
/*
+ * Go through all the rules applicable to the process, fill first array
+ * with amount of resource left before hitting next limit, and the second
+ * with pointers to the limit to be hit.
+ */
+/*
+ * XXX: We should sort the rules somewhat, so that 'log' rules are enforced
+ * before 'deny', if both are for the same subject, resource and amount.
+ */
+static void
+hrl_compute_available(struct proc *p, int64_t (*availablep)[],
+ struct hrl_rule *(*rulesp)[])
+{
+ int i, resource;
+ int64_t available;
+ struct hrl_limit *limit;
+
+ mtx_assert(&hrl_lock, MA_OWNED);
+
+ for (i = 0; i < HRL_RESOURCE_MAX; i++) {
+ (*availablep)[i] = INT64_MAX;
+ (*rulesp)[i] = NULL;
+ }
+
+ mtx_assert(&hrl_lock, MA_OWNED);
+
+ LIST_FOREACH(limit, &p->p_limits, hl_next) {
+ resource = limit->hl_rule->hr_resource;
+ available = limit->hl_rule->hr_amount -
+ p->p_usage.hu_resources[resource];
+ /* Skip limits that have been already exceeded. */
+ if (available < 0)
+ continue;
+ if (available < (*availablep)[resource]) {
+ (*availablep)[resource] = available;
+ (*rulesp)[resource] = limit->hl_rule;
+ }
+ }
+}
+
+/*
* Increase allocation of 'resource' by 'amount' for process 'p'.
* Return 0 if it's below limits, or errno, if it's not.
*/
@@ -563,53 +539,6 @@
}
void
-hrl_adjust(int subject, id_t subject_id, int per, int resource, int action, int64_t amount)
-{
- struct hrl_node searched, *node, *existing;
-
- searched.hn_rule.hr_subject = subject;
- searched.hn_rule.hr_subject_id = subject_id;
- searched.hn_rule.hr_per = per;
- searched.hn_rule.hr_resource = resource;
- searched.hn_rule.hr_action = action;
-
- /*
- * Removing a limit.
- */
- if (amount == -1) {
- mtx_lock(&hrl_lock);
- node = RB_FIND(hrl_tree, &hrls, &searched);
- if (node != NULL) {
- node = RB_REMOVE(hrl_tree, &hrls, node);
- KASSERT(node != NULL, ("hrl_adjust: node removal failed"));
- }
- mtx_unlock(&hrl_lock);
- if (node != NULL) {
- hrl_rule_remove_limits(&node->hn_rule);
- uma_zfree(hrl_node_zone, node);
- }
- return;
- }
-
- /*
- * Adding a new limit or changing existing one.
- */
- node = uma_zalloc(hrl_node_zone, M_WAITOK);
- *node = searched;
- mtx_lock(&hrl_lock);
- existing = RB_INSERT(hrl_tree, &hrls, node);
- if (existing != NULL)
- existing->hn_rule.hr_amount = amount;
- else
- node->hn_rule.hr_amount = amount;
- mtx_unlock(&hrl_lock);
- if (existing != NULL)
- uma_zfree(hrl_node_zone, node);
- else
- hrl_rule_add_limits(&node->hn_rule);
-}
-
-void
hrl_usage_add(struct hrl_usage *dest, const struct hrl_usage *src)
{
int i;
@@ -651,12 +580,13 @@
static int
hrl_rule_matches(const struct hrl_rule *rule, const struct hrl_rule *filter)
{
+
if (filter->hr_subject != HRL_SUBJECT_UNDEFINED) {
if (rule->hr_subject != filter->hr_subject)
return (0);
}
- if (filter->hr_subject_id >= 0) {
+ if (filter->hr_subject_id != HRL_SUBJECT_ID_UNDEFINED) {
if (rule->hr_subject_id != filter->hr_subject_id)
return (0);
}
@@ -733,120 +663,118 @@
}
/*
- * Add a new limit for a rule, if it's not already there.
+ * Add a new limit for a rule, increasing refcount for the rule.
*/
static void
-hrl_limit_add_if_needed(struct hrl_limits_head *limits_head, struct hrl_rule *rule)
+hrl_limit_add(struct hrl_limits_head *limits_head, struct hrl_rule *rule)
+{
+ struct hrl_limit *limit;
+
+ hrl_rule_acquire(rule);
+ limit = uma_zalloc(hrl_limit_zone, M_WAITOK);
+ limit->hl_rule = rule;
+
+ mtx_lock(&hrl_lock);
+ LIST_INSERT_HEAD(limits_head, limit, hl_next);
+ mtx_unlock(&hrl_lock);
+}
+
+#if 0
+static int
+hrl_limit_remove(struct hrl_limits_head *limits_head, struct hrl_rule *rule)
{
- struct hrl_limit *limit, *new_limit;
+ struct hrl_limit *limit, *limittmp;
- new_limit = uma_zalloc(hrl_limit_zone, M_WAITOK);
mtx_lock(&hrl_lock);
- LIST_FOREACH(limit, limits_head, hl_next) {
+ LIST_FOREACH_SAFE(limit, limits_head, hl_next, limittmp) {
if (limit->hl_rule == rule) {
+ LIST_REMOVE(limit, hl_next);
mtx_unlock(&hrl_lock);
- uma_zfree(hrl_limit_zone, new_limit);
- return;
+ uma_zfree(hrl_limit_zone, limit);
+ hrl_rule_release(rule);
+ return (1);
}
}
- new_limit->hl_rule = rule;
- LIST_INSERT_HEAD(limits_head, new_limit, hl_next);
mtx_unlock(&hrl_lock);
+ return (0);
}
+#endif
/*
- * Remove a limit for a rule.
+ * Remove limits for a rules matching the filter and release
+ * the refcounts for the rules, possibly freeing them. Returns
+ * the number of limit structures removed.
*/
-static void
-hrl_limit_remove(struct hrl_limits_head *limits_head, struct hrl_rule *rule)
+static int
+hrl_limit_remove_matching(struct hrl_limits_head *limits_head,
+ const struct hrl_rule *filter)
{
+ int removed = 0;
struct hrl_limit *limit, *limittmp;
+again:
mtx_lock(&hrl_lock);
LIST_FOREACH_SAFE(limit, limits_head, hl_next, limittmp) {
- if (limit->hl_rule == rule) {
+ if (hrl_rule_matches(limit->hl_rule, filter)) {
LIST_REMOVE(limit, hl_next);
mtx_unlock(&hrl_lock);
+ hrl_rule_release(limit->hl_rule);
uma_zfree(hrl_limit_zone, limit);
- return;
+ removed++;
+ goto again;
}
}
mtx_unlock(&hrl_lock);
+ return (removed);
}
-/*
- * Bind a rule to subjects to which it applies.
- */
-static void
-hrl_rule_add_limits(struct hrl_rule *rule)
+struct hrl_rule *
+hrl_rule_alloc(void)
{
- struct proc *p;
- struct uidinfo *uip;
- struct gidinfo *gip;
- struct prison *pr;
+ struct hrl_rule *rule;
- switch (rule->hr_subject) {
- case HRL_SUBJECT_PROCESS:
- /*
- * The sx lock is to keep the process from going away.
- */
- sx_slock(&proctree_lock);
- p = pfind(rule->hr_subject_id);
- if (p == NULL) {
- sx_sunlock(&proctree_lock);
- return;
- }
+ rule = uma_zalloc(hrl_rule_zone, M_WAITOK);
+ refcount_init(&rule->hr_refcount, 1);
+ return (rule);
+}
- PROC_UNLOCK(p);
- hrl_limit_add_if_needed(&p->p_limits, rule);
- sx_sunlock(&proctree_lock);
- return;
+void
+hrl_rule_acquire(struct hrl_rule *rule)
+{
- case HRL_SUBJECT_USER:
- uip = uifind_existing(rule->hr_subject_id);
- if (uip == NULL)
- return;
- hrl_limit_add_if_needed(&uip->ui_limits, rule);
- uifree(uip);
- return;
+ KASSERT(rule->hr_refcount > 0, ("rule->hr_refcount > 0"));
- case HRL_SUBJECT_GROUP:
- gip = gifind_existing(rule->hr_subject_id);
- if (gip == NULL)
- return;
- hrl_limit_add_if_needed(&gip->gi_limits, rule);
- gifree(gip);
- return;
+ refcount_acquire(&rule->hr_refcount);
+}
- case HRL_SUBJECT_LOGINCLASS:
- panic("hrl_rule_add_limits: HRL_SUBJECT_LOGINCLASS unimplemented");
- return;
+void
+hrl_rule_release(struct hrl_rule *rule)
+{
- case HRL_SUBJECT_JAIL:
- sx_xlock(&allprison_lock);
- pr = prison_find(rule->hr_subject_id);
- if (pr == NULL) {
- sx_xunlock(&allprison_lock);
- return;
- }
- hrl_limit_add_if_needed(&pr->pr_limits, rule);
- prison_free(pr);
- sx_xunlock(&allprison_lock);
- return;
+ KASSERT(rule->hr_refcount > 0, ("rule->hr_refcount > 0"));
- default:
- panic("hrl_rule_add_limits: unknown subject %d", rule->hr_subject);
- }
+ if (refcount_release(&rule->hr_refcount))
+ uma_zfree(hrl_rule_zone, rule);
}
-static void
-hrl_rule_remove_limits(struct hrl_rule *rule)
+/*
+ * Link a rule with subjects to which it applies.
+ */
+int
+hrl_rule_add(struct hrl_rule *rule)
{
struct proc *p;
+ struct ucred *cred;
struct uidinfo *uip;
struct gidinfo *gip;
struct prison *pr;
+ struct loginclass *lc;
+ /*
+ * Make sure there are no duplicated rules.
+ */
+ hrl_rule_remove(rule);
+
switch (rule->hr_subject) {
case HRL_SUBJECT_PROCESS:
/*
@@ -856,83 +784,142 @@
p = pfind(rule->hr_subject_id);
if (p == NULL) {
sx_sunlock(&proctree_lock);
- return;
+ return (ESRCH);
}
PROC_UNLOCK(p);
- hrl_limit_remove(&p->p_limits, rule);
+ hrl_limit_add(&p->p_limits, rule);
sx_sunlock(&proctree_lock);
- return;
+ /*
+ * In case of per-process rule, we don't have anything more
+ * to do.
+ */
+ return (0);
case HRL_SUBJECT_USER:
- uip = uifind_existing(rule->hr_subject_id);
- if (uip == NULL)
- return;
- hrl_limit_remove(&uip->ui_limits, rule);
- uifree(uip);
- return;
+ uip = uifind(rule->hr_subject_id);
+ KASSERT(uip == NULL, ("hrl_rule_add: uifind failed"));
+ hrl_limit_add(&uip->ui_limits, rule);
+ /*
+ * Don't call uifree(2); we don't want the uidinfo
+ * to go away, because the rule should stay there even
+ * if there are no processes with that uid. The same
+ * applies to the cases below.
+ */
+ break;
case HRL_SUBJECT_GROUP:
gip = gifind_existing(rule->hr_subject_id);
- if (gip == NULL)
- return;
- hrl_limit_remove(&gip->gi_limits, rule);
- gifree(gip);
- return;
+ KASSERT(gip == NULL, ("hrl_rule_add: gifind failed"));
+ hrl_limit_add(&gip->gi_limits, rule);
+ break;
case HRL_SUBJECT_LOGINCLASS:
- panic("hrl_rule_remove: HRL_SUBJECT_LOGINCLASS unimplemented");
- return;
+ KASSERT(rule->hr_subject_id > 0, ("rule->hr_subject_id > 0"));
+ lc = (struct loginclass *)(long)rule->hr_subject_id;
+ hrl_limit_add(&lc->lc_limits, rule);
+ break;
case HRL_SUBJECT_JAIL:
sx_xlock(&allprison_lock);
pr = prison_find(rule->hr_subject_id);
if (pr == NULL) {
sx_xunlock(&allprison_lock);
- return;
+ return (ESRCH);
}
- hrl_limit_remove(&pr->pr_limits, rule);
- prison_free(pr);
+ hrl_limit_add(&pr->pr_limits, rule);
sx_xunlock(&allprison_lock);
- return;
+ break;
default:
- panic("hrl_rule_remove: unknown subject %d", rule->hr_subject);
+ panic("hrl_rule_add_limits: unknown subject %d",
+ rule->hr_subject);
+ }
+
+ /*
+ * Now go through all the processes and add the new rule to the ones
+ * it applies to.
+ */
+ sx_slock(&proctree_lock);
+ FOREACH_PROC_IN_SYSTEM(p) {
+ cred = p->p_ucred;
+ switch (rule->hr_subject) {
+ case HRL_SUBJECT_USER:
+ if (cred->cr_uid == rule->hr_subject_id ||
+ cred->cr_ruid == rule->hr_subject_id)
+ break;
+ continue;
+ case HRL_SUBJECT_GROUP:
+ if (groupmember(rule->hr_subject_id, cred))
+ break;
+ continue;
+ case HRL_SUBJECT_LOGINCLASS:
+ lc = (struct loginclass *)(long)rule->hr_subject_id; /* XXX: This line is here to remove cc warning; investigate. */
+ if (p->p_loginclass == lc)
+ break;
+ continue;
+ case HRL_SUBJECT_JAIL:
+ for (pr = cred->cr_prison; pr != NULL; pr = pr->pr_parent)
+ if (pr->pr_id == rule->hr_subject_id)
+ break;
+ continue;
+ default:
+ panic("hrl_rule_add_limits: unknown subject %d",
+ rule->hr_subject);
+ }
+
+ hrl_limit_add(&p->p_limits, rule);
}
+ sx_sunlock(&proctree_lock);
+
+ return (0);
}
/*
- * Add a rule to the ruleset or change the 'hr_amount' of existing
- * rule.
+ * Remove all rules that match the filter.
*/
-static int
-hrl_rule_add(struct hrl_rule *rule)
+int
+hrl_rule_remove(const struct hrl_rule *filter)
{
- struct hrl_node *node, *existing;
+ int error, found = 0;
+ struct proc *p;
+
+ if (filter->hr_subject == HRL_SUBJECT_PROCESS &&
+ filter->hr_subject_id != HRL_SUBJECT_ID_UNDEFINED) {
+ sx_slock(&proctree_lock);
+ p = pfind(filter->hr_subject_id);
+ if (p == NULL)
+ return (ESRCH);
+ PROC_UNLOCK(p);
+ error = hrl_limit_remove_matching(&p->p_limits, filter);
+ sx_sunlock(&proctree_lock);
+ return (error);
+ }
- node = uma_zalloc(hrl_node_zone, M_WAITOK);
- node->hn_rule = *rule;
+ /*
+ * XXX: per-process, per-group, per-jail and per-class limits.
+ */
- mtx_lock(&hrl_lock);
- existing = RB_INSERT(hrl_tree, &hrls, node);
- if (existing != NULL)
- existing->hn_rule.hr_amount = rule->hr_amount;
- mtx_unlock(&hrl_lock);
+ sx_slock(&proctree_lock);
+ FOREACH_PROC_IN_SYSTEM(p) {
+ error = hrl_limit_remove_matching(&p->p_limits, filter);
+ if (error == 0)
+ found = 1;
+ }
+ sx_sunlock(&proctree_lock);
- if (existing != NULL)
- uma_zfree(hrl_node_zone, node);
+ if (found)
+ return (0);
else
- hrl_rule_add_limits(rule);
-
- return (0);
+ return (ESRCH);
}
-
static int
hrl_rule_parse(struct hrl_rule *rule, char *rulestr)
{
int error;
- char *subjectstr, *subject_idstr, *resourcestr, *actionstr, *amountstr, *perstr;
+ char *subjectstr, *subject_idstr, *resourcestr, *actionstr,
+ *amountstr, *perstr;
subjectstr = strsep(&rulestr, ":");
subject_idstr = strsep(&rulestr, ":");
@@ -950,7 +937,7 @@
}
if (subject_idstr == NULL || subject_idstr[0] == '\0')
- rule->hr_subject_id = -1;
+ rule->hr_subject_id = HRL_SUBJECT_ID_UNDEFINED;
else {
error = str2id(subject_idstr, &rule->hr_subject_id);
if (error)
@@ -960,7 +947,8 @@
if (resourcestr == NULL || resourcestr[0] == '\0')
rule->hr_resource = HRL_RESOURCE_UNDEFINED;
else {
- error = str2value(resourcestr, &rule->hr_resource, resourcenames);
+ error = str2value(resourcestr, &rule->hr_resource,
+ resourcenames);
if (error)
return (EINVAL);
}
@@ -989,7 +977,8 @@
return (EINVAL);
}
- if (rule->hr_subject_id > 0 && rule->hr_subject == HRL_SUBJECT_UNDEFINED)
+ if (rule->hr_subject_id != HRL_SUBJECT_ID_UNDEFINED &&
+ rule->hr_subject == HRL_SUBJECT_UNDEFINED)
return (EINVAL);
return (0);
@@ -1021,105 +1010,6 @@
}
/*
- * XXX: We should sort the rules somewhat, so that 'log' rules are enforced
- * before 'deny', if both are for the same subject, resource and amount.
- */
-static void
-_hrl_compute_available(struct hrl_limits_head *limits_head,
- struct hrl_usage *usage, int64_t (*availablep)[],
- struct hrl_rule *(*rulesp)[])
-{
- int resource;
- int64_t available;
- struct hrl_limit *limit;
-
- mtx_assert(&hrl_lock, MA_OWNED);
-
- LIST_FOREACH(limit, limits_head, hl_next) {
- resource = limit->hl_rule->hr_resource;
- available = limit->hl_rule->hr_amount -
- usage->hu_resources[resource];
- /* Skip limits that have been already exceeded. */
- if (available < 0)
- continue;
- if (available < (*availablep)[resource]) {
- (*availablep)[resource] = available;
- (*rulesp)[resource] = limit->hl_rule;
- }
- }
-}
-
-/*
- * Go through all the rules applicable to the process, fill first array
- * with amount of resource left before hitting next limit, and the second
- * with pointers to the limit to be hit.
- */
-static void
-hrl_compute_available(struct proc *p, int64_t (*availablep)[],
- struct hrl_rule *(*rulesp)[])
-{
- int i;
- struct ucred *cred;
- struct uidinfo *ui, *rui;
- struct prison *pr;
-
- mtx_assert(&hrl_lock, MA_OWNED);
-
- for (i = 0; i < HRL_RESOURCE_MAX; i++) {
- (*availablep)[i] = INT64_MAX;
- (*rulesp)[i] = NULL;
- }
-
- cred = p->p_ucred;
- ui = cred->cr_uidinfo;
- rui = cred->cr_ruidinfo;
- pr = cred->cr_prison;
- _hrl_compute_available(&p->p_limits, &p->p_usage, availablep, rulesp);
- _hrl_compute_available(&ui->ui_limits, &ui->ui_usage, availablep, rulesp);
- _hrl_compute_available(&rui->ui_limits, &rui->ui_usage, availablep,
- rulesp);
- if (hrl_group_accounting) {
- /*
- * XXX: Groups.
- */
- }
- _hrl_compute_available(&pr->pr_limits, &pr->pr_usage, availablep,
- rulesp);
-}
-
-/*
- * Remove a rule from the ruleset.
- */
-static int
-hrl_rule_remove(struct hrl_rule *rule)
-{
- int found = 1;
- struct hrl_node *node, *next;
-
-restart:
- mtx_lock(&hrl_lock);
- for (node = RB_MIN(hrl_tree, &hrls); node != NULL; node = next) {
- next = RB_NEXT(hrl_tree, &hrls, node);
- if (!hrl_rule_matches(&node->hn_rule, rule))
- continue;
- found = 1;
- node = RB_REMOVE(hrl_tree, &hrls, node);
- KASSERT(node != NULL, ("hrl_rule_remove: node removal failed"));
-
- mtx_unlock(&hrl_lock);
- hrl_rule_remove_limits(&node->hn_rule);
- uma_zfree(hrl_node_zone, node);
- goto restart;
- }
- mtx_unlock(&hrl_lock);
-
- if (found == 0)
- return (ENOENT);
-
- return (0);
-}
-
-/*
* Routine used by HRL syscalls to read in input string.
*/
static int
@@ -1159,7 +1049,8 @@
sbuf_delete(outputsbuf);
return (ERANGE);
}
- error = copyout(sbuf_data(outputsbuf), outbufp, sbuf_len(outputsbuf) + 1);
+ error = copyout(sbuf_data(outputsbuf), outbufp,
+ sbuf_len(outputsbuf) + 1);
sbuf_delete(outputsbuf);
return (error);
}
@@ -1280,91 +1171,141 @@
return (EINVAL);
}
+ if (error)
+ return (error);
+
error = hrl_write_outbuf(outputsbuf, uap->outbufp, uap->outbuflen);
return (error);
}
-static int
-hrl_get_rules_2(struct thread *td, char *inputstr, struct sbuf **outputsbuf)
+int
+hrl_get_rules(struct thread *td, struct hrl_get_rules_args *uap)
{
- int error = 0, copied = 0;
- struct hrl_rule *buf, filter;
- struct hrl_node *node;
+ int error, copied, maxcopied = HRL_MAX_RULES;
+ char *inputstr;
+ struct sbuf *outputsbuf;
+ struct hrl_rule filter, *buf;
+ struct hrl_limit *limit;
+ struct proc *p;
+
+ error = hrl_read_inbuf(&inputstr, uap->inbufp, uap->inbuflen);
+ if (error)
+ return (error);
error = hrl_rule_parse(&filter, inputstr);
+ free(inputstr, M_HRL);
if (error)
return (error);
buf = malloc(HRL_MAX_RULES * sizeof(struct hrl_rule), M_HRL, M_WAITOK);
- /*
- * Copy the limits to the temporary buffer. We cannot
- * copy it directly to the userland because of the mutex.
- */
- mtx_lock(&hrl_lock);
- RB_FOREACH(node, hrl_tree, &hrls) {
- /*
- * XXX: Do not show everything to the client; just the
- * nodes that affect him.
- */
- if (copied >= HRL_MAX_RULES) {
- /*
- * XXX: Hey, what to do now?
- */
- error = EDOOFUS;
- break;
+again:
+ buf = malloc(maxcopied * sizeof(*buf), M_HRL, M_WAITOK);
+ copied = 0;
+ sx_slock(&proctree_lock);
+ FOREACH_PROC_IN_SYSTEM(p) {
+ mtx_lock(&hrl_lock);
+ LIST_FOREACH(limit, &p->p_limits, hl_next) {
+ if (copied >= HRL_MAX_RULES) {
+ mtx_unlock(&hrl_lock);
+ sx_sunlock(&proctree_lock);
+ maxcopied *= 4;
+ free(buf, M_HRL);
+ goto again;
+ }
+ if (!hrl_rule_matches(limit->hl_rule, &filter))
+ continue;
+ *(buf + copied) = *limit->hl_rule;
+ copied++;
}
-
- if (!hrl_rule_matches(&node->hn_rule, &filter))
- continue;
-
- *(buf + copied) = node->hn_rule;
- copied++;
+ mtx_unlock(&hrl_lock);
}
- mtx_unlock(&hrl_lock);
+ sx_sunlock(&proctree_lock);
if (error)
goto out;
- *outputsbuf = hrl_rules_to_sbuf(buf, copied);
+ /*
+ * XXX: Iterate over the rest (other than per-process) of the rules.
+ */
+
+ outputsbuf = hrl_rules_to_sbuf(buf, copied);
+
+ error = hrl_write_outbuf(outputsbuf, uap->outbufp, uap->outbuflen);
out:
free(buf, M_HRL);
-
return (error);
}
-
int
-hrl_get_rules(struct thread *td, struct hrl_get_rules_args *uap)
+hrl_get_limits(struct thread *td, struct hrl_get_limits_args *uap)
{
- int error;
+ int error, copied, maxcopied = HRL_MAX_RULES;
char *inputstr;
struct sbuf *outputsbuf;
+ struct hrl_rule filter, *buf;
+ struct hrl_limit *limit;
+ struct proc *p;
error = hrl_read_inbuf(&inputstr, uap->inbufp, uap->inbuflen);
if (error)
return (error);
- error = hrl_get_rules_2(td, inputstr, &outputsbuf);
+ error = hrl_rule_parse(&filter, inputstr);
free(inputstr, M_HRL);
if (error)
return (error);
+ if (filter.hr_subject == HRL_SUBJECT_UNDEFINED)
+ return (EINVAL);
+
+ if (filter.hr_subject_id == HRL_SUBJECT_ID_UNDEFINED)
+ return (EINVAL);
+
+ if (filter.hr_subject != HRL_SUBJECT_PROCESS)
+ return (EOPNOTSUPP);
+
+again:
+ buf = malloc(maxcopied * sizeof(*buf), M_HRL, M_WAITOK);
+ copied = 0;
+
+ p = pfind(filter.hr_subject_id);
+ if (p == NULL) {
+ error = ESRCH;
+ goto out;
+ }
+ mtx_lock(&hrl_lock);
+ LIST_FOREACH(limit, &p->p_limits, hl_next) {
+ if (copied >= HRL_MAX_RULES) {
+ mtx_unlock(&hrl_lock);
+ PROC_UNLOCK(p);
+ maxcopied *= 4;
+ free(buf, M_HRL);
+ goto again;
+ }
+ if (!hrl_rule_matches(limit->hl_rule, &filter))
+ continue;
+ *(buf + copied) = *limit->hl_rule;
+ copied++;
+ }
+ mtx_unlock(&hrl_lock);
+ PROC_UNLOCK(p);
+ if (error)
+ goto out;
+
+ outputsbuf = hrl_rules_to_sbuf(buf, copied);
+
error = hrl_write_outbuf(outputsbuf, uap->outbufp, uap->outbuflen);
+out:
+ free(buf, M_HRL);
return (error);
}
int
-hrl_get_limits(struct thread *td, struct hrl_get_limits_args *uap)
-{
- return (EDOOFUS);
-}
-
-int
hrl_add_rule(struct thread *td, struct hrl_add_rule_args *uap)
{
int error;
- struct hrl_rule rule;
+ struct hrl_rule *rule;
char *inputstr;
error = priv_check(td, PRIV_HRL_SET);
@@ -1375,20 +1316,36 @@
if (error)
return (error);
- error = hrl_rule_parse(&rule, inputstr);
+ rule = hrl_rule_alloc();
+
+ error = hrl_rule_parse(rule, inputstr);
free(inputstr, M_HRL);
if (error)
- return (error);
>>> TRUNCATED FOR MAIL (1000 lines) <<<
More information about the p4-projects
mailing list