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