From: Gerrit Huizenga Part 4 of 5 patches to support Rule Based Classification Engine for CKRM. This patch connects RBCE with CKRM core. Full functionality of RBCE achieved with this patch. Signed-Off-By: Hubertus Franke Signed-Off-By: Chandra Seetharaman Signed-Off-By: Shailabh Nagar Signed-Off-By: Vivek Kashyap Signed-Off-By: Gerrit Huizenga Signed-off-by: Andrew Morton --- kernel/ckrm/rbce/Makefile | 2 kernel/ckrm/rbce/rbce_core.c | 890 +++++++++++++++++++++++++++++++++++++++ kernel/ckrm/rbce/rbce_internal.h | 23 + kernel/ckrm/rbce/rbce_main.c | 67 ++ 4 files changed, 961 insertions(+), 21 deletions(-) diff -puN kernel/ckrm/rbce/Makefile~ckrm-rule-based-classification-engine-full-ce kernel/ckrm/rbce/Makefile --- 25/kernel/ckrm/rbce/Makefile~ckrm-rule-based-classification-engine-full-ce Wed Jul 13 14:44:19 2005 +++ 25-akpm/kernel/ckrm/rbce/Makefile Wed Jul 13 14:44:19 2005 @@ -3,4 +3,4 @@ # obj-$(CONFIG_CKRM_RBCE) += rbce.o -rbce-objs := rbce_fs.o rbce_main.o rbce_token.o +rbce-objs := rbce_fs.o rbce_main.o rbce_token.o rbce_core.o diff -puN /dev/null kernel/ckrm/rbce/rbce_core.c --- /dev/null Thu Apr 11 07:25:15 2002 +++ 25-akpm/kernel/ckrm/rbce/rbce_core.c Wed Jul 13 14:44:19 2005 @@ -0,0 +1,890 @@ +/* Rule-based Classification Engine (RBCE) and + * Consolidated RBCE module code (combined) + * + * Copyright (C) Hubertus Franke, IBM Corp. 2003 + * (C) Chandra Seetharaman, IBM Corp. 2003 + * (C) Vivek Kashyap, IBM Corp. 2004 + * + * Module for loading of classification policies and providing + * a user API for Class-based Kernel Resource Management (CKRM) + * + * Latest version, more details at http://ckrm.sf.net + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#include "rbce_internal.h" + +/* + * Callback from core when a class is deleted. + */ +static void +rbce_class_deletecb(const char *classname, void *classobj, int classtype) +{ + static struct rbce_class *cls; + struct named_obj_hdr *pos; + struct rbce_rule *rule; + + write_lock(&rbce_rwlock); + cls = find_class_name(classname); + if (cls) { + if (cls->classobj != classobj) { + printk(KERN_ERR "rbce: class %s changed identity\n", + classname); + } + cls->classobj = NULL; + list_for_each_entry(pos, &rules_list[cls->classtype], link) { + rule = (struct rbce_rule *)pos; + if (rule->target_class) { + if (!strcmp + (rule->target_class->obj.name, classname)) { + put_class(cls); + rule->target_class = NULL; + rule->classtype = -1; + } + } + } + if ((cls = find_class_name(classname)) != NULL) { + printk(KERN_ERR + "rbce ERROR: class %s exists in rbce after " + "removal in core\n", classname); + } + } + write_unlock(&rbce_rwlock); + return; +} + +/*====================== Classification Functions =======================*/ + +/* + * Match the given full path name with the command expression. + * This function treats the folowing 2 charaters as special if seen in + * cmd_exp, all other chanracters are compared as is: + * ? - compares to any one single character + * * - compares to one or more single characters + * + * If fullpath is 1, tsk_comm is compared in full. otherwise only the command + * name (basename(tsk_comm)) is compared. + */ +static inline int +match_cmd(const char *tsk_comm, const char *cmd_exp, int fullpath) +{ + const char *c, *t, *last_ast, *cmd = tsk_comm; + char next_c; + + /* get the command name if we don't have to match the fullpath */ + if (!fullpath && ((c = strrchr(tsk_comm, '/')) != NULL)) { + cmd = c + 1; + } + + /* now faithfully assume the entire pathname is in cmd */ + + /* we now have to effectively implement a regular expression + * for now assume + * '?' any single character + * '*' one or more '?' + * rest must match + */ + + c = cmd_exp; + t = cmd; + if (t == NULL || c == NULL) { + return 0; + } + + last_ast = NULL; + next_c = '\0'; + + while (*c && *t) { + switch (*c) { + case '?': + if (*t == '/') { + return 0; + } + c++; + t++; + continue; + case '*': + if (*t == '/') { + return 0; + } + /* eat up all '*' in c */ + while (*(c + 1) == '*') + c++; + next_c = '\0'; + last_ast = c; + /*t++; Add this for matching '*' with "one" + or more chars. */ + while (*t && (*t != *(c + 1)) && *t != '/') + t++; + if (*t == *(c + 1)) { + c++; + if (*c != '/') { + if (*c == '?') { + if (*t == '/') { + return 0; + } + t++; + c++; + } + next_c = *c; + if (*c) { + if (*t == '/') { + return 0; + } + t++; + c++; + if (!*c && *t) + c = last_ast; + } + } else { + last_ast = NULL; + } + continue; + } + return 0; + case '/': + next_c = '\0'; + /*FALLTHRU*/ default: + if (*t == *c && next_c != *t) { + c++, t++; + continue; + } else { + /* reset to last asterix and + continue from there */ + if (last_ast) { + c = last_ast; + } else { + return 0; + } + } + } + } + + /* check for trailing "*" */ + while (*c == '*') + c++; + + return (!*c && !*t); +} + +static inline void reverse(char *str, int n) +{ + char s; + int i, j = n - 1; + + for (i = 0; i < j; i++, j--) { + s = str[i]; + str[i] = str[j]; + str[j] = s; + } +} + +static inline int itoa(int n, char *str) +{ + int i = 0, sz = 0; + + do { + str[i++] = n % 10 + '0'; + sz++; + n = n / 10; + } while (n > 0); + + (void)reverse(str, sz); + return sz; +} + +static inline int v4toa(__u32 y, char *a) +{ + int i; + int size = 0; + + for (i = 0; i < 4; i++) { + size += itoa(y & 0xff, &a[size]); + a[size++] = '.'; + y >>= 8; + } + return --size; +} + +static inline int match_ipv4(struct ckrm_net_struct *ns, char **string) +{ + char *ptr = *string; + int size; + char a4[16]; + + size = v4toa(ns->ns_daddrv4, a4); + + *string += size; + return !strncmp(a4, ptr, size); +} + +static inline int match_port(struct ckrm_net_struct *ns, char *ptr) +{ + char a[5]; + int size = itoa(ns->ns_dport, a); + + return !strncmp(a, ptr, size); +} + +static int __evaluate_rule(struct task_struct *tsk, struct ckrm_net_struct *ns, + struct rbce_rule *rule, bitvector_t * vec_eval, + bitvector_t * vec_true, char **filename); +/* + * evaluate the given task against the given rule with the vec_eval and + * vec_true in context. Return 1 if the task satisfies the given rule, 0 + * otherwise. + * + * If the bit corresponding to the rule is set in the vec_eval, then the + * corresponding bit in vec_true is the result. If it is not set, evaluate + * the rule and set the bits in both the vectors accordingly. + * + * On return, filename will have the pointer to the pathname of the task's + * executable, if the rule had any command related terms. + * + * Caller must hold the rbce_rwlock atleast in read mode. + */ +static inline int +evaluate_rule(struct task_struct *tsk, struct ckrm_net_struct *ns, + struct rbce_rule *rule, bitvector_t * vec_eval, + bitvector_t * vec_true, char **filename) +{ + int tidx = rule->index; + + if (!bitvector_test(tidx, vec_eval)) { + if (__evaluate_rule + (tsk, ns, rule, vec_eval, vec_true, filename)) { + bitvector_set(tidx, vec_true); + } + bitvector_set(tidx, vec_eval); + } + return bitvector_test(tidx, vec_true); +} + +/* + * evaluate the given task against every term in the given rule with + * vec_eval and vec_true in context. + * + * If the bit corresponding to a rule term is set in the vec_eval, then the + * corresponding bit in vec_true is the result for taht particular. If it is + * not set, evaluate the rule term and set the bits in both the vectors + * accordingly. + * + * This fucntions returns true only if all terms in the rule evaluate true. + * + * On return, filename will have the pointer to the pathname of the task's + * executable, if the rule had any command related terms. + * + * Caller must hold the rbce_rwlock atleast in read mode. + */ +static int +__evaluate_rule(struct task_struct *tsk, struct ckrm_net_struct *ns, + struct rbce_rule *rule, bitvector_t * vec_eval, + bitvector_t * vec_true, char **filename) +{ + int i; + int no_ip = 1; + + for (i = rule->num_terms; --i >= 0;) { + int rc = 1, tidx = rule->terms[i]; + + if (!bitvector_test(tidx, vec_eval)) { + struct rbce_rule_term *term = &gl_terms[tidx]; + + switch (term->op) { + + case RBCE_RULE_CMD_PATH: + case RBCE_RULE_CMD: +#if __NOT_YET__ + if (!*filename) { /* get this once */ + if (((*filename = + kmalloc(NAME_MAX, + GFP_ATOMIC)) == NULL) + || + (get_exe_path_name + (tsk, *filename, NAME_MAX) < 0)) { + rc = 0; + break; + } + } + rc = match_cmd(*filename, term->u.string, + (term->op == + RBCE_RULE_CMD_PATH)); +#else + rc = match_cmd(tsk->comm, term->u.string, + (term->op == + RBCE_RULE_CMD_PATH)); +#endif + break; + case RBCE_RULE_REAL_UID: + if (term->operator == RBCE_LESS_THAN) { + rc = (tsk->uid < term->u.id); + } else if (term->operator == RBCE_GREATER_THAN){ + rc = (tsk->uid > term->u.id); + } else if (term->operator == RBCE_NOT) { + rc = (tsk->uid != term->u.id); + } else { + rc = (tsk->uid == term->u.id); + } + break; + case RBCE_RULE_REAL_GID: + if (term->operator == RBCE_LESS_THAN) { + rc = (tsk->gid < term->u.id); + } else if (term->operator == RBCE_GREATER_THAN){ + rc = (tsk->gid > term->u.id); + } else if (term->operator == RBCE_NOT) { + rc = (tsk->gid != term->u.id); + } else { + rc = (tsk->gid == term->u.id); + } + break; + case RBCE_RULE_EFFECTIVE_UID: + if (term->operator == RBCE_LESS_THAN) { + rc = (tsk->euid < term->u.id); + } else if (term->operator == RBCE_GREATER_THAN){ + rc = (tsk->euid > term->u.id); + } else if (term->operator == RBCE_NOT) { + rc = (tsk->euid != term->u.id); + } else { + rc = (tsk->euid == term->u.id); + } + break; + case RBCE_RULE_EFFECTIVE_GID: + if (term->operator == RBCE_LESS_THAN) { + rc = (tsk->egid < term->u.id); + } else if (term->operator == RBCE_GREATER_THAN){ + rc = (tsk->egid > term->u.id); + } else if (term->operator == RBCE_NOT) { + rc = (tsk->egid != term->u.id); + } else { + rc = (tsk->egid == term->u.id); + } + break; + case RBCE_RULE_APP_TAG: + rc = (RBCE_DATA(tsk) + && RBCE_DATA(tsk)-> + app_tag) ? !strcmp(RBCE_DATA(tsk)-> + app_tag, + term->u.string) : 0; + break; + case RBCE_RULE_DEP_RULE: + rc = evaluate_rule(tsk, NULL, term->u.deprule, + vec_eval, vec_true, + filename); + break; + + case RBCE_RULE_IPV4: + /* TBD: add NOT_EQUAL match. At present */ + /* rbce recognises EQUAL matches only. */ + if (ns && term->operator == RBCE_EQUAL) { + int ma = 0; + int mp = 0; + char *ptr = term->u.string; + + if (term->u.string[0] == '*') + ma = 1; + else + ma = match_ipv4(ns, &ptr); + + if (*ptr != '\\') { + rc = 0; + break; + } else { + ++ptr; + if (*ptr == '*') + mp = 1; + else + mp = match_port(ns, + ptr); + } + rc = mp && ma; + } else + rc = 0; + no_ip = 0; + break; + + case RBCE_RULE_IPV6: /* no support yet */ + rc = 0; + no_ip = 0; + break; + + default: + rc = 0; + printk(KERN_ERR "Error evaluate term op=%d\n", + term->op); + break; + } + if (!rc && no_ip) { + bitvector_clear(tidx, vec_true); + } else { + bitvector_set(tidx, vec_true); + } + bitvector_set(tidx, vec_eval); + } else { + rc = bitvector_test(tidx, vec_true); + } + if (!rc) { + return 0; + } + } + return 1; +} + +/* + * This is some old debug code which needs to be trimmed. + */ + +#define valid_pdata(pdata) (1) +#define store_pdata(pdata) +#define unstore_pdata(pdata) + +struct rbce_private_data *create_private_data(struct rbce_private_data + *src, int copy_sample) +{ + int vsize = 0, psize, bsize = 0; + struct rbce_private_data *pdata; + + if (use_persistent_state) { + vsize = gl_allocated; + bsize = vsize / 8 + sizeof(bitvector_t); + psize = sizeof(struct rbce_private_data) + 2 * bsize; + } else { + psize = sizeof(struct rbce_private_data); + } + + pdata = kmalloc(psize, GFP_ATOMIC); + if (pdata != NULL) { + if (use_persistent_state) { + pdata->bitmap_version = gl_bitmap_version; + pdata->eval = (bitvector_t *) & pdata->data[0]; + pdata->true = (bitvector_t *) & pdata->data[bsize]; + if (src && (src->bitmap_version == gl_bitmap_version)) { + memcpy(pdata->data, src->data, 2 * bsize); + } else { + bitvector_init(pdata->eval, vsize); + bitvector_init(pdata->true, vsize); + } + } + pdata->evaluate = 1; + pdata->rules_version = src ? src->rules_version : 0; + pdata->app_tag = NULL; + } + store_pdata(pdata); + return pdata; +} + +static inline void free_private_data(struct rbce_private_data *pdata) +{ + if (valid_pdata(pdata)) { + unstore_pdata(pdata); + kfree(pdata); + } +} + +void free_all_private_data(void) +{ + struct task_struct *proc, *thread; + + read_lock(&tasklist_lock); + do_each_thread(proc, thread) { + struct rbce_private_data *pdata; + + pdata = RBCE_DATA(thread); + RBCE_DATAP(thread) = NULL; + free_private_data(pdata); + } while_each_thread(proc, thread); + read_unlock(&tasklist_lock); + return; +} + +/* + * reclassify function, which is called by all the callback functions. + * + * Takes that task to be reclassified and ruleflags that indicates the + * attributes that caused this reclassification request. + * + * On success, returns the core class pointer to which the given task should + * belong to. + */ +static struct ckrm_core_class *rbce_classify(struct task_struct *tsk, + struct ckrm_net_struct *ns, + unsigned long termflag, + int classtype) +{ + int i; + struct rbce_rule *rule; + bitvector_t *vec_true = NULL, *vec_eval = NULL; + struct rbce_class *tgt = NULL; + struct ckrm_core_class *cls = NULL; + char *filename = NULL; + + if (!valid_pdata(RBCE_DATA(tsk))) { + return NULL; + } + if (classtype >= CKRM_MAX_CLASSTYPES) { + /* can't handle more than CKRM_MAX_CLASSTYPES */ + return NULL; + } + /* fast path to avoid locking in case CE is not enabled or */ + /* if no rules are defined or if no evaluation is needed. */ + if (!rbce_enabled || !gl_num_rules || + (RBCE_DATA(tsk) && !RBCE_DATA(tsk)->evaluate)) { + return NULL; + } + /* FIXME: optimize_policy should be called from here if */ + /* gl_action is non-zero. Also, it has to be called with the */ + /* rbce_rwlock held in write mode. */ + + read_lock(&rbce_rwlock); + + vec_eval = vec_true = NULL; + if (use_persistent_state) { + struct rbce_private_data *pdata = RBCE_DATA(tsk); + + if (!pdata + || (pdata + && (gl_bitmap_version != pdata->bitmap_version))) { + struct rbce_private_data *new_pdata = + create_private_data(pdata, 1); + + if (new_pdata) { + if (pdata) { + new_pdata->rules_version = + pdata->rules_version; + new_pdata->evaluate = pdata->evaluate; + new_pdata->app_tag = pdata->app_tag; + free_private_data(pdata); + } + pdata = RBCE_DATAP(tsk) = new_pdata; + termflag = RBCE_TERMFLAG_ALL; + /* need to evaluate them all */ + } else { + /* + * we shouldn't free the pdata as it has more + * details than the vectors. But, this + * reclassification should go thru + */ + pdata = NULL; + } + } + if (!pdata) { + goto cls_determined; + } + vec_eval = pdata->eval; + vec_true = pdata->true; + } else { + int bsize = gl_allocated; + + vec_eval = bitvector_alloc(bsize); + vec_true = bitvector_alloc(bsize); + + if (vec_eval == NULL || vec_true == NULL) { + goto cls_determined; + } + termflag = RBCE_TERMFLAG_ALL; + /* need to evaluate all of them now */ + } + + /* + * using bit ops invalidate all terms related to this termflag + * context (only in per task vec) + */ + + if (termflag == RBCE_TERMFLAG_ALL) { + bitvector_zero(vec_eval); + } else { + for (i = 0; i < NUM_TERM_MASK_VECTOR; i++) { + if (test_bit(i, &termflag)) { + bitvector_t *maskvec = get_gl_mask_vecs(i); + + bitvector_and_not(vec_eval, vec_eval, maskvec); + } + } + } + bitvector_and(vec_true, vec_true, vec_eval); + + /* run through the rules in order and see what needs evaluation */ + list_for_each_entry(rule, &rules_list[classtype], obj.link) { + if (rule->state == RBCE_RULE_ENABLED && + rule->target_class && + rule->target_class->classobj && + evaluate_rule(tsk, ns, rule, vec_eval, vec_true, + &filename)) { + tgt = rule->target_class; + cls = rule->target_class->classobj; + break; + } + } + + cls_determined: + if (!use_persistent_state) { + if (vec_eval) { + bitvector_free(vec_eval); + } + if (vec_true) { + bitvector_free(vec_true); + } + } + ckrm_core_grab(cls); + read_unlock(&rbce_rwlock); + if (filename) { + kfree(filename); + } + if (RBCE_DATA(tsk)) { + RBCE_DATA(tsk)->rules_version = gl_rules_version; + } + return cls; +} + +/***************************************************************************** + * + * Module specific utilization of core RBCE functionality + * + * Includes support for the various classtypes + * New classtypes will require extensions here + * + *****************************************************************************/ + +/* helper functions that are required in the extended version */ + +static inline void rbce_tc_manual(struct task_struct *tsk) +{ + read_lock(&rbce_rwlock); + + if (!RBCE_DATA(tsk)) { + RBCE_DATAP(tsk) = + (void *)create_private_data(RBCE_DATA(tsk->parent), 0); + } + if (RBCE_DATA(tsk)) { + RBCE_DATA(tsk)->evaluate = 0; + } + read_unlock(&rbce_rwlock); + return; +} + +/***************************************************************************** + * VARIOUS CLASSTYPES + *****************************************************************************/ + +/* to enable type coercion of the function pointers */ + +/*============================================================================ + * TASKCLASS CLASSTYPE + *============================================================================*/ + +int tc_classtype = -1; + +/* + * fork callback to be registered with core module. + */ +static inline void *rbce_tc_forkcb(struct task_struct *tsk) +{ + int rule_version_changed = 1; + struct ckrm_core_class *cls; + read_lock(&rbce_rwlock); + /* dup ce_data */ + RBCE_DATAP(tsk) = + (void *)create_private_data(RBCE_DATA(tsk->parent), 0); + read_unlock(&rbce_rwlock); + + if (RBCE_DATA(tsk->parent)) { + rule_version_changed = + (RBCE_DATA(tsk->parent)->rules_version != gl_rules_version); + } + cls = rule_version_changed ? + rbce_classify(tsk, NULL, RBCE_TERMFLAG_ALL, tc_classtype) : NULL; + + /* + * note the fork notification to any user client will be sent through + * the guaranteed fork-reclassification + */ + return cls; +} + +/* + * exit callback to be registered with core module. + */ +static void rbce_tc_exitcb(struct task_struct *tsk) +{ + struct rbce_private_data *pdata; + + pdata = RBCE_DATA(tsk); + RBCE_DATAP(tsk) = NULL; + if (pdata) { + if (pdata->app_tag) { + kfree(pdata->app_tag); + } + free_private_data(pdata); + } + return; +} + +static void *rbce_tc_classify(enum ckrm_event event, ...) +{ + va_list args; + void *cls = NULL; + struct task_struct *tsk; + struct rbce_private_data *pdata; + + va_start(args, event); + tsk = va_arg(args, struct task_struct *); + va_end(args); + + /* we only have to deal with events between + * [ CKRM_LATCHABLE_EVENTS .. CKRM_NONLATCHABLE_EVENTS ) + */ + switch (event) { + + case CKRM_EVENT_FORK: + cls = rbce_tc_forkcb(tsk); + break; + + case CKRM_EVENT_EXIT: + rbce_tc_exitcb(tsk); + break; + + case CKRM_EVENT_EXEC: + cls = rbce_classify(tsk, NULL, RBCE_TERMFLAG_CMD | + RBCE_TERMFLAG_UID | RBCE_TERMFLAG_GID, + tc_classtype); + break; + + case CKRM_EVENT_UID: + cls = rbce_classify(tsk, NULL, RBCE_TERMFLAG_UID, tc_classtype); + break; + + case CKRM_EVENT_GID: + cls = rbce_classify(tsk, NULL, RBCE_TERMFLAG_GID, tc_classtype); + break; + + case CKRM_EVENT_LOGIN: + case CKRM_EVENT_USERADD: + case CKRM_EVENT_USERDEL: + case CKRM_EVENT_LISTEN_START: + case CKRM_EVENT_LISTEN_STOP: + case CKRM_EVENT_APPTAG: + /* no interest in this events .. */ + break; + + default: + /* catch all */ + break; + + case CKRM_EVENT_RECLASSIFY: + if ((pdata = (RBCE_DATA(tsk)))) { + pdata->evaluate = 1; + } + cls = rbce_classify(tsk, NULL, RBCE_TERMFLAG_ALL, tc_classtype); + break; + + } + + return cls; +} + +static void rbce_tc_notify(int event, void *core, struct task_struct *tsk) +{ + if (event != CKRM_EVENT_MANUAL) + return; + rbce_tc_manual(tsk); +} + +static struct ckrm_eng_callback rbce_taskclass_ecbs = { + .c_interest = (unsigned long)(-1), /* set whole bitmap */ + .classify = (ce_classify_fct) rbce_tc_classify, + .class_delete = rbce_class_deletecb, + .n_interest = (1 << CKRM_EVENT_MANUAL), + .notify = (ce_notify_fct) rbce_tc_notify, + .always_callback = 0, +}; + +/*============================================================================ + * ACCEPTQ CLASSTYPE + *============================================================================*/ + +int sc_classtype = -1; + +static void *rbce_sc_classify(enum ckrm_event event, ...) +{ + /* no special consideratation */ + void *result; + va_list args; + struct task_struct *tsk; + struct ckrm_net_struct *ns; + + va_start(args, event); + ns = va_arg(args, struct ckrm_net_struct *); + tsk = va_arg(args, struct task_struct *); + va_end(args); + + result = rbce_classify(tsk, ns, RBCE_TERMFLAG_ALL, sc_classtype); + + return result; +} + +static struct ckrm_eng_callback rbce_acceptQclass_ecbs = { + .c_interest = (unsigned long)(-1), + .always_callback = 0, /* enable during debugging only */ + .classify = (ce_classify_fct) & rbce_sc_classify, + .class_delete = rbce_class_deletecb, +}; + +/*============================================================================ + * Module Initialization ... + *============================================================================*/ + +#define TASKCLASS_NAME "taskclass" +#define SOCKCLASS_NAME "socket_class" + +struct ce_regtable_struct { + const char *name; + struct ckrm_eng_callback *cbs; + int *clsvar; +}; + +struct ce_regtable_struct ce_regtable[] = { + {TASKCLASS_NAME, &rbce_taskclass_ecbs, &tc_classtype}, + {SOCKCLASS_NAME, &rbce_acceptQclass_ecbs, &sc_classtype}, + {NULL} +}; + +void unregister_classtype_engines(void) +{ + int rc; + struct ce_regtable_struct *ceptr = ce_regtable; + + while (ceptr->name) { + if (*ceptr->clsvar >= 0) { + while ((rc = ckrm_unregister_engine(ceptr->name)) == -EAGAIN) + ; + *ceptr->clsvar = -1; + } + ceptr++; + } +} + +int register_classtype_engines(void) +{ + int rc; + struct ce_regtable_struct *ceptr = ce_regtable; + + while (ceptr->name) { + rc = ckrm_register_engine(ceptr->name, ceptr->cbs); + if ((rc < 0) && (rc != -ENOENT)) { + unregister_classtype_engines(); + return (rc); + } + if (rc != -ENOENT) + *ceptr->clsvar = rc; + ceptr++; + } + return 0; +} diff -puN kernel/ckrm/rbce/rbce_internal.h~ckrm-rule-based-classification-engine-full-ce kernel/ckrm/rbce/rbce_internal.h --- 25/kernel/ckrm/rbce/rbce_internal.h~ckrm-rule-based-classification-engine-full-ce Wed Jul 13 14:44:19 2005 +++ 25-akpm/kernel/ckrm/rbce/rbce_internal.h Wed Jul 13 14:44:19 2005 @@ -41,6 +41,8 @@ #include #include +#include "rbce_bitvector.h" + /* * comman data structure used for identification of class and rules * in the RBCE namespace @@ -205,14 +207,25 @@ struct rbce_private_data { bitvector_t *eval; bitvector_t *true; char *app_tag; + unsigned long bitmap_version; char data[0]; /* bitvectors eval and true */ }; #define RBCE_DATA(tsk) ((struct rbce_private_data*)((tsk)->ce_data)) #define RBCE_DATAP(tsk) ((tsk)->ce_data) +/* Other rbce global stuff. */ + extern struct rbce_eng_callback rbce_rcfs_ecbs; extern int rbce_enabled; +extern struct list_head rules_list[]; +extern const int use_persistent_state; +extern int gl_num_rules; +extern int gl_bitmap_version; +extern int gl_allocated; +extern struct rbce_rule_term *gl_terms; +extern int gl_rules_version; +extern rwlock_t rbce_rwlock; extern int rbce_mkdir(struct inode *, struct dentry *, int); extern int rbce_rmdir(struct inode *, struct dentry *); @@ -228,4 +241,14 @@ extern int rbce_rename_rule(const char * extern int rules_parse(char *, struct rbce_rule_term **, int *); +extern struct rbce_private_data *create_private_data(struct rbce_private_data + *, int); +extern bitvector_t *get_gl_mask_vecs(int); +extern struct rbce_class *find_class_name(const char *); +extern void put_class(struct rbce_class *); +extern void free_all_private_data(void); + +extern void unregister_classtype_engines(void); +extern int register_classtype_engines(void); + #endif /* _RBCE_INTERNAL_H */ diff -puN kernel/ckrm/rbce/rbce_main.c~ckrm-rule-based-classification-engine-full-ce kernel/ckrm/rbce/rbce_main.c --- 25/kernel/ckrm/rbce/rbce_main.c~ckrm-rule-based-classification-engine-full-ce Wed Jul 13 14:44:19 2005 +++ 25-akpm/kernel/ckrm/rbce/rbce_main.c Wed Jul 13 14:44:19 2005 @@ -23,7 +23,6 @@ */ #include "rbce_internal.h" -#include "rbce_bitvector.h" MODULE_DESCRIPTION(RBCE_MOD_DESCR); MODULE_AUTHOR("Hubertus Franke, Chandra Seetharaman (IBM)"); @@ -57,19 +56,20 @@ int termop_2_vecidx[RBCE_RULE_INVALID] = extern int errno; -int rbce_enabled = 1; -const int use_persistent_state = 1; - static LIST_HEAD(class_list); -static struct list_head rules_list[CKRM_MAX_CLASSTYPES]; -static int gl_num_rules; +struct list_head rules_list[CKRM_MAX_CLASSTYPES]; static int gl_action, gl_num_terms; -static int gl_bitmap_version, gl_action, gl_num_terms; -static int gl_allocated, gl_released; -static struct rbce_rule_term *gl_terms; -static int gl_rules_version; +static int gl_released; static bitvector_t *gl_mask_vecs[NUM_TERM_MASK_VECTOR]; -static rwlock_t rbce_rwlock = RW_LOCK_UNLOCKED; + +int rbce_enabled = 1; +const int use_persistent_state = 1; +int gl_num_rules; +int gl_bitmap_version; +int gl_allocated; +struct rbce_rule_term *gl_terms; +int gl_rules_version; +rwlock_t rbce_rwlock = RW_LOCK_UNLOCKED; /* * One lock to protect them all !!! * Additions, deletions to rules must @@ -84,6 +84,12 @@ static rwlock_t rbce_rwlock = RW_LOCK_UN static void optimize_policy(void); +bitvector_t * +get_gl_mask_vecs(int index) +{ + return gl_mask_vecs[index]; +} + static inline struct rbce_rule *find_rule_name(const char *name) { struct named_obj_hdr *pos; @@ -353,7 +359,7 @@ static inline int __delete_rule(struct r /* * Optimize the rule evaluation logic * - * Caller must hold global_rwlock in write mode. + * Caller must hold rbce_rwlock in write mode. */ static void optimize_policy(void) { @@ -1127,12 +1133,6 @@ int rbce_rule_exists(const char *rname) } /*====================== Magic file handling =======================*/ -struct rbce_private_data *create_private_data(struct rbce_private_data *a, - int b) -{ - return NULL; -} - static inline void reset_evaluation(struct rbce_private_data *pdata,int termflag) { @@ -1197,15 +1197,25 @@ out: int init_rbce(void) { - int rc, line; + int rc, i, line; printk(KERN_INFO "Installing \'%s\' module\n", modname); - rc = rcfs_register_engine(&rbce_rcfs_ecbs); + for (i = 0; i < CKRM_MAX_CLASSTYPES; i++) { + INIT_LIST_HEAD(&rules_list[i]); + } + + rc = register_classtype_engines(); line = __LINE__; if (rc) goto out; + /* register any other class type engine here */ + rc = rcfs_register_engine(&rbce_rcfs_ecbs); + line = __LINE__; + if (rc) + goto out_unreg_classtype;; + if (rcfs_mounted) { rc = rbce_create_config(); line = __LINE__; @@ -1214,6 +1224,8 @@ int init_rbce(void) } rcfs_unregister_engine(&rbce_rcfs_ecbs); +out_unreg_classtype: + unregister_classtype_engines(); out: printk(KERN_ERR "%s: error installing rc=%d line=%d\n", __FUNCTION__, rc, line); @@ -1222,12 +1234,27 @@ out: void exit_rbce(void) { + int i; printk(KERN_INFO "Removing \'%s\' module\n", modname); + /* Print warnings if lists are not empty, which is a bug */ + if (!list_empty(&class_list)) { + printk(KERN_WARNING "exit_rbce: Class list is not empty\n"); + } + + for (i = 0; i < CKRM_MAX_CLASSTYPES; i++) { + if (!list_empty(&rules_list[i])) { + printk(KERN_WARNING "exit_rbce: Rules list for " + "classtype %d is not empty\n", i); + } + } + if (rcfs_mounted) rbce_clear_config(); rcfs_unregister_engine(&rbce_rcfs_ecbs); + unregister_classtype_engines(); + free_all_private_data(); } module_init(init_rbce); _