Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 27 Jun 2009 21:22:54 GMT
From:      Edward Tomasz Napierala <trasz@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 165329 for review
Message-ID:  <200906272122.n5RLMsHc095521@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=165329

Change 165329 by trasz@trasz_victim on 2009/06/27 21:22:43

	Extend rule parsing and matching a little, so one can do something
	like this:
	
	[root@victim:~]# hrl ::openfiles
	Defined resource limits matching "::openfiles":
	process:926:openfiles:deny=7149
	process:926:openfiles:sigxfsz=7149
	process:927:openfiles:deny=7149
	process:927:openfiles:sigxfsz=7149
	process:928:openfiles:deny=7149
	process:928:openfiles:sigxfsz=7149
	process:929:openfiles:deny=7149
	process:929:openfiles:sigxfsz=7149
	[root@victim:~]# hrl -r ::openfiles
	[root@victim:~]# hrl ::openfiles
	Defined resource limits matching "::openfiles":
	No resource limits defined.

Affected files ...

.. //depot/projects/soc2009/trasz_limits/sys/kern/kern_hrl.c#17 edit
.. //depot/projects/soc2009/trasz_limits/sys/sys/hrl.h#12 edit
.. //depot/projects/soc2009/trasz_limits/usr.sbin/hrl/hrl.c#10 edit

Differences ...

==== //depot/projects/soc2009/trasz_limits/sys/kern/kern_hrl.c#17 (text+ko) ====

@@ -188,18 +188,19 @@
 
 	mtx_lock(&hrl_lock);
 	for (i = 0; i < HRL_RESOURCE_MAX; i++) {
-		if (p->p_accounting.ha_resources[i] != 0)
+		if (p->p_accounting.ha_resources[i] != 0) {
 #if 0
 			KASSERT(p->p_accounting.ha_resources == 0,
 			    ("dead process still holding resources"));
-#else
 			printf("hrl_proc_exiting: %s = %lld\n",
 			    hrl_resource_name(i),
 			    p->p_accounting.ha_resources[i]);
+#else
 			if (p->p_accounting.ha_resources[i] > 0)
 				hrl_free_proc(p, i, p->p_accounting.ha_resources[i]);
 			else
 			    p->p_accounting.ha_resources[i] = 0;
+		}
 #endif
 	}
 	mtx_unlock(&hrl_lock);
@@ -501,51 +502,39 @@
 }
 
 static int
-hrl_get_rules(struct thread *td, void *bufp, size_t buflen)
+hrl_rule_matches(const struct hrl_rule *rule, const struct hrl_rule *filter)
 {
-	int error = 0, copied = 0;
-	struct hrl_rule *buf;
-	struct hrl_node *node;
+	if (filter->hr_subject != HRL_SUBJECT_UNDEFINED) {
+		if (rule->hr_subject != filter->hr_subject)
+			return (0);
+	}
 
-	if (buflen > HRL_MAX_LIMITS * sizeof(struct hrl_rule))
-		return (EINVAL);
+	if (filter->hr_subject_id >= 0) {
+		if (rule->hr_subject_id != filter->hr_subject_id)
+			return (0);
+	}
 
-	buf = malloc(buflen, M_HRL, M_WAITOK);
+	if (filter->hr_resource != HRL_RESOURCE_UNDEFINED) {
+		if (rule->hr_resource != filter->hr_resource)
+			return (0);
+	}
 
-	/*
-	 * 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.
-		 */
-		/* +1 to make room for the terminating NULL entry. */
-		if ((copied + 1) * sizeof(*buf) >= buflen) {
-			error = EFBIG;
-			break;
-		}
-		*(buf + copied) = node->hn_rule;
-		copied++;
+	if (filter->hr_action != HRL_ACTION_UNDEFINED) {
+		if (rule->hr_action != filter->hr_action)
+			return (0);
 	}
-	mtx_unlock(&hrl_lock);
-	if (error)
-		goto out;
 
-	/* Add terminating NULL entry. */
-	bzero(buf + copied, sizeof(*buf));
-	copied++;
+	if (filter->hr_amount >= 0) {
+		if (rule->hr_amount != filter->hr_amount)
+			return (0);
+	}
 
-	error = copyout(buf, bufp, sizeof(struct hrl_rule) * copied);
-	if (error)
-		goto out;
+	if (filter->hr_per != HRL_SUBJECT_UNDEFINED) {
+		if (rule->hr_per != filter->hr_per)
+			return (0);
+	}
 
-out:
-	free(buf, M_HRL);
-	
-	return (error);
+	return (1);
 }
 
 static int
