PERFORCE change 165329 for review
Edward Tomasz Napierala
trasz at FreeBSD.org
Sat Jun 27 21:22:55 UTC 2009
http://perforce.freebsd.org/chv.cgi?CH=165329
Change 165329 by trasz at trasz_victim on 2009/06/27 21:22:43
Extend rule parsing and matching a little, so one can do something
like this:
[root at 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 at victim:~]# hrl -r ::openfiles
[root at 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:
More information about the p4-projects
mailing list