Re: [blare] Test Blare Policy

[ Thread Index | Date Index | More blare-ids.org/blare Archives ]


On 03/08/2013 03:40 PM, Plane Benjamin wrote:
Hi everyone,


Thank you again for your help last wednesday ;)
Thank you for coming over.


I am now playing around with Blare and I am trying really simple cases. However I met problems in several situations.

Here is the description of attributes of each file:



getinfo file1 : 4

getpolicy file2 : {1 2}



I now run the following command : cat file1 >> file2 which is an illegal information flow regard to the policy I chose.

Result : the machine is completely frozen, a hard reboot is mandatory.
This is the bug I am working on.
Can you add it to the bugtracker here ?
For testing purpose, you can apply the attached patch, but note that there are memory leaks so don't use it in a production environment.


However I tried several times this example and it works twice. I managed to see the Blare flag in dmesg.

By the way you can find in attachment the stacktrace of the system I copied right after the succesfull example.


I can't read your attachment. Can you send it in plaintext or something?

--
Guillaume
diff --git a/Documentation/security/blare.txt b/Documentation/security/blare.txt
new file mode 100644
index 0000000..c3d512a
--- /dev/null
+++ b/Documentation/security/blare.txt
@@ -0,0 +1,23 @@
+--- What is Blare ? ---
+
+Blare is an IDS for the Linux kernel. It implements a policy centered on users,
+programs, containers or any combinations of those. It uses *tags* to supervise
+information flows within the operating systems. Tags can be attached to data
+and programs in userspace :
+    - information tags (itags)
+    - policy tags (ptags)
+    - execute policy tags (xptags)
+
+Tasks running programs that do not have any policy defined in their xptags are
+not supervised. Therefore, no alerts will be raised if they access illegal
+information. However, information will continue to be spread through their
+*information tags*, and alerts will still be raised if they write to containers
+that are supervised (i.e., that have a policy tag defined).
+
+Blare is implemented as a LSM module and therefore does not avoid the
+enforcement of standard DAC security.
+
+--- How to enable/disable ---
+
+set CONFIG_SECURITY_BLARE=y
+
diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h
index 88e78de..0adc456 100644
--- a/include/linux/lsm_audit.h
+++ b/include/linux/lsm_audit.h
@@ -82,6 +82,14 @@ struct common_audit_data {
 			int result;
 		} smack_audit_data;
 #endif
+#ifdef CONFIG_SECURITY_BLARE
+        struct blare_audit_data {
+			char *subject;
+			char *object;
+			char *mode;
+            int legal;
+        } blare_audit_data;
+#endif
 #ifdef CONFIG_SECURITY_SELINUX
 		/* SELinux data */
 		struct {
diff --git a/include/linux/security.h b/include/linux/security.h
index e8c619d..3af1292 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1189,6 +1189,10 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *	@shmflg contains the operational flags.
  *	Return 0 if permission is granted.
  *
+ * @shm_shmdt:
+ * Cleanup after a process detaches this memory segment
+ * @shp: contains the detached shared memory structure 
+ * 
  * Security hooks for System V Semaphores
  *
  * @sem_alloc_security:
@@ -1553,6 +1557,8 @@ struct security_operations {
 	int (*shm_shmctl) (struct shmid_kernel *shp, int cmd);
 	int (*shm_shmat) (struct shmid_kernel *shp,
 			  char __user *shmaddr, int shmflg);
+	void (*shm_shmdt) (struct shmid_kernel *shp);
+    int (*pipe_create) (struct file *fildes, int flags);
 
 	int (*sem_alloc_security) (struct sem_array *sma);
 	void (*sem_free_security) (struct sem_array *sma);
@@ -1599,6 +1605,7 @@ struct security_operations {
 	int (*socket_setsockopt) (struct socket *sock, int level, int optname);
 	int (*socket_shutdown) (struct socket *sock, int how);
 	int (*socket_sock_rcv_skb) (struct sock *sk, struct sk_buff *skb);
+	void (*socket_sock_release) (struct sock *sk);
 	int (*socket_getpeersec_stream) (struct socket *sock, char __user *optval, int __user *optlen, unsigned len);
 	int (*socket_getpeersec_dgram) (struct socket *sock, struct sk_buff *skb, u32 *secid);
 	int (*sk_alloc_security) (struct sock *sk, int family, gfp_t priority);
@@ -1806,6 +1813,8 @@ void security_shm_free(struct shmid_kernel *shp);
 int security_shm_associate(struct shmid_kernel *shp, int shmflg);
 int security_shm_shmctl(struct shmid_kernel *shp, int cmd);
 int security_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr, int shmflg);
+void security_shm_shmdt(struct shmid_kernel *shp);
+int security_pipe_create(struct file *fildes, int flags);
 int security_sem_alloc(struct sem_array *sma);
 void security_sem_free(struct sem_array *sma);
 int security_sem_associate(struct sem_array *sma, int semflg);
@@ -1820,7 +1829,6 @@ int security_netlink_recv(struct sk_buff *skb, int cap);
 int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
 int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
 void security_release_secctx(char *secdata, u32 seclen);
-
 int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
 int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen);
 int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen);
@@ -1832,6 +1840,7 @@ static inline void security_init_mnt_opts(struct security_mnt_opts *opts)
 {
 }
 
+
 static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
 {
 }
@@ -2473,6 +2482,9 @@ static inline int security_shm_shmat(struct shmid_kernel *shp,
 	return 0;
 }
 
+static inline void security_shm_shmdt(struct shmid_kernel *shp)
+{ }
+
 static inline int security_sem_alloc(struct sem_array *sma)
 {
 	return 0;
@@ -2571,6 +2583,7 @@ int security_socket_getsockopt(struct socket *sock, int level, int optname);
 int security_socket_setsockopt(struct socket *sock, int level, int optname);
 int security_socket_shutdown(struct socket *sock, int how);
 int security_sock_rcv_skb(struct sock *sk, struct sk_buff *skb);
+void security_sock_release(struct sock *sk);
 int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
 				      int __user *optlen, unsigned len);
 int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid);
@@ -2691,6 +2704,10 @@ static inline int security_sock_rcv_skb(struct sock *sk,
 	return 0;
 }
 