@@ -556,8 +545,6 @@
 	if (value == NULL)
 		return (EINVAL);
 
-	printf("str2value: '%s'\n", str);
-
 	for (i = 0; table[i].d_name != NULL; i++) {
 		if (strcasecmp(table[i].d_name, str) == 0) {
 			*value =  table[i].d_value;
@@ -576,8 +563,6 @@
 	if (str == NULL)
 		return (EINVAL);
 
-	printf("str2id: '%s'\n", str);
-
 	*value = strtoul(str, &end, 10);
 	if ((size_t)(end - str) != strlen(str))
 		return (EINVAL);
@@ -593,8 +578,6 @@
 	if (str == NULL)
 		return (EINVAL);
 
-	printf("str2int64: '%s'\n", str);
-
 	*value = strtoul(str, &end, 10);
 	if ((size_t)(end - str) != strlen(str))
 		return (EINVAL);
@@ -603,6 +586,27 @@
 }
 
 static int
+hrl_rule_add(struct hrl_rule *rule)
+{
+	struct hrl_node *node, *existing;
+
+	node = uma_zalloc(hrl_zone, M_WAITOK);
+	node->hn_rule = *rule;
+
+	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);
+
+	if (existing != NULL)
+		uma_zfree(hrl_zone, node);
+
+	return (0);
+}
+
+
+static int
 hrl_rule_parse(struct hrl_rule *rule, char *rulestr)
 {
 	int error;
@@ -611,53 +615,122 @@
 	subjectstr = strsep(&rulestr, ":");
 	subject_idstr = strsep(&rulestr, ":");
 	resourcestr = strsep(&rulestr, ":");
-	actionstr = strsep(&rulestr, "=");
+	actionstr = strsep(&rulestr, "=/");
 	amountstr = strsep(&rulestr, "/");
 	perstr = rulestr;
 
-	error = str2value(subjectstr, &rule->hr_subject, subjectnames);
-	if (error)
-		return (EINVAL);
-	error = str2id(subject_idstr, &rule->hr_subject_id);
-	if (error)
-		return (EINVAL);
-	error = str2value(resourcestr, &rule->hr_resource, resourcenames);
-	if (error)
-		return (EINVAL);
-	error = str2value(actionstr, &rule->hr_action, actionnames);
-	if (error)
-		return (EINVAL);
-	error = str2int64(amountstr, &rule->hr_amount);
-	if (error)
-		return (EINVAL);
-	if (perstr != NULL && perstr[0] != '\0') {
+	if (subjectstr == NULL || subjectstr[0] == '\0')
+		rule->hr_subject = HRL_SUBJECT_UNDEFINED;
+	else {
+		error = str2value(subjectstr, &rule->hr_subject, subjectnames);
+		if (error)
+			return (EINVAL);
+	}
+
+	if (subject_idstr == NULL || subject_idstr[0] == '\0')
+		rule->hr_subject_id = -1;
+	else {
+		error = str2id(subject_idstr, &rule->hr_subject_id);
+		if (error)
+			return (EINVAL);
+	}
+
+	if (resourcestr == NULL || resourcestr[0] == '\0')
+		rule->hr_resource = HRL_RESOURCE_UNDEFINED;
+	else {
+		error = str2value(resourcestr, &rule->hr_resource, resourcenames);
+		if (error)
+			return (EINVAL);
+	}
+
+	if (actionstr == NULL || actionstr[0] == '\0')
+		rule->hr_action = HRL_ACTION_UNDEFINED;
+	else {
+		error = str2value(actionstr, &rule->hr_action, actionnames);
+		if (error)
+			return (EINVAL);
+	}
+
+	if (amountstr == NULL || amountstr[0] == '\0')
+		rule->hr_amount = -1;
+	else {
+		error = str2int64(amountstr, &rule->hr_amount);
+		if (error)
+			return (EINVAL);
+	}
+
+	if (perstr == NULL || perstr[0] == '\0')
+		rule->hr_per = rule->hr_subject;
+	else {
 		error = str2value(perstr, &rule->hr_per, subjectnames);
 		if (error)
 			return (EINVAL);
-	} else
-		rule->hr_per = rule->hr_subject;
+	}
+
+	if (rule->hr_subject_id > 0 && rule->hr_subject == HRL_SUBJECT_UNDEFINED)
+		return (EINVAL);
 
 	return (0);
 }
 
 static int
