This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / kernel / ckrm / rbce / rbcemod.c
1 /* Rule-based Classification Engine (RBCE) and
2  * Consolidated RBCE module code (combined)
3  *
4  * Copyright (C) Hubertus Franke, IBM Corp. 2003
5  *           (C) Chandra Seetharaman, IBM Corp. 2003
6  *           (C) Vivek Kashyap, IBM Corp. 2004 
7  * 
8  * Module for loading of classification policies and providing
9  * a user API for Class-based Kernel Resource Management (CKRM)
10  *
11  * Latest version, more details at http://ckrm.sf.net
12  * 
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it would be useful, but
19  * WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21  *
22  */
23
24 /* Changes
25  *
26  * 28 Aug 2003
27  *        Created. First cut with much scope for cleanup !
28  * 07 Nov 2003
29  *        Made modifications to suit the new RBCE module.
30  *        Made modifications to address sampling and delivery
31  * 16 Mar 2004
32  *        Integrated changes from original RBCE module
33  * 25 Mar 2004
34  *        Merged RBCE and CRBCE into common code base
35  * 29 Mar 2004
36  *        Incorporated listen call back and IPv4 match support
37  * 23 Apr 2004
38  *        Added Multi-Classtype Support
39  */
40
41 #include <linux/init.h>
42 #include <linux/module.h>
43 #include <linux/kernel.h>
44 #include <asm/io.h>
45 #include <asm/uaccess.h>
46 #include <linux/mm.h>
47 #include <linux/mount.h>
48 #include <linux/proc_fs.h>
49 #include <linux/limits.h>
50 #include <linux/pid.h>
51 #include <linux/sysctl.h>
52
53 #include <linux/ckrm_rc.h>
54 #include <linux/ckrm_ce.h>
55 #include <linux/ckrm_net.h>
56 #include "bitvector.h"
57 #include <linux/rbce.h>
58
59 #warning MEF I cannot believe that vserver changes force the following include statement: FIX THIS!
60 #include <linux/vs_cvirt.h>
61
62
63 #define DEBUG
64
65 MODULE_DESCRIPTION(RBCE_MOD_DESCR);
66 MODULE_AUTHOR("Hubertus Franke, Chandra Seetharaman (IBM)");
67 MODULE_LICENSE("GPL");
68
69 static char modname[] = RBCE_MOD_NAME;
70
71 /* ==================== typedef, global variables etc., ==================== */
72 struct named_obj_hdr {
73         struct list_head link;
74         int referenced;
75         char *name;
76 };
77
78 #define GET_REF(x) ((x)->obj.referenced)
79 #define INC_REF(x) (GET_REF(x)++)
80 #define DEC_REF(x) (--GET_REF(x))
81 struct rbce_class {
82         struct named_obj_hdr obj;
83         int classtype;
84         void *classobj;
85 };
86
87 typedef enum {
88         RBCE_RULE_CMD_PATH = 1, // full qualified path
89         RBCE_RULE_CMD,          // basename of the command
90         RBCE_RULE_ARGS,         // arguments of the command
91         RBCE_RULE_REAL_UID,     // task's real uid
92         RBCE_RULE_REAL_GID,     // task's real gid
93         RBCE_RULE_EFFECTIVE_UID,        // task's effective uid
94         RBCE_RULE_EFFECTIVE_GID,        // task's effective gid
95         RBCE_RULE_APP_TAG,      // task's application tag
96         RBCE_RULE_IPV4,         // IP address of listen(), ipv4 format
97         RBCE_RULE_IPV6,         // IP address of listen(), ipv6 format
98         RBCE_RULE_XID,          // VSERVER 
99         RBCE_RULE_DEP_RULE,     // dependent rule; must be the first term
100         RBCE_RULE_INVALID,      // invalid, for filler
101         RBCE_RULE_INVALID2,     // invalid, for filler
102 } rbce_rule_op_t;
103
104 typedef enum {
105         RBCE_EQUAL = 1,
106         RBCE_NOT,
107         RBCE_LESS_THAN,
108         RBCE_GREATER_THAN,
109 } rbce_operator_t;
110
111 struct rbce_rule_term {
112         rbce_rule_op_t op;
113         rbce_operator_t operator;
114         union {
115                 char *string;   // path, cmd, arg, tag, ipv4 and ipv6
116                 long id;        // uid, gid, euid, egid
117                 struct rbce_rule *deprule;
118         } u;
119 };
120
121 struct rbce_rule {
122         struct named_obj_hdr obj;
123         struct rbce_class *target_class;
124         int classtype;
125         int num_terms;
126         int *terms;     // vector of indices into the global term vector
127         int index;      // index of this rule into the global term vector
128         int termflag;   // which term ids would require a recalculation
129         int do_opt;     // do we have to consider this rule during optimize
130         char *strtab;   // string table to store the strings of all terms
131         int order;      // order of execution of this rule
132         int state;      // RBCE_RULE_ENABLED/RBCE_RULE_DISABLED
133 };
134
135 // rules states
136 #define RBCE_RULE_DISABLED 0
137 #define RBCE_RULE_ENABLED  1
138
139 ///
140 // Data structures and macros used for optimization
141 #define RBCE_TERM_CMD   (0)
142 #define RBCE_TERM_UID   (1)
143 #define RBCE_TERM_GID   (2)
144 #define RBCE_TERM_TAG   (3)
145 #define RBCE_TERM_IPV4  (4)
146 #define RBCE_TERM_IPV6  (5)
147 #define RBCE_TERM_XID   (6)
148
149 #define NUM_TERM_MASK_VECTOR  (7)     // must be one more the last RBCE_TERM_...
150
151 // Rule flags. 1 bit for each type of rule term
152 #define RBCE_TERMFLAG_CMD   (1 << RBCE_TERM_CMD)
153 #define RBCE_TERMFLAG_UID   (1 << RBCE_TERM_UID)
154 #define RBCE_TERMFLAG_GID   (1 << RBCE_TERM_GID)
155 #define RBCE_TERMFLAG_TAG   (1 << RBCE_TERM_TAG)
156 #define RBCE_TERMFLAG_IPV4  (1 << RBCE_TERM_IPV4)
157 #define RBCE_TERMFLAG_IPV6  (1 << RBCE_TERM_IPV6)
158 #define RBCE_TERMFLAG_XID   (1 << RBCE_TERM_XID)
159 #define RBCE_TERMFLAG_ALL (RBCE_TERMFLAG_CMD | RBCE_TERMFLAG_UID |                      \
160                            RBCE_TERMFLAG_GID | RBCE_TERMFLAG_TAG | RBCE_TERMFLAG_XID |  \
161                            RBCE_TERMFLAG_IPV4 | RBCE_TERMFLAG_IPV6)
162
163 int termop_2_vecidx[RBCE_RULE_INVALID] = {
164         [RBCE_RULE_CMD_PATH] = RBCE_TERM_CMD,
165         [RBCE_RULE_CMD] = RBCE_TERM_CMD,
166         [RBCE_RULE_ARGS] = RBCE_TERM_CMD,
167         [RBCE_RULE_REAL_UID] = RBCE_TERM_UID,
168         [RBCE_RULE_REAL_GID] = RBCE_TERM_GID,
169         [RBCE_RULE_EFFECTIVE_UID] = RBCE_TERM_UID,
170         [RBCE_RULE_EFFECTIVE_GID] = RBCE_TERM_GID,
171         [RBCE_RULE_XID] = RBCE_TERM_XID,
172         [RBCE_RULE_APP_TAG] = RBCE_TERM_TAG,
173         [RBCE_RULE_IPV4] = RBCE_TERM_IPV4,
174         [RBCE_RULE_IPV6] = RBCE_TERM_IPV6,
175         [RBCE_RULE_DEP_RULE] = -1
176 };
177
178 #define TERMOP_2_TERMFLAG(x)    (1 << termop_2_vecidx[x])
179 #define TERM_2_TERMFLAG(x)              (1 << x)
180
181 #define POLICY_INC_NUMTERMS     (BITS_PER_LONG) // No. of terms added at a time
182 #define POLICY_ACTION_NEW_VERSION       0x01    // Force reallocation
183 #define POLICY_ACTION_REDO_ALL          0x02    // Recompute all rule flags
184 #define POLICY_ACTION_PACK_TERMS        0x04    // Time to pack the terms
185
186 const int use_persistent_state = 1;
187
188 struct ckrm_eng_callback ckrm_ecbs;
189
190 // Term vector state
191 //
192 static int gl_bitmap_version, gl_action, gl_num_terms;
193 static int gl_allocated, gl_released;
194 struct rbce_rule_term *gl_terms;
195 bitvector_t *gl_mask_vecs[NUM_TERM_MASK_VECTOR];
196
197 extern int errno;
198 static void optimize_policy(void);
199
200 #ifndef CKRM_MAX_CLASSTYPES
201 #define CKRM_MAX_CLASSTYPES 32
202 #endif
203
204 struct list_head rules_list[CKRM_MAX_CLASSTYPES];
205 LIST_HEAD(class_list);          // List of classes used
206
207 static int gl_num_rules;
208 static int gl_rules_version;
209 int rbce_enabled = 1;
210 static rwlock_t global_rwlock = RW_LOCK_UNLOCKED;
211         /*
212          * One lock to protect them all !!!
213          * Additions, deletions to rules must
214          * happen with this lock being held in write mode.
215          * Access(read/write) to any of the data structures must happen 
216          * with this lock held in read mode.
217          * Since, rule related changes do not happen very often it is ok to
218          * have single rwlock.
219          */
220
221 /*
222  * data structure rbce_private_data holds the bit vector 'eval' which 
223  * specifies if rules and terms of rules are evaluated against the task
224  * and if they were evaluated, bit vector 'true' holds the result of that
225  * evaluation.
226  *
227  * This data structure is maintained in a task, and the bitvectors are
228  * updated only when needed.
229  *
230  * Each rule and each term of a rule has a corresponding bit in the vector.
231  *
232  */
233 struct rbce_private_data {
234         struct rbce_ext_private_data ext_data;
235         int evaluate;           // whether to evaluate rules or not ?
236         int rules_version;      // whether to evaluate rules or not ?
237         char *app_tag;
238         unsigned long bitmap_version;
239         bitvector_t *eval;
240         bitvector_t *true;
241         char data[0];           // eval points to this variable size data array
242 };
243
244 #define RBCE_DATA(tsk) ((struct rbce_private_data*)((tsk)->ce_data))
245 #define RBCE_DATAP(tsk) ((tsk)->ce_data)
246
247 /* ======================= DEBUG  Functions ========================= */
248
249 #ifdef DEBUG
250
251 int rbcedebug = 0x00;
252
253 #define DBG_CLASSIFY_RES     ( 0x01 )
254 #define DBG_CLASSIFY_DETAILS ( 0x02 )
255 #define DBG_OPTIMIZATION     ( 0x04 )
256 #define DBG_SHOW_RESCTL      ( 0x08 )
257 #define DBG_CLASS            ( 0x10 )
258 #define DBG_RULE             ( 0x20 )
259 #define DBG_POLICY           ( 0x40 )
260
261 #define DPRINTK(x, y...)   if (rbcedebug & (x)) printk(KERN_DEBUG y)
262         // debugging selectively enabled through /proc/sys/debug/rbce
263
264 static void print_context_vectors(void)
265 {
266         int i;
267
268         if ((rbcedebug & DBG_OPTIMIZATION) == 0) {
269                 return;
270         }
271         for (i = 0; i < NUM_TERM_MASK_VECTOR; i++) {
272                 printk(KERN_DEBUG "%d: ", i);
273                 bitvector_print(DBG_OPTIMIZATION, gl_mask_vecs[i]);
274                 printk(KERN_DEBUG "\n");
275         }
276 }
277 #else
278
279 #define DPRINTK(x, y...)
280 #define print_context_vectors(x)
281 #endif
282
283 /* ====================== VSERVER support ========================== */
284 #define CONFIG_VSERVER
285 #ifdef CONFIG_VSERVER 
286 #include <linux/vs_base.h>
287 #else
288 typedef unsigned int xid_t;
289 #define vx_task_xid(t)  (0)
290 #endif 
291
292 /* ======================= Helper Functions ========================= */
293
294 #include "token.c"
295
296 static struct ckrm_core_class *rbce_classify(struct task_struct *,
297                                              struct ckrm_net_struct *,
298                                              unsigned long, int classtype);
299
300 static inline struct rbce_rule *find_rule_name(const char *name)
301 {
302         struct named_obj_hdr *pos;
303         int i;
304
305         for (i = 0; i < CKRM_MAX_CLASSTYPES; i++) {
306                 list_for_each_entry(pos, &rules_list[i], link) {
307                         if (!strcmp(pos->name, name)) {
308                                 return ((struct rbce_rule *)pos);
309                         }
310                 }
311         }
312         return NULL;
313 }
314
315 static inline struct rbce_class *find_class_name(const char *name)
316 {
317         struct named_obj_hdr *pos;
318
319         list_for_each_entry(pos, &class_list, link) {
320                 if (!strcmp(pos->name, name))
321                         return (struct rbce_class *)pos;
322         }
323         return NULL;
324 }
325
326 /*
327  * Insert the given rule at the specified order
328  *              order = -1 ==> insert at the tail.
329  *
330  * Caller must hold global_rwlock in write mode.
331  */
332 static int insert_rule(struct rbce_rule *rule, int order)
333 {
334 #define ORDER_COUNTER_INCR 10
335         static int order_counter;
336         int old_counter;
337         struct list_head *head = &rules_list[rule->classtype];
338         struct list_head *insert = head;
339         struct rbce_rule *tmp;
340
341         if (gl_num_rules == 0) {
342                 order_counter = 0;
343         }
344
345         switch (order) {
346         case -1:
347                 rule->order = order_counter;
348                 // FIXME: order_counter overflow/wraparound!!
349                 order_counter += ORDER_COUNTER_INCR;
350                 break;
351         default:
352                 old_counter = order_counter;
353                 if (order_counter < order) {
354                         order_counter = order;
355                 }
356                 rule->order = order;
357                 order_counter += ORDER_COUNTER_INCR;
358                 list_for_each_entry(tmp, head, obj.link) {
359                         if (rule->order == tmp->order) {
360                                 order_counter = old_counter;
361                                 return -EEXIST;
362                         }
363                         if (rule->order < tmp->order) {
364                                 insert = &tmp->obj.link;
365                                 break;
366                         }
367                 }
368         }
369         list_add_tail(&rule->obj.link, insert);
370         // protect the module from removed when any rule is
371         // defined
372         try_module_get(THIS_MODULE);
373         gl_num_rules++;
374         gl_rules_version++;
375         return 0;
376 }
377
378 /*
379  * Remove the rule and reinsert at the specified order.
380  *
381  * Caller must hold global_rwlock in write mode.
382  */
383 static int reinsert_rule(struct rbce_rule *rule, int order)
384 {
385         list_del(&rule->obj.link);
386         gl_num_rules--;
387         gl_rules_version++;
388         module_put(THIS_MODULE);
389         return insert_rule(rule, order);
390 }
391
392 /*
393  * Get a refernece to the class, create one if it doesn't exist
394  *
395  * Caller need to hold global_rwlock in write mode.
396  * __GFP_WAIT
397  */
398
399 static struct rbce_class *create_rbce_class(const char *classname,
400                                             int classtype, void *classobj)
401 {
402         struct rbce_class *cls;
403
404         if (classtype >= CKRM_MAX_CLASSTYPES) {
405                 printk(KERN_ERR
406                        "ckrm_classobj returned %d as classtype which cannot "
407                        " be handled by RBCE\n", classtype);
408                 return NULL;
409         }
410
411         cls = kmalloc(sizeof(struct rbce_class), GFP_ATOMIC);
412         if (!cls) {
413                 return NULL;
414         }
415         cls->obj.name = kmalloc(strlen(classname) + 1, GFP_ATOMIC);
416         if (cls->obj.name) {
417                 GET_REF(cls) = 1;
418                 cls->classobj = classobj;
419                 strcpy(cls->obj.name, classname);
420                 list_add_tail(&cls->obj.link, &class_list);
421                 cls->classtype = classtype;
422         } else {
423                 kfree(cls);
424                 cls = NULL;
425         }
426         return cls;
427 }
428
429 static struct rbce_class *get_class(char *classname, int *classtype)
430 {
431         struct rbce_class *cls;
432         void *classobj;
433
434         if (!classname) {
435                 return NULL;
436         }
437         cls = find_class_name(classname);
438         if (cls) {
439                 if (cls->classobj) {
440                         INC_REF(cls);
441                         *classtype = cls->classtype;
442                         return cls;
443                 }
444                 return NULL;
445         }
446         classobj = ckrm_classobj(classname, classtype);
447         if (!classobj) {
448                 return NULL;
449         }
450
451         return create_rbce_class(classname, *classtype, classobj);
452 }
453
454 /*
455  * Drop a refernece to the class, create one if it doesn't exist
456  *
457  * Caller need to hold global_rwlock in write mode.
458  */
459 static void put_class(struct rbce_class *cls)
460 {
461         if (cls) {
462                 if (DEC_REF(cls) <= 0) {
463                         list_del(&cls->obj.link);
464                         kfree(cls->obj.name);
465                         kfree(cls);
466                 }
467         }
468         return;
469 }
470
471 /*
472  * Callback from core when a class is added
473  */
474
475 #ifdef RBCE_EXTENSION
476 static void rbce_class_addcb(const char *classname, void *clsobj, int classtype)
477 {
478         struct rbce_class *cls;
479
480         write_lock(&global_rwlock);
481         cls = find_class_name((char *)classname);
482         if (cls) {
483                 cls->classobj = clsobj;
484         } else {
485                 cls = create_rbce_class(classname, classtype, clsobj);
486         }
487         if (cls)
488                 notify_class_action(cls, 1);
489         write_unlock(&global_rwlock);
490         return;
491 }
492 #endif
493
494 /*
495  * Callback from core when a class is deleted.
496  */
497 static void
498 rbce_class_deletecb(const char *classname, void *classobj, int classtype)
499 {
500         static struct rbce_class *cls;
501         struct named_obj_hdr *pos;
502         struct rbce_rule *rule;
503
504         write_lock(&global_rwlock);
505         cls = find_class_name(classname);
506         if (cls) {
507                 if (cls->classobj != classobj) {
508                         printk(KERN_ERR "rbce: class %s changed identity\n",
509                                classname);
510                 }
511                 notify_class_action(cls, 0);
512                 cls->classobj = NULL;
513                 list_for_each_entry(pos, &rules_list[classtype], link) {
514                         rule = (struct rbce_rule *)pos;
515                         if (rule->target_class) {
516                                 if (!strcmp
517                                     (rule->target_class->obj.name, classname)) {
518                                         put_class(cls);
519                                         rule->target_class = NULL;
520                                         rule->classtype = -1;
521                                 }
522                         }
523                 }
524                 if ((cls = find_class_name(classname)) != NULL) {
525                         printk(KERN_ERR
526                                "rbce ERROR: class %s exists in rbce after "
527                                "removal in core\n", classname);
528                 }
529         }
530         write_unlock(&global_rwlock);
531         return;
532 }
533
534 /*
535  * Allocate an index in the global term vector
536  * On success, returns the index. On failure returns -errno.
537  * Caller must hold the global_rwlock in write mode as global data is
538  * written onto.
539  */
540 static int alloc_term_index(void)
541 {
542         int size = gl_allocated;
543
544         if (gl_num_terms >= size) {
545                 int i;
546                 struct rbce_rule_term *oldv, *newv;
547                 int newsize = size + POLICY_INC_NUMTERMS;
548
549                 oldv = gl_terms;
550                 newv =
551                     kmalloc(newsize * sizeof(struct rbce_rule_term),
552                             GFP_ATOMIC);
553                 if (!newv) {
554                         return -ENOMEM;
555                 }
556                 memcpy(newv, oldv, size * sizeof(struct rbce_rule_term));
557                 for (i = size; i < newsize; i++) {
558                         newv[i].op = -1;
559                 }
560                 gl_terms = newv;
561                 gl_allocated = newsize;
562                 kfree(oldv);
563
564                 gl_action |= POLICY_ACTION_NEW_VERSION;
565                 DPRINTK(DBG_OPTIMIZATION,
566                         "alloc_term_index: Expanding size from %d to %d\n",
567                         size, newsize);
568         }
569         return gl_num_terms++;
570 }
571
572 /*
573  * Release an index in the global term vector
574  *
575  * Caller must hold the global_rwlock in write mode as the global data
576  * is written onto.
577  */
578 static void release_term_index(int idx)
579 {
580         if ((idx < 0) || (idx > gl_num_terms))
581                 return;
582
583         gl_terms[idx].op = -1;
584         gl_released++;
585         if ((gl_released > POLICY_INC_NUMTERMS) &&
586             (gl_allocated >
587              (gl_num_terms - gl_released + POLICY_INC_NUMTERMS))) {
588                 gl_action |= POLICY_ACTION_PACK_TERMS;
589         }
590         return;
591 }
592
593 /*
594  * Release the indices, string memory, and terms associated with the given
595  * rule.
596  *
597  * Caller should be holding global_rwlock
598  */
599 static void __release_rule(struct rbce_rule *rule)
600 {
601         int i, *terms = rule->terms;
602
603         // remove memory and references from other rules
604         for (i = rule->num_terms; --i >= 0;) {
605                 struct rbce_rule_term *term = &gl_terms[terms[i]];
606
607                 if (term->op == RBCE_RULE_DEP_RULE) {
608                         DEC_REF(term->u.deprule);
609                 }
610                 release_term_index(terms[i]);
611         }
612         rule->num_terms = 0;
613         if (rule->strtab) {
614                 kfree(rule->strtab);
615                 rule->strtab = NULL;
616         }
617         if (rule->terms) {
618                 kfree(rule->terms);
619                 rule->terms = NULL;
620         }
621         return;
622 }
623
624 /*
625  * delete the given rule and all memory associated with it.
626  *
627  * Caller is responsible for protecting the global data
628  */
629 static inline int __delete_rule(struct rbce_rule *rule)
630 {
631         // make sure we are not referenced by other rules
632         if (GET_REF(rule)) {
633                 return -EBUSY;
634         }
635         __release_rule(rule);
636         put_class(rule->target_class);
637         release_term_index(rule->index);
638         list_del(&rule->obj.link);
639         gl_num_rules--;
640         gl_rules_version++;
641         module_put(THIS_MODULE);
642         kfree(rule->obj.name);
643         kfree(rule);
644         return 0;
645 }
646
647 /*
648  * Optimize the rule evaluation logic
649  *
650  * Caller must hold global_rwlock in write mode.
651  */
652 static void optimize_policy(void)
653 {
654         int i, ii;
655         struct rbce_rule *rule;
656         struct rbce_rule_term *terms;
657         int num_terms;
658         int bsize;
659         bitvector_t **mask_vecs;
660         int pack_terms = 0;
661         int redoall;
662
663         /*
664          * Due to dynamic rule addition/deletion of rules the term
665          * vector can get sparse. As a result the bitvectors grow as we don't
666          * reuse returned indices. If it becomes sparse enough we pack them
667          * closer.
668          */
669
670         pack_terms = (gl_action & POLICY_ACTION_PACK_TERMS);
671         DPRINTK(DBG_OPTIMIZATION,
672                 "----- Optimize Policy ----- act=%x pt=%d (a=%d n=%d r=%d)\n",
673                 gl_action, pack_terms, gl_allocated, gl_num_terms, gl_released);
674
675         if (pack_terms) {
676                 int nsz = ALIGN((gl_num_terms - gl_released),
677                                 POLICY_INC_NUMTERMS);
678                 int newidx = 0;
679                 struct rbce_rule_term *newterms;
680
681                 terms = gl_terms;
682                 newterms =
683                     kmalloc(nsz * sizeof(struct rbce_rule_term), GFP_ATOMIC);
684                 if (newterms) {
685                         for (ii = 0; ii < CKRM_MAX_CLASSTYPES; ii++) {
686                                 // FIXME: check only for task class types
687                                 list_for_each_entry_reverse(rule,
688                                                             &rules_list[ii],
689                                                             obj.link) {
690                                         rule->index = newidx++;
691                                         for (i = rule->num_terms; --i >= 0;) {
692                                                 int idx = rule->terms[i];
693                                                 newterms[newidx] = terms[idx];
694                                                 rule->terms[i] = newidx++;
695                                         }
696                                 }
697                         }
698                         kfree(terms);
699                         gl_allocated = nsz;
700                         gl_released = 0;
701                         gl_num_terms = newidx;
702                         gl_terms = newterms;
703
704                         gl_action &= ~POLICY_ACTION_PACK_TERMS;
705                         gl_action |= POLICY_ACTION_NEW_VERSION;
706                 }
707         }
708
709         num_terms = gl_num_terms;
710         bsize = gl_allocated / 8 + sizeof(bitvector_t);
711         mask_vecs = gl_mask_vecs;
712         terms = gl_terms;
713
714         if (gl_action & POLICY_ACTION_NEW_VERSION) {
715                 /* allocate new mask vectors */
716                 char *temp = kmalloc(NUM_TERM_MASK_VECTOR * bsize, GFP_ATOMIC);
717
718                 DPRINTK(DBG_OPTIMIZATION,
719                         "------ allocmasks act=%x -------  ver=%d\n", gl_action,
720                         gl_bitmap_version);
721                 if (!temp) {
722                         return;
723                 }
724                 if (mask_vecs[0]) {// index 0 has the alloc returned address
725                         kfree(mask_vecs[0]);
726                 }
727                 for (i = 0; i < NUM_TERM_MASK_VECTOR; i++) {
728                         mask_vecs[i] = (bitvector_t *) (temp + i * bsize);
729                         bitvector_init(mask_vecs[i], gl_allocated);
730                 }
731                 gl_action &= ~POLICY_ACTION_NEW_VERSION;
732                 gl_action |= POLICY_ACTION_REDO_ALL;
733                 gl_bitmap_version++;
734         }
735
736         /* We do two things here at once
737          * 1) recompute the rulemask for each required rule
738          *      we guarantee proper dependency order during creation time and
739          *      by reversely running through this list. 
740          * 2) recompute the mask for each term and rule, if required
741          */
742
743         redoall = gl_action & POLICY_ACTION_REDO_ALL;
744         gl_action &= ~POLICY_ACTION_REDO_ALL;
745
746         DPRINTK(DBG_OPTIMIZATION, "------- run act=%x --------  redoall=%d\n",
747                 gl_action, redoall);
748         for (ii = 0; ii < CKRM_MAX_CLASSTYPES; ii++) {
749                 // FIXME: check only for task class types
750                 list_for_each_entry_reverse(rule, &rules_list[ii], obj.link) {
751                         unsigned long termflag;
752
753                         if (!redoall && !rule->do_opt)
754                                 continue;
755                         termflag = 0;
756                         for (i = rule->num_terms; --i >= 0;) {
757                                 int j, idx = rule->terms[i];
758                                 struct rbce_rule_term *term = &terms[idx];
759                                 int vecidx = termop_2_vecidx[term->op];
760                                 
761                                 if (vecidx == -1) {
762                                         termflag |= term->u.deprule->termflag;
763                                         /* mark this term belonging to all 
764                                            contexts of deprule */
765                                         for (j = 0; j < NUM_TERM_MASK_VECTOR;
766                                              j++) {
767                                                 if (term->u.deprule->termflag 
768                                                     & (1 << j)) {
769                                                         bitvector_set(idx,
770                                                                       mask_vecs
771                                                                       [j]);
772                                                 }
773                                         }
774                                 } else {
775                                         termflag |= TERM_2_TERMFLAG(vecidx);
776                                         /* mark this term belonging to 
777                                            a particular context */
778                                         bitvector_set(idx, mask_vecs[vecidx]);
779                                 }
780                         }
781                         for (i = 0; i < NUM_TERM_MASK_VECTOR; i++) {
782                                 if (termflag & (1 << i)) {
783                                         bitvector_set(rule->index,
784                                                       mask_vecs[i]);
785                                 }
786                         }
787                         rule->termflag = termflag;
788                         rule->do_opt = 0;
789                         DPRINTK(DBG_OPTIMIZATION, "r-%s: %x %d\n",
790                                 rule->obj.name, rule->termflag, rule->index);
791                 }
792         }
793         print_context_vectors();
794         return;
795 }
796
797 /* ======================= Rule related Functions ========================= */
798
799 /*
800  * Caller need to hold global_rwlock in write mode.
801  */
802 static int
803 fill_rule(struct rbce_rule *newrule, struct rbce_rule_term *terms, int nterms)
804 {
805         char *class, *strtab;
806         int i, j, order, state, real_nterms, index;
807         int strtablen, rc = 0, counter;
808         struct rbce_rule_term *term = NULL;
809         struct rbce_class *targetcls = NULL;
810         struct rbce_rule *deprule;
811
812         if (!newrule) {
813                 return -EINVAL;
814         }
815         // Digest filled terms.
816         real_nterms = 0;
817         strtab = class = NULL;
818         strtablen = 0;
819         state = -1;
820         order = -1;
821         index = -1;
822         for (i = 0; i < nterms; i++) {
823                 if (terms[i].op != RBCE_RULE_INVALID) {
824                         real_nterms++;
825
826                         switch (terms[i].op) {
827                         case RBCE_RULE_DEP_RULE:
828                                 // check if the depend rule is valid
829                                 //
830                                 deprule = find_rule_name(terms[i].u.string);
831                                 if (!deprule || deprule == newrule) {
832                                         rc = -EINVAL;
833                                         goto out;
834                                 } else {
835                                         // make sure _a_ depend rule 
836                                         // appears in only one term.
837                                         for (j = 0; j < i; j++) {
838                                                 if (terms[j].op ==
839                                                     RBCE_RULE_DEP_RULE
840                                                     && terms[j].u.deprule ==
841                                                     deprule) {
842                                                         rc = -EINVAL;
843                                                         goto out;
844                                                 }
845                                         }
846                                         terms[i].u.deprule = deprule;
847                                 }
848
849                                 // +depend is acceptable and -depend is not
850                                 if (terms[i].operator != TOKEN_OP_DEP_DEL) {
851                                         terms[i].operator = RBCE_EQUAL;
852                                 } else {
853                                         rc = -EINVAL;
854                                         goto out;
855                                 }
856                                 break;
857
858                         case RBCE_RULE_CMD_PATH:
859                         case RBCE_RULE_CMD:
860                         case RBCE_RULE_ARGS:
861                         case RBCE_RULE_APP_TAG:
862                         case RBCE_RULE_IPV4:
863                         case RBCE_RULE_IPV6:
864                                 // sum up the string length
865                                 strtablen += strlen(terms[i].u.string) + 1;
866                                 break;
867                         default:
868                                 break;
869
870                         }
871                 } else {
872                         switch (terms[i].operator) {
873                         case TOKEN_OP_ORDER:
874                                 order = terms[i].u.id;
875                                 if (order < 0) {
876                                         rc = -EINVAL;
877                                         goto out;
878                                 }
879                                 break;
880                         case TOKEN_OP_STATE:
881                                 state = terms[i].u.id != 0;
882                                 break;
883                         case TOKEN_OP_CLASS:
884                                 class = terms[i].u.string;
885                                 break;
886                         default:
887                                 break;
888                         }
889                 }
890         }
891
892         // Check if class was specified
893         if (class != NULL) {
894                 int classtype;
895                 if ((targetcls = get_class(class, &classtype)) == NULL) {
896                         rc = -EINVAL;
897                         goto out;
898                 }
899                 put_class(newrule->target_class);
900
901                 newrule->target_class = targetcls;
902                 newrule->classtype = classtype;
903         }
904         if (!newrule->target_class) {
905                 rc = -EINVAL;
906                 goto out;
907         }
908
909         if (state != -1) {
910                 newrule->state = state;
911         }
912         if (order != -1) {
913                 newrule->order = order;
914         }
915         newrule->terms = kmalloc(real_nterms * sizeof(int), GFP_ATOMIC);
916         if (!newrule->terms) {
917                 rc = -ENOMEM;
918                 goto out;
919         }
920         newrule->num_terms = real_nterms;
921         if (strtablen && ((strtab = kmalloc(strtablen, GFP_ATOMIC)) == NULL)) {
922                 rc = -ENOMEM;
923                 goto out;
924         }
925
926         if (newrule->index == -1) {
927                 index = alloc_term_index();
928                 if (index < 0) {
929                         rc = -ENOMEM;
930                         goto out;
931                 }
932                 newrule->index = index;
933                 term = &gl_terms[newrule->index];
934                 term->op = RBCE_RULE_DEP_RULE;
935                 term->u.deprule = newrule;
936         }
937         newrule->strtab = strtab;
938         newrule->termflag = 0;
939
940         // Fill the term vector
941         strtablen = 0;
942         counter = 0;
943         for (i = 0; i < nterms; i++) {
944                 if (terms[i].op == RBCE_RULE_INVALID) {
945                         continue;
946                 }
947
948                 newrule->terms[counter] = alloc_term_index();
949                 if (newrule->terms[counter] < 0) {
950                         for (j = 0; j < counter; j++) {
951                                 release_term_index(newrule->terms[j]);
952                         }
953                         rc = -ENOMEM;
954                         goto out;
955                 }
956                 term = &gl_terms[newrule->terms[counter]];
957                 term->op = terms[i].op;
958                 term->operator = terms[i].operator;
959                 switch (terms[i].op) {
960                 case RBCE_RULE_CMD_PATH:
961                 case RBCE_RULE_CMD:
962                 case RBCE_RULE_ARGS:
963                 case RBCE_RULE_APP_TAG:
964                 case RBCE_RULE_IPV4:
965                 case RBCE_RULE_IPV6:
966                         term->u.string = &strtab[strtablen];
967                         strcpy(term->u.string, terms[i].u.string);
968                         strtablen = strlen(term->u.string) + 1;
969                         break;
970
971                 case RBCE_RULE_REAL_UID:
972                 case RBCE_RULE_REAL_GID:
973                 case RBCE_RULE_EFFECTIVE_UID:
974                 case RBCE_RULE_EFFECTIVE_GID:
975                 case RBCE_RULE_XID:
976                         term->u.id = terms[i].u.id;
977                         break;
978
979                 case RBCE_RULE_DEP_RULE:
980                         term->u.deprule = terms[i].u.deprule;
981                         INC_REF(term->u.deprule);
982                         break;
983                 default:
984                         break;
985                 }
986                 counter++;
987         }
988
989       out:
990         if (rc) {
991                 if (targetcls) {
992                         put_class(targetcls);
993                 }
994                 if (index >= 0) {
995                         release_term_index(index);
996                 }
997                 kfree(newrule->terms);
998                 kfree(strtab);
999
1000         }
1001         return rc;
1002 }
1003
1004 int change_rule(const char *rname, char *rdefn)
1005 {
1006         struct rbce_rule *rule = NULL, *deprule;
1007         struct rbce_rule_term *new_terms = NULL, *term, *terms;
1008         int nterms, new_term_mask = 0, oterms, tot_terms;
1009         int i, j, k, rc, new_order = 0;
1010
1011         if ((nterms = rules_parse(rdefn, &new_terms, &new_term_mask)) <= 0) {
1012                 return !nterms ? -EINVAL : nterms;
1013         }
1014
1015         write_lock(&global_rwlock);
1016         rule = find_rule_name(rname);
1017         if (rule == NULL) {
1018                 rule = kmalloc(sizeof(struct rbce_rule), GFP_ATOMIC);
1019                 if (rule) {
1020                         rule->obj.name = kmalloc(strlen(rname) + 1, GFP_ATOMIC);
1021                         if (rule->obj.name) {
1022                                 strcpy(rule->obj.name, rname);
1023                                 GET_REF(rule) = 0;
1024                                 rule->order = -1;
1025                                 rule->index = -1;
1026                                 rule->state = RBCE_RULE_ENABLED;
1027                                 rule->target_class = NULL;
1028                                 rule->classtype = -1;
1029                                 rule->terms = NULL;
1030                                 rule->do_opt = 1;
1031                                 INIT_LIST_HEAD(&rule->obj.link);
1032                                 rc = fill_rule(rule, new_terms, nterms);
1033                                 if (rc) {
1034                                         kfree(rule);
1035                                 } else {
1036                                         if ((rc =
1037                                              insert_rule(rule,
1038                                                          rule->order)) == 0) {
1039                                                 if (rbce_enabled) {
1040                                                         optimize_policy();
1041                                                 }
1042                                         } else {
1043                                                 __delete_rule(rule);
1044                                         }
1045                                 }
1046                         } else {
1047                                 kfree(rule);
1048                                 rc = -ENOMEM;
1049                         }
1050                         kfree(new_terms);
1051                 } else {
1052                         rc = -ENOMEM;
1053                 }
1054                 write_unlock(&global_rwlock);
1055                 return rc;
1056         }
1057
1058         oterms = rule->num_terms;
1059         tot_terms = nterms + oterms;
1060
1061         terms = kmalloc(tot_terms * sizeof(struct rbce_rule_term), GFP_ATOMIC);
1062
1063         if (!terms) {
1064                 kfree(new_terms);
1065                 write_unlock(&global_rwlock);
1066                 return -ENOMEM;
1067         }
1068
1069         new_term_mask &= ~(1 << RBCE_RULE_DEP_RULE);
1070         //ignore the new deprule terms for the first iteration.
1071         // taken care of later.
1072         for (i = 0; i < oterms; i++) {
1073                 term = &gl_terms[rule->terms[i]];       // old term
1074
1075                 if ((1 << term->op) & new_term_mask) {  
1076                         // newrule has this attr/value
1077                         for (j = 0; j < nterms; j++) {
1078                                 if (term->op == new_terms[j].op) {
1079                                         terms[i].op = new_terms[j].op;
1080                                         terms[i].operator = new_terms[j].
1081                                             operator;
1082                                         terms[i].u.string =
1083                                             new_terms[j].u.string;
1084                                         new_terms[j].op = RBCE_RULE_INVALID2;
1085                                         break;
1086                                 }
1087                         }
1088                 } else {
1089                         terms[i].op = term->op;
1090                         terms[i].operator = term->operator;
1091                         terms[i].u.string = term->u.string;
1092                 }
1093         }
1094
1095         i = oterms;             // for readability
1096
1097         for (j = 0; j < nterms; j++) {
1098                 // handled in the previous iteration
1099                 if (new_terms[j].op == RBCE_RULE_INVALID2) {
1100                         continue;
1101                 }
1102
1103                 if (new_terms[j].op == RBCE_RULE_DEP_RULE) {
1104                         if (new_terms[j].operator == TOKEN_OP_DEP) {
1105                                 // "depend=rule" deletes all depends in the 
1106                                 // original rule so, delete all depend rule 
1107                                 // terms in the original rule
1108                                 for (k = 0; k < oterms; k++) {
1109                                         if (terms[k].op == RBCE_RULE_DEP_RULE) {
1110                                                 terms[k].op = RBCE_RULE_INVALID;
1111                                         }
1112                                 }
1113                                 // must copy the new deprule term
1114                         } else {
1115                                 // delete the depend rule term if was defined 
1116                                 // in the original rule for both +depend 
1117                                 // and -depend
1118                                 deprule = find_rule_name(new_terms[j].u.string);
1119                                 if (deprule) {
1120                                         for (k = 0; k < oterms; k++) {
1121                                                 if (terms[k].op ==
1122                                                     RBCE_RULE_DEP_RULE
1123                                                     && terms[k].u.deprule ==
1124                                                     deprule) {
1125                                                         terms[k].op =
1126                                                             RBCE_RULE_INVALID;
1127                                                         break;
1128                                                 }
1129                                         }
1130                                 }
1131                                 if (new_terms[j].operator == TOKEN_OP_DEP_DEL) {
1132                                         // No need to copy the new deprule term
1133                                         continue;
1134                                 }
1135                         }
1136                 } else {
1137                         if ((new_terms[j].op == RBCE_RULE_INVALID) &&
1138                             (new_terms[j].operator == TOKEN_OP_ORDER)) {
1139                                 new_order++;
1140                         }
1141                 }
1142                 terms[i].op = new_terms[j].op;
1143                 terms[i].operator = new_terms[j].operator;
1144                 terms[i].u.string = new_terms[j].u.string;
1145                 i++;
1146                 new_terms[j].op = RBCE_RULE_INVALID2;
1147         }
1148
1149         tot_terms = i;
1150
1151         // convert old deprule pointers to name pointers.
1152         for (i = 0; i < oterms; i++) {
1153                 if (terms[i].op != RBCE_RULE_DEP_RULE)
1154                         continue;
1155                 terms[i].u.string = terms[i].u.deprule->obj.name;
1156         }
1157
1158         // release the rule
1159         __release_rule(rule);
1160
1161         rule->do_opt = 1;
1162         rc = fill_rule(rule, terms, tot_terms);
1163         if (rc == 0 && new_order) {
1164                 rc = reinsert_rule(rule, rule->order);
1165         }
1166         if (rc != 0) {          // rule creation/insertion failed
1167                 __delete_rule(rule);
1168         }
1169         if (rbce_enabled) {
1170                 optimize_policy();
1171         }
1172         write_unlock(&global_rwlock);
1173         kfree(new_terms);
1174         kfree(terms);
1175         return rc;
1176 }
1177
1178 /*
1179  * Delete the specified rule.
1180  *
1181  */
1182 int delete_rule(const char *rname)
1183 {
1184         int rc = 0;
1185         struct rbce_rule *rule;
1186
1187         write_lock(&global_rwlock);
1188
1189         if ((rule = find_rule_name(rname)) == NULL) {
1190                 write_unlock(&global_rwlock);
1191                 goto out;
1192         }
1193         rc = __delete_rule(rule);
1194         if (rbce_enabled && (gl_action & POLICY_ACTION_PACK_TERMS)) {
1195                 optimize_policy();
1196         }
1197         write_unlock(&global_rwlock);
1198       out:
1199         DPRINTK(DBG_RULE, "delete rule %s\n", rname);
1200         return rc;
1201 }
1202
1203 /*
1204  * copy the rule specified by rname and to the given result string.
1205  *
1206  */
1207 void get_rule(const char *rname, char *result)
1208 {
1209         int i;
1210         struct rbce_rule *rule;
1211         struct rbce_rule_term *term;
1212         char *cp = result, oper, idtype[3], str[5];
1213
1214         read_lock(&global_rwlock);
1215
1216         rule = find_rule_name(rname);
1217         if (rule != NULL) {
1218                 for (i = 0; i < rule->num_terms; i++) {
1219                         term = gl_terms + rule->terms[i];
1220                         switch (term->op) {
1221                         case RBCE_RULE_REAL_UID:
1222                                 strcpy(idtype, "u");
1223                                 goto handleid;
1224                         case RBCE_RULE_REAL_GID:
1225                                 strcpy(idtype, "g");
1226                                 goto handleid;
1227                         case RBCE_RULE_EFFECTIVE_UID:
1228                                 strcpy(idtype, "eu");
1229                                 goto handleid;
1230                         case RBCE_RULE_EFFECTIVE_GID:
1231                                 strcpy(idtype, "eg");
1232                                 goto handleid;
1233                         case RBCE_RULE_XID:
1234                                 strcpy(idtype, "x");
1235                               handleid:
1236                                 if (term->operator == RBCE_LESS_THAN) {
1237                                         oper = '<';
1238                                 } else if (term->operator == RBCE_GREATER_THAN) {
1239                                         oper = '>';
1240                                 } else if (term->operator == RBCE_NOT) {
1241                                         oper = '!';
1242                                 } else {
1243                                         oper = '=';
1244                                 }
1245                                 cp +=
1246                                     sprintf(cp, "%sid%c%ld,", idtype, oper,
1247                                             term->u.id);
1248                                 break;
1249                         case RBCE_RULE_CMD_PATH:
1250                                 strcpy(str, "path");
1251                                 goto handle_str;
1252                         case RBCE_RULE_CMD:
1253                                 strcpy(str, "cmd");
1254                                 goto handle_str;
1255                         case RBCE_RULE_ARGS:
1256                                 strcpy(str, "args");
1257                                 goto handle_str;
1258                         case RBCE_RULE_APP_TAG:
1259                                 strcpy(str, "tag");
1260                                 goto handle_str;
1261                         case RBCE_RULE_IPV4:
1262                                 strcpy(str, "ipv4");
1263                                 goto handle_str;
1264                         case RBCE_RULE_IPV6:
1265                                 strcpy(str, "ipv6");
1266                               handle_str:
1267                                 cp +=
1268                                     sprintf(cp, "%s=%s,", str, term->u.string);
1269                                 break;
1270                         case RBCE_RULE_DEP_RULE:
1271                                 cp +=
1272                                     sprintf(cp, "depend=%s,",
1273                                             term->u.deprule->obj.name);
1274                                 break;
1275                         default:
1276                                 break;
1277                         }
1278                 }
1279                 if (!rule->num_terms) {
1280                         cp += sprintf(cp, "***** no terms defined ***** ");
1281                 }
1282
1283                 cp +=
1284                     sprintf(cp, "order=%d,state=%d,", rule->order, rule->state);
1285                 cp +=
1286                     sprintf(cp, "class=%s",
1287                             rule->target_class ? rule->target_class->obj.
1288                             name : "***** REMOVED *****");
1289                 *cp = '\0';
1290         } else {
1291                 sprintf(result, "***** Rule %s doesn't exist *****", rname);
1292         }
1293
1294         read_unlock(&global_rwlock);
1295         return;
1296 }
1297
1298 /*
1299  * Change the name of the given rule "from_rname" to "to_rname"
1300  *
1301  */
1302 int rename_rule(const char *from_rname, const char *to_rname)
1303 {
1304         struct rbce_rule *rule;
1305         int nlen, rc = -EINVAL;
1306
1307         if (!to_rname || !*to_rname) {
1308                 return rc;
1309         }
1310         write_lock(&global_rwlock);
1311
1312         rule = find_rule_name(from_rname);
1313         if (rule != NULL) {
1314                 if ((nlen = strlen(to_rname)) > strlen(rule->obj.name)) {
1315                         char *name = kmalloc(nlen + 1, GFP_ATOMIC);
1316                         if (!name) {
1317                                 return -ENOMEM;
1318                         }
1319                         kfree(rule->obj.name);
1320                         rule->obj.name = name;
1321                 }
1322                 strcpy(rule->obj.name, to_rname);
1323                 rc = 0;
1324         }
1325         write_unlock(&global_rwlock);
1326         return rc;
1327 }
1328
1329 /*
1330  * Return TRUE if the given rule exists, FALSE otherwise
1331  *
1332  */
1333 int rule_exists(const char *rname)
1334 {
1335         struct rbce_rule *rule;
1336
1337         read_lock(&global_rwlock);
1338         rule = find_rule_name(rname);
1339         read_unlock(&global_rwlock);
1340         return rule != NULL;
1341 }
1342
1343 /*====================== Magic file handling =======================*/
1344 /*
1345  * Reclassify
1346  */
1347 static struct rbce_private_data *create_private_data(struct rbce_private_data *,
1348                                                      int);
1349
1350 static inline
1351 void reset_evaluation(struct rbce_private_data *pdata,int termflag)
1352 {
1353         /* reset TAG ruleterm evaluation results to pick up 
1354          * on next classification event
1355          */
1356         if (use_persistent_state && gl_mask_vecs[termflag]) {
1357                 bitvector_and_not( pdata->eval, pdata->eval, 
1358                                    gl_mask_vecs[termflag] );
1359                 bitvector_and_not( pdata->true, pdata->true, 
1360                                    gl_mask_vecs[termflag] );
1361         }
1362 }
1363   
1364 int set_tasktag(int pid, char *tag)
1365 {
1366         char *tp;
1367         int rc = 0;
1368         struct task_struct *tsk;
1369         struct rbce_private_data *pdata;
1370         int len;
1371
1372         if (!tag) {
1373                 return -EINVAL;
1374         }
1375         len = strlen(tag) + 1;
1376         tp = kmalloc(len, GFP_ATOMIC);
1377         if (!tp) {
1378                 return -ENOMEM;
1379         }
1380         strncpy(tp,tag,len);
1381
1382         read_lock(&tasklist_lock);
1383         if ((tsk = find_task_by_pid(pid)) == NULL) {
1384                 rc = -EINVAL;
1385                 goto out;
1386         }
1387
1388         if (unlikely(!RBCE_DATA(tsk))) {
1389                 RBCE_DATAP(tsk) = create_private_data(NULL, 0);
1390                 if (!RBCE_DATA(tsk)) {
1391                         rc = -ENOMEM;
1392                         goto out;
1393                 }
1394         }
1395         pdata = RBCE_DATA(tsk);
1396         if (pdata->app_tag) {
1397                 kfree(pdata->app_tag);
1398         }
1399         pdata->app_tag = tp;
1400         reset_evaluation(pdata,RBCE_TERMFLAG_TAG);
1401         
1402  out:
1403         read_unlock(&tasklist_lock);
1404         if (rc != 0) 
1405                 kfree(tp);
1406         return rc;
1407 }
1408
1409 /*====================== Classification Functions =======================*/
1410
1411 /*
1412  * Match the given full path name with the command expression.
1413  * This function treats the folowing 2 charaters as special if seen in
1414  * cmd_exp, all other chanracters are compared as is:
1415  *              ? - compares to any one single character
1416  *              * - compares to one or more single characters
1417  *
1418  * If fullpath is 1, tsk_comm is compared in full. otherwise only the command
1419  * name (basename(tsk_comm)) is compared.
1420  */
1421 static int match_cmd(const char *tsk_comm, const char *cmd_exp, int fullpath)
1422 {
1423         const char *c, *t, *last_ast, *cmd = tsk_comm;
1424         char next_c;
1425
1426         // get the command name if we don't have to match the fullpath
1427         if (!fullpath && ((c = strrchr(tsk_comm, '/')) != NULL)) {
1428                 cmd = c + 1;
1429         }
1430
1431         /* now faithfully assume the entire pathname is in cmd */
1432
1433         /* we now have to effectively implement a regular expression 
1434          * for now assume 
1435          *    '?'   any single character 
1436          *    '*'   one or more '?'
1437          *    rest  must match
1438          */
1439
1440         c = cmd_exp;
1441         t = cmd;
1442         if (t == NULL || c == NULL) {
1443                 return 0;
1444         }
1445
1446         last_ast = NULL;
1447         next_c = '\0';
1448
1449         while (*c && *t) {
1450                 switch (*c) {
1451                 case '?':
1452                         if (*t == '/') {
1453                                 return 0;
1454                         }
1455                         c++;
1456                         t++;
1457                         continue;
1458                 case '*':
1459                         if (*t == '/') {
1460                                 return 0;
1461                         }
1462                         // eat up all '*' in c
1463                         while (*(c + 1) == '*')
1464                                 c++;
1465                         next_c = '\0';
1466                         last_ast = c;
1467                         //t++;  // Add this for matching '*' with "one" 
1468                                 // or more chars.
1469                         while (*t && (*t != *(c + 1)) && *t != '/')
1470                                 t++;
1471                         if (*t == *(c + 1)) {
1472                                 c++;
1473                                 if (*c != '/') {
1474                                         if (*c == '?') {
1475                                                 if (*t == '/') {
1476                                                         return 0;
1477                                                 }
1478                                                 t++;
1479                                                 c++;
1480                                         }
1481                                         next_c = *c;
1482                                         if (*c) {
1483                                                 if (*t == '/') {
1484                                                         return 0;
1485                                                 }
1486                                                 t++;
1487                                                 c++;
1488                                                 if (!*c && *t)
1489                                                         c = last_ast;
1490                                         }
1491                                 } else {
1492                                         last_ast = NULL;
1493                                 }
1494                                 continue;
1495                         }
1496                         return 0;
1497                 case '/':
1498                         next_c = '\0';
1499                  /*FALLTHRU*/ default:
1500                         if (*t == *c && next_c != *t) {
1501                                 c++, t++;
1502                                 continue;
1503                         } else {
1504                                 /* reset to last asterix and 
1505                                    continue from there */
1506                                 if (last_ast) {
1507                                         c = last_ast;
1508                                 } else {
1509                                         return 0;
1510                                 }
1511                         }
1512                 }
1513         }
1514
1515         /* check for trailing "*" */
1516         while (*c == '*')
1517                 c++;
1518
1519         return (!*c && !*t);
1520 }
1521
1522 static void reverse(char *str, int n)
1523 {
1524         char s;
1525         int i, j = n - 1;
1526
1527         for (i = 0; i < j; i++, j--) {
1528                 s = str[i];
1529                 str[i] = str[j];
1530                 str[j] = s;
1531         }
1532 }
1533
1534 static int itoa(int n, char *str)
1535 {
1536         int i = 0, sz = 0;
1537
1538         do {
1539                 str[i++] = n % 10 + '0';
1540                 sz++;
1541                 n = n / 10;
1542         } while (n > 0);
1543
1544         (void)reverse(str, sz);
1545         return sz;
1546 }
1547
1548 static int v4toa(__u32 y, char *a)
1549 {
1550         int i;
1551         int size = 0;
1552
1553         for (i = 0; i < 4; i++) {
1554                 size += itoa(y & 0xff, &a[size]);
1555                 a[size++] = '.';
1556                 y >>= 8;
1557         }
1558         return --size;
1559 }
1560
1561 int match_ipv4(struct ckrm_net_struct *ns, char **string)
1562 {
1563         char *ptr = *string;
1564         int size;
1565         char a4[16];
1566
1567         size = v4toa(ns->ns_daddrv4, a4);
1568
1569         *string += size;
1570         return !strncmp(a4, ptr, size);
1571 }
1572
1573 int match_port(struct ckrm_net_struct *ns, char *ptr)
1574 {
1575         char a[5];
1576         int size = itoa(ns->ns_dport, a);
1577
1578         return !strncmp(a, ptr, size);
1579 }
1580
1581 static int __evaluate_rule(struct task_struct *tsk, struct ckrm_net_struct *ns,
1582                            struct rbce_rule *rule, bitvector_t * vec_eval,
1583                            bitvector_t * vec_true, char **filename);
1584 /*
1585  * evaluate the given task against the given rule with the vec_eval and
1586  * vec_true in context. Return 1 if the task satisfies the given rule, 0
1587  * otherwise.
1588  *
1589  * If the bit corresponding to the rule is set in the vec_eval, then the
1590  * corresponding bit in vec_true is the result. If it is not set, evaluate
1591  * the rule and set the bits in both the vectors accordingly.
1592  *
1593  * On return, filename will have the pointer to the pathname of the task's
1594  * executable, if the rule had any command related terms.
1595  *
1596  * Caller must hold the global_rwlock atleast in read mode.
1597  */
1598 static inline int
1599 evaluate_rule(struct task_struct *tsk, struct ckrm_net_struct *ns,
1600               struct rbce_rule *rule, bitvector_t * vec_eval,
1601               bitvector_t * vec_true, char **filename)
1602 {
1603         int tidx = rule->index;
1604
1605         if (!bitvector_test(tidx, vec_eval)) {
1606                 if (__evaluate_rule
1607                     (tsk, ns, rule, vec_eval, vec_true, filename)) {
1608                         bitvector_set(tidx, vec_true);
1609                 }
1610                 bitvector_set(tidx, vec_eval);
1611         }
1612         return bitvector_test(tidx, vec_true);
1613 }
1614
1615 /*
1616  * evaluate the given task against every term in the given rule with
1617  * vec_eval and vec_true in context.
1618  *
1619  * If the bit corresponding to a rule term is set in the vec_eval, then the
1620  * corresponding bit in vec_true is the result for taht particular. If it is
1621  * not set, evaluate the rule term and set the bits in both the vectors
1622  * accordingly.
1623  *
1624  * This fucntions returns true only if all terms in the rule evaluate true.
1625  *
1626  * On return, filename will have the pointer to the pathname of the task's
1627  * executable, if the rule had any command related terms.
1628  *
1629  * Caller must hold the global_rwlock atleast in read mode.
1630  */
1631 static int
1632 __evaluate_rule(struct task_struct *tsk, struct ckrm_net_struct *ns,
1633                 struct rbce_rule *rule, bitvector_t * vec_eval,
1634                 bitvector_t * vec_true, char **filename)
1635 {
1636         int i;
1637         int no_ip = 1;
1638
1639         for (i = rule->num_terms; --i >= 0;) {
1640                 int rc = 1, tidx = rule->terms[i];
1641
1642                 if (!bitvector_test(tidx, vec_eval)) {
1643                         struct rbce_rule_term *term = &gl_terms[tidx];
1644
1645                         switch (term->op) {
1646
1647                         case RBCE_RULE_CMD_PATH:
1648                         case RBCE_RULE_CMD:
1649 #if 0
1650                                 if (!*filename) {       /* get this once */
1651                                         if (((*filename =
1652                                               kmalloc(NAME_MAX,
1653                                                       GFP_ATOMIC)) == NULL)
1654                                             ||
1655                                             (get_exe_path_name
1656                                              (tsk, *filename, NAME_MAX) < 0)) {
1657                                                 rc = 0;
1658                                                 break;
1659                                         }
1660                                 }
1661                                 rc = match_cmd(*filename, term->u.string,
1662                                                (term->op ==
1663                                                 RBCE_RULE_CMD_PATH));
1664 #else
1665                                 rc = match_cmd(tsk->comm, term->u.string,
1666                                                (term->op ==
1667                                                 RBCE_RULE_CMD_PATH));
1668 #endif
1669                                 break;
1670                         case RBCE_RULE_REAL_UID:
1671                                 if (term->operator == RBCE_LESS_THAN) {
1672                                         rc = (tsk->uid < term->u.id);
1673                                 } else if (term->operator == RBCE_GREATER_THAN){
1674                                         rc = (tsk->uid > term->u.id);
1675                                 } else if (term->operator == RBCE_NOT) {
1676                                         rc = (tsk->uid != term->u.id);
1677                                 } else {
1678                                         rc = (tsk->uid == term->u.id);
1679                                 }
1680                                 break;
1681                         case RBCE_RULE_REAL_GID:
1682                                 if (term->operator == RBCE_LESS_THAN) {
1683                                         rc = (tsk->gid < term->u.id);
1684                                 } else if (term->operator == RBCE_GREATER_THAN){
1685                                         rc = (tsk->gid > term->u.id);
1686                                 } else if (term->operator == RBCE_NOT) {
1687                                         rc = (tsk->gid != term->u.id);
1688                                 } else {
1689                                         rc = (tsk->gid == term->u.id);
1690                                 }
1691                                 break;
1692                         case RBCE_RULE_EFFECTIVE_UID:
1693                                 if (term->operator == RBCE_LESS_THAN) {
1694                                         rc = (tsk->euid < term->u.id);
1695                                 } else if (term->operator == RBCE_GREATER_THAN){
1696                                         rc = (tsk->euid > term->u.id);
1697                                 } else if (term->operator == RBCE_NOT) {
1698                                         rc = (tsk->euid != term->u.id);
1699                                 } else {
1700                                         rc = (tsk->euid == term->u.id);
1701                                 }
1702                                 break;
1703                         case RBCE_RULE_EFFECTIVE_GID:
1704                                 if (term->operator == RBCE_LESS_THAN) {
1705                                         rc = (tsk->egid < term->u.id);
1706                                 } else if (term->operator == RBCE_GREATER_THAN){
1707                                         rc = (tsk->egid > term->u.id);
1708                                 } else if (term->operator == RBCE_NOT) {
1709                                         rc = (tsk->egid != term->u.id);
1710                                 } else {
1711                                         rc = (tsk->egid == term->u.id);
1712                                 }
1713                                 break;
1714                         case RBCE_RULE_APP_TAG:
1715                                 rc = (RBCE_DATA(tsk)
1716                                       && RBCE_DATA(tsk)->
1717                                       app_tag) ? !strcmp(RBCE_DATA(tsk)->
1718                                                          app_tag,
1719                                                          term->u.string) : 0;
1720                                 break;
1721                         case RBCE_RULE_DEP_RULE:
1722                                 rc = evaluate_rule(tsk, NULL, term->u.deprule,
1723                                                    vec_eval, vec_true,
1724                                                    filename);
1725                                 break;
1726
1727                         case RBCE_RULE_IPV4:
1728                                 // TBD: add NOT_EQUAL match. At present rbce
1729                                 // recognises EQUAL matches only.
1730                                 if (ns && term->operator == RBCE_EQUAL) {
1731                                         int ma = 0;
1732                                         int mp = 0;
1733                                         char *ptr = term->u.string;
1734
1735                                         if (term->u.string[0] == '*')
1736                                                 ma = 1;
1737                                         else
1738                                                 ma = match_ipv4(ns, &ptr);
1739
1740                                         if (*ptr != '\\') {     // error
1741                                                 rc = 0;
1742                                                 break;
1743                                         } else {
1744                                                 ++ptr;
1745                                                 if (*ptr == '*')
1746                                                         mp = 1;
1747                                                 else
1748                                                         mp = match_port(ns,
1749                                                                         ptr);
1750                                         }
1751                                         rc = mp && ma;
1752                                 } else
1753                                         rc = 0;
1754                                 no_ip = 0;
1755                                 break;
1756
1757                         case RBCE_RULE_IPV6:    // no support yet
1758                                 rc = 0;
1759                                 no_ip = 0;
1760                                 break;
1761
1762                         case RBCE_RULE_XID:
1763                         {
1764                                 xid_t xid = vx_task_xid(tsk);
1765
1766                                 if (term->operator == RBCE_LESS_THAN) {
1767                                         rc = (xid < term->u.id);
1768                                 } else if (term->operator == RBCE_GREATER_THAN) {
1769                                         rc = (xid > term->u.id);
1770                                 } else if (term->operator == RBCE_NOT) {
1771                                         rc = (xid != term->u.id);
1772                                 } else {
1773                                         rc = (xid == term->u.id);
1774                                 }
1775                                 break;
1776                         }
1777                                 
1778                         default:
1779                                 rc = 0;
1780                                 printk(KERN_ERR "Error evaluate term op=%d\n",
1781                                        term->op);
1782                                 break;
1783                         }
1784                         if (!rc && no_ip) {
1785                                 bitvector_clear(tidx, vec_true);
1786                         } else {
1787                                 bitvector_set(tidx, vec_true);
1788                         }
1789                         bitvector_set(tidx, vec_eval);
1790                 } else {
1791                         rc = bitvector_test(tidx, vec_true);
1792                 }
1793                 if (!rc) {
1794                         return 0;
1795                 }
1796         }
1797         return 1;
1798 }
1799
1800 //#define PDATA_DEBUG
1801 #ifdef PDATA_DEBUG
1802
1803 #define MAX_PDATA 10000
1804 void *pdata_arr[MAX_PDATA];
1805 int pdata_count, pdata_next;
1806 static spinlock_t pdata_lock = SPIN_LOCK_UNLOCKED;
1807
1808 static inline int valid_pdata(struct rbce_private_data *pdata)
1809 {
1810         int i;
1811
1812         if (!pdata) {
1813                 return 1;
1814         }
1815         spin_lock(&pdata_lock);
1816         for (i = 0; i < MAX_PDATA; i++) {
1817                 if (pdata_arr[i] == pdata) {
1818                         spin_unlock(&pdata_lock);
1819                         return 1;
1820                 }
1821         }
1822         spin_unlock(&pdata_lock);
1823         printk(KERN_WARNING "INVALID/CORRUPT PDATA %p\n", pdata);
1824         return 0;
1825 }
1826
1827 static inline void store_pdata(struct rbce_private_data *pdata)
1828 {
1829         int i = 0;
1830
1831         if (pdata) {
1832                 spin_lock(&pdata_lock);
1833
1834                 while (i < MAX_PDATA) {
1835                         if (pdata_arr[pdata_next] == NULL) {
1836                                 printk(KERN_DEBUG "storing %p at %d, count %d\n", pdata,
1837                                        pdata_next, pdata_count);
1838                                 pdata_arr[pdata_next++] = pdata;
1839                                 if (pdata_next == MAX_PDATA) {
1840                                         pdata_next = 0;
1841                                 }
1842                                 pdata_count++;
1843                                 break;
1844                         }
1845                         pdata_next++;
1846                         i++;
1847                 }
1848                 spin_unlock(&pdata_lock);
1849         }
1850         if (i == MAX_PDATA) {
1851                 printk(KERN_DEBUG "PDATA BUFFER FULL pdata_count %d pdata %p\n",
1852                        pdata_count, pdata);
1853         }
1854 }
1855
1856 static inline void unstore_pdata(struct rbce_private_data *pdata)
1857 {
1858         int i;
1859         if (pdata) {
1860                 spin_lock(&pdata_lock);
1861                 for (i = 0; i < MAX_PDATA; i++) {
1862                         if (pdata_arr[i] == pdata) {
1863                                 printk(KERN_DEBUG "unstoring %p at %d, count %d\n", pdata,
1864                                        i, pdata_count);
1865                                 pdata_arr[i] = NULL;
1866                                 pdata_count--;
1867                                 pdata_next = i;
1868                                 break;
1869                         }
1870                 }
1871                 spin_unlock(&pdata_lock);
1872                 if (i == MAX_PDATA) {
1873                         printk(KERN_DEBUG "pdata %p not found in the stored array\n",
1874                                pdata);
1875                 }
1876         }
1877         return;
1878 }
1879
1880 #else                           // PDATA_DEBUG
1881
1882 #define valid_pdata(pdata) (1)
1883 #define store_pdata(pdata)
1884 #define unstore_pdata(pdata)
1885
1886 #endif                          // PDATA_DEBUG
1887
1888 /*
1889  * Allocate and initialize a rbce_private_data data structure.
1890  *
1891  * Caller must hold global_rwlock atleast in read mode.
1892  */
1893
1894 static inline void
1895 copy_ext_private_data(struct rbce_private_data *src,
1896                       struct rbce_private_data *dst)
1897 {
1898         if (src)
1899                 dst->ext_data = src->ext_data;
1900         else
1901                 memset(&dst->ext_data, 0, sizeof(dst->ext_data));
1902 }
1903
1904 static struct rbce_private_data *create_private_data(struct rbce_private_data
1905                                                      *src, int copy_sample)
1906 {
1907         int vsize, psize, bsize;
1908         struct rbce_private_data *pdata;
1909
1910         if (use_persistent_state) {
1911                 vsize = gl_allocated;
1912                 bsize = vsize / 8 + sizeof(bitvector_t);
1913                 psize = sizeof(struct rbce_private_data) + 2 * bsize;
1914         } else {
1915                 psize = sizeof(struct rbce_private_data);
1916         }
1917
1918         pdata = kmalloc(psize, GFP_ATOMIC);
1919         if (pdata != NULL) {
1920                 if (use_persistent_state) {
1921                         pdata->bitmap_version = gl_bitmap_version;
1922                         pdata->eval = (bitvector_t *) & pdata->data[0];
1923                         pdata->true = (bitvector_t *) & pdata->data[bsize];
1924                         if (src && (src->bitmap_version == gl_bitmap_version)) {
1925                                 memcpy(pdata->data, src->data, 2 * bsize);
1926                         } else {
1927                                 bitvector_init(pdata->eval, vsize);
1928                                 bitvector_init(pdata->true, vsize);
1929                         }
1930                 }
1931                 copy_ext_private_data(src, pdata);
1932                 //if (src) { // inherit evaluate and app_tag
1933                 //      pdata->evaluate = src->evaluate;
1934                 //      if(src->app_tag) {
1935                 //              int len = strlen(src->app_tag)+1;
1936                 //              printk(KERN_DEBUG "CREATE_PRIVATE: apptag %s len %d\n",
1937                 //                          src->app_tag,len);
1938                 //              pdata->app_tag = kmalloc(len, GFP_ATOMIC);
1939                 //              if (pdata->app_tag) {
1940                 //                      strcpy(pdata->app_tag, src->app_tag);
1941                 //              }
1942                 //      }
1943                 //} else {
1944                 pdata->evaluate = 1;
1945                 pdata->rules_version = src ? src->rules_version : 0;
1946                 pdata->app_tag = NULL;
1947                 //}
1948         }
1949         store_pdata(pdata);
1950         return pdata;
1951 }
1952
1953 static inline void free_private_data(struct rbce_private_data *pdata)
1954 {
1955         if (valid_pdata(pdata)) {
1956                 unstore_pdata(pdata);
1957                 kfree(pdata);
1958         }
1959 }
1960
1961 static void free_all_private_data(void)
1962 {
1963         struct task_struct *proc, *thread;
1964
1965         read_lock(&tasklist_lock);
1966         do_each_thread(proc, thread) {
1967                 struct rbce_private_data *pdata;
1968
1969                 pdata = RBCE_DATA(thread);
1970                 RBCE_DATAP(thread) = NULL;
1971                 free_private_data(pdata);
1972         } while_each_thread(proc, thread);
1973         read_unlock(&tasklist_lock);
1974         return;
1975 }
1976
1977 /*
1978  * reclassify function, which is called by all the callback functions.
1979  *
1980  * Takes that task to be reclassified and ruleflags that indicates the
1981  * attributes that caused this reclassification request.
1982  *
1983  * On success, returns the core class pointer to which the given task should
1984  * belong to.
1985  */
1986 static struct ckrm_core_class *rbce_classify(struct task_struct *tsk,
1987                                              struct ckrm_net_struct *ns,
1988                                              unsigned long termflag,
1989                                              int classtype)
1990 {
1991         int i;
1992         struct rbce_rule *rule;
1993         bitvector_t *vec_true = NULL, *vec_eval = NULL;
1994         struct rbce_class *tgt = NULL;
1995         struct ckrm_core_class *cls = NULL;
1996         char *filename = NULL;
1997
1998         if (!valid_pdata(RBCE_DATA(tsk))) {
1999                 return NULL;
2000         }
2001         if (classtype >= CKRM_MAX_CLASSTYPES) {
2002                 // can't handle more than CKRM_MAX_CLASSTYPES
2003                 return NULL;
2004         }
2005         // fast path to avoid locking in case CE is not enabled or if no rules
2006         // are defined or if the tasks states that no evaluation is needed.
2007         if (!rbce_enabled || !gl_num_rules ||
2008             (RBCE_DATA(tsk) && !RBCE_DATA(tsk)->evaluate)) {
2009                 return NULL;
2010         }
2011         // FIXME: optimize_policy should be called from here if
2012         // gl_action is non-zero. Also, it has to be called with the
2013         // global_rwlock held in write mode.
2014
2015         read_lock(&global_rwlock);
2016
2017         vec_eval = vec_true = NULL;
2018         if (use_persistent_state) {
2019                 struct rbce_private_data *pdata = RBCE_DATA(tsk);
2020
2021                 if (!pdata
2022                     || (pdata
2023                         && (gl_bitmap_version != pdata->bitmap_version))) {
2024                         struct rbce_private_data *new_pdata =
2025                             create_private_data(pdata, 1);
2026
2027                         if (new_pdata) {
2028                                 if (pdata) {
2029                                         new_pdata->rules_version =
2030                                             pdata->rules_version;
2031                                         new_pdata->evaluate = pdata->evaluate;
2032                                         new_pdata->app_tag = pdata->app_tag;
2033                                         free_private_data(pdata);
2034                                 }
2035                                 pdata = RBCE_DATAP(tsk) = new_pdata;
2036                                 termflag = RBCE_TERMFLAG_ALL;   
2037                                 // need to evaluate them all
2038                         } else {
2039                                 // we shouldn't free the pdata as it has more 
2040                                 // details than the vectors. But, this 
2041                                 // reclassification should go thru
2042                                 pdata = NULL;
2043                         }
2044                 }
2045                 if (!pdata) {
2046                         goto cls_determined;
2047                 }
2048                 vec_eval = pdata->eval;
2049                 vec_true = pdata->true;
2050         } else {
2051                 int bsize = gl_allocated;
2052
2053                 vec_eval = bitvector_alloc(bsize);
2054                 vec_true = bitvector_alloc(bsize);
2055
2056                 if (vec_eval == NULL || vec_true == NULL) {
2057                         goto cls_determined;
2058                 }
2059                 termflag = RBCE_TERMFLAG_ALL; 
2060                 // need to evaluate all of them now
2061         }
2062
2063         /* 
2064          * using bit ops invalidate all terms related to this termflag
2065          * context (only in per task vec)
2066          */
2067         DPRINTK(DBG_CLASSIFY_DETAILS, "\nClassify: termflag=%lx\n", termflag);
2068         DPRINTK(DBG_CLASSIFY_DETAILS, "     eval before: ");
2069         bitvector_print(DBG_CLASSIFY_DETAILS, vec_eval);
2070         DPRINTK(DBG_CLASSIFY_DETAILS, "\n     true before: ");
2071         bitvector_print(DBG_CLASSIFY_DETAILS, vec_true);
2072         DPRINTK(DBG_CLASSIFY_DETAILS, "\n     redo => ");
2073
2074         if (termflag == RBCE_TERMFLAG_ALL) {
2075                 DPRINTK(DBG_CLASSIFY_DETAILS, "  redoall ");
2076                 bitvector_zero(vec_eval);
2077         } else {
2078                 for (i = 0; i < NUM_TERM_MASK_VECTOR; i++) {
2079                         if (test_bit(i, &termflag)) {
2080                                 bitvector_t *maskvec = gl_mask_vecs[i];
2081
2082                                 DPRINTK(DBG_CLASSIFY_DETAILS, "  mask(%d) ", i);
2083                                 bitvector_print(DBG_CLASSIFY_DETAILS, maskvec);
2084                                 bitvector_and_not(vec_eval, vec_eval, maskvec);
2085                         }
2086                 }
2087         }
2088         bitvector_and(vec_true, vec_true, vec_eval);
2089
2090         DPRINTK(DBG_CLASSIFY_DETAILS, "\n     eval now:    ");
2091         bitvector_print(DBG_CLASSIFY_DETAILS, vec_eval);
2092         DPRINTK(DBG_CLASSIFY_DETAILS, "\n");
2093
2094         /* run through the rules in order and see what needs evaluation */
2095         list_for_each_entry(rule, &rules_list[classtype], obj.link) {
2096                 if (rule->state == RBCE_RULE_ENABLED &&
2097                     rule->target_class &&
2098                     rule->target_class->classobj &&
2099                     evaluate_rule(tsk, ns, rule, vec_eval, vec_true,
2100                                   &filename)) {
2101                         tgt = rule->target_class;
2102                         cls = rule->target_class->classobj;
2103                         break;
2104                 }
2105         }
2106
2107       cls_determined:
2108         DPRINTK(DBG_CLASSIFY_RES,
2109                 "==> |%s|; pid %d; euid %d; egid %d; ruid %d; rgid %d;"
2110                 "tag |%s| ===> class |%s|\n",
2111                 filename ? filename : tsk->comm,
2112                 tsk->pid,
2113                 tsk->euid,
2114                 tsk->egid,
2115                 tsk->uid,
2116                 tsk->gid,
2117                 RBCE_DATA(tsk) ? RBCE_DATA(tsk)->app_tag : "",
2118                 tgt ? tgt->obj.name : "");
2119         DPRINTK(DBG_CLASSIFY_DETAILS, "     eval after: ");
2120         bitvector_print(DBG_CLASSIFY_DETAILS, vec_eval);
2121         DPRINTK(DBG_CLASSIFY_DETAILS, "\n     true after: ");
2122         bitvector_print(DBG_CLASSIFY_DETAILS, vec_true);
2123         DPRINTK(DBG_CLASSIFY_DETAILS, "\n");
2124
2125         if (!use_persistent_state) {
2126                 if (vec_eval) {
2127                         bitvector_free(vec_eval);
2128                 }
2129                 if (vec_true) {
2130                         bitvector_free(vec_true);
2131                 }
2132         }
2133         ckrm_core_grab(cls);
2134         read_unlock(&global_rwlock);
2135         if (filename) {
2136                 kfree(filename);
2137         }
2138         if (RBCE_DATA(tsk)) {
2139                 RBCE_DATA(tsk)->rules_version = gl_rules_version;
2140         }
2141         return cls;
2142 }
2143
2144 /*****************************************************************************
2145  *
2146  * Module specific utilization of core RBCE functionality
2147  *
2148  * Includes support for the various classtypes 
2149  * New classtypes will require extensions here
2150  * 
2151  *****************************************************************************/
2152
2153 /* helper functions that are required in the extended version */
2154
2155 static inline void rbce_tc_manual(struct task_struct *tsk)
2156 {
2157         read_lock(&global_rwlock);
2158
2159         if (!RBCE_DATA(tsk)) {
2160                 RBCE_DATAP(tsk) =
2161                     (void *)create_private_data(RBCE_DATA(tsk->parent), 0);
2162         }
2163         if (RBCE_DATA(tsk)) {
2164                 RBCE_DATA(tsk)->evaluate = 0;
2165         }
2166         read_unlock(&global_rwlock);
2167         return;
2168 }
2169
2170 /*****************************************************************************
2171  *   load any extensions
2172  *****************************************************************************/
2173
2174 #ifdef RBCE_EXTENSION
2175 #include "rbcemod_ext.c"
2176 #endif
2177
2178 /*****************************************************************************
2179  *    VARIOUS CLASSTYPES
2180  *****************************************************************************/
2181
2182 // to enable type coercion of the function pointers
2183
2184 /*============================================================================
2185  *    TASKCLASS CLASSTYPE
2186  *============================================================================*/
2187
2188 int tc_classtype = -1;
2189
2190 /*
2191  * fork callback to be registered with core module.
2192  */
2193 inline static void *rbce_tc_forkcb(struct task_struct *tsk)
2194 {
2195         int rule_version_changed = 1;
2196         struct ckrm_core_class *cls;
2197         read_lock(&global_rwlock);
2198         // dup ce_data
2199         RBCE_DATAP(tsk) =
2200             (void *)create_private_data(RBCE_DATA(tsk->parent), 0);
2201         read_unlock(&global_rwlock);
2202
2203         if (RBCE_DATA(tsk->parent)) {
2204                 rule_version_changed =
2205                     (RBCE_DATA(tsk->parent)->rules_version != gl_rules_version);
2206         }
2207         cls = rule_version_changed ?
2208             rbce_classify(tsk, NULL, RBCE_TERMFLAG_ALL, tc_classtype) : NULL;
2209
2210         // note the fork notification to any user client will be sent through
2211         // the guaranteed fork-reclassification
2212         return cls;
2213 }
2214
2215 /*
2216  * exit callback to be registered with core module.
2217  */
2218 static void rbce_tc_exitcb(struct task_struct *tsk)
2219 {
2220         struct rbce_private_data *pdata;
2221
2222         send_exit_notification(tsk);
2223
2224         pdata = RBCE_DATA(tsk);
2225         RBCE_DATAP(tsk) = NULL;
2226         if (pdata) {
2227                 if (pdata->app_tag) {
2228                         kfree(pdata->app_tag);
2229                 }
2230                 free_private_data(pdata);
2231         }
2232         return;
2233 }
2234
2235 #define AENT(x) [ CKRM_EVENT_##x] = #x
2236 static const char *event_names[CKRM_NUM_EVENTS] = {
2237         AENT(NEWTASK),
2238         AENT(FORK),
2239         AENT(EXIT),
2240         AENT(EXEC),
2241         AENT(UID),
2242         AENT(GID),
2243         AENT(XID),
2244         AENT(LOGIN),
2245         AENT(USERADD),
2246         AENT(USERDEL),
2247         AENT(LISTEN_START),
2248         AENT(LISTEN_STOP),
2249         AENT(APPTAG),
2250         AENT(RECLASSIFY),
2251         AENT(MANUAL),
2252 };
2253
2254 void *rbce_tc_classify(enum ckrm_event event, ...)
2255 {
2256         va_list args;
2257         void *cls = NULL;
2258         struct task_struct *tsk;
2259         struct rbce_private_data *pdata;
2260
2261         va_start(args, event);
2262         tsk = va_arg(args, struct task_struct *);
2263         va_end(args);
2264
2265         /* we only have to deal with events between 
2266          * [ CKRM_LATCHABLE_EVENTS .. CKRM_NONLATCHABLE_EVENTS ) 
2267          */
2268
2269         // printk(KERN_DEBUG "tc_classify %p:%d:%s '%s'\n",tsk,tsk->pid,
2270         //                      tsk->comm,event_names[event]);
2271
2272         switch (event) {
2273
2274         case CKRM_EVENT_FORK:
2275                 cls = rbce_tc_forkcb(tsk);
2276                 break;
2277
2278         case CKRM_EVENT_EXIT:
2279                 rbce_tc_exitcb(tsk);
2280                 break;
2281
2282         case CKRM_EVENT_EXEC:
2283                 cls = rbce_classify(tsk, NULL, RBCE_TERMFLAG_CMD |
2284                                     RBCE_TERMFLAG_UID | RBCE_TERMFLAG_GID,
2285                                     tc_classtype);
2286                 break;
2287
2288         case CKRM_EVENT_UID:
2289                 cls = rbce_classify(tsk, NULL, RBCE_TERMFLAG_UID, tc_classtype);
2290                 break;
2291
2292         case CKRM_EVENT_GID:
2293                 cls = rbce_classify(tsk, NULL, RBCE_TERMFLAG_GID, tc_classtype);
2294                 break;
2295
2296         case CKRM_EVENT_XID:
2297                 cls = rbce_classify(tsk, NULL, RBCE_TERMFLAG_XID, tc_classtype);
2298                 break;
2299
2300         case CKRM_EVENT_LOGIN:
2301         case CKRM_EVENT_USERADD:
2302         case CKRM_EVENT_USERDEL:
2303         case CKRM_EVENT_LISTEN_START:
2304         case CKRM_EVENT_LISTEN_STOP:
2305         case CKRM_EVENT_APPTAG:
2306                 /* no interest in this events .. */
2307                 break;
2308
2309         default:
2310                 /* catch all */
2311                 break;
2312
2313         case CKRM_EVENT_RECLASSIFY:
2314                 if ((pdata = (RBCE_DATA(tsk)))) {
2315                         pdata->evaluate = 1;
2316                 }
2317                 cls = rbce_classify(tsk, NULL, RBCE_TERMFLAG_ALL, tc_classtype);
2318                 break;
2319
2320         }
2321         // printk(KERN_DEBUG "tc_classify %p:%d:%s '%s' ==> %p\n",tsk,tsk->pid,
2322         //                      tsk->comm,event_names[event],cls);
2323
2324         return cls;
2325 }
2326
2327 #ifndef RBCE_EXTENSION
2328 static void rbce_tc_notify(int event, void *core, struct task_struct *tsk)
2329 {
2330         printk(KERN_DEBUG "tc_manual %p:%d:%s '%s'\n", tsk, tsk->pid, tsk->comm,
2331                event_names[event]);
2332         if (event != CKRM_EVENT_MANUAL)
2333                 return;
2334         rbce_tc_manual(tsk);
2335 }
2336 #endif
2337
2338 static struct ckrm_eng_callback rbce_taskclass_ecbs = {
2339         .c_interest = (unsigned long)(-1),      // set whole bitmap
2340         .classify = (ce_classify_fct_t) rbce_tc_classify,
2341         .class_delete = rbce_class_deletecb,
2342 #ifndef RBCE_EXTENSION
2343         .n_interest = (1 << CKRM_EVENT_MANUAL),
2344         .notify = (ce_notify_fct_t) rbce_tc_notify,
2345         .always_callback = 0,
2346 #else
2347         .n_interest = (unsigned long)(-1),      // set whole bitmap
2348         .notify = (ce_notify_fct_t) rbce_tc_ext_notify,
2349         .class_add = rbce_class_addcb,
2350         .always_callback = 1,
2351 #endif
2352 };
2353
2354 /*============================================================================
2355  *    ACCEPTQ CLASSTYPE
2356  *============================================================================*/
2357
2358 int sc_classtype = -1;
2359
2360 void *rbce_sc_classify(enum ckrm_event event, ...)
2361 {
2362         // no special consideratation
2363         void *result;
2364         va_list args;
2365         struct task_struct *tsk;
2366         struct ckrm_net_struct *ns;
2367
2368         va_start(args, event);
2369         ns = va_arg(args, struct ckrm_net_struct *);
2370         tsk = va_arg(args, struct task_struct *);
2371         va_end(args);
2372
2373         result = rbce_classify(tsk, ns, RBCE_TERMFLAG_ALL, sc_classtype);
2374
2375         DPRINTK(DBG_CLASSIFY_RES,
2376                 "==>  %d.%d.%d.%d\\%d , %p:%d:%s '%s' => %p\n",
2377                 NIPQUAD(ns->ns_daddrv4), ns->ns_dport,
2378                 tsk, tsk ? tsk->pid : 0, tsk ? tsk->comm : "-",
2379                 event_names[event], result);
2380         return result;
2381 }
2382
2383 static struct ckrm_eng_callback rbce_acceptQclass_ecbs = {
2384         .c_interest = (unsigned long)(-1),
2385         .always_callback = 0,   // enable during debugging only
2386         .classify = (ce_classify_fct_t) & rbce_sc_classify,
2387         .class_delete = rbce_class_deletecb,
2388 };
2389
2390 /*============================================================================
2391  *    Module Initialization ...
2392  *============================================================================*/
2393
2394 #define TASKCLASS_NAME  "taskclass"
2395 #define SOCKCLASS_NAME  "socket_class"
2396
2397 struct ce_regtable_struct {
2398         const char *name;
2399         struct ckrm_eng_callback *cbs;
2400         int *clsvar;
2401 };
2402
2403 struct ce_regtable_struct ce_regtable[] = {
2404         {TASKCLASS_NAME, &rbce_taskclass_ecbs, &tc_classtype},
2405         {SOCKCLASS_NAME, &rbce_acceptQclass_ecbs, &sc_classtype},
2406         {NULL}
2407 };
2408
2409 static void unregister_classtype_engines(void)
2410   {
2411         int rc;
2412         struct ce_regtable_struct *ceptr = ce_regtable;
2413
2414         while (ceptr->name) {
2415                 if (*ceptr->clsvar >= 0) {
2416                         printk(KERN_DEBUG "ce unregister with <%s>\n",ceptr->name);
2417                         while ((rc = ckrm_unregister_engine(ceptr->name)) == -EAGAIN)
2418                                 ;
2419                         printk(KERN_DEBUG "ce unregister with <%s> rc=%d\n",ceptr->name,rc);
2420                         *ceptr->clsvar = -1;
2421                 }
2422                 ceptr++;
2423         }
2424   }
2425
2426 static int register_classtype_engines(void)
2427 {
2428         int rc;
2429         struct ce_regtable_struct *ceptr = ce_regtable;
2430
2431         while (ceptr->name) {
2432                 rc = ckrm_register_engine(ceptr->name, ceptr->cbs);
2433                 printk(KERN_DEBUG "ce register with <%s> typeId=%d\n",ceptr->name,rc);
2434                 if ((rc < 0) && (rc != -ENOENT)) {
2435                         unregister_classtype_engines();
2436                         return (rc);
2437                 }
2438                 if (rc != -ENOENT) 
2439                         *ceptr->clsvar = rc;
2440                 ceptr++;
2441         }
2442         return 0;
2443 }
2444
2445 // =========== /proc/sysctl/debug/rbce debug stuff =============
2446
2447 #ifdef DEBUG
2448 static struct ctl_table_header *rbce_sysctl_table_header;
2449
2450 #define CTL_RBCE_DEBUG (201)    // picked some number.. dont know algo to pick
2451 static struct ctl_table rbce_entry_table[] = {
2452         {
2453          .ctl_name = CTL_RBCE_DEBUG,
2454          .procname = "rbce",
2455          .data = &rbcedebug,
2456          .maxlen = sizeof(int),
2457          .mode = 0644,
2458          .proc_handler = &proc_dointvec,
2459          },
2460         {0}
2461 };
2462
2463 static struct ctl_table rbce_root_table[] = {
2464         {
2465          .ctl_name = CTL_DEBUG,
2466          .procname = "debug",
2467          .data = NULL,
2468          .maxlen = 0,
2469          .mode = 0555,
2470          .child = rbce_entry_table},
2471         {0}
2472 };
2473
2474 static inline void start_debug(void)
2475 {
2476         rbce_sysctl_table_header = register_sysctl_table(rbce_root_table, 1);
2477 }
2478 static inline void stop_debug(void)
2479 {
2480         if (rbce_sysctl_table_header)
2481                 unregister_sysctl_table(rbce_sysctl_table_header);
2482 }
2483
2484 #else
2485
2486 static inline void start_debug(void)
2487 {
2488 }
2489 static inline void stop_debug(void)
2490 {
2491 }
2492
2493 #endif                          // DEBUG
2494
2495 extern int rbce_mkdir(struct inode *, struct dentry *, int);
2496 extern int rbce_rmdir(struct inode *, struct dentry *);
2497 extern int rbce_create_magic(void);
2498 extern int rbce_clear_magic(void);
2499
2500 rbce_eng_callback_t rcfs_ecbs = {
2501         rbce_mkdir,
2502         rbce_rmdir,
2503         rbce_create_magic,
2504         rbce_clear_magic
2505 };
2506
2507 /* ======================= Module definition Functions ====================== */
2508
2509 int init_rbce(void)
2510 {
2511         int rc, i, line;
2512
2513         printk(KERN_DEBUG "<1>\nInstalling \'%s\' module\n", modname);
2514
2515         for (i = 0; i < CKRM_MAX_CLASSTYPES; i++) {
2516                 INIT_LIST_HEAD(&rules_list[i]);
2517         }
2518
2519         rc = init_rbce_ext_pre();
2520         line = __LINE__;
2521         if (rc)
2522                 goto out;
2523
2524         rc = register_classtype_engines();
2525         line = __LINE__;
2526         if (rc)
2527                 goto out_unreg_ckrm;    // need to remove anyone opened
2528
2529         /* register any other class type engine here */
2530
2531         rc = rcfs_register_engine(&rcfs_ecbs);
2532         line = __LINE__;
2533         if (rc)
2534                 goto out_unreg_ckrm;
2535
2536         if (rcfs_mounted) {
2537                 rc = rbce_create_magic();
2538                 line = __LINE__;
2539                 if (rc)
2540                         goto out_unreg_rcfs;
2541         }
2542
2543         start_debug();
2544
2545         rc = init_rbce_ext_post();
2546         line = __LINE__;
2547         if (rc)
2548                 goto out_debug;
2549
2550         return 0;               // SUCCESS
2551
2552       out_debug:
2553         stop_debug();
2554
2555       out_unreg_rcfs:
2556         rcfs_unregister_engine(&rcfs_ecbs);
2557       out_unreg_ckrm:
2558         unregister_classtype_engines();
2559         exit_rbce_ext();
2560       out:
2561
2562         printk(KERN_DEBUG "<1>%s: error installing rc=%d line=%d\n", __FUNCTION__, rc,
2563                line);
2564         return rc;
2565 }
2566
2567 void exit_rbce(void)
2568 {
2569         int i;
2570
2571         printk(KERN_DEBUG "<1>Removing \'%s\' module\n", modname);
2572
2573         stop_debug();
2574         exit_rbce_ext();
2575
2576         // Print warnings if lists are not empty, which is a bug
2577         if (!list_empty(&class_list)) {
2578                 printk(KERN_DEBUG "exit_rbce: Class list is not empty\n");
2579         }
2580
2581         for (i = 0; i < CKRM_MAX_CLASSTYPES; i++) {
2582                 if (!list_empty(&rules_list[i])) {
2583                         printk(KERN_DEBUG "exit_rbce: Rules list for classtype %d"
2584                              " is not empty\n", i);
2585                 }
2586         }
2587
2588         if (rcfs_mounted)
2589                 rbce_clear_magic();
2590
2591         rcfs_unregister_engine(&rcfs_ecbs);
2592         unregister_classtype_engines();
2593         free_all_private_data();
2594 }
2595
2596 EXPORT_SYMBOL(get_rule);
2597 EXPORT_SYMBOL(rule_exists);
2598 EXPORT_SYMBOL(change_rule);
2599 EXPORT_SYMBOL(delete_rule);
2600 EXPORT_SYMBOL(rename_rule);
2601 EXPORT_SYMBOL(set_tasktag);
2602
2603 module_init(init_rbce);
2604 module_exit(exit_rbce);
2605
2606