+static inline void security_sock_release(struct sock *sk)
+{
+}
+
 static inline int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
 						    int __user *optlen, unsigned len)
 {
diff --git a/ipc/shm.c b/ipc/shm.c
index 02ecf2c..dd13bed 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -237,6 +237,7 @@ static void shm_close(struct vm_area_struct *vma)
 	shp->shm_lprid = task_tgid_vnr(current);
 	shp->shm_dtim = get_seconds();
 	shp->shm_nattch--;
+    security_shm_shmdt(shp);
 	if (shm_may_destroy(ns, shp))
 		shm_destroy(ns, shp);
 	else
diff --git a/net/socket.c b/net/socket.c
index 2877647..8a10822 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -511,6 +511,10 @@ const struct file_operations bad_sock_fops = {
 
 void sock_release(struct socket *sock)
 {
+    /* This hook is used byu Blare-IDS to free the security field of the socket
+     * (when not using sk_alloc_secuity/sk_free_security*/
+    security_sock_release(sock->sk);
+
 	if (sock->ops) {
 		struct module *owner = sock->ops->owner;
 
diff --git a/security/Kconfig b/security/Kconfig
index 51bd5a0..666beed 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -186,6 +186,7 @@ config LSM_MMAP_MIN_ADDR
 source security/selinux/Kconfig
 source security/smack/Kconfig
 source security/tomoyo/Kconfig
+source security/blare/Kconfig
 source security/apparmor/Kconfig
 
 source security/integrity/Kconfig
@@ -195,6 +196,7 @@ choice
 	default DEFAULT_SECURITY_SELINUX if SECURITY_SELINUX
 	default DEFAULT_SECURITY_SMACK if SECURITY_SMACK
 	default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO
+	default DEFAULT_SECURITY_BLARE if SECURITY_BLARE
 	default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR
 	default DEFAULT_SECURITY_DAC
 
@@ -211,6 +213,9 @@ choice
 	config DEFAULT_SECURITY_TOMOYO
 		bool "TOMOYO" if SECURITY_TOMOYO=y
 
+config DEFAULT_SECURITY_BLARE
+		bool "BLARE" if SECURITY_BLARE=y
+
 	config DEFAULT_SECURITY_APPARMOR
 		bool "AppArmor" if SECURITY_APPARMOR=y
 
@@ -224,6 +229,7 @@ config DEFAULT_SECURITY
 	default "selinux" if DEFAULT_SECURITY_SELINUX
 	default "smack" if DEFAULT_SECURITY_SMACK
 	default "tomoyo" if DEFAULT_SECURITY_TOMOYO
+	default "BLARE" if DEFAULT_SECURITY_BLARE
 	default "apparmor" if DEFAULT_SECURITY_APPARMOR
 	default "" if DEFAULT_SECURITY_DAC
 
diff --git a/security/Makefile b/security/Makefile
index a5e502f..a9adf8f 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_KEYS)			+= keys/
 subdir-$(CONFIG_SECURITY_SELINUX)	+= selinux
 subdir-$(CONFIG_SECURITY_SMACK)		+= smack
 subdir-$(CONFIG_SECURITY_TOMOYO)        += tomoyo
+subdir-$(CONFIG_SECURITY_BLARE)        += blare
 subdir-$(CONFIG_SECURITY_APPARMOR)	+= apparmor
 
 # always enable default capabilities
@@ -20,6 +21,7 @@ obj-$(CONFIG_SECURITY_SELINUX)		+= selinux/built-in.o
 obj-$(CONFIG_SECURITY_SMACK)		+= smack/built-in.o
 obj-$(CONFIG_AUDIT)			+= lsm_audit.o
 obj-$(CONFIG_SECURITY_TOMOYO)		+= tomoyo/built-in.o
+obj-$(CONFIG_SECURITY_BLARE)		+= blare/built-in.o
 obj-$(CONFIG_SECURITY_APPARMOR)		+= apparmor/built-in.o
 obj-$(CONFIG_CGROUP_DEVICE)		+= device_cgroup.o
 
diff --git a/security/blare/Kconfig b/security/blare/Kconfig
new file mode 100644
index 0000000..3549ae7
--- /dev/null
+++ b/security/blare/Kconfig
@@ -0,0 +1,12 @@
+config SECURITY_BLARE
+    bool "BLARE" 
+    depends on SECURITY
+	select AUDIT
+	select SECURITYFS
+	select SECURITY_NETWORK
+    select NETLABEL
+    default n 
+    help
+      This selects the Blare Intrusion Detection System Kernel.
+      Blare is IDS configured by a MAC policy, and based on information flow control at the operating system level. 
+      If you are unsure how to answer this question, answer N.
diff --git a/security/blare/Makefile b/security/blare/Makefile
new file mode 100644
index 0000000..b3e58ea
--- /dev/null
+++ b/security/blare/Makefile
@@ -0,0 +1,5 @@
+# For compiling as part of the linux source tree
+obj-$(CONFIG_SECURITY_BLARE) := blare_lsm.o
+blare_lsm-objs += lsm_hooks.o xattr.o itag.o itag_rcu.o ptags.o tests.o legality.o blare_securityfs.o network.o shm.o file_ops.o blare.o netlabel.o netfilter_hooks.o audit.o trace.o mmap.o #configfs.o
+
+
diff --git a/security/blare/audit.c b/security/blare/audit.c
new file mode 100644
index 0000000..d1d9eff
--- /dev/null
+++ b/security/blare/audit.c
@@ -0,0 +1,98 @@
+/*  This file contains the auditing code related to Blare IDS.
+ *
+ *  Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ *
+ */
+
+
+#ifdef CONFIG_AUDIT
+#include <linux/lsm_audit.h>
+#include <linux/fs.h>
+#include "blare.h"
+#include "include/audit.h"
+
+/** Adapted from smack code
+ * blare_log_callback - Blare specific information
+ * will be called by generic audit code
+ * @ab : the audit_buffer
+ * @a  : audit_data
+ *
+ */
+static void blare_log_callback(struct audit_buffer *ab, void *a)
+{
+	struct common_audit_data *ad = a;
+	struct blare_audit_data *bad = &ad->blare_audit_data;
+	audit_log_format(ab, "lsm=Blare action=%s",
+			 bad->legal ? "illegal" : "legal");
+	audit_log_format(ab, " subject=");
+	audit_log_untrustedstring(ab, bad->subject);
+	audit_log_format(ab, " object=");
+	audit_log_untrustedstring(ab, bad->object);
+	audit_log_format(ab, " mode=%s", bad->mode);
+}
+
+
+// From Smack code
+inline void str_from_perm(char *string, int access)
+{
+	int i = 0;
+	if (access & MAY_READ)
+		string[i++] = 'r';
+	if (access & MAY_WRITE)
+		string[i++] = 'w';
+	if (access & MAY_EXEC)
+		string[i++] = 'x';
+	if (access & MAY_APPEND)
+		string[i++] = 'a';
+    string[i] = '\0';
+}
+
+ /*  blare_log - Audit illegal or legal accesses depending on 
+  *  blare_audit_policy, adapted from Smack */
+void blare_log(char *subject_label, char *object_label, int mode,
+	       int legal, struct blare_audit_info *bai)
+{
+	char mode_buf[NB_ACCESS_MODES + 1];
+	struct blare_audit_data *bad;
+	//struct common_audit_data *a = &bai->a;
+    struct common_audit_data *a;
+
+    a = kzalloc(sizeof(struct common_audit_data), GFP_KERNEL);
+
+    /* We do not log legal information flows by default */
+    if (legal == 1 && (BLARE_AUDIT_LEGAL == 0))
+		return;
+
+	bad = &a->blare_audit_data;
+
+    /* Smack has a function to convert an access mode into a string */
+	str_from_perm(mode_buf, mode);
+
+    a->type = LSM_AUDIT_DATA_TASK;
+	a->u.tsk = current;
+
+	//bad->subject = subject_label;
+    bad->subject = "subject";
+	//bad->object  = object_label;
+    bad->object = "object";
+	bad->mode = mode_buf;
+	bad->legal  = legal;
+	a->lsm_pre_audit = blare_log_callback;
+
+	common_lsm_audit(a);
+    kfree(a);
+}
+#else /* #ifdef CONFIG_AUDIT */
+void blare_log(char *subject_label, char *object_label, int mode,
+               int legal)
+{
+}
+#endif
+
diff --git a/security/blare/blare.c b/security/blare/blare.c
new file mode 100644
index 0000000..a2fb4cf
--- /dev/null
+++ b/security/blare/blare.c
@@ -0,0 +1,409 @@
+/* General functions of Blare IDS. 
+ *  Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ */
+
+#include <linux/security.h>
+#include "blare.h"
+#include "include/itag.h"
+#include "include/ptags.h"
+#include "include/shm.h"
+#include "include/legality.h"
+#include <linux/list.h>
+#include <linux/kmod.h>
+#include "include/xattr.h"
+
+
+/* Warnings, always printed */
+void blare_warn(const char* format,...){
+    va_list args;
+    va_start(args,format);
+    printk(KERN_WARNING "blare_warning _%s(pid %d;cpu %d)_ ", current->comm, current->pid, current->on_cpu);
+    vprintk(format,args);
+    va_end(args);
+}
+
+/* Print messages only if Blare was compiled with DEBUG enabled */
+void blare_debug(const char* format,...){
+    va_list args;
+    if (!DEBUG)
+        return;
+    va_start(args,format);
+    printk(KERN_DEBUG "blare_debug: _%s(pid %d;cpu %d)_ ",current->comm, current->pid, current->on_cpu);
+    vprintk(format,args);
+    va_end(args);
+}
+
+
+/* Before transfering tags, there are some points to check */
+int current_process_check(void){
+    const struct cred *cred;
+    struct blare_task_struct *tstruct;
+    int err = 0;
+    cred = get_current_cred();
+    if (unlikely(!cred)){
+        err = -ENODATA;
+        goto error;
+    }
+
+    if (blare_enabled == 0){
+        err = -1;
+        goto error;
+    }
+    /* PID 0  is the swapper*/
+    if  (current->pid == 0){
+        err = -2;
+        goto error;
+    }
+
+    tstruct = cred->security;
+    if (unlikely(!tstruct)){
+        blare_error(-ECANCELED); // if pid!=0 and !tstruct we're in trouble
+        err = -ECANCELED;
+        goto error;
+    }
+
+    if (tstruct->info_list){
+        /* Trusted processes do not propagate information nor xptags */
+        if ((blare_check_trusted_process(tstruct->info_list)) == 0){
+            err = -3;
+            goto error;
+        }
+    }
+
+    // If we reach this point, it is ok to transfer the tags
+    err = 0;
+error:
+    put_cred(cred);
+    return err;
+}
+
+/* Propagation of information tags from an object to a task*/
+int blare_task_read_info(struct list_head *info){
+    int rc;
+    struct list_head *newlist;
+    //struct blare_task_struct *tstruct = current_security();
+    struct blare_task_struct *tstruct;     
+    struct cred *cred;
+
+    /* Nothing to do */
+    if (!info || list_empty(info))
+        return 0;
+
+    /* Check wether the current process should transfer tags */
+    rc = current_process_check();
+    if (rc != 0)
+        return rc;
+
+    cred = prepare_creds();
+    tstruct = cred->security;
+
+    if (tstruct->info_list){
+        rc = itag_merge(tstruct->info_list,info, GFP_KERNEL);
+        if (rc< 0)
+            BLARE_DEBUG("[task_read] Error -1 merging tags");
+        if (rc !=0)
+            tstruct->info_rev++;
+    }
+    else{
+        rcu_read_lock();
+        newlist = itag_copy(info, GFP_ATOMIC);
+        rcu_read_unlock();
+        if (newlist && !IS_ERR(newlist)){
+            tstruct->info_list = newlist;
+        }
+        else
+            BLARE_DEBUG("Error %d trying to copy itag list", (int)PTR_ERR(newlist));
+    }
+
+    commit_creds(cred);
+    return 0;
+}
+
+/* Propagation of xptags from an object to a task */
+int blare_task_read_xpolicy(struct list_head *xpolicy){
+    int rc;
+    const struct cred *cred;
+    struct blare_task_struct *tstruct; 
+
+    /* Nothing to do */
+    if (!xpolicy)
+        return 0;
+
+    /* Check wether the current process should transfer tags */
+    rc = current_process_check();
+    if (rc != 0)
+        return rc;
+
+    cred = get_current_cred();
+    tstruct = cred->security;
+
+    if(tstruct->xpolicy_list)
+        tstruct->xpolicy_list = common_sets(tstruct->xpolicy_list,xpolicy);
+    else
+        tstruct->xpolicy_list = ptag_copy(xpolicy);
+
+    put_cred(cred);
+
+    return 0;
+}
+
+/* Deprecated stub, don't use
+ */
+int blare_task_read(struct blare_tags *objtags){
+    int rc;
+
+    if (!objtags)
+        return 0;
+
+    rc = blare_task_read_info(objtags->info);
+    rc = blare_task_read_xpolicy(objtags->xpolicy);
+
+    /* Update shm segments  TODO
+       if (tstruct->shm && !(list_empty(tstruct->shm)))
+       blare_update_shm_tags(tstruct->shm,tstruct->info_list);
+       */
+
+    /* Policy check. Or we can also do it later, as this function won't return 0
+     * if this is an illegal flow.
+    rc = check_policy(tstruct->info_list, tstruct->policy_list);
+    if (rc < 0) printk(KERN_CRIT "[BLARE_POLICY_VIOLATION] process with pid"
+            "%d running %s made an illegal READ access to resource.",
+            current->pid,current->comm);
+            */
+    return 0;
+}
+
+/* When a task writes into an object */
+int blare_task_write(struct blare_tags *objtags){
+    struct blare_task_struct *tstruct;
+    struct list_head *copy = NULL;
+    int err = 0;
+    const struct cred *cred;
+
+    if (blare_enabled == 0 || current->pid == 0)
+        return 0;
+
+    if(unlikely(!objtags)) return -ENODATA;
+
+    cred = get_current_cred();
+    if (unlikely(!cred)){
+        err = -ENODATA;
+        goto exit;
+    }
+
+    tstruct = cred->security;
+    if (unlikely(!tstruct)){
+        err = -ENODATA;
+        goto exit;
+    }
+
+    /* Information tags propagation */
+    if (tstruct->info_list && !list_empty(tstruct->info_list)){
+        if (objtags->info){
+
+            /* Trusted processes do not propagate information */
+            if ((err = blare_check_trusted_process(tstruct->info_list)) == 0){
+                err = 0;
+                goto exit;
+            }
+
+            /* Make sure we don't screw itags ordering - for debug purpose 
+            err = itag_check_order(tstruct->info_list);
+            if (err < 0) BLARE_DEBUG("Wrong itag order before merge");
+            */
+
+            err = itag_merge(objtags->info, tstruct->info_list, GFP_KERNEL);
+            if (err < 0) BLARE_DEBUG("[task_write] Error %d merging tags",err);
+
+        }
+        else{
+            /* BUG: causes exponential memory allocation ! 
+             * Fixed, was caused by itag_merge screwing the ordering of itags
+             * */
+            rcu_read_lock();
+            copy = itag_copy(tstruct->info_list, GFP_ATOMIC);
+            rcu_read_unlock();
+            if (!IS_ERR(copy)){
+                objtags->info = copy;
+            }
+            else{
+                err = PTR_ERR(copy);
+                BLARE_DEBUG("(blare_task_write) Error %d while copying itag",err);
+            }
+        }
+    }
+
+    /* Execute policy tag propagation 
+     */
+    if (tstruct->xpolicy_list)
+        xptag_merge(&objtags->xpolicy, tstruct->xpolicy_list);
+
+    err = 0;
+exit:
+    put_cred (cred);
+    return err;
+}
+
+int blare_task_write_info(struct list_head *info){
+ struct blare_task_struct *tstruct;
+    struct list_head *copy = NULL;
+    int err = 0;
+    const struct cred *cred;
+
+    if (blare_enabled == 0 || current->pid == 0)
+        return 0;
+
+    //if(unlikely(!info)) return -ENODATA;
+
+    cred = get_current_cred();
+    if (unlikely(!cred)){
+        err = -ENODATA;
+        goto exit;
+    }
+
+    tstruct = cred->security;
+    if (unlikely(!tstruct)){
+        err = -ENODATA;
+        goto exit;
+    }
+
+    /* Information tags propagation */
+    if (tstruct->info_list && !list_empty(tstruct->info_list)){
+        if (info){
+
+            /* Trusted processes do not propagate information */
+            if ((err = blare_check_trusted_process(tstruct->info_list)) == 0){
+                err = 0;
+                goto exit;
+            }
+
+            err = itag_merge(info, tstruct->info_list, GFP_KERNEL);
+            if (err < 0) BLARE_DEBUG("[task_write] Error %d merging tags",err);
+
+        }
+        else{
+            rcu_read_lock();
+            copy = itag_copy(tstruct->info_list, GFP_ATOMIC);
+            rcu_read_unlock();
+            if (!IS_ERR(copy)){
+                info = copy;
+            }
+            else{
+                err = PTR_ERR(copy);
+                BLARE_DEBUG("(blare_task_write) Error %d while copying itag",err);
+            }
+        }
+    }
+exit:
+    put_cred(cred);
+    return 0;
+}
+
+
+/* Helper function to pring tags contents */
+void tags_print (struct blare_tags *tags){
+    itag_count (tags->info);
+    policytag_print(tags->xpolicy);
+}
+
+/* Helper function to allocate a blare_tags structure */
+struct blare_tags *blare_tags_alloc(gfp_t flags)
+{
+    return (struct blare_tags*) kmem_cache_zalloc(blare_tags_cache, flags);
+}
+ 
+/* Helper function to free a tags structure and its
+ * allocated fields */
+void tags_free(struct blare_tags **tagsp){
+    struct blare_tags *tags;
+    if (!tagsp || !*tagsp) return;
+
+    tags = *tagsp;
+
+   if (tags->info) 
+       itag_free(tags->info); 
+   if (tags->xpolicy)
+       policy_tag_free(tags->xpolicy);  
+
+   kmem_cache_free(blare_tags_cache,tags);
+   *tagsp = NULL;
+}
+
+
+/* Invoke a userspace program to report a message from blare */
+int blare_call(char *msg){
+    char *argv[] = { "/usr/bin/blared", msg, NULL };
+    static char *envp[] = {
+        "HOME=/",
+        "TERM=linux",
+        "PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL };
+
+    return call_usermodehelper( argv[0], argv, envp, UMH_WAIT_PROC );
+}
+
+
+/* Check whether a process's itag is set to 0  
+ * which means that we do not propagate anything 
+ * (i.e. trusted process)*/
+int blare_check_trusted_process(struct list_head *itag){
+    struct information *info;
+
+    /* Itag can't be null here */
+    BUG_ON(!itag);
+
+    rcu_read_lock();
+    info = list_first_entry(itag, struct information, node);
+    rcu_read_unlock();
+    if (info->value == 0){
+        return 0;
+        }
+    else
+        return -1;
+}
+
+/* Check whether the current process is trusted 
+ * returns 0 if it is trusted, -1 otherwise
+ * */
+int blare_current_is_trusted(void){
+    struct blare_task_struct *tstruct;
+    int rc;
+    const struct cred *ro_cred;
+
+    ro_cred = get_current_cred();
+    tstruct = ro_cred->security;
+
+    if (tstruct && tstruct->info_list){
+        //rcu_read_lock();
+        rc = blare_check_trusted_process(tstruct->info_list);
+        //rcu_read_unlock();
+    }
+    else
+        rc = -1;
+
+    put_cred(ro_cred);
+    return rc;
+}
+
+/* The current information tag - D*/
+char *blare_current_info_to_s(void){
+    struct blare_task_struct *tstruct;
+    const struct cred *ro_cred;
+    char *str = NULL;
+
+    ro_cred = get_current_cred();
+    tstruct = ro_cred->security;
+
+    if (tstruct && tstruct->info_list)
+        str = itag_to_s(tstruct->info_list);
+    put_cred(ro_cred);
+    return str;
+}
+
+
diff --git a/security/blare/blare.h b/security/blare/blare.h
new file mode 100644
index 0000000..124d873
--- /dev/null
+++ b/security/blare/blare.h
@@ -0,0 +1,212 @@
+/* Check Documentation/blare.txt for documentation on Blare.
+ *
+ *  Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ */
+
+#ifndef __BLARE_H
+#define __BLARE_H
+
+#include <linux/security.h>
+#include <net/netlabel.h>
+#include <linux/list.h>
+
+/* Blare stores meta information in the extended attributes of the filesystem.
+ * Such meta-information are called tags. 
+ * INFO_XATTR store information tags
+ * POLICY_XATTR store policy tags
+ * XPOLICY_XATTR store execute policy tags
+ */
+
+#define INFO_XATTR "security.blare.info"
+
+#define POLICY_XATTR "security.blare.policy"
+#define POLICY_COUNT "security.blare.policy_count"
+#define POLICY_VERSION "security.blare.policy_version"
+
+#define XPOLICY_XATTR "security.blare.xpolicy"
+#define XPOLICY_COUNT "security.blare.xpolicy_count"
+#define XPOLICY_VERSION "security.blare.xpolicy_version"
+
+#define ROLE_XATTR "security.blare.role"
+#define ROLE_COUNT "security.blare.role_count"
+
+// Tracing binaries
+#define TRACE_XATTR "security.blare_trace"
+
+/* Set this to enable debug mode (printk) */
+#define DEBUG false
+
+/* Auditing, should we also log legal events ? */
+#define BLARE_AUDIT_LEGAL true
+
+/* Verbose (printk) POLICY and INFO operations (for debug) */
+#define DEBUG_POLICY false
+#define DEBUG_XPOLICY false
+#define DEBUG_INFO false
+#define DEBUG_NETWORK false
+#define DEBUG_SECURITYFS true
+#define DEBUG_NET DEBUG_NETWORK
+#define DEBUG_MMAP false
+
+#define BLARE_DEBUG(x...) { if (DEBUG) {printk(KERN_DEBUG "BLARE_DEBUG@%s:%d [%s(pid %d)]",__func__, __LINE__, current->comm,current->pid); printk(KERN_DEBUG x);}}
+
+#define BLARE_DEBUG_NET(x...) { if (DEBUG_NETWORK) {printk(KERN_DEBUG "BLARE_DEBUG_NET@%s:%d [%s(pid %d)]",__func__, __LINE__, current->comm,current->pid); printk(KERN_DEBUG x);}}
+
+#define BLARE_WARN_ON(condition,format...){ if (unlikely(condition)){ printk(KERN_WARNING "BLARE: WARNING, [%s]", current->comm) ; printk(KERN_WARNING format);}}
+
+/* Critical errors */
+#define blare_error(errno){printk(KERN_WARNING "blare: error %d in function %s, line %d  _%s:%d_", errno, __func__, __LINE__,  current->comm,current->pid);} 
+
+extern int blare_enabled;
+
+extern struct kmem_cache *blare_info_cache;
+extern struct kmem_cache *blare_policy_array_cache;
+extern struct kmem_cache *blare_tree_item_cache;
+extern struct kmem_cache *blare_policy_tree_cache;
+extern struct kmem_cache *blare_cache_slab;
+extern struct kmem_cache *blare_file_struct_cache;
+extern struct kmem_cache *blare_task_struct_cache;
+extern struct kmem_cache *blare_shmptr_cache;
+extern struct kmem_cache *blare_tags_cache;
+extern struct security_operations blare_ops;
+extern struct rb_root blare_cache_root;
+extern int blare_initialized __initdata;
+extern struct list_head *blare_network_policy;
+extern struct rb_root *blare_mmap_tree_root;
+
+/* Structure attached to processes
+ * in their credentials
+ * cred->security */
+struct blare_task_struct{
+    struct list_head *info_list;
+    int info_rev; // revision number
+    struct list_head *policy_list;
+    struct list_head *xpolicy_list;
+    struct list_head *shm;
+    struct list_head *threads;
+    struct list_head *mmap_list;
+    int trace;  //Should we trace (log the actions of) this process ?
+};
+
+/* blare_task_struct has a threads list of blare_thread items, each of them
+ * embedding the pid of the thread and a pointer to its information tag 
+ */
+struct blare_thread{
+    struct list_head *info_list;
+    struct list_head node;
+    int pid;
+};
+
+/* Set of tags to attach to any object */
+struct blare_tags{
+    struct list_head *info;
+    /* Used by softirqs invoking rcv_skb*/
+    spinlock_t info_lock; 
+    atomic_t refcount;
+    int info_rev; //unused
+    struct list_head *policy;
+    struct list_head *xpolicy;
+};
+
+
+/* Structure attached to files and binary handlers (binprm)
+ * in their credentials
+ * cred->security
+ * */
+struct blare_file_struct{
+    int *info_array;
+    int info_size;
+    struct policy_array **policy_arrays;
+    int policy_count;
+    struct policy_array **xpolicy_arrays;
+    int xpolicy_count;
+    struct blare_tags tags; // used for unnamed pipes
+};
+
+
+/* An information tag is a list of struct information elements
+ */
+struct information{
+    // This is a chained list of integer values
+    // representing an ordered set
+    struct list_head node;
+    int value;
+};
+
+
+/* We attach information tags to shared memory segments. Processes maintain a
+ * list of pointers (of type blare_shmptr) to currently attached shared memory
+ * segments. 
+ */
+struct blare_shmptr{
+    struct list_head node;
+    struct blare_tags *ptr;
+    int shmflg; //shmat() flags, i.e. SHM_RDONLY etc.
+};
+
+
+/* This intermediate structure is used when reading policy tags from the
+ * filesystem XATTR*/
+struct policy_array{
+    int *array;
+    int size;
+};
+
+
+/* Each set of a policy tag is a binary tree composed of elements of type
+ * tree_item
+ */
+struct tree_item{
+    struct rb_node node;
+    int value;
+};
+
+/* A policy tag is a list of binary trees (a set of sets)
+ * Each binary tree has the following type:
+ * */
+struct policy_tree{
+    struct list_head list;
+    struct rb_root *root;
+    int cardinal;
+};
+
+/* Unused ?*/
+struct xpolicy{
+    struct list_head policy_list;
+};
+
+/*
+struct blare_cipso {
+	int	blare_level;
+	char blare_catset[BLARE_TAG_LEN];
+};
+*/
+
+/* From blare.c */
+int blare_task_read(struct blare_tags *objtags);
+int blare_task_read_info(struct list_head *info);
+int blare_task_read_xpolicy(struct list_head *xpolicy);
+int blare_task_write(struct blare_tags *objtags);
+void tags_print (struct blare_tags *tags);
+struct blare_tags *tags_alloc(void);
+void tags_free(struct blare_tags **tags);
+struct blare_tags *blare_tags_alloc(gfp_t flags);
+int blare_call(char *msg);
+int blare_set_skbuff_netlabel(struct sk_buff *skb, struct list_head *itag);
+//void blare_cipso_doi(void);
+//void blare_netlabel_audit_set(struct netlbl_audit *nap);
+int blare_check_trusted_process(struct list_head *itag);
+int blare_current_is_trusted(void);
+char *blare_current_info_to_s(void);
+unsigned int inet_addr(char *str);
+void blare_warn(const char* format,...);
+void blare_debug(const char* format,...);
+int blare_task_write_info(struct list_head *info);
+#endif
diff --git a/security/blare/blare_securityfs.c b/security/blare/blare_securityfs.c
new file mode 100644
index 0000000..19973cd
--- /dev/null
+++ b/security/blare/blare_securityfs.c
@@ -0,0 +1,258 @@
+/* securityfs is used in blare to do things like setting the network policy,
+ * setting per user policies etc.
+ *
+ *  Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ */
+
+#include "blare.h"
+#include <linux/uaccess.h>
+#include "include/network.h"
+#include "include/netlabel.h"
+#include "include/ptags.h"
+
+static struct dentry *blare_fs_dir __initdata;
+extern int blare_enabled;
+
+/*
+struct blare_securityfs_data{
+    int *array;
+    size_t size;
+}
+*/
+
+
+/**
+ * This is used by blare to read a set of the network policy from its "network"
+ * entry. The user writes to the virtual file, and we read it from kernelspace.
+ * @userbuf: user buffer to copy data from  (NOT NULL)
+ * @alloc_size: size of user buffer (REQUIRES: @alloc_size >= @copy_size)
+ * @copy_size: size of data to copy from user buffer
+ * @pos: position write is at in the file (NOT NULL)
+ *
+ * Returns: kernel buffer containing copy of user buffer data or an
+ *          ERR_PTR on failure.
+ */
+static char *blare_securityfs_buffer_write(const char __user *buffer, size_t
+        alloc_size, size_t copy_size, loff_t *pos){ 
+
+    char *data; 
+    BUG_ON(copy_size > alloc_size);
+
+	if (*pos != 0)
+		/* only writes from pos 0, that is complete writes */
+		return ERR_PTR(-ESPIPE);
+
+    /* TODO: check permissions */
+	
+	data = kmalloc(alloc_size, GFP_KERNEL); 
+
+	if (data == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	if (copy_from_user(data, buffer, copy_size)) {
+		kfree(data);
+		return ERR_PTR(-EFAULT);
+	}
+
+    // The caller should free it
+	return data;
+}
+
+/**
+ * policy_load
+ * .write file hook function to load a new policy subset via securityfs
+ */
+static ssize_t policy_load(struct file *f, const char __user *buffer, size_t size,
+		loff_t *pos){
+    ssize_t error;
+    int *array;
+
+    array = (int*)blare_securityfs_buffer_write(buffer, size, size, pos);
+
+    /*
+    printk("Got the following array: ");
+    array_print(array,size/sizeof(int));
+    */
+
+    error = PTR_ERR(array);
+    if (!IS_ERR(array)) {
+        error = blare_network_policy_add(array,size);
+        printk(KERN_INFO "blare: added array @%p with size %zd. Error code was %zd\n",array,size,error);
+        kfree(array);
+        return size;
+        //policytag_print(blare_network_policy);
+    }
+    else
+        printk(KERN_INFO "Blare: error: %zd\n loading the network policy",error);
+
+    return error;
+}
+
+/*
+ * policy_export
+ * .read file hook function to export a policy list to userspace
+ */
+static ssize_t policy_export(struct file *f, char __user *buffer, size_t size, loff_t *pos){
+    if (*pos != 0)
+        return -ESPIPE;
+
+    if (!blare_network_policy){
+        printk(KERN_INFO "(empty set)\n");
+        return 0;
+    }
+
+    policytag_print(blare_network_policy);
+
+    /*
+    if (DEBUG_SECURITYFS) printk("[policy_export] buffersize: %zd\n",size);
+    if (DEBUG_SECURITYFS && !buffer) printk("[policy_export] buffer is NULL\n");
+    */
+
+    return 0;
+}
+
+
+/* Enable / disable blare 
+ * .write hook function */
+static ssize_t activate(struct file *f, const char __user *buffer, size_t size,
+		loff_t *pos){
+    char *data, error;
+
+    data = blare_securityfs_buffer_write(buffer, size, size, pos);
+    if (IS_ERR(data)){
+        error = PTR_ERR(data);
+        printk(KERN_WARNING "blare_securityfs: error %d\n", error);
+        return error;
+    }
+
+    if (strncmp(data, "1", 1) == 0){
+        printk(KERN_INFO "*** BlARE ENABLED ***\n");
+        blare_enabled = 1;
+    }
+    else if (strncmp(data, "0", 1) == 0){
+        printk(KERN_INFO "*** BlARE DISABLED ***\n");
+        blare_enabled = 0;
+    }
+    else
+        printk(KERN_INFO "Blare: what ? I don't understand what \"%c\" means\n",data[0]);
+    kfree(data);
+    return size;
+}
+
+
+/* Is blare enabled ? */
+static ssize_t is_enabled(struct file *f, char __user *buffer, size_t size, loff_t *pos){
+    if (*pos != 0)
+        return -ESPIPE;
+
+    if(blare_enabled != 0 && blare_enabled !=1)
+        printk(KERN_WARNING "blare: blare_enabled should be either 0 or 1, but"
+                "it is %d !\n", blare_enabled);
+    else
+        printk(KERN_INFO "%d\n",blare_enabled);
+
+    return 0;
+}
+
+/**
+ * File operations attached to /sys/kernel/security/blare/network
+ */
+static const struct file_operations blare_securityfs_policy_ops = {
+	.write = policy_load,
+	.llseek = default_llseek,
+    .read = policy_export
+};
+
+/* Blare activation / desactivation */
+static const struct file_operations blare_securityfs_active_ops = {
+	.write = activate,
+	.llseek = default_llseek,
+    .read = is_enabled
+};
+
+/* Called once for every securityfs entry */
+static int __init blare_securityfs_create(const char *name, int mask,
+			      const struct file_operations *fops)
+{
+	struct dentry *dentry;
+
+	dentry = securityfs_create_file(name, S_IFREG | mask, blare_fs_dir,
+					NULL, fops);
+
+	return IS_ERR(dentry) ? PTR_ERR(dentry) : 0;
+}
+
+
+/**
+ * blare_free_securityfs 
+ *
+ * releases dentries allocated by blare_init_securityfs
+ */
+void __init blare_free_securityfs(void)
+{
+	if (blare_fs_dir) {
+        //TODO: blare_securityfs_remove(".load");
+
+		securityfs_remove(blare_fs_dir);
+		blare_fs_dir = NULL;
+	}
+}
+
+/**
+ * blare_create_blarefs - create the Blare security filesystem
+ *
+ * dentries created here are released by blare_destroy_blarefs
+ *
+ * Returns: error on failure
+ */
+int __init blare_init_securityfs(void)
+{
+	int rc;
+
+	if (!blare_initialized)
+		return 0;
+
+
+	if (blare_fs_dir) {
+		if(DEBUG) printk("Blare securityfs already exists\n");
+		return -EEXIST;
+	}
+
+	blare_fs_dir = securityfs_create_dir("blare", NULL);
+	if (IS_ERR(blare_fs_dir)) {
+		rc = PTR_ERR(blare_fs_dir);
+		blare_fs_dir = NULL;
+		goto error;
+	}
+
+	rc = blare_securityfs_create("network", 0640, &blare_securityfs_policy_ops);
+	if (rc)
+		goto error;
+
+	rc = blare_securityfs_create("enabled", 0640, &blare_securityfs_active_ops);
+    if (rc)
+        goto error;
+
+    printk(KERN_INFO "Blare: securityfs enabled :)\n");
+
+    /* Initialize CIPSO labels*/
+    blare_cipso_doi();
+
+    //blare_enabled = 1;
+
+	return 0;
+
+error:
+	blare_free_securityfs();
+	if(DEBUG) printk(KERN_INFO "Error creating Blare securityfs entry :(\n");
+	return rc;
+}
+
+fs_initcall(blare_init_securityfs);
diff --git a/security/blare/cache.c b/security/blare/cache.c
new file mode 100644
index 0000000..c057838
--- /dev/null
+++ b/security/blare/cache.c
@@ -0,0 +1,54 @@
+/* The Blare cache stores information about files currently being opened 
+ * by processes monitored by Blare.  It is a binary tree indexed on the inode.
+ * Well.. that's what it would be if it was implemented :).
+ *
+ * TODO: There is a bottleneck somewhere at the filesystem level, which really
+ * slows down the system. It has to do with Blare updating the extended
+ * attributes at every file access. Some cache mechanism probably would be the
+ * answer.
+ *
+ *  Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ */
+
+
+ 
+#include "blare.h"
+
+/* To be implemented */
+int blare_cache_add_entry();
+int blare_cache_del_entry();
+
+
+/* Search for an entry in the blare cache for inode @inode.
+ * Returns the corresponding blare_cache_entry if found
+ * Retunrs NULL otherwise
+ */
+struct blare_cache_entry *blare_get_cache_entry(struct inode  *inode){
+    struct rb_node *node;
+    struct blare_cache_entry *entry;
+
+    node = blare_cache_root->rb_node; 
+
+    while (node)
+    {
+        entry = rb_entry(node, struct blare_cache_entry, node);
+
+        if (entry->inode->i_ino > inode->i_ino)
+            node = node->rb_left;
+
+        else if ( entry->inode->i_ino < inode->i_ino)
+            node = node->rb_right;
+
+        else
+            return entry;  
+    }
+    return NULL;
+}
+
diff --git a/security/blare/configfs.c b/security/blare/configfs.c
new file mode 100644
index 0000000..c44c33b
--- /dev/null
+++ b/security/blare/configfs.c
@@ -0,0 +1,326 @@
+/*
+ * vim: noexpandtab ts=8 sts=0 sw=8:
+ *
+ * configfs_example_macros.c - This file is a demonstration module
+ *      containing a number of configfs subsystems.  It uses the helper
+ *      macros defined by configfs.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ *
+ * Based on sysfs:
+ * 	sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel
+ *
+ * configfs Copyright (C) 2005 Oracle.  All rights reserved.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/configfs.h>
+/*
+ * 02-simple-children
+ *
+ * This example merely has a simple one-attribute child.  Note that
+ * there is no extra attribute structure, as the child's attribute is
+ * known from the get-go.  Also, there is no container for the
+ * subsystem, as it has no attributes of its own.
+ */
+
+struct simple_child {
+	struct config_item item;
+	int storeme;
+};
+
+inline struct simple_child *to_simple_child(struct config_item *item)
+{
+	return item ? container_of(item, struct simple_child, item) : NULL;
+}
+
+struct configfs_attribute simple_child_attr_storeme = {
+	.ca_owner = THIS_MODULE,
+	.ca_name = "storeme",
+	.ca_mode = S_IRUGO | S_IWUSR,
+};
+
+struct configfs_attribute *simple_child_attrs[] = {
+	&simple_child_attr_storeme,
+	NULL,
+};
+
+ssize_t simple_child_attr_show(struct config_item *item,
+		struct configfs_attribute *attr,
+		char *page)
+{
+	ssize_t count;
+	struct simple_child *simple_child = to_simple_child(item);
+
+	count = sprintf(page, "%d\n", simple_child->storeme);
+
+	return count;
+}
+
+ssize_t simple_child_attr_store(struct config_item *item,
+		struct configfs_attribute *attr,
+		const char *page, size_t count)
+{
+	struct simple_child *simple_child = to_simple_child(item);
+	unsigned long tmp;
+	char *p = (char *) page;
+
+	tmp = simple_strtoul(p, &p, 10);
+	if (!p || (*p && (*p != '\n')))
+		return -EINVAL;
+
+	if (tmp > INT_MAX)
+		return -ERANGE;
+
+	simple_child->storeme = tmp;
+
+	return count;
+}
+
+void simple_child_release(struct config_item *item)
+{
+	kfree(to_simple_child(item));
+}
+
+struct configfs_item_operations simple_child_item_ops = {
+	.release		= simple_child_release,
+	.show_attribute		= simple_child_attr_show,
+	.store_attribute	= simple_child_attr_store,
+};
+
+struct config_item_type simple_child_type = {
+	.ct_item_ops	= &simple_child_item_ops,
+	.ct_attrs	= simple_child_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
+
+struct simple_children {
+	struct config_group group;
+};
+
+inline struct simple_children *to_simple_children(struct config_item *item)
+{
+	return item ? container_of(to_config_group(item), struct simple_children, group) : NULL;
+}
+
+struct config_item *simple_children_make_item(struct config_group *group, const char *name)
+{
+	struct simple_child *simple_child;
+
+	simple_child = kzalloc(sizeof(struct simple_child), GFP_KERNEL);
+	if (!simple_child)
+		return ERR_PTR(-ENOMEM);
+
+	config_item_init_type_name(&simple_child->item, name,
+			&simple_child_type);
+
+	simple_child->storeme = 0;
+
+	return &simple_child->item;
+}
+
+struct configfs_attribute simple_children_attr_description = {
+	.ca_owner = THIS_MODULE,
+	.ca_name = "description",
+	.ca_mode = S_IRUGO,
+};
+
+struct configfs_attribute *simple_children_attrs[] = {
+	&simple_children_attr_description,
+	NULL,
+};
+
+ssize_t simple_children_attr_show(struct config_item *item,
+		struct configfs_attribute *attr,
+		char *page)
+{
+	return sprintf(page,
+			"[02-simple-children]\n"
+			"\n"
+			"This subsystem allows the creation of child config_items.  These\n"
+			"items have only one attribute that is readable and writeable.\n");
+}
+
+void simple_children_release(struct config_item *item)
+{
+	kfree(to_simple_children(item));
+}
+
+struct configfs_item_operations simple_children_item_ops = {
+	.release	= simple_children_release,
+	.show_attribute	= simple_children_attr_show,
+};
+
+/*
+ * Note that, since no extra work is required on ->drop_item(),
+ * no ->drop_item() is provided.
+ */
+struct configfs_group_operations simple_children_group_ops = {
+	.make_item	= simple_children_make_item,
+};
+
+struct config_item_type simple_children_type = {
+	.ct_item_ops	= &simple_children_item_ops,
+	.ct_group_ops	= &simple_children_group_ops,
+	.ct_attrs	= simple_children_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
+struct configfs_subsystem simple_children_subsys = {
+	.su_group = {
+		.cg_item = {
+			.ci_namebuf = "02-simple-children",
+			.ci_type = &simple_children_type,
+		},
+	},
+};
+
+
+/* ----------------------------------------------------------------- */
+
+/*
+ * 03-group-children
+ *
+ * This example reuses the simple_children group from above.  However,
+ * the simple_children group is not the subsystem itself, it is a
+ * child of the subsystem.  Creation of a group in the subsystem creates
+ * a new simple_children group.  That group can then have simple_child
+ * children of its own.
+ */
+
+struct config_group *group_children_make_group(struct config_group *group, const char *name)
+{
+	struct simple_children *simple_children;
+
+	simple_children = kzalloc(sizeof(struct simple_children),
+			GFP_KERNEL);
+	if (!simple_children)
+		return ERR_PTR(-ENOMEM);
+
+	config_group_init_type_name(&simple_children->group, name,
+			&simple_children_type);
+
+	return &simple_children->group;
+}
+
+struct configfs_attribute group_children_attr_description = {
+	.ca_owner = THIS_MODULE,
+	.ca_name = "description",
+	.ca_mode = S_IRUGO,
+};
+
+struct configfs_attribute *group_children_attrs[] = {
+	&group_children_attr_description,
+	NULL,
+};
+
+ssize_t group_children_attr_show(struct config_item *item,
+		struct configfs_attribute *attr,
+		char *page)
+{
+	return sprintf(page,
+			"[03-group-children]\n"
+			"\n"
+			"This subsystem allows the creation of child config_groups.  These\n"
+			"groups are like the subsystem simple-children.\n");
+}
+
+struct configfs_item_operations group_children_item_ops = {
+	.show_attribute	= group_children_attr_show,
+};
+
+/*
+ * Note that, since no extra work is required on ->drop_item(),
+ * no ->drop_item() is provided.
+ */
+struct configfs_group_operations group_children_group_ops = {
+	.make_group	= group_children_make_group,
+};
+
+struct config_item_type group_children_type = {
+	.ct_item_ops	= &group_children_item_ops,
+	.ct_group_ops	= &group_children_group_ops,
+	.ct_attrs	= group_children_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
+struct configfs_subsystem group_children_subsys = {
+	.su_group = {
+		.cg_item = {
+			.ci_namebuf = "03-group-children",
+			.ci_type = &group_children_type,
+		},
+	},
+};
+
+/* ----------------------------------------------------------------- */
+
+/*
+ * We're now done with our subsystem definitions.
+ * For convenience in this module, here's a list of them all.  It
+ * allows the init function to easily register them.  Most modules
+ * will only have one subsystem, and will only call register_subsystem
+ * on it directly.
+ */
+struct configfs_subsystem *example_subsys[] = {
+	&simple_children_subsys,
+	&group_children_subsys,
+	NULL,
+};
+
+int configfs_example_init(void)
+{
+	int ret;
+	int i;
+	struct configfs_subsystem *subsys;
+
+	for (i = 0; example_subsys[i]; i++) {
+		subsys = example_subsys[i];
+
+		config_group_init(&subsys->su_group);
+		mutex_init(&subsys->su_mutex);
+		ret = configfs_register_subsystem(subsys);
+		if (ret) {
+			printk(KERN_ERR "Error %d while registering subsystem %s\n",
+					ret,
+					subsys->su_group.cg_item.ci_namebuf);
+			goto out_unregister;
+		}
+	}
+
+	return 0;
+
+out_unregister:
+	for (; i >= 0; i--) {
+		configfs_unregister_subsystem(example_subsys[i]);
+	}
+
+	return ret;
+}
+
+void  configfs_example_exit(void)
+{
+	int i;
+
+	for (i = 0; example_subsys[i]; i++) {
+		configfs_unregister_subsystem(example_subsys[i]);
+	}
+}
+
+
diff --git a/security/blare/file_ops.c b/security/blare/file_ops.c
new file mode 100644
index 0000000..e0f8b45
--- /dev/null
+++ b/security/blare/file_ops.c
@@ -0,0 +1,371 @@
+/*  Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ */
+
+
+#include "blare.h"
+#include "include/itag.h"
+#include "include/ptags.h"
+#include "include/xattr.h"
+#include "include/legality.h"
+#include "include/audit.h"
+#include "include/file_ops.h"
+
+/* The current process may read a file */
+int blare_may_read(struct dentry *dp, struct blare_file_struct *fstruct){
+    int rc, icount,xpcount;
+    struct cred *cred;
+    struct blare_task_struct *tstruct;
+    //struct blare_audit_info audit;
+
+    /* Trusted processes do not propagate tags nor does the kernel swapper*/
+    if (blare_current_is_trusted() == 0 || (blare_enabled == 0) || (current->pid == 0))
+        return 0;
+
+    cred = prepare_creds();
+    if (unlikely(!cred || !cred->security)){
+        abort_creds(cred);
+        return -ENODATA;
+    }
+
+    if (fstruct->info_array)
+        blare_warn("Allocating a new info array but one already exists\n");
+
+    tstruct = cred->security;
+
+    /* Information tag propagation     
+     * blare_alloc_file_info is to be used along
+     * with blare_free_file_info*/
+    icount = blare_alloc_file_info(dp,fstruct);     
+    
+    /*
+    if (icount < 0)
+        blare_warn("error %d - couldn't read information tag from file %s", icount, dp->d_name.name);
+        */
+
+    if (icount > 0){
+        /* Thread 
+        if (current->pid != current->tgid){
+            //BLARE_DEBUG("Subthread: current pid [%d] / current tgid"
+            //"[%d]\n",current->pid,current->tgid);
+        }
+        */
+
+        if (file_is_excluded(fstruct)){
+            abort_creds(cred);
+            blare_free_file_info(fstruct);
+            printk(KERN_DEBUG"blare: may_read, file %s is excluded (0)\n", dp->d_name.name);
+            return 0;
+        }
+
+        rc = itag_insert(fstruct->info_array,fstruct->info_size,&tstruct->info_list,
+                    GFP_KERNEL, DISCARD_EXEC);
+        /*
+        if (rc > 0){ // Tag has changed
+            tstruct->info_rev++;
+            itag_print_msg(tstruct->info_list,"blare_file_read:");
+        }
+        */
+
+        blare_free_file_info(fstruct);
+
+        /* Note: here we want to continue with the other tags even if it fails
+         * except when ENOMEM*/
+        if (rc == -ENOMEM){
+            abort_creds(cred);
+            return rc; 
+        }
+
+        /* Now we're done with fstruct->info_array, we need to free it */
+    }
+
+
+    /* Also update eventual shared memory segments 
+       if (tstruct->shm && !(list_empty(tstruct->shm)))
+       blare_update_shm(tstruct->shm,tstruct->info_list);
+       */
+
+    /* Xptag propagation*/
+    xpcount = blare_alloc_file_xpolicy(dp,fstruct);
+    if (xpcount > 0){
+        rc = xptag_insert(fstruct->xpolicy_arrays, fstruct->xpolicy_count,
+                 &tstruct->xpolicy_list);
+        blare_free_file_xpolicy(fstruct);
+        if (rc == -ENOMEM){
+            blare_error(rc);
+            abort_creds(cred);
+            return rc;
+        }
+    }
+
+    /*Commit the new creds for the current process if something has changed
+    */
+    if (icount > 0 || xpcount > 0)
+        commit_creds(cred);
+    else{
+        abort_creds(cred);
+        return 0;
+    }
+
+    rc= check_policy(tstruct->info_list, tstruct->policy_list);
+    if (rc <0)
+        printk(KERN_CRIT "[BLARE_POLICY_VIOLATION] %s with pid %d "
+                "made an illegal READ access to file %s.\n"
+                ,current->comm,current->pid,dp->d_name.name);
+
+    //blare_log(blare_current_info_to_s(), "unknown", MAY_READ, rc, &audit);
+
+    /* Policy check*/
+    return rc;
+}
+
+int blare_may_append(struct dentry *dp, struct blare_file_struct *fstruct){
+    const struct cred *ro_cred;
+    struct blare_task_struct *tstruct;
+    int rc, icount, size;
+    struct list_head *newtag;
+
+    /* Trusted processes do not propagate tags */
+    if (blare_current_is_trusted() == 0 || (blare_enabled == 0) || (current->pid == 0))
+        return 0;
+
+    ro_cred = get_current_cred(); 
+    tstruct = ro_cred->security;
+
+    if (unlikely(!tstruct)){
+        put_cred(ro_cred);
+        return -ENODATA;
+    }
+
+    /* Nothing to write or append */
+    if (!tstruct->info_list || list_empty(tstruct->info_list)){
+        goto xptag;
+    }
+
+
+    icount = blare_alloc_file_info(dp,fstruct);
+    if (file_is_excluded(fstruct)){
+        put_cred(ro_cred);
+        blare_free_file_info(fstruct);
+        printk(KERN_DEBUG"blare: may_append, file %s is excluded (0)\n", dp->d_name.name);
+        return 0;
+    }
+
+    /* Is there something to append ? */
+    if (icount > 0){
+        newtag = itag_copy(tstruct->info_list, GFP_KERNEL);
+        //itag_print_msg(newtag, "newtag:");
+        rc = itag_insert(fstruct->info_array, fstruct->info_size, &newtag,
+                GFP_KERNEL, TAINT_EXEC);
+        if (rc < 0){
+            blare_error(rc);
+            itag_free(newtag);
+            blare_free_file_info(fstruct);
+            goto xptag;
+        }
+        rc = blare_write_info(dp,newtag);
+        blare_free_file_info(fstruct);
+    }
+    else{
+        blare_may_write(dp, fstruct);
+        blare_free_file_info(fstruct);
+    }
+    
+xptag:
+    //blare_debug("TODO: xptag append");
+
+    put_cred(ro_cred);
+    return 0;
+}
+
+/* The current process may write to the file */
+int blare_may_write(struct dentry *dp, struct blare_file_struct *fstruct){
+    const struct cred *ro_cred;
+    struct blare_task_struct *tstruct;
+    struct list_head *file_policy;
+    int rc;
+
+    /* Trusted processes do not propagate tags */
+    if (blare_current_is_trusted() == 0 || (blare_enabled == 0) || (current->pid == 0))
+        return 0;
+
+    ro_cred = get_current_cred(); 
+    tstruct = ro_cred->security;
+    //tstruct = current_security();
+
+    if (unlikely(!tstruct)){
+        put_cred(ro_cred);
+        return -ENODATA;
+    }
+
+    /* Should we propagate tags to this file ?*/
+    rc = blare_alloc_file_info(dp,fstruct);
+    if (file_is_excluded(fstruct)){
+        put_cred(ro_cred);
+        blare_free_file_info(fstruct);
+        blare_debug("may_write, file %s is excluded (0)\n", dp->d_name.name);
+        return 0;
+    }
+    else
+        blare_free_file_info(fstruct);
+
+    /* Information tags propagation 
+     * */
+    rc = blare_write_info(dp,tstruct->info_list);
+    if (rc !=0)
+        blare_warn("failed to write information tag to file \"%s\", error %d", dp->d_name.name, rc);
+
+    /* Propagate the execute policy */
+    rc = blare_write_xpolicy(dp,tstruct->xpolicy_list);
+    if (rc < 0)
+        blare_warn("failed to write xpolicy tag to file %s, error %d", dp->d_name.name, rc);
+
+    // Get the file's policy
+    rc = blare_alloc_file_cpolicy(dp,fstruct);
+
+    /* If there is a policy for the current file AND an information tag for
+     * the current process*/
+    if (rc > 0 && tstruct->info_list){
+        file_policy =
+            arrays2policytag(fstruct->policy_arrays,fstruct->policy_count);
+        blare_free_file_cpolicy(fstruct);
+
+        rc = check_policy(tstruct->info_list,file_policy);
+
+        if (rc < 0)
+            printk(KERN_CRIT "[BLARE_POLICY_VIOLATION] process with pid %d"
+                    "running %s wrote illegal information to file"
+                    "%s.\n",current->pid,current->comm,dp->d_name.name);
+
+        // Free the policy list & btrees...
+        policy_tag_free(file_policy);
+    }
+
+    put_cred(ro_cred);
+
+    return rc;
+}
+
+/* The current process may read a file */
+int blare_may_exec(struct dentry *dp, struct blare_file_struct *fstruct){
+    int rc, icount,xpcount;
+    struct cred *cred;
+    struct blare_task_struct *tstruct;
+    //struct blare_audit_info audit;
+    struct list_head *fxptag = NULL;
+
+    /* Trusted processes do not propagate tags nor does the kernel swapper*/
+    if (blare_current_is_trusted() == 0 || (blare_enabled == 0) || (current->pid == 0))
+        return 0;
+
+    cred = prepare_creds();
+    if (unlikely(!cred || !cred->security)){
+        abort_creds(cred);
+        return -ENODATA;
+    }
+
+    tstruct = cred->security;
+
+    /* Information tag propagation */
+    icount = blare_alloc_file_info(dp,fstruct);
+    /*
+    if (icount < 0)
+        blare_warn("error %d - couldn't read information tag from file %s", icount, dp->d_name.name);
+        */
+
+    if (icount > 0){
+        /* Thread 
+        if (current->pid != current->tgid){
+            //BLARE_DEBUG("Subthread: current pid [%d] / current tgid"
+            //"[%d]\n",current->pid,current->tgid);
+        }
+        */
+
+        if (file_is_excluded(fstruct)){
+            abort_creds(cred);
+            blare_free_file_info(fstruct);
+            printk(KERN_DEBUG"blare: may_exec, file %s is excluded (0)\n", dp->d_name.name);
+            return 0;
+        }
+
+        rc = itag_insert(fstruct->info_array,fstruct->info_size,&tstruct->info_list,
+                    GFP_KERNEL, TAINT_EXEC);
+        if (rc > 0){ // Tag has changed
+            //tstruct->info_rev++;
+            itag_print_msg(tstruct->info_list,"blare_may_exec:");
+        }
+
+        blare_free_file_info(fstruct);
+
+        /* Note: here we want to continue with the other tags even if it fails
+         * except when ENOMEM*/
+        if (rc == -ENOMEM){
+            abort_creds(cred);
+            return rc; 
+        }
+    }
+
+    xpcount = blare_alloc_file_xpolicy(dp,fstruct);
+    if (xpcount > 0){
+        fxptag = arrays2policytag(fstruct->xpolicy_arrays, fstruct->xpolicy_count);
+        /* Intersect the policy tag of the current process with the xptag of the
+         * executed file */
+        xptag_merge(&tstruct->policy_list, fxptag);
+        blare_free_file_xpolicy(fstruct);
+    }
+
+    if (icount > 0 || xpcount > 0)
+        commit_creds(cred);
+    else
+        abort_creds(cred);
+
+    if (fxptag)
+        policy_tag_free(fxptag);
+
+    /* Check for policy violation */
+    rc = check_policy(tstruct->info_list, tstruct->policy_list);
+    if (rc < 0)
+        printk(KERN_CRIT "[BLARE_POLICY_VIOLATION] process with pid %d"
+                "running %s wrote illegal information to file"
+                "%s.\n",current->pid,current->comm,dp->d_name.name);
+
+
+    return rc;
+}
+
+/* blare_file_struct has pointers to inner structures.
+ * This function frees the inner structures, but doesn't free the
+ * blare_file_struct itself*/
+void blare_free_fstruct (struct blare_file_struct *fstruct){
+    int i;
+
+    if (fstruct->info_array)
+        kfree(fstruct->info_array);
+
+    if (fstruct->policy_arrays){
+        for(i=0;i<fstruct->policy_count;i++)
+            kmem_cache_free(blare_policy_array_cache,fstruct->policy_arrays[i]);
+    }
+
+    if (fstruct->xpolicy_arrays){
+        for(i=0;i<fstruct->xpolicy_count;i++)
+            kmem_cache_free(blare_policy_array_cache,fstruct->xpolicy_arrays[i]);
+    }
+
+}
+
+inline int file_is_excluded(struct blare_file_struct *fstruct){
+    if (!fstruct || !fstruct->info_array || fstruct->info_size < 1)
+        return false;
+
+    if (fstruct->info_array[0] == 0)
+        return true;
+
+    return false;
+}
diff --git a/security/blare/include/audit.h b/security/blare/include/audit.h
new file mode 100644
index 0000000..75cb072
--- /dev/null
+++ b/security/blare/include/audit.h
@@ -0,0 +1,16 @@
+#include <linux/lsm_audit.h>
+
+#define NB_ACCESS_MODES 5 // rwxat (inspired from Smack)
+
+struct blare_audit_info{
+#ifdef CONFIG_AUDIT
+	struct common_audit_data a;
+#endif
+};
+
+void blare_log(char *subject_label, char *object_label, int mode,
+	       int legal, struct blare_audit_info *bai);
+
+inline void str_from_perm(char *string, int access);
+
+
diff --git a/security/blare/include/file_ops.h b/security/blare/include/file_ops.h
new file mode 100644
index 0000000..fea119b
--- /dev/null
+++ b/security/blare/include/file_ops.h
@@ -0,0 +1,14 @@
+#ifndef __BLARE_FOPS_H
+#define __BLARE_FOPS_H
+
+int blare_may_read(struct dentry *dp, struct blare_file_struct *fstruct);
+int blare_may_write(struct dentry *dp, struct blare_file_struct *fstruct);
+int blare_may_exec(struct dentry *dp, struct blare_file_struct *fstruct);
+void blare_free_fstruct (struct blare_file_struct *fstruct);
+
+/* Excluded files do not propagate taint. This is useful for logfiles and the
+ * like */
+inline int file_is_excluded(struct blare_file_struct *fstruct);
+int blare_may_append(struct dentry *dp, struct blare_file_struct *fstruct);
+
+#endif
diff --git a/security/blare/include/itag.h b/security/blare/include/itag.h
new file mode 100644
index 0000000..9daf100
--- /dev/null
+++ b/security/blare/include/itag.h
@@ -0,0 +1,79 @@
+/* Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ */
+
+
+#ifndef __BLARE_ITAG_H
+#define __BLARE_ITAG_H
+
+/* When processes write or append to a file, they propagate their information
+ * tag, which is composed of negative and positive values, corresponding to
+ * elements in  I or X (see ICC 2011 article). 
+ * When processes read a file, they are only tainted by the positive values,
+ * i.e. negative values are discared, hence READ_MODE */
+#define DISCARD_EXEC 0x01 //Discard negative values in information tags
+#define TAINT_EXEC 0x02
+
+int itag2array(struct list_head *list, int **buffer);
+struct list_head *array2itag(int *array, int size);
+inline struct list_head *itag_exec(int *array, int size);
+struct list_head *array2itag_generic(int *array, int size, bool exec);
+
+int itag_insert(int *array, int size, struct list_head **head, gfp_t flags, int exec_flag);
+struct list_head *itag_copy(struct list_head *head, gfp_t gfp_flags);
+struct list_head *itag_copy_rcu(struct list_head *head);
+
+void itag_print(struct list_head *head);
+int itag_count(struct list_head *head);
+void itag_free(struct list_head *head);
+void array_print(int*array, int size);
+int itag_merge(struct list_head* a, struct list_head *b, gfp_t flags);
+int itag_merge_rcu(struct list_head* a, struct list_head *b);
+int itag_alloc(struct list_head **security);
+struct blare_thread *blare_current_threadinfo(struct list_head *tlist);
+char *itag_to_s(struct list_head *head);
+
+/* Moved to netlabel.h */
+uint8_t *blare_itag2bitmap(struct list_head *itag);
+//struct list_head *blare_bitmap2itag(uint8_t *bitmap);
+//struct list_head *blare_catmap2itag(struct netlbl_lsm_secattr_catmap *catmap);
+//int blare_itag2catmap(struct list_head *itag, struct netlbl_lsm_secattr_catmap *catmap);
+// int itag2secattr(struct list_head *itag, struct netlbl_lsm_secattr *secattr);
+
+void itag_print_msg(struct list_head *head, const char* msg, ...);
+
+int itag_check_sanity(struct list_head *itag);
+
+/* Helper functions */
+static inline void itag_debug(struct list_head *itag, const char *msg){
+    if(DEBUG_INFO && itag)
+        itag_print_msg(itag,msg);
+}
+
+/* Returns a reference on the current itag.
+ * */
+static inline struct list_head* current_itag_copy(gfp_t flags){
+    struct blare_task_struct *tstruct;
+    const struct cred *cred; 
+    struct list_head *itag;
+
+    cred = get_current_cred();
+    if(unlikely(!cred || !cred->security)){
+        put_cred(cred);
+        blare_error(-ENODATA);
+        return NULL;
+    }
+
+    tstruct = cred->security;
+    itag = itag_copy(tstruct->info_list, flags);
+    put_cred(cred);
+    return itag;
+}
+
+#endif
diff --git a/security/blare/include/itag_rcu.h b/security/blare/include/itag_rcu.h
new file mode 100644
index 0000000..3f72821
--- /dev/null
+++ b/security/blare/include/itag_rcu.h
@@ -0,0 +1,33 @@
+/* Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ */
+
+
+#ifndef __BLARE_ITAG_RCU_H
+#define __BLARE_ITAG_RCU_H
+
+int itag2array_rcu(struct list_head *list, int **buffer);
+int itag_insert_rcu(int *array, int size, struct list_head **head, gfp_t flags);
+int itag_count_rcu(struct list_head *head);
+int itag_merge_rcu(struct list_head *a, struct list_head *b);
+int itag_check_sanity_rcu(struct list_head *head);
+void itag_free_rcu(struct list_head *head);
+
+int itag_basic_check_rcu(struct list_head *head);
+int itag_check_order_rcu(struct list_head *head);
+int itag_check_null_pointer_rcu(struct list_head *head);
+
+/*
+static int itag_basic_check_rcu(struct list_head *head);
+static int itag_check_order_rcu(struct list_head *head);
+static int itag_check_null_pointer_rcu(struct list_head *head);
+*/
+
+
+#endif
diff --git a/security/blare/include/legality.h b/security/blare/include/legality.h
new file mode 100644
index 0000000..6ff9684
--- /dev/null
+++ b/security/blare/include/legality.h
@@ -0,0 +1,19 @@
+/* Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ */
+
+
+#ifndef __BLARE_LEG_H
+#define __BLARE_LEG_H
+
+/* Functions from legality.c */
+int check_policy(struct list_head* info_list, struct list_head* policy_list);
+int check_netpolicy(struct list_head* info_list);
+
+#endif
diff --git a/security/blare/include/lib.h b/security/blare/include/lib.h
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/security/blare/include/lib.h
@@ -0,0 +1 @@
+
diff --git a/security/blare/include/mmap.h b/security/blare/include/mmap.h
new file mode 100644
index 0000000..22fbc82
--- /dev/null
+++ b/security/blare/include/mmap.h
@@ -0,0 +1,36 @@
+/* Shared memory mappings (mmap) don't have any file descriptor when the MAP_ANONYMOUS flag is
+ * used. Therefore, we maintain a tree to store tags related to each mapping. 
+ *
+ * Processes have a list of bound mmaps. A mmap is bound to a process when the
+ * process calls shmat, until it calls shmdt for a given memory segment.
+ * */
+
+#include <linux/list.h>
+#include "../blare.h"
+#include <linux/rbtree.h>
+
+/* This structure is used in the global mmap tree, where mmaps are sorted by
+ * addresses 
+ * @node: the red black tree node
+ * @addr: the address of the memory mapping
+ * @tags: blare tags associated with this mmap
+ * @refcount: how many processes are currently bound to this mmap
+ * */
+struct blare_mmap_struct{
+    struct rb_node node;
+    long addr;
+    struct blare_tags *tags;
+    atomic_t refcount;
+};
+
+/* This structure is used by processes in their lists of bound mmaps 
+ * @node is the list node
+ * @mmap is a pointer to the structure residing in the global tree for a given
+ * mmap*/
+struct blare_mmap_bound{
+    struct list_head node;
+    struct blare_mmap_struct *mmap;
+};
+
+struct blare_mmap_struct *blare_mmap(unsigned long addr);
+
diff --git a/security/blare/include/netlabel.h b/security/blare/include/netlabel.h
new file mode 100644
index 0000000..1438f32
--- /dev/null
+++ b/security/blare/include/netlabel.h
@@ -0,0 +1,36 @@
+/* Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ */
+
+
+#include <linux/list.h>
+#include <net/netlabel.h>
+#include "../blare.h" 
+
+#ifndef __BLARE_NETLABEL_H
+#define __BLARE_NETLABEL_H
+
+#define BLARE_BITMAP_SIZE 32 // UNUSED 
+#define BLARE_BITMAP_MAX 239  // how many tags in the bitmap, see the RFC
+#define BLARE_CIPSO_LEVEL 200 
+#define BLARE_CIPSO_DOI 3 // Arbitrary
+#define BLARE_CIPSO_HOST_LABEL_MAX 255
+#define BLARE_CIPSO_DOMAIN "BLARE_CIPSOv4"
+#define BLARE_CIPSO_UNLBL "BLARE_UNLBL"
+
+#define	INADDR_HOSTIP ((unsigned long int) 0x0a000001)
+#define	INADDR_HOSTMASK ((unsigned long int) 0xffffff00)
+
+void blare_cipso_doi(void);
+struct list_head *blare_catmap2itag(struct netlbl_lsm_secattr_catmap *catmap);
+int blare_itag2secattr(struct list_head *itag, struct netlbl_lsm_secattr *secattr);
+int blare_label_socket(struct socket *socket);
+int blare_netlabel_insert(struct blare_tags *tags, struct netlbl_lsm_secattr_catmap *catmap);
+
+#endif
diff --git a/security/blare/include/network.h b/security/blare/include/network.h
new file mode 100644
index 0000000..58f63ec
--- /dev/null
+++ b/security/blare/include/network.h
@@ -0,0 +1,12 @@
+/* Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ */
+
+
+int blare_network_policy_add(int *data, size_t size);
diff --git a/security/blare/include/ptags.h b/security/blare/include/ptags.h
new file mode 100644
index 0000000..7932e80
--- /dev/null
+++ b/security/blare/include/ptags.h
@@ -0,0 +1,34 @@
+/* Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ */
+
+
+#ifndef __BLARE_PTAGS_H
+#define __BLARE_PTAGS_H
+
+struct rb_root *array2tree(int *array, int size);
+int tree_insert(struct rb_root *root, struct tree_item *new);
+struct list_head* arrays2policytag(struct policy_array **arrays, int policy_count);
+void tree_free(struct rb_root *root);
+void policytag_print(struct list_head *head);
+void policy_tag_free(struct list_head *head);
+struct tree_item *tree_search(struct rb_root *root, int value);
+int tree_is_subset(struct policy_tree *a, struct policy_tree *b);
+struct policy_tree *intersection(struct policy_tree *a, struct policy_tree *b);
+int xptag_insert(struct policy_array **xpolicy_arrays, int xpolicy_count, struct list_head **xpolicy_list);
+void tree_print(struct rb_root *root);
+struct list_head *ptag_copy(struct list_head *head);
+struct rb_root *tree_copy(struct rb_root *root);
+int *ptree2array(struct policy_tree *ptree);
+
+
+void xptag_merge(struct list_head **a, struct list_head *b);
+struct list_head *common_sets(struct list_head *a, struct list_head *b);
+
+#endif
diff --git a/security/blare/include/shm.h b/security/blare/include/shm.h
new file mode 100644
index 0000000..b6e1bb5
--- /dev/null
+++ b/security/blare/include/shm.h
@@ -0,0 +1,21 @@
+/* Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ */
+
+
+#ifndef __BLARE_SHM
+#define __BLARE_SHM
+
+struct list_head *shm_list_copy(struct list_head *list);
+void shm_list_free(struct list_head *list);
+int blare_update_shm_tags(struct list_head *list, struct list_head *info);
+int shm_list_add(struct kern_ipc_perm *isp, struct list_head **list, int shmflg);
+void shm_list_del(struct kern_ipc_perm *isp, struct list_head *list);
+
+#endif
diff --git a/security/blare/include/test.h b/security/blare/include/test.h
new file mode 100644
index 0000000..8cadfd5
--- /dev/null
+++ b/security/blare/include/test.h
@@ -0,0 +1,20 @@
+/* Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ */
+
+
+#ifndef __BLARE_TEST_H
+#define __BLARE_TEST_H
+
+/*Functions from blare_test.c */
+void test_alloc(void);
+void list_test(void);
+int checklist(struct list_head *head);
+
+#endif
diff --git a/security/blare/include/trace.h b/security/blare/include/trace.h
new file mode 100644
index 0000000..673d23a
--- /dev/null
+++ b/security/blare/include/trace.h
@@ -0,0 +1,25 @@
+ /*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ *
+ *  Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ */
+
+void blare_init_trace(struct dentry *dp, struct blare_task_struct *tstruct);
+void blare_trace(int type, int mode, int flags, struct file *file, int id);
+
+
+#define TRACE_MMAP 1
+#define TRACE_FILE 2
+#define TRACE_SHM 3
+#define TRACE_INET 4
+#define TRACE_UNIX 5
+#define TRACE_MSGQ 6
+#define TRACE_PIPE 7
+#define TRACE_CLONE 8
+
+#define MMAP_FLAGS 21 //strlen("MAP_ANONYNOUS +MAP_SHARED +MAP_PRIVATE");
diff --git a/security/blare/include/xattr.h b/security/blare/include/xattr.h
new file mode 100644
index 0000000..450dc75
--- /dev/null
+++ b/security/blare/include/xattr.h
@@ -0,0 +1,27 @@
+/* Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ */
+
+
+int blare_check_trace_flag(struct dentry *dp, int **ptr);
+
+int blare_alloc_file_cpolicy(struct dentry *dp, struct blare_file_struct *fstruct);
+void blare_free_file_cpolicy(struct blare_file_struct *fstruct);
+
+int blare_alloc_file_info(struct dentry *d, struct blare_file_struct *fstruct);
+void blare_free_file_info(struct blare_file_struct *fstruct);
+
+int blare_alloc_file_xpolicy(struct dentry *dp, struct blare_file_struct *fstruct);
+void blare_free_file_xpolicy(struct blare_file_struct *fstruct);
+
+int blare_write_info(struct dentry *d, struct list_head *list);
+int blare_write_xpolicy(struct dentry *dp, struct list_head *xpolicy_list);
+
+
+
diff --git a/security/blare/itag.c b/security/blare/itag.c
new file mode 100644
index 0000000..8b4f864
--- /dev/null
+++ b/security/blare/itag.c
@@ -0,0 +1,540 @@
+/* Information tag functions - non RCU versions
+ *
+ *  Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ */
+#include "blare.h"
+#include "include/itag.h"
+
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/rbtree.h>
+#include <linux/errno.h>
+
+/* Local static functions */
+static int itag_check_order(struct list_head *head);
+static int itag_check_null_pointer(struct list_head *head);
+static int itag_basic_check(struct list_head *head);
+
+
+/* This function is used to serialize information tags (lists) 
+ * The serialized representation is an array if int and can thus be written
+ * to the extended attributes of the filesystem. */
+
+int itag2array(struct list_head *list, int **buffer){
+    struct information *info;
+    int *array, i=0, size=0, buffersize;
+
+    if (!list)
+        return 0;
+
+    if (list_empty(list))
+        return 0;
+
+    // Count the number of items in the list
+    list_for_each_entry(info, list, node){
+        size ++;
+    }
+
+    if (size == 0) 
+        return 0;
+
+    buffersize = size * sizeof(int);
+    array = (int*)kmalloc(buffersize,GFP_KERNEL);
+
+    if (!array) 
+        return -ENOMEM;
+
+    // Fill the array (in reverse order)
+    list_for_each_entry(info, list, node){
+        if (i>=size) break; // just make sure we don't get out of the array bounds
+        array[i] = info->value;
+        i++;
+    }
+
+    *buffer = array;
+
+    if (DEBUG_INFO){
+        blare_debug("[itag2array]: corresponding array has size %d: ",size);
+        array_print(array,size);
+       }
+
+    return size;
+}
+
+
+/* Don't call this function, use array2itag or exec instead
+ * Create a new (ordered) list of struct information elements (i.e. an information tag)
+ * from an (ordered) array of int
+ * Returns : the head of the list*/
+struct list_head *array2itag_generic(int *array, int size, bool exec){
+    struct list_head *head;
+    int i;
+    struct  information *new;
+
+    // If the array is null, there is no information
+    if (!array || !size || size <=0) 
+        return NULL;
+
+    head = kmalloc(sizeof(struct list_head), GFP_KERNEL);
+
+    if (!head) 
+        return NULL;
+
+    /* Note : head is a standalone list_head element to describe the list
+     * see the list_add macro from linux/list.h */
+    INIT_LIST_HEAD(head);
+
+    //For each element in the array
+    for(i=0;i<size;i++){
+        /* Discard negative tags (which should only be propagated on write
+         * access. We don't reread them afterwards)
+         */
+        if (array[i] < 0) continue;
+
+        new = kmem_cache_alloc(blare_info_cache,GFP_KERNEL);
+        if (!new) return NULL;
+        INIT_LIST_HEAD(&new->node);
+
+        if (exec){
+            new->value = -array[i];
+            list_add(&new->node,head);
+        }
+        else{
+            new->value = array[i];
+            list_add_tail(&new->node,head);
+        }
+    }
+
+    /* If the array only had negative elements, we have an empty list */
+    if (list_empty(head)){
+        kfree(head);
+        head = NULL;
+    }
+    return head;
+}
+
+/* This stub function is used when reading an information tag
+ * from the extended attributes of the filesystem. */
+
+struct list_head *array2itag(int *array, int size){
+    return array2itag_generic(array,size,false);
+}
+
+/* This stub function is used when executing code. The information tag
+ * is read from the filesystem, and transformed into negatives values
+ * (running code). */
+
+inline struct list_head *itag_exec(int *array, int size){
+    return array2itag_generic(array,size,true);
+}
+
+/* Fills an existing (ordered) list of struct information elements (i.e. information tag) 
+ * from an (ordered) array of int (xattr representation).
+ * Returns : the new head of the list.
+ * @exec_flag: determines whether we should discard the execution part of the
+ * itag (i.e. elements of X represented by negative values).
+ * When reading a regular file, those should be discarded. When executing code,
+ * the current process should merge its itag with exec(itag_of_file).
+ * */
+int itag_insert(int *array, int size, struct list_head **head, gfp_t flags, int exec_flag){
+    //struct list_head *position;
+    struct information *info, *new;
+    int i=0, count=0;
+
+    BLARE_WARN_ON((!head || !array || size<=0),"NULL pointers in itag_insert()"
+            "parameters, this should NOT happen");
+
+    if (!head || !array || size <=0) return -1;
+
+    // If there is no list yet, then we we create a new one from the array
+    if (!*head){
+        *head = array2itag(array,size);
+        return 0;
+    }
+
+    list_for_each_entry(info, *head, node){
+        /* We don't restart at the beginning of the array*/
+        for(i=i; i<size; i++){
+            // Discard negative tags (those are only propagated on write access)
+            if (array [i] < 0 && (exec_flag & DISCARD_EXEC)) continue;
+
+            if (array[i] == info->value){
+                i++; 
+                break; //break the loop and iterate over the list
+            }
+
+            if (array[i] > info->value && ! list_is_last(&info->node,*head))
+                break;
+
+            new = kmem_cache_alloc(blare_info_cache,flags);
+            if (!new){
+                BLARE_DEBUG("[itag_insert] No mem :(\n");
+                return -ENOMEM;
+            }
+            new->value = array[i];
+
+            if (array[i] < info->value)
+                list_add_tail(&new->node,&info->node);
+            else
+                list_add(&new->node,&info->node);
+            count ++;
+        }
+    }
+    return count;
+}
+
+
+/*Print the content of an information tag (list) */
+void itag_print(struct list_head *head){
+    char *str;
+    str = itag_to_s(head);
+    printk(KERN_INFO "blare: %s (pid %d) %s\n", current->comm, current->pid, str);
+    kfree(str);
+}
+
+void itag_print_msg(struct list_head *head, const char* msg, ...){
+    va_list args;
+
+    char *str = itag_to_s(head);
+    if (str){
+        va_start(args, msg);
+        //printk(KERN_DEBUG "blare: %s (pid %d) %s %s\n", current->comm, current->pid, msg, str);
+        printk(KERN_DEBUG "blare: _%s(pid %d)_  %s: ", current->comm, current->pid, str);
+        vprintk(msg, args);
+        kfree(str);
+        va_end(args);
+    }
+}
+
+/* This function alloates memory - don't forget to free it
+ * This function also sucks, use it at your own risk :).
+ * TODO: cleanup all that junk, or just remove it.
+ */
+char *itag_to_s(struct list_head *head){
+    char *str = NULL, *msg;
+    struct information *infoptr;
+    int size=0, rc;
+
+    rc = itag_check_sanity(head);
+    if ( rc != 0){
+        blare_error(rc);
+        msg = "(sanity error)";
+        goto alloc;
+    }
+
+    if (!head){
+        msg = "(null)";
+        goto alloc;
+    }
+
+    else if (list_empty(head)){
+        msg = "(list_empty)";
+        goto alloc;
+    }
+
+    else{
+        msg = "itag[";
+        size = (strlen(msg)) * sizeof(char); 
+        list_for_each_entry(infoptr, head, node){
+            //infoptr = list_entry(position, struct information, node);
+            if (infoptr){
+                size += snprintf(NULL, 0, "%d ", infoptr->value); //just counts size
+            }
+        }
+        size += snprintf(NULL, 0, "]");
+        /*sizeof(char) because strlen and sprintf don't count the terminating \0 char */
+        str = (char*)kzalloc(size + sizeof(char), GFP_ATOMIC); 
+        if (!str){
+            return "ERROR";
+        }
+        sprintf(str, "%s", msg);
+        list_for_each_entry(infoptr, head, node){ 
+            //infoptr = list_entry(position, struct information, node); 
+            if (infoptr)
+                sprintf(str + strlen(str), "%d ", infoptr->value); 
+        }
+
+        // strlen - 1 because we overwrite the last space
+        sprintf(str + strlen(str) - 1, "]"); 
+    }
+
+    return str;
+
+alloc: // const char* to char* so we can kfree it later.
+    size = (strlen(msg) + 1) * sizeof(char);
+    str = (char*)kmalloc(size, GFP_KERNEL);
+    sprintf(str, "%s", msg);
+    return str;
+}
+
+int itag_count(struct list_head *head){
+    int i=0;
+    struct information *info;
+
+    if (!head) return -1;
+    list_for_each_entry(info, head, node)
+        i++;
+    return i;
+}
+
+/* Free an itag */
+void itag_free(struct list_head *head){
+    struct list_head *position, *tmp;
+    struct information *info;
+
+    // In case there is no list
+    if (!head) return;
+
+    
+    rc = itag_check_sanity(head);
+    if (rc !=0){
+        blare_error(rc);
+        return;
+    }
+    
+
+    list_for_each_safe(position, tmp, head){
+        info = list_entry(position, struct information, node);
+        list_del(position);
+        if (info)
+            kmem_cache_free(blare_info_cache,info);
+        else
+            blare_warn("itag_free: itag has null entries :(");
+    }
+    kfree(head); 
+}
+
+/* Allocates a new information tag.
+ * On success, returns 0 and @security points to the new information tag.
+ * On failure to allocate memory, returns -ENOMEM
+ */
+int itag_alloc(struct list_head **security){
+    struct list_head *itag;
+
+    itag = kmalloc(sizeof(struct list_head),GFP_KERNEL);
+    if(!itag) return -ENOMEM;
+
+    INIT_LIST_HEAD(itag);
+    *security = itag;
+    return 0;
+}
+
+struct list_head *itag_copy(struct list_head *head, gfp_t gfp_flags){
+    struct list_head *newhead;
+    struct information *infoptr, *new = NULL;
+
+    if (!head){ 
+        BLARE_DEBUG("(itag_copy) Error: NULL head");
+        return NULL;
+        //return ERR_PTR(-ENODATA);
+    }
+
+    newhead = kmalloc(sizeof(struct list_head), gfp_flags);
+    if (!newhead) goto nomem; 
+
+    INIT_LIST_HEAD(newhead);
+
+    list_for_each_entry(infoptr, head, node){
+        new = kmem_cache_alloc(blare_info_cache,gfp_flags);
+        if (!new){
+            goto nomem;
+        }
+
+        INIT_LIST_HEAD(&new->node);
+        new->value = infoptr->value;
+        list_add_tail(&new->node,newhead);
+    }
+    return newhead;
+
+nomem:
+    BLARE_DEBUG("[itag_copy] ERROR: not enough memory\n");
+    itag_free(newhead);
+    //return ERR_PTR(-ENOMEM);
+    return NULL;
+}
+
+
+/* This is the non-RCU version of itag-merge */
+int itag_merge(struct list_head *a, struct list_head *b, gfp_t flags){
+    struct list_head *itema, *itemb;
+    struct information *infoa, *infob, *new;
+    int count=0;
+
+    /* We don't like NULL pointers */
+    if (!a || !b) return -1;
+
+    /* Nothing to merge */
+    if (list_empty(b))
+        return 0;
+
+    /* This should not happen, itag_copy has to be used in this case */
+    if (list_empty(a))
+        return -ENODATA;
+
+    // Pick b's first item (b itself isn't embedded in any structure)
+    infoa = list_first_entry(a, struct information, node);
+    infob = list_first_entry(b, struct information, node);
+    itema = &infoa->node;
+    itemb = &infob->node;
+
+    do {
+        infoa = list_entry(itema,struct information, node);
+        infob = list_entry(itemb,struct information, node);
+
+        if (!infoa || !infob){
+            return -2;
+        }
+
+        /* Avoid deadlooping on equal lists */
+        if(infoa->value == infob->value && list_is_last(itema,a) &&
+                list_is_last(itemb,b))
+            goto out;
+
+        else if(infoa->value == infob->value){
+            itema = itema->next;
+            itemb = itemb->next;
+        }
+
+        else if (infoa->value < infob->value && !list_is_last(itema,a)){
+            itema = itema->next;
+        }
+
+        else{
+            new = kmem_cache_alloc(blare_info_cache,flags); 
+            if (!new){
+                goto nomem;
+            }
+            new->value = infob->value;
+
+            // Add smaller values at the head
+            if (infob->value < infoa->value) 
+                list_add_tail(&new->node,itema);
+            else
+                // Add higher values at the tail 
+                list_add(&new->node,itema);
+
+            itemb = itemb->next;
+            count ++; // How many new items
+        }
+
+    } while (!list_is_last(itemb->prev,b));
+
+out:
+    return count;
+nomem:
+    BLARE_DEBUG("-ENOMEM in itag_insert :(");
+    return -ENOMEM;
+}
+
+/* Prints a given array of int */
+void array_print(int *array, int size){
+    int i;
+    BLARE_DEBUG("[array_print] ");
+    for(i=0;i<size;i++)
+        printk(KERN_DEBUG "%d, ",array[i]);
+    printk("\n");
+}
+
+
+/* Check the sanity of an itag (for null pointers and ordering
+ * errors) */
+int itag_check_sanity(struct list_head *itag){
+    int rc;
+
+    if(!itag)
+        return 0; // Not unsafe
+
+    /* rc in {0, -2, -3, -4}*/
+    rc = itag_basic_check(itag);
+    if (rc != 0){
+        return rc;
+    }
+
+    /* rc in {0, -5} */
+    rc = itag_check_null_pointer(itag);
+    if (rc !=0){
+        blare_debug("itag is not safe, it has null pointers (error %d)",rc);
+        return rc;
+    }
+
+    /* rc in {0, -1} */
+    rc = itag_check_order(itag);
+    if (rc !=0){
+        blare_debug("itag is not safe, its ordering is wrong (error %d)",rc);
+        return rc;
+    }
+
+    return 0;
+}
+
+
+
+/* Static functions - don't call them directly 
+ * *******************************************/
+
+
+/* For debug purpose
+ * An itag should always be sorted in ascending order. If it is not the case, it
+ * is broken and that seriously sucks*/
+static int itag_check_order(struct list_head *head){
+    struct information *info;
+    int x;
+
+    info = list_first_entry(head, struct information, node);
+    x = info->value;
+    list_for_each_entry(info, head, node){
+        if (info->value == 0)
+            continue;
+        if (info->value < x){
+            return -1;
+        }
+        x = info->value;
+    }
+    return 0;
+}
+
+/* Debug, check for NULL pointers or ERR_PTR in an itag*/
+static int itag_basic_check(struct list_head *head){
+    if (!head)
+        return -2;
+
+    if(IS_ERR(head))
+        return(PTR_ERR(head));
+
+    if (!head->next)
+        return -3;
+
+    if (!head->prev)
+        return -4;
+
+    return 0;
+}
+
+
+/* Debug, check recursively for errors in an itag */
+static int itag_check_null_pointer(struct list_head *head){
+    struct list_head *pos;
+    struct information *info;
+    int rc;
+
+    list_for_each_entry(info, head, node){
+        pos = &info->node;
+        if (!pos)
+            return -5;
+
+        rc = itag_basic_check(pos);
+
+        if(rc !=0)
+            return rc;
+    }
+    return 0;
+}
+
+
diff --git a/security/blare/itag_rcu.c b/security/blare/itag_rcu.c
new file mode 100644
index 0000000..b9983d5
--- /dev/null
+++ b/security/blare/itag_rcu.c
@@ -0,0 +1,478 @@
+/* Information tag functions, RCU version
+ *
+ *  Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ */
+#include "blare.h"
+#include "include/itag.h"
+
+#include <linux/list.h>
+#include <linux/rculist.h>
+#include <linux/slab.h>
+#include <linux/rbtree.h>
+#include <linux/errno.h>
+
+/* Local static functions - not exported in itag_rcu.h*/
+static int itag_check_order_rcu(struct list_head *head);
+static int itag_check_null_pointer_rcu(struct list_head *head);
+static int itag_basic_check_rcu(struct list_head *head);
+
+
+/* This function is used to serialize information tags (lists). The serialized
+ * representation is an array of int, which is contigous in memory and can thus
+ * be dumped to the extended attributes of the filesystem straight away. */
+
+int itag2array_rcu(struct list_head *list, int **buffer){
+    struct information *info;
+    struct list_head *l;
+    int *array, i=0, size=0, buffersize;
+
+    rcu_read_lock();
+    l = rcu_dereference(list);
+    if (!l || list_empty(l)){
+        rcu_read_unlock();
+        return 0;
+    }
+
+    // Count the number of items in the list
+    list_for_each_entry_rcu(info, list, node){
+        size ++;
+    }
+    rcu_read_unlock();
+
+    if (size == 0) 
+        return 0;
+
+    buffersize = size * sizeof(int);
+    array = (int*)kmalloc(buffersize,GFP_KERNEL);
+
+    if (!array) 
+        return -ENOMEM;
+
+    // Fill the array (in reverse order)
+    rcu_read_lock();
+    list_for_each_entry_rcu(info, list, node){
+        if (i>=size) break; // just make sure we don't get out of the array bounds
+        //info = list_entry_rcu(item, struct information, node);
+        array[i] = info->value;
+        i++;
+    }
+    rcu_read_unlock();
+
+    *buffer = array;
+
+    if (DEBUG_INFO){
+        blare_debug("[itag2array]: corresponding array has size %d: ",size);
+        array_print(array,size);
+       }
+
+    return size;
+}
+
+
+
+/* Fills an existing (ordered) list of struct information elements (i.e. information tag) 
+ * from an (ordered) array of int (xattr representation).
+ * Returns : the new head of the list */
+int itag_insert_rcu(int *array, int size, struct list_head **head, gfp_t flags){
+    //struct list_head *position;
+    struct information *info, *new;
+    int i=0;
+
+    BLARE_WARN_ON((!head || !array || size<=0),"NULL pointers in itag_insert()"
+            "parameters, this should NOT happen");
+
+    if (!head || !array || size <=0) return -1;
+
+    // If there is no list yet, then we we create a new one from the array
+    if (!*head){
+        *head = array2itag(array,size);
+        return 0;
+    }
+
+    rcu_read_lock();
+    list_for_each_entry_rcu(info, *head, node){
+        /* We don't restart at the beginning of the array*/
+        for(i=i; i<size; i++){
+            // Discard negative tags (those are only propagated on write access)
+            if (array [i] < 0) continue;
+
+            if (array[i] == info->value){
+                i++; 
+                break; //break the loop and iterate over the list
+            }
+
+            if (array[i] > info->value && ! list_is_last(&info->node,*head))
+                break;
+
+            new = kmem_cache_alloc(blare_info_cache,flags);
+            if (!new){
+                BLARE_DEBUG("[itag_insert] No mem :(\n");
+                rcu_read_unlock();
+                return -ENOMEM;
+            }
+            new->value = array[i];
+
+            if (array[i] < info->value)
+                list_add_tail_rcu(&new->node,&info->node);
+            else
+                list_add_rcu(&new->node,&info->node);
+        }
+    }
+    rcu_read_unlock();
+
+    return 0;
+}
+
+
+char *itag_to_s_rcu(struct list_head *head){
+    char *str = NULL, *msg;
+    struct information *infoptr;
+    int size=0, rc;
+
+    rc = itag_check_sanity(head);
+    if ( rc != 0){
+        blare_error(rc);
+        msg = "error";
+        goto alloc;
+    }
+
+    if (!head){
+        msg = "itag[null";
+        goto alloc;
+    }
+
+    else if (list_empty(head)){
+        msg = "itag[empty list";
+        goto alloc;
+    }
+
+    else{
+        msg = "itag[";
+        size = (strlen(msg)) * sizeof(char); 
+        rcu_read_lock();
+        list_for_each_entry_rcu(infoptr, head, node){
+            //infoptr = list_entry(position, struct information, node);
+            if (infoptr){
+                size += snprintf(NULL, 0, "%d ", infoptr->value); //just counts size
+            }
+        }
+        size += snprintf(NULL, 0, "]");
+        /*sizeof(char) because strlen and sprintf don't count the terminating \0 char */
+        str = (char*)kzalloc(size + sizeof(char), GFP_ATOMIC); 
+        if (!str){
+            rcu_read_unlock();
+            return "ERROR";
+        }
+        sprintf(str, "%s", msg);
+        list_for_each_entry_rcu(infoptr, head, node){ 
+            //infoptr = list_entry(position, struct information, node); 
+            if (infoptr)
+                sprintf(str + strlen(str), "%d ", infoptr->value); 
+        }
+
+        // strlen - 1 because we overwrite the last space
+        sprintf(str + strlen(str) - 1, "]"); 
+    }
+
+    rcu_read_unlock();
+    return str;
+
+alloc: // const char* to char* so we can kfree it later.
+    size = (strlen(msg) + 1) * sizeof(char);
+    str = (char*)kmalloc(size, GFP_KERNEL);
+    sprintf(str, "%s", msg);
+    return str;
+}
+
+
+int itag_count_rcu(struct list_head *head){
+    int i=0;
+    struct information *info;
+
+    if (!head) return -1;
+    rcu_read_lock();
+    list_for_each_entry_rcu(info, head, node)
+        i++;
+    rcu_read_unlock();
+    return i;
+}
+
+/* This is the RCU-safe version */
+void itag_free_rcu(struct list_head *head){
+    struct list_head *position, *tmp;
+    struct information *info;
+    int rc;
+
+    // In case there is no list
+    if (!head) return;
+
+    rc = itag_check_sanity(head);
+    if (rc !=0){
+        blare_error(rc);
+        return;
+    }
+
+    rcu_read_lock();
+    list_for_each_safe(position, tmp, head){
+        info = list_entry_rcu(position, struct information, node);
+        list_del_rcu(position);
+        if (info)
+            kmem_cache_free(blare_info_cache,info);
+        else
+            blare_warn("itag_free: itag has null entries :(");
+    }
+    rcu_read_unlock();
+    kfree(head); 
+}
+
+struct list_head *itag_copy_rcu(struct list_head *head){
+    struct list_head *newhead;
+    struct information *infoptr, *new = NULL;
+
+    if (!head){ 
+        BLARE_DEBUG("(itag_copy) Error: NULL head");
+        return NULL;
+        //return ERR_PTR(-ENODATA);
+    }
+
+    rcu_read_lock();
+    newhead = kmalloc(sizeof(struct list_head), GFP_ATOMIC);
+    if (!newhead) goto nomem; 
+
+    INIT_LIST_HEAD(newhead);
+
+    list_for_each_entry_rcu(infoptr, head, node){
+        new = kmem_cache_alloc(blare_info_cache, GFP_ATOMIC);
+        if (!new){
+            goto nomem;
+        }
+
+        INIT_LIST_HEAD(&new->node);
+        new->value = infoptr->value;
+        list_add_tail_rcu(&new->node,newhead);
+    }
+    rcu_read_unlock();
+
+    return newhead;
+
+nomem:
+    rcu_read_unlock();
+    BLARE_DEBUG("[itag_copy] ERROR: not enough memory\n");
+    itag_free_rcu(newhead);
+    //return ERR_PTR(-ENOMEM);
+    return NULL;
+}
+
+/* Merge list b into list a 
+ * Returns: the number of new items in a, 0 if unchanged
+ */
+int itag_merge_rcu(struct list_head *a, struct list_head *b){
+    struct list_head *itema, *itemb;
+    struct information *infoa, *infob, *new;
+    int count=0;
+
+    if (!a || !b) return -1;
+
+    rcu_read_lock();
+
+    // Pick b's first item (b itself isn't embedded in any structure)
+    infoa = list_first_entry_rcu(a, struct information, node);
+    infob = list_first_entry_rcu(b, struct information, node);
+    itema = &infoa->node;
+    itemb = &infob->node;
+
+    do {
+        infoa = list_entry_rcu(itema,struct information, node);
+        infob = list_entry_rcu(itemb,struct information, node);
+
+        if (!infoa || !infob){
+            rcu_read_unlock();
+            return -2;
+        }
+
+        if(infoa->value == infob->value){
+            itema = itema->next;
+            itemb = itemb->next;
+        }
+
+        else if (infoa->value < infob->value && !list_is_last(itema,a)){
+            itema = itema->next;
+        }
+
+        else{
+            new = kmem_cache_alloc(blare_info_cache, GFP_ATOMIC); 
+            if (!new){
+                goto nomem;
+            }
+            new->value = infob->value;
+
+            // Add smaller values at the head
+            if (infob->value < infoa->value) 
+                list_add_tail_rcu(&new->node,itema);
+            else
+                // Add higher values at the tail 
+                list_add_rcu(&new->node,itema);
+
+            itemb = itemb->next;
+            count ++; // How many new items
+        }
+
+    } while (!list_is_last(itemb->prev,b));
+
+    rcu_read_unlock();
+    return count;
+
+nomem:
+    rcu_read_unlock();
+    BLARE_DEBUG("-ENOMEM in itag_insert :(");
+    return -ENOMEM;
+}
+
+
+
+int itag_check_sanity_rcu(struct list_head *head){
+    int rc;
+    
+    rc = itag_basic_check_rcu(head); 
+    if (rc != 0)
+        return rc;
+
+    rc = itag_check_null_pointer_rcu(head);
+    if (rc != 0)
+        return rc;
+
+    rc = itag_check_order_rcu(head);
+    if (rc != 0)
+        return rc;
+
+    return 0;
+}
+
+
+
+/* With NTPL, threads are not standalone processes anymore, but they all share
+ * the same address space. We can't safely consider threads as isolated unless
+ * the code has been audited first, but in the case you want to watch threads
+ * separately, this is the place to do it. */
+struct blare_thread *blare_current_threadinfo_rcu(struct list_head *tlist){
+    struct blare_thread *t;
+
+    // In case there is no list ... TODO: BUG_ON()
+    if (!tlist) return NULL;
+
+    rcu_read_lock();
+    list_for_each_entry_rcu(t, tlist, node){ 
+        if (t->pid == current->pid){
+            rcu_read_unlock();
+            return t;
+        }
+    }
+    rcu_read_unlock();
+    return NULL;
+
+    /* TODO: To be continued */
+}
+
+ /***********************************************************************
+********** Static functions - don't call them directly ******************
+***********************************************************************/
+
+
+/* Perform preliminary checks before calling other check functions */
+static int itag_basic_check_rcu(struct list_head *head){
+    struct list_head *h, *prev, *next;
+    
+    rcu_read_lock();
+
+    h = rcu_dereference(head);
+    next = rcu_dereference(head->next);
+    prev = rcu_dereference(head->prev);
+
+    if (!head){
+        rcu_read_unlock();
+        return -1;
+    }
+
+    if(IS_ERR(head)){
+        rcu_read_unlock();
+        return(PTR_ERR(head));
+    }
+
+    if (!next){
+        rcu_read_unlock();
+        return -6;
+    }
+
+    if (!prev){
+        rcu_read_unlock();
+        return -7;
+    }
+    rcu_read_unlock();
+    return 0;
+}
+
+
+/* For debug purpose
+ * An itag should always be sorted in ascending order. If it is not the case, it
+ * is broken and that seriously sucks*/
+static int itag_check_order_rcu(struct list_head *head){
+    struct information *info;
+    int x=0;
+    rcu_read_lock();
+    list_for_each_entry_rcu(info, head, node){
+        //info = list_entry(pos,struct information,node);
+        if (x==0)
+            continue;
+        if (info->value < x){
+            rcu_read_unlock();
+            return -1;
+        }
+        x = info->value;
+    }
+    rcu_read_unlock();
+    return 0;
+}
+
+
+static int itag_check_null_pointer_rcu(struct list_head *head){
+    struct list_head *pos;
+    struct information *info;
+    int err;
+
+    rcu_read_lock();
+
+    list_for_each_entry_rcu(info, head, node){
+        err = -2;
+        if (!info)
+            goto err;
+        err = -3;
+        if (!info->value)
+            goto err;
+
+        pos = &info->node;
+
+        err = -4;
+        if (!pos->next)
+            goto err;
+
+        err = -5;
+        if (!pos->prev)
+            goto err;
+    }
+
+    rcu_read_unlock();
+    return 0;
+
+err:
+    rcu_read_unlock();
+    return err;
+}
+
+
diff --git a/security/blare/legality.c b/security/blare/legality.c
new file mode 100644
index 0000000..5e70bc3
--- /dev/null
+++ b/security/blare/legality.c
@@ -0,0 +1,92 @@
+ /*  Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ */
+
+
+#include "blare.h"
+#include "include/itag.h"
+#include "include/ptags.h"
+
+
+/* Check whether the information tag of a process is included in its policy tag
+ * Return codes :
+ * -EACCESS (permission denied) in case of an invalid information flow
+ *  0 if there is no information tag or no policy tag
+ *  0 if the current process is trusted
+ *  1 if the information flow is legal
+ */
+int check_policy(struct list_head* info_list, struct list_head* policy_list){
+    struct list_head *info_item, *tree_item;
+    struct information *info;
+    struct policy_tree *policy;
+    struct tree_item *tag;
+    int legal, rc;
+
+    // Nothing to check
+    if (!info_list || !policy_list) return 0;
+
+    if(list_empty(info_list)){
+        if(DEBUG) printk("[check_policy] Process %s has an empty information tag...\n",current->comm);
+        return 0;
+    }
+
+    /* Trusted processes have an empty itag (magic number 0) */
+    rc = blare_check_trusted_process(info_list);
+    if (rc == 0)
+        return 0;
+
+    // Iterate over the policy list
+    list_for_each(tree_item,policy_list){
+        policy = list_entry(tree_item, struct policy_tree, list);
+        legal=1;
+
+        // Iterate over the information tags
+        list_for_each(info_item,info_list){
+            info = list_entry(info_item, struct information, node);
+            tag = tree_search(policy->root,info->value);
+
+            if (!tag){
+                legal=0; break;
+                /*
+                if(DEBUG_POLICY)
+                    printk("[check_policy] %d is not in the tree, skipping\n",info->value);
+                    */
+            }
+        }
+
+        if(legal == 1){
+            if(DEBUG_POLICY)
+                printk("[blare_container_check] found a matching policy set (LEGAL)\n");
+            return 1;
+        }
+    }
+
+    return -EACCES;
+}
+
+
+/* Check an itag against the network policy */
+int check_netpolicy(struct list_head* info_list){
+    int legal;
+    char *itag_s;
+
+    if (!info_list)
+        return 1;
+    legal = check_policy(info_list, blare_network_policy);
+    if (legal < 0){
+        itag_s = itag_to_s(info_list);
+        if (likely(itag_s)){
+            printk(KERN_WARNING "blare_NETPOLICY_violation (pid %d - %s): %s\n", current->pid, current->comm, itag_s);
+            kfree(itag_s);
+        }
+    }
+
+    return legal;
+}
+
diff --git a/security/blare/lsm_hooks.c b/security/blare/lsm_hooks.c
new file mode 100644
index 0000000..e244720
--- /dev/null
+++ b/security/blare/lsm_hooks.c
@@ -0,0 +1,1282 @@
+/*  This file contains the LSM hooks related to the Blare IDS.
+ *  All the hook always return 0 (permission granted), as we do
+ *  not enforce the policy.
+ *
+ *  Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ *
+ */
+
+#include "blare.h"
+#include "include/shm.h"
+//#include "include/test.h"
+#include "include/file_ops.h"
+#include "include/xattr.h"
+#include "include/itag.h"
+#include "include/itag_rcu.h"
+#include "include/ptags.h"
+#include "include/legality.h"
+#include "include/netlabel.h"
+#include "include/trace.h"
+#include "include/mmap.h"
+
+#include <linux/security.h>
+#include <linux/xattr.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/pipe_fs_i.h>
+#include <linux/net.h>
+#include <net/sock.h>
+#include <linux/tcp.h>
+#include <linux/in.h>
+#include <asm/uaccess.h>
+#include <linux/file.h>
+#include <linux/socket.h>
+#include <linux/mman.h>
+#include <net/cipso_ipv4.h>
+#include <net/netlabel.h>
+#include <linux/stat.h>
+
+struct kmem_cache *blare_info_cache;
+struct kmem_cache *blare_policy_array_cache;
+struct kmem_cache *blare_tree_item_cache;
+struct kmem_cache *blare_policy_tree_cache;
+struct kmem_cache *blare_task_struct_cache;
+struct kmem_cache *blare_file_struct_cache;
+struct kmem_cache *blare_shmptr_cache;
+struct kmem_cache *blare_tags_cache;
+
+struct list_head *blare_network_policy;
+
+// Keep tracks of memory initialization (for debug)
+int inode_tags = 0;
+
+//struct proc_dir_entry *blare_proc_dir;
+//struct proc_dir_entry *blare_net_policy;
+
+//struct kmem_cache *blare_cache_slab;
+//struct rb_root blare_cache_root;
+
+int blare_initialized __initdata;
+int blare_enabled = 1; //__initdata; // see blare_securityfs
+
+//static DEFINE_SPINLOCK(sk_lock);
+rwlock_t sk_lock = __RW_LOCK_UNLOCKED(sk_lock);
+unsigned long irqflags;
+
+static int __init blare_init(void);
+security_initcall(blare_init);
+
+/*------------------------------- 
+ * Blare initialization
+ * -----------------------------*/
+static int __init blare_init(void)
+{
+    int rc;
+    rc = register_security(&blare_ops);
+
+    if (rc){
+        printk (KERN_INFO "***** Failed to register Blare :( ***** \n");
+        blare_initialized=0;
+        //blare_enabled = 0;
+        return rc;
+    }
+
+    else
+        printk (KERN_INFO "***** Blare LSM loaded :) *****\n");
+
+    blare_initialized=1;
+    //blare_enabled = 1;
+
+    // Initialize slab caches 
+    blare_info_cache = kmem_cache_create("Blare_info", sizeof(struct
+                information), 0, SLAB_HWCACHE_ALIGN, NULL);
+
+    blare_policy_array_cache = kmem_cache_create("Blare_policy_array",
+            sizeof(struct policy_array), 0, SLAB_HWCACHE_ALIGN, NULL);
+
+    blare_tree_item_cache = kmem_cache_create("Blare_tree_item", 
+            sizeof(struct tree_item), 0, SLAB_HWCACHE_ALIGN, NULL);
+
+    blare_policy_tree_cache = kmem_cache_create("Blare_policy_tree",
+            sizeof(struct policy_tree), 0, SLAB_HWCACHE_ALIGN, NULL);
+
+    blare_task_struct_cache = kmem_cache_create("Blare_task_struct",
+            sizeof(struct blare_task_struct), 0, SLAB_HWCACHE_ALIGN, NULL);
+
+    blare_file_struct_cache = kmem_cache_create("Blare_file_struct",
+            sizeof(struct blare_file_struct), 0, SLAB_HWCACHE_ALIGN, NULL);
+
+    blare_shmptr_cache = kmem_cache_create("Blare_shmptr", 
+            sizeof(struct blare_shmptr), 0, SLAB_HWCACHE_ALIGN, NULL);
+
+    blare_tags_cache = kmem_cache_create("Blare_tags", 
+            sizeof(struct blare_tags), 0, SLAB_HWCACHE_ALIGN, NULL);
+
+    /* Initlialize the network policy list 
+     * It is a global list of policy tags shared by all the sockets. See blare.h
+     * for more information on policy tags
+     * */
+    blare_network_policy = kmalloc(sizeof(struct list_head), GFP_KERNEL);
+    INIT_LIST_HEAD(blare_network_policy);
+
+    blare_mmap_tree_root = kmalloc(sizeof(struct rb_root), GFP_KERNEL);
+    *blare_mmap_tree_root = RB_ROOT;
+
+    /* Proc stuff
+    blare_proc_dir = proc_mkdir ("blare", NULL);
+    blare_uid_dir = proc_mkdir ("uid", blare_proc_dir);
+    blare_proc_socket = create_proc_entry("net_policy",0666,blare_proc_dir);
+    */
+#ifndef CONFIG_NETLABEL
+    printk(KERN_INFO "blare: please enable CONFIG_NETLABEL\n");
+#endif
+
+    return 0;
+}
+
+
+/* ---------------------------- 
+ * Blare LSM hooks
+ * ---------------------------*/
+
+static int blare_inode_alloc_security(struct inode *inode){
+    struct blare_tags *tags;
+    if (unlikely(inode->i_security)){
+        BLARE_DEBUG("[inode_alloc_security] Pipe inode already has security"
+                "attached, overlaping with file_permission ? exiting\n");
+        return 0;
+    }
+
+    //BLARE_DEBUG("Allocating tags, inode no %lu",inode->i_ino);
+    tags = kmem_cache_zalloc(blare_tags_cache,GFP_KERNEL);
+    tags->info = NULL;
+
+    if (!tags) return -ENOMEM;
+    inode->i_security = tags;
+
+    inode_tags ++;
+    return 0;
+}
+
+/* Inode permission: triggered by any operation on
+ * inodes such as fopen(), pipe_read() and the like
+ */
+static int blare_inode_permission(struct inode *inode, int mask, unsigned flags){
+    struct blare_tags *tags;
+    int rc;
+    if (inode->i_pipe){
+        tags = inode->i_security; 
+
+        if (tags && (mask & MAY_READ)){
+            rc = blare_task_read(tags);
+        }
+        else if (mask & MAY_WRITE){
+            if (!inode->i_security){
+                //blare_inode_alloc_security(inode);
+                //tags = inode->i_security;
+                BLARE_DEBUG("No security attached to inode...");
+                return 0;
+            }
+
+            rc = blare_task_write(tags);
+            if (rc < 0){
+                BLARE_DEBUG("Error %d writing to pipe",rc);
+            }
+        }
+    }
+    blare_trace(TRACE_PIPE, mask, flags, NULL, inode->i_ino);
+    return 0;
+}
+
+static void blare_inode_free_security(struct inode *inode){
+    struct blare_tags *tags;
+    //struct pipe_inode_info *info;
+
+    /*
+    if (inode->i_pipe){
+        info = inode->i_pipe;
+        while (info->readers >0 || info->writers>0)
+            schedule();
+    }
+    */
+    tags = inode->i_security;
+    tags_free(&tags);
+    inode->i_security = NULL;
+    inode_tags--;
+
+    //BLARE_DEBUG("inode_free_security for inode no %lu - %d overall allocated inode tags",inode->i_ino,inode_tags);
+}
+
+/* Read/write operations on files.
+ * Note : opening a file won't trigger this hook. 
+ * See inode_permission in this case.
+ */
+static int blare_file_permission (struct file *file, int mask){
+    struct blare_file_struct *fstruct;
+    struct dentry *dp;
+    struct inode *inode;
+    int rc;
+    struct kstat stat;
+
+    if (!file->f_security){
+        BLARE_DEBUG("[blare_file_permission] Error: no structure attached to current"
+                "file\n");
+        return 0;
+    }
+
+    fstruct = file->f_security;
+
+    /* dcache locking mechanism, see documentation/filesystems/vfs.txt */
+    dp = dget(file->f_dentry);
+
+    /* We don't want sockets here */
+    rc = vfs_getattr(file->f_vfsmnt, dp, &stat);
+
+    if (S_ISSOCK(stat.mode) && DEBUG){
+        //blare_warn("file_permission: IS_SOCK - Todo: handle this properly by calling socket_sendmsg|recvmsg\n");
+        goto exit;
+    }
+
+    /* There is no link between the inode/dentry/file on uninitialized FSs */
+    if (!dp){
+        if(DEBUG) printk("[blare_file_permission] Warning: filesystem has NOT"
+                "been initialized yet\n");
+        return 0;
+    }
+
+    inode = dp->d_inode;
+    if (!inode)
+        goto exit;
+
+    if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
+        mask |= MAY_APPEND;
+
+    /* This is for the unnamed pipes. (i.e.: cat | grep) */
+    if (inode->i_pipe){
+        blare_inode_permission(inode,mask,0);
+        goto exit;
+    }
+
+    if((mask & MAY_READ))// || (mask & MAY_APPEND))
+        rc = blare_may_read(dp,fstruct);
+    //rc = blare_shm_update_all(tstruct->shm,tstruct->info_list);
+
+    /* Pure write with no append */
+    if (mask & MAY_WRITE && ! (mask & MAY_APPEND)){
+        /*
+        if (mask & MAY_APPEND)
+        else
+            */
+        rc = blare_may_write(dp, fstruct);
+    }
+
+    else if(mask & MAY_APPEND)
+        rc = blare_may_append(dp, fstruct);
+
+    blare_trace(TRACE_FILE, mask, 0, file, 0);
+
+exit:
+    dput(dp);
+    return 0;
+}
+
+/*blare_file_alloc_security:
+ *	Allocate and attach a security structure to the file->f_security field.*/
+static int blare_file_alloc_security(struct file *file){
+    struct blare_file_struct *fstruct;
+    
+    fstruct = kmem_cache_zalloc(blare_file_struct_cache, GFP_KERNEL);
+    if (!fstruct)
+        return -ENOMEM;
+    fstruct->info_array = NULL;
+
+    file->f_security = fstruct;
+    return 0;
+}
+
+/*
+ * blare_file_free_security:
+ * free the security structure attached to the file->f_security field
+ */
+static void blare_file_free_security(struct file *file){
+    struct blare_file_struct *fstruct;
+
+    if (file->f_security){
+        fstruct = file->f_security;
+        blare_free_fstruct(fstruct);
+        kmem_cache_free(blare_file_struct_cache,fstruct);
+        file->f_security = NULL;
+    }
+}
+
+/* Todo (or already caught by file_permission) */
+static int blare_file_mmap(struct file *file, unsigned long reqprot,
+        unsigned long prot, unsigned long flags,
+        unsigned long addr, unsigned long addr_only){
+
+    struct dentry *dp;
+    struct blare_file_struct *fstruct;
+    struct blare_mmap_struct *mstruct;
+
+#ifdef CONFIG_MMAP_ALLOW_UNINITIALIZED
+    if (flags & MAP_UNINITIALIZED)
+        blare_warning("Your kernel is configured with"
+                "CONFIG_MMAP_ALLOW_UNINITIALIZED, pages mapped with the"
+                "MAP_UNINITIALIZED won't be cleared beforehands");
+#endif
+
+    /* Pages cannot be accessed */
+    if(prot == PROT_NONE)
+        return 0;
+
+    /* No file descriptor */
+    if (flags & MAP_ANONYMOUS){
+        blare_trace(TRACE_MMAP, prot, flags, NULL, addr);
+    }
+
+    /* From here, we should always have a file descriptor */
+    else{
+        if (!file || !file->f_dentry){
+            blare_debug("Hmm, non anonymous mmap with no file descriptor... flags are %lu and prot is %lu - address is %lu\n", flags, prot, addr);
+            return 0;
+        }
+
+        if(!file->f_security){
+            blare_debug("Hmm, mmaped file has no f_security field\n");
+            return 0;
+        }
+
+        fstruct = file->f_security;
+
+        dp = dget(file->f_dentry);
+
+        if(prot & PROT_READ)
+            blare_may_read(dp,fstruct);
+
+        /* When MAP_PRIVATE, updates to the mapping are not carried through the
+         * underlying file */
+        if ((prot & PROT_WRITE) && !(flags & MAP_PRIVATE))
+            blare_may_write(dp,fstruct);
+
+        /* Code execution :
+         * - append exec(itag) to the current->security->info_list
+         * - update policy_tag: restrict it 
+         *   TODO: should we check PROT_EXEC before PROT_WRITE instead 
+         *   (i.e. also transfer execution tags) ? */
+        if(prot & PROT_EXEC)
+            blare_may_exec(dp, fstruct);
+
+        blare_trace(TRACE_MMAP, prot, flags, file, addr);
+        dput(dp);
+    }
+
+    /* Shared data between processes
+    if (flags & MAP_SHARED){
+        mstruct = blare_mmap(addr);
+    }
+    */
+
+    return 0;
+
+}
+
+/* After execve, once the new creds have been set.
+ */
+static void blare_bprm_committed_creds(struct linux_binprm *bprm){
+    // Before there was bprm_free_security, but it isn't used anymore
+    //struct blare_file_struct *fstruct;
+    struct blare_task_struct *tstruct;
+    const struct cred *ro_cred;
+    int rc;
+
+    ro_cred = get_current_cred();
+    tstruct = ro_cred->security;
+    //tstruct = current_security();
+    if (!tstruct || ! tstruct->info_list){
+        put_cred(ro_cred);
+        return;
+    }
+
+    itag_print_msg(tstruct->info_list, "exec(%s)\n", bprm->filename);
+
+    rc = blare_check_trusted_process(tstruct->info_list);
+    if (rc == 0) 
+        printk(KERN_INFO "blare: %s (pid %d) : trusted process\n",current->comm, current->pid);
+    put_cred(ro_cred);
+}
+
+/* 
+ *  Called during execve()
+ *  - Read tags from the xattr of the file associted with binprm
+ *  - Save security information in the bprm->cred->security field.
+ *  - The process will get those credentials (bprm->cred) after execve().
+ */
+static int blare_bprm_set_creds(struct linux_binprm *bprm){
+
+    int rc;
+    struct blare_file_struct *fstruct;
+    struct blare_task_struct *tstruct;
+    //struct list_head *xpolicy_list;
+    struct dentry *dp;
+
+    /* Should we disable this ? */
+    rc = cap_bprm_set_creds(bprm);
+    if (rc){
+        printk(KERN_WARNING "blare: %s (pid %d) cap_bprm_set_creds returned error %d, this may be an issue...\n", current->comm, current->pid, rc);
+        return rc;
+    }
+
+    // It might be called multiple times
+    if (bprm->cred_prepared || (blare_enabled == 0)) return 0;
+
+    bprm->cred->security = NULL;
+
+    /* There is a locking mechanism with dcache
+     * So we can't access file->f_dentry directly
+     * see Documentation/filesystem/dentry-locking.txt */
+    dp = dget(bprm->file->f_dentry);
+
+    /* It is possible that the filesystem hasn't been initialized yet
+     * In this case there is no link between the inode/dentry/file */
+    if (!dp){
+        printk("[bprm_set_creds] Filesystem hasn't been initialized\
+                yet\n");
+        return 0;
+    }
+
+    /* Allocate a temporary security structure for the binary file */
+    fstruct = kmem_cache_zalloc(blare_file_struct_cache, GFP_KERNEL);
+    if (!fstruct) return -ENOMEM;
+
+    // Allocate a security structure for the process's tags
+    tstruct = kmem_cache_zalloc(blare_task_struct_cache, GFP_KERNEL);
+
+    if (!tstruct){
+        kmem_cache_free(blare_file_struct_cache, fstruct);
+        dput(dp);
+        BLARE_DEBUG("no memory, could not allocate task struct\n");
+        return -ENOMEM;
+    }
+
+    /* TODO: shm stuff
+       tstruct->shm = kmalloc(sizeof(struct list_head),GFP_KERNEL);
+       if (!tstruct->shm){
+       dput(dp);
+       kmem_cache_free(blare_file_struct_cache, fstruct);
+       kmem_cache_free(blare_task_struct_cache, tstruct);
+       return -ENOMEM;
+       }
+
+       INIT_LIST_HEAD(tstruct->shm);
+       */
+
+    /* Read the information tag */
+    rc = blare_alloc_file_info(dp,fstruct);
+    if (rc > 0){
+        tstruct->info_list = itag_exec(fstruct->info_array,fstruct->info_size);
+        blare_free_file_info(fstruct);
+    }
+        
+    /* Read the execute policy tag and use it to determine the policy tag of the
+       current process */
+    rc = blare_alloc_file_xpolicy(dp,fstruct);
+    if (rc > 0){
+        tstruct->policy_list =
+            arrays2policytag(fstruct->xpolicy_arrays,fstruct->xpolicy_count);
+        blare_free_file_xpolicy(fstruct);
+
+        if (DEBUG_XPOLICY){
+            printk("[bprm_set_creds] GOT xptag for %s : ",bprm->filename);
+            policytag_print(tstruct->policy_list);
+        }
+    }
+
+    /* We can mark some binary files to be traceable. In this case,
+     * Blare will report all the operations those binaries do */
+    blare_init_trace(dp, tstruct);
+    
+    bprm->cred->security = tstruct;
+
+    blare_free_fstruct(fstruct);
+    kmem_cache_free(blare_file_struct_cache,fstruct);
+
+    dput(dp);
+
+    return 0; 
+}
+
+/* This is an alternative way to copy the process credentials (see
+ * blare_security_prepare_creds() for the original code.
+ * The idea behind this new function is that linked lists need only to be
+ * protected for concurrent writers, but not for concurrent readers.
+ * A single writer and multiple readers is fine.
+ * The linked list is safe by design when at most one writer updates at a
+ * given time.
+ * To be used along with blare_cred_free_alternate()
+ */
+static int blare_security_prepare_creds_alternate (struct cred *new, const struct cred
+        *old, gfp_t gfp) {
+        struct blare_task_struct *tnew;
+    const struct blare_task_struct *told;
+
+    if (old && old->security){
+        told = old->security;
+        tnew = kmemdup(told, sizeof(struct blare_task_struct), gfp);
+        new->security = tnew;
+    }
+    return 0;
+}
+
+
+/* Replaces security_task_alloc()  - from new security hooks included in commit
+ d84f4f992cbd76e8f39c488cf0c5d123843923b1)
+ * Note : this is used by  prepare_creds() to copy the security attributes
+ * of the process. The kernel does actually copy the credentials, but not
+ * the security fields. This part of the code is left to us.
+ *
+ * There are two cases  
+ * - either the current task already has a security structure, and 
+ * what we want is to copy it as is ;
+ * - or there is nothing, and then we create a new empty structure
+ *   with a NULL info_list
+ */ 
+static int blare_security_prepare_creds (struct cred *new, const struct cred
+        *old, gfp_t gfp) {
+        struct blare_task_struct *tnew;
+    const struct blare_task_struct *told;
+
+    /*=== The following copies all the structures*/
+
+    // At this stage, we initialize the new security structure to NULL
+    new->security = NULL;
+
+    /* If there is no security field attached to the old credentials, 
+     * we create a new empty one */
+
+    tnew = kmem_cache_zalloc(blare_task_struct_cache, GFP_KERNEL);
+    if (!tnew)
+        return -ENOMEM;
+
+    /* If information exists in the old credentials, then we copy it
+     * to the new ones */
+    told = old->security;
+
+    if (told){
+        if (told->info_list){
+            tnew->info_list = itag_copy(told->info_list, GFP_KERNEL);
+            if (IS_ERR(tnew->info_list))
+                tnew->info_list = NULL;
+        }
+
+        if (told->policy_list)
+            tnew->policy_list = ptag_copy(told->policy_list);
+
+        if (told->xpolicy_list)
+            tnew->xpolicy_list = ptag_copy(told->xpolicy_list);
+
+        tnew->trace = told->trace;
+
+        /* TODO: shm and mmap
+           if (told->shm)
+           tnew->shm = shm_list_copy(told->shm);
+
+           if (told->shm_ro)
+           tnew->shm_ro = shm_list_copy(told->shm_ro);
+           */
+    }
+
+    new->security = tnew;
+    return 0;
+}
+
+/* Fork() and stuff */
+static int blare_task_create(unsigned long clone_flags){
+
+    /* Parent & child share the same address space (i.e. copy_mm() does not
+     * allocate a new address space).
+     */
+    if ((clone_flags & CLONE_VM) && !(clone_flags & CLONE_THREAD))
+        blare_debug("CLONE_VM: we do not catch this yet, but parent & child will"
+                "share the same address space\n");
+         
+     /* Otherwise, only the shared anonymous memory mappings are shared 
+     */
+
+    blare_trace(TRACE_CLONE, 0, clone_flags, NULL, 0);
+
+    return 0;
+}
+
+/* This is the alternate version of blare_cred_free, see
+ * blare_prepare_creds_alternate()*/
+static void blare_cred_free_alternate(struct cred *cred){
+    struct blare_task_struct *tstruct; 
+    struct list_head *list;
+
+    if (cred->security){
+        tstruct = cred->security;
+        kmem_cache_free(blare_task_struct_cache, tstruct);
+        cred->security = NULL;
+    }
+    return;
+}
+
+
+/* @cred_free:
+ *	@cred points to the credentials.
+ *	Deallocate and clear the cred->security field in a set of credentials.
+ */
+static void blare_cred_free(struct cred *cred){
+    struct blare_task_struct *tstruct; 
+    struct list_head *list;
+
+    /* Free everything including the itag, ptag and xptag*/
+
+    // In case there is nothing to free
+    if (!cred->security)
+        return;
+
+    tstruct = cred->security;
+    list = tstruct->info_list;
+
+    itag_free(tstruct->info_list);
+
+    policy_tag_free(tstruct->policy_list);
+    policy_tag_free(tstruct->xpolicy_list);
+    //shm_list_free(tstruct->shm);
+
+    cred->security = NULL;
+    kmem_cache_free(blare_task_struct_cache, tstruct);
+}
+
+/* Security.h says:  @cred_alloc_blank
+ *	Only allocate sufficient memory and attach to @cred such that
+ *	cred_transfer() will not get ENOMEM.
+ */
+static int blare_cred_alloc_blank(struct cred *cred, gfp_t gfp){
+    struct blare_task_struct *tnew;
+
+    tnew = kmem_cache_zalloc(blare_task_struct_cache, gfp);
+    tnew->info_list = NULL;
+    cred->security = tnew;
+    if (DEBUG) printk("Cred allocated a blank structure (kzalloc)\n");
+
+    return 0;
+}
+
+/* security.h says : @cred_transfer
+ *	Transfer data from original creds to new creds
+ */
+static void blare_cred_transfer(struct cred *new, const struct cred *old){
+    new->security = old->security;
+    if (DEBUG) printk("[cred_transfer]\n");
+}
+
+
+/* /proc/pid/attr/current gives the information tag of processes */
+static int blare_getprocattr(struct task_struct *task, char *name, 
+        char **value)
+{
+    int error = -ENOENT;
+    char *str;
+    int *array;
+    int rc = 0;
+    int i;
+    int size = 0;
+    struct blare_task_struct *tstruct; 
+    const struct cred *cred = get_task_cred(task);
+
+    tstruct = cred->security;
+    //printk("getprocattr begin : %p\n", tstruct);
+    if (strcmp(name, "current") == 0)
+    {
+        rc = itag2array(tstruct->info_list, &array);
+
+        if (rc < 0)
+            return rc;
+
+        size += snprintf(NULL, 0, "itags : ");
+        for (i = 0 ; i < rc ; i++)
+            size += snprintf(NULL, 0, "%d ", array[i]);
+
+        //for '\0' and '\n'	
+        str = kmalloc(size + (2 * sizeof (char)), GFP_KERNEL); 
+        sprintf(str, "itags : ");
+
+        for (i = 0 ; i < rc ; i++)
+            sprintf(str + strlen(str) * sizeof(char),"%d ", array[i]);
+
+        sprintf(str + strlen(str) * sizeof(char), "\n");
+
+        *value = str;
+        error = size + 1;
+    }
+
+    else
+        error = -EINVAL;
+
+    put_cred(cred);
+    kfree(array);
+
+    return error;
+}
+
+
+
+/* @sk_alloc_security:
+ *	Allocate and attach a security structure to the sk->sk_security field,
+ *	which is used to copy security attributes between local stream sockets.
+ */
+static int blare_sk_alloc_security (struct sock *sk, 
+        int family, gfp_t priority){
+    struct blare_tags *tags;
+
+    tags = kmem_cache_zalloc(blare_tags_cache,GFP_KERNEL);
+    if (!tags) return -ENOMEM;
+    tags->info = NULL;
+    spin_lock_init(&tags->info_lock);
+    //kref_init(&tags->refcount);
+    sk->sk_security = tags;
+
+    return 0;
+}
+
+
+/* @sk_free_security:
+ *	Deallocate security structure.
+ */
+static void blare_sk_free_security(struct sock *sk){
+    struct blare_tags *tags;
+
+    tags = sk->sk_security;
+    if (!tags)
+        return;
+
+    /* TODO: we only check itags here, we should
+     * call tags_free */
+    if (tags->info)
+        itag_free(tags->info);
+
+    kmem_cache_free(blare_tags_cache,tags);
+    // tags_free(&tags);
+    sk->sk_security = NULL;
+}
+
+
+/* This hook is used to free sk->sk_security before 
+ * the sock gets released 
+ * UNUSED, to be removed
+ * */
+void blare_socket_sock_release(struct sock *sk){
+}
+
+/* Read netlabel options off network packets (sk_buff)
+ * Extract information tag from the bitmap (catmap)
+ * Append tags to the current process's information tag
+ * Note: this code cannot block as the callers have spinlocks
+ */
+int blare_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb){
+    int rc = 0;
+    struct netlbl_lsm_secattr secattr;
+    struct netlbl_lsm_secattr_catmap *catmap;
+    struct list_head *itag = NULL;
+    struct blare_tags *tags;
+    //struct sock_common common;
+    //__be32 daddr;
+
+    if (unlikely((!sk || sk->sk_family != PF_INET || (blare_enabled == 0))))
+        return 0;
+
+    netlbl_secattr_init(&secattr);
+    rc = netlbl_skbuff_getattr(skb, sk->sk_family, &secattr);
+
+    if (rc != 0){
+        blare_error(rc);
+        return 0;
+    }
+
+    tags = sk->sk_security;
+    if (unlikely(!tags)){
+        blare_error(-ENODATA);
+        return 0;
+    }
+
+    catmap = secattr.attr.mls.cat;
+    if (!catmap)
+        return 0;
+
+    spin_lock(&tags->info_lock);
+
+    if (!tags->info)
+        tags->info = blare_catmap2itag(catmap);
+    else
+        rc = blare_netlabel_insert(tags, catmap);
+
+    spin_unlock(&tags->info_lock);
+
+    if (rc < 0)
+        blare_error(rc);
+
+    //itag_print_msg(tags->info, "rcv_skb:");
+
+    return 0;
+}
+
+static int blare_socket_recvmsg(struct socket *sock, struct msghdr *msg,
+			    int size, int flags){
+    struct sock *sk;
+    struct blare_task_struct *tstruct;
+    int rc = 0;
+    struct cred *cred;
+    struct sock_common common;
+    __be32 daddr;
+    struct blare_tags *tags;
+    int err;
+
+    sk = sock->sk;
+    if (unlikely(!sk))
+        return 0;
+
+    if (!sk->sk_security || blare_enabled == 0)
+        return 0;
+
+    if(blare_current_is_trusted() == 0)
+        return 0;
+
+    tags = sk->sk_security;
+    //kref_get(&tags->refcount);
+
+    if (!tags->info && !tags->xpolicy)
+        goto release;
+
+    /* Get IP addresses
+    common = sk->__sk_common;
+    daddr = common.skc_daddr;
+    */
+
+    cred = prepare_creds();
+    if (unlikely(!cred))
+        goto release;
+        
+    tstruct = cred->security;
+    if (unlikely(!tstruct)){
+        abort_creds(cred);
+        goto release;
+    }
+
+    if (tstruct->info_list){
+        rc = itag_check_sanity(tags->info);
+        if (rc < 0){
+            blare_error(rc);
+            abort_creds(cred);
+            goto release;
+        }
+        rc = itag_merge(tstruct->info_list, tags->info, GFP_ATOMIC);
+        //blare_debug("socket_recvmsg: merged %d tags from socket to process\n", rc);
+    }
+    else{
+        tstruct->info_list = itag_copy(tags->info, GFP_ATOMIC);
+    }
+
+    //itag_print_msg(tags->info, "(socket)blare_net_in");/* (%d.%d.%d.%d)", daddr
+    //& 0xff, (daddr << 8) & 0xff, (daddr << 16) & 0xff, (daddr << 24) & 0xff);*/
+
+    //kref_put (&tags->refcount, blare_sk_free_security);
+
+    commit_creds(cred);
+
+    if (sk->sk_family == AF_INET)
+        blare_trace(TRACE_INET, MAY_READ, flags, NULL, size);
+    else 
+        blare_trace(TRACE_UNIX, MAY_READ, flags, NULL, size);
+
+    return 0;
+
+release:
+    //kref_put (&tags->refcount, blare_sk_free_security);
+    return 0;
+}
+
+/* Update the socket's netlabel before allowing outgoing traffic */
+static int blare_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size){
+    struct netlbl_lsm_secattr secattr;
+    int rc;
+    struct sock *sk;
+    struct blare_task_struct *tstruct = NULL;
+    const struct cred *cred;
+
+    sk = sock->sk;
+
+    /* ipv4 only*/
+    if (sk->sk_family != PF_INET || blare_enabled == 0)
+        return 0;
+
+    if(blare_current_is_trusted() == 0)
+        return 0;
+    
+    cred = get_current_cred();
+    if (unlikely(!cred)){
+        //put_cred(cred);
+        return 0;
+    }
+
+    tstruct = cred->security;
+
+    /* No tags = no netlabel*/
+    if (unlikely(!tstruct)){
+        put_cred(cred);
+        blare_error(-ENODATA);
+        return 0;
+    }
+
+    if (!tstruct->info_list || list_empty(tstruct->info_list)){
+        put_cred(cred);
+        return 0;
+    }
+
+    //itag_debug(tstruct->info_list,"socket_out");
+
+    netlbl_secattr_init(&secattr);
+    rc = blare_itag2secattr(tstruct->info_list, &secattr);
+    put_cred(cred);
+
+    if (rc !=0){
+        blare_error(rc);
+        return 0;
+    }
+    else{
+        /* We need to lock the socket before setting netlabel secattr */
+        local_bh_disable();
+        bh_lock_sock_nested(sk);
+
+        rc = netlbl_sock_setattr(sk, sk->sk_family, &secattr);
+
+        bh_unlock_sock(sk);
+        local_bh_enable();
+
+        netlbl_secattr_destroy(&secattr);
+    }
+
+    if (rc !=0)
+        blare_warn("error %d setting socket attributes", rc);
+
+    blare_trace(TRACE_INET, MAY_WRITE, 0, NULL, size);
+    return 0;
+}
+
+
+/* This is the right place to set a first netlabel on the socket This is also
+ * the only place where we do not need a lock nor disabling the bottom halves.
+ */
+static int blare_socket_post_create(struct socket *sock, int family,
+				int type, int protocol, int kern){
+    struct sock *sk;
+    sk = sock->sk;
+    sk->sk_security = NULL;
+   return 0;
+}
+
+/* Unix sockets hook
+ * Process sends AF_UNIX packets*/
+static int blare_unix_may_send (struct socket *sock, struct socket *other){
+    struct sock *sk;
+    struct blare_tags *tags;
+
+    sk = other->sk;
+
+    /* tags are allocated in sk_alloc_security */
+    tags = sk->sk_security;
+    if (!tags) return 0;
+
+    //BLARE_DEBUG("[unix_may_send] calls task_write");
+    blare_task_write(tags);
+    
+    blare_trace(TRACE_UNIX, MAY_WRITE, 0, NULL, 0);
+    return 0;
+}
+
+
+/* We do track message queues too.
+ */
+static int blare_msg_queue_msgsnd (struct msg_queue *msq, struct msg_msg *msg, int msqflg){
+    struct blare_tags *tags;
+
+    tags = msg->security;
+    blare_task_write(tags);
+    printk("[blare_msg_queue_msgsnd] (process %s)\n",current->comm);
+
+    blare_trace(TRACE_MSGQ, MAY_WRITE, 0, NULL, 0);
+    return 0;
+}
+
+/* We receive a message, and we have to wake up the target process in case the
+ * current process is not the target process (which truely happens).
+ */
+static int blare_msg_queue_msgrcv (struct msg_queue *msq, struct msg_msg *msg, 
+        struct task_struct *target, long type, int mode){
+    struct blare_tags *tags;
+    int rc;
+
+    if (!msg->security) return 0;
+    tags = msg->security;
+    printk("[blare_msg_queue_msgrcv] (target %s )\n", target->comm);
+
+    /* We cannot alter target's credentials unless it is the current process */
+    if (target != current)
+        wake_up_process(target);
+
+    rc = blare_task_read(tags);
+    blare_trace(TRACE_MSGQ, MAY_READ, 0, NULL, 0);
+    return 0;
+}
+
+/* Allocate a security structure to single messages in System V message queues */
+static int blare_msg_alloc_security(struct msg_msg *msg){
+    struct blare_tags *tags;
+    tags = kmem_cache_zalloc(blare_tags_cache, GFP_KERNEL);
+    if (!tags) return -ENOMEM;
+    tags->info = NULL;
+    msg->security = tags;
+    return 0;
+}
+
+static void blare_msg_free_security(struct msg_msg *msg){
+    struct blare_tags *tags;
+    tags = msg->security;
+    tags_free(&tags);
+    msg->security = NULL;
+}
+
+/* Allocate a security structure when a new shared memory segment is created
+*/
+static int blare_shm_alloc_security(struct shmid_kernel *shp){
+    struct blare_tags *shtags;
+    struct kern_ipc_perm *isp = &shp->shm_perm;
+    shtags = kzalloc(sizeof(struct blare_tags), GFP_KERNEL);
+    if (!shtags) return -ENOMEM;
+
+    isp->security = shtags;
+    /*rc = itag_alloc(&shtags->info);
+    return rc;
+    */
+    return 0;
+}
+
+/* Current process attaches to a shared memory segment. */
+static int blare_shm_shmat (struct shmid_kernel *shp, char __user *shmaddr, int shmflg){
+    struct blare_task_struct *tstruct;
+    struct kern_ipc_perm *isp = &shp->shm_perm;
+    int rc;
+    struct blare_tags *shtags;
+    const struct cred *cred;
+    
+    //TODO
+    return 0;
+
+    cred = get_current_cred();
+    tstruct = cred->security;
+    if (!tstruct)
+        goto out;
+
+    if (isp->security)
+        shtags = isp->security;
+    else{
+        blare_error(-ENODATA);
+        goto out;
+    }
+    /*
+    else
+        shtags = kmem_cache_alloc(blare_tags_cache, GFP_KERNEL);
+        */
+
+    if (!shtags){
+        blare_error(-ENOMEM);
+        goto out;
+    }
+
+    rc = shm_list_add(isp, &(tstruct->shm), shmflg);
+    if (rc < 0){
+        blare_error(rc);
+        goto out;
+    }
+
+    /* TODO: we should probably move that to shm_list_add: 
+     * --- */
+    rc = itag_merge(shtags->info, tstruct->info_list, GFP_KERNEL);
+    if (rc < 0)
+        blare_error(rc);
+
+    rc = itag_merge(tstruct->info_list, shtags->info, GFP_KERNEL);
+    if (rc < 0)
+        blare_error(rc);
+    /*---*/
+
+out:
+    put_cred(cred); 
+
+    blare_trace(TRACE_SHM, 0, shmflg, NULL, isp->id);
+    return 0;
+}
+
+
+/* Triggered by shmdt() syscall */
+static void blare_shm_shmdt(struct shmid_kernel *shp){
+    struct blare_task_struct *tstruct;
+    struct kern_ipc_perm *isp;     
+    const struct cred *cred;
+
+    //TODO
+    return;
+
+    isp = &shp->shm_perm;
+    if (isp && isp->security){
+        cred = get_current_cred();
+        tstruct = cred->security;
+        if (tstruct && tstruct->shm)
+            shm_list_del(isp,tstruct->shm);
+
+        put_cred(cred);
+    }
+}
+
+/* Free the security structure attached to a memory segments when it is
+ * destroyed. This hook is called in shm_destroy() (see ipc/shm.c).
+ */
+static void blare_shm_free_security(struct shmid_kernel *shp){
+    struct blare_tags *shtags;
+    struct kern_ipc_perm *isp = &shp->shm_perm;
+    shtags = isp->security;
+    if (shtags){
+        itag_free(shtags->info);
+        kfree(shtags);
+        isp->security = NULL;
+    }
+}
+
+// Unused, just for debug purpose
+int blare_file_receive(struct file *file){
+    struct inode *inode;
+    struct dentry *dp;
+    dp = dget(file->f_dentry);
+    inode = dp->d_inode;
+    BLARE_DEBUG("received fd:");
+    printk(KERN_DEBUG "%lu", inode->i_ino);
+    dput(dp);
+    return 0;
+}
+
+
+/* Hooks */
+struct security_operations blare_ops = {
+    .name = "blare",
+
+    /* File hooks*/
+    .file_permission = 		    blare_file_permission,
+    .file_alloc_security = 		blare_file_alloc_security,
+    .file_free_security = 		blare_file_free_security,
+    .file_mmap =                blare_file_mmap,
+
+    .inode_alloc_security =     blare_inode_alloc_security,
+    .inode_free_security =     blare_inode_free_security,
+
+    /* Task credentials */
+    .cred_alloc_blank = blare_cred_alloc_blank,
+    .cred_free  =   blare_cred_free,
+    .cred_transfer = blare_cred_transfer,
+    .cred_prepare = blare_security_prepare_creds,
+    .task_create = blare_task_create,
+
+    /* Proc attributes */
+    .getprocattr = blare_getprocattr,
+
+    /* bprm stuff (execution of binaries) */
+    .bprm_set_creds =        blare_bprm_set_creds,
+    .bprm_committed_creds = blare_bprm_committed_creds,
+
+    /* Socket and IPC hooks */
+    .sk_alloc_security = blare_sk_alloc_security,
+    .sk_free_security = blare_sk_free_security,
+	.socket_sock_rcv_skb = blare_socket_sock_rcv_skb,
+    .socket_recvmsg = blare_socket_recvmsg,
+    .socket_sendmsg = blare_socket_sendmsg,
+    //.socket_post_create = blare_socket_post_create, 
+    .socket_sock_release = blare_socket_sock_release,
+
+    .unix_may_send = blare_unix_may_send,
+
+    /* Shared memory segments*/
+
+    .shm_shmdt = blare_shm_shmdt,
+    /*
+    .shm_shmat = blare_shm_shmat,
+    .shm_alloc_security = blare_shm_alloc_security,
+    .shm_free_security = blare_shm_free_security,
+    */
+
+    .msg_msg_alloc_security = blare_msg_alloc_security,
+    .msg_msg_free_security = blare_msg_free_security,
+    .msg_queue_msgrcv = blare_msg_queue_msgrcv,
+    .msg_queue_msgsnd = blare_msg_queue_msgsnd,
+
+    /* We'll need them later
+    .netlink_recv = blare_netlink_recv,
+    .netlink_send = blare_netlink_send
+    */
+};
+
+
+
+// ***  Unused stuff *** 
+//
+/* This extra hook was to make sure we don't create tag structures for
+ * all inodes but only those linked to a pipe...
+ * Only used once to debug stuff
+int blare_pipe_create(struct file *fildes, int flags){
+    struct dentry *dp;
+    struct inode *inode;
+    return 0;
+
+    BLARE_DEBUG("pipe_create");
+
+    if (fildes->f_dentry)
+        dp = dget(fildes->f_dentry);
+
+    if(dp){
+        inode = dp->d_inode;
+        if (inode->i_pipe)
+            BLARE_DEBUG("Pipe initialized");
+    }
+
+    return 0;
+}
+*/
+
+/*  security.h says : @file_mprotect:
+ *	Check permissions before changing memory access permissions.
+ *	@vma contains the memory region to modify.
+ *	@reqprot contains the protection requested by the application.
+ *	@prot contains the protection that will be applied by the kernel.
+ *	Return 0 if permission is granted.
+ */
+
+/* This makes sure processes do not clear the O_APPEND flag that is used when a
+ * file is opened in append mode.
+ * But it also breaks stuff :(
+ * TODO: There are some authentication problems to resolve first.
+static int blare_file_fcntl(struct file *file, unsigned int cmd, 
+        unsigned long arg){
+    if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) 
+        return -EPERM;
+    return 0;
+}
+*/
+
+
diff --git a/security/blare/mmap.c b/security/blare/mmap.c
new file mode 100644
index 0000000..9a11f49
--- /dev/null
+++ b/security/blare/mmap.c
@@ -0,0 +1,197 @@
+/*  mmap management in Blare IDS.
+ *  See include/mmap.h for more information
+ *
+ *  Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ *
+ */
+
+#include "include/mmap.h"
+#include "blare.h"
+//#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/rbtree.h>
+#include <linux/errno.h>
+
+struct rb_root *blare_mmap_tree_root;
+
+/* Local static functions */
+static struct blare_mmap_struct *blare_mmap_add(unsigned long addr);
+static struct blare_mmap_struct *blare_mmap_del(unsigned long addr);
+
+static struct blare_mmap_struct *blare_search_mmap(unsigned long addr);
+
+static int mmap_bind(struct list_head **list, struct blare_mmap_struct *mstruct,
+        struct blare_mmap_bound **bound);
+
+static struct blare_mmap_bound *find_mmap(struct list_head *mmap_list,
+        struct blare_mmap_struct *mstruct);
+
+
+/* This is the function to call when a mmap occurs 
+ * @addr: the address of the mapping
+ * Returns: a pointer to the blare_mmap_struct for this mapping
+ * Note: if no structure exists yet, it will be created by the underlying
+ * code.
+ * */
+struct blare_mmap_struct *blare_mmap(unsigned long addr){
+    struct blare_mmap_struct *mstruct;
+    struct blare_mmap_bound *bound;
+    const struct cred *cred;
+    struct blare_task_struct *tstruct;
+    struct list_head *list;
+    int rc = 0;
+
+    mstruct = blare_mmap_add(addr);
+    atomic_inc(&mstruct->refcount);
+    //mmap_list_add(mstruct); //TODO
+
+    cred = get_current_cred();
+    tstruct = cred->security;
+    list = tstruct->mmap_list;
+
+    /* Bind the mmap structure to the current process */
+    rc = mmap_bind(&tstruct->mmap_list, mstruct, &bound);
+
+    put_cred(cred);
+    return mstruct;
+}
+
+
+/* === Static === */
+
+/* Add a new memory mapping to the global mmap tree */
+static struct blare_mmap_struct *blare_mmap_add(unsigned long addr){
+    struct rb_node **new, *parent = NULL;
+    struct blare_mmap_struct *mstruct, *newstruct;
+    int value;
+    struct rb_root *root = blare_mmap_tree_root;
+
+    if (!addr){
+        blare_error(-ENODATA);
+        return NULL;
+    }
+
+    new = &(root->rb_node);
+
+    /* Go to the bottom of the tree */
+    while (*new)
+    {
+        mstruct = container_of(*new,struct blare_mmap_struct,node);
+        value = mstruct->addr;
+        parent = *new;
+        if (addr > value)
+            new = &((*new)->rb_left);
+        else if (addr < value)
+            new = &((*new)->rb_right);
+        else
+            return mstruct; // If already in the tree
+    }
+
+    /* Add new node and rebalance tree. */
+    newstruct = kmalloc(sizeof(struct blare_mmap_struct), GFP_KERNEL);
+    rb_link_node(&newstruct->node, parent, new);
+    rb_insert_color(&newstruct->node, root);
+
+    return mstruct;
+}
+
+/* Return a reference on a blare_mmap_struct if found in the mmap tree
+ */
+static struct blare_mmap_struct *blare_search_mmap(unsigned long addr){
+struct rb_node *node;
+    struct blare_mmap_struct *mstruct;
+    struct rb_root *root = blare_mmap_tree_root;
+
+    if (!root){
+        blare_error(-ENODATA);
+        return NULL;
+    }
+
+    node = root->rb_node;  /* top of the tree */
+
+    while (node)
+    {
+        mstruct = rb_entry(node, struct blare_mmap_struct, node);
+
+        if(DEBUG_MMAP)
+            printk("[tree_search] search for %lu, current node is %lu\n",addr ,mstruct->addr);
+
+        if (mstruct->addr < addr)
+            node = node->rb_left;
+        else if (mstruct->addr > addr )
+            node = node->rb_right;
+        else
+            return mstruct;  /* Found it */
+    }
+    return NULL; /*Found nothing*/
+}
+
+
+/* Bind an entry of the mmap tree to a process */
+static int mmap_bind(struct list_head **list, struct blare_mmap_struct *mstruct,
+        struct blare_mmap_bound **bound){
+    struct blare_mmap_bound *nbound;
+    struct list_head *newlist;
+
+    if (!list)
+        return -ENODATA;
+    
+    /* The process may have no list at all at this stage if this is its first
+     * mmap, in this case we need to allocate it*/
+if (!*list){
+        newlist = kmalloc(sizeof(struct list_head), GFP_KERNEL);
+        if (!newlist) return -ENOMEM;
+        INIT_LIST_HEAD(newlist);
+        *list = newlist;
+    }
+
+    /* If the list already exists, we need to ensure the mmap is not (bound)
+     * there already */
+    else{
+        nbound = find_mmap(*list, mstruct);
+        if (nbound){
+            *bound = nbound;
+            return 1;
+        }
+    }
+
+    /* Alocate a list node to be added to the current process's shm list*/
+    nbound = kmalloc(sizeof(struct blare_mmap_bound),GFP_KERNEL);
+    if (!nbound)
+        return -ENOMEM;
+
+    nbound->mmap = mstruct;
+    list_add(&nbound->node, *list);
+
+    *bound = nbound;
+    return 0;
+}
+
+/* Find whether a mmap is already bound to the process holding mmap_list.
+ * This check is necessary to ensure we don't bind it twice in mmap_bind
+ */
+static struct blare_mmap_bound *find_mmap(struct list_head *mmap_list, struct blare_mmap_struct *mstruct){
+    struct list_head *position;
+    struct blare_mmap_bound *bound;
+
+    if (!mmap_list){
+        blare_error(-ENODATA);
+        return NULL;
+    }
+
+    list_for_each(position, mmap_list){
+        bound = list_entry(position, struct blare_mmap_bound, node);
+        if (bound && bound->mmap == mstruct)
+            return bound;
+    }
+    return NULL;
+}
+
+
diff --git a/security/blare/netfilter_hooks.c b/security/blare/netfilter_hooks.c
new file mode 100644
index 0000000..05da188
--- /dev/null
+++ b/security/blare/netfilter_hooks.c
@@ -0,0 +1,153 @@
+/* Netfilter hooks
+ *
+ *  Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ */
+
+
+#if defined (CONFIG_NETFILTER)
+#include <linux/netfilter_ipv4.h>
+#include "blare.h"
+#include "include/netlabel.h"
+#include <linux/export.h>
+#include "include/itag.h"
+
+extern int blare_initialized;
+
+/* We don't use netfilter hooks anymore. ipv4_output was used at first to label
+ * the packets themselves (for outgoing traffic), as opposed to labelling the
+ * sockets as we do currently. To enable those hooks, uncomment the __initcall
+ * at the bottom of this file.
+ * */
+static unsigned int blare_ipv4_output(unsigned int hooknum,
+					struct sk_buff *skb,
+					const struct net_device *in,
+					const struct net_device *out,
+					int (*okfn)(struct sk_buff *))
+{
+    struct netlbl_lsm_secattr secattr;
+    int rc;
+    struct sock *sk;
+    struct blare_task_struct *tstruct = NULL;
+    const struct cred *cred;
+
+    sk = skb->sk;
+
+    /* ipv4 only*/
+    if (sk->sk_family != PF_INET || blare_enabled == 0)
+        return 0;
+
+    cred = get_current_cred();
+    if (!cred){
+        put_cred(cred);
+        return 0;
+    }
+
+    tstruct = cred->security;
+
+    /* No tags = no netlabel*/
+    if (unlikely(!tstruct)){
+        put_cred(cred);
+        blare_debug("No task struct");
+        return NF_ACCEPT;
+    }
+
+    if (!tstruct->info_list || list_empty(tstruct->info_list)){
+        put_cred(cred);
+        return NF_ACCEPT;
+    }
+
+
+    netlbl_secattr_init(&secattr);
+    rc = blare_itag2secattr(tstruct->info_list, &secattr);
+    put_cred(cred);
+
+    if (rc !=0){
+        blare_error(rc);
+    }
+    else{
+        /* We need to lock the socket before setting netlabel secattr */
+        /*
+        local_bh_disable();
+        bh_lock_sock_nested(sk);
+        */
+
+        rc = netlbl_skbuff_setattr(skb, sk->sk_family, &secattr);
+
+        /*
+        bh_unlock_sock(sk);
+        local_bh_enable();
+        */
+
+        itag_debug(tstruct->info_list,"socket_out");
+        netlbl_secattr_destroy(&secattr);
+    }
+
+    if (rc !=0)
+        blare_warn("error %d setting socket attributes", rc);
+
+    return NF_ACCEPT;
+}
+
+
+/* We use socket_skb_rcv instead */
+static unsigned int blare_ipv4_input(unsigned int hooknum,
+					struct sk_buff *skb,
+					const struct net_device *in,
+					const struct net_device *out,
+					int (*okfn)(struct sk_buff *))
+{
+
+    return NF_ACCEPT;
+}
+
+static struct nf_hook_ops blare_ipv4_ops[] = {
+    {
+        .hook =		blare_ipv4_output,
+        .owner =	THIS_MODULE,
+        .pf =		PF_INET,
+        .hooknum =	NF_INET_LOCAL_OUT,
+        .priority =	NF_IP_PRI_SECURITY,
+        .priority = 50
+    },
+
+    {
+        .hook =		blare_ipv4_input,
+        .owner =	THIS_MODULE,
+        .pf =		PF_INET,
+        .hooknum =	NF_INET_LOCAL_IN,
+        .priority =	NF_IP_PRI_SECURITY,
+        .priority = 50
+    }
+};
+
+
+/* Netfilter hooks init */
+static int __init blare_nf_ip_init(void)
+{
+	int err = 0;
+
+	if (!blare_initialized){
+        printk(KERN_DEBUG "Blare: blare is NOT initialized, can't initialize netfilter hooks :(\n");
+        return 0;
+    }
+
+	err = nf_register_hooks(blare_ipv4_ops, ARRAY_SIZE(blare_ipv4_ops));
+	if (err)
+		panic("Blare: nf_register_hooks (IPv4) error %d :(\n", err);
+    else
+        printk(KERN_DEBUG "Blare:  Registered netfilter hooks :)\n");
+
+    return 0;
+}
+
+#endif
+
+//__initcall(blare_nf_ip_init);
+
diff --git a/security/blare/netlabel.c b/security/blare/netlabel.c
new file mode 100644
index 0000000..2f11984
--- /dev/null
+++ b/security/blare/netlabel.c
@@ -0,0 +1,432 @@
+/*  We use netlabel to carry security information on network packets.
+ *
+ *  Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ */
+
+
+#include <net/netlabel.h>
+#include <net/cipso_ipv4.h>
+#include "include/netlabel.h"
+#include "blare.h"
+#include <linux/in.h>
+#include <linux/byteorder/generic.h>
+#include "include/itag.h"
+
+
+/**
+ * blare_netlabel_audit_set - fill a netlbl_audit struct
+ */
+void blare_netlabel_audit_set(struct netlbl_audit *nap)
+{
+    u32 secid = 10; //arbitrary static value - may be changed later
+	nap->secid = secid;
+	nap->loginuid = audit_get_loginuid(current);
+	nap->sessionid = audit_get_sessionid(current);
+}
+
+
+ /* Initialization of Netlabel domain mappings
+  * Called from blare_init_securityfs()
+  */
+void blare_cipso_doi(void)
+{
+    int rc;
+    struct cipso_v4_doi *doip;
+    struct netlbl_audit nai;
+
+    /* Netlabel mapping addresses*/
+    //const struct in_addr inmask = {0x0}; // /0
+    const struct in_addr inmask = {0x0}; 
+    const struct in_addr inaddr = {0x0}; 
+ 
+    /* Localhost only, i.e. only local traffic gets labeled
+    const struct in_addr inmask_local = {0xff}; // /0
+    const struct in_addr inaddr_local = {0x100007f}; //127.0.0.1
+     */
+
+    blare_netlabel_audit_set(&nai);
+
+    /* Remove Netlabel default unlabelled mapping*/
+    rc = netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai);
+    if (rc != 0)
+        printk(KERN_WARNING "blare %s:%d remove rc = %d\n",
+                __func__, __LINE__, rc);
+
+    doip = kmalloc(sizeof(struct cipso_v4_doi), GFP_KERNEL);
+    if (doip == NULL)
+        panic("Blare:  Failed to initialize cipso DOI.\n");
+    doip->map.std = NULL;
+    doip->doi = BLARE_CIPSO_DOI;
+    doip->type = CIPSO_V4_MAP_PASS;
+    doip->tags[0] = CIPSO_V4_TAG_RBITMAP;
+    for (rc = 1; rc < CIPSO_V4_TAG_MAXCNT; rc++)
+        doip->tags[rc] = CIPSO_V4_TAG_INVALID;
+
+    /* Add a cipsov4 doi */
+    rc = netlbl_cfg_cipsov4_add(doip, &nai);
+    if (rc != 0) {
+        printk(KERN_WARNING "blare %s:%d failed to add cipso doi (%d) :(\n",
+                __func__, __LINE__, rc);
+        kfree(doip);
+        return;
+    }
+   
+    /* Blare labelled mapping 
+     * I don't know why: specifying addresses here breaks netlbl_sock_setattr(),
+     * which always return -EDESTADDRREQ. Setting those to NULL strangely fixes it...
+     */
+    //rc = netlbl_cfg_cipsov4_map_add(doip->doi, BLARE_CIPSO_DOMAIN, &inaddr, &inmask , &nai);
+    rc = netlbl_cfg_cipsov4_map_add(doip->doi, BLARE_CIPSO_DOMAIN, NULL, NULL , &nai);
+
+    if (rc != 0) {
+        printk(KERN_WARNING "blare %s:%d failed to add cipsov4 mapping (%d) :(\n",
+                __func__, __LINE__, rc);
+        kfree(doip);
+        return;
+    }
+
+    printk(KERN_INFO "Blare: CIPSO domain initialized :)\n");
+    printk(KERN_INFO "Blare: netlabel mapping for addr=%x, mask=%x\n",inaddr.s_addr,inmask.s_addr);
+}
+
+/* Fills an itag from a Netlabel category bitmap 
+ * @tags: a pointer to the struct blare_tags of the socket (sk->sk_security)
+ * The caller must ensure tags->info exists before calling this function.
+ * */
+int blare_netlabel_insert(struct blare_tags *tags, struct netlbl_lsm_secattr_catmap *catmap){
+    int pcat = -1, count = 0;
+    struct list_head *itag;
+    struct information *item, *info;
+
+    if (unlikely(!catmap || !tags))
+        return -1;
+
+    itag = tags->info;
+    if (!itag)
+        return -2;
+
+    list_for_each_entry(item, itag, node){
+        for(pcat;;){
+            pcat = netlbl_secattr_catmap_walk(catmap, pcat);
+            if (pcat < 0) //returns -ENOENT on failure
+                break;
+
+            /* This goes to the next list item and to the next pcat */
+            if (item->value == pcat){
+                pcat ++;
+                break;
+            }
+
+            /* This goes to the next list item*/
+            if (pcat > item->value && !list_is_last(&item->node,itag)){
+                break;
+            }
+
+            info = kmem_cache_alloc(blare_info_cache,GFP_ATOMIC);
+            if (!info) goto nomem;
+            /* Here we substract the offset we added in blare_itag2catmap and
+             * get back the original values*/
+            info->value = (pcat - (BLARE_BITMAP_MAX/2));
+
+            blare_debug("blare: converting recieved catmap:"
+                    "pcat = %d -> info->value =%d\n", current->comm,
+                    current->pid, pcat, info->value);
+
+            if (pcat < item->value)
+                list_add_tail(&info->node,itag);
+            else
+                list_add(&info->node, itag);
+            count ++;
+        }
+    }
+    
+    return count;
+nomem:
+    return -ENOMEM;
+}
+
+/* Generates an itag from a Netlabel category bitmap */
+struct list_head *blare_catmap2itag(struct netlbl_lsm_secattr_catmap *catmap)
+{
+    int pcat;
+    struct list_head *itag;
+    struct information *info;
+
+    if (!catmap) return NULL;
+
+    itag = kmalloc(sizeof(struct list_head),GFP_ATOMIC);
+    if (!itag) goto nomem;
+    INIT_LIST_HEAD(itag);
+
+    for(pcat=-1;;){
+        pcat = netlbl_secattr_catmap_walk(catmap, pcat + 1);
+        if (pcat < 0) //returns -ENOENT on failure
+            break;
+        else{
+            info = kmem_cache_alloc(blare_info_cache,GFP_ATOMIC);
+            if (!info) goto nomem;
+            /* Here we substract the offset we added in blare_itag2catmap and
+             * get back the original values*/
+            info->value = (pcat - (BLARE_BITMAP_MAX/2));
+
+            if(DEBUG_NETWORK) 
+                printk(KERN_DEBUG"blare: %s (pid %d) converting recieved catmap:"
+                        "pcat = %d >> info->value =%d\n", current->comm,
+                        current->pid, pcat, info->value);
+
+            list_add_tail(&info->node,itag);
+        }
+    }
+
+    if (list_empty(itag)){
+        kfree(itag);
+        return NULL;
+    }
+    return itag;
+nomem:
+    BLARE_DEBUG("ENOMEM :(\n");
+    itag_free(itag);
+    //return ERR_PTR(-ENOMEM);
+    return NULL;
+}
+
+/* Generates a netlabel category bitmap from an itag */
+int blare_itag2catmap_rcu(struct list_head* itag, struct netlbl_lsm_secattr_catmap *catmap)
+{
+    struct information *info;
+    //struct list_head *position;
+    int rc, val;
+
+    if (!catmap || !itag)
+        return -ENODATA; 
+
+    catmap->startbit = 0;
+
+    rcu_read_lock();
+    list_for_each_entry_rcu(info, itag, node){
+        //info = list_entry_rcu(position, struct information, node);
+        /* We do add an offset to the tags before insterting them in the catmap,
+         * as the catmap only takes positive values. */
+        val = info->value + (BLARE_BITMAP_MAX/2);
+        if ((val > 0) && (val < BLARE_BITMAP_MAX)){
+            if (DEBUG_NET) printk(KERN_DEBUG "blare: inserting %d(%d) in category map\n", val, info->value);
+            rc = netlbl_secattr_catmap_setbit(catmap, val, GFP_ATOMIC);
+            if (rc < 0)
+                blare_error(rc);
+        }
+    }
+    rcu_read_unlock();
+    return 0;
+}
+
+int blare_itag2catmap(struct list_head* itag, struct netlbl_lsm_secattr_catmap *catmap)
+{
+    struct information *info;
+    //struct list_head *position;
+    int rc, val;
+
+    if (!catmap || !itag)
+        return -ENODATA; 
+
+    catmap->startbit = 0;
+
+    list_for_each_entry(info, itag, node){
+        //info = list_entry_rcu(position, struct information, node);
+        /* We do add an offset to the tags before insterting them in the catmap,
+         * as the catmap only takes positive values. */
+        val = info->value + (BLARE_BITMAP_MAX/2);
+        if ((val > 0) && (val < BLARE_BITMAP_MAX)){
+            if (DEBUG_NET) printk(KERN_DEBUG "blare: inserting %d(%d) in category map\n", val, info->value);
+            rc = netlbl_secattr_catmap_setbit(catmap, val, GFP_ATOMIC);
+            if (rc < 0)
+                blare_error(rc);
+        }
+    }
+    return 0;
+}
+
+
+/* Convert an itag into a netlabel secattr structure 
+ * The secattr structure must be allocated and initialized by the caller.
+ * If the itag is NULL or empty, just set the MLS level and domain
+ * */
+int blare_itag2secattr(struct list_head *itag, struct netlbl_lsm_secattr *secattr){
+    int rc;
+
+    if(!itag)
+        return -ENODATA;
+
+    if(IS_ERR(itag))
+        return PTR_ERR(itag);
+
+    secattr->flags |= (NETLBL_SECATTR_MLS_LVL | NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_SECID);
+    secattr->attr.mls.lvl = BLARE_CIPSO_LEVEL; 
+    secattr->domain = BLARE_CIPSO_DOMAIN;
+    secattr->attr.secid = 10;
+    secattr->type = 1;
+
+    if (itag && !list_empty(itag)){
+        secattr->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
+        if (!secattr->attr.mls.cat)
+            return -ENOMEM;
+
+        rc = blare_itag2catmap(itag, secattr->attr.mls.cat);
+        if (rc < 0)
+            goto err;
+
+        secattr->flags |= NETLBL_SECATTR_MLS_CAT;
+        if (DEBUG_NET) 
+            printk(KERN_DEBUG "blare_itag2secattr: %s (pid %d) catmap created\n", current->comm, current->pid);
+    }
+    return 0;
+
+err:
+    blare_error(rc);
+    netlbl_secattr_catmap_free(secattr->attr.mls.cat);
+    return rc;
+}
+
+
+/* ############ Unused funcions ############ */
+
+/* Create a bitmap from an itag. This bitmap can then used as a network label
+ * to carry blare tags over the network.
+ * This function isn't used at the moment.
+ * */
+uint8_t *blare_itag2bitmap(struct list_head *itag){
+    struct information *info;
+    //struct list_head *position;
+    int x;
+    uint8_t *bitmap;
+
+    if (!itag)
+        return NULL;
+
+    bitmap = kzalloc(sizeof(uint8_t) * BLARE_BITMAP_MAX, GFP_KERNEL);
+
+    list_for_each_entry_rcu(info, itag, node){
+        //info = list_entry_rcu(position, struct information, node);
+        x = info->value;
+        if (x < 240 && x>0){
+            bitmap[x/8] |= (1 << (x%8));
+            printk(KERN_INFO "blare: bitmap no %d is %02X\n",x/8,bitmap[x/8]);
+        }
+    }
+    return bitmap;
+}
+
+/* Create an itag from a bitmap.  
+ * * This function is **UNUSED*** 
+ * */
+struct list_head *blare_bitmap2itag(uint8_t *bitmap){
+    struct information *info; 
+    struct list_head *itag;
+    int i,j,k,val;
+
+    if (!bitmap) 
+        return NULL;
+
+    itag = kmalloc(sizeof(struct list_head), GFP_KERNEL);
+    INIT_LIST_HEAD(itag);
+    //if (!itag) return ERR_PTR(-ENOMEM); 
+    if (!itag) return NULL; 
+
+    for (i=0; i<BLARE_BITMAP_SIZE; i++){
+        for (j=0;j<7;j++){
+            k = bitmap[i];
+            if (((k >> j) & 1) == 1){
+                val = 8 * i + j;
+                info = kmem_cache_alloc(blare_info_cache,GFP_KERNEL);
+                //if (!info) return ERR_PTR(-ENOMEM);
+                if (!info) return NULL;
+                info->value = val;
+                list_add_tail(&info->node,itag);
+            }
+        }
+    }
+    return itag;
+}
+
+unsigned int inet_addr(char *str)
+{
+    int a,b,c,d;
+    char arr[4];
+    sscanf(str,"%d.%d.%d.%d",&a,&b,&c,&d);
+    arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d;
+    return *(unsigned int*)arr;
+}
+
+/* Unused */
+int blare_label_socket(struct socket *sock){
+    struct blare_tags *sotags;
+    struct netlbl_lsm_secattr secattr;
+    int rc;
+    struct sock *sk;
+    struct blare_task_struct *tstruct;
+    const struct cred *cred;
+
+    sk = sock->sk;
+    if (sk->sk_family != PF_INET || blare_enabled == 0)
+        return 0;
+
+    cred = get_current_cred();
+    tstruct = cred->security;
+    if (!tstruct){
+        put_cred(cred);
+        return -ENODATA;
+    }
+
+    itag_debug(tstruct->info_list,"socket_out");
+    put_cred(cred);
+
+    if (!sk->sk_security){
+        blare_warn("socket should have tags");
+        return 0;
+    }
+
+    sotags = sk->sk_security;
+    /* Are we already up to date ? 
+     * This should be in blare_task_write
+     if (sotags->info_rev == tstruct->info_rev && tstruct->info_rev != 0)
+     goto exit;
+     */
+
+    rc = blare_task_write(sotags);
+    if (rc !=0){
+        blare_error(rc);
+        return 0;
+    }
+
+    /* We need to lock the socket before setting netlabel secattr 
+    local_bh_disable();
+    bh_lock_sock_nested(sk);
+    */
+
+    netlbl_secattr_init(&secattr);
+    rc = blare_itag2secattr(sotags->info, &secattr);
+    if (rc !=0){
+        blare_error(rc);
+    }
+    else
+        rc = netlbl_sock_setattr(sk, sk->sk_family, &secattr);
+
+    netlbl_secattr_destroy(&secattr);
+    /*
+    bh_unlock_sock(sk);
+    local_bh_enable();
+    */
+
+    if (rc !=0)
+        blare_warn("error %d setting socket attributes", rc);
+    return 0;
+}
+
+
+
diff --git a/security/blare/network.c b/security/blare/network.c
new file mode 100644
index 0000000..ebb91b8
--- /dev/null
+++ b/security/blare/network.c
@@ -0,0 +1,44 @@
+/* Network policy stuff
+ *
+ *  Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ */
+
+
+#include "blare.h"
+#include "include/itag.h"
+#include "include/ptags.h"
+
+/*
+ * Adds a new tree to the global network policy tag
+ */
+int blare_network_policy_add(int *data, size_t size){
+    struct rb_root *root;
+    struct policy_tree *tree;
+    int count = size/sizeof(int);
+
+    if(!data) return -ENODATA;
+
+    tree = kmem_cache_alloc(blare_policy_tree_cache, GFP_KERNEL);
+    if (!tree) return -ENOMEM;
+
+    root = array2tree(data,count);
+
+    tree->root = root;
+    tree->cardinal = count;
+
+    tree_print(root);
+
+    // TODO: if no root ?
+
+    list_add(&tree->list, blare_network_policy);
+
+    return 0;
+}
+
diff --git a/security/blare/network.h b/security/blare/network.h
new file mode 100644
index 0000000..469eb91
--- /dev/null
+++ b/security/blare/network.h
@@ -0,0 +1,17 @@
+/*  Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ */
+
+
+#ifndef __BLARE_NET_H
+#define __BLARE_NET_H
+/* Functions from network.c*/
+int blare_network_policy_add(int *data, size_t size);
+
+#endif
diff --git a/security/blare/ptags.c b/security/blare/ptags.c
new file mode 100644
index 0000000..35ea4f4
--- /dev/null
+++ b/security/blare/ptags.c
@@ -0,0 +1,619 @@
+/* Policy tags functions.
+ * This file is splitted into two sections : ptag (policy tag) and xptag (execute policy tag).
+ *
+ *  Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ */
+
+#include "blare.h"
+#include "include/ptags.h"
+#include "include/itag.h"
+
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/rbtree.h>
+
+/* ######### Policy tag functions ##########*/
+
+/* This function is used to convert policy tags from their XATTR linear representation
+ * into their abstract representation in memory.
+ * A set of arrays (each one being a subset of the policy) is converted into a list of trees. 
+ */
+struct list_head* arrays2policytag(struct policy_array **arrays, int policy_count){
+    int i,size;
+    int *array;
+    struct list_head *head;
+    struct policy_tree *new;
+
+    BUG_ON(policy_count <= 0);
+
+    // Where is this one freed ?
+    head = kmalloc(sizeof(struct list_head),GFP_KERNEL);
+    if (!head) return ERR_PTR(-ENOMEM);
+
+    INIT_LIST_HEAD(head);
+
+    for(i=0;i<policy_count;i++){
+        new = kmem_cache_alloc(blare_policy_tree_cache,GFP_KERNEL);
+        if (!new) return ERR_PTR(-ENOMEM);
+
+        array = arrays[i]->array;
+        size = arrays[i]->size;
+    
+        INIT_LIST_HEAD(&new->list);
+
+        /* Skip null arrays, with an error */
+        if(!array){
+            blare_error(-ENODATA);
+            kmem_cache_free(blare_policy_tree_cache, new);
+            continue;
+        }
+
+        new->root = array2tree(array,size);
+        /* This probably cannot happen */
+        if (!new->root){
+            blare_error(-ENODATA);
+            kmem_cache_free(blare_policy_tree_cache, new);
+            continue;
+        }
+
+        new->cardinal = size;
+        list_add(&new->list,head);
+
+        if(DEBUG_POLICY){
+            BLARE_DEBUG("[arrays2policytag] Converted array to tree. Array: ");
+            array_print(array,size);
+            BLARE_DEBUG("[arrays2policytag] Tree: ");
+            tree_print(new->root);
+        }
+    }
+    return head;
+}
+
+
+/* Print all the trees of a policy tag */
+void policytag_print(struct list_head *head){
+    struct list_head *position;
+    struct policy_tree *ptr;
+
+    if (!head){
+        BLARE_DEBUG("[policytag_print] null \n");
+        return;
+    }
+
+    if (list_empty(head))
+        BLARE_DEBUG("[policytag_print] empty list\n");
+
+    list_for_each(position,head){
+        ptr = list_entry(position, struct policy_tree, list);
+        tree_print(ptr->root);
+        printk(" - ");
+    }
+    printk("\n");
+}
+
+/* Free the memory of a whole policy tag
+ * including all its subsets (trees) 
+ */
+void policy_tag_free(struct list_head *head){
+    struct list_head *position,*tmp;
+    struct policy_tree *tree;
+
+    if (!head ) return;
+
+    list_for_each_safe(position,tmp,head){
+        tree = list_entry(position, struct policy_tree, list);
+        tree_free(tree->root);
+        list_del(position);
+        kmem_cache_free(blare_policy_tree_cache,tree);
+    }
+
+}
+
+/* Returns a copy of the given policy tag (list of trees)*/
+struct list_head *ptag_copy(struct list_head *head){
+    struct list_head *position, *newhead;
+    struct policy_tree *ptree, *newtree;
+
+    if (!head){
+        if (DEBUG) BLARE_DEBUG("[ptag_copy] Error: null head\n");
+        return NULL;
+    }
+
+    newhead = kmalloc(sizeof(struct list_head), GFP_KERNEL);
+    if (!newhead) return NULL;
+    INIT_LIST_HEAD(newhead);
+
+    list_for_each(position,head){
+        ptree = list_entry(position, struct policy_tree, list);
+        if (!ptree){
+            if (DEBUG) BLARE_DEBUG("[ptag_copy] Error: null tree... abort\n");
+            return NULL; // we should free memory here
+        }
+
+        newtree = kmem_cache_alloc(blare_policy_tree_cache,GFP_KERNEL);
+        if (!newtree){
+            BLARE_DEBUG("[ptag_copy] could not allocate memory\n");
+            return NULL;
+        }
+        newtree->root = tree_copy(ptree->root);
+        if (ptree->cardinal) 
+            newtree->cardinal = ptree->cardinal;
+        list_add(&newtree->list,newhead);
+    }
+    return newhead;
+}
+
+
+/* ######### Tree functions ##########*/
+
+/* This creates a policy tree (binary tree of integers) from an array of integers.
+ * (A policy tag is a list of policy trees)
+ */
+struct rb_root *array2tree(int *array, int size){
+    struct rb_root *root;
+    struct tree_item *new;
+    int i,rc;
+
+    if (!array || size == 0){
+        blare_error(-ENODATA);
+        return NULL;
+    }
+
+    // Where is this one freed ?
+    root = kmalloc(sizeof(struct rb_root),GFP_KERNEL);
+    if(!root && DEBUG)
+        BLARE_DEBUG("[array2tree] memory allocation failed\n");
+
+    if (!root) return NULL;
+
+    *root = RB_ROOT;
+
+    for(i=0;i<size;i++){
+        new = kmem_cache_alloc(blare_tree_item_cache,GFP_KERNEL);
+
+        // If there is no memory, free the allocated nodes
+        // and return NULL
+        if (!new){
+            if(DEBUG)
+                BLARE_DEBUG("[array2tree] couldn't create node\n");
+            tree_free(root);
+            return NULL;
+        }
+
+        new->value = array[i];
+        rc = tree_insert(root,new);
+        if (rc < 0 && DEBUG) BLARE_DEBUG("[array2tree] Error: null root or tree_item\n");
+    }
+    return root;
+}
+
+int *ptree2array(struct policy_tree *ptree){
+    int *array, i=0;
+    struct rb_node *node;
+    struct tree_item *tag;
+    struct rb_root *root;
+
+    if (!ptree || !ptree->root){
+        if (DEBUG_XPOLICY) BLARE_DEBUG("[ptree2array] WARNING: null tree. Exiting\n");
+        return NULL;
+    }
+
+    if (ptree->cardinal <= 0){
+        if (DEBUG_XPOLICY) BLARE_DEBUG("[ptree2array] WARNING: non positive cardinal. Exiting\n");
+        return NULL;
+    }
+
+    root = ptree->root;
+
+    array = kmalloc(ptree->cardinal * sizeof(int), GFP_KERNEL);
+    if (!array) return NULL;
+
+    for (node = rb_last(root); node; node = rb_prev(node)){
+        tag = rb_entry(node, struct tree_item, node);
+        array[i] = tag->value;
+        i++;
+    }
+    return array;
+}
+
+
+/* Insert new elements in a tree of integers
+ */
+int tree_insert(struct rb_root *root, struct tree_item *data){
+    struct rb_node **new, *parent = NULL;
+    struct tree_item *tag;
+    int value;
+
+    if (!root || !data){
+        if (DEBUG) BLARE_DEBUG("[tree_insert] null root or data\n");
+        return -1;
+    }
+
+    new = &(root->rb_node);
+
+    /* Go to the bottom of the tree */
+    while (*new)
+    {
+        tag = container_of(*new,struct tree_item,node);
+        value = tag->value;
+        parent = *new;
+        if (data->value > tag->value)
+            new = &((*new)->rb_left);
+        else if (data->value < tag->value)
+            new = &((*new)->rb_right);
+        else
+            return 1;
+    }
+
+    /* Add new node and rebalance tree. */
+    rb_link_node(&data->node, parent, new);
+    rb_insert_color(&data->node, root);
+
+    return 2;
+
+}
+
+/* Returns a copy of the tree */
+struct rb_root *tree_copy(struct rb_root *root){
+    struct rb_root *newroot;
+    struct rb_node *node;
+    struct tree_item *tag, *newtag;
+    int rc;
+
+    if (!root){
+        if (DEBUG) BLARE_DEBUG("[tree_copy] Error: null root\n");
+        return NULL;
+    }
+
+    newroot = kmalloc(sizeof(struct rb_root), GFP_KERNEL);
+    if (!newroot) return NULL;
+    *newroot = RB_ROOT;
+
+    for (node = rb_first(root); node; node = rb_next(node)){
+        tag = rb_entry(node, struct tree_item, node);
+        if (!tag && DEBUG) BLARE_DEBUG("[tree_copy] Error: null tag !\n"); // That should not happen anyway
+
+        newtag = kmem_cache_alloc(blare_tree_item_cache,GFP_KERNEL);
+        if (!newtag) {
+            BLARE_DEBUG("[tree_copy] Memory allocation error\n");
+            return NULL;
+        }
+
+        newtag->value = tag->value;
+        rc = tree_insert(newroot,newtag);
+        if (rc < 0) BLARE_DEBUG("[tree_copy] Error: null root or tree_item\n");
+    }
+    return newroot;
+}
+
+
+
+/* Free the memory of a tree (subset of a policy tag)
+ * */
+void tree_free(struct rb_root *root){
+    struct rb_node *node,*tmp;
+    struct tree_item *tag;
+
+    if (!root) return;
+
+    for (node = rb_first(root); node; node = tmp){
+        tmp = rb_next(node);
+        tag = rb_entry(node, struct tree_item, node);
+        rb_erase(node,root);
+        kmem_cache_free(blare_tree_item_cache,tag);
+    }
+}
+
+
+/* Print the given tree of a policy tag */
+void tree_print(struct rb_root *root){
+    struct rb_node *node;
+    struct tree_item *tag;
+
+    BLARE_DEBUG("[tree_print] ");
+
+    if (!root){
+        if (DEBUG) BLARE_DEBUG("null root");
+        return;
+    }
+
+    if(RB_EMPTY_ROOT(root)) 
+        BLARE_DEBUG("empty root");
+
+    for (node = rb_first(root); node; node = rb_next(node)){
+        tag = rb_entry(node, struct tree_item, node);
+        printk("%d ",tag->value);
+    }
+}
+
+
+/* Search in a given tree (subset of a policy tag) for a given value
+ * Will return the corresponding struct tree_item if found, or NULL if not found
+ */
+struct tree_item *tree_search(struct rb_root *root, int value){
+    struct rb_node *node;
+    struct tree_item *item;
+    
+    if (!root){
+        if (DEBUG) BLARE_DEBUG("[tree_search] Error: null root\n"); 
+        return NULL;
+    }
+
+    node = root->rb_node;  /* top of the tree */
+
+    while (node)
+    {
+        item = rb_entry(node, struct tree_item, node);
+
+        if(DEBUG_POLICY)
+            printk("[tree_search] search for %d, current node is %d\n",value,item->value);
+
+        if (item->value < value)
+            node = node->rb_left;
+        else if (item->value > value)
+            node = node->rb_right;
+        else
+            return item;  /* Found it */
+    }
+    return NULL; /*Found nothing*/
+}
+
+
+/* Finds out if a is a subset of b, or b is a subset of a (or none of the two)
+ * returns -1 if none is a subset of the other
+ * returns 1 if b is a subset of a
+ * returns 2 if a is a subset of b
+ */
+int tree_is_subset(struct policy_tree *a, struct policy_tree *b){
+    struct policy_tree *big, *small;
+    struct rb_node *node;
+    struct tree_item *item_a, *item_b;
+
+    if (a->cardinal > b->cardinal){
+        big = a; small = b;
+    }
+    else{
+        big = b ; small = a;
+    }
+
+    // If the small tree is a subset of the big tree
+    // then all of its values are in the big tree !
+    for (node = rb_first(small->root); node; node = rb_next(node)){
+        item_a = rb_entry(node, struct tree_item, node);
+
+        // Look for values of a inside b
+        item_b = tree_search(big->root,item_a->value);
+
+        // If a value is not in the big tree, then we don't have a subset
+        if (!item_b)
+            return -1;
+    }
+
+    // If we reach this point, one is the subset of the other... but which one ?
+    if (a == big){
+        tree_print(b->root);
+        printk(KERN_DEBUG "is a subset of ");
+        tree_print(a->root);
+        printk(KERN_DEBUG "\n");
+        return 1;
+    }
+    else{
+        tree_print(a->root);
+        printk(KERN_DEBUG "is a subset of ");
+        tree_print(b->root);
+        printk(KERN_DEBUG "\n");
+        return 2;
+    }
+}
+
+
+
+/* Intersection of two sets (represented as trees)
+ * Iterates over the two trees and finds common elements 
+ * The common elements form a new tree. A pointer on this new tree is returned.
+ * It returns NULL in case of failure
+ * */
+struct policy_tree *intersection(struct policy_tree *a, struct policy_tree *b){
+    struct tree_item *item_a, *item_b, *new;
+    struct policy_tree *result;
+    struct rb_node *node;
+    struct rb_root *root;
+    int cardinal=0;
+
+    if (!a || !b){
+        if(DEBUG_XPOLICY) BLARE_DEBUG("[intersection] Error: one of the trees is NULL\n");
+        return NULL;
+    }
+
+    if (!a->root || !b->root){
+        if (DEBUG_XPOLICY) BLARE_DEBUG("[intersection] Error: one of the trees does not have a root\n");
+        return NULL;
+    }
+
+    /*
+    if (DEBUG_XPOLICY){
+        BLARE_DEBUG("[intersection] intersection of trees: ");
+        tree_print(a->root);
+        tree_print(b->root);
+        printk("\n");
+    }
+    */
+
+    result = kmem_cache_alloc(blare_policy_tree_cache,GFP_KERNEL);
+    if (!result){
+        BLARE_DEBUG("[intersection] ERROR: could not allocate memory\n");
+        return NULL;
+    }
+    
+    result->cardinal = 0;
+  
+    // Quick check for an easy case of mutual exclusion
+    /*
+    if (rb_first(a->root) > rb_last(b->root) || rb_first(b->root) > rb_last(a->root))
+        return result; // Empty tree
+        */
+  
+    root = kmalloc(sizeof(struct rb_root), GFP_KERNEL);
+    if (!root) return NULL;
+
+    *root = RB_ROOT;
+    result->root = root;
+
+    // Iterate over a
+    for (node = rb_first(a->root); node; node = rb_next(node)){
+        item_a = rb_entry(node, struct tree_item, node);
+        if (!item_a){
+            if (DEBUG_XPOLICY) BLARE_DEBUG("[intersection] Error: NULL item in tree\n");
+            kfree(result);
+            kfree(root);
+            return NULL;
+        }
+
+        //if (DEBUG_XPOLICY) BLARE_DEBUG("[intersection] looking for %d in tree_b\n",item_a->value);
+        // Look for values of a inside b
+        item_b = tree_search(b->root,item_a->value);
+
+        // If found, apend them to the result
+        if (item_b){
+            new = kmem_cache_alloc(blare_tree_item_cache,GFP_KERNEL);
+            if (!new){
+                BLARE_DEBUG("[intersection] ERROR: could not allocate memory\n");
+                return NULL;
+            }
+            cardinal ++;
+            new->value = item_b->value;
+            tree_insert(result->root,new);
+        }
+    }
+
+    result->cardinal = cardinal;
+    if (DEBUG_XPOLICY){
+        BLARE_DEBUG("[intersection] newtree: ");
+        tree_print(result->root);
+        printk("(cardinal: %d)\n",cardinal);
+    }
+    return result;
+}
+
+
+/* ######### Xptag functions ##########*/
+
+/* This function takes two policy tags (or execute policy tags) and looks for
+ * all the common elements of each of their subsets. This relation is defined
+ * as \sqcap in the ICC2011 paper */
+
+void xptag_merge(struct list_head **a, struct list_head *b){
+    struct list_head **old, *new;
+    if (a && *a){
+        old = a;
+        new = common_sets(*a,b);
+        policy_tag_free(*old);
+        *a = new;
+    }
+}
+
+struct list_head *common_sets(struct list_head *a, struct list_head *b){
+    struct list_head *position_a, *position_b, *position_c, *newlist, *tmp;
+    struct policy_tree *tree_a, *tree_b, *tree_c, *inter;
+    int rc=0;
+
+    if (!a || !b) return NULL;
+
+    // initialize new list
+    newlist = kmalloc(sizeof(struct list_head),GFP_KERNEL);
+    if (! newlist)
+        return ERR_PTR(-ENOMEM);
+
+    INIT_LIST_HEAD(newlist);
+
+    // Compare all the sets from the two policies
+    list_for_each(position_a,a){
+        tree_a = list_entry(position_a, struct policy_tree, list);
+
+        list_for_each(position_b,b){
+            tree_b = list_entry(position_b, struct policy_tree, list);
+
+            inter = intersection(tree_a,tree_b);
+            if (!inter){
+                if(DEBUG_XPOLICY) BLARE_DEBUG("[common_sets] Error: null intersection\n");
+                continue;
+            }
+
+            if (inter->cardinal == 0){
+                kmem_cache_free(blare_policy_tree_cache,inter);
+                continue;
+            }
+
+            // Is inter a subset of something already in there ?
+            list_for_each_safe(position_c,tmp,newlist){
+                tree_c = list_entry(position_c, struct policy_tree, list);
+
+                rc = tree_is_subset(inter,tree_c);
+                // If inter \subseteq tree_c
+                if (rc == 2){
+                    tree_free(inter->root);
+                    kmem_cache_free(blare_policy_tree_cache,inter);
+                    break;
+                }
+
+                // If tree_c \subseteq inter
+                if (rc == 1){
+                    list_del(&tree_c->list);
+                    tree_free(tree_c->root);
+                    kmem_cache_free(blare_policy_tree_cache,tree_c);
+                    break;
+                }
+            }
+
+            // In case we didn't find any matching intersection
+            if (rc != 2 && inter->cardinal > 0)
+                list_add(&inter->list,newlist);
+        }
+    }
+    return newlist;
+}
+
+/* This function reads the sets of xpolicy_arrays (that corresponds the xattr
+ * representation of an execute policy tag), converts it into a list of trees,
+ * and inserts it into the xptag of the current process. This inclusion
+ * proceeds to the suppression of similar sets (or sets included in other sets).
+ */
+int xptag_insert(struct policy_array **xpolicy_arrays, int xpolicy_count,struct list_head **xpolicy_list){
+    struct list_head *converted, *newlist;
+
+    //BUG_ON(!xpolicy_list);
+    if (!xpolicy_list){
+        blare_warn("No xpolicy list");
+        return -1;
+    }
+
+    converted = arrays2policytag(xpolicy_arrays,xpolicy_count);
+
+    if (IS_ERR(converted))
+        return PTR_ERR(converted);
+
+    if (DEBUG_XPOLICY){
+        BLARE_DEBUG("[xptag_insert] Got xpolicy list from xattr: ");
+        policytag_print(converted);
+    }
+
+    // No xpolicy_list for the current process
+    if (!*xpolicy_list){
+        *xpolicy_list = converted;
+        return 1;
+    }
+
+    // Modify current->xpolicy_list
+    newlist = common_sets(*xpolicy_list,converted);
+    policy_tag_free(*xpolicy_list);
+    *xpolicy_list = newlist;
+
+    return 0;
+}
diff --git a/security/blare/shm.c b/security/blare/shm.c
new file mode 100644
index 0000000..4d31a81
--- /dev/null
+++ b/security/blare/shm.c
@@ -0,0 +1,157 @@
+/*  Shared memory segments
+ *  Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ */
+
+#include <linux/list.h>
+#include <linux/security.h>
+#include <linux/slab.h>
+
+#include "blare.h"
+#include "include/itag.h"
+#include "include/shm.h"
+
+/* blare_update_shm: update information tags of all shared memory segments of
+ * @shmlist.  
+ * @shmlist contains a linked list of struct blare_shmptr 
+ * @info contains the source information tag used for the update. 
+ */
+int blare_update_shm_tags(struct list_head *shmlist, struct list_head *info){ 
+    struct blare_shmptr *shm; 
+    struct list_head *item;
+    struct blare_tags *shtags;
+
+    list_for_each(item,shmlist){
+        shm = list_entry(item, struct blare_shmptr, node);
+        /* TODO: mutex on update ! */
+        if (!(shm->shmflg & SHM_RDONLY) && shm->ptr){
+            shtags = shm->ptr;
+            itag_merge(shtags->info, info, GFP_KERNEL);
+        }
+    }
+    return 0;
+}
+
+
+/* Shm lists attached to processes 
+ *
+ */
+
+/* Free a list */
+void shm_list_free(struct list_head *list){
+    struct blare_shmptr *shm; 
+    struct list_head *item, *tmp;
+
+    if (!list) return;
+
+    list_for_each_safe(item,tmp,list){
+        shm = list_entry(item, struct blare_shmptr, node);
+        kmem_cache_free(blare_shmptr_cache,shm);
+    }
+    kfree(list);
+}
+
+/* shm_list_add: adds a new shm information tag pointer to the list @list
+ */
+int shm_list_add(struct kern_ipc_perm *isp, struct list_head **list, int shmflg){
+    struct blare_shmptr *bshm;
+    struct list_head *shm;
+
+    if (!list || !isp)
+        return -ENODATA;
+
+    /* Alocate a structure to be added to the current process's shm list*/
+    bshm = kmem_cache_alloc(blare_shmptr_cache,GFP_ATOMIC);
+    if (!bshm) return -ENOMEM;
+
+    bshm->ptr = isp->security;
+    bshm->shmflg = shmflg;
+
+    /* The list might not have been initialized yet*/
+    if (!*list){
+        shm = kmalloc(sizeof(struct list_head), GFP_ATOMIC);
+        if (!shm) return -ENOMEM;
+        INIT_LIST_HEAD(shm);
+        *list = shm;
+    }
+
+    list_add(&bshm->node, *list);
+
+    return 0;
+}
+
+/* Removes an item (@shp) from the list @list*/
+void shm_list_del(struct kern_ipc_perm *isp, struct list_head *list){
+    struct list_head *item, *tmp;
+    struct blare_shmptr *bshm;
+
+    if (!isp || !list){
+        blare_error(-ENODATA);
+        return;
+    }
+
+    if(!isp->security){
+        blare_warn("I can't find the corresponding blare_shmptr with no"
+                "security pointer\n");
+        return;
+    }
+
+    list_for_each_safe(item, tmp, list){
+        bshm = list_entry(item, struct blare_shmptr, node);
+        if (!bshm || !bshm->ptr){
+            blare_error(-ENODATA);
+            break;
+        }
+
+        if (bshm->ptr == isp->security){
+            list_del(&bshm->node);
+            kmem_cache_free(blare_shmptr_cache, bshm);
+        }
+    }
+
+    if (list_empty(list))
+        kfree(list);
+}
+
+/* Makes a copy of the shm list of a process.
+ */
+struct list_head *shm_list_copy(struct list_head *list){
+    struct blare_shmptr *shm; 
+    struct blare_shmptr *shm2; 
+    struct list_head *item, *newlist;
+
+    newlist = kmalloc(sizeof(struct list_head),GFP_KERNEL);
+    if (!newlist) return NULL;
+
+    INIT_LIST_HEAD(newlist);
+
+    list_for_each(item,list){
+        shm = list_entry(item, struct blare_shmptr, node);
+        shm2 = kmem_cache_alloc(blare_shmptr_cache,GFP_KERNEL);
+        if (!shm2) goto nomem;
+
+        shm2->ptr = shm->ptr;
+        shm2->shmflg = shm->shmflg;
+        INIT_LIST_HEAD(&shm2->node);
+        list_add(&shm2->node,newlist);
+    }
+
+    return newlist;
+
+nomem:
+    /* Free what we have allocated*/
+    list_for_each(item,newlist){
+        shm = list_entry(item, struct blare_shmptr, node);
+        kmem_cache_free(blare_shmptr_cache, shm);
+    }
+    kfree(newlist);
+    return NULL;
+    //return -ENOMEM;
+}
+
diff --git a/security/blare/tests.c b/security/blare/tests.c
new file mode 100644
index 0000000..9b68468
--- /dev/null
+++ b/security/blare/tests.c
@@ -0,0 +1,114 @@
+
+/* Some tests. If you got anything to write related to testing, it goes right
+ * here.
+ * Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ */
+
+#include "blare.h"
+#include "include/itag.h"
+#include "include/ptags.h"
+
+/*** Synopsis ***/
+void test_alloc(void);
+int checklist(struct list_head *head);
+struct list_head *itag_create(int *array, int size);
+void list_test(void);
+
+/******************************************************/
+
+
+/* Test slab allocation
+ */
+void test_alloc(){
+    char *item;
+    item = kmem_cache_alloc(blare_info_cache,GFP_KERNEL);
+    if(item)
+        printk("Object has been successfully allocated\n");
+    else
+        printk("Error allocating object\n");
+
+    kmem_cache_free(blare_info_cache,item);
+    printk("Object freed\n");
+
+}
+
+ /* Check stuff
+  */
+int checklist(struct list_head *head){
+    printk("Checklist...\n");
+    return 0;
+}
+
+struct list_head *itag_create(int *array, int size){
+    struct list_head *head;
+    int i;
+    struct  information *new;
+
+    // If the array is null, there is no information
+    if (!array || !size || size <=0) 
+        return NULL;
+
+    head = kmalloc(sizeof(struct list_head), GFP_KERNEL);
+
+    if (!head) 
+        return ERR_PTR(-ENOMEM);
+
+    /* Note : head is a standalone list_head element to describe the list
+     * see the list_add macro from linux/list.h */
+    INIT_LIST_HEAD(head);
+
+    //For each element in the array
+    for(i=0;i<size;i++){
+        new = kmem_cache_alloc(blare_info_cache,GFP_KERNEL);
+        if (!new) return ERR_PTR(-ENOMEM);
+        INIT_LIST_HEAD(&new->node);
+        new->value = array[i];
+        list_add_tail(&new->node,head);
+    }
+
+    return head;
+}
+
+
+/* Lists tests
+ */
+void list_test(){
+    struct list_head *list, *list2, *newlist;
+    int array[] = {-1,2,3,4,7,9};
+    int array2[] = {-4,5,6,7,8,9,10};
+
+    list = itag_create(array,6);
+    itag_print(list);
+
+    list2 = itag_create(array2,7);
+    itag_print(list2);
+
+    /*
+    itag_insert(array2,3,list);
+    BLARE_DEBUG("New list:");
+    itag_print(list);
+    */
+
+    BLARE_DEBUG("Copy: ");
+    newlist = itag_copy(list, GFP_KERNEL);
+    itag_print(newlist);
+
+    BLARE_DEBUG("Merge: ");
+    itag_merge(list,list2, GFP_KERNEL);
+    itag_print(list);
+
+    BLARE_DEBUG("Free: ");
+    itag_free(newlist);
+    itag_free(list);
+    itag_free(list2);
+
+}
+
+
diff --git a/security/blare/trace.c b/security/blare/trace.c
new file mode 100644
index 0000000..ba4d4d6b
--- /dev/null
+++ b/security/blare/trace.c
@@ -0,0 +1,189 @@
+ /*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ *
+ *  Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ * ---
+ *  By Default, Blare IDS logs illegal information flows (security policy violations).
+ *  It won't log all legal information flows (thought this could be done
+ *  using the audit subsystem like smack does, see audit.c). 
+ *
+ *  However, it is sometimes needed to track all the information flows related
+ *  to a specific binary as well as all the processes executing it. This can be
+ *  useful to determine what a binary program is doing, and how Blare tags are
+ *  propagated. This is a bit similar to what strace can do for one instance of
+ *  a running program, but we generalize it to all the instances of the program
+ *  (or bunch of programs) whenever it is executed.
+ * ---
+ */
+
+#include "blare.h"
+#include "include/audit.h"
+#include "include/xattr.h"
+#include "include/itag.h"
+#include <linux/mman.h>
+#include "include/trace.h"
+
+static inline void str_from_mmap_prot(char *string, int prot)
+{
+	int i = 0;
+	if (prot & PROT_READ)
+		string[i++] = 'r';
+	if (prot & PROT_WRITE)
+		string[i++] = 'w';
+	if (prot & PROT_EXEC)
+		string[i++] = 'x';
+    string[i] = '\0';
+}
+
+static inline void str_from_mmap_flags(char *string, int flags){
+    int offset = 0;
+    char *msg;
+
+    if (flags & MAP_ANONYMOUS){
+        msg = "+ANONYMOUS";
+        strcat(string, msg);
+        offset += strlen(msg);
+    }
+
+    if (flags & MAP_PRIVATE){
+        msg = " +PRIVATE";
+        strcat(string+offset, msg);
+        offset += strlen(msg);
+    }
+
+    if (flags & MAP_SHARED){
+        msg = " +SHARED";
+        strcat(string+offset, msg);
+    }
+}
+
+
+/* Check wether we should trace a binary execution and
+ * set tstruct->trace appropriately*/
+
+void blare_init_trace(struct dentry *dp, struct blare_task_struct *tstruct){
+    int trace = 0, rc;
+    int *ptr;
+
+    rc = blare_check_trace_flag(dp, &ptr);
+    if (rc == -ENODATA)
+        return;
+
+    if (rc < 0)
+        blare_debug("error %d reading trace xattr\n");
+
+    trace = *ptr;
+    if (trace == 1){
+        tstruct->trace = 1;
+        printk("blare: tracing enabled for %s\n", dp->d_name.name);
+    }
+    kfree(ptr);
+}
+
+/* @subject: the file, socket or other object that is accessed
+ * @mode: the access mode [r,w,x,a] or the protection flags for mmaps
+ * @flags: special flags (MAP_ANONYMOUS etc.)
+ * @id: optional
+ */
+void blare_trace(int type, int mode, int flags, struct file *file, int id){
+    const struct cred *cred;
+    char modes[NB_ACCESS_MODES + 1];
+    char flags_str[MMAP_FLAGS + 1];
+    struct blare_task_struct *tstruct; 
+    char *itag, *typestr = NULL, *path = '\0', *buf = NULL; 
+    // char *dpath = NULL
+    struct dentry *dp;
+
+    if (!file)
+        goto next;
+
+    dp = dget(file->f_dentry);
+    if (!dp)
+        goto next;
+
+    /*
+    buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+    if (!buf){
+        blare_error(-ENOMEM);
+        return;
+    }
+
+    dpath = dentry_path(dp, buf, PAGE_SIZE);
+    if (IS_ERR(dpath)){
+        blare_error(PTR_ERR(path));
+        path = dp->d_name.name;
+    }
+    else
+        path = dpath;
+    */
+
+    path = (char*)dp->d_name.name;
+    dput(dp);
+
+next:
+    flags_str[0] = '\0';
+    //strcat(modes, "n/a"); //by default, no mode
+    modes[0] = '\0';
+    
+    cred = get_current_cred();
+    tstruct = cred->security;
+    if (!tstruct || tstruct->trace == 0){
+        put_cred(cred);
+        return;
+    }
+
+    switch (type){
+        case TRACE_MMAP: 
+            typestr = "mmap";
+            str_from_mmap_prot(modes, mode);
+            str_from_mmap_flags(flags_str, flags);
+            break;
+        case TRACE_SHM:
+            typestr = "shm";
+            break;
+        case TRACE_FILE:
+            typestr = "file";
+            str_from_perm(modes, mode);
+            break;
+        case TRACE_INET:
+            typestr = "af_inet";
+            str_from_perm(modes, mode); // We use MAY_READ and MAY_WRITE instead of send/recieve
+            break;
+        case TRACE_UNIX:
+            typestr = "af_unix";
+            str_from_perm(modes, mode);
+            break;
+        case TRACE_MSGQ:
+            typestr = "msg_queue";
+            str_from_perm(modes, mode);
+            break;
+        case TRACE_PIPE:
+            typestr = "sys_pipe";
+            str_from_perm(modes, mode);
+            break;
+        case TRACE_CLONE:
+            typestr = "sys_clone";
+            //str_from_clone_flags(flags_str, flags);
+            break;
+        default:
+            typestr = "";
+            blare_debug("no trace type given\n");
+            return;
+    }
+
+    itag = itag_to_s(tstruct->info_list);
+    put_cred(cred);
+
+    printk(KERN_DEBUG "blare_trace: _%s(pid %d;cpu %d;parent %d)_ %s %s [mode %s] %s id %d -->"
+            "%s\n",current->comm, current->pid, current->on_cpu, current->real_parent->pid, typestr, path, modes, flags_str, id, 
+            itag);
+    kfree(itag);
+    kfree(buf);
+}
+
diff --git a/security/blare/xattr.c b/security/blare/xattr.c
new file mode 100644
index 0000000..3d68014
--- /dev/null
+++ b/security/blare/xattr.c
@@ -0,0 +1,381 @@
+/* We do store security labels in the extended attributes of the filesystem
+ * (security namespace).
+ *
+ * Author:
+ *      Christophe Hauser <christophe.hauser@xxxxxxxxxx>
+ *      
+ *  Copyright (C) 2010  University of Rennes 1
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ */
+
+#include "blare.h"
+#include "include/itag.h"
+#include "include/ptags.h"
+
+#include <linux/xattr.h>
+#include <linux/rbtree.h>
+#include <linux/errno.h>
+
+
+/* Static functions specific to this module. You should probably not use them
+ * directly unless you know what you are doing */
+static int blare_read_xattr_size(struct dentry *dp, const char *fieldname);
+static int blare_read_xattr(struct dentry *dp, const char *fieldname, int **buffer);
+static int blare_write_xattr(struct dentry *dp, const char *fieldname, int *buffer, int buffersize);
+static int blare_read_policy_generic(struct dentry *dp, struct blare_file_struct *fstruct, bool exec);
+
+
+/* Check whether we should trace a binary program's execution */
+int blare_check_trace_flag(struct dentry *dp, int **ptr){
+    if (!dp) return -ENODATA;
+    return blare_read_xattr(dp,TRACE_XATTR,ptr);
+}
+
+
+/* Reads the information tag of a file from the extended attributes, allocates
+ * fstruct->info_array and sets fstruct->info_count to the size of the array.
+ * @dentry : the dentry corresponding to the accessed file 
+ * NB: to be used along with blare_file_free_info
+ *  */
+int blare_alloc_file_info(struct dentry *dp, struct blare_file_struct *fstruct){
+    int rc,count;
+    int *arrayptr; 
+
+    rc = blare_read_xattr(dp,INFO_XATTR,&arrayptr);
+
+    /* Error*/
+    if (rc<=0)
+        return rc;
+
+    count = rc/sizeof(int);
+    if(arrayptr){
+        fstruct->info_array = arrayptr;
+        fstruct->info_size = count; 
+        return count;
+    }
+
+    // We should never reach this point anyway
+    return -ENODATA;
+}
+
+
+/* Free the information (tag) parf of a fstruct*/
+inline void blare_free_file_info(struct blare_file_struct *fstruct){
+    kfree(fstruct->info_array);
+    fstruct->info_array = NULL;
+}
+
+
+/* Get the container's policy from the extended attributes (and allocate the
+ * buffer to contain it in fstruct->xpolicy_arrays) */
+inline int blare_alloc_file_cpolicy(struct dentry *dp, struct blare_file_struct *fstruct){
+    return blare_read_policy_generic(dp,fstruct,false);
+}
+
+inline void blare_free_file_cpolicy(struct blare_file_struct *fstruct){
+    int i;
+    for(i=0;i<fstruct->policy_count;i++)
+        kmem_cache_free(blare_policy_array_cache,fstruct->policy_arrays[i]);
+}
+
+inline int blare_alloc_file_xpolicy(struct dentry *dp, struct blare_file_struct *fstruct){
+    return blare_read_policy_generic(dp,fstruct,true);
+}
+
+inline void blare_free_file_xpolicy(struct blare_file_struct *fstruct){
+    int i;
+    for(i=0;i<fstruct->xpolicy_count;i++)
+        kmem_cache_free(blare_policy_array_cache,fstruct->xpolicy_arrays[i]);
+}
+
+
+/* Write the information tag to the filesystem's extended attributes
+ * @dp is the struct dentry attached to the file we're writing to (see dcache)
+ * @list points to the head of the information tag
+ */
+int blare_write_info(struct dentry *dp, struct list_head *list){
+    int *array, buffersize,rc;
+
+    rc = itag2array(list,&array);
+    if (rc <= 0) // <0 is an error, 0 is no data
+        return rc;
+
+    buffersize = rc * sizeof(int);
+    // Write the xattr
+    rc = blare_write_xattr(dp,INFO_XATTR,array,buffersize);
+    if (rc < 0){
+        if(DEBUG_INFO)
+            printk(KERN_DEBUG "[blare_write_info] error %d writing XATTR\n",rc);
+        kfree(array);
+        return rc;
+    }
+
+    if (DEBUG_INFO)
+        itag_print_msg(list,"wrote to file %s ", dp->d_name.name);
+    // Cleanup
+    kfree(array);
+
+    // If all is well
+    return 0;
+}
+
+
+/* Write an xptag to the extended attributes of a file
+ * @xpolicy_list: the xptag to write
+ * @dp: the dentry pointer 
+ */
+int blare_write_xpolicy(struct dentry *dp, struct list_head *xpolicy_list){
+    struct list_head *position;
+    struct policy_tree *ptree;
+    int xattr_name_len, rc, *array, *policycount;
+    char *xattr_name;
+
+    if (!xpolicy_list) return 0;
+
+    if (list_empty(xpolicy_list)){
+        if(DEBUG_XPOLICY) printk("[blare_write_policy] attempt to write an EMPTY list\n");
+        return 0;
+    }
+
+    xattr_name_len = sizeof(XPOLICY_XATTR) + sizeof(int);
+    xattr_name = (char*) kmalloc(xattr_name_len,GFP_KERNEL);
+    policycount = (int*) kmalloc(sizeof(int), GFP_KERNEL);
+    *policycount = 0;
+
+    list_for_each(position,xpolicy_list){
+        ptree = list_entry(position, struct policy_tree, list);
+        if (!ptree){
+            if (DEBUG_XPOLICY) printk("[blare_write_xpolicy] Got a NULL policy tree (policycount is %d)\n",*policycount);
+            return -1;
+        }
+
+        array = ptree2array(ptree);
+        if (!array){
+            if (DEBUG_XPOLICY) printk("[blare_write_xpolicy] Got a NULL array (at index %d)\n",*policycount);
+            return -2;
+        }
+
+        snprintf (xattr_name, xattr_name_len,"%s%d", XPOLICY_XATTR,*policycount);
+        /* ptree->cardinal tells us how many information we need to write */
+        rc = blare_write_xattr(dp,xattr_name,array,(ptree->cardinal * sizeof(int)));
+        if (rc < 0) return rc;
+
+        (*policycount)++; 
+        if (DEBUG_XPOLICY) printk("[blare_write_policy] policycount is %d\n",*policycount);
+    }
+
+    rc = blare_write_xattr(dp,XPOLICY_COUNT,policycount,sizeof(int));
+    kfree(policycount);
+    kfree(xattr_name);
+
+    if (rc < 0) return rc;
+
+    return 1;
+}
+
+
+
+/* ########### Static ############# */
+
+/* Returns the size of @fieldname from the xattr of a file 
+ * @fieldname is the name of the field in the extended attributes, 
+ * e.g. "security.blare.info".
+ */
+static int blare_read_xattr_size(struct dentry *dp, const char *fieldname){
+    int rc;
+    struct inode *inode;
+
+    inode = dp->d_inode;
+
+    if (!inode->i_op->getxattr) 
+        return -EOPNOTSUPP;
+    
+    // dummy NULL buffer 
+    // vfs_getxattr will then return the size of *fieldname
+    // See man vfs_getxattr
+
+    // Read the xattr
+    rc = inode->i_op->getxattr(dp, fieldname, NULL, 0);
+    //blare_debug("get_xattr_size returned %d - read access to %s", rc, dp->d_name.name);
+    return rc;
+}
+
+/* Read @fieldname from the xattr of a file corresponding to @dp
+ * @fieldname is the name of the field in the extended attributes, 
+ * e.g. "security.blare.info".
+ * @buffer points to the address of a buffer that is next allocated by
+ * this function (and needs to be freed afterwards). 
+ */
+static int blare_read_xattr(struct dentry *dp, const char *fieldname, int **buffer){
+    struct inode *inode;
+    int size,rc;
+    int *buff;
+
+    if(!fieldname){
+        printk("[blare_read_xattr] No Xattr Fieldname provided...\n");
+        return -1;
+    }
+
+    inode = dp->d_inode;
+    
+    // Get the size of the xattr
+    size = blare_read_xattr_size(dp,fieldname);
+    if (size<=0)
+        return size;
+
+    // Allocate memory
+    buff = (int*)kzalloc(size,GFP_KERNEL);
+    if (!buff)
+        return -ENOMEM;
+
+    // Read the xattr
+    rc = inode->i_op->getxattr(dp, fieldname, buff, size);
+    if (rc<0){
+        kfree(buff);
+        return rc;
+    }
+
+    *buffer = buff;
+    return size;
+}
+
+
+/* Write @buffer to the filesystem's extended attributes in the field corresponding to @fieldname
+ * @dp is the struct dentry attached to the file we're writing to (see dcache)
+ * @buffersize is the size of the buffer
+ */
+static int blare_write_xattr(struct dentry *dp, const char *fieldname, int *buffer, int buffersize){
+    struct inode *inode;
+    int rc;
+
+    inode = dp->d_inode;
+
+    // First : is the xattr handler initialized for this file ?
+    if (!inode->i_op->setxattr){
+        if(DEBUG_INFO)
+            printk("[blare_write_info] setxattr on file %s -EOPNOTSUPP... handler might not be initialized yet\n",dp->d_name.name);
+        return -EOPNOTSUPP;
+    }
+
+    rc = inode->i_op->setxattr(dp, fieldname, buffer, buffersize, 0);
+    return rc;
+}
+
+
+/* Read the policy tag from the extended attributes of the filesystem
+ * @dp is the struct dentry attached to the file we're reading from (see dcache)
+ * @fstruct is the opaque security structure attached to the opened file
+ */
+static int blare_read_policy_generic(struct dentry *dp, struct blare_file_struct *fstruct, bool exec){
+
+    // This is not actually a list
+    struct policy_array *policy_array, **policy_list;
+
+    //int buffersize, xattr_count, version, *versionptr, count, *buffer, rc,i, xattr_size;
+    int rc, i, xattr_name_len;
+    int *policy_count, *buffer; // *xattr_version
+    char *xattr_name;
+    const char *PCOUNT, *PATTR;
+
+    /* Are we reading a policy or an execute policy ? */
+    if(exec){
+        PCOUNT = XPOLICY_COUNT;
+        PATTR = XPOLICY_XATTR;
+        xattr_name_len = sizeof(XPOLICY_XATTR) + sizeof(int);
+    }
+    else{
+        PCOUNT = POLICY_COUNT;
+        PATTR = POLICY_XATTR;
+        xattr_name_len = sizeof(POLICY_XATTR) + sizeof(int);
+    }
+
+    // Version of the policy
+    /*
+    rc = blare_read_xattr(dp,POLICY_VERSION,&xattr_version);
+    if (rc<0)
+        return rc;
+    printk("[blare_read_policy] policyversion: %d\n",*xattr_version);
+    */
+
+    // Get the number of subsets in the policy tag 
+    rc = blare_read_xattr(dp, PCOUNT, &policy_count);
+    if (rc < 0)
+        return rc;
+
+    // In case there is no policy defined for this container
+    if(!*policy_count > 0)
+        return -1;
+
+    if(DEBUG_POLICY || DEBUG_XPOLICY)
+        printk("[blare_read_policy] %s:security.blare.policy_count is %d\n",dp->d_name.name,*policy_count);
+
+    // Allocate memory for the list (note that it is a list of pointers to policy_array structs
+    policy_list = kmalloc(*policy_count * sizeof(struct policy_array*), GFP_KERNEL);
+    //policy_list = kmalloc(*policy_count * sizeof(int), GFP_KERNEL);
+
+    //Allocate a buffer to store the names
+    //xattr_name_len = (sizeof(PATTR) + sizeof(int)); 
+    xattr_name = (char*) kmalloc(xattr_name_len,GFP_KERNEL);
+
+    // Read each array
+    for (i=0; i<*policy_count ; i++){
+        // Each set of the policy tag is written in a separate xattr, with the same
+        // base name + a number (0-9);
+        snprintf (xattr_name, xattr_name_len,"%s%d", PATTR,i);
+        if(DEBUG_POLICY)
+            printk("[blare_read_policy] xattr name: %s\n",xattr_name);
+
+        rc = blare_read_xattr(dp, xattr_name, &buffer);
+        if (rc < 0){
+            kfree (xattr_name);
+            return rc;
+        }
+
+        policy_array = kmem_cache_alloc(blare_policy_array_cache, GFP_KERNEL);
+        policy_array->array = buffer;
+
+        // The number of integers in the int[] of the xattr
+        policy_array->size = rc/sizeof(int);
+
+        policy_list[i] = policy_array;
+    }
+
+    /* Are we reading a policy xattr or an execute policy xattr ? */
+    if(exec){
+        fstruct->xpolicy_arrays = policy_list;
+        fstruct->xpolicy_count = *policy_count;
+    }
+    else{
+        fstruct->policy_arrays = policy_list;
+        fstruct->policy_count = *policy_count;
+    }
+
+    /* Only free local stuff, the remaining is freed in :
+     *  - file_free_security when this is called from file_permission
+     *  - anywhere else in the other cases (e.g. after calling this function)
+     */
+
+    kfree(policy_count);
+    kfree(xattr_name);
+
+    // If all is well
+    //return rc/sizeof(int);
+    return *policy_count;
+}
+
+/* There is no FPU in kernel mode...
+ * This computes log10(*policy_count); 
+int log10(int x){
+    int log;
+    log = 1;
+    while (x >= 10){
+        log ++;
+        x = x / 10;
+    }
+    return log;
+}
+
+ * */
diff --git a/security/security.c b/security/security.c
index e2f684a..a8c4031 100644
--- a/security/security.c
+++ b/security/security.c
@@ -946,6 +946,16 @@ int security_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr, int shmfl
 	return security_ops->shm_shmat(shp, shmaddr, shmflg);
 }
 
+void security_shm_shmdt(struct shmid_kernel *shp)
+{
+	security_ops->shm_shmdt(shp);
+}
+
+int security_pipe_create(struct file *fildes, int flags)
+{
+	return security_ops->pipe_create(fildes, flags);
+}
+
 int security_sem_alloc(struct sem_array *sma)
 {
 	return security_ops->sem_alloc_security(sma);
@@ -1125,6 +1135,11 @@ int security_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
 }
 EXPORT_SYMBOL(security_sock_rcv_skb);
 
+void security_sock_release(struct sock *sk){
+	return security_ops->socket_sock_release(sk);
+}
+EXPORT_SYMBOL(security_sock_release);
+
 int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
 				      int __user *optlen, unsigned len)
 {


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/