-hrl_rule_add(struct hrl_rule *rule)
+hrl_get_rules(struct thread *td, char *inputstr, void *bufp, size_t buflen)
 {
-	struct hrl_node *node, *existing;
+	int error = 0, copied = 0;
+	struct hrl_rule *buf, filter;
+	struct hrl_node *node;
+
+	if (buflen > HRL_MAX_LIMITS * sizeof(struct hrl_rule))
+		return (EINVAL);
+
+	if (inputstr != NULL) {
+		error = hrl_rule_parse(&filter, inputstr);
+		if (error)
+			return (error);
+	}
 
-	node = uma_zalloc(hrl_zone, M_WAITOK);
-	node->hn_rule = *rule;
+	buf = malloc(buflen, 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);
-	existing = RB_INSERT(hrl_tree, &hrls, node);
-	if (existing != NULL)
-		existing->hn_rule.hr_amount = rule->hr_amount;
+	RB_FOREACH(node, hrl_tree, &hrls) {
+		/*
+		 * XXX: Do not show everything to the client; just the
+		 *      nodes that affect him.
+		 */
+		/* +1 to make room for the terminating NULL entry. */
+		if ((copied + 1) * sizeof(*buf) >= buflen) {
+			error = EFBIG;
+			break;
+		}
+
+		if (inputstr != NULL) {
+			if (!hrl_rule_matches(&node->hn_rule, &filter))
+				continue;
+		}
+
+		*(buf + copied) = node->hn_rule;
+		copied++;
+	}
 	mtx_unlock(&hrl_lock);
+	if (error)
+		goto out;
+
+	/* Add terminating NULL entry. */
+	bzero(buf + copied, sizeof(*buf));
+	copied++;
 
-	if (existing != NULL)
-		uma_zfree(hrl_zone, node);
+	error = copyout(buf, bufp, sizeof(struct hrl_rule) * copied);
+	if (error)
+		goto out;
 
-	return (0);
+out:
+	free(buf, M_HRL);
+	
+	return (error);
 }
 
 static int
@@ -670,6 +743,12 @@
 	if (error)
 		return (error);
 	error = hrl_rule_parse(&rule, inputstr);
+	if (rule.hr_subject == HRL_SUBJECT_UNDEFINED ||
+	    rule.hr_subject_id <= 0 ||
+	    rule.hr_resource == HRL_RESOURCE_UNDEFINED ||
+	    rule.hr_action == HRL_ACTION_UNDEFINED ||
+	    rule.hr_amount < 0)
+		return (EINVAL);
 	if (error)
 		return (error);
 	error = hrl_rule_add(&rule);
