PERFORCE change 166013 for review
Edward Tomasz Napierala
trasz at FreeBSD.org
Mon Jul 13 16:05:43 UTC 2009
http://perforce.freebsd.org/chv.cgi?CH=166013
Change 166013 by trasz at trasz_victim on 2009/07/13 16:05:40
Add basic resource limit enforcement.
Affected files ...
.. //depot/projects/soc2009/trasz_limits/sys/kern/kern_hrl.c#29 edit
Differences ...
==== //depot/projects/soc2009/trasz_limits/sys/kern/kern_hrl.c#29 (text+ko) ====
@@ -33,6 +33,7 @@
#include <sys/queue.h>
#include <sys/jail.h>
#include <sys/kernel.h>
+#include <sys/limits.h>
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/resourcevar.h>
@@ -154,6 +155,8 @@
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)[]);
MALLOC_DEFINE(M_HRL, "hrl", "Hierarchical Resource Limits");
@@ -200,7 +203,7 @@
int i;
/*
- * XXX: Free these two some other way.
+ * XXX: Free these three some other way.
*/
hrl_allocated_proc(p, HRL_RESOURCE_FILESIZE, 0);
hrl_allocated_proc(p, HRL_RESOURCE_COREDUMPSIZE, 0);
@@ -296,6 +299,8 @@
int i, j;
struct ucred *cred;
struct prison *pr;
+ int64_t available[HRL_RESOURCE_MAX];
+ struct hrl_rule *rules[HRL_RESOURCE_MAX];
KASSERT(amount > 0, ("hrl_alloc_proc: invalid amount for %s: %lld",
hrl_resource_name(resource), amount));
@@ -305,6 +310,21 @@
#endif
mtx_lock(&hrl_lock);
+ /*
+ * XXX: Check maxfilesperproc.
+ */
+ /*
+ * XXX: Do this just before we start running on a CPU, not all the time.
+ */
+ hrl_compute_available(p, &available, &rules);
+ /*
+ * Return fake error code; the caller should change it into proper
+ * one for the situation - EFSIZ, ENOMEM, EMFILE etc.
+ */
+ if (available[resource] < 0 && rules[resource]->hr_action == HRL_ACTION_DENY) {
+ mtx_unlock(&hrl_lock);
+ return (EDOOFUS);
+ }
p->p_usage.hu_resources[resource] += amount;
cred = p->p_ucred;
cred->cr_ruidinfo->ui_usage.hu_resources[resource] += amount;
@@ -335,14 +355,6 @@
#endif
mtx_unlock(&hrl_lock);
- /*
- * XXX: When denying, return proper errno - EFSIZ, ENOMEM, EMFILE etc.
- */
-
- /*
- * Check maxfilesperproc.
- */
-
return (0);
}
@@ -360,6 +372,8 @@
int64_t diff;
struct ucred *cred;
struct prison *pr;
+ int64_t available[HRL_RESOURCE_MAX];
+ struct hrl_rule *rules[HRL_RESOURCE_MAX];
KASSERT(amount >= 0, ("hrl_allocated_proc: invalid amount for %s: %lld",
hrl_resource_name(resource), amount));
@@ -370,6 +384,20 @@
mtx_lock(&hrl_lock);
diff = amount - p->p_usage.hu_resources[resource];
+ if (diff > 0) {
+ /*
+ * XXX: Do this just before we start running on a CPU, not all the time.
+ */
+ hrl_compute_available(p, &available, &rules);
+ /*
+ * Return fake error code; the caller should change it into proper
+ * one for the situation - EFSIZ, ENOMEM, EMFILE etc.
+ */
+ if (available[resource] < 0 && rules[resource]->hr_action == HRL_ACTION_DENY) {
+ mtx_unlock(&hrl_lock);
+ return (EDOOFUS);
+ }
+ }
p->p_usage.hu_resources[resource] = amount;
cred = p->p_ucred;
cred->cr_ruidinfo->ui_usage.hu_resources[resource] += diff;
@@ -985,22 +1013,88 @@
return (error);
}
+/*
+ * 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] = INT_MAX; /* XXX: It's int64_t, not int. */
+ (*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);
+}
+
static int
hrl_get_rules_pid(struct thread *td, char *inputstr, struct sbuf **outputsbuf)
{
- int error = 0, copied = 0;
+ int error = 0, copied = 0, i;
id_t pid;
struct proc *p;
- struct ucred *cred;
struct hrl_rule *buf;
- struct hrl_limit *limit;
- struct prison *pr;
+ int64_t available[HRL_RESOURCE_MAX];
+ struct hrl_rule *rules[HRL_RESOURCE_MAX];
error = str2id(inputstr, &pid);
if (error)
return (error);
- buf = malloc(HRL_MAX_RULES * sizeof(struct hrl_rule), M_HRL, M_WAITOK);
+ buf = malloc(HRL_RESOURCE_MAX * sizeof(struct hrl_rule), M_HRL, M_WAITOK);
if ((p = pfind(pid)) == NULL) {
if ((p = zpfind(pid)) == NULL) {
@@ -1009,72 +1103,19 @@
}
}
- cred = p->p_ucred;
- pr = cred->cr_prison;
+ mtx_lock(&hrl_lock);
+ hrl_compute_available(p, &available, &rules);
/*
* Copy the limits to the temporary buffer. We cannot
* copy it directly to the userland because of the mutex.
*/
- mtx_lock(&hrl_lock);
- LIST_FOREACH(limit, &p->p_limits, hl_next) {
- if (copied >= HRL_MAX_RULES) {
- /*
- * XXX: Hey, what to do now?
- */
- error = EDOOFUS;
- break;
- }
-
- *(buf + copied) = *(limit->hl_rule);
+ for (i = 0; i < HRL_RESOURCE_MAX; i++) {
+ *(buf + copied) = *(rules[i]);
copied++;
}
- LIST_FOREACH(limit, &cred->cr_uidinfo->ui_limits, hl_next) {
- if (copied >= HRL_MAX_RULES) {
- /*
- * XXX: Hey, what to do now?
- */
- error = EDOOFUS;
- break;
- }
-
- *(buf + copied) = *(limit->hl_rule);
- copied++;
- }
- if (cred->cr_uidinfo != cred->cr_ruidinfo) {
- LIST_FOREACH(limit, &cred->cr_ruidinfo->ui_limits, hl_next) {
- if (copied >= HRL_MAX_RULES) {
- /*
- * XXX: Hey, what to do now?
- */
- error = EDOOFUS;
- break;
- }
-
- *(buf + copied) = *(limit->hl_rule);
- copied++;
- }
- }
-
- /*
- * XXX: Groups.
- */
+ mtx_unlock(&hrl_lock);
- for (pr = cred->cr_prison; pr != NULL; pr = pr->pr_parent) {
- LIST_FOREACH(limit, &pr->pr_limits, hl_next) {
- if (copied >= HRL_MAX_RULES) {
- /*
- * XXX: Hey, what to do now?
- */
- error = EDOOFUS;
- break;
- }
-
- *(buf + copied) = *(limit->hl_rule);
- copied++;
- }
- }
- mtx_unlock(&hrl_lock);
PROC_UNLOCK(p);
if (error)
goto out;
More information about the p4-projects
mailing list