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