@@ -679,21 +758,26 @@
 static int
 hrl_rule_remove(struct hrl_rule *rule)
 {
-	struct hrl_node searched, *node;
+	int found = 1;
+	struct hrl_node *node, *next;
 
-	searched.hn_rule = *rule;
-
+restart:
 	mtx_lock(&hrl_lock);
-	node = RB_FIND(hrl_tree, &hrls, &searched);
-	if (node != NULL) {
+	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_adjust: node removal failed"));
+		KASSERT(node != NULL, ("hrl_proc_exit: node removal failed"));
+
+		mtx_unlock(&hrl_lock);
+		uma_zfree(hrl_zone, node);
+		goto restart;
 	}
 	mtx_unlock(&hrl_lock);
 
-	if (node != NULL)
-		uma_zfree(hrl_zone, node);
-	else
+	if (found == 0)
 		return (ENOENT);
 
 	return (0);
@@ -815,7 +899,7 @@
 
 	switch (uap->op) {
 	case HRL_OP_GET_RULES:
-		error = hrl_get_rules(td, uap->outbufp, uap->outbuflen);
+		error = hrl_get_rules(td, inputstr, uap->outbufp, uap->outbuflen);
 		break;
 	case HRL_OP_ADD_RULE:
 		error = hrl_add_rule(td, inputstr);

==== //depot/projects/soc2009/trasz_limits/sys/sys/hrl.h#12 (text+ko) ====

@@ -54,51 +54,54 @@
 	int64_t	hr_amount;
 };
 
-#define	HRL_SUBJECT_PROCESS	0x0001
-#define	HRL_SUBJECT_USER	0x0002
-#define	HRL_SUBJECT_GROUP	0x0003
-#define	HRL_SUBJECT_LOGINCLASS	0x0004
-#define	HRL_SUBJECT_JAIL	0x0005
-#define	HRL_SUBJECT_MAX		HRL_SUBJECT_JAIL
+#define	HRL_SUBJECT_UNDEFINED		0x0000
+#define	HRL_SUBJECT_PROCESS		0x0001
+#define	HRL_SUBJECT_USER		0x0002
+#define	HRL_SUBJECT_GROUP		0x0003
+#define	HRL_SUBJECT_LOGINCLASS		0x0004
+#define	HRL_SUBJECT_JAIL		0x0005
+#define	HRL_SUBJECT_MAX			HRL_SUBJECT_JAIL
 
 /*
  * 'hr_per' takes the same flags as 'hr_subject'.
  */
 
-#define	HRL_RESOURCE_CPUTIME	0x0001
-#define	HRL_RESOURCE_FILESIZE	0x0002
-#define	HRL_RESOURCE_DATASIZE	0x0003
-#define	HRL_RESOURCE_STACKSIZE	0x0004
+#define	HRL_RESOURCE_UNDEFINED		0x0000
+#define	HRL_RESOURCE_CPUTIME		0x0001
+#define	HRL_RESOURCE_FILESIZE		0x0002
+#define	HRL_RESOURCE_DATASIZE		0x0003
+#define	HRL_RESOURCE_STACKSIZE		0x0004
 #define	HRL_RESOURCE_COREDUMPSIZE	0x0005
-#define	HRL_RESOURCE_MEMORYUSE	0x0006
+#define	HRL_RESOURCE_MEMORYUSE		0x0006
 #define	HRL_RESOURCE_MEMORYLOCKED	0x0007
 #define	HRL_RESOURCE_MAXPROCESSES	0x0008
-#define	HRL_RESOURCE_OPENFILES	0x0009
-#define	HRL_RESOURCE_SBSIZE	0x000a
-#define	HRL_RESOURCE_VMEMORYUSE	0x000b
+#define	HRL_RESOURCE_OPENFILES		0x0009
+#define	HRL_RESOURCE_SBSIZE		0x000a
+#define	HRL_RESOURCE_VMEMORYUSE		0x000b
 #define	HRL_RESOURCE_PTY		0x000c
 #define	HRL_RESOURCE_MAX		HRL_RESOURCE_PTY
 
-#define	HRL_ACTION_DENY		0x0001
-#define	HRL_ACTION_DELAY	0x0002
-#define	HRL_ACTION_LOG		0x0003
-#define	HRL_ACTION_SIGHUP	0x0004
-#define	HRL_ACTION_SIGINT	0x0005
-#define	HRL_ACTION_SIGKILL	0x0006
-#define	HRL_ACTION_SIGSEGV	0x0007
-#define	HRL_ACTION_SIGXCPU	0x0008
-#define	HRL_ACTION_SIGXFSZ	0x0009
-#define	HRL_ACTION_MAX		HRL_ACTION_SIGXFSZ
+#define	HRL_ACTION_UNDEFINED		0x0000
+#define	HRL_ACTION_DENY			0x0001
+#define	HRL_ACTION_DELAY		0x0002
+#define	HRL_ACTION_LOG			0x0003
+#define	HRL_ACTION_SIGHUP		0x0004
+#define	HRL_ACTION_SIGINT		0x0005
+#define	HRL_ACTION_SIGKILL		0x0006
+#define	HRL_ACTION_SIGSEGV		0x0007
+#define	HRL_ACTION_SIGXCPU		0x0008
+#define	HRL_ACTION_SIGXFSZ		0x0009
+#define	HRL_ACTION_MAX			HRL_ACTION_SIGXFSZ
 
-#define	HRL_MAX_LIMITS		1024
+#define	HRL_MAX_LIMITS			1024
 
-#define	HRL_OP_GET_RULES	1
-#define	HRL_OP_ADD_RULE		6
-#define	HRL_OP_REMOVE_RULE	7
-#define	HRL_OP_GET_ACC_PID	2
-#define	HRL_OP_GET_ACC_UID	3
-#define	HRL_OP_GET_ACC_GID	4
-#define	HRL_OP_GET_ACC_JAILID	5
+#define	HRL_OP_GET_RULES		1
+#define	HRL_OP_ADD_RULE			6
+#define	HRL_OP_REMOVE_RULE		7
+#define	HRL_OP_GET_ACC_PID		2
+#define	HRL_OP_GET_ACC_UID		3
+#define	HRL_OP_GET_ACC_GID		4
+#define	HRL_OP_GET_ACC_JAILID		5
 
 /*
  * 'hrl_acc' defines resource consumption for a particular

==== //depot/projects/soc2009/trasz_limits/usr.sbin/hrl/hrl.c#10 (text+ko) ====

@@ -241,7 +241,7 @@
 }
 
 static void
-print_rules(void)
+print_rules(char *filter)
 {
 	int error;
 	size_t ruleslen, i;
@@ -254,12 +254,18 @@
 		if (rules == NULL)
 			err(1, "realloc");
 
-		error = hrl(HRL_OP_GET_RULES, NULL, 0, rules, ruleslen);
+		if (filter != NULL)
+			error = hrl(HRL_OP_GET_RULES, filter, strlen(filter) + 1, rules, ruleslen);
+		else
+			error = hrl(HRL_OP_GET_RULES, NULL, 0, rules, ruleslen);
 		if (error && errno != EFBIG)
 			err(1, "hrl");
 	} while (error && errno == EFBIG);
 
-	printf("Defined resource limits:\n");
+	if (filter != NULL)
+		printf("Defined resource limits matching \"%s\":\n", filter);
+	else
+		printf("Defined resource limits:\n");
 
 	if (rules[0].hr_subject == 0) {
 		printf("No resource limits defined.\n");
@@ -358,7 +364,7 @@
 usage(void)
 {
 
-	fprintf(stderr, "usage: hrl [-a rule | -r rule | -u user | -g group | -p pid | -j jailid]\n");
+	fprintf(stderr, "usage: hrl [-a rule | -r rule | -u user | -g group | -p pid | -j jailid] [rule]\n");
 	exit(1);
 }
 
@@ -409,13 +415,22 @@
 		}
 	}
 
+	argc -= optind;
+	argv += optind;
+
+	if (argc > 1)
+		usage();
+
+	if (argc == 1)
+		rule = strdup(argv[0]);
+
 	if (aflag + gflag + jflag + pflag + rflag + uflag > 1)
 		errx(1, "only one flag may be specified "
 		    "at the same time");
 
 	switch (op) {
 	case HRL_OP_GET_RULES:
-		print_rules();
+		print_rules(rule);
 		break;
 
 	case HRL_OP_GET_ACC_PID:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200906272122.n5RLMsHc095521>