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>