[ Thread Index |
Date Index
| More blare-ids.org/blare Archives
]
Au cas où quelqu'un ici a besoin des policy tags, ce patche corrige le bug causé
par une désallocation prématurée des arbres de politiques par le SLAB (lors de
la vérification de politique).
--
Christophe
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..ad76467 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);
@@ -1806,6 +1812,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 +1828,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 +1839,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 +2481,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 +2582,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 +2703,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..5eb1b08 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -511,13 +511,13 @@ const struct file_operations bad_sock_fops = {
void sock_release(struct socket *sock)
{
- if (sock->ops) {
- struct module *owner = sock->ops->owner;
+ if (sock->ops) {
+ struct module *owner = sock->ops->owner;
- sock->ops->release(sock);
- sock->ops = NULL;
- module_put(owner);
- }
+ sock->ops->release(sock);
+ sock->ops = NULL;
+ module_put(owner);
+ }
if (rcu_dereference_protected(sock->wq, 1)->fasync_list)
printk(KERN_ERR "sock_release: fasync list not empty!\n");
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..b94d701
--- /dev/null
+++ b/security/blare/blare.h
@@ -0,0 +1,213 @@
+/* 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 DEBUG_SLAB 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..e6fe915
--- /dev/null
+++ b/security/blare/file_ops.c
@@ -0,0 +1,375 @@
+/* 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"
+
+/* Local functions prototypes */
+static int blare_check_file_policy(struct dentry *dp,
+ struct blare_file_struct *fstruct, struct blare_task_struct *tstruct);
+
+
+/* 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){
+ 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);
+ commit_creds(cred);
+ }
+ else{
+ abort_creds(cred);
+ return 0;
+ }
+ //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;
+ 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);
+
+ /* Let's check if this is legal*/
+ rc = blare_check_file_policy(dp, fstruct, tstruct);
+ }
+ else{ /* TODO: this should be optimized*/
+ blare_free_file_info(fstruct);
+ blare_may_write(dp, 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;
+ 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)
+ rc = blare_check_file_policy(dp, fstruct, tstruct);
+
+ /*Otherwise, the only thing to do is to release the creds.*/
+ 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;
+}
+
+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;
+}
+
+/* When writing or appending information to a file, check that the content is
+ * legal w.r.t. the policy tag of the file*/
+
+static int blare_check_file_policy(struct dentry *dp,
+ struct blare_file_struct *fstruct, struct blare_task_struct *tstruct){
+ int rc;
+ struct list_head *file_policy;
+
+ // 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);
+
+ 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);
+ blare_free_file_cpolicy(fstruct);
+ }
+ return rc;
+}
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..00cb54e
--- /dev/null
+++ b/security/blare/include/file_ops.h
@@ -0,0 +1,13 @@
+#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);
+
+/* 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..5918661
--- /dev/null
+++ b/security/blare/itag.c
@@ -0,0 +1,541 @@
+/* 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 (unlikely(!head)) return;
+
+
+ int rc;
+ 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 (likely(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..a3b450d
--- /dev/null
+++ b/security/blare/lsm_hooks.c
@@ -0,0 +1,1302 @@
+/* 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
+ * Add SLAB_POISON and SLAB_RED_ZONE when debugging
+ */
+ if (DEBUG_SLAB) {
+ blare_info_cache = kmem_cache_create("Blare_info", sizeof(struct
+ information), 0, SLAB_HWCACHE_ALIGN|SLAB_POISON|SLAB_RED_ZONE, NULL);
+
+ blare_policy_array_cache = kmem_cache_create("Blare_policy_array",
+ sizeof(struct policy_array), 0,
+ SLAB_HWCACHE_ALIGN|SLAB_POISON|SLAB_RED_ZONE, NULL);
+
+ blare_tree_item_cache = kmem_cache_create("Blare_tree_item",
+ sizeof(struct tree_item), 0,
+ SLAB_HWCACHE_ALIGN|SLAB_POISON|SLAB_RED_ZONE, NULL);
+
+ blare_policy_tree_cache = kmem_cache_create("Blare_policy_tree",
+ sizeof(struct policy_tree), 0,
+ SLAB_HWCACHE_ALIGN|SLAB_POISON|SLAB_RED_ZONE, NULL);
+
+ blare_task_struct_cache = kmem_cache_create("Blare_task_struct",
+ sizeof(struct blare_task_struct), 0,
+ SLAB_HWCACHE_ALIGN|SLAB_POISON|SLAB_RED_ZONE, NULL);
+
+ blare_file_struct_cache = kmem_cache_create("Blare_file_struct",
+ sizeof(struct blare_file_struct), 0,
+ SLAB_HWCACHE_ALIGN|SLAB_POISON|SLAB_RED_ZONE, NULL);
+
+ blare_shmptr_cache = kmem_cache_create("Blare_shmptr",
+ sizeof(struct blare_shmptr), 0,
+ SLAB_HWCACHE_ALIGN|SLAB_POISON|SLAB_RED_ZONE, NULL);
+
+ blare_tags_cache = kmem_cache_create("Blare_tags",
+ sizeof(struct blare_tags), 0,
+ SLAB_HWCACHE_ALIGN|SLAB_POISON|SLAB_RED_ZONE, NULL);
+ } else {
+ 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 */
+ else if (mask & MAY_WRITE && ! (mask & MAY_APPEND))
+ 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;
+ 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;
+
+ 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;
+}
+
+
+/* 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,
+ .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..2e672cc 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);