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