Anoubis Version: anoubis.0.9.5.27.73.234
Head of the Anoubis Branch: f90e4de4168eb75072a844e57e2c811b65f88683
Masterhead of the diff: 22763c5cf3690a681551162c15d34d935308c8d7
Upstream Commit Message:
tree f571fbe8f635983c9ea21b73dcec53d7a68f2450
parent 0fdd07f77fd9cc6a7d49076793daef06ea5d8f13
author Linus Torvalds <torvalds@linux-foundation.org> 1259812281 -0800
committer Linus Torvalds <torvalds@linux-foundation.org> 1259812281 -0800

Linux 2.6.32
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index 9ac4e37..3513554 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -181,50 +181,6 @@ static int piix_pci_device_resume(struct pci_dev *pdev);
 static unsigned int in_module_init = 1;
 
 static const struct pci_device_id piix_pci_tbl[] = {
-	/* Intel PIIX3 for the 430HX etc */
-	{ 0x8086, 0x7010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_mwdma },
-	/* VMware ICH4 */
-	{ 0x8086, 0x7111, 0x15ad, 0x1976, 0, 0, piix_pata_vmw },
-	/* Intel PIIX4 for the 430TX/440BX/MX chipset: UDMA 33 */
-	/* Also PIIX4E (fn3 rev 2) and PIIX4M (fn3 rev 3) */
-	{ 0x8086, 0x7111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 },
-	/* Intel PIIX4 */
-	{ 0x8086, 0x7199, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 },
-	/* Intel PIIX4 */
-	{ 0x8086, 0x7601, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 },
-	/* Intel PIIX */
-	{ 0x8086, 0x84CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 },
-	/* Intel ICH (i810, i815, i840) UDMA 66*/
-	{ 0x8086, 0x2411, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_66 },
-	/* Intel ICH0 : UDMA 33*/
-	{ 0x8086, 0x2421, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_33 },
-	/* Intel ICH2M */
-	{ 0x8086, 0x244A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
-	/* Intel ICH2 (i810E2, i845, 850, 860) UDMA 100 */
-	{ 0x8086, 0x244B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
-	/*  Intel ICH3M */
-	{ 0x8086, 0x248A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
-	/* Intel ICH3 (E7500/1) UDMA 100 */
-	{ 0x8086, 0x248B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
-	/* Intel ICH4 (i845GV, i845E, i852, i855) UDMA 100 */
-	{ 0x8086, 0x24CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
-	{ 0x8086, 0x24CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
-	/* Intel ICH5 */
-	{ 0x8086, 0x24DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
-	/* C-ICH (i810E2) */
-	{ 0x8086, 0x245B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
-	/* ESB (855GME/875P + 6300ESB) UDMA 100  */
-	{ 0x8086, 0x25A2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
-	/* ICH6 (and 6) (i915) UDMA 100 */
-	{ 0x8086, 0x266F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
-	/* ICH7/7-R (i945, i975) UDMA 100*/
-	{ 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100_nomwdma1 },
-	{ 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100_nomwdma1 },
-	/* ICH8 Mobile PATA Controller */
-	{ 0x8086, 0x2850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
-
-	/* SATA ports */
-	
 	/* 82801EB (ICH5) */
 	{ 0x8086, 0x24d1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
 	/* 82801EB (ICH5) */
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index df1f86b..743de9e 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -138,6 +138,15 @@ config ICS932S401
 	  This driver can also be built as a module. If so, the module
 	  will be called ics932s401.
 
+config EVENTDEV
+	tristate "Event device for kernel notifications"
+	depends on EXPERIMENTAL
+	---help---
+	  This device allows the kernel to queue arbitrary events
+	  that occur inside the kernel to user space. Depending on the
+	  event a user space process can also provide the kernel with
+	  an answer in the form of an error code.
+
 config ATMEL_SSC
 	tristate "Device driver for Atmel SSC peripheral"
 	depends on AVR32 || ARCH_AT91
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index f982d2e..7bddbd0 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -21,5 +21,6 @@ obj-$(CONFIG_HP_ILO)		+= hpilo.o
 obj-$(CONFIG_ISL29003)		+= isl29003.o
 obj-$(CONFIG_EP93XX_PWM)	+= ep93xx_pwm.o
 obj-$(CONFIG_C2PORT)		+= c2port/
+obj-$(CONFIG_EVENTDEV)		+= eventdev.o
 obj-y				+= eeprom/
 obj-y				+= cb710/
diff --git a/drivers/misc/eventdev.c b/drivers/misc/eventdev.c
new file mode 100644
index 0000000..7f43ae4
--- /dev/null
+++ b/drivers/misc/eventdev.c
@@ -0,0 +1,523 @@
+/*
+ * Copyright (c) 2009 GeNUA mbH <info@genua.de>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/rcupdate.h>
+
+#include <linux/eventdev.h>
+
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+
+/* FIXME: Currently this stuff must not be called from IRQ-Context! */
+
+#define EVENTDEV_NAME "eventdev"
+
+/*
+ * Locking: The contents of messages are only accessed while the message
+ * is not on any list of a queue. This means that there is exactly one thread
+ * that has access to the message. Exceptions are the fields @link and
+ * @msg_reply which are protected by the queue's lock while the message
+ * is not private.
+ * Additionally @wait is only accessed by wait_queue primitives.
+ */
+struct eventdev_msg {
+	struct eventdev_hdr hdr;
+	char * msg_data;
+	struct list_head link;
+	wait_queue_head_t wait;
+	int msg_reply;
+};
+
+struct eventdev_queue {
+	spinlock_t lock;
+	atomic_t users;
+	unsigned int waiters;
+	wait_queue_head_t read_wait;
+	struct list_head messages;
+	struct list_head waiting;
+	struct file * file;
+	struct rcu_head rcu;
+};
+
+static wait_queue_head_t die_wait;
+
+struct rcu_head * eventdev_rcu_head(struct eventdev_queue * q)
+{
+	return &q->rcu;
+}
+
+void eventdev_rcu_put(struct rcu_head * head)
+{
+	struct eventdev_queue * q;
+	q = container_of(head, struct eventdev_queue, rcu);
+	eventdev_put_queue(q);
+}
+
+static int eventdev_get_token(eventdev_token * tok)
+{
+	static eventdev_token next_token = 0;
+	static spinlock_t tokenlock = SPIN_LOCK_UNLOCKED;
+
+	spin_lock_bh(&tokenlock);
+	*tok = ++next_token;
+	spin_unlock_bh(&tokenlock);
+	return 0;
+}
+
+static void free_eventdev_msg(struct eventdev_msg * m)
+{
+	BUG_ON(waitqueue_active(&m->wait));
+	if (m->msg_data)
+		kfree(m->msg_data);
+	kfree(m);
+}
+
+static inline int consume_reply(struct eventdev_queue * q,
+				struct eventdev_msg * m)
+{
+	int ret = 0;
+	spin_lock_bh(&q->lock);
+	if (m->msg_reply >= 0) {
+		list_del(&m->link);
+		ret = 1;
+		q->waiters--;
+	}
+	spin_unlock_bh(&q->lock);
+	return ret;
+}
+
+/*
+ * The data in @data must be allocated by the caller.
+ * The queue @q must be registered to receive messages from the
+ * message source src.
+ */
+static int eventdev_wait(struct eventdev_queue * q, struct eventdev_msg * m)
+{
+	int ret;
+
+	might_sleep();
+
+	if (wait_event_killable(m->wait, consume_reply(q, m)) == 0) {
+		ret = m->msg_reply;
+	} else {
+		/* SIGKILL is pending. Clean up and let the process die. */
+		spin_lock_bh(&q->lock);
+		list_del(&m->link);
+		q->waiters--;
+		ret = EINTR;
+		spin_unlock_bh(&q->lock);
+	}
+	free_eventdev_msg(m);
+	wake_up(&die_wait);
+	return -ret;
+}
+
+/*
+ * The caller is expected to hold a reference to the queue. This reference
+ * is expected to be valid after the function returns even if the function
+ * sleeps. Failure to follow this rule might result in warnings emitted by
+ * eventdev_put_queue.
+ *
+ * The return value indicates that the message was successfully enqueued.
+ * In all cases the buffer pointed to by data is freed.
+ */
+
+static inline int __eventdev_enqueue(struct eventdev_queue * q,
+	unsigned char src, char * data, int len, int *retval, gfp_t flags)
+{
+	struct eventdev_msg * m;
+	int err;
+
+	/*
+	 * This is a small race where we might add messages to an already
+	 * dead queue. This is harmless.
+	 */
+	if (q->file == NULL) {
+		kfree(data);
+		return -EPIPE;
+	}
+	m = kmalloc(sizeof(struct eventdev_msg), flags);
+	if (!m) {
+		kfree(data);
+		return -ENOMEM;
+	}
+	m->hdr.msg_size = sizeof(struct eventdev_hdr) + len;
+	m->hdr.msg_source = src;
+	m->hdr.msg_flags = retval?EVENTDEV_NEED_REPLY:0;
+	m->hdr.msg_pid = current->tgid;
+	m->hdr.msg_uid = current_uid();
+	m->msg_data = data;
+	m->msg_reply = retval?-1:0;
+	init_waitqueue_head(&m->wait);
+	err = eventdev_get_token(&m->hdr.msg_token);
+	if (err)
+		goto err_out;
+	spin_lock_bh(&q->lock);
+	if (q->file == NULL) {
+		spin_unlock_bh(&q->lock);
+		err = -EPIPE;
+		goto err_out;
+	}
+	if (retval)
+		q->waiters++;
+	list_add_tail(&m->link, &q->messages);
+	spin_unlock_bh(&q->lock);
+	wake_up(&q->read_wait);
+	if (retval)
+		(*retval) = eventdev_wait(q, m);
+	return 0;
+err_out:
+	kfree(m);
+	kfree(data);
+	return err;
+}
+
+int eventdev_enqueue_wait(struct eventdev_queue * q, unsigned char src,
+		char * data, int len, int * retval, gfp_t flags)
+{
+	BUG_ON(!retval);
+	return __eventdev_enqueue(q, src, data, len, retval, flags);
+}
+
+int eventdev_enqueue_nowait(struct eventdev_queue * q, unsigned char src,
+		char * data, int len, gfp_t flags)
+{
+	return __eventdev_enqueue(q, src, data, len, NULL, flags);
+}
+
+static struct eventdev_msg * eventdev_dequeue_one(struct eventdev_queue * q)
+{
+	struct eventdev_msg * m = NULL;
+
+	spin_lock_bh(&q->lock);
+	if (!list_empty(&q->messages)) {
+		m = list_entry(q->messages.next, struct eventdev_msg, link);
+		list_del(&m->link);
+	}
+	spin_unlock_bh(&q->lock);
+	return m;
+}
+
+static int eventdev_copy_one(struct eventdev_queue * q,
+			     struct eventdev_msg * m,
+			     char __user *buf, size_t len)
+{
+	size_t cnt = m->hdr.msg_size;
+	int err = -EINVAL;
+
+	if (cnt > len)
+		goto fail;
+	err = -EFAULT;
+	if (copy_to_user(buf, &m->hdr, sizeof(struct eventdev_hdr)))
+		goto fail;
+	buf += sizeof(struct eventdev_hdr);
+	cnt -= sizeof(struct eventdev_hdr);
+	if (copy_to_user(buf, m->msg_data, cnt))
+		goto fail;
+	return m->hdr.msg_size;
+fail:
+	spin_lock_bh(&q->lock);
+	list_add(&m->link, &q->messages);
+	spin_unlock_bh(&q->lock);
+	wake_up(&q->read_wait);
+	return err;
+}
+
+static ssize_t eventdev_read(struct file * file, char __user * buf, size_t len,
+			 loff_t * off)
+{
+	struct eventdev_queue * q = file->private_data;
+	struct eventdev_msg * m;
+	int err;
+
+	BUG_ON(!q);
+
+	if (file->f_flags & O_NONBLOCK) {
+		m = eventdev_dequeue_one(q);
+		if (!m)
+			return -EAGAIN;
+	} else {
+		err = wait_event_interruptible (q->read_wait,
+						(m = eventdev_dequeue_one(q)));
+		if (err == -ERESTARTSYS)
+			return -EINTR;
+		BUG_ON(err);
+	}
+
+	BUG_ON(!m);
+	/*
+	 * eventdev_copy_one will requeue the message onto the
+	 * q->messsages queue on errors.
+	 */
+	err = eventdev_copy_one(q, m, buf, len);
+	if (err < 0)
+		return err;
+	/*
+	 * Message successfully copied: Put it onto the list of
+	 * messages that are waiting for a reply if necessary.
+	 */
+	if (m->msg_reply) {
+		BUG_ON(m->msg_reply >= 0);
+		spin_lock_bh(&q->lock);
+		list_add_tail(&m->link, &q->waiting);
+		spin_unlock_bh(&q->lock);
+	} else {
+		free_eventdev_msg(m);
+	}
+	return err;
+}
+
+static int flush_condition(struct eventdev_queue * q)
+{
+	struct eventdev_msg * m;
+	int ret = 1;
+
+	spin_lock_bh(&q->lock);
+	if (q->waiters) {
+		ret = 0;
+		list_for_each_entry(m, &q->waiting, link) {
+			if (m->msg_reply < 0) {
+				m->msg_reply = EIO;
+				wake_up(&m->wait);
+			}
+		}
+		list_for_each_entry(m, &q->messages, link) {
+			if (m->msg_reply < 0) {
+				m->msg_reply = EIO;
+				wake_up(&m->wait);
+			}
+		}
+	}
+	spin_unlock_bh(&q->lock);
+	return ret;
+}
+
+static void flush_queue(struct eventdev_queue * q)
+{
+	wait_event(die_wait, flush_condition(q));
+}
+
+void __eventdev_get_queue(struct eventdev_queue * q)
+{
+	BUG_ON(atomic_read(&q->users) <= 0);
+	atomic_inc(&q->users);
+}
+
+/*
+ * This function returns our module iff the queue was freed. The caller
+ * must drop a reference to the module if the return value is not NULL.
+ *
+ * As eventdev_put_queue can be called from an rcu callback handler
+ * it must not block. This assumption is true even for the call to flush_queue
+ * as long as there are no buggy callers that do not hold a reference to the
+ * queue while sleeping on the queue.
+ */
+struct module * __eventdev_put_queue(struct eventdev_queue * q)
+{
+	struct eventdev_msg * m;
+
+	BUG_ON(atomic_read(&q->users) <= 0);
+	if (!atomic_dec_and_test(&q->users))
+		return NULL;
+
+	BUG_ON(q->file != NULL);
+	/*
+	 * NOTE: This can only happen with buggy callers of __eventdev_enqueue.
+	 * NOTE: See comment there. We try to fix up the mess.
+	 */
+	WARN_ON(!list_empty(&q->waiting));
+	flush_queue(q);
+	while(!list_empty(&q->messages)) {
+		m = list_entry(q->messages.next, struct eventdev_msg, link);
+		list_del(&m->link);
+		free_eventdev_msg(m);
+	}
+	kfree(q);
+	return THIS_MODULE;
+}
+
+static ssize_t eventdev_write(struct file * file, const char __user * buf,
+			  size_t len, loff_t * off)
+{
+	struct eventdev_reply rep;
+	struct eventdev_queue * q;
+	struct eventdev_msg * m;
+	int ret = 0;
+	int err = 0;
+
+	q = file->private_data;
+	if (!q)
+		return -EBADF;
+	while (len >= sizeof(rep)) {
+		err = -EFAULT;
+		if (copy_from_user(&rep, buf, sizeof(struct eventdev_reply)))
+			break;
+		buf += sizeof(struct eventdev_reply);
+		len -= sizeof(struct eventdev_reply);
+		err = -ESRCH;
+		spin_lock_bh(&q->lock);
+		list_for_each_entry(m, &q->waiting, link) {
+			if (m->hdr.msg_token == rep.msg_token) {
+				if (rep.reply >= 0) {
+					m->msg_reply = rep.reply;
+				} else {
+					m->msg_reply = EIO;
+				}
+				wake_up(&m->wait);
+				err = 0;
+				break;
+			}
+		}
+		spin_unlock_bh(&q->lock);
+		if (err)
+			break;
+		ret += sizeof(rep);
+	}
+	if (ret)
+		return ret;
+	if (err)
+		return err;
+	return -EINVAL;
+}
+
+static unsigned int
+eventdev_poll(struct file * file, struct poll_table_struct * wait)
+{
+	unsigned int ret = POLLOUT | POLLWRNORM;
+	struct eventdev_queue * q = file->private_data;
+	poll_wait(file, &q->read_wait, wait);
+	if (!list_empty(&q->messages))
+		ret |= (POLLIN | POLLRDNORM);
+	return ret;
+}
+
+static int eventdev_release(struct inode * inodde, struct file * file)
+{
+	struct eventdev_queue * q = file->private_data;
+
+	BUG_ON(!q);
+
+	spin_lock_bh(&q->lock);
+	q->file = NULL;
+	file->private_data = NULL;
+	spin_unlock_bh(&q->lock);
+	flush_queue(q);
+
+	/*
+	 * eventdev_put_queue might drop a reference to this module. This
+	 * is ok because this cannot be the last refernce as the file
+	 * structure holds a reference of its own. The following BUG_ON
+	 * checks this.
+	 */
+	BUG_ON(THIS_MODULE && module_refcount(THIS_MODULE) < 2);
+	eventdev_put_queue(q);
+	return 0;
+}
+
+static int eventdev_open(struct inode * inode, struct file * file)
+{
+	struct eventdev_queue * q = kmalloc(sizeof(*q), GFP_KERNEL);
+	if (!q)
+		return -ENOMEM;
+	spin_lock_init(&q->lock);
+	INIT_LIST_HEAD(&q->messages);
+	INIT_LIST_HEAD(&q->waiting);
+	init_waitqueue_head(&q->read_wait);
+	q->file = file;
+	__module_get(THIS_MODULE);
+	atomic_set(&q->users, 1);
+	q->waiters = 0;
+	file->private_data = q;
+	return 0;
+}
+
+static struct file_operations eventdev_fops = {
+	.owner		= THIS_MODULE,
+	.open		= eventdev_open,
+	.release	= eventdev_release,
+	.read		= eventdev_read,
+	.write		= eventdev_write,
+	.poll		= eventdev_poll,
+};
+
+struct eventdev_queue * eventdev_get_queue(struct file * file)
+{
+	struct eventdev_queue * q;
+	if (file->f_op != &eventdev_fops)
+		return NULL;
+	q = file->private_data;
+	__eventdev_get_queue(q);
+	return q;
+}
+
+static struct miscdevice eventdev_device = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= EVENTDEV_NAME,
+	.fops	= &eventdev_fops,
+};
+
+static int __init eventdev_init(void)
+{
+	init_waitqueue_head(&die_wait);
+	if (misc_register(&eventdev_device) < 0) {
+		printk(KERN_ERR "eventdev: Cannot register device\n");
+		return -EIO;
+	}
+	printk(KERN_INFO "eventdev: Device registered\n");
+	return 0;
+}
+
+static void __exit eventdev_exit(void)
+{
+	if (misc_deregister(&eventdev_device) < 0) {
+		printk(KERN_ERR "eventdev: Cannot unregister device\n");
+		return;
+	}
+	printk(KERN_INFO "eventdev: Device unregistered\n");
+}
+
+EXPORT_SYMBOL(eventdev_get_queue);
+EXPORT_SYMBOL(__eventdev_get_queue);
+EXPORT_SYMBOL(__eventdev_put_queue);
+EXPORT_SYMBOL(eventdev_enqueue_wait);
+EXPORT_SYMBOL(eventdev_enqueue_nowait);
+
+module_init(eventdev_init);
+module_exit(eventdev_exit);
+
+MODULE_AUTHOR("Christian Ehrhardt <ehrhardt@genua.de>");
+MODULE_DESCRIPTION("Device Driver for kernel event device");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/fs/dcache.c b/fs/dcache.c
index a100fa3..443f269 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1926,7 +1926,9 @@ char *__d_path(const struct path *path, struct path *root,
 
 		if (dentry == root->dentry && vfsmnt == root->mnt)
 			break;
-		if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
+		if ((vfsmnt && dentry == vfsmnt->mnt_root) || IS_ROOT(dentry)) {
+			if (!vfsmnt)
+				break;
 			/* Global root? */
 			if (vfsmnt->mnt_parent == vfsmnt) {
 				goto global_root;
@@ -2336,6 +2338,7 @@ EXPORT_SYMBOL(d_lookup);
 EXPORT_SYMBOL(d_move);
 EXPORT_SYMBOL_GPL(d_materialise_unique);
 EXPORT_SYMBOL(d_path);
+EXPORT_SYMBOL_GPL(__d_path);
 EXPORT_SYMBOL(d_prune_aliases);
 EXPORT_SYMBOL(d_rehash);
 EXPORT_SYMBOL(d_splice_alias);
diff --git a/fs/namei.c b/fs/namei.c
index d11f404..6d5316f 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -33,8 +33,11 @@
 #include <linux/fcntl.h>
 #include <linux/device_cgroup.h>
 #include <linux/fs_struct.h>
+#include <linux/anoubis.h>
+#include <linux/anoubis_playground.h>
 #include <asm/uaccess.h>
 
+
 #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
 
 /* [Feb-1997 T. Schoebel-Theuer]
@@ -285,7 +288,7 @@ int inode_permission(struct inode *inode, int mask)
 		return retval;
 
 	return security_inode_permission(inode,
-			mask & (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND));
+		mask & (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND|MAY_ACCESS));
 }
 
 /**
@@ -788,12 +791,100 @@ static __always_inline void follow_dotdot(struct nameidata *nd)
 	follow_mount(&nd->path);
 }
 
+#ifdef CONFIG_SECURITY_ANOUBIS_PLAYGROUND
+
+/**
+ * Create a playground mangled name from the name in @orig. The playground-ID
+ * to use is in @pgid.
+ *
+ * @pgname: The new name is stored in this qstr. The memory in the
+ *     name-field must be freed by the caller.
+ * @orig: The original name. At least @orig->len+@extra bytes in @orig->name
+ *     must bue accessible as some users of qstrs assume that they can
+ *     access the first byte after the actual name.
+ * @whiteout: If true, a whiteout name is created, otherwise a normal
+ *     name is created.
+ * @pgid: The playground-ID.
+ * @extra: Copy this many bytes after the actual name into the new name.
+ *     Additionally, the name is always terminated by a zero byte. Most
+ *     callers want to pass 1 here.
+ * @return Zero in case of success, a negative error code in case of
+ *     errors.
+ */
+static int __pg_create_qstr(struct qstr *pgname, const struct qstr *orig,
+				int whiteout, anoubis_cookie_t pgid, int extra)
+{
+	char pgidstr[40];
+	char *namebuf;
+	int prefixlen;
+
+	BUG_ON(sizeof(pgid) < sizeof(unsigned long long));
+	BUG_ON(sizeof(unsigned long long) > 8);
+	BUG_ON(pgid == 0);
+	if (whiteout)
+		snprintf(pgidstr, sizeof(pgidstr), ".plgrD%llx.",
+						(unsigned long long)pgid);
+	else
+		snprintf(pgidstr, sizeof(pgidstr), ".plgr.%llx.",
+						(unsigned long long)pgid);
+	prefixlen = strlen(pgidstr);
+	pgname->len = orig->len + prefixlen;
+	namebuf = kmalloc(pgname->len+extra+1, GFP_ATOMIC);
+	if (namebuf == NULL)
+		return -ENOMEM;
+	memcpy(namebuf, pgidstr, prefixlen);
+	memcpy(namebuf + prefixlen, orig->name, orig->len+extra);
+	namebuf[pgname->len+extra] = 0;
+	pgname->name = namebuf;
+	pgname->hash = full_name_hash(pgname->name, pgname->len);
+	return 0;
+}
+
+/**
+ * Call __pg_create_qstr with the whiteout parameter set to false.
+ */
+static inline int pg_create_qstr(struct qstr *pgname, const struct qstr *orig,
+					anoubis_cookie_t pgid, int extra)
+{
+	return __pg_create_qstr(pgname, orig, 0, pgid, extra);
+}
+
+/**
+ * Call __pg_create_qstr with the whiteout parameter set to true.
+ */
+static inline int pg_create_whiteout_qstr(struct qstr *pgname,
+		const struct qstr *orig, anoubis_cookie_t pgid, int extra)
+{
+	return __pg_create_qstr(pgname, orig, 1, pgid, extra);
+}
+
+/**
+ * Call the directory specific hash function for file names (if any)
+ * and assign the resulting value to the hash field of the qstr.
+ *
+ * @param dir The directory.
+ * @param name The file name to hash.
+ * @return Zero in case of success, a negative error code in case of an
+ *     error.
+ */
+static inline int pg_hash_qstr(struct dentry *dir, struct qstr *name)
+{
+	int err;
+
+	if (dir->d_op == NULL || dir->d_op->d_hash == NULL)
+		return 0;
+	err = dir->d_op->d_hash(dir, name);
+	return err;
+}
+
+#endif
+
 /*
  *  It's more convoluted than I'd like it to be, but... it's still fairly
  *  small and for now I'd prefer to have fast path as straight as possible.
  *  It _is_ time-critical.
  */
-static int do_lookup(struct nameidata *nd, struct qstr *name,
+static int do_lookup_pg(struct nameidata *nd, struct qstr *name,
 		     struct path *path)
 {
 	struct vfsmount *mnt = nd->path.mnt;
@@ -827,6 +918,195 @@ fail:
 	return PTR_ERR(dentry);
 }
 
+#ifdef CONFIG_SECURITY_ANOUBIS_PLAYGROUND
+
+/**
+ * Mark the file given as dst as a file that must be filled from the inode
+ * referenced by srcdentry and srcmnt before it can be accessed.
+ * This function emulates an open on the file in srcdentry and attaches
+ * new file handle to the file dst. This function takes all required
+ * references on the parameters, it does not consume any references held
+ * by the caller.
+ *
+ * @param dst The destrination file.
+ * @param srcmnt The vfsmount of the source file.
+ * @param srcdentry The dentry of the source file.
+ * @return Zero in case of success, a negative error code in case of an
+ *     error.
+ *
+ * NOTE: The calle to anoubis_playground_set_lowerfile will try to
+ * NOTE: call deny_write_access on the lower file. I.e. this function
+ * NOTE: fails with -EBUSY if the lower file is alreday open for writing.
+ */
+static int anoubis_pg_needcopy(struct file *dst, struct vfsmount *srcmnt,
+			       struct dentry *srcdentry)
+{
+	struct path path = { srcmnt, srcdentry };
+	struct file *srcfile;
+	const struct cred *cred = current_cred();
+
+	int err = may_open(&path, MAY_READ, FMODE_READ);
+	if (err)
+		return err;
+	/* dentry_open will either release or consume these references! */
+	mntget(srcmnt);
+	dget(srcdentry);
+	srcfile = dentry_open(srcdentry, srcmnt, O_RDONLY, cred);
+	if (IS_ERR(srcfile))
+		return PTR_ERR(srcfile);
+	err = anoubis_playground_set_lowerfile(dst, srcfile);
+	if (err < 0) {
+		fput(srcfile);
+		return err;
+	}
+	return 0;
+}
+
+/**
+ * Return true if the name in the qstr is either "." or "..".
+ *
+ * @param name The string to test.
+ * @return False if the name is a normal directory entry, true if the name
+ *     is either "." or "..".
+ */
+static inline int isdot(struct qstr *name)
+{
+	if (name->name[0] == '.') {
+		switch(name->len) {
+		case 1:
+			return 1;
+		case 2:
+			return (name->name[1] == '.');
+		}
+	}
+	return 0;
+}
+
+static int do_lookup(struct nameidata *nd, struct qstr *name,
+		     struct path *pathp)
+{
+	anoubis_cookie_t pgid = anoubis_get_playgroundid();
+	struct path pgpath, origpath;
+	struct qstr pgname;
+	struct inode *inode;
+	int err;
+
+	if (pgid == 0 || isdot(name) ||
+				!anoubis_playground_enabled(nd->path.dentry))
+		return do_lookup_pg(nd, name, pathp);
+	err = pg_create_qstr(&pgname, name, pgid, 1);
+	if (err < 0)
+		return err;
+	err = pg_hash_qstr(nd->path.dentry, &pgname);
+	if (err < 0) {
+		kfree(pgname.name);
+		return err;
+	}
+	err = do_lookup_pg(nd, &pgname, &pgpath);
+	kfree(pgname.name);
+	if (err < 0)
+		return err;
+	/* Positive dentry: Just return. */
+	if (pgpath.dentry->d_inode) {
+		(*pathp) = pgpath;
+		return 0;
+	}
+	path_put_conditional(&pgpath, nd);
+
+	/* Check for whiteouts. */
+	err = pg_create_whiteout_qstr(&pgname, name, pgid, 1);
+	if (err < 0)
+		return err;
+	err = pg_hash_qstr(nd->path.dentry, &pgname);
+	if (err < 0) {
+		kfree(pgname.name);
+		return err;
+	}
+	err = do_lookup_pg(nd, &pgname, &pgpath);
+	kfree(pgname.name);
+	if (err < 0)
+		return err;
+	if (pgpath.dentry->d_inode != NULL)
+		err = -ENOENT;
+	path_put_conditional(&pgpath, nd);
+	if (err)
+		return err;
+
+	/*
+	 * Search for the original file.
+	 */
+	err = do_lookup_pg(nd, name, &origpath);
+	if (err < 0)
+		return err;
+
+	/* If this is not the last component, return now. */
+	if (nd->flags & (LOOKUP_PARENT | LOOKUP_CONTINUE))
+		goto out;
+
+	/* If the object does not exist, we are done. Use production. */
+	inode = origpath.dentry->d_inode;
+	if (inode == NULL)
+		goto out;
+
+	/*
+	 * At this point we know that:
+	 * - Both lookups were done without error.
+	 * - The playground lookup returned a negative dentry.
+	 * We can either:
+	 * - Return the special error code -EPGCLONEREG that will cause
+	 *   the caller to copy the file into the playground or
+	 * - Return the original dentry.
+	 * All creates should be done via lookup_hash not this path.
+	 */
+	BUG_ON(nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET));
+	if (nd->flags & LOOKUP_OPEN) {
+		int is_write = (nd->intent.open.flags &
+					(FMODE_WRITE | O_TRUNC));
+
+		/* Use original file for non-write accesses. */
+		if (!is_write)
+			goto out;
+		/* Use original file for writes to non-regular files. */
+		if (!S_ISREG(inode->i_mode))
+			goto out;
+		err = -EPGCLONEREG;
+		goto copy;
+	}
+	/*
+	 * The playground file does not yet exist, this is the last
+	 * component of the path and the file is the source of a
+	 * hardlink or rename: Tell the caller that the file must be
+	 * copied before we can continue.
+	 */
+	if (nd->flags & LOOKUP_PLAYGROUND_CREATE) {
+		if (S_ISREG(inode->i_mode)) {
+			err = -EPGCLONEREG;
+			goto copy;
+		}
+		if (S_ISLNK(inode->i_mode)) {
+			err = -EPGCLONESYMLINK;
+			goto copy;
+		}
+	}
+out:
+	(*pathp) = origpath;
+	return 0;
+copy:
+	BUG_ON(!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode));
+	path_put_conditional(&origpath, nd);
+	return err;
+}
+
+#else
+
+static inline int do_lookup(struct nameidata *nd, struct qstr *name,
+		     struct path *path)
+{
+	return do_lookup_pg(nd, name, path);
+}
+
+#endif
+
 /*
  * Name resolution.
  * This is the basic name resolution function, turning a pathname into
@@ -1219,16 +1499,332 @@ out:
  * needs parent already locked. Doesn't follow mounts.
  * SMP-safe.
  */
-static struct dentry *lookup_hash(struct nameidata *nd)
+static struct dentry *lookup_hash_pg(struct nameidata *nd, struct qstr *last)
 {
 	int err;
 
 	err = inode_permission(nd->path.dentry->d_inode, MAY_EXEC);
 	if (err)
 		return ERR_PTR(err);
-	return __lookup_hash(&nd->last, nd->path.dentry, nd);
+	return __lookup_hash(last, nd->path.dentry, nd);
+}
+
+#ifdef CONFIG_SECURITY_ANOUBIS_PLAYGROUND
+
+/**
+ * Create a whiteout marker file. This is always a regular file with
+ * zero permissions. Must be called with the inode mutex of the directory
+ * already held.
+ *
+ * @param nd The nameidata of the directory.
+ * @param origname The original (non-playground name to whiteout.
+ * @return Zero if the whiteout was created and did not exist before. 
+ *     -EEXIST if the whiteout already exists and another error code
+ *     if something else went wrong.
+ *
+ * NOTE: The tail of this function is a simplified version of mknodat.
+ * NOTE: Changes in mknodat must be done in this function, too.
+ */
+static int anoubis_pg_create_whiteout(struct nameidata *nd,
+					struct qstr *origname)
+{
+	struct qstr pgname;
+	struct dentry *white;
+	int err;
+	anoubis_cookie_t pgid = anoubis_get_playgroundid();
+
+	BUG_ON(nd->flags & LOOKUP_OPEN);
+	BUG_ON(pgid == 0);
+	err = pg_create_whiteout_qstr(&pgname, origname, pgid, 0);
+	if (err < 0)
+		return err;
+	err = pg_hash_qstr(nd->path.dentry, &pgname);
+	if (err < 0)
+		return err; 
+	white = lookup_hash_pg(nd, &pgname);
+	kfree(pgname.name);
+	if (IS_ERR(white))
+		return PTR_ERR(white);
+	if (white->d_inode) {
+		dput(white);
+		return -EEXIST;
+	}
+	err = mnt_want_write(nd->path.mnt);
+	if (err)
+		goto out_dput;
+	err = security_path_mknod(&nd->path, white, S_IFREG, 0 /* dev */);
+	if (err == 0)
+		err = vfs_create(nd->path.dentry->d_inode, white, S_IFREG, nd);
+	mnt_drop_write(nd->path.mnt);
+out_dput:
+	dput(white);
+	return err;
+}
+
+/**
+ * Check if we can ignore an O_EXCL flag in lookup_create.
+ * We can ignore the flag if the target of the lookup will not be
+ * created anyway because it is a symlink the will be followed.
+ * Additionally, an O_EXCL flag can be ignored if it was given by
+ * user without O_CREAT and the O_CREAT flag was only added by the
+ * playground copy trigger (LOOKUP_PLAYGROUND_CREATE).
+ * This function only applies to the case where the file does not yet
+ * exist in the playground. An exiting file in the playground has handled
+ * by the normal O_EXCL code in the open path.
+ *
+ * @param dentry The dentry of the original file.
+ * @param flags The lookup flags from the nameidata structure.
+ * @return True if the O_EXCL flag can ignored without an error.
+ */
+static inline int pg_ignore_excl(struct dentry *dentry, unsigned long flags)
+{
+	struct inode *inode = dentry->d_inode;
+
+	if (inode == NULL)
+		return 1;
+	if (flags & LOOKUP_PLAYGROUND_CREATE)
+		return 1;
+	if (S_ISLNK(inode->i_mode) && (flags & LOOKUP_FOLLOW))
+		return 1;
+	return 0;
+}
+
+static struct dentry *lookup_hash(struct nameidata *nd)
+{
+	anoubis_cookie_t pgid = anoubis_get_playgroundid();
+	struct qstr pgname;
+	int err, is_create;
+	struct dentry *pgdentry, *origdentry, *whiteout;
+	int unlink = (nd->flags & LOOKUP_PLAYGROUND_UNLINK);
+	struct inode *originode;
+
+	if (pgid == 0 || isdot(&nd->last) ||
+				!anoubis_playground_enabled(nd->path.dentry))
+		return lookup_hash_pg(nd, &nd->last);
+
+	err = pg_create_qstr(&pgname, &nd->last, pgid, 1);
+	if (err < 0)
+		return ERR_PTR(err);
+	pgdentry = lookup_hash_pg(nd, &pgname);
+	kfree(pgname.name);
+	/*
+	 * Error or positive dentry? Just return it. However, if this is
+	 * going to be an unlink, make sure that the original file does not
+	 * exist of is hidden by a whiteout.
+	 * NOTE: Consider the following case:
+	 * - The playground creates a new directory foo/ and a file bar
+	 *   within foo: This creates
+	 *     .plgr.xxx.foo/   and
+	 *     .plgr.xxx.foo/.plgr.xxx.bar
+	 * - The playground then removes foo/bar: If .plgr.xxx.foo/bar does
+	 *   not exist we must remove .plgr.xxx.foo/.plgr.xxx.bar without
+	 *   creating a whiteout. This is important, if the playground
+	 *   tries then tries to remove the directory foo. This is only
+	 *   possible if .plgr.xxx.foo/ is an empty direcotry, i.e. it
+	 *   must not contain whiteouts.
+	 */
+	if (IS_ERR(pgdentry))
+		return pgdentry;
+	if (pgdentry->d_inode) {
+		if (!unlink)
+			return pgdentry;
+		origdentry = lookup_hash_pg(nd, &nd->last);
+		if (IS_ERR(origdentry))
+			goto use_orig;
+		if (origdentry->d_inode != NULL) {
+			err = anoubis_pg_create_whiteout(nd, &nd->last);
+			if (err < 0 && err != -EEXIST)
+				goto error;
+		}
+		goto use_pg;
+	}
+
+	/* lookup_hash cannot be used for parent lookup. */
+	BUG_ON(nd->flags & (LOOKUP_PARENT | LOOKUP_CONTINUE));
+	origdentry = lookup_hash_pg(nd, &nd->last);
+	/*
+	 * Allow removal of sockets from within a playground but delay
+	 * other error handling until after the whiteout check.
+	 */
+	if (!IS_ERR(origdentry) && origdentry->d_inode &&
+				S_ISSOCK(origdentry->d_inode->i_mode))
+		goto use_orig;
+
+	/*
+	 * The playground dentry is negative, check for whiteouts and
+	 * return the negative playground dentry if a whiteout is present.
+	 * We must never touch the original dentry if a whiteout exists.
+	 */
+	err = pg_create_whiteout_qstr(&pgname, &nd->last, pgid, 1);
+	if (err < 0)
+		return ERR_PTR(err);
+	whiteout = lookup_hash_pg(nd, &pgname);
+	kfree(pgname.name);
+	if (!IS_ERR(whiteout)) {
+		if (whiteout->d_inode) {
+			dput(whiteout);
+			if (!IS_ERR(origdentry))
+				dput(origdentry);
+			return pgdentry;
+		}
+		dput(whiteout);
+	}
+	/* Delayed error handling for origdentry. */
+	if (IS_ERR(origdentry))
+		goto use_orig;
+	originode = origdentry->d_inode;
+	is_create = (nd->flags & (LOOKUP_CREATE|LOOKUP_RENAME_TARGET));
+	if (is_create) {
+		/*
+		 * orig does not exist and we create => use playground
+		 * However, if the create flag is forced by the playgound
+		 * return an error instead.
+		 */
+		if (originode == NULL) {
+			err = -ENOENT;
+			if (nd->flags & LOOKUP_PLAYGROUND_CREATE)
+				goto error;
+			if (nd->flags & LOOKUP_PLAYGROUND_DIRRENAME)
+				goto use_orig;
+			if (nd->flags & LOOKUP_PLAYGROUND_SOCKET)
+				goto use_orig;
+			goto use_pg;
+		}
+		/*
+		 * This process is creating an object in the playground
+		 * explicitly (e.g. via anoubis_playground_clone_symlink.
+		 * Use playground file to allow create.
+		 */
+		if (anoubis_playground_get_pgcreate())
+			goto use_pg;
+		/*
+		 * Orig exists and O_EXCL lookup => EEXIST. However, there
+		 * are some cases where this error must be suppressed.
+		 */
+		err = -EEXIST;
+		if ((nd->flags & LOOKUP_EXCL) &&
+					!pg_ignore_excl(origdentry, nd->flags))
+			goto error;
+		/*
+		 * Directory rename. Return original dentry and let
+		 * inode_rename handle fobidden cases.
+		 */
+		if (nd->flags & LOOKUP_PLAYGROUND_DIRRENAME)
+			goto use_orig;
+		/*
+		 * This is create without an open where the original file
+		 * exists. Most calllers want EEXIST in this case. However,
+		 * the target of a rename can in fact exist. In the renam
+		 */
+		if ((nd->flags & LOOKUP_OPEN) == 0) {
+			err = -EEXIST;
+			if ((nd->flags & LOOKUP_RENAME_TARGET) == 0)
+				goto error;
+			err = 0;
+			if (!S_ISDIR(originode->i_mode))
+				goto use_pg;
+			/*
+			 * XXX CEH: In theory a rename is possible, if the
+			 * XXX CEH: target directory is empty and both the
+			 * XXX CEH: src and the target of the rename are
+			 * XXX CEH: directories. For now, give EEXIST, too.
+			 */
+			err = -EEXIST;
+			goto error;
+		}
+		/* Fall through to the open case. */
+	}
+	if (nd->flags & LOOKUP_OPEN) {
+		int is_write = (nd->intent.open.flags &
+					(FMODE_WRITE | O_TRUNC));
+		/* Use original file for non-write accesses. */
+		if (!is_write)
+			goto use_orig;
+		/* Use original file for writes to non-regular files. */
+		if (originode && !S_ISREG(originode->i_mode))
+			goto use_orig;
+		BUG_ON(!is_create);
+		if (nd->flags & LOOKUP_PLAYGROUND_CREATE) {
+			mode_t mode = originode->i_mode & S_IRWXU;
+			nd->intent.open.create_mode = mode;
+		}
+		/* No need to copy data if file is being truncated. */
+		if (nd->intent.open.flags & O_TRUNC)
+			goto use_pg;
+		err = anoubis_pg_needcopy(nd->intent.open.file,
+						nd->path.mnt, origdentry);
+		if (err)
+			goto error;
+		goto use_pg;
+	}
+
+	/*
+	 * Use the negative dentry if the file does not exist at all.
+	 * Cases where we might create the non-existing file have been
+	 * handled above, i.e.  we can safely use the original dentry.
+	 */
+	if (originode == NULL)
+		goto use_orig;
+	/*
+	 * LOOKUP_PLAYGROUND_CREATE without LOOKUP_OPEN, i.e. this is the
+	 * source of a rename or hardlink. Return EPGCLONE* where supported
+	 * if the playground file does not exist.
+	 */
+	err = -EACCES;
+	if (nd->flags & LOOKUP_PLAYGROUND_CREATE) {
+		if (S_ISREG(originode->i_mode))
+			err = -EPGCLONEREG;
+		if (S_ISLNK(originode->i_mode))
+			err = -EPGCLONESYMLINK;
+		/* Dirs are accessed in the production system. */
+		if (S_ISDIR(originode->i_mode)) {
+			nd->flags |= LOOKUP_PLAYGROUND_DIRRENAME;
+			goto use_orig;
+		}
+		goto error;
+	}
+	/*
+	 * Unlink where the playground file does not exist but the
+	 * original file does exist.
+	 */
+	if (unlink) {
+		/*
+		 * Do not allow removal of directories in the production
+		 * system for now. We must make sure that the directory is
+		 * empty before we can delete it.
+		 */
+		err = -EPGWHITEOUT;
+		if (S_ISDIR(originode->i_mode))
+			err = -EACCES;
+		goto error;
+	}
+use_orig:
+	dput(pgdentry);
+	return origdentry;
+use_pg:
+	dput(origdentry);
+	return pgdentry;
+error:
+	dput(pgdentry);
+	dput(origdentry);
+	return ERR_PTR(err);
 }
 
+#else
+
+static inline struct dentry *lookup_hash(struct nameidata *nd)
+{
+	return lookup_hash_pg(nd, &nd->last);
+}
+
+static int anoubis_pg_create_whiteout(struct nameidata *nd,
+					struct qstr *origname)
+{
+	return 0;
+}
+
+#endif
+
 static int __lookup_one_len(const char *name, struct qstr *this,
 		struct dentry *base, int len)
 {
@@ -1279,6 +1875,145 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
 	return __lookup_hash(&this, base, NULL);
 }
 
+#ifdef CONFIG_SECURITY_ANOUBIS_PLAYGROUND
+
+struct dentry *lookup_one_len_cached(const char *name, struct dentry *base,
+    int len)
+{
+	int err;
+	struct qstr this;
+
+	WARN_ON_ONCE(!mutex_is_locked(&base->d_inode->i_mutex));
+
+	err = __lookup_one_len(name, &this, base, len);
+	if (err)
+		return ERR_PTR(err);
+	err = inode_permission(base->d_inode, MAY_EXEC);
+	if (err)
+		return ERR_PTR(err);
+	if (base->d_op && base->d_op->d_hash) {
+		err = base->d_op->d_hash(base, &this);
+		if (err < 0)
+			return ERR_PTR(err);
+	}
+	return cached_lookup(base, &this, NULL);
+}
+
+static inline int anoubis_is_pg_file(const char *name, int len,
+    int *prefixlen, anoubis_cookie_t *cookie, int *whiteout)
+{
+	int off;
+
+	/*
+	 * At least
+	 * - 6 bytes for the ".plgr." prefix
+	 * - one for the playground id itself
+	 * - one for the final dot
+	 */
+	if (len < 8 || memcmp(name, ".plgr", 5) != 0)
+		return 0;
+	switch (name[5]) {
+	default:
+		return 0;
+	case 'D':
+		(*whiteout) = 1;
+		break;
+	case '.':
+		(*whiteout) = 0;
+		break;
+	}
+	for (off=6; off<len; ++off) {
+		if (name[off] == '.')
+			break;
+	}
+
+	/* Skip the dot. */
+	off++;
+
+	/*
+	 * If there is at least one byte after the final dot, extract
+	 * offset and playground id.
+	 */
+	if (off < len) {
+		char ch;
+		if (sscanf(name+6, "%llx%c", cookie, &ch) != 2 || ch != '.')
+			return 0;
+		(*prefixlen) = off;
+		return 1;
+	}
+	return 0;
+}
+
+int anoubis_pg_validate_name(const char *name, struct dentry *base, int len,
+					anoubis_cookie_t pgid, ino_t ino)
+{
+	struct qstr origname, pgname;
+	struct dentry *tmp;
+	int err, exists, off, whiteout;
+	anoubis_cookie_t file_cookie;
+
+	if (pgid == 0 || !anoubis_playground_enabled(base))
+		return 0;
+
+	origname.name = name;
+	origname.len = len;
+	if (isdot(&origname))
+		return 0;
+	if (anoubis_is_pg_file(name, len, &off, &file_cookie, &whiteout)) {
+		/*
+		 * This is a playground file. It is valid iff the
+		 * file's playground id matches the playground id of the
+		 * process.
+		 */
+		if (file_cookie != pgid || whiteout)
+			return -ENOENT;
+		return off;
+	}
+
+	/*
+	 * First check for a playground version of this entry. If one exists,
+	 * the playground version must be reported and this entry is skipped.
+	 * Additionally, if a whiteout exists for the file, the file is
+	 * skipped, too. This is the second iteration through the loop.
+	 */
+	for (whiteout = 0; whiteout < 2; ++whiteout) {
+		err = __pg_create_qstr(&pgname, &origname, whiteout, pgid, 0);
+		if (err < 0)
+			return -ENOMEM;
+		/*
+		 * Some filesystems deadlock if we try to do a lookup in
+		 * a directory while a readdir is still in progress.
+		 */
+		if (anoubis_playground_readdirok(base->d_inode)) {
+			tmp = lookup_one_len(pgname.name, base, pgname.len);
+		} else {
+			tmp = lookup_one_len_cached(pgname.name, base,
+			    pgname.len);
+		}
+		kfree(pgname.name);
+		if (tmp == NULL)
+			continue;
+		if (IS_ERR(tmp)) {
+			if (PTR_ERR(tmp) == -ENOENT)
+				continue;
+			return PTR_ERR(tmp);
+		}
+		/*
+		 * This is subtle: If the playground version of the file
+		 * is in fact the same inode as the one that we are about
+		 * to report, this is probably due to a recursive call to
+		 * this filter function that already filtered the name.
+		 */
+		exists = (tmp->d_inode != NULL && tmp->d_inode->i_ino != ino);
+		dput(tmp);
+		if (exists)
+			return -ENOENT;
+	}
+	return 0;
+}
+
+#endif
+
 /**
  * lookup_one_noperm - bad hack for sysfs
  * @name:	pathname component to lookup
@@ -1676,6 +2411,7 @@ struct file *do_filp_open(int dfd, const char *pathname,
 	struct dentry *dir;
 	int count = 0;
 	int will_write;
+	int pg_create = 0;
 	int flag = open_to_namei_flags(open_flag);
 
 	if (!acc_mode)
@@ -1696,9 +2432,15 @@ struct file *do_filp_open(int dfd, const char *pathname,
 	if (!(flag & O_CREAT)) {
 		error = path_lookup_open(dfd, pathname, lookup_flags(flag),
 					 &nd, flag);
-		if (error)
+		if (error && error != -EPGCLONEREG) {
+			BUG_ON(error == -EPGWHITEOUT);
+			BUG_ON(error == -EPGCLONESYMLINK);
 			return ERR_PTR(error);
-		goto ok;
+		}
+		if (error == 0)
+			goto ok;
+		pg_create = 1;
+		mode = 0;
 	}
 
 	/*
@@ -1735,11 +2477,15 @@ struct file *do_filp_open(int dfd, const char *pathname,
 	dir = nd.path.dentry;
 	nd.flags &= ~LOOKUP_PARENT;
 	nd.flags |= LOOKUP_CREATE | LOOKUP_OPEN;
+	if (pg_create)
+		nd.flags |= LOOKUP_PLAYGROUND_CREATE;
 	if (flag & O_EXCL)
 		nd.flags |= LOOKUP_EXCL;
 	mutex_lock(&dir->d_inode->i_mutex);
 	path.dentry = lookup_hash(&nd);
 	path.mnt = nd.path.mnt;
+	if (nd.flags & LOOKUP_PLAYGROUND_CREATE)
+		mode = nd.intent.open.create_mode;
 
 do_last:
 	error = PTR_ERR(path.dentry);
@@ -1788,7 +2534,7 @@ do_last:
 	audit_inode(pathname, path.dentry);
 
 	error = -EEXIST;
-	if (flag & O_EXCL)
+	if ((flag & O_EXCL) && !pg_create)
 		goto exit_dput;
 
 	if (__follow_mount(&path)) {
@@ -1906,6 +2652,8 @@ do_link:
 	mutex_lock(&dir->d_inode->i_mutex);
 	path.dentry = lookup_hash(&nd);
 	path.mnt = nd.path.mnt;
+	if (nd.flags & LOOKUP_PLAYGROUND_CREATE)
+		mode = nd.intent.open.create_mode;
 	__putname(nd.last.name);
 	goto do_last;
 }
@@ -2233,12 +2981,20 @@ static long do_rmdir(int dfd, const char __user *pathname)
 	}
 
 	nd.flags &= ~LOOKUP_PARENT;
+	nd.flags |= LOOKUP_PLAYGROUND_UNLINK;
 
 	mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
 	dentry = lookup_hash(&nd);
 	error = PTR_ERR(dentry);
-	if (IS_ERR(dentry))
+	if (IS_ERR(dentry)) {
+		BUG_ON(error == -EPGCLONEREG || error == -EPGCLONESYMLINK);
+		if (error != -EPGWHITEOUT)
+			goto exit2;
+		error = anoubis_pg_create_whiteout(&nd, &nd.last);
+		if (error == -EEXIST)
+			error = -ENOENT;
 		goto exit2;
+	}
 	error = mnt_want_write(nd.path.mnt);
 	if (error)
 		goto exit3;
@@ -2317,10 +3073,20 @@ static long do_unlinkat(int dfd, const char __user *pathname)
 		goto exit1;
 
 	nd.flags &= ~LOOKUP_PARENT;
+	nd.flags |= LOOKUP_PLAYGROUND_UNLINK;
 
 	mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
 	dentry = lookup_hash(&nd);
 	error = PTR_ERR(dentry);
+	BUG_ON(IS_ERR(dentry)
+	    && (error == -EPGCLONEREG || error == -EPGCLONESYMLINK));
+	if (IS_ERR(dentry) && error == -EPGWHITEOUT) {
+		error = anoubis_pg_create_whiteout(&nd, &nd.last);
+		if (error == -EEXIST)
+			error = -ENOENT;
+		mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
+		goto exit1;
+	}
 	if (!IS_ERR(dentry)) {
 		/* Why not before? Because we want correct error value */
 		if (nd.last.name[nd.last.len])
@@ -2492,16 +3258,35 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
 	struct nameidata nd;
 	struct path old_path;
 	int error;
+	unsigned int lookup_flags = LOOKUP_PLAYGROUND_CREATE;
 	char *to;
 
 	if ((flags & ~AT_SYMLINK_FOLLOW) != 0)
 		return -EINVAL;
 
-	error = user_path_at(olddfd, oldname,
-			     flags & AT_SYMLINK_FOLLOW ? LOOKUP_FOLLOW : 0,
-			     &old_path);
-	if (error)
-		return error;
+retry:
+	if (flags & AT_SYMLINK_FOLLOW)
+		lookup_flags |= LOOKUP_FOLLOW;
+	error = user_path_at(olddfd, oldname, lookup_flags, &old_path);
+	if (error) {
+		switch(error) {
+		default:
+			return error;
+		case -EPGCLONEREG:
+			error = anoubis_playground_clone_reg(olddfd, oldname);
+			if (error == 0)
+				goto retry;
+			return error;
+		case -EPGCLONESYMLINK:
+			error = anoubis_playground_clone_symlink(olddfd,
+								 oldname);
+			if (error == 0)
+				goto retry;
+			return error;
+		case -EPGWHITEOUT:
+			BUG();
+		}
+	}
 
 	error = user_path_parent(newdfd, newname, &nd, &to);
 	if (error)
@@ -2695,8 +3480,10 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
 	struct nameidata oldnd, newnd;
 	char *from;
 	char *to;
-	int error;
+	int error, do_retry;
 
+retry:
+	do_retry = 0;
 	error = user_path_parent(olddfd, oldname, &oldnd, &from);
 	if (error)
 		goto exit;
@@ -2719,6 +3506,7 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
 		goto exit2;
 
 	oldnd.flags &= ~LOOKUP_PARENT;
+	oldnd.flags |= LOOKUP_PLAYGROUND_CREATE | LOOKUP_PLAYGROUND_UNLINK;
 	newnd.flags &= ~LOOKUP_PARENT;
 	newnd.flags |= LOOKUP_RENAME_TARGET;
 
@@ -2726,8 +3514,38 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
 
 	old_dentry = lookup_hash(&oldnd);
 	error = PTR_ERR(old_dentry);
-	if (IS_ERR(old_dentry))
-		goto exit3;
+	if (IS_ERR(old_dentry)) {
+		/*
+		 * We do not create whiteouts at this point. They will be
+		 * be created by the next retry in lookup_hash because the
+		 * playground file will exist in the next retry. Apart from
+		 * that we cannot create the whiteout now, because:
+		 * - The directory is already unlocked, i.e. we must not
+		 *   call anoubis_pg_create_whiteout.
+		 * - anoubis_playground_clone_* is unreliable as it does a
+		 *   complete path traversal again and is thus prone to
+		 *   rename attacks of the user, i.e. we do not really know
+		 *   if the file that will be renamed, has a whiteout.
+		 */
+		switch(error) {
+		default:
+			goto exit3;
+		case -EPGWHITEOUT:
+			BUG();
+		case -EPGCLONEREG:
+			unlock_rename(new_dir, old_dir);
+			error = anoubis_playground_clone_reg(olddfd, oldname);
+			break;
+		case -EPGCLONESYMLINK:
+			unlock_rename(new_dir, old_dir);
+			error = anoubis_playground_clone_symlink(olddfd,
+								 oldname);
+			break;
+		}
+		if (error == 0)
+			do_retry = 1;
+		goto exit2;
+	}
 	/* source must exist */
 	error = -ENOENT;
 	if (!old_dentry->d_inode)
@@ -2739,6 +3557,8 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
 			goto exit4;
 		if (newnd.last.name[newnd.last.len])
 			goto exit4;
+	} else {
+		newnd.flags |= (oldnd.flags & LOOKUP_PLAYGROUND_DIRRENAME);
 	}
 	/* source should not be ancestor of target */
 	error = -EINVAL;
@@ -2762,6 +3582,7 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
 		goto exit6;
 	error = vfs_rename(old_dir->d_inode, old_dentry,
 				   new_dir->d_inode, new_dentry);
+	anoubis_playground_clear_accessok(old_dir->d_inode);
 exit6:
 	mnt_drop_write(oldnd.path.mnt);
 exit5:
@@ -2777,6 +3598,8 @@ exit1:
 	path_put(&oldnd.path);
 	putname(from);
 exit:
+	if (do_retry)
+		goto retry;
 	return error;
 }
 
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index faa0918..eecef1d 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -1419,6 +1419,8 @@ static void init_once(void *foo)
 	INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC);
 	nfsi->npages = 0;
 	atomic_set(&nfsi->silly_count, 1);
+	nfsi->silly_block_depth = 0;
+	nfsi->silly_blocker = NULL;
 	INIT_HLIST_HEAD(&nfsi->silly_list);
 	init_waitqueue_head(&nfsi->waitqueue);
 	nfs4_init_once(nfsi);
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c
index 1064c91..d216045 100644
--- a/fs/nfs/unlink.c
+++ b/fs/nfs/unlink.c
@@ -214,7 +214,13 @@ void nfs_block_sillyrename(struct dentry *dentry)
 {
 	struct nfs_inode *nfsi = NFS_I(dentry->d_inode);
 
+	if (nfsi->silly_blocker == current) {
+		nfsi->silly_block_depth++;
+		return;
+	}
 	wait_event(nfsi->waitqueue, atomic_cmpxchg(&nfsi->silly_count, 1, 0) == 1);
+	nfsi->silly_blocker = current;
+	nfsi->silly_block_depth++;
 }
 
 void nfs_unblock_sillyrename(struct dentry *dentry)
@@ -223,6 +229,11 @@ void nfs_unblock_sillyrename(struct dentry *dentry)
 	struct nfs_inode *nfsi = NFS_I(dir);
 	struct nfs_unlinkdata *data;
 
+	if (--nfsi->silly_block_depth) {
+		BUG_ON(current != nfsi->silly_blocker);
+		return;
+	}
+	nfsi->silly_blocker = NULL;
 	atomic_inc(&nfsi->silly_count);
 	spin_lock(&dir->i_lock);
 	while (!hlist_empty(&nfsi->silly_list)) {
diff --git a/fs/open.c b/fs/open.c
index 4f01e06..52c6640 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -831,10 +831,6 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
 	f->f_op = fops_get(inode->i_fop);
 	file_move(f, &inode->i_sb->s_files);
 
-	error = security_dentry_open(f, cred);
-	if (error)
-		goto cleanup_all;
-
 	if (!open && f->f_op)
 		open = f->f_op->open;
 	if (open) {
@@ -857,6 +853,12 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
 		}
 	}
 
+	error = security_dentry_open(f, cred);
+	if (error) {
+		fput(f);
+		f = ERR_PTR(-EPERM);
+	}
+
 	return f;
 
 cleanup_all:
diff --git a/fs/readdir.c b/fs/readdir.c
index 7723401..4a92371 100644
--- a/fs/readdir.c
+++ b/fs/readdir.c
@@ -19,6 +19,41 @@
 
 #include <asm/uaccess.h>
 
+#ifdef CONFIG_SECURITY_ANOUBIS_PLAYGROUND
+
+#include <linux/anoubis.h>
+#include <linux/anoubis_playground.h>
+
+struct playground_callback {
+	filldir_t	orig_filler;
+	void *		orig_buf;
+	struct file *	base;
+};
+
+/* NOTE: @name is not a string, it might not be terminated by a NUL byte. */
+static int pg_filler(void * __buf, const char * name, int namlen,
+			loff_t offset, u64 ino, unsigned int d_type)
+{
+	anoubis_cookie_t pgid = anoubis_get_playgroundid();
+	struct playground_callback *pgbuf = __buf;
+	int nameoff = 0;
+
+	if (pgid == 0)
+		goto done;
+	nameoff = anoubis_pg_validate_name(name, pgbuf->base->f_path.dentry,
+					   namlen, pgid, ino);
+	if (nameoff == -ENOENT)
+		return 0;
+	if (nameoff < 0)
+		return nameoff;
+
+done:
+	return pgbuf->orig_filler(pgbuf->orig_buf, name+nameoff,
+	    namlen-nameoff, offset, ino, d_type);
+}
+
+#endif
+
 int vfs_readdir(struct file *file, filldir_t filler, void *buf)
 {
 	struct inode *inode = file->f_path.dentry->d_inode;
@@ -36,7 +71,16 @@ int vfs_readdir(struct file *file, filldir_t filler, void *buf)
 
 	res = -ENOENT;
 	if (!IS_DEADDIR(inode)) {
+#ifdef CONFIG_SECURITY_ANOUBIS_PLAYGROUND
+		struct playground_callback pgbuf;
+
+		pgbuf.orig_filler = filler;
+		pgbuf.orig_buf = buf;
+		pgbuf.base = file;
+		res = file->f_op->readdir(file, &pgbuf, pg_filler);
+#else
 		res = file->f_op->readdir(file, buf, filler);
+#endif
 		file_accessed(file);
 	}
 	mutex_unlock(&inode->i_mutex);
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 1feed71..fccb134 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -174,6 +174,10 @@ ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/asm/a.out.h \
       		  $(srctree)/include/asm-$(SRCARCH)/a.out.h),)
 unifdef-y += a.out.h
 endif
+unifdef-y += anoubis.h
+unifdef-y += anoubis_alf.h
+unifdef-y += anoubis_sfs.h
+unifdef-y += anoubis_playground.h
 unifdef-y += apm_bios.h
 unifdef-y += atalk.h
 unifdef-y += atmdev.h
@@ -203,6 +207,7 @@ unifdef-y += elfcore.h
 unifdef-y += errno.h
 unifdef-y += errqueue.h
 unifdef-y += ethtool.h
+unifdef-y += eventdev.h
 unifdef-y += eventpoll.h
 unifdef-y += signalfd.h
 unifdef-y += ext2_fs.h
diff --git a/include/linux/anoubis.h b/include/linux/anoubis.h
new file mode 100644
index 0000000..457ae63
--- /dev/null
+++ b/include/linux/anoubis.h
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2008 GeNUA mbH <info@genua.de>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef ANOUBIS_H
+#define ANOUBIS_H
+
+#include <linux/eventdev.h>
+
+/*
+ * Changes between diffenrt versions:
+ * 0x00010005: Add playground messages.
+ * 0x00010006: Change pg_file messages for dir rename
+ */
+#define ANOUBISCORE_VERSION		0x00010006UL
+
+typedef u_int64_t anoubis_cookie_t;
+
+#define ANOUBIS_CS_LEN		32
+struct anoubis_ioctl_csum {
+	int fd;
+	u_int8_t csum[ANOUBIS_CS_LEN];
+};
+
+struct anoubis_ioctl_lastpgid {
+	anoubis_cookie_t lastpgid;
+	int fd;
+};
+
+#define	ANOUBIS_TYPE			'a'
+#define ANOUBIS_DECLARE_FD		_IO(ANOUBIS_TYPE,0x10)
+#define ANOUBIS_DECLARE_LISTENER	_IO(ANOUBIS_TYPE,0x11)
+#define ANOUBIS_REQUEST_STATS		_IO(ANOUBIS_TYPE,0x12)
+#define ANOUBIS_UNDECLARE_FD		_IO(ANOUBIS_TYPE,0x13)
+/* Old REPLACE POLICY ioctl. Do not reuse */
+#define ANOUBIS_OLD_REPLACE_POLICY	_IO(ANOUBIS_TYPE,0x14)
+#define ANOUBIS_GETVERSION		_IOR(ANOUBIS_TYPE,0x15, unsigned long)
+#define ANOUBIS_GETCSUM			_IOWR(ANOUBIS_TYPE,0x16, \
+					    struct anoubis_ioctl_csum)
+#define ANOUBIS_CREATE_PLAYGROUND	_IO(ANOUBIS_TYPE,0x17)
+#define ANOUBIS_SET_LASTPGID		_IOW(ANOUBIS_TYPE,0x18, \
+					    struct anoubis_ioctl_lastpgid)
+#define ANOUBIS_SCAN_STARTED		_IO(ANOUBIS_TYPE, 0x19)
+#define ANOUBIS_SCAN_SUCCESS		_IO(ANOUBIS_TYPE, 0x1a)
+
+#define ANOUBIS_SOURCE_TEST		0
+#define ANOUBIS_SOURCE_ALF		10
+#define ANOUBIS_SOURCE_SANDBOX		20
+#define ANOUBIS_SOURCE_SFS		30
+#define ANOUBIS_SOURCE_SFSEXEC		31
+#define ANOUBIS_SOURCE_SFSPATH		32
+#define ANOUBIS_SOURCE_PROCESS		40
+#define ANOUBIS_SOURCE_STAT		50
+#define ANOUBIS_SOURCE_IPC		60
+#define ANOUBIS_SOURCE_PLAYGROUND	70
+#define ANOUBIS_SOURCE_PLAYGROUNDPROC	71
+#define ANOUBIS_SOURCE_PLAYGROUNDFILE	72
+
+struct anoubis_event_common {
+	anoubis_cookie_t task_cookie;
+	anoubis_cookie_t pgid;
+};
+
+/* flags returned via anoubis_raise */
+#define ANOUBIS_RET_CLEAN(x)		(x & 0xffff)
+#define ANOUBIS_RET_FLAGS(x)		(x & ~0xffff)
+#define ANOUBIS_RET_OPEN_LOCKWATCH	(1<<16)
+#define ANOUBIS_RET_NEED_SECUREEXEC	(1<<17)
+#define ANOUBIS_RET_NEED_PLAYGROUND	(1<<18)
+
+#define ANOUBIS_PROCESS_OP_FORK		0x0001UL
+#define ANOUBIS_PROCESS_OP_EXIT		0x0002UL
+#define ANOUBIS_PROCESS_OP_REPLACE	0x0003UL
+#define ANOUBIS_PROCESS_OP_CREATE	0x0004UL
+#define ANOUBIS_PROCESS_OP_DESTROY	0x0005UL
+
+struct ac_process_message {
+	struct anoubis_event_common common;
+	anoubis_cookie_t task_cookie;
+	unsigned long op;
+};
+
+#define ANOUBIS_SOCKET_OP_CONNECT 0x0001UL
+#define ANOUBIS_SOCKET_OP_DESTROY 0x0002UL
+
+struct ac_ipc_message {
+	struct anoubis_event_common common;
+	u_int32_t		op;
+	anoubis_cookie_t	source;
+	anoubis_cookie_t	dest;
+	anoubis_cookie_t	conn_cookie;
+};
+
+struct anoubis_stat_value {
+	u_int32_t subsystem;
+	u_int32_t key;
+	u_int64_t value;
+};
+
+struct anoubis_stat_message {
+	struct anoubis_event_common common;
+	struct anoubis_stat_value vals[0];
+};
+
+#ifdef __KERNEL__
+
+#include <linux/security.h>
+
+struct anoubis_internal_stat_value {
+	u_int32_t subsystem;
+	u_int32_t key;
+	u_int64_t * valuep;
+};
+
+struct anoubis_task_label {
+	anoubis_cookie_t task_cookie;
+	int listener; /* Only accessed by the task itself. */
+};
+
+/*
+ * Wrappers around eventdev_enqueue. Removes the queue if it turns out
+ * to be dead.
+ */
+extern int anoubis_raise(void * buf, size_t len, int src);
+extern int anoubis_raise_flags(void * buf, size_t len, int src, int *flags);
+extern int anoubis_notify(void * buf, size_t len, int src);
+extern int anoubis_notify_atomic(void * buf, size_t len, int src);
+extern int anoubis_need_secureexec(struct linux_binprm *bprm);
+extern int anoubis_is_listener(void);
+
+#ifdef CONFIG_SECURITY_ANOUBIS
+
+extern void anoubis_task_create(struct task_struct *tsk);
+extern void anoubis_task_destroy(struct task_struct *tsk);
+
+#else
+
+static inline void anoubis_task_create(struct task_struct *tsk)
+{
+}
+
+static inline void anoubis_task_destroy(struct task_struct *tsk)
+{
+}
+
+#endif
+
+/*
+ * Module mulitplexor functions
+ */
+
+#define DECLARE(NAME) typeof (((struct security_operations *)NULL)->NAME) NAME;
+struct anoubis_hooks {
+	/* Private Data: Do not touch from outside of anoubis_core. */
+	int magic;
+	atomic_t refcount;
+	unsigned long version;
+	/* Hooks */
+	void (*anoubis_stats)(struct anoubis_internal_stat_value**, int *);
+	int (*anoubis_getcsum)(struct file *, u_int8_t *);
+	DECLARE(unix_stream_connect);
+	DECLARE(socket_post_create);
+	DECLARE(socket_connect);
+	DECLARE(socket_accepted);
+	DECLARE(socket_sendmsg);
+	DECLARE(socket_recvmsg);
+	DECLARE(socket_skb_recv_datagram);
+	DECLARE(sk_alloc_security);
+	DECLARE(sk_free_security);
+	DECLARE(inode_alloc_security);
+	DECLARE(inode_free_security);
+	DECLARE(inode_permission);
+	DECLARE(inode_create);
+	DECLARE(inode_mknod);
+	DECLARE(inode_mkdir);
+	DECLARE(inode_link);
+	DECLARE(inode_symlink);
+	DECLARE(inode_unlink);
+	DECLARE(inode_rmdir);
+	DECLARE(inode_rename);
+	DECLARE(inode_readlink);
+	DECLARE(inode_setxattr);
+	DECLARE(inode_removexattr);
+	DECLARE(inode_follow_link);
+	DECLARE(dentry_open);
+	DECLARE(file_alloc_security);
+	DECLARE(file_free_security);
+	DECLARE(file_lock);
+#ifdef CONFIG_SECURITY_PATH
+	DECLARE(path_link);
+	DECLARE(path_unlink);
+	DECLARE(path_mkdir);
+	DECLARE(path_rmdir);
+	DECLARE(path_rename);
+	DECLARE(path_symlink);
+	DECLARE(path_truncate);
+	DECLARE(path_mknod);
+#endif
+	DECLARE(cred_prepare);
+	DECLARE(cred_commit);
+	DECLARE(cred_free);
+	DECLARE(bprm_set_creds);
+	DECLARE(bprm_committed_creds);
+	DECLARE(bprm_secureexec);
+	DECLARE(capable);
+	DECLARE(ptrace_access_check);
+
+	DECLARE(d_instantiate);
+	DECLARE(inode_init_security);
+	DECLARE(inode_delete);
+};
+#undef DECLARE
+
+extern int anoubis_deny_write_access(struct file *file);
+extern void anoubis_allow_write_access(struct file *file);
+
+extern int anoubis_register(struct anoubis_hooks *, int *);
+extern void anoubis_unregister(int idx);
+extern void * anoubis_set_sublabel(void ** labelp, int idx, void * subl);
+extern void * anoubis_get_sublabel(void ** labelp, int idx);
+extern void * anoubis_get_sublabel_const(void *label, int idx);
+extern anoubis_cookie_t anoubis_get_task_cookie(void);
+extern anoubis_cookie_t anoubis_alloc_pgid(void);
+
+/**
+ * Reconstruct the absolute path name of the dentry/vfsmnt pair
+ * given by path. This function is used by both the sfs and the
+ * playground module.
+ * The use of "root" below is somewhat of a hack. We should actually pass
+ * the global file system root but we don't have that. However, __d_path
+ * is prepared to handle paths that are not below the given root. Thus
+ * this trick should be ok for now.
+ *
+ * @param path The dentry and vfsmnt of the path.
+ * @param buf A preallocated buffer where the path will be stored. The
+ *     path will be terminated by a NUL byte.
+ * @param len The lenght of the preallocated buffer.
+ * @return A pointer to the first byte of the path. This pointer will
+ *     point somewhere into the middle of the buffer buf.
+ */
+static inline char * global_dpath(struct path * path, char * buf, int len)
+{
+	char * ret;
+	struct path root;
+
+	root.mnt = NULL;
+	root.dentry = NULL;
+	spin_lock(&dcache_lock);
+	ret = __d_path(path, &root, buf, len);
+	spin_unlock(&dcache_lock);
+	return ret;
+}
+
+/**
+ * Reconstruct the path name of the dentry relative to the root of the
+ * device that the dentry lives on. This is similar to global_dpath except
+ * that this function does not travers mount points. This has the benefit
+ * that no vfsmount is required. The use of root is even more or a hack
+ * than  in global_dpath. It relies to some extent on the implementation of
+ * __d_path. This function is designed to work, even if dentry->d_inode
+ * is NULL. The root of the file system is taken from the dentry's parent
+ * in this case.
+ * NOTE: The kernel might append the string " (deleted)" to the path name.
+ * NOTE: If this happens for an unlinked dentry this function remove the
+ * NOTE: deleted part automaticall. This differs from the behaviour of
+ * NOTE: global_dpath. It also means that the string might end before the
+ * NOTE: end of the buffer.
+ *
+ * @param dentry The dentry of the path.
+ * @param buf The buffer where the path will be stored.
+ * @param len The length of the path name buffer.
+ * @return A pointer to the start of the pathname in the path name buffer.
+ *     This function will fill the buffer starting at the end.
+ */
+static inline char * local_dpath(struct dentry *dentry, char *buf, int len)
+{
+	struct path root;
+	struct path path;
+	char * ret;
+	struct super_block *super = NULL;
+
+	if (dentry->d_inode) {
+		super = dentry->d_inode->i_sb;
+	} else {
+		struct dentry *parent = dentry->d_parent;
+		if (!parent || !parent->d_inode)
+			return NULL;
+		super = parent->d_inode->i_sb;
+	}
+	if (!super)
+		return NULL;
+	root.mnt = NULL;
+	root.dentry = super->s_root;
+	path.dentry = dentry;
+	path.mnt = NULL;
+	spin_lock(&dcache_lock);
+	ret = __d_path(&path, &root, buf, len);
+	spin_unlock(&dcache_lock);
+	/*
+	 * Remove the trailing string " (deleted)" if the dentry is
+	 * unlinked. This happens in the playground before the rename.
+	 */
+	if (ret && !IS_ERR(ret) && d_unhashed(dentry) && !IS_ROOT(dentry)) {
+		int	slen = strlen(ret);
+
+		if (slen > 10 && strcmp(ret + slen-10, " (deleted)") == 0)
+			ret[slen-10] = 0;
+	}
+	return ret;
+}
+
+#endif
+
+#endif
diff --git a/include/linux/anoubis_alf.h b/include/linux/anoubis_alf.h
new file mode 100644
index 0000000..d8b20a9
--- /dev/null
+++ b/include/linux/anoubis_alf.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2008 GeNUA mbH <info@genua.de>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef ANOUBIS_ALF_H
+#define ANOUBIS_ALF_H
+
+#ifdef __KERNEL__
+
+#include <linux/in.h>
+#include <linux/in6.h>
+
+#else
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#endif
+
+#include <linux/anoubis.h>
+
+enum alf_ops
+{
+	ALF_ANY = 0,
+	ALF_CONNECT = 1,
+	ALF_ACCEPT = 2,
+	ALF_SENDMSG = 3,
+	ALF_RECVMSG = 4
+};
+
+struct alf_event
+{
+	struct anoubis_event_common common;
+	union
+	{
+		struct sockaddr_in	in_addr;
+		struct sockaddr_in6	in6_addr;
+	} local;
+	union
+	{
+		struct sockaddr_in	in_addr;
+		struct sockaddr_in6	in6_addr;
+	} peer;
+	unsigned short family;
+	unsigned short type;
+	unsigned short protocol;
+
+	unsigned short op;
+};
+
+/* Stat keys for ANOUBIS_SOURCE_ALF */
+#define ALF_STAT_LOADTIME		10
+#define ALF_STAT_ASK			11
+#define ALF_STAT_ASK_DENY		12
+#define ALF_STAT_ALLOWPORT		13
+#define ALF_STAT_FORCED_NOTIFY		14
+#define ALF_STAT_PROCESSED		15
+#define ALF_STAT_FORCED_DISCONNECT	16
+#define ALF_STAT_CONNECT		17
+#define ALF_STAT_ACCEPT			18
+#define ALF_STAT_SENDMSG		19
+#define ALF_STAT_RECEIVEMSG		20
+
+#endif
diff --git a/include/linux/anoubis_playground.h b/include/linux/anoubis_playground.h
new file mode 100644
index 0000000..4178f71
--- /dev/null
+++ b/include/linux/anoubis_playground.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2010 GeNUA mbH <info@genua.de>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef ANOUBIS_PLAYGROUND_H
+#define ANOUBIS_PLAYGROUND_H
+
+/* Statistic Keys for ANOUBIS_SOURCE_PLAYGROUND */
+#define PG_STAT_LOADTIME		10
+#define PG_STAT_DEVICEWRITE_DELAY	11
+#define PG_STAT_DEVICEWRITE_ASK		12
+#define PG_STAT_DEVICEWRITE_DENY	13
+#define PG_STAT_RENAME_ASK		14
+#define PG_STAT_RENAME_OVERRIDE		15
+
+#define ANOUBIS_PLAYGROUND_OP_OPEN	1
+#define ANOUBIS_PLAYGROUND_OP_RENAME	2
+#define ANOUBIS_PLAYGROUND_OP_SCAN	3
+
+/**
+ * This message is sent to the daemon if a playground process is
+ * trying to perform an action that requires user confirmation because
+ * it will affect the production system. Fields:
+ * @common: The common data for all anoubis events.
+ * @op: The operation that the process wants to perfrom, e.g.
+ *    ANOUBIS_PLAYGROUND_OP_OPEN or ANOUBIS_PLAYGROUND_OP_RENAME.
+ * @mode: The file mode of the (first) inode involved in the operation.
+ *    (Taken directly forom inode->i_mode).
+ * @pathbuf: Contains one or two NUL-terminated path names, depending on
+ *    the value of the op field.
+ */
+struct pg_open_message {
+	struct anoubis_event_common common;
+	u_int32_t op;
+	u_int32_t mode;
+	char pathbuf[0];
+};
+
+/**
+ * This message is sent by the anoubis-Daemon after a new playground ID
+ * has been assigned to a process. Fields:
+ * common: Common data for all anoubis events. This contains both the task
+ *     cookie and the playground-ID of the current process.
+ */
+struct pg_proc_message {
+	struct anoubis_event_common common;
+};
+
+#define ANOUBIS_PGFILE_INSTANTIATE	1
+#define ANOUBIS_PGFILE_DELETE		2
+#define ANOUBIS_PGFILE_SCAN		3
+
+/**
+ * This message is used to inform the anoubis daemon about an operation
+ * to an inode with a playground label. The daemon uses these messages
+ * to track file names and inodes with playground labels.
+ * Fields:
+ * common: The common event data for all anoubis events.
+ * pgid: The playground ID of the file.
+ * dev: The device of the file.
+ * ino: The inode number of the file.
+ * op: The operation that is performed with the file (ANOUBIS_PGFILE_*).
+ * path: The path name of the file relative to the device given by dev
+ *       (0-terminated) and the old path name if the operation was a directory
+ *       rename (0-terminated). The old path name may be empty but the
+ *       0-byte is always added.
+ */
+struct pg_file_message {
+	struct anoubis_event_common common;
+	anoubis_cookie_t pgid;
+	u_int64_t dev;
+	u_int64_t ino;
+	int op;
+	char path[0];
+};
+
+#ifdef __KERNEL__
+
+#include <linux/dcache.h>
+#include <linux/errno.h>
+
+#include <linux/anoubis.h>
+
+
+#define anoubis_get_playgroundid()	anoubis_get_playgroundid_tsk(current)
+
+#ifdef CONFIG_SECURITY_ANOUBIS_PLAYGROUND
+
+extern int anoubis_playground_create(int rename);
+extern anoubis_cookie_t anoubis_get_playgroundid_tsk(struct task_struct *tsk);
+extern int anoubis_pg_validate_name(const char *name, struct dentry *base,
+					int len, anoubis_cookie_t pgid, ino_t);
+extern int anoubis_playground_enabled(struct dentry *dentry);
+extern int anoubis_playground_set_lowerfile(struct file *up, struct file *low);
+extern int anoubis_playground_clone_reg(int atfd, const char __user *oldname);
+extern int anoubis_playground_clone_symlink(int atfd, const char __user *);
+
+extern int anoubis_playground_get_pgcreate(void);
+extern void anoubis_playground_clear_accessok(struct inode *inode);
+extern int anoubis_playground_readdirok(struct inode *inode);
+extern int anoubis_playground_scanstarted(struct file *file);
+extern int anoubis_playground_scansuccess(struct file *file);
+
+#else
+
+static inline int anoubis_playground_create(void)
+{
+	return -ENOSYS;
+}
+
+static inline anoubis_cookie_t anoubis_get_playgroundid_tsk(
+			struct task_struct *tsk)
+{
+	return 0;
+}
+
+static inline int anoubis_pg_validate_name(const char *name,
+			struct dentry *base, int len, anoubis_cookie_t pgid)
+{
+	return 1;
+}
+
+static inline int anoubis_playground_clone_reg(int atfd,
+						const char __user *oldname)
+{
+	return 0;
+}
+
+static inline int anoubis_playground_clone_symlink(int atfd,
+						const char __user *oldname)
+{
+	return 0;
+}
+
+static inline int anoubis_playground_get_pgcreate(void)
+{
+	return 0;
+}
+
+static inline void anoubis_playground_clear_accessok(struct inode *inode)
+{
+}
+
+static inline int anoubis_playground_scanstarted(struct file *file)
+{
+	return -ENOSYS;
+}
+
+static inline int anoubis_playground_scansuccess(struct file *file)
+{
+	return -ENOSYS;
+}
+
+#endif
+
+#endif /* __KERNEL__ */
+
+#endif /* ANOUBIS_PG_H */
diff --git a/include/linux/anoubis_sfs.h b/include/linux/anoubis_sfs.h
new file mode 100644
index 0000000..10fab8a
--- /dev/null
+++ b/include/linux/anoubis_sfs.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2008 GeNUA mbH <info@genua.de>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef ANOUBIS_SFS_H
+#define ANOUBIS_SFS_H
+
+#include <linux/anoubis.h>
+
+#define ANOUBIS_SFS_CS_LEN	ANOUBIS_CS_LEN	/* Length of Checksum */
+
+#define ANOUBIS_OPEN_FLAG_READ		0x0001UL
+#define ANOUBIS_OPEN_FLAG_WRITE		0x0002UL
+#define ANOUBIS_OPEN_FLAG_EXEC		0x0004UL
+#define ANOUBIS_OPEN_FLAG_FOLLOW	0x0008UL
+
+#define ANOUBIS_OPEN_FLAG_PATHHINT	0x0020UL
+#define ANOUBIS_OPEN_FLAG_STATDATA	0x0040UL
+#define ANOUBIS_OPEN_FLAG_CSUM		0x0080UL
+#define ANOUBIS_OPEN_FLAG_SECUREEXEC	0x0100UL
+
+/* Statistic Keys for ANOUBIS_SOURCE_SFS */
+#define SFS_STAT_LOADTIME		10
+#define SFS_STAT_CSUM_RECALC		11
+#define SFS_STAT_CSUM_RECALC_FAIL	12
+#define SFS_STAT_EV			14
+#define SFS_STAT_EV_DENY		16
+#define SFS_STAT_LATE_ALLOC		17
+#define SFS_STAT_PATH			18
+#define SFS_STAT_PATH_DENY		19
+
+struct sfs_open_message
+{
+	struct anoubis_event_common common;
+	u_int64_t ino;
+	u_int64_t dev;
+	unsigned long flags;
+	u_int8_t csum[ANOUBIS_SFS_CS_LEN];
+	char pathhint[1];
+};
+
+#define ANOUBIS_PATH_OP_LINK		1
+#define ANOUBIS_PATH_OP_UNLINK		2
+#define ANOUBIS_PATH_OP_SLINK		3
+#define ANOUBIS_PATH_OP_MKDIR		4
+#define ANOUBIS_PATH_OP_RMDIR		5
+#define ANOUBIS_PATH_OP_MKNOD		6
+#define ANOUBIS_PATH_OP_RENAME		7
+#define ANOUBIS_PATH_OP_TRUNC		8
+#define ANOUBIS_PATH_OP_LOCK		9
+#define ANOUBIS_PATH_OP_UNLOCK		10
+
+struct sfs_path_message
+{
+	struct anoubis_event_common common;
+	unsigned int op;
+	unsigned int pathlen[2];
+	char paths[];
+};
+
+#ifdef __KERNEL__
+
+int anoubis_sfs_get_csum(struct file * file, u_int8_t * csum);
+
+#endif
+
+#endif /* ANOUBIS_SFS_H */
diff --git a/include/linux/dazukofs_fs.h b/include/linux/dazukofs_fs.h
new file mode 100644
index 0000000..b69807d
--- /dev/null
+++ b/include/linux/dazukofs_fs.h
@@ -0,0 +1,12 @@
+#ifndef _DAZUKOFS_FS_H_
+#define _DAZUKOFS_FS_H_
+
+struct inode;
+
+static inline struct inode *get_lower_inode(struct inode *upper)
+{
+	return upper;
+}
+
+
+#endif	/* _DAZUKOFS_FS_H_ */
diff --git a/include/linux/errno.h b/include/linux/errno.h
index 4668583..1c051f4 100644
--- a/include/linux/errno.h
+++ b/include/linux/errno.h
@@ -29,6 +29,11 @@
 #define EIOCBQUEUED	529	/* iocb queued, will get completion event */
 #define EIOCBRETRY	530	/* iocb queued, will trigger a retry */
 
+/* Defined for the anoubis Playground */
+#define EPGCLONEREG	600	/* file must be copied into playground */
+#define EPGCLONESYMLINK	601	/* Symlink must be copied into playground */
+#define EPGWHITEOUT	602	/* Create whiteout in playground */
+
 #endif
 
 #endif
diff --git a/include/linux/eventdev.h b/include/linux/eventdev.h
new file mode 100644
index 0000000..dc924de
--- /dev/null
+++ b/include/linux/eventdev.h
@@ -0,0 +1,64 @@
+#ifndef _EVENTDEV_H_
+#define _EVENTDEV_H_
+
+#ifdef __KERNEL__
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/rcupdate.h>
+
+#endif /* __KERNEL__ */
+
+typedef u_int32_t eventdev_token;
+
+#define EVENTDEV_NEED_REPLY	1
+
+struct eventdev_hdr {
+	unsigned short msg_size;
+	unsigned char msg_source;
+	unsigned char msg_flags;
+	eventdev_token msg_token;
+	u_int32_t msg_pid;
+	u_int32_t msg_uid;
+};
+
+struct eventdev_reply {
+	eventdev_token msg_token;
+	int reply;
+};
+
+#ifdef __KERNEL__
+
+struct eventdev_queue;
+
+extern int eventdev_enqueue_wait(struct eventdev_queue * q, unsigned char src,
+	char * data, int len, int * retval, gfp_t flags);
+extern int eventdev_enqueue_nowait(struct eventdev_queue * q, unsigned char src,
+	char * data, int len, gfp_t flags);
+extern struct eventdev_queue * eventdev_get_queue(struct file * file);
+extern void __eventdev_get_queue(struct eventdev_queue * q);
+
+/* Return a pointer to an RCU head embedded in the eventdev structure. */
+extern struct rcu_head * eventdev_rcu_head(struct eventdev_queue * q);
+extern void eventdev_rcu_put(struct rcu_head *);
+
+/* Do NOT call this function directly. Use eventdev_put_queue instead. */
+extern struct module * __eventdev_put_queue(struct eventdev_queue * q);
+
+/*
+ * This MUST be inlined at the caller or else there might be module
+ * remove races: If this is the final module_put the module might
+ * be removed before the function returns. Thus this function cannot
+ * reside within the module itself.
+ */
+static inline void eventdev_put_queue(struct eventdev_queue * q)
+{
+	struct module * m = __eventdev_put_queue(q);
+	if (unlikely(m))
+		module_put(m);
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* _EVENTDEV_H_ */
diff --git a/include/linux/namei.h b/include/linux/namei.h
index ec0f607..7b47cd6 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -57,6 +57,11 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
 #define LOOKUP_EXCL		0x0400
 #define LOOKUP_RENAME_TARGET	0x0800
 
+#define LOOKUP_PLAYGROUND_CREATE	0x10000
+#define LOOKUP_PLAYGROUND_UNLINK	0x20000
+#define LOOKUP_PLAYGROUND_DIRRENAME	0x40000
+#define LOOKUP_PLAYGROUND_SOCKET	0x80000
+
 extern int user_path_at(int, const char __user *, unsigned, struct path *);
 
 #define user_path(name, path) user_path_at(AT_FDCWD, name, LOOKUP_FOLLOW, path)
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index d09db1b..f8f1328 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -172,6 +172,8 @@ struct nfs_inode {
 
 	/* Number of in-flight sillydelete RPC calls */
 	atomic_t		silly_count;
+	int			silly_block_depth;
+	struct task_struct	*silly_blocker;
 	/* List of deferred sillydelete requests */
 	struct hlist_head	silly_list;
 	wait_queue_head_t	waitqueue;
diff --git a/include/linux/security.h b/include/linux/security.h
index 239e40d..08b1701 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -914,6 +914,11 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *	@sock contains the listening socket structure.
  *	@newsock contains the newly created server socket for connection.
  *	Return 0 if permission is granted.
+ * @socket_accepted:
+ *	Check permission after accepting a new connection.
+ *	@sock contains the listening socket structure.
+ *	@newsock contains the newly created server socket for connection.
+ *	Return 0 if permission is granted.
  * @socket_sendmsg:
  *	Check permission before transmitting a message to another socket.
  *	@sock contains the socket structure.
@@ -963,6 +968,11 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *	incoming sk_buff @skb has been associated with a particular socket, @sk.
  *	@sk contains the sock (not socket) associated with the incoming sk_buff.
  *	@skb contains the incoming network data.
+ * @socket_skb_recv_datagram:
+ *	Check permission after receiving a socket-buffer from a socket.
+ *	@sk contains the socket structure.
+ *	@skb contains the incoming network data.
+ *	Return 0 if permission is granted.  
  * @socket_getpeersec_stream:
  *	This hook allows the security module to provide peer socket security
  *	state for unix or connected tcp sockets to userspace via getsockopt
@@ -1643,6 +1653,7 @@ struct security_operations {
 			       struct sockaddr *address, int addrlen);
 	int (*socket_listen) (struct socket *sock, int backlog);
 	int (*socket_accept) (struct socket *sock, struct socket *newsock);
+	int (*socket_accepted) (struct socket * sock, struct socket * newsock);
 	int (*socket_sendmsg) (struct socket *sock,
 			       struct msghdr *msg, int size);
 	int (*socket_recvmsg) (struct socket *sock,
@@ -1653,6 +1664,7 @@ struct security_operations {
 	int (*socket_setsockopt) (struct socket *sock, int level, int optname);
 	int (*socket_shutdown) (struct socket *sock, int how);
 	int (*socket_sock_rcv_skb) (struct sock *sk, struct sk_buff *skb);
+	int (*socket_skb_recv_datagram) (struct sock * sk, struct sk_buff * skb);
 	int (*socket_getpeersec_stream) (struct socket *sock, char __user *optval, int __user *optlen, unsigned len);
 	int (*socket_getpeersec_dgram) (struct socket *sock, struct sk_buff *skb, u32 *secid);
 	int (*sk_alloc_security) (struct sock *sk, int family, gfp_t priority);
@@ -2664,6 +2676,7 @@ int security_socket_bind(struct socket *sock, struct sockaddr *address, int addr
 int security_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen);
 int security_socket_listen(struct socket *sock, int backlog);
 int security_socket_accept(struct socket *sock, struct socket *newsock);
+int security_socket_accepted(struct socket * sock, struct socket * newsock);
 int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size);
 int security_socket_recvmsg(struct socket *sock, struct msghdr *msg,
 			    int size, int flags);
@@ -2673,6 +2686,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);
+int security_socket_skb_recv_datagram (struct sock * sk, struct sk_buff * skb);
 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);
@@ -2745,6 +2759,12 @@ static inline int security_socket_accept(struct socket *sock,
 	return 0;
 }
 
+static inline int security_socket_accepted(struct socket * sock,
+					   struct socket * newsock)
+{
+	return 0;
+}
+
 static inline int security_socket_sendmsg(struct socket *sock,
 					  struct msghdr *msg, int size)
 {
@@ -2790,6 +2810,12 @@ static inline int security_sock_rcv_skb(struct sock *sk,
 	return 0;
 }
 
+static int security_socket_skb_recv_datagram(struct sock * sk,
+					     struct sk_buff * skb)
+{
+	return 0;
+}
+
 static inline int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
 						    int __user *optlen, unsigned len)
 {
diff --git a/kernel/fork.c b/kernel/fork.c
index 166b8c4..2c003c9 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -65,6 +65,8 @@
 #include <linux/perf_event.h>
 #include <linux/posix-timers.h>
 
+#include <linux/anoubis.h>
+
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 #include <asm/uaccess.h>
@@ -162,6 +164,7 @@ void __put_task_struct(struct task_struct *tsk)
 	WARN_ON(atomic_read(&tsk->usage));
 	WARN_ON(tsk == current);
 
+	anoubis_task_destroy(tsk);
 	exit_creds(tsk);
 	delayacct_tsk_free(tsk);
 
@@ -1037,6 +1040,9 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 	retval = copy_creds(p, clone_flags);
 	if (retval < 0)
 		goto bad_fork_free;
+#ifdef CONFIG_SECURITY_ANOUBIS
+	anoubis_task_create(p);
+#endif
 
 	/*
 	 * If multiple threads are within copy_process(), then this check
@@ -1340,6 +1346,7 @@ bad_fork_cleanup_cgroup:
 	module_put(task_thread_info(p)->exec_domain->module);
 bad_fork_cleanup_count:
 	atomic_dec(&p->cred->user->processes);
+	anoubis_task_destroy(p);
 	exit_creds(p);
 bad_fork_free:
 	free_task(p);
diff --git a/net/core/datagram.c b/net/core/datagram.c
index 4ade301..d2c27fb 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -48,6 +48,7 @@
 #include <linux/poll.h>
 #include <linux/highmem.h>
 #include <linux/spinlock.h>
+#include <linux/security.h>
 
 #include <net/protocol.h>
 #include <linux/skbuff.h>
@@ -192,6 +193,13 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags,
 		}
 		spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags);
 
+		if (security_socket_skb_recv_datagram(sk, skb)) {
+			/* skb_kill_datagram will remove the packet from the
+			 * queue even if MSG_PEEK is set */
+			skb_kill_datagram(sk, skb, flags);
+			skb = NULL;
+		}
+
 		if (skb)
 			return skb;
 
diff --git a/net/socket.c b/net/socket.c
index 7565536..117c817 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1516,6 +1516,10 @@ SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
 	err = sock->ops->accept(sock, newsock, sock->file->f_flags);
 	if (err < 0)
 		goto out_fd;
+	
+	err = security_socket_accepted(sock, newsock);
+	if (err)
+		goto out_fd;
 
 	if (upeer_sockaddr) {
 		if (newsock->ops->getname(newsock, (struct sockaddr *)&address,
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index fc820cd..b996ef8 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -823,6 +823,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 		if (err)
 			goto out_mknod_parent;
 
+		nd.flags |= LOOKUP_PLAYGROUND_SOCKET;
 		dentry = lookup_create(&nd, 0);
 		err = PTR_ERR(dentry);
 		if (IS_ERR(dentry))
diff --git a/scripts/package/mkspec b/scripts/package/mkspec
index 47bdd2f..6bee514 100755
--- a/scripts/package/mkspec
+++ b/scripts/package/mkspec
@@ -26,10 +26,10 @@ __KERNELRELEASE=`echo $KERNELRELEASE | sed -e "s/-//g"`
 
 echo "Name: kernel"
 echo "Summary: The Linux Kernel"
-echo "Version: $__KERNELRELEASE"
+echo "Version: ${KERNELRELEASE%%-*}"
 # we need to determine the NEXT version number so that uname and
 # rpm -q will agree
-echo "Release: `. $srctree/scripts/mkversion`"
+echo "Release: ${KERNELRELEASE#*-}"
 echo "License: GPL"
 echo "Group: System Environment/Kernel"
 echo "Vendor: The Linux Community"
@@ -39,7 +39,7 @@ if ! $PREBUILT; then
 echo "Source: kernel-$__KERNELRELEASE.tar.gz"
 fi
 
-echo "BuildRoot: /var/tmp/%{name}-%{PACKAGE_VERSION}-root"
+echo "BuildRoot: %{_tmppath}/%{name}-%{PACKAGE_VERSION}-root"
 echo "Provides: $PROVIDES"
 echo "%define __spec_install_post /usr/lib/rpm/brp-compress || :"
 echo "%define debug_package %{nil}"
@@ -48,9 +48,16 @@ echo "%description"
 echo "The Linux Kernel, the operating system core itself"
 echo ""
 
+echo "%package devel"
+echo "Summary: Development package for building kernel modules to match the $KERNELRELEASE kernel"
+echo "Group: System Environment/Kernel"
+echo "%description devel"
+echo "This package provides kernel headers and makefiles sufficient to build modules against the $KERNELRELEASE kernel package."
+echo ""
+
 if ! $PREBUILT; then
 echo "%prep"
-echo "%setup -q"
+echo "%setup -q -n kernel-${__KERNELRELEASE}"
 echo ""
 fi
 
@@ -64,13 +71,65 @@ fi
 echo "%install"
 echo "%ifarch ia64"
 echo 'mkdir -p $RPM_BUILD_ROOT/boot/efi $RPM_BUILD_ROOT/lib/modules'
-echo 'mkdir -p $RPM_BUILD_ROOT/lib/firmware'
 echo "%else"
 echo 'mkdir -p $RPM_BUILD_ROOT/boot $RPM_BUILD_ROOT/lib/modules'
-echo 'mkdir -p $RPM_BUILD_ROOT/lib/firmware'
 echo "%endif"
 
 echo 'INSTALL_MOD_PATH=$RPM_BUILD_ROOT make %{_smp_mflags} KBUILD_SRC= modules_install'
+echo 'rm -r $RPM_BUILD_ROOT/lib/firmware'
+
+# Taken from the Fedora specfile
+echo "KERNELRELEASE=\"$KERNELRELEASE\""
+echo "DevelDir=\"/usr/src/kernels/$KERNELRELEASE\""
+echo 'rm -f $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/build'
+echo 'rm -f $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/source'
+echo 'mkdir -p $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/build'
+echo '(cd $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE ; ln -s build source)'
+
+# first copy everything
+echo 'cp --parents `find  -type f -name "Makefile*" -o -name "Kconfig*"` $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/build'
+echo 'cp Module.symvers $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/build'
+echo 'cp System.map $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/build'
+echo 'if [ -s Module.markers ]; then'
+echo '  cp Module.markers $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/build'
+echo 'fi'
+# then drop all but the needed Makefiles/Kconfig files
+echo 'rm -rf $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/build/Documentation'
+echo 'rm -rf $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/build/scripts'
+echo 'rm -rf $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/build/include'
+echo 'cp .config $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/build'
+echo 'cp -a scripts $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/build'
+echo 'if [ -d arch/$Arch/scripts ]; then'
+echo '  cp -a arch/$Arch/scripts $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/build/arch/%{_arch} || :'
+echo 'fi'
+echo 'if [ -f arch/$Arch/*lds ]; then'
+echo '  cp -a arch/$Arch/*lds $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/build/arch/%{_arch}/ || :'
+echo 'fi'
+echo 'rm -f $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/build/scripts/*.o'
+echo 'rm -f $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/build/scripts/*/*.o'
+echo 'if [ -d arch/%{asmarch}/include ]; then'
+echo '  cp -a --parents arch/%{asmarch}/include $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/build/'
+echo 'fi'
+echo 'mkdir -p $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/build/include'
+echo 'cd include'
+echo 'cp -a acpi config crypto keys linux math-emu media mtd net pcmcia rdma rxrpc scsi sound trace video drm asm-generic $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/build/include'
+echo 'asmdir=$(readlink asm)'
+echo 'cp -a $asmdir $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/build/include/'
+echo 'pushd $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/build/include'
+echo 'ln -s $asmdir asm'
+echo 'popd'
+# Make sure the Makefile and version.h have a matching timestamp so that
+# external modules can be built
+echo 'touch -r $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/build/Makefile $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/build/include/linux/version.h'
+echo 'touch -r $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/build/.config $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/build/include/linux/autoconf.h'
+# Cop' .config to include/config/auto.conf so "make prepare" is unnecessary.'
+echo 'cp $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/build/.config $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/build/include/config/auto.conf'
+echo 'cd ..'
+# Move the devel headers out of the root file system
+echo 'mkdir -p $RPM_BUILD_ROOT/usr/src/kernels'
+echo 'mv $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/build $RPM_BUILD_ROOT/$DevelDir'
+echo 'ln -sf ../../..$DevelDir $RPM_BUILD_ROOT/lib/modules/$KERNELRELEASE/build'
+
 echo "%ifarch ia64"
 echo 'cp $KBUILD_IMAGE $RPM_BUILD_ROOT'"/boot/efi/vmlinuz-$KERNELRELEASE"
 echo 'ln -s '"efi/vmlinuz-$KERNELRELEASE" '$RPM_BUILD_ROOT'"/boot/"
@@ -95,6 +154,46 @@ echo 'mv vmlinux.orig vmlinux'
 echo "%endif"
 
 echo ""
+
+cat << EOF
+%post
+# this is verified to work with fedora 8 and suse 10.3
+echo "Creating initrd..."
+if [ -x /usr/lib/bootloader/bootloader_entry ] ; then
+	#suse
+	/sbin/mkinitrd -k /boot/vmlinuz-$KERNELRELEASE \
+		-i /boot/initrd-$KERNELRELEASE
+	/usr/lib/bootloader/bootloader_entry add \
+		anoubis \
+		$KERNELRELEASE \
+		vmlinuz-$KERNELRELEASE \
+		initrd-$KERNELRELEASE
+elif [ -x /sbin/new-kernel-pkg ] ; then
+	# fedora
+	/sbin/new-kernel-pkg --package kernel-$KERNELRELEASE \
+		--mkinitrd --depmod --install $KERNELRELEASE
+else
+	echo "Warning: Don't know how to create initrd for this system"
+fi
+
+%preun
+echo "Removing initrd..."
+if [ -x /usr/lib/bootloader/bootloader_entry ] ; then
+	#suse
+	rm -f /boot/initrd-$KERNELRELEASE
+	/usr/lib/bootloader/bootloader_entry remove anoubis \
+		$KERNELRELEASE \
+		vmlinuz-$KERNELRELEASE \
+		initrd-$KERNELRELEASE
+elif [ -x /sbin/new-kernel-pkg ] ; then
+	# fedora
+	/sbin/new-kernel-pkg --package kernel-$KERNELRELEASE \
+		--rminitrd --rmmoddep --remove $KERNELRELEASE
+else
+	echo "Warning: Don't know how to remove initrd for this system"
+fi
+EOF
+
 echo "%clean"
 echo 'rm -rf $RPM_BUILD_ROOT'
 echo ""
@@ -102,6 +201,10 @@ echo "%files"
 echo '%defattr (-, root, root)'
 echo "%dir /lib/modules"
 echo "/lib/modules/$KERNELRELEASE"
-echo "/lib/firmware"
 echo "/boot/*"
 echo ""
+echo "%files devel"
+echo "%dir /usr/src/kernels"
+echo "/usr/src/kernels/$KERNELRELEASE"
+echo ""
+
diff --git a/security/Kconfig b/security/Kconfig
index fb363cd..f4bf371 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -160,10 +160,12 @@ config LSM_MMAP_MIN_ADDR
 	  systems running LSM.
 
 source security/selinux/Kconfig
+
 source security/smack/Kconfig
 source security/tomoyo/Kconfig
 
 source security/integrity/ima/Kconfig
 
-endmenu
+source security/anoubis/Kconfig
 
+endmenu
diff --git a/security/Makefile b/security/Makefile
index 95ecc06..7cbd801 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_ANOUBIS)	+= anoubis
 
 # always enable default capabilities
 obj-y		+= commoncap.o min_addr.o
@@ -19,6 +20,7 @@ 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_ROOTPLUG)		+= root_plug.o
+obj-$(CONFIG_SECURITY_ANOUBIS)		+= anoubis/built-in.o
 obj-$(CONFIG_CGROUP_DEVICE)		+= device_cgroup.o
 
 # Object integrity file lists
diff --git a/security/anoubis/Kconfig b/security/anoubis/Kconfig
new file mode 100644
index 0000000..ae4e07a
--- /dev/null
+++ b/security/anoubis/Kconfig
@@ -0,0 +1,53 @@
+#
+# Anoubis configuration
+#
+
+menu "Anoubis framework"
+
+config SECURITY_ANOUBIS
+	bool "Anoubis framework"
+	depends on SECURITY && EVENTDEV=y
+	help
+	  This option provides support for the Anoubis framework.
+
+config SECURITY_ANOUBIS_ALF
+	tristate "Application Level Firewall module"
+	depends on SECURITY_ANOUBIS && SECURITY_NETWORK
+	help
+	  This option provides support for the Anoubis ALF module
+
+config SECURITY_ANOUBIS_IPC
+	tristate "Anoubis IPC Module"
+	depends on SECURITY_ANOUBIS && SECURITY_NETWORK
+	help
+	  This option provides support for the Anoubis IPC module.
+
+config SECURITY_ANOUBIS_SFS
+	tristate "Secure Filesystem Module"
+	depends on SECURITY_ANOUBIS && SECURITY_PATH && CRYPTO && CRYPTO_SHA256
+	help
+	  This option provides initial support for the Anoubis SFS module.
+
+config SECURITY_ANOUBIS_PLAYGROUND
+	bool "Anoubis Playground feature"
+	depends on SECURITY_ANOUBIS
+	help
+	  This option provides support for the Anoubis Playground feature.
+	  This feature provides individual processes with the ability to
+	  make modifications to the file system that are only visible to
+	  the process itself and its children.
+
+config SECURITY_ANOUBIS_DEBUG
+	bool "Anoubis debug messages"
+	depends on SECURITY_ANOUBIS
+	help
+	  This option enables debug messages in Anoubis modules to aid
+	  developers finding problems.
+
+config SECURITY_EVENTDEVTEST
+	tristate "Test module for Eventdev devices"
+	depends on SECURITY_ANOUBIS && SECURITY
+	help
+	  This is a test module for the eventdev device.
+
+endmenu
diff --git a/security/anoubis/Makefile b/security/anoubis/Makefile
new file mode 100644
index 0000000..fb41e09
--- /dev/null
+++ b/security/anoubis/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_SECURITY_ANOUBIS)		+= anoubis_core.o
+obj-$(CONFIG_SECURITY_ANOUBIS_ALF)	+= alf.o
+obj-$(CONFIG_SECURITY_ANOUBIS_IPC)	+= ipc.o
+obj-$(CONFIG_SECURITY_ANOUBIS_SFS)	+= sfs.o
+obj-$(CONFIG_SECURITY_EVENTDEVTEST)	+= eventdevtest.o
+obj-$(CONFIG_SECURITY_ANOUBIS_PLAYGROUND)	+= playground.o
diff --git a/security/anoubis/alf.c b/security/anoubis/alf.c
new file mode 100644
index 0000000..9f17399
--- /dev/null
+++ b/security/anoubis/alf.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright (c) 2007 GeNUA mbH <info@genua.de>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/file.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/security.h>
+#include <linux/net.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/inetdevice.h>
+#include <linux/sched.h>
+#include <linux/anoubis.h>
+#include <linux/anoubis_alf.h>
+#include <linux/udp.h>
+#include <linux/debug_locks.h>
+
+#include <net/sock.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
+
+#define MAX_SOCK_ADDR	128 /* See net/socket.c */
+
+static int allow_ports_min = -1;
+static int allow_ports_max = -1;
+static int ac_index = -1;
+
+static u_int64_t alf_stat_loadtime;
+static u_int64_t alf_stat_ask;
+static u_int64_t alf_stat_ask_deny;
+static u_int64_t alf_stat_allowport;
+static u_int64_t alf_stat_forced_notify;
+static u_int64_t alf_stat_processed;
+static u_int64_t alf_stat_forced_disconnect;
+static u_int64_t alf_stat_connect;
+static u_int64_t alf_stat_accept;
+static u_int64_t alf_stat_sendmsg;
+static u_int64_t alf_stat_receivemsg;
+
+static struct anoubis_internal_stat_value alf_stats[] = {
+	{ ANOUBIS_SOURCE_ALF, ALF_STAT_LOADTIME, &alf_stat_loadtime },
+	{ ANOUBIS_SOURCE_ALF, ALF_STAT_ASK, &alf_stat_ask },
+	{ ANOUBIS_SOURCE_ALF, ALF_STAT_ASK_DENY, &alf_stat_ask_deny },
+	{ ANOUBIS_SOURCE_ALF, ALF_STAT_ALLOWPORT, &alf_stat_allowport },
+	{ ANOUBIS_SOURCE_ALF, ALF_STAT_FORCED_NOTIFY, &alf_stat_forced_notify },
+	{ ANOUBIS_SOURCE_ALF, ALF_STAT_PROCESSED, &alf_stat_processed },
+	{ ANOUBIS_SOURCE_ALF, ALF_STAT_FORCED_DISCONNECT,
+	    &alf_stat_forced_disconnect },
+	{ ANOUBIS_SOURCE_ALF, ALF_STAT_CONNECT, &alf_stat_connect },
+	{ ANOUBIS_SOURCE_ALF, ALF_STAT_ACCEPT, &alf_stat_accept },
+	{ ANOUBIS_SOURCE_ALF, ALF_STAT_SENDMSG, &alf_stat_sendmsg },
+	{ ANOUBIS_SOURCE_ALF, ALF_STAT_RECEIVEMSG, &alf_stat_receivemsg },
+};
+
+static void alf_get_stats(struct anoubis_internal_stat_value **ptr, int *cnt)
+{
+	(*ptr) = alf_stats;
+	(*cnt) = sizeof(alf_stats)/sizeof(struct anoubis_internal_stat_value);
+}
+
+/* Ask in userspace what to do for a given event */
+static inline int alf_ask(struct alf_event *event)
+{
+	int ret;
+
+	if (unlikely(in_atomic() || irqs_disabled())) {
+#ifdef CONFIG_SECURITY_ANOUBIS_DEBUG
+		static int info_printed = 0;
+
+		if (printk_ratelimit())
+			printk(KERN_WARNING
+			    "ALF: only notifying while atomic!\n");
+
+		if (!info_printed) {
+			printk(KERN_WARNING
+			    "preempt_count: %d, pid: %u, op: %u\n",
+			    preempt_count(), current->pid, event->op);
+			debug_show_all_locks();
+			WARN_ON(1);
+			info_printed = 1;
+		}
+#endif
+		alf_stat_forced_notify++;
+		ret = anoubis_notify_atomic((char *)event, sizeof(*event),
+		    ANOUBIS_SOURCE_ALF);
+	} else {
+		alf_stat_ask++;
+		ret =  anoubis_raise((char *)event, sizeof(*event),
+		    ANOUBIS_SOURCE_ALF);
+	}
+	/*
+	 * Translate EPIPE (no eventdev queue) into a reasonable error
+	 * code. EPIPE confuses NFS.
+	 */
+	if (ret == -EPIPE)
+		ret = -EHOSTUNREACH;
+	if (ret != 0)
+		alf_stat_ask_deny++;
+	return ret;
+}
+
+/* Check a connection against the policy database. */
+static int alf_check_policy(int op, struct socket *sock,
+    struct sockaddr *address)
+{
+	char myaddress[MAX_SOCK_ADDR], tmpaddr[MAX_SOCK_ADDR];
+	int mylen;
+	int localport = 0;
+	struct alf_event *event;
+	int event_size;
+
+	if (!sock || !sock->sk)
+		return -EBADF;
+
+	switch(sock->sk->sk_family) {
+	case AF_UNIX:
+	case AF_NETLINK:
+	case AF_KEY:
+		return 0;
+	}
+
+	alf_stat_processed++;
+	if (sock->ops->getname(sock, (struct sockaddr *)myaddress,
+	    &mylen, 0) < 0)
+		return -EBADF;
+
+	if (address == NULL) {
+		int addrlen;
+
+		/*
+		 * NOTE: Passing 2 instead of 1 for the peer parameter
+		 * will return the (old) peer address even if the socket
+		 * is already closed. The SO_GETPEERNAME socket option
+		 * uses the same trick so this should be ok.
+		 */
+		if (sock->ops->getname(sock, (struct sockaddr *)tmpaddr,
+		    &addrlen, 2) < 0) {
+			/*
+			 * The socket is not connected and the sendmsg
+			 * request did not specify a target address either.
+			 * There are several cases where this can happen,
+			 * but fortunately we want to allow all of them to
+			 * pass through:
+			 * - dhclient triggers this with RAW sockets.
+			 * - nfs triggers it if MSG_MORE was set on an
+			 *   earlier sendmsg (which did have an address!)
+			 */
+			return 0;
+		} else {
+			address = (struct sockaddr *)&tmpaddr;
+		}
+	}
+
+	event_size = sizeof(struct alf_event);
+	if ((event = kmalloc(event_size, GFP_NOWAIT)) == NULL)
+		return -ENOMEM;
+
+	event->family = sock->sk->sk_family;
+	event->type = sock->type;
+	event->protocol = sock->sk->sk_protocol;
+	event->op = op;
+
+	if (sock->sk->sk_family == AF_INET) {
+		/* IPv4 */
+		event->local.in_addr = *((struct sockaddr_in *)&myaddress);
+		event->peer.in_addr = *((struct sockaddr_in *)address);
+		localport = ntohs(event->local.in_addr.sin_port);
+	} else if (sock->sk->sk_family == AF_INET6) {
+		/* IPv6 */
+		event->local.in6_addr = *((struct sockaddr_in6 *)&myaddress);
+		event->peer.in6_addr = *((struct sockaddr_in6 *)address);
+		localport = ntohs(event->local.in6_addr.sin6_port);
+	}
+	if (localport && allow_ports_min <= localport
+	    && localport <= allow_ports_max) {
+		alf_stat_allowport++;
+		kfree(event);
+		return 0;
+	}
+
+	return alf_ask(event);
+}
+
+/* Called before the SYN packet of a tcp-connection is sent, local address
+ * is invalid due to this */
+static int alf_socket_connect(struct socket * sock, struct sockaddr * address,
+    int addrlen)
+{
+	alf_stat_connect++;
+	return alf_check_policy(ALF_CONNECT, sock, address);
+}
+
+/* Called after a connection has been accepted, so we know
+ * our peer. */
+static int alf_socket_accepted(struct socket * sock,
+    struct socket * newsock)
+{
+	alf_stat_accept++;
+	return alf_check_policy(ALF_ACCEPT, newsock, NULL);
+}
+
+/* Called before sending any packet over an existing connection, both addresses
+ * are valid */
+static int alf_socket_sendmsg(struct socket * sock, struct msghdr * msg,
+    int size)
+{
+	int ret;
+
+	alf_stat_sendmsg++;
+	ret = alf_check_policy(ALF_SENDMSG, sock,
+	    (struct sockaddr *)msg->msg_name);
+
+	/* Close open TCP/SCTP connections */
+	if ((ret != 0) &&
+	    (sock->sk->sk_family == AF_INET ||
+	    sock->sk->sk_family == AF_INET6) &&
+	    (sock->sk->sk_protocol == IPPROTO_TCP ||
+	    sock->sk->sk_protocol == IPPROTO_SCTP ||
+	    sock->sk->sk_protocol == IPPROTO_IP)) {
+		alf_stat_forced_disconnect++;
+		sock->sk->sk_prot->disconnect(sock->sk, 0);
+	}
+
+	return ret;
+}
+
+/* Called before receiving a packet from an existing connection, so we only
+ * know our peer in TCP connections. */
+static int alf_socket_recvmsg(struct socket * sock, struct msghdr * msg,
+    int size, int flags)
+{
+	int ret;
+
+	alf_stat_receivemsg++;
+	if (sock->sk->sk_family != AF_INET && sock->sk->sk_family != AF_INET6)
+		return 0;
+
+	if (sock->sk->sk_protocol != IPPROTO_TCP &&
+	    sock->sk->sk_protocol != IPPROTO_SCTP &&
+	    sock->sk->sk_protocol != IPPROTO_IP)
+		return 0;
+
+	ret = alf_check_policy(ALF_RECVMSG, sock, NULL);
+
+	/* Close open TCP connections */
+	if (ret != 0) {
+		alf_stat_forced_disconnect++;
+		sock->sk->sk_prot->disconnect(sock->sk, 0);
+	}
+
+	return ret;
+}
+
+/* Called after receiving one sk_buff from the queue */
+static int alf_socket_skb_recv_datagram(struct sock * sk, struct sk_buff * skb)
+{
+	char myaddress[MAX_SOCK_ADDR];
+
+	if (!sk || !skb)
+		return 0;
+
+	/* TCP and SCTP handled by alf_socket_recvmsg */
+	if ((sk->sk_family == AF_INET ||
+	    sk->sk_family == AF_INET6) &&
+	    (sk->sk_protocol == IPPROTO_TCP ||
+	    sk->sk_protocol == IPPROTO_SCTP ||
+	    sk->sk_protocol == IPPROTO_IP))
+		return 0;
+
+	memset(myaddress, 0, sizeof(myaddress));
+
+	if (sk->sk_family == AF_INET) {
+		struct sockaddr_in *addr = (struct sockaddr_in*)myaddress;
+
+		addr->sin_family = AF_INET;
+		addr->sin_addr.s_addr = ip_hdr(skb)->saddr;
+
+		if (sk->sk_protocol == IPPROTO_UDP ||
+		    sk->sk_protocol == IPPROTO_UDPLITE)
+			addr->sin_port = udp_hdr(skb)->source;
+		else
+			addr->sin_port = 0;
+
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+	} else if (sk->sk_family == AF_INET6) {
+		struct sockaddr_in6 *addr = (struct sockaddr_in6*)myaddress;
+
+		addr->sin6_family = AF_INET6;
+		addr->sin6_flowinfo = 0;
+		addr->sin6_scope_id = 0;
+
+		if (skb->protocol == htons(ETH_P_IP))
+			ipv6_addr_set(&addr->sin6_addr, 0, 0,
+					htonl(0xffff), ip_hdr(skb)->saddr);
+		else {
+			ipv6_addr_copy(&addr->sin6_addr,
+					&ipv6_hdr(skb)->saddr);
+			if (ipv6_addr_type(&addr->sin6_addr) &
+			    IPV6_ADDR_LINKLOCAL)
+				addr->sin6_scope_id = IP6CB(skb)->iif;
+		}
+
+		if (sk->sk_protocol == IPPROTO_UDP ||
+		    sk->sk_protocol == IPPROTO_UDPLITE)
+			addr->sin6_port = udp_hdr(skb)->source;
+		else
+			addr->sin6_port = 0;
+#endif
+	}
+	alf_stat_receivemsg++;
+	return alf_check_policy(ALF_RECVMSG, sk->sk_socket,
+	    (struct sockaddr *)myaddress);
+}
+
+/* Security operations. */
+static struct anoubis_hooks alf_ops = {
+	.version = ANOUBISCORE_VERSION,
+	.socket_connect = alf_socket_connect,
+	.socket_accepted = alf_socket_accepted,
+	.socket_sendmsg = alf_socket_sendmsg,
+	.socket_recvmsg = alf_socket_recvmsg,
+	.socket_skb_recv_datagram = alf_socket_skb_recv_datagram,
+	.anoubis_stats = alf_get_stats,
+};
+
+/* Initialise event device and register with the LSM framework */
+static int __init alf_init(void)
+{
+	int ret;
+	struct timeval tv;
+
+	do_gettimeofday(&tv);
+	alf_stat_loadtime = tv.tv_sec;
+	ret = anoubis_register(&alf_ops, &ac_index);
+	if (ret < 0) {
+		ac_index = -1;
+		printk(KERN_INFO "Failed to register Anoubis ALF\n");
+		return ret;
+	}
+	printk(KERN_INFO "Anoubis ALF module installed\n");
+	return 0;
+}
+
+/* Unregister from LSM framework and remove event device */
+static void __exit alf_exit(void)
+{
+	if (ac_index >= 0)
+		anoubis_unregister(ac_index);
+	printk(KERN_INFO "Anoubis ALF security module removed\n");
+}
+
+module_init(alf_init);
+module_param(allow_ports_min, int, 0444);
+MODULE_PARM_DESC(allow_ports_min,
+    "Start of port range that is excluded from filtering");
+module_param(allow_ports_max, int, 0444);
+MODULE_PARM_DESC(allow_ports_min,
+    "End of port range that is excluded from filtering");
+module_exit(alf_exit);
+
+MODULE_DESCRIPTION("Anoubis ALF module");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/security/anoubis/anoubis_core.c b/security/anoubis/anoubis_core.c
new file mode 100644
index 0000000..9e9dc87
--- /dev/null
+++ b/security/anoubis/anoubis_core.c
@@ -0,0 +1,1747 @@
+/*
+ * Copyright (c) 2008 GeNUA mbH <info@genua.de>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/cred.h>
+#include <linux/dcache.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/rcupdate.h>
+#include <linux/eventdev.h>
+#include <linux/sched.h>
+#include <linux/security.h>
+#include <linux/types.h>
+#include <linux/time.h>
+#include <linux/anoubis.h>
+#include <linux/anoubis_playground.h>
+#include <net/sock.h>
+#include <asm/uaccess.h>
+
+/**
+ * This is the eventdev queue used by the anoubis module to queue events
+ * for user space.
+ *
+ * The anoubis_queue pointer is protected by RCU. Writers must also use the
+ * queuelock. The queue itself is protected by its reference counts. A reader
+ * must read the anoubis_queue pointer _and_ acquire a reference to the queue
+ * within the rcu_read_lock()/rcu_read_unlock() block.
+ */
+static struct eventdev_queue * anoubis_queue;
+
+/**
+ * This lock must be held by writers that want to modify the anoubis_queue
+ * pointer.
+ */
+static spinlock_t queuelock;
+
+/**
+ * The value fo the last task_cookie given out to some running task.
+ * The initial value is zero and will not be used as a task cookie.
+ */
+static anoubis_cookie_t task_cookie;
+
+/**
+ * The last playground ID assigned to some playground. The anoubis daemon
+ * can increase this value if it detects that playgrounds are still active
+ * from before the last system reboot.
+ */
+static anoubis_cookie_t last_pgid;
+
+/**
+ * This lock protects the above values task_cookie and last_pgid.
+ * Atomic types cannot be used because these value must support the full
+ * 64bit range.
+ */
+static spinlock_t task_cookie_lock;
+
+/**
+ * Maximum number of concurrently loaded anoubis sub-modules. This
+ * influences the size of the security labels allocated by anoubis!
+ */
+#define MAX_ANOUBIS_MODULES 10
+
+/**
+ * A serial number that is increased when a new set of security hooks
+ * is registered. The current serial number is stored in the
+ * hook registration and can be used to destinguish outdated security labels
+ * from labels that are still valid.
+ */
+static unsigned int serial = 1;
+
+/**
+ * This flag is used to lock out a new registration from a slot that is
+ * in the process of being unregistred.
+ */
+static char blocked[MAX_ANOUBIS_MODULES];
+
+/**
+ * This arrayy hold the current security hooks for each anoubis sub-module.
+ * The array is protected by rcu. Writers must hold the hooks_lock, too.
+ * Additionally, the hooks structures themselves use a reference counter that
+ * prevents modules from being unloaded while hooks from that module are
+ * still running.
+ */
+static struct anoubis_hooks * hooks[MAX_ANOUBIS_MODULES];
+
+/**
+ * This lock protects the hooks array. It must be held during modifications.
+ * Readers can rely on RCU alone.
+ */
+static spinlock_t hooks_lock = SPIN_LOCK_UNLOCKED;
+
+/* Module stacking. */
+extern struct security_operations * security_ops;
+static struct security_operations * original_ops;
+
+/**
+ * This is the generic security label used by anoubis. Each sub-module
+ * requests a slot (between zero and MAX_ANOUBIS_MODULES-1). The module
+ * passes this slot to the accessor function (anoubis_(get|set)_sublabel).
+ *
+ * Fields:
+ * label_lock: This protects access to the other fields of this label.
+ * labels: The security labels of individual sub-modules are stored
+ *     in this array.
+ * magic: When a label is allocated, the magic number from the hooks
+ *     structure of the module's slot is stored in the respective field
+ *     of this array. Subsequent accesses to the label will return a NULL
+ *     label if the magic number stored in the label differs from that of
+ *     hooks that are active in the corresponding slot.
+ */
+struct anoubis_label {
+	spinlock_t label_lock; /* XXX Use RCU? */
+	void * labels[MAX_ANOUBIS_MODULES];
+	unsigned int magic[MAX_ANOUBIS_MODULES];
+};
+
+/**
+ * This is an extension of the anoubis_label structure that is used for
+ * labels on task credentials. This is neccessary because the basic task
+ * tracking infrastructure is provided by anobuis_core and not by a
+ * sub-module.
+ *
+ * Fields.
+ * _l: The anoubis_label structure. This must be first to make sure that
+ *     the label can be cast to an anoubis_label.
+ * task_cookie: The task cookie of the task.
+ * listener: True if the task it the process that listens on the
+ *     anoubis_queue for events. anoubis_raise will turn ask events for
+ *     a listener process into notifications.
+ */
+struct anoubis_cred_label {
+	struct anoubis_label	_l;
+	anoubis_cookie_t	task_cookie;
+	unsigned int		listener:1;
+};
+
+/**
+ * Get the credentials label associated with the current task.
+ *
+ * @param None.
+ * @return The creditials label of the current task or NULL.
+ */
+static struct anoubis_cred_label * ac_current_label(void)
+{
+	const struct cred * cred = __task_cred(current);
+	if (unlikely(cred == NULL))
+		return NULL;
+	return cred->security;
+}
+
+/**
+ * Return the task cookie of the current task. The task cookie is an
+ * integer value that uniquely identifies a process during system uptime.
+ * Task cookies are not reused after a process exits.
+ *
+ * @param None.
+ * @return The task cookie.
+ */
+anoubis_cookie_t anoubis_get_task_cookie(void)
+{
+	struct anoubis_cred_label *cred = ac_current_label();
+
+	if (unlikely(!cred))
+		return 0;
+	return cred->task_cookie;
+}
+
+/**
+ * Return true if the current process is an anoubis listener process, i.e.
+ * it is listening for events on the anoubis queue.
+ *
+ * @param None.
+ * @return True if the process is a listener.
+ */
+int anoubis_is_listener(void)
+{
+	struct anoubis_cred_label * tsec = ac_current_label();
+
+	if (unlikely(tsec == NULL))
+		return 0;
+	if (unlikely(tsec->listener))
+		return 1;
+	return 0;
+}
+
+/**
+ * Send an anoubis event to the current anoubis queue and deal with all
+ * kinds of failures. This function assumes that the message in buf starts
+ * with an struct anoubis_event_common and this structure is filled in
+ * by this function.
+ *
+ * @param buf The message to send (without the eventdev_hdr).
+ * @param len The length of the message.
+ * @param src This value identies the module that is the source of the
+ *     message. It can be used by user space to determine the format of
+ *     the message.
+ * @param wait True if the event expects an answer and the process should
+ *     be blocked until the answer is received.
+ * @param flags The answer from user space can contain an error code and
+ *     additional flags. If the caller is interested in flags it must pass
+ *     and integer pointer here where flags will be returned. If this
+ *     value is NULL, flags are discarded.
+ * @param gpf The memory allocation mode to use for any memory allocations
+ *     that might be needed.
+ * @return A negative error code indicate that the event should be denied.
+ *     It can be due to either a failure when queueing the message or due to
+ *     a reply to the event. The special error code -EPIPE is only sent,
+ *     if no anoubis queue is available to queue the message at this time.
+ *     Zero indicates that the event was successfully sent and should be
+ *     allowed. If wait is false there is no answer from user space, i.e.
+ *     in this case error returns always indicate a failure to queue the
+ *     message.
+ *
+ * NOTE: The function return does not destinguish between an error returned
+ *     from user space and a failure to queue the message. However, this
+ *     function will unregister and drop the current queue if it failed to
+ *     queue the message on an existing queue.
+ */
+static int __anoubis_event_common(void * buf, size_t len, int src, int wait,
+    int *flags, gfp_t gfp)
+{
+	int put, err, ret = 0;
+	struct eventdev_queue * q;
+	struct anoubis_cred_label * sec = ac_current_label();
+	struct anoubis_event_common * common = buf;
+
+	BUG_ON(len < sizeof(struct anoubis_event_common));
+	if (likely(sec)) {
+		common->task_cookie = sec->task_cookie;
+	} else {
+		common->task_cookie = 0;
+	}
+	common->pgid = anoubis_get_playgroundid();
+	if (flags)
+		(*flags) = 0;
+	rcu_read_lock();
+	q = rcu_dereference(anoubis_queue);
+	if (q)
+		__eventdev_get_queue(q);
+	rcu_read_unlock();
+	if (!q) {
+		kfree(buf);
+		return -EPIPE;
+	}
+	if (wait) {
+		err = eventdev_enqueue_wait(q, src, buf, len, &ret, gfp);
+	} else {
+		err = eventdev_enqueue_nowait(q, src, buf, len, gfp);
+	}
+	if (!err) {
+		/* daemon replies returned via eventdev_wait are
+		 * negative (or 0 if no flags are set) */
+		if (ret < 0) {
+			if (flags)
+				*flags = ANOUBIS_RET_FLAGS(-ret);
+			ret = -(ANOUBIS_RET_CLEAN(-ret));
+		}
+		/* EPIPE is reserved for "no queue" */
+		if (ret == -EPIPE)
+			ret = -EIO;
+		goto out;
+	}
+	ret = -EIO;
+	if (err != -EPIPE) {
+		printk (KERN_ERR "Cannot queue message: errno = %d\n", -err);
+		goto out;
+	}
+	ret = -EPIPE;
+	put = 0;
+	spin_lock_bh(&queuelock);
+	if (anoubis_queue == q) {
+		put = 1;
+		rcu_assign_pointer(anoubis_queue, NULL);
+	}
+	spin_unlock_bh(&queuelock);
+	if (put)
+		eventdev_put_queue(q);
+	call_rcu(eventdev_rcu_head(q), eventdev_rcu_put);
+	return ret;
+out:
+	eventdev_put_queue(q);
+	return ret;
+}
+
+/**
+ * Send an event to the anoubis queue without expecting an answer from
+ * user space (notification).
+ *
+ * @param buf The event data.
+ * @param len The length of the event.
+ * @param src The source indication of the event.
+ * @return Zero in case of success, a negative error code if an error
+ *     occured.
+ *
+ * NOTE: This function is a wrapper around __anoubis_event_common.
+ */
+int anoubis_notify(void * buf, size_t len, int src)
+{
+	might_sleep();
+	return __anoubis_event_common(buf, len, src, 0, NULL, GFP_KERNEL);
+}
+
+/**
+ * Send an event to the anoubis queue without expecting an answer from
+ * user space (notification). The only difference to anoubis_notify is that
+ * this function will not sleep.
+ *
+ * @param buf The event data.
+ * @param len The length of the event.
+ * @param src The source indication of the event.
+ * @return Zero in case of success, a negative error code if an error
+ *     occured.
+ *
+ * NOTE: This function is a wrapper around __anoubis_event_common.
+ */
+int anoubis_notify_atomic(void * buf, size_t len, int src)
+{
+	return __anoubis_event_common(buf, len, src, 0, NULL, GFP_NOWAIT);
+}
+
+/**
+ * Send an event to the anoubis queue that must be answered by the anoubis
+ * daemon. Flags in the reply to the event are dicarded by this function.
+ * This function will always sleep!
+ *
+ * @param buf The event data.
+ * @param len The length of the event.
+ * @param src The source indication of the event.
+ * @return Zero in case of success, a negative error code if an error
+ *     occured.
+ *
+ * NOTE: This function is a wrapper around __anoubis_event_common.
+ */
+int anoubis_raise(void * buf, size_t len, int src)
+{
+	int wait = 1;
+	struct anoubis_cred_label * sec = ac_current_label();
+	if (likely(sec)) {
+		if (unlikely(sec->listener))
+			wait = 0;
+	}
+	return __anoubis_event_common(buf, len, src, wait, NULL, GFP_KERNEL);
+}
+
+/**
+ * Send an event to the anoubis queue that must be answered by the anoubis
+ * daemon. This function will always sleep!
+ *
+ * @param buf The event data.
+ * @param len The length of the event.
+ * @param src The source indication of the event.
+ * @param flags Any flags that might be part of the reply to the event
+ *     are returned in the integer pointed to by this parameter.
+ * @return Zero in case of success, a negative error code if an error
+ *     occured.
+ *
+ * NOTE: This function is a wrapper around __anoubis_event_common.
+ */
+int anoubis_raise_flags(void * buf, size_t len, int src, int *flags)
+{
+	int wait = 1;
+	struct anoubis_cred_label * sec = ac_current_label();
+	if (likely(sec)) {
+		if (unlikely(sec->listener))
+			wait = 0;
+	}
+	return __anoubis_event_common(buf, len, src, wait, flags, GFP_KERNEL);
+}
+
+/**
+ * This function queries all anoubis modules for the current value
+ * of their statistics counters. The data is collected and combined into
+ * a notification event that is sent to the anoubis queue.
+ *
+ * @param None.
+ * @return Zero in case of success, a negative error code if an error
+ *     occured.
+ */
+static int ac_stats(void)
+{
+	int total, alloctotal, sz, pos, i,j;
+	struct anoubis_internal_stat_value * stat;
+	struct anoubis_stat_message * data = NULL;
+
+	/*
+	 * Phase 1: Just count the number of entries.
+	 * Phase 2: Allocate memory and retry
+	 * Phase 3: Recount elements and fill them in as long as they fit.
+	 *     If this fails free memory and retry. Otherwise raise event.
+	 */
+	alloctotal = 0;
+retry:
+	total = 0;
+	pos = 0;
+	spin_lock(&hooks_lock);
+	for(i=0; i<MAX_ANOUBIS_MODULES; ++i) {
+		int cnt;
+		if (hooks[i] && hooks[i]->anoubis_stats) {
+			hooks[i]->anoubis_stats(&stat, &cnt);
+			total += cnt;
+			if (!data)
+				continue;
+			if (total > alloctotal)
+				break;
+			for(j=0; j<cnt; j++,pos++) {
+				data->vals[pos].subsystem = stat[j].subsystem;
+				data->vals[pos].key = stat[j].key;
+				data->vals[pos].value = *(stat[j].valuep);
+			}
+		}
+	}
+	/* Previous run returned different number of elements. */
+	spin_unlock(&hooks_lock);
+	if (data && (total > alloctotal)) {
+		kfree(data);
+		data = NULL;
+		alloctotal = 0;
+		goto retry;
+	}
+	/* Calculate size of message */
+	sz = sizeof(struct anoubis_stat_message)
+	    + total * sizeof(struct anoubis_stat_value);
+	/* If memory is not yet allocated, do it now and retry. */
+	if (data == NULL) {
+		alloctotal = total;
+		data = kmalloc(sz, GFP_KERNEL);
+		if (!data)
+			return -ENOMEM;
+		goto retry;
+	}
+	/* Message is complete. Send it. */
+	return anoubis_notify(data, sz, ANOUBIS_SOURCE_STAT);
+}
+
+/**
+ * Calculate and return the anoubis checksum (sha256) for a file.
+ * This function queries all sub-modules for an anoubis_getsum function.
+ * The first of these functions is called and the result is returned.
+ *
+ * @param file The file to checksum.
+ * @param csum The checksum is returned in this buffer. The caller must
+ *     provide enough memory to hold a binary representation of a
+ *     sha256 checksum.
+ * @return Zero in case of success, a negative error code in case of
+ *     an error.
+ */
+static int ac_getcsum(struct file * file, u8 * csum)
+{
+	int i;
+	int ret = -ENOSYS;
+	struct anoubis_hooks * h = NULL;
+	int (*func)(struct file *, u8 *) = NULL;
+
+	rcu_read_lock();
+	for(i=0; i<MAX_ANOUBIS_MODULES; ++i) {
+		h = rcu_dereference(hooks[i]);
+		if (h && h->anoubis_getcsum) {
+			atomic_inc(&h->refcount);
+			func = h->anoubis_getcsum;
+			break;
+		}
+	}
+	rcu_read_unlock();
+	if (!h)
+		return -ENOSYS;
+	ret = (*func)(file, csum);
+	atomic_dec(&h->refcount);
+	return ret;
+}
+
+/**
+ * This function implements the device open hook for the anoubis device.
+ * No special setup is required.
+ *
+ * @param inode The inode of the device.
+ * @param file The file that is being opened.
+ * @return Zero (success).
+ */
+static int anoubis_open(struct inode * inode, struct file * file)
+{
+	file->private_data = NULL;
+	return 0;
+}
+
+/**
+ * This function implements the device ioctl hook for the anoubis device.
+ * This hook can be used as an unlocked_ioctl, i.e. it does not depend
+ * on the caller to hold the BKL.
+ *
+ * @param file The device file that is ioctl'ed.
+ * @param cmd The ioctl command.
+ * @param arg The ioctl argument.
+ */
+static long anoubis_ioctl(struct file * file, unsigned int cmd,
+			       unsigned long arg)
+{
+	struct eventdev_queue * q;
+	struct file * eventfile;
+	struct anoubis_cred_label * sec;
+	int ret;
+
+	/* For now only root is allowed to do declare a queue or a listener. */
+	switch(cmd) {
+	case ANOUBIS_DECLARE_LISTENER:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		eventfile = fget(arg);
+		if (!eventfile)
+			return -EBADF;
+		q = eventdev_get_queue(eventfile);
+		fput(eventfile);
+		if (!q)
+			return -EPERM;
+		if (rcu_dereference(anoubis_queue) != q) {
+			eventdev_put_queue(q);
+			return -EPERM;
+		}
+		eventdev_put_queue(q);
+		sec = ac_current_label();
+		if(unlikely(!sec))
+			return -EINVAL;
+		sec->listener = 1;
+		break;
+	case ANOUBIS_DECLARE_FD:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		eventfile = fget(arg);
+		if (!eventfile)
+			return -EBADF;
+		q = eventdev_get_queue(eventfile);
+		fput(eventfile);
+		if (!q)
+			return -EINVAL;
+		spin_lock_bh(&queuelock);
+		if (anoubis_queue == NULL) {
+			rcu_assign_pointer(anoubis_queue, q);
+			q = NULL;
+		}
+		spin_unlock_bh(&queuelock);
+		synchronize_rcu();
+		if (q) {
+			eventdev_put_queue(q);
+			return -EBUSY;
+		}
+		break;
+	case ANOUBIS_UNDECLARE_FD:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		eventfile = fget(arg);
+		if (!eventfile)
+			return -EBADF;
+		q = eventdev_get_queue(eventfile);
+		fput(eventfile);
+		if (!q)
+			return -EINVAL;
+		ret = -EBADF;
+		spin_lock_bh(&queuelock);
+		if (anoubis_queue == q) {
+			rcu_assign_pointer(anoubis_queue, NULL);
+			eventdev_put_queue(q);
+			ret = 0;
+		}
+		spin_unlock_bh(&queuelock);
+		synchronize_rcu();
+		eventdev_put_queue(q);
+		return ret;
+	case ANOUBIS_REQUEST_STATS:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		return ac_stats();
+	case ANOUBIS_OLD_REPLACE_POLICY:
+		{
+			static int do_print = 1;
+			if (do_print) {
+				do_print = 0;
+				printk(KERN_INFO "Old POLICY_REPLACE ioctl no "
+				    "longer supported. Update your anoubisd\n");
+			}
+		}
+		return 0;
+	case ANOUBIS_GETVERSION:
+		{
+			unsigned long version = ANOUBISCORE_VERSION;
+			if (unlikely(!arg))
+				return -EINVAL;
+			if (copy_to_user((void __user *)arg, &version,
+			    sizeof(version)))
+				return -EFAULT;
+			break;
+		}
+	case ANOUBIS_GETCSUM:
+		{
+			struct anoubis_ioctl_csum __user *cs;
+			int fd;
+			u8 csum[ANOUBIS_CS_LEN];
+			struct file * csfile;
+
+			cs = (void __user *)arg;
+			if (copy_from_user(&fd, &cs->fd, sizeof(fd)))
+				return -EFAULT;
+			csfile = fget(fd);
+			if (!csfile)
+				return -EBADF;
+			ret = ac_getcsum(csfile, csum);
+			fput(csfile);
+			if (ret < 0)
+				return ret;
+			if (copy_to_user(&cs->csum, csum, ANOUBIS_CS_LEN))
+				return -EFAULT;
+			return 0;
+		}
+	case ANOUBIS_CREATE_PLAYGROUND:
+		/* arg == 1 means rename an existing playground only. */
+		if (arg != 0 && arg != 1)
+			return -EINVAL;
+		return anoubis_playground_create(arg);
+	case ANOUBIS_SET_LASTPGID:
+		{
+			struct anoubis_ioctl_lastpgid __user *uptr;
+			struct anoubis_ioctl_lastpgid lastpgid;
+
+			if (!capable(CAP_SYS_ADMIN))
+				return -EPERM;
+			uptr = (void __user *)arg;
+			if (copy_from_user(&lastpgid, uptr, sizeof(lastpgid)))
+				return -EFAULT;
+			eventfile = fget(lastpgid.fd);
+			if (!eventfile)
+				return -EBADF;
+			q = eventdev_get_queue(eventfile);
+			fput(eventfile);
+			spin_lock(&task_cookie_lock);
+			ret = -EPERM;
+			if (q == rcu_dereference(anoubis_queue)) {
+				ret = -ERANGE;
+				if (lastpgid.lastpgid > last_pgid) {
+					last_pgid = lastpgid.lastpgid;
+					ret = 0;
+				}
+			}
+			spin_unlock(&task_cookie_lock);
+			eventdev_put_queue(q);
+			return ret;
+		}
+	case ANOUBIS_SCAN_STARTED:
+	case ANOUBIS_SCAN_SUCCESS:
+		{
+			struct file *scanfile;
+			if (!capable(CAP_SYS_ADMIN) || !anoubis_is_listener())
+				return -EPERM;
+			if (anoubis_get_playgroundid())
+				return -EPERM;
+			scanfile = fget(arg);
+			if (!scanfile)
+				return -EBADF;
+			if (cmd == ANOUBIS_SCAN_STARTED)
+				ret = anoubis_playground_scanstarted(scanfile);
+			else
+				ret = anoubis_playground_scansuccess(scanfile);
+			fput(scanfile);
+			return ret;
+		}
+	default:
+		return -EINVAL;
+	}
+	return 0;
+};
+
+/**
+ * This structure is used by the miscdevice driver to implement the
+ * anoubis device. The anoubis device only supports ioctls.
+ */
+static struct file_operations anoubis_fops = {
+	.owner		= THIS_MODULE,
+	.open		= anoubis_open,
+	.unlocked_ioctl	= anoubis_ioctl,
+};
+
+/**
+ * This structure describes the anoubis device to the miscdevice driver.
+ * The device will be called "anoubis" in the dev file system.
+ */
+static struct miscdevice anoubis_device = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "anoubis",
+	.fops	= &anoubis_fops,
+};
+
+/**
+ * This lock protects "late" anoubis label allocations. Normally, the
+ * anoubis label should be allocated in the appropriate security hook.
+ * However, with removable modules it is possible that some objects that
+ * should already have a label do not yet have one. This lock protects
+ * concurrent allocations of this type against each other.
+ */
+static spinlock_t late_alloc_lock = SPIN_LOCK_UNLOCKED;
+
+/**
+ * Allocate an anoubis security label and initialize it.
+ *
+ * @param gfp The memory allocation mode to use for the allocation.
+ * @param len The length of the label. This should usually be
+ *     the size of an anobuis_label structure but might be large e.g.
+ *     for task labels.
+ * @return The initialized label of NULL if an error occured.
+ */
+static void * __ac_alloc_label(gfp_t gfp, size_t len)
+{
+	int i;
+	struct anoubis_label * sec;
+
+	sec = kmalloc(len, gfp);
+	if (!sec)
+		return NULL;
+	spin_lock_init(&sec->label_lock);
+	for (i=0; i<MAX_ANOUBIS_MODULES; ++i) {
+		sec->magic[i] = 0;
+		sec->labels[i] = NULL;
+	}
+	return sec;
+}
+
+/**
+ * Allocate an anoubis security label and initialize it.
+ *
+ * @param gfp The memory allocation mode to use for the allocation.
+ * @return The initialized label of NULL if an error occured.
+ */
+static struct anoubis_label * ac_alloc_label(gfp_t gfp)
+{
+	return __ac_alloc_label(gfp, sizeof(struct anoubis_label));
+}
+
+/**
+ * Return the modul specific sub-label from a label. The module's slot
+ * is given in idx. This function allocates a new anoubis label if non
+ * exists. The current hooks must use the same magic number as the
+ * magic number stored in the label. If this is not the case, NULL
+ * is returned. This ensures that a module does not get label data
+ * in the format of another module that previously used the same slot.
+ *
+ * @param lp The location of the label pointer. If anoubis label is
+ *     allocated, it is stored in *lp.
+ * @param idx The slot number of the module requesting its sub-label.
+ * @return The sub-label or NULL (e.g. if the magic numbers do not match).
+ */
+void * anoubis_get_sublabel(void ** lp, int idx)
+{
+	struct anoubis_label * l = (*lp);
+	unsigned long flags;
+
+	if (unlikely(!l)) {
+		l = ac_alloc_label(GFP_ATOMIC);
+		if (unlikely(!l))
+			return NULL;
+		spin_lock_irqsave(&late_alloc_lock, flags);
+		if (unlikely(*lp)) {
+			kfree(l);
+			l = (*lp);
+		} else {
+			(*lp) = l;
+		}
+		spin_unlock_irqrestore(&late_alloc_lock, flags);
+	}
+	return anoubis_get_sublabel_const(l, idx);
+}
+
+/**
+ * This function is a faster replacement for anoubis_get_sublabel that
+ * can be used iff the label is already allocated. The main reason for
+ * the existence of this function is a security label pointer embedded
+ * in a const data structure.
+ *
+ * @param lv A pointer to the anoubis label.
+ * @param idx The slot number of the module requesting its sub-label.
+ * @return The sub-label or NULL (e.g. if the magic numbers do not match).
+ */
+void * anoubis_get_sublabel_const(void *lv, int idx)
+{
+	struct anoubis_label * l = lv;
+	void * ret = NULL;
+	struct anoubis_hooks * h;
+	unsigned long flags;
+
+	spin_lock_irqsave(&l->label_lock, flags);
+	if (l->labels[idx] == NULL)
+		goto out;
+
+	rcu_read_lock();
+	h = rcu_dereference(hooks[idx]);
+	if (!h || (l->magic[idx] != h->magic)) {
+		rcu_read_unlock();
+		goto out;
+	}
+	rcu_read_unlock();
+	ret = l->labels[idx];
+out:
+	spin_unlock_irqrestore(&l->label_lock, flags);
+	return ret;
+}
+
+/**
+ * Modify the sub-label in an anoubis label. The anoubis label is
+ * allocated if it is currently NULL. This function sets the magic
+ * number for the slot to the value obtained from the hooks in the
+ * slot.
+ *
+ * @param lp The location of the pointer to the anoubis label.
+ *     The pointer to the label itself is *lp.
+ * @param idx The slot number of the module requesting to change its
+ *     sub-label.
+ * @param subl The new value of the sub-label.
+ * @return The old value of the sub-label (as it would have been returned
+ *     by anoubis_get_sublabel).
+ */
+void * anoubis_set_sublabel(void ** lp, int idx, void * subl)
+{
+	void * old = NULL;
+	struct anoubis_label * l = (*lp);
+	struct anoubis_hooks * h;
+	unsigned long flags;
+
+	if (unlikely(!l)) {
+		l = ac_alloc_label(GFP_ATOMIC);
+		BUG_ON(!l);
+		spin_lock_irqsave(&late_alloc_lock, flags);
+		if (unlikely(*lp)) {
+			kfree(l);
+			l = (*lp);
+		} else {
+			(*lp) = l;
+		}
+		spin_unlock_irqrestore(&late_alloc_lock, flags);
+	}
+	rcu_read_lock();
+	h = rcu_dereference(hooks[idx]);
+	/*
+	 * This case is very rare. Not much we can do actually. However,
+	 * it is in theory possible that hooks are unregistered while a
+	 * hook is running and this hook can legally see h == NULL
+	 */
+	if (!h) {
+		rcu_read_unlock();
+		return NULL;
+	}
+	spin_lock_irqsave(&l->label_lock, flags);
+	if (l->magic[idx] == h->magic)
+		old = l->labels[idx];
+	else
+		l->magic[idx] = h->magic;
+	l->labels[idx] = subl;
+	spin_unlock_irqrestore(&l->label_lock, flags);
+	rcu_read_unlock();
+	return old;
+}
+
+/**
+ * Deny write access to the file. Trying to open it for writing will
+ * result in -ETXTBUSY. This simply exports the core's deny_write_access
+ * function to anoubis sub-modules.
+ *
+ * @param inode The inode.
+ * @return Zero in case of success, -ETXTBUSY otherwise.
+ */
+int anoubis_deny_write_access(struct file *file)
+{
+	return deny_write_access(file);
+}
+
+/**
+ * Allow write access after a successful call to anoubis_deny_write_access.
+ * This simply exports the core's allow_write_access function to anoubis
+ * sub-modules.
+ *
+ * @param inode The inode.
+ * @return Zero in case of success, -ETXTBUSY otherwise.
+ */
+void anoubis_allow_write_access(struct file *file)
+{
+	allow_write_access(file);
+}
+
+/**
+ * Register a new set of anoubis hooks from a sub-module.
+ *
+ * This is difficult because the hooks might be called immediately after
+ * we insert the hooks. This may be before the module knows its index. In
+ * this case the module has no access to its label from the hooks. To avoid
+ * this we first store the (predicted) index of the new module
+ * in (*idx_ptr). The synchronize_rcu() call ensures that all CPUs actually
+ * see the new index value. Only after we know that this is the case we
+ * actually enable the new hooks.
+ * As we drop the hooks_lock during synchronize_rcu() we must make sure
+ * that the new index is still availiable after we reacquire the spinlock.
+ *
+ * @param newhooks The new anoubis hooks. The magic value of the hooks
+ *     structure is set to a new value determined from the serial counter
+ *     defined above.
+ * @param idx_ptr The slot allocated for the module is stored the location
+ *     pointed to be idx_ptr. It is guaranteed that all CPUs see this
+ *     store before the hooks are first called.
+ * @return Zero in case of success, a negative error code in case of an
+ *     error.
+ */
+int anoubis_register(struct anoubis_hooks * newhooks, int * idx_ptr)
+{
+	int k, ret = -ESRCH;
+	struct anoubis_hooks * ourhooks;
+
+	if (newhooks->version != ANOUBISCORE_VERSION)
+		return -EINVAL;
+	ourhooks = kmalloc(sizeof(struct anoubis_hooks), GFP_KERNEL);
+	if (!ourhooks)
+		return -ENOMEM;
+	*ourhooks = *newhooks;
+	atomic_set(&ourhooks->refcount, 0);
+retry:
+	spin_lock(&hooks_lock);
+	for (k=0; k<MAX_ANOUBIS_MODULES; ++k) {
+		if (hooks[k] == NULL && blocked[k] == 0) {
+			(*idx_ptr) = k;
+			spin_unlock(&hooks_lock);
+			synchronize_rcu();
+			spin_lock(&hooks_lock);
+			if (hooks[k]) {
+				spin_unlock(&hooks_lock);
+				goto retry;
+			}
+			ourhooks->magic = serial;
+			serial++;
+			if (unlikely(!serial))
+				printk(KERN_INFO "anoubis_core: "
+				    "Serial number overflow\n");
+			rcu_assign_pointer(hooks[k], ourhooks);
+			ret = 0;
+			break;
+		}
+	}
+	spin_unlock(&hooks_lock);
+	if (ret < 0)
+		kfree(ourhooks);
+	synchronize_rcu();
+	return ret;
+};
+
+/**
+ * Unregister a set of security hooks. This is a dangerous operation and
+ * should only be used for debugging purposes. The reason is that the
+ * hooks in the module are the only way to free sub-labels allocated by
+ * the sub-module. Once these hooks are deregisted there is no way to
+ * recover this memory.
+ *
+ * @param idx The slot of the module. It is guaranteed that all
+ *     hooks that are currently running terminate before this function
+ *     returns. This is achieved by waiting for the reference count of
+ *     the hooks structure to become zero.
+ * @return None.
+ */
+void anoubis_unregister(int idx)
+{
+	struct anoubis_hooks * old;
+	BUG_ON(idx < 0 || idx >= MAX_ANOUBIS_MODULES);
+	spin_lock(&hooks_lock);
+	BUG_ON(!hooks[idx]);
+	blocked[idx] = 1;
+	old = rcu_dereference(hooks[idx]);
+	rcu_assign_pointer(hooks[idx], NULL);
+	spin_unlock(&hooks_lock);
+	synchronize_rcu();
+	if (old) {
+		while(atomic_read(&old->refcount)) {
+			schedule_timeout_interruptible(HZ);
+			synchronize_rcu();
+		}
+		kfree(old);
+	}
+	spin_lock(&hooks_lock);
+	blocked[idx] = 0;
+	spin_unlock(&hooks_lock);
+}
+
+/**
+ * This is a helper macro that calls a particular hook in all available
+ * sub-modules that are currenty registered. If any module returns
+ * non-zero the macro will return the error value. If multiple hooks
+ * return an error the hook with the highest magic number wins.
+ * All available hooks are called, even if some of them return errors.
+ * The macro hold a reference counter to the hooks structure but no
+ * other locks while the hook is running.
+ *
+ * @param FUNC The name of the hook.
+ * @param ARGS The argument list for the hook (including parentheses).
+ * @param ORIGMAGIC The magic number in the hooks structure determines
+ *     the priority of the error codes returned by individual modules.
+ *     This parameter can be used to modify the magic code of the
+ *     original_ops operations (aka capability). Use zero her unless you
+ *     have some compelling reason to do this differently.
+ * @return Zero if all hooks returned zero, an error code if at least one
+ *     hook returned an error.
+ */
+#define __HOOKS(FUNC, ARGS, ORIGMAGIC) ({			\
+	int i;							\
+	int ret = 0, ret2;					\
+	unsigned int mymagic, lastmagic = (ORIGMAGIC);		\
+	if (original_ops->FUNC)					\
+		ret = original_ops->FUNC ARGS;			\
+	for(i=0; i<MAX_ANOUBIS_MODULES; ++i) {			\
+		typeof(hooks[i]->FUNC) _func;			\
+		struct anoubis_hooks * h;			\
+		rcu_read_lock();				\
+		h = rcu_dereference(hooks[i]);			\
+		if (h && h->FUNC) {				\
+			_func = h->FUNC;			\
+			mymagic = h->magic;			\
+			atomic_inc(&h->refcount);		\
+			rcu_read_unlock();			\
+			ret2 = (*_func) ARGS ;			\
+			atomic_dec(&h->refcount);		\
+			if (!ret2)				\
+				continue;			\
+			if (!ret || lastmagic > mymagic) {	\
+				ret = ret2;			\
+				lastmagic = mymagic;		\
+			}					\
+		} else {					\
+			rcu_read_unlock();			\
+		}						\
+	}							\
+	ret;							\
+});
+
+/**
+ * The same as __HOOKS except that teh ORIGMAGIC parameter is set to
+ * zero explicitly.
+ */
+#define HOOKS(FUNC,ARGS)	__HOOKS(FUNC, ARGS, 0)
+
+
+/**
+ * This is a helper macro that calls a particular hook in all available
+ * sub-modules that are currenty registered. The hook must have a return
+ * type of void. The macro hold a reference counter to the hooks structure
+ * but no other locks while the hook is running.
+ *
+ * @param FUNC The name of the hook.
+ * @param ARGS The argument list for the hook (including parentheses).
+ * @return None.
+ */
+#define VOIDHOOKS(FUNC, ARGS) do {				\
+	int i;							\
+	if (original_ops)					\
+		original_ops->FUNC ARGS;			\
+	for(i=0; i<MAX_ANOUBIS_MODULES; ++i) {			\
+		typeof(hooks[i]->FUNC) _func;			\
+		struct anoubis_hooks * h;			\
+		rcu_read_lock();				\
+		h = rcu_dereference(hooks[i]);			\
+		if (h && h->FUNC) {				\
+			_func = hooks[i]->FUNC;			\
+			atomic_inc(&h->refcount);		\
+			rcu_read_unlock();			\
+			_func ARGS ;				\
+			atomic_dec(&h->refcount);		\
+		} else {					\
+			rcu_read_unlock();			\
+		}						\
+	}							\
+} while(0)
+
+/* Implementation of security hooks */
+static int ac_unix_stream_connect(struct socket *sock, struct socket *other,
+    struct sock *newsk)
+{
+	return HOOKS(unix_stream_connect, (sock, other, newsk));
+}
+static int ac_socket_post_create(struct socket *sock, int family, int type,
+    int protocol, int kern)
+{
+	return HOOKS(socket_post_create, (sock, family, type, protocol, kern));
+}
+static int ac_socket_connect(struct socket * sock, struct sockaddr * address,
+    int addrlen)
+{
+	return HOOKS(socket_connect, (sock, address, addrlen));
+}
+static int ac_socket_accepted(struct socket * sock, struct socket * newsock)
+{
+	return HOOKS(socket_accepted, (sock, newsock));
+}
+static int ac_socket_sendmsg(struct socket * sock, struct msghdr * msg,
+    int size)
+{
+	return HOOKS(socket_sendmsg, (sock, msg, size));
+}
+static int ac_socket_recvmsg(struct socket * sock, struct msghdr * msg,
+    int size, int flags)
+{
+	return HOOKS(socket_recvmsg, (sock, msg, size, flags));
+}
+static int ac_socket_skb_recv_datagram(struct sock * sk, struct sk_buff * skb)
+{
+	return HOOKS(socket_skb_recv_datagram, (sk, skb));
+}
+static int ac_sk_alloc(struct sock *sk, int family, gfp_t priority)
+{
+	if ((sk->sk_security = ac_alloc_label(priority)) == NULL)
+		return -ENOMEM;
+	return HOOKS(sk_alloc_security, (sk, family, priority));
+}
+static void ac_sk_free(struct sock *sk)
+{
+	if (!sk->sk_security)
+		return;
+	VOIDHOOKS(sk_free_security, (sk));
+	kfree(sk->sk_security);
+	sk->sk_security = NULL;
+}
+
+/* INODE */
+static int ac_inode_alloc_security(struct inode * inode)
+{
+	if ((inode->i_security = ac_alloc_label(GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+	return HOOKS(inode_alloc_security, (inode));
+}
+static void ac_inode_free_security(struct inode * inode)
+{
+	if (!inode->i_security)
+		return;
+	VOIDHOOKS(inode_free_security, (inode));
+	kfree(inode->i_security);
+	inode->i_security = NULL;
+}
+static int ac_inode_permission(struct inode * inode, int mask)
+{
+	return HOOKS(inode_permission, (inode, mask));
+}
+static int ac_inode_create(struct inode *dir, struct dentry *dentry, int mode)
+{
+	return HOOKS(inode_create, (dir, dentry, mode));
+}
+static int ac_inode_mknod(struct inode *dir, struct dentry *dentry, int mode,
+								dev_t dev)
+{
+	return HOOKS(inode_mknod, (dir, dentry, mode, dev));
+}
+static int ac_inode_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+	return HOOKS(inode_mkdir, (dir, dentry, mode));
+}
+static int ac_inode_link(struct dentry *old_dentry, struct inode *dir,
+						struct dentry *new_dentry)
+{
+	return HOOKS(inode_link, (old_dentry, dir, new_dentry));
+}
+static int ac_inode_symlink(struct inode *dir, struct dentry *new_dentry,
+    const char *oldname)
+{
+	return HOOKS(inode_symlink, (dir, new_dentry, oldname));
+}
+static int ac_inode_unlink(struct inode *dir, struct dentry *dentry)
+{
+	return HOOKS(inode_unlink, (dir, dentry));
+}
+static int ac_inode_rmdir(struct inode *dir, struct dentry *dentry)
+{
+	return HOOKS(inode_rmdir, (dir, dentry));
+}
+static int ac_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
+			struct inode *new_dir, struct dentry *new_dentry)
+{
+	return HOOKS(inode_rename, (old_dir, old_dentry, new_dir, new_dentry));
+}
+static int ac_inode_readlink(struct dentry *dentry)
+{
+	return HOOKS(inode_readlink, (dentry));
+}
+static int ac_inode_setxattr(struct dentry * dentry, const char * name,
+    const void * value, size_t size, int flags)
+{
+	return HOOKS(inode_setxattr, (dentry, name, value, size, flags));
+}
+/*
+ * NOTE: We use __HOOKS with a very low priority for the capability hook.
+ * NOTE: This is neccessary to make sure that user space sees an appropriate
+ * NOTE: error code in playground commit. Otherwise, the EINPROGRESS or EBUSY
+ * NOTE: would be will overruled by the EPERM returned from the capability
+ * NOTE: hook in original_ops.
+ */
+static int ac_inode_removexattr(struct dentry *dentry, const char *name)
+{
+	return __HOOKS(inode_removexattr, (dentry, name), (unsigned int)-1);
+}
+
+/**
+ * Implementation of the inode_init_security hook.
+ *
+ * This function has special error code conventions:
+ *   . Zero: An extended Attribute (name/value) was assigned.
+ *   . -EOPNOTSUPP: This hook does not want to set extended attributes.
+ *   . Other < 0: A real error occured.
+ *
+ * We use a modified version of the code in the HOOKS macro to
+ * deal with this properly:
+ * - If any hook returns a real error (not -EOPNOTSUPP), return this
+ *   error code and make sure that memory allocated by another hook
+ *   gets freed properly.
+ * - At most one hook can return zero. All other hooks must return
+ *   -EOPNOTSUPP and this does not count as an error.
+ *
+ * NOTE: As a matter of best practice we call all hooks even if we
+ * NOTE: find one that returns an error early.
+ */
+static int ac_inode_init_security(struct inode *inode, struct inode *dir,
+				  char **namep, void **valuep, size_t *lenp)
+{
+
+	int i;
+	int ret = 0, ret2, gotname = 0;
+	unsigned int mymagic, lastmagic = 0;
+	char *myname = NULL, *name = NULL;
+	void *myvalue = NULL, *value = NULL;
+	size_t mylen = 0, len = 0;
+
+	if (original_ops->inode_init_security) {
+		ret = original_ops->inode_init_security(inode, dir,
+						&myname, &myvalue, &mylen);
+		if (ret == 0) {
+			gotname = 1;
+			name = myname;
+			value = myvalue;
+			len = mylen;
+		} else if (ret == -EOPNOTSUPP) {
+			ret = 0;
+		}
+	}
+
+	for(i=0; i<MAX_ANOUBIS_MODULES; ++i) {
+		typeof(hooks[i]->inode_init_security) _func;
+		struct anoubis_hooks *h;
+		rcu_read_lock();
+		h = rcu_dereference(hooks[i]);
+		if (h && h->inode_init_security) {
+			_func = h->inode_init_security;
+			mymagic = h->magic;
+			atomic_inc(&h->refcount);
+			rcu_read_unlock();
+			ret2 = (*_func)(inode, dir, &myname, &myvalue, &mylen);
+			atomic_dec(&h->refcount);
+			if (ret2 == -EOPNOTSUPP)
+				continue;
+			if (ret2 == 0) {
+				if (!gotname) {
+					name = myname;
+					value = myvalue;
+					len = mylen;
+					gotname = 1;
+					continue;
+				}
+				if (myname)
+					kfree(myname);
+				if (myvalue)
+					kfree(myvalue);
+				ret2 = -EPERM;
+			}
+			/* At this point we know that ret2 is not zero. */
+			if (!ret || lastmagic > mymagic) {
+				ret = ret2;
+				lastmagic = mymagic;
+			}
+		} else {
+			rcu_read_unlock();
+		}
+	}
+	if (ret) {
+		if (gotname) {
+			if (name)
+				kfree(name);
+			if (value)
+				kfree(value);
+		}
+	} else if (gotname == 0) {
+		ret = -EOPNOTSUPP;
+	} else {
+		if (namep)
+			(*namep) = name;
+		else if (name)
+			kfree(name);
+		if (valuep)
+			(*valuep) = value;
+		else if (value)
+			kfree(value);
+		if (lenp)
+			(*lenp) = len;
+	}
+	return ret;
+}
+static int ac_inode_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+	return HOOKS(inode_follow_link, (dentry, nd));
+}
+static void ac_inode_delete(struct inode *inode)
+{
+	VOIDHOOKS(inode_delete, (inode));
+}
+
+/* FILES and DENTRIES*/
+static int ac_dentry_open(struct file *file, const struct cred *cred)
+{
+	return HOOKS(dentry_open, (file, cred));
+}
+static void ac_d_instantiate(struct dentry *dentry, struct inode *inode)
+{
+	VOIDHOOKS(d_instantiate, (dentry, inode));
+}
+static int ac_file_alloc_security(struct file *file)
+{
+	if ((file->f_security = ac_alloc_label(GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+	return HOOKS(file_alloc_security, (file));
+}
+static void ac_file_free_security(struct file *file)
+{
+	if (!file->f_security)
+		return;
+	VOIDHOOKS(file_free_security, (file));
+	kfree(file->f_security);
+	file->f_security = NULL;
+}
+static int ac_file_lock(struct file *file, unsigned int cmd)
+{
+	return HOOKS(file_lock, (file, cmd));
+}
+
+#ifdef CONFIG_SECURITY_PATH
+/* PATH */
+static int ac_path_link(struct dentry *old_dentry, struct path *new_dir,
+			struct dentry *new_dentry)
+{
+	return HOOKS(path_link, (old_dentry, new_dir, new_dentry));
+}
+
+static int ac_path_unlink(struct path *dir, struct dentry *dentry)
+{
+	return HOOKS(path_unlink, (dir, dentry));
+}
+
+static int ac_path_mkdir(struct path *dir, struct dentry *dentry, int mode)
+{
+	return HOOKS(path_mkdir, (dir, dentry, mode));
+}
+
+static int ac_path_rmdir(struct path *dir, struct dentry *dentry)
+{
+	return HOOKS(path_rmdir, (dir, dentry));
+}
+
+static int ac_path_rename(struct path *old_dir, struct dentry *old_dentry,
+			  struct path *new_dir, struct dentry *new_dentry)
+{
+	return HOOKS(path_rename, (old_dir, old_dentry, new_dir, new_dentry));
+}
+
+static int ac_path_symlink(struct path *dir, struct dentry *dentry,
+    const char *old_name)
+{
+	return HOOKS(path_symlink, (dir, dentry, old_name));
+}
+
+static int ac_path_truncate(struct path *path, loff_t length,
+    unsigned int time_attr)
+{
+	return HOOKS(path_truncate, (path, length, time_attr));
+}
+
+static int ac_path_mknod(struct path *dir, struct dentry *dentry, int mode,
+    unsigned int dev)
+{
+	return HOOKS(path_mknod, (dir, dentry, mode, dev));
+}
+
+#endif
+
+/**
+ * Send a process message to the anoubis queue. These messages are used
+ * to notify the anoubis daemon of newly created processed, execs and
+ * processes that have died.
+ *
+ * @param op The operation that is reported.
+ * @param cookie The task cookie of a potentially new process. Note that
+ *     the task cookie of the current process is in the anoubis_common
+ *     structure.
+ * @return None.
+ */
+static void ac_process_message(int op, anoubis_cookie_t cookie)
+{
+	struct ac_process_message	*msg;
+
+	msg = kmalloc(sizeof(struct ac_process_message), GFP_ATOMIC);
+	if (!msg)
+		return;
+	msg->task_cookie = cookie;
+	msg->op = op;
+	anoubis_notify_atomic(msg, sizeof(struct ac_process_message),
+	    ANOUBIS_SOURCE_PROCESS);
+}
+
+/* EXEC related security hooks. */
+static int ac_cred_prepare(struct cred * nc, const struct cred * old, gfp_t gfp)
+{
+	struct anoubis_cred_label	*cl;
+
+	cl = __ac_alloc_label(gfp, sizeof (struct anoubis_cred_label));
+	if (cl == NULL)
+		return -ENOMEM;
+	spin_lock(&task_cookie_lock);
+	cl->task_cookie = task_cookie++;
+	spin_unlock(&task_cookie_lock);
+	cl->listener = 0;
+	nc->security = &cl->_l;
+	ac_process_message(ANOUBIS_PROCESS_OP_FORK, cl->task_cookie);
+
+	return HOOKS(cred_prepare, (nc, old, gfp));
+}
+
+/**
+ * Return a new and previously unused playground ID. We simply increment
+ * use the value of the next_pgid counter and increment its value. The
+ * anoubis daemon can use an ioctl to increase the playground ID if old
+ * playgrounds are still active.
+ *
+ * @param None.
+ * @return A unique an previously unused cookie.
+ */
+anoubis_cookie_t anoubis_alloc_pgid(void)
+{
+	anoubis_cookie_t	ret;
+	spin_lock(&task_cookie_lock);
+	ret = ++last_pgid;
+	spin_unlock(&task_cookie_lock);
+	BUG_ON(ret == 0);	/* playground ID 64 bit wrap around? */
+	return ret;
+}
+
+static void ac_cred_free(struct cred * cred)
+{
+	struct anoubis_cred_label	*sec = cred->security;
+
+	if (sec == NULL)
+		return;
+	VOIDHOOKS(cred_free, (cred));
+	cred->security = NULL;
+	ac_process_message(ANOUBIS_PROCESS_OP_EXIT, sec->task_cookie);
+	kfree(sec);
+}
+
+/**
+ * We reported a new process with the label in new. However, it turns
+ * out that new will now replace old without creating a new process.
+ * Thus we need to do the following:
+ * - Set the task cookie of new to that of old
+ * - Report this to the daemon and let the daemon do the accounting.
+ *
+ * @param nc The new credentials.
+ * @param old The old credentials.
+ * @return None.
+ */
+static void ac_cred_commit(struct cred *nc, const struct cred* old)
+{
+	struct anoubis_cred_label	*nsec = nc->security;
+	struct anoubis_cred_label	*osec = old->security;
+
+	if (nsec && osec) {
+		ac_process_message(ANOUBIS_PROCESS_OP_REPLACE,
+		    nsec->task_cookie);
+		nsec->task_cookie = osec->task_cookie;
+		nsec->listener = osec->listener;
+		VOIDHOOKS(cred_commit, (nc, old));
+	}
+}
+
+/**
+ * This function is called by the core kernel code if a new task is
+ * created. We use this to send am appropriate message to the anoubis
+ * daemon.
+ *
+ * @param tsk The newly created task struture.
+ * @return None.
+ */
+void anoubis_task_create(struct task_struct *tsk)
+{
+	const struct cred		*cred = tsk->real_cred;
+	struct anoubis_cred_label	*sec = cred->security;
+
+	if (!sec)
+		return;
+	ac_process_message(ANOUBIS_PROCESS_OP_CREATE, sec->task_cookie);
+}
+
+/**
+ * This function is called by the anoubis core kernel code if a task
+ * is destroyed. This is useful because task credentials can live longer
+ * than the task itself (e.g. cloned in file handles).
+ *
+ * @param tsk The task that is being destroyed.
+ * @return None.
+ */
+void anoubis_task_destroy(struct task_struct *tsk)
+{
+	const struct cred		*cred = tsk->real_cred;
+	struct anoubis_cred_label	*sec = cred->security;
+
+	if (!sec)
+		return;
+	ac_process_message(ANOUBIS_PROCESS_OP_DESTROY, sec->task_cookie);
+}
+
+static int ac_bprm_set_creds(struct linux_binprm * bprm)
+{
+	return HOOKS(bprm_set_creds, (bprm));
+}
+
+static void ac_bprm_committed_creds(struct linux_binprm *bprm)
+{
+	VOIDHOOKS(bprm_committed_creds, (bprm));
+}
+
+static int ac_bprm_secureexec(struct linux_binprm *bprm)
+{
+	return HOOKS(bprm_secureexec, (bprm));
+}
+
+/* Wrapper that exports secureexec to the anoubis modules. */
+/**
+ * This function asks all security modules if a secure exec is needed
+ * and returns true if it is. Some modules might want to do special
+ * things in this case. It is a simple wrapper around security_bprm_secureexec
+ * which is not exported to modules.
+ *
+ * @param bprm The linux_binprm structure of the exec.
+ */
+int anoubis_need_secureexec(struct linux_binprm *bprm)
+{
+	return security_bprm_secureexec(bprm);
+}
+
+/**
+ * This function implements capable security hook. It allows a security
+ * module to revoke certain capabilities that are given to a process.
+ */
+static int anoubis_capable(struct task_struct *tsk, const struct cred *cred,
+			int cap, int audit)
+{
+	if (tsk == current && anoubis_get_playgroundid())
+		return -EPERM;
+	return cap_capable(tsk, cred, cap, audit);
+}
+
+/**
+ * Check if the current task is allowed to access another task using
+ * ptrace. This implements the ptrace_access_check security hook.
+ * We return an error if the playground IDs of the two task differ and
+ * CAP_SYS_PTRACE is not set on the current task.
+ *
+ * @param tsk The vicim of the ptrace operation.
+ * @param mode The access mode.
+ * @return Zero if access is granted, a negative error code if it isn't.
+ */
+static int ac_ptrace_access_check(struct task_struct *tsk, unsigned int mode)
+{
+	int rc = 0;
+	anoubis_cookie_t pgid, tpgid;
+
+	rc = cap_ptrace_access_check(tsk, mode);
+	if (rc != 0)
+		return rc;
+
+	rcu_read_lock();
+
+	pgid = anoubis_get_playgroundid_tsk(current);
+	tpgid = anoubis_get_playgroundid_tsk(tsk);
+
+	/* playground tasks can only trace tasks in the same playground */
+	if (pgid && pgid != tpgid)
+		rc = -EPERM;
+	/* non-playground tasks can only trace playground tasks
+	   when privileged */
+	else if (!pgid && tpgid && !capable(CAP_SYS_PTRACE))
+		rc = -EPERM;
+
+	rcu_read_unlock();
+
+	return rc;
+}
+
+/**
+ * This structure defines the security hooks used by anoubis_core.
+ */
+static struct security_operations anoubis_core_ops = {
+	.unix_stream_connect = ac_unix_stream_connect,
+	.socket_post_create = ac_socket_post_create,
+	.socket_connect = ac_socket_connect,
+	.socket_accepted = ac_socket_accepted,
+	.socket_sendmsg = ac_socket_sendmsg,
+	.socket_recvmsg = ac_socket_recvmsg,
+	.socket_skb_recv_datagram = ac_socket_skb_recv_datagram,
+	.sk_alloc_security = ac_sk_alloc,
+	.sk_free_security = ac_sk_free,
+	.inode_alloc_security = ac_inode_alloc_security,
+	.inode_free_security = ac_inode_free_security,
+	.inode_permission = ac_inode_permission,
+	.inode_create = ac_inode_create,
+	.inode_mknod = ac_inode_mknod,
+	.inode_mkdir = ac_inode_mkdir,
+	.inode_link = ac_inode_link,
+	.inode_symlink = ac_inode_symlink,
+	.inode_unlink = ac_inode_unlink,
+	.inode_rmdir = ac_inode_rmdir,
+	.inode_rename = ac_inode_rename,
+	.inode_readlink = ac_inode_readlink,
+	.inode_setxattr = ac_inode_setxattr,
+	.inode_removexattr = ac_inode_removexattr,
+	.inode_init_security = ac_inode_init_security,
+	.inode_follow_link = ac_inode_follow_link,
+	.inode_delete = ac_inode_delete,
+	.dentry_open = ac_dentry_open,
+	.d_instantiate = ac_d_instantiate,
+	.file_alloc_security = ac_file_alloc_security,
+	.file_free_security = ac_file_free_security,
+	.file_lock = ac_file_lock,
+#ifdef CONFIG_SECURITY_PATH
+	.path_link = ac_path_link,
+	.path_unlink = ac_path_unlink,
+	.path_mkdir = ac_path_mkdir,
+	.path_rmdir = ac_path_rmdir,
+	.path_rename = ac_path_rename,
+	.path_symlink = ac_path_symlink,
+	.path_truncate = ac_path_truncate,
+	.path_mknod = ac_path_mknod,
+#endif
+	.cred_prepare = ac_cred_prepare,
+	.cred_free = ac_cred_free,
+	.cred_commit = ac_cred_commit,
+	.bprm_set_creds = ac_bprm_set_creds,
+	.bprm_committed_creds = ac_bprm_committed_creds,
+	.bprm_secureexec = ac_bprm_secureexec,
+	.capable = anoubis_capable,
+	.ptrace_access_check = ac_ptrace_access_check,
+};
+/**
+ * Initialize the anoubis_core module. This function is called very
+ * early in the boot process. Some initialization must be deferred to
+ * anoubis_core_late_init.
+ *
+ * @param None.
+ * @return Zero in case of success, a negative error code if an error
+ *     occured.
+ */
+static int __init anoubis_core_init(void)
+{
+	int rc = 0;
+
+	spin_lock_init(&queuelock);
+	spin_lock_init(&task_cookie_lock);
+	task_cookie = 1;
+	original_ops = security_ops;
+	if (!original_ops)
+		panic ("anoubis_core: No initial security operatons\n");
+	rc = register_security(&anoubis_core_ops);
+	if (rc < 0) {
+		printk(KERN_CRIT "anoubis_core: Cannot register "
+		    "security operations\n");
+		if (misc_deregister(&anoubis_device) < 0)
+			printk(KERN_CRIT "anoubis_core: Cannot unregister "
+			    "device\n");
+		return rc;
+	}
+	printk(KERN_INFO "anoubis_core: Successfully initialized.\n");
+	return rc;
+}
+
+/**
+ * This function does the rest of the initializations in the anoubis module.
+ * In particular, it makes the anoubis device available to the user.
+ *
+ * @param None.
+ * @return Zero in case of success, a negative error code in case of an
+ *     error.
+ */
+static int __init anoubis_core_init_late(void)
+{
+	if (misc_register(&anoubis_device) < 0)
+		panic ("anoubis_core: Cannot register device\n");
+	printk(KERN_INFO "anoubis_core: Device registered\n");
+	return 0;
+}
+
+/* Export functions that are useful to sub-modules. */
+EXPORT_SYMBOL(anoubis_raise);
+EXPORT_SYMBOL(anoubis_raise_flags);
+EXPORT_SYMBOL(anoubis_notify);
+EXPORT_SYMBOL(anoubis_notify_atomic);
+EXPORT_SYMBOL(anoubis_register);
+EXPORT_SYMBOL(anoubis_unregister);
+EXPORT_SYMBOL(anoubis_get_sublabel);
+EXPORT_SYMBOL(anoubis_get_sublabel_const);
+EXPORT_SYMBOL(anoubis_set_sublabel);
+EXPORT_SYMBOL(anoubis_get_task_cookie);
+EXPORT_SYMBOL(anoubis_need_secureexec);
+EXPORT_SYMBOL(anoubis_deny_write_access);
+EXPORT_SYMBOL(anoubis_allow_write_access);
+
+/* Register the anoubis_core module initialization functions. */
+security_initcall(anoubis_core_init);
+module_init(anoubis_core_init_late);
+
+/* Define module meta data. */
+MODULE_AUTHOR("Christian Ehrhardt <ehrhardt@genua.de>");
+MODULE_DESCRIPTION("ANOUBIS core module");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/security/anoubis/eventdevtest.c b/security/anoubis/eventdevtest.c
new file mode 100644
index 0000000..b9d498a
--- /dev/null
+++ b/security/anoubis/eventdevtest.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2008 GeNUA mbH <info@genua.de>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Sample security module to test the eventdev module. The module reads
+ * the extended attribute security.eventdevtest of each file that is being
+ * opened. If the attribute is there its value can be one of
+ *   - N: Notify the eventdevice of the open action
+ *   - A: Ask the eventdevice for permission
+ * In both cases the inode number of the file being opend is stored as
+ * an inode_t 32-bit in the Message.
+ */
+
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/namei.h>
+#include <linux/security.h>
+#include <linux/xattr.h>
+
+#include <linux/anoubis.h>
+
+#define XATTR_EVENTDEVTEST_SUFFIX "eventdevtest"
+#define XATTR_EVENTDEVTEST_NAME XATTR_SECURITY_PREFIX XATTR_EVENTDEVTEST_SUFFIX
+
+#define MY_NAME "eventdevtest"
+
+#define EVENT_NONE 0
+#define EVENT_NOTIFY 1
+#define EVENT_ASK 2
+
+struct eventdevtest_event {
+	struct anoubis_event_common common;
+	ino_t ino;
+};
+
+static int lookup_xattr(struct dentry * dentry)
+{
+	int ret;
+	char buf[10];
+	struct inode *inode = dentry->d_inode;
+
+	if (!inode)
+		return EVENT_NONE;
+	if (!S_ISREG(inode->i_mode))
+		return EVENT_NONE;
+	if (!inode->i_op->getxattr)
+		return EVENT_NONE;
+	ret = inode->i_op->getxattr(dentry, XATTR_EVENTDEVTEST_NAME, NULL, 0);
+	if (ret == -ENODATA || ret == -ENOTSUPP)
+		return EVENT_NONE;
+	if (ret != 1) {
+		printk(KERN_ERR "eventdevtest: getxattr failed with %d\n", ret);
+		return EVENT_NONE;
+	}
+	ret = inode->i_op->getxattr(dentry, XATTR_EVENTDEVTEST_NAME, buf, 1);
+	if (ret != 1) {
+		printk(KERN_ERR "eventdevtest: getxattr failed with %d\n", ret);
+		return EVENT_NONE;
+	}
+	switch(buf[0]) {
+	case 'N': return EVENT_NOTIFY;
+	case 'A': return EVENT_ASK;
+	}
+	return EVENT_NONE;
+}
+
+static int eventdevtest_dentry_open (struct file *fp, const struct cred * cred)
+{
+	int xattr, err;
+	struct eventdevtest_event * buf;
+	struct dentry * dentry = fp->f_path.dentry;
+	struct inode * inode;
+
+	if (!dentry)
+		return 0;
+	inode = dentry->d_inode;
+	if (!inode)
+		return 0;
+	xattr = lookup_xattr(dentry);
+	if (xattr == EVENT_NONE)
+		return 0;
+	buf = kmalloc(sizeof(struct eventdevtest_event), GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+	memcpy(&buf->ino, &inode->i_ino, sizeof(ino_t));
+	err = 0;
+	switch(xattr) {
+	case EVENT_ASK:
+		err =  anoubis_raise(buf, sizeof(*buf), ANOUBIS_SOURCE_TEST);
+		break;
+	case EVENT_NOTIFY:
+		err = anoubis_notify(buf, sizeof(*buf), ANOUBIS_SOURCE_TEST);
+		break;
+	}
+	/* In tests suppress errors if no queue is present. */
+	if (err == -EPIPE)
+		return 0;
+	return err;
+}
+
+/* Security operations. */
+static struct anoubis_hooks eventdevtest_ops = {
+	.version = ANOUBISCORE_VERSION,
+	.dentry_open = eventdevtest_dentry_open,
+};
+
+static int ac_index = -1;
+
+/*
+ * Remove the module.
+ */
+
+static void __exit eventdevtest_exit(void)
+{
+	if (ac_index >= 0)
+		anoubis_unregister(ac_index);
+}
+
+/*
+ * Initialize the eventdevteset module.
+ */
+
+static int __init eventdevtest_init(void)
+{
+	int rc = 0;
+
+	/* register ourselves with the security framework */
+	if ((rc = anoubis_register(&eventdevtest_ops, &ac_index)) < 0) {
+		ac_index = -1;
+		printk(KERN_ERR "eventdevtest: Failure registering with the "
+			      "kernel.\n");
+		return rc;
+	}
+	printk(KERN_INFO "eventdevtest: Successfully initialized.\n");
+	return 0;
+}
+
+module_init(eventdevtest_init);
+module_exit(eventdevtest_exit);
+
+MODULE_AUTHOR("Christian Ehrhardt <ehrhardt@genua.de>");
+MODULE_DESCRIPTION("LSM test Module for eventdev devices");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/security/anoubis/ipc.c b/security/anoubis/ipc.c
new file mode 100644
index 0000000..f7de5b4
--- /dev/null
+++ b/security/anoubis/ipc.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2008 GeNUA mbH <info@genua.de>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/module.h>
+#include <linux/anoubis.h>
+#include <linux/security.h>
+
+#include <net/sock.h>
+
+static int ac_index = -1;
+
+static anoubis_cookie_t	conn_cookie;
+static spinlock_t conn_cookie_lock;
+
+struct anoubis_sock_label {
+	spinlock_t		lock;
+	anoubis_cookie_t	task_cookie;
+	anoubis_cookie_t	peer_cookie;
+	anoubis_cookie_t	conn_cookie;
+};
+
+/* Makros to acces the label. */
+#define SKSEC(X) \
+    ((struct anoubis_sock_label *)anoubis_get_sublabel(&(X)->sk_security, \
+    ac_index))
+#define SETSKSEC(X,V) \
+    ((struct anoubis_sock_label *)anoubis_set_sublabel(&((X)->sk_security), \
+    ac_index, (V)))
+
+static int ipc_unix_stream_connect(struct socket *sock, struct socket *other,
+    struct sock *newsk)
+{
+	struct anoubis_sock_label *newl, *old;
+	struct anoubis_sock_label *sockl = NULL, *otherl = NULL;
+	struct ac_ipc_message	*msg;
+	anoubis_cookie_t	 cookie;
+	unsigned long		 flags;
+
+	if (!sock || !sock->sk || !other || !other->sk)
+		return 0;
+
+	sockl = SKSEC(sock->sk);
+	otherl = SKSEC(other->sk);
+	if (sockl == NULL || otherl == NULL)
+		return 0;
+
+	newl = kmalloc(sizeof(struct anoubis_sock_label), GFP_ATOMIC);
+	if (!newl)
+		return -ENOMEM;
+	spin_lock_init(&newl->lock);
+
+	spin_lock_irqsave(&conn_cookie_lock, flags);
+	cookie = conn_cookie++;
+	spin_unlock_irqrestore(&conn_cookie_lock, flags);
+
+	spin_lock(&sockl->lock);
+	sockl->conn_cookie = cookie;
+	sockl->peer_cookie = otherl->task_cookie;
+	spin_unlock(&sockl->lock);
+	spin_lock(&newl->lock);
+	newl->task_cookie = otherl->task_cookie;
+	newl->peer_cookie = sockl->task_cookie;
+	newl->conn_cookie = cookie;
+	spin_unlock(&newl->lock);
+
+	old = SETSKSEC(newsk, newl);
+	BUG_ON(old);
+
+	msg = kmalloc(sizeof(struct ac_ipc_message), GFP_NOWAIT);
+	if (msg) {
+		msg->op = ANOUBIS_SOCKET_OP_CONNECT;
+		spin_lock(&newl->lock);
+		msg->source = newl->task_cookie;
+		msg->dest = newl->peer_cookie;
+		msg->conn_cookie = newl->conn_cookie;
+		spin_unlock(&newl->lock);
+		anoubis_notify_atomic(msg, sizeof(struct ac_ipc_message),
+		    ANOUBIS_SOURCE_IPC);
+	}
+
+	return 0;
+}
+
+static int ipc_socket_post_create(struct socket *sock, int family, int type,
+    int protocol, int kern)
+{
+	struct anoubis_sock_label *sl, *old;
+	anoubis_cookie_t tcookie = anoubis_get_task_cookie();
+
+	if (family != AF_UNIX || tcookie == 0)
+		return 0;
+
+	sl = kmalloc(sizeof(struct anoubis_sock_label), GFP_ATOMIC);
+	if (!sl)
+		return -ENOMEM;
+
+	sl->task_cookie = tcookie;
+	sl->peer_cookie = 0;
+	sl->conn_cookie = 0;
+	spin_lock_init(&sl->lock);
+
+	old = SETSKSEC(sock->sk, sl);
+	BUG_ON(old);
+
+	return 0;
+}
+
+static int ipc_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
+{
+	struct anoubis_sock_label *old;
+
+	old = SETSKSEC(sk, NULL);
+	BUG_ON(old);
+
+	return 0;
+}
+
+static void ipc_sk_free_security(struct sock *sk)
+{
+	struct ac_ipc_message		*msg;
+	struct anoubis_sock_label	*l = SETSKSEC(sk, NULL);
+
+	if (!l)
+		return;
+
+	if (l->peer_cookie != 0) {
+		msg = kmalloc(sizeof(struct ac_ipc_message), GFP_NOWAIT);
+		if (msg) {
+			msg->op = ANOUBIS_SOCKET_OP_DESTROY;
+			msg->source = l->task_cookie;
+			msg->dest = l->peer_cookie;
+			msg->conn_cookie = l->conn_cookie;
+			anoubis_notify_atomic(msg,
+			    sizeof(struct ac_ipc_message), ANOUBIS_SOURCE_IPC);
+		}
+	}
+
+	kfree(l);
+}
+
+/* Security operations. */
+static struct anoubis_hooks ipc_ops = {
+	.version = ANOUBISCORE_VERSION,
+	.unix_stream_connect = ipc_unix_stream_connect,
+	.socket_post_create = ipc_socket_post_create,
+	.sk_alloc_security = ipc_sk_alloc_security,
+	.sk_free_security = ipc_sk_free_security,
+};
+
+/* Initialise event device and register with the LSM framework */
+static int __init ipc_init(void)
+{
+	int ret;
+
+	spin_lock_init(&conn_cookie_lock);
+	conn_cookie = 1;
+
+	ret = anoubis_register(&ipc_ops, &ac_index);
+	if (ret < 0) {
+		ac_index = -1;
+		printk(KERN_INFO "Failed to register Anoubis IPC\n");
+		return ret;
+	}
+	printk(KERN_INFO "Anoubis IPC module installed\n");
+	return 0;
+}
+
+/* Unregister from LSM framework and remove event device */
+static void __exit ipc_exit(void)
+{
+	if (ac_index >= 0)
+		anoubis_unregister(ac_index);
+	printk(KERN_INFO "Anoubis IPC security module removed\n");
+}
+
+module_init(ipc_init);
+module_exit(ipc_exit);
+
+MODULE_DESCRIPTION("Anoubis IPC module");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/security/anoubis/playground.c b/security/anoubis/playground.c
new file mode 100644
index 0000000..8543238
--- /dev/null
+++ b/security/anoubis/playground.c
@@ -0,0 +1,1854 @@
+/*
+ * Copyright (c) 2010 GeNUA mbH <info@genua.de>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/file.h>
+#include <linux/gfp.h>
+#include <linux/module.h>
+#include <linux/namei.h>
+#include <linux/net.h>
+#include <linux/sched.h>
+#include <linux/security.h>
+#include <linux/socket.h>
+#include <linux/string.h>
+#include <linux/syscalls.h>
+#include <linux/uaccess.h>
+#include <linux/un.h>
+#include <linux/xattr.h>
+#include <linux/dazukofs_fs.h>
+#include "../../fs/ecryptfs/ecryptfs_kernel.h"
+
+#include <asm/system.h>
+
+#include <net/sock.h>
+
+#include <linux/anoubis.h>
+#include <linux/anoubis_playground.h>
+
+#define XATTR_ANOUBIS_PG_SUFFIX "anoubis_pg"
+#define XATTR_ANOUBIS_PG XATTR_SECURITY_PREFIX XATTR_ANOUBIS_PG_SUFFIX
+
+static int ac_index = -1;
+
+static u_int64_t pg_stat_loadtime;
+static u_int64_t pg_stat_devicewrite_delay;
+static u_int64_t pg_stat_devicewrite_ask;
+static u_int64_t pg_stat_devicewrite_deny;
+static u_int64_t pg_stat_rename_ask;
+static u_int64_t pg_stat_rename_override;
+
+/**
+ * Statistic counters for the REQUEST_STATS ioctl on /dev/anoubis.
+ */
+static struct anoubis_internal_stat_value pg_stats[] = {
+	{ ANOUBIS_SOURCE_PLAYGROUND, PG_STAT_LOADTIME, &pg_stat_loadtime },
+	{ ANOUBIS_SOURCE_PLAYGROUND, PG_STAT_DEVICEWRITE_DELAY,
+	  &pg_stat_devicewrite_delay },
+	{ ANOUBIS_SOURCE_PLAYGROUND, PG_STAT_DEVICEWRITE_ASK,
+	  &pg_stat_devicewrite_ask},
+	{ ANOUBIS_SOURCE_PLAYGROUND, PG_STAT_DEVICEWRITE_DENY,
+	  &pg_stat_devicewrite_deny },
+	{ ANOUBIS_SOURCE_PLAYGROUND, PG_STAT_RENAME_ASK, &pg_stat_rename_ask },
+	{ ANOUBIS_SOURCE_PLAYGROUND, PG_STAT_RENAME_OVERRIDE,
+	  &pg_stat_rename_override },
+};
+
+/**
+ * List of file systems that are passed through the playground without
+ * any modifications, i.e. even playground processes are allowed to write
+ * to these filesystems and lookups will be performed without modifications.
+ * This list should be documented in the user's Guide!
+ */
+static const char *nopg_fs[] = {
+	"proc",
+	"tmpfs",
+	"usbfs",
+	"sysfs",
+	"fuse",
+	"fuseblk",
+	"fusectl",
+	NULL,
+};
+
+/**
+ * List file systems that can deadlock if readdir does a lookup on the
+ * same directory during filldir.
+ */
+static const char *broken_readdir_fs[] = {
+	"xfs",
+	"dazukofs",
+	"ecryptfs",
+	NULL,
+};
+
+/**
+ * This implements the anoubis statistics gathering function for the
+ * anoubis playground module.
+ *
+ * @param ptr A pointer to internal array with statistic descriptors
+ *     (struct internal_stat_value) is stored here.
+ * @param count The total number of statistic descriptors is stored
+ *     here.
+ * @return None.
+ */
+static void pg_getstats(struct anoubis_internal_stat_value **ptr, int * count)
+{
+	(*ptr) = pg_stats;
+	(*count) = sizeof(pg_stats)/sizeof(struct anoubis_internal_stat_value);
+}
+
+/**
+ * Values for the scanstatus field of pg_inode_sec. See below for
+ * the precise meaing.
+ */
+#define PG_SCANSTATUS_NONE		0
+#define	PG_SCANSTATUS_INPROGRESS	1
+#define PG_SCANSTATUS_SUCCESS		2
+#define PG_SCANSTATUS_COMMITTED		3
+
+/**
+ * Values for the stacktype field of pg_inode_sec.
+ */
+#define INODE_STACKTYPE_NONE		0
+#define	INODE_STACKTYPE_DAZUKO		1
+#define	INODE_STACKTYPE_ECRYPTFS	2
+
+/**
+ * The inode security label of the playground anoubis module.
+ * Fields:
+ * @pgid: The playground-ID of the playground that this inode belongs to.
+ *     A value of zero means that the inode is not part of particular
+ *     playground.
+ * @accesstask: This value is set to the task cookie of a process if
+ *     one of the renameok flag is set. Only the given task is allowed to
+ *     perform the rename operation.
+ * @stacktype: If the inode belongs to a stacking file system and the
+ *     security information should be maintained on the lower inode, this
+ *     tells which stack type is used and how to find the lower inode.
+ * @havexattr: True if the file system has extended attributes, i.e. if
+ *     there is a security label for the file, it can be read from the
+ *     persistent storage on the file system.
+ * @pglookupenabled: True if playground style lookups are enabled. Some
+ *     filesystems do not support this and have this flag cleared.
+ * @renameok: Renaming this inode is ok for the task specified by
+ *     accesstask even if the process is in the playground and the inode
+ *     is not. This permission is only valid for a single rename.
+ * @readdirok: True if a lookup during filldir/readdir does not deadlock on
+ *     this inode. This value depends on the file system type.
+ * @scanstatus: This value determines the current scanning status of the file.
+ *     Possible values are:
+ *     PG_SCANSTATUS_NONE: Not scanned, no scanning in progress.
+ *     PG_SCANSTATUS_INPROGRESS: The daemon has started the scan process.
+ *         This value is set via an ioclt.
+ *     PG_SCANSTATUS_SUCCESS: Scanning completed successfully. The user
+ *         can now remove the security label.
+ *     PG_SCANSTATUS_COMMITTED: The security label has been or is about to
+ *         be removed. A playground process is no longer allowed to write
+ *         to the file.
+ */
+struct pg_inode_sec {
+	anoubis_cookie_t	pgid;
+	anoubis_cookie_t	accesstask;
+	int			stacktype;
+	unsigned int		havexattr:1;
+	unsigned int		pgenabled:1;
+	unsigned int		renameok:1;
+	unsigned int		readdirok:1;
+	atomic_t		scanstatus;
+};
+
+/**
+ * The security label for file structures. We store the file handle of the
+ * lower file that needs to be copied for playground files that get copied
+ * during write.
+ * Fields:
+ * @lower: The lower file or NULL if no copy is needed.
+ */
+struct pg_file_sec {
+	struct file *lower;
+};
+
+/**
+ * Playground security labels for task/credentials.
+ * Fields:
+ *
+ * @pgid: The playgroudn-ID of the current task.
+ * @pgcreate: True if a newly created file of this process should always
+ *     be created in the playground even if the open is exclusive and
+ *     the original file already exists.
+ */
+struct pg_task_sec {
+	anoubis_cookie_t	pgid;
+	unsigned int		pgcreate:1;
+};
+
+/*
+ * Macros to access the security labels with their approriate type.
+ * Please note that the credentials structure are often const, i.e.
+ * we must not change the sec->security pointer. Thus we use
+ * anoubis_get_sublabel_const and only access the pointer if it is not
+ * NULL. The latter can happen for the initial task.
+ */
+#define _SEC(TYPE,X) ((TYPE)anoubis_get_sublabel(&(X), ac_index))
+#define _SECCONST(TYPE,X) \
+		((X)?((TYPE)anoubis_get_sublabel_const(X, ac_index)):NULL)
+#define _ISEC(X) _SEC(struct pg_inode_sec *, (X)->i_security)
+#define CSEC(X) _SECCONST(struct pg_task_sec *, (X)->security)
+#define FSEC(X) _SEC(struct pg_file_sec *, (X)->f_security)
+
+#define _SETSEC(TYPE,X,V) ((TYPE)anoubis_set_sublabel(&(X), ac_index, (V)))
+#define SETISEC(X,V) _SETSEC(struct pg_inode_sec *, ((X)->i_security), (V))
+#define SETCSEC(X,V) _SETSEC(struct pg_task_sec *, ((X)->security), (V))
+#define SETFSEC(X,V) _SETSEC(struct pg_file_sec *, ((X)->f_security), (V))
+
+/**
+ * Return the security attribute of the lowest inode in a chain of
+ * stacked inodes. Currently, we only support dazukofs as a stacking
+ * file system that is able to maintain security information on the lower
+ * inode.
+ *
+ * @param inode The upper inode.
+ * @return The security attribute to use for this inode.
+ */
+static inline struct pg_inode_sec * ISEC(struct inode *inode)
+{
+	struct pg_inode_sec	*sec;
+
+	while (1) {
+		if (unlikely(!inode))
+			return NULL;
+		sec  = _ISEC(inode);
+		if (unlikely(!sec))
+			return NULL;
+		if (likely(sec->stacktype == INODE_STACKTYPE_NONE))
+			return sec;
+		switch (sec->stacktype) {
+		case INODE_STACKTYPE_DAZUKO:
+			inode = get_lower_inode(inode);
+			if (inode == NULL)
+				return sec;
+			break;
+		case INODE_STACKTYPE_ECRYPTFS:
+			inode = ecryptfs_inode_to_lower(inode);
+			if (inode == NULL)
+				return sec;
+			break;
+		default:
+			BUG();
+		}
+	}
+}
+
+/**
+ * This implements the inode_alloc_security hook for the playground module.
+ * Allocate a new playground inode security label. This initializes
+ * the playground-ID to and havexattr to zero. This means that the
+ * inode does not have a playground label and cannot be written to by
+ * playground processes. This will be changed later on by the d_instantiate
+ * or by the inode_init hook.
+ *
+ * @param inode The Inode.
+ * @return Zero in case of success, a negative error code in case of errors.
+ */
+static int pg_inode_alloc_security(struct inode * inode)
+{
+	struct pg_inode_sec *sec, *old;
+	const char *ftype;
+	int i;
+
+	sec = kmalloc(sizeof (struct pg_inode_sec), GFP_KERNEL);
+	if (!sec)
+		return -ENOMEM;
+	sec->pgid = 0;
+	sec->havexattr = 0;
+	sec->pgenabled = 1;
+	sec->readdirok = 1;
+	sec->accesstask = 0;
+	sec->renameok = 0;
+	sec->stacktype = INODE_STACKTYPE_NONE;
+	atomic_set(&sec->scanstatus, PG_SCANSTATUS_NONE);
+	ftype = inode->i_sb->s_type->name;
+	if (strcmp(ftype, "dazukofs") == 0)
+		sec->stacktype = INODE_STACKTYPE_DAZUKO;
+	else if (strcmp(ftype, "ecryptfs") == 0)
+		sec->stacktype = INODE_STACKTYPE_ECRYPTFS;
+	for (i=0; nopg_fs[i]; ++i) {
+		if (strcmp(ftype, nopg_fs[i]) == 0) {
+			sec->pgenabled = 0;
+			break;
+		}
+	}
+	for (i=0; broken_readdir_fs[i]; ++i) {
+		if (strcmp(ftype, broken_readdir_fs[i]) == 0) {
+			sec->readdirok = 0;
+			break;
+		}
+	}
+	old = SETISEC(inode, sec);
+	BUG_ON(old);
+
+	return 0;
+}
+
+/**
+ * Release memory allocated for the anoubis playground inode label.
+ *
+ * @param inode The inode.
+ * @return None.
+ */
+static void pg_inode_free_security(struct inode * inode)
+{
+	struct pg_inode_sec *sec = SETISEC(inode, NULL);
+	if (sec)
+		kfree (sec);
+}
+
+/**
+ * Fill a struct pg_open_message with the information from the parameters
+ * and the current process. The file mode is taken from the first path.
+ *
+ * @param msgp A pointer to the resulting message is stored in the location
+ *     given by this parameter. The message is allocated using kmalloc.
+ * @param op This is the operation that is about to be performed.
+ * @param f_path1 The first path involved in the operation. Must be
+ *     non-NULL.
+ * @param f_path2 An optional second path involved in the operation. This
+ *     path can be NULL.
+ * @return The length of the message that was allocated or a negative
+ *     error code in case of an error. No memory is allocated if an error
+ *     is returned.
+ */
+static inline int pg_open_message_fill(void **msgp, int op,
+    struct path *f_path1, struct path *f_path2)
+{
+	struct pg_open_message *msg = NULL;
+	char *buf1, *buf2 = NULL, *path1, *path2 = NULL;
+	int error, pathlen1, pathlen2 = 0, alloclen;
+
+	buf1 = (char *)__get_free_page(GFP_KERNEL);
+	if (buf1 == NULL)
+		return -ENOMEM;
+	if (f_path2) {
+		error = -ENOMEM;
+		buf2 = (char *)__get_free_page(GFP_KERNEL);
+		if (!buf2)
+			goto err;
+	}
+	path1 = global_dpath(f_path1, buf1, PAGE_SIZE);
+	error = -EIO;
+	if (!path1 || IS_ERR(path1))
+		goto err;
+	pathlen1 = buf1+PAGE_SIZE - path1;
+	if (f_path2) {
+		path2 = global_dpath(f_path2, buf2, PAGE_SIZE);
+		error = -EIO;
+		if (!path2 || IS_ERR(path2))
+			goto err;
+		pathlen2 = buf2+PAGE_SIZE - path2;
+	}
+	alloclen = sizeof(struct pg_open_message) + pathlen1 + pathlen2;
+	error = -ENOMEM;
+	msg = kmalloc(alloclen, GFP_KERNEL);
+	if (!msg)
+		goto err;
+	msg->op = op;
+	msg->mode = f_path1->dentry->d_inode->i_mode;
+	memcpy(msg->pathbuf, path1, pathlen1);
+	if (pathlen2)
+		memcpy(msg->pathbuf + pathlen1, path2, pathlen2);
+	if (buf1)
+		free_page((unsigned long)buf1);
+	if (buf2)
+		free_page((unsigned long)buf2);
+	(*msgp) = msg;
+	return alloclen;
+err:
+	if (buf1)
+		free_page((unsigned long)buf1);
+	if (buf2)
+		free_page((unsigned long)buf2);
+	if (msg)
+		kfree(msg);
+	return error;
+}
+
+/**
+ * This function notifies the anoubis Daemon about a modified playground
+ * ID of a process. The kernel does not depend on the notification to succeed,
+ * i.e. memory allocation errors are simply discarded.
+ *
+ * @param None. The Message is always sent for the current process.
+ * @return None.
+ */
+static inline void pg_notify_pgid_change(void)
+{
+	struct pg_proc_message *procmsg;
+
+	procmsg = kmalloc(sizeof(struct pg_proc_message), GFP_ATOMIC);
+	if (!procmsg)
+		return;
+	anoubis_notify_atomic(procmsg, sizeof(struct pg_proc_message),
+	    ANOUBIS_SOURCE_PLAYGROUNDPROC);
+}
+
+/**
+ * This function notifies the anoubis daemon about a newly instantiated
+ * inode with a playground label. This event is sent for both newly
+ * created files and inodes that are read from disk. The daemon must
+ * handle cases where the same inode is reported more than once.
+ *
+ * @param dentry The directory entry to report. If this is NULL, the
+ *     inode data is reported without a pathname.
+ * @param inode The inode to report. If this is NULL, the inode data is
+ *     taken from the dentry.
+ * @param pgid The playground ID of the file. For ANOUBIS_PGFILE_DELETE,
+ *     this is the old playground ID. For other message types it is the new
+ *     playground ID.
+ * @return None.
+ */
+static inline void pg_notify_file(struct dentry *dentry, struct inode * inode,
+    int op, anoubis_cookie_t pgid, struct dentry *old_dentry)
+{
+	char *buf = NULL, *old_buf = NULL, *path = NULL, *old_path = NULL;
+	struct pg_file_message *fmsg;
+	int pathlen = 1, old_pathlen = 1, alloclen;
+
+	if (!inode)
+		inode = dentry->d_inode;
+	if (!inode)
+		return;
+	if (dentry)
+		buf = (char *)__get_free_page(GFP_KERNEL);
+	if (buf) {
+		path = local_dpath(dentry, buf, PAGE_SIZE);
+		if (path && !IS_ERR(path)) {
+			pathlen = 1 + strlen(path);
+		} else {
+			pathlen = 1;
+			path = NULL;
+		}
+	}
+	if (old_dentry)
+		old_buf = (char *)__get_free_page(GFP_KERNEL);
+	if (old_buf) {
+		old_path = local_dpath(old_dentry, old_buf, PAGE_SIZE);
+		if (old_path && !IS_ERR(old_path)) {
+			old_pathlen = 1 + strlen(old_path);
+		} else {
+			old_pathlen = 1;
+			old_path = NULL;
+		}
+	}
+	alloclen = sizeof(struct pg_file_message) + pathlen + old_pathlen;
+	fmsg = kmalloc(alloclen, GFP_KERNEL);
+	if (fmsg == NULL) {
+		printk(KERN_CRIT "pg_notify_file: Out of memory\n");
+		if (buf)
+			free_page((unsigned long)buf);
+		if (old_buf)
+			free_page((unsigned long)old_buf);
+		return;
+	}
+	fmsg->pgid = pgid;
+	fmsg->ino = inode->i_ino;
+	fmsg->dev = inode->i_sb->s_dev;
+	fmsg->op = op;
+	if (path) {
+		memcpy(fmsg->path, path, pathlen);
+	} else {
+		fmsg->path[0] = 0;
+	}
+	if (buf)
+		free_page((unsigned long)buf);
+	if (old_path) {
+		memcpy(fmsg->path + pathlen, old_path, old_pathlen);
+	} else {
+		fmsg->path[pathlen] = 0;
+	}
+	if (old_buf)
+		free_page((unsigned long)old_buf);
+	anoubis_notify(fmsg, alloclen, ANOUBIS_SOURCE_PLAYGROUNDFILE);
+}
+
+/**
+ * Notify the anoubis daemon of a delted inode. This function send one
+ * event for each inode in the stack of inodes if the inode is indeed
+ * on a stacking file system that we support.
+ *
+ * @param inode The inode to report.
+ * @param pgid The (new) playground ID of the file.
+ * @return None.
+ */
+static inline void pg_notify_delete_all(struct inode *inode,
+    anoubis_cookie_t pgid)
+{
+	struct		pg_inode_sec *sec;
+
+	while (inode) {
+		pg_notify_file(NULL, inode, ANOUBIS_PGFILE_DELETE, pgid, NULL);
+		sec = _ISEC(inode);
+		if (sec == NULL || sec->stacktype == INODE_STACKTYPE_NONE)
+			break;
+		switch (sec->stacktype) {
+		case INODE_STACKTYPE_DAZUKO:
+			inode = get_lower_inode(inode);
+			break;
+		case INODE_STACKTYPE_ECRYPTFS:
+			inode = ecryptfs_inode_to_lower(inode);
+			break;
+		default:
+			BUG();
+		}
+	}
+}
+
+
+
+/**
+ * This implements the inode_permission security hook for the anoubis
+ * playground security module.
+ *
+ * Test if the current task is allowed to access the inode @inode.
+ * Rules for the access check:
+ * - Non-Playground processes must not access files with playground label.
+ * - Playground processes must not write to production files. These
+ *   are files the have a zero inode label. Files that cannot have an
+ *   inode label (because the file system does not support extended
+ *   attribute) are treated as production files, too.
+ * - Playground processes must not access files from a different playground.
+ *
+ * @param inode The inode.
+ * @param mask The access mask (MAY_READ, MAY_WRITE, MAY_EXEC and MAY_APPEND)
+ * @return Zero if the access is ok, a negative error code if the
+ *     access it not allowed.
+ */
+static int pg_inode_permission(struct inode * inode, int mask)
+{
+	struct pg_inode_sec *isec = ISEC(inode);
+	anoubis_cookie_t pgid = anoubis_get_playgroundid();
+
+	if (unlikely(anoubis_is_listener())) {
+		if ((mask & (MAY_WRITE | MAY_APPEND)) == 0)
+			return 0;
+	}
+	if (isec && (mask & (MAY_WRITE | MAY_APPEND))) {
+		/*
+		 * This loop is here to make sure that we never change
+		 * the scanstatus value from PG_SCANSTATUS_COMMITTED to
+		 * something else.
+		 */
+		while (1) {
+			int old = atomic_read(&isec->scanstatus);
+
+			if (old == PG_SCANSTATUS_NONE)
+				break;
+			if (old == PG_SCANSTATUS_COMMITTED) {
+				if (pgid)
+					return -EPERM;
+				break;
+			}
+			atomic_cmpxchg(&isec->scanstatus, old,
+						PG_SCANSTATUS_NONE);
+		}
+	}
+	if (pgid == 0) {
+		/* Allow access to playground dirs */
+		if (S_ISDIR(inode->i_mode))
+			return 0;
+		/* Not a playground process: Deny access to playground files */
+		if (isec && isec->pgid)
+			return -EPERM;
+		return 0;
+	}
+	/* Allow access on file systems that do not support the playground. */
+	if (isec && isec->pgenabled == 0)
+		return 0;
+
+	/* Ok, this is a playground process */
+
+	if (!isec || isec->havexattr == 0 || isec->pgid == 0) {
+		/*
+		 * The file is a production file (not part of any playground)
+		 * or the file system does not support security labels.
+		 *
+		 * Reading production files is always ok.
+		 */
+		if ((mask & MAY_WRITE) == 0)
+			return 0;
+
+		/*
+		 * Writing to special files (devices, sockets, and fifos)
+		 * is ok. However, the user must be asked for permission
+		 * first. This is done in dentry_open.
+		 */
+		if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)
+		    || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
+			pg_stat_devicewrite_delay++;
+			return 0;
+		}
+
+		/*
+		 * Writing to production directories is allowed for playground
+		 * processes because the playground must be able to create
+		 * playground named versions of a directory entry. However,
+		 * writing is not allowed, if the file system does not support
+		 * extended attributes.
+		 */
+		if (S_ISDIR(inode->i_mode) && isec && isec->havexattr == 1)
+			return 0;
+
+		/*
+		 * Report success, if the caller is sys_access. The file
+		 * will be copied in case of an actual access.
+		 */
+		if (mask & MAY_ACCESS)
+			return 0;
+
+		/* Deny all other writes. */
+		return -EPERM;
+	}
+	/*
+	 * At this point we know that the process is in a playground
+	 * and the file is in a playground, too. Access is allowed iff
+	 * the playground IDs match. EACCES seems somewhat more correct
+	 * for this case than EPERM. In theory we would want to return
+	 * ENOENT for this case but this is a bit risky because it might
+	 * cause the caller to create a negative dentry.
+	 */
+	if (pgid != isec->pgid)
+		return -EACCES;
+	return 0;
+}
+
+/**
+ * Utility function that checks if creating a new node in a directory
+ * is allowed. The inode_permission hook allows reads and writes in
+ * all directories including playground directories. However, it should
+ * not be possible to create non playground files in playground directories.
+ *
+ * @param dir The inode of the directory.
+ * @param pgid The playgroud ID of the newly created file.
+ * @return Zero if access is allowed, -EXDEV if access is not allowed.
+ */
+static int pg_can_create_in_dir(struct inode *dir, anoubis_cookie_t pgid)
+{
+	struct pg_inode_sec *sec;
+
+	sec = ISEC(dir);
+	if (sec && sec->pgenabled && sec->pgid && sec->pgid != pgid)
+		return -EXDEV;
+	return 0;
+}
+
+/**
+ * This implementes the inode_create security hook. We disallow the
+ * creation of non playground files in a playground directory. The rest
+ * is handled by inode_permission.
+ *
+ * @param dir The directory where the new file will be created.
+ * @param dentry The name of the file to create.
+ * @param mode The file creation mode.
+ * @return Zero if access is allowed, a negative error code if access is
+ *     denied.
+ */
+static int pg_inode_create(struct inode *dir, struct dentry *dentry, int mode)
+{
+	return pg_can_create_in_dir(dir, anoubis_get_playgroundid());
+}
+
+/**
+ * This implements the inode_mknod security hook. We disallow the
+ * creation of non playground inodes in a playground directory. The rest
+ * is handled by inode_permission.
+ *
+ * @param dir The directory where the new file will be created.
+ * @param dentry The name of the node to create.
+ * @param mode The file creation mode.
+ * @param dev The device ID if a device is created.
+ * @return Zero if access is allowed, a negative error code if access is
+ *     denied.
+ */
+static int pg_inode_mknod(struct inode *dir, struct dentry *dentry, int mode,
+								dev_t dev)
+{
+	return pg_can_create_in_dir(dir, anoubis_get_playgroundid());
+}
+
+/**
+ * This implements the inode_mkdir security hook. We disallow the
+ * creation of non playground directories in a playground directory. The
+ * rest is handled in inode_permission.
+ *
+ * @param dir The directory where the new directory will be created.
+ * @param dentry The name of the directory to create.
+ * @param mode The file creation mode of the directory.
+ * @return Zero if access is allowed, a negative error code if access is
+ *     denied.
+ */
+static int pg_inode_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+	return pg_can_create_in_dir(dir, anoubis_get_playgroundid());
+}
+
+/**
+ * This implements the inode_link security hook. A playground process
+ * can only create hard links to playground files in the same playground.
+ * A non-playground process cannot create links to playground files at all.
+ * Additionally, if the target directory is in a playground, it must be in
+ * the same playground as the source file.
+ *
+ * @param The directory entry of the old name.
+ * @param dir The inode of the directory where the link will be created.
+ * @param new_dentry The directory entry of the new name.
+ * @return Zero in case of success, a negative error code in case of errors.
+ */
+static int pg_inode_link(struct dentry *old_dentry, struct inode *dir,
+						struct dentry *new_dentry)
+{
+	struct pg_inode_sec *sec;
+	anoubis_cookie_t pgid = anoubis_get_playgroundid();
+
+	if (!anoubis_playground_enabled(old_dentry))
+		return pg_can_create_in_dir(dir, pgid);
+	sec = ISEC(old_dentry->d_inode);
+	if (sec->pgid != pgid)
+		return -EACCES;
+	return pg_can_create_in_dir(dir, pgid);
+}
+
+/**
+ * This implements the inode_symlink security hook. We disallow the
+ * creation of non playground symlinks in a playground directory. The
+ * rest is handled in inode_permission.
+ *
+ * @param dir The directory where the new symlink will be created.
+ * @param dentry The name of the symlink to create.
+ * @param oldpath The target name of the symlink.
+ * @return Zero if access is allowed, a negative error code if access is
+ *     denied.
+ */
+static int pg_inode_symlink(struct inode *dir, struct dentry *dentry,
+						const char *oldname)
+{
+	return pg_can_create_in_dir(dir, anoubis_get_playgroundid());
+}
+
+/**
+ * This implements the inode_unlink and inode_rmdir security hooks. A
+ * playground process can only unlink files that are in the same playground.
+ * Processes that are not in a playground can unlink all files.
+ * Exception: Sockets can be unlinked from within a playground, too.
+ *
+ * @param dir The directory of the file.
+ * @param dentry The file itself.
+ * @return Zero if unlink is allowed or a negative error code.
+ */
+static int pg_inode_unlink(struct inode *dir, struct dentry *dentry)
+{
+	struct pg_inode_sec *sec;
+
+	anoubis_cookie_t pgid = anoubis_get_playgroundid();
+	if (!pgid)
+		return 0;
+	if (!anoubis_playground_enabled(dentry))
+		return 0;
+	if (S_ISSOCK(dentry->d_inode->i_mode))
+		return 0;
+	sec = ISEC(dentry->d_inode);
+	if (sec->pgid != pgid)
+		return -EACCES;
+	return 0;
+}
+
+/**
+ * This implements the inode_rename security hook. A playground process
+ * can only rename files that are marked as playground files. If the
+ * victim of the rename already exists, it must be a playground file, too.
+ *
+ * @param old_dir The directory of the rename source.
+ * @param old_dentry The directory entry of the rename source.
+ * @param new_dir The directory of the rename target.
+ * @param new_dentry The directory entry of the rename target.
+ * @return Zero if rename is allow, a negative error code otherwise.
+ */
+static int pg_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
+			   struct inode *new_dir, struct dentry *new_dentry)
+{
+	struct pg_inode_sec *sec;
+	anoubis_cookie_t filepgid = 0, pgid = anoubis_get_playgroundid();
+	anoubis_cookie_t renametask = 0;
+	int rename_override = 0;
+
+	if (anoubis_playground_enabled(old_dentry)) {
+		sec = ISEC(old_dentry->d_inode);
+		if (sec->pgid) {
+			filepgid = sec->pgid;
+		} else {
+			int ret = pg_can_create_in_dir(new_dir, sec->pgid);
+			if (ret < 0)
+				return ret;
+		}
+		if (sec->renameok)
+			renametask = sec->accesstask;
+		sec->renameok = 0;
+		sec->accesstask = 0;
+		if (sec->pgid != pgid) {
+			if (sec->pgid == 0 && renametask
+			    && renametask == anoubis_get_task_cookie()) {
+				rename_override = 1;
+				pg_stat_rename_override++;
+			} else {
+				return -EACCES;
+			}
+		}
+	}
+	if (anoubis_playground_enabled(new_dentry)) {
+		sec = ISEC(new_dentry->d_inode);
+		/*
+		 * If this rename happens in the production system,
+		 * (user override) do not allow the target in the playground.
+		 */
+		if (rename_override) {
+			if (sec->pgid)
+				return -EACCES;
+		} else if (sec->pgid != pgid)
+			return -EACCES;
+	}
+	if (filepgid)
+		pg_notify_file(new_dentry, old_dentry->d_inode,
+		    ANOUBIS_PGFILE_INSTANTIATE, filepgid,
+		    S_ISDIR(old_dentry->d_inode->i_mode) ? old_dentry : NULL);
+	return 0;
+}
+
+/**
+ * This implements the path_rename security hook. We only use this hook
+ * if we are about to rename a directory in the production system. This
+ * cannot be done in the playground and requires confirmation from the
+ * user. This hook asks the user for confirmation and marks the source inode
+ * appropriatly. This will prevent the subsequent inode_rename hook from
+ * denying the rename.
+ *
+ * @param old_dir The old directory that contains the dentry to be renamed.
+ * @param old_dentry The dentry to be renamed.
+ * @param new_dir The new directory that contains the target of the rename.
+ * @param new_dentry The target dentry of the rename.
+ * @return Zero if rename is allowed or a negative error code.
+ */
+static int pg_path_rename(struct path *old_dir, struct dentry *old_dentry,
+			  struct path *new_dir, struct dentry *new_dentry)
+{
+	struct path path1, path2;
+	void *msg;
+	int len, err;
+	struct pg_inode_sec *sec;
+	struct inode *inode;
+	anoubis_cookie_t pgid = anoubis_get_playgroundid();
+
+	inode = old_dentry->d_inode;
+	if (!pgid || !inode || !S_ISDIR(inode->i_mode))
+		return 0;
+	if (!anoubis_playground_enabled(old_dentry))
+		return 0;
+	sec = ISEC(inode);
+	/*
+	 * No user confirmations for file systems that do not support
+	 * xattrs and the playground. inode_rename will take care of these
+	 * cases.
+	 */
+	if (!sec || sec->havexattr == 0)
+		return 0;
+	/* No restrictions on known playground files here. */
+	if (sec->pgid != 0)
+		return 0;
+	/* This is a playground process and source is a production file. */
+	path1.mnt = old_dir->mnt;
+	path1.dentry = old_dentry;
+	path2.mnt = new_dir->mnt;
+	path2.dentry = new_dentry;
+	pg_stat_rename_ask++;
+	len = pg_open_message_fill(&msg, ANOUBIS_PLAYGROUND_OP_RENAME,
+						&path1, &path2);
+	if (len < 0)
+		return len;
+	err = anoubis_raise(msg, len, ANOUBIS_SOURCE_PLAYGROUND);
+	if (err == -EPIPE)
+		err = -EIO;
+	if (err < 0)
+		return err;
+	sec->renameok = 1;
+	sec->accesstask = anoubis_get_task_cookie();
+	return 0;
+}
+
+/**
+ * This implements the inode_readlink security hook. Reading symlinks is
+ * allowed for production file symlinks and for symlinks that live in the
+ * same playground as the process.
+ *
+ * @param dentry The symlink to read.
+ * @return Zero if readlink is allowed, or a negative error code.
+ */
+static int pg_inode_readlink(struct dentry *dentry)
+{
+	struct pg_inode_sec *sec;
+	anoubis_cookie_t pgid = anoubis_get_playgroundid();
+
+	if (!anoubis_playground_enabled(dentry))
+		return 0;
+	sec = ISEC(dentry->d_inode);
+	if (sec->pgid == 0)
+		return 0;
+	if (sec->pgid == pgid)
+		return 0;
+	return -EACCES;
+}
+
+/**
+ * This implements the inode_setxattr security hook. We simply deny
+ * access to the playground security attribute for everyone.
+ *
+ * @param dentry The dentry for the file.
+ * @param name The name of the security attribute.
+ * @param value The value to set.
+ * @param size The number of bytes in the value.
+ * @param flags Flags form the setxattr system call.
+ * @return Zero if the system call can continue, a negative error code
+ *     if the system call is not allowed.
+ */
+static int pg_inode_setxattr(struct dentry * dentry, const char * name,
+    const void * value, size_t size, int flags)
+{
+	if (strcmp(name, XATTR_ANOUBIS_PG) == 0)
+		return -EPERM;
+	return 0;
+}
+
+/**
+ * This implements the inode_removexattr security hook. Removing the
+ * extended attribute is the first step of a commit. However, this may
+ * require the daemon to perform a scan first. Additionally, it is not
+ * allowed to commit an inode into an uncommitted playground directory,
+ * in this case the user must commit the directory first.
+ *
+ * @param dentry The dentry for the file.
+ * @param name The name of the security attribute.
+ * @return Zero if the system call can continue, a negative error code
+ *     if the system call is not allowed.
+ */
+static int pg_inode_removexattr(struct dentry *dentry, const char *name)
+{
+	struct inode *inode = dentry->d_inode;
+	struct dentry *parent = dentry->d_parent;
+	struct pg_inode_sec *sec;
+	int ret = -EPERM;
+
+	if (strcmp(name, XATTR_ANOUBIS_PG) != 0)
+		return 0;
+	if (!inode)
+		return 0;
+	if (!is_owner_or_cap(inode))
+		return -EACCES;
+	sec = ISEC(inode);
+	if (sec == NULL || !sec->havexattr || !sec->pgenabled || sec->pgid == 0)
+		return -EPERM;
+	if (parent && anoubis_playground_enabled(parent)) {
+		struct pg_inode_sec *dsec = ISEC(parent->d_inode);
+
+		if (dsec && dsec->pgid)
+			return -ENOTEMPTY;
+	}
+	switch(atomic_read(&sec->scanstatus)) {
+	case PG_SCANSTATUS_NONE:
+	case PG_SCANSTATUS_INPROGRESS:
+		/*
+		 * Send an event even if the scan appears to be in
+		 * progress already. This can happen if a previous scan
+		 * failed.
+		 */
+		pg_notify_file(dentry, NULL, ANOUBIS_PGFILE_SCAN,
+		    sec->pgid, NULL);
+		ret = -EINPROGRESS;
+		break;
+	case PG_SCANSTATUS_SUCCESS:
+		atomic_cmpxchg(&sec->scanstatus, PG_SCANSTATUS_SUCCESS,
+						PG_SCANSTATUS_COMMITTED);
+		ret = -ETXTBSY;
+		if (atomic_read(&sec->scanstatus) == PG_SCANSTATUS_COMMITTED) {
+			anoubis_cookie_t pgid = sec->pgid;
+
+			sec->pgid = 0;
+			if (pgid)
+				pg_notify_delete_all(dentry->d_inode, pgid);
+			ret = 0;
+			smp_mb();
+			atomic_set(&sec->scanstatus, PG_SCANSTATUS_NONE);
+		}
+		break;
+	case PG_SCANSTATUS_COMMITTED:
+		ret = 0;
+		break;
+	default:
+		BUG();
+	}
+	return ret;
+}
+
+/**
+ * This implements the d_instantiate security hook.
+ * We use this point to read a security label from an extended
+ * attribute on disk.
+ *
+ * @param dentry The directory entry for the new file.
+ * @param inode The inode that is now associated with this file.
+ * @return  None.
+ *
+ * NOTE: There is no error code for this hook. Thus we simply mark
+ * NOTE: the inode as a production (by not setting havexattr to true)
+ * NOTE: if something goes wrong.
+ */
+static void pg_d_instantiate(struct dentry *dentry, struct inode *inode)
+{
+	struct pg_inode_sec *isec;
+	static char attrbuf[128];
+	unsigned long long int fspgid;
+	char ch;
+	int rc;
+
+	if (!inode)
+		return;
+	isec = ISEC(inode);
+	if (!isec)
+		return;
+	if (isec->pgenabled == 0)
+		goto noxattr;
+	if (!inode->i_op->getxattr)
+		goto noxattr;
+	BUG_ON(dentry == NULL);
+	rc = inode->i_op->getxattr(dentry, XATTR_ANOUBIS_PG, attrbuf,
+	    sizeof(attrbuf) - 1);
+	switch (-rc) {
+	case ENODATA:
+		isec->havexattr = 1;
+		isec->pgid = 0;
+		return;
+	case ENOTSUPP:
+	case EOPNOTSUPP:
+		goto noxattr;
+	}
+	if (rc < 0) {
+		printk(KERN_ERR "anoubis_playground: Error %d while reading "
+					"extended attributes\n", rc);
+		goto noxattr;
+	}
+	attrbuf[rc] = 0;
+	if (sscanf(attrbuf, "%llx%c", &fspgid, &ch) != 1) {
+		printk(KERN_ERR "anoubis_playground: Malformed extended "
+							"attribute\n");
+		goto noxattr;
+	}
+	BUG_ON(dentry->d_inode != inode);
+	isec->pgid = fspgid;
+	isec->havexattr = 1;
+	if (fspgid)
+		pg_notify_file(dentry, NULL, ANOUBIS_PGFILE_INSTANTIATE,
+		    fspgid, NULL);
+	return;
+noxattr:
+	isec->havexattr = 0;
+	isec->pgid = 0;
+}
+
+/**
+ * Implements the inode_init_security hook. We set the inode's security
+ * label to the current processes playground ID for this newly created
+ * file.
+ *
+ * @param inode The inode of the new file.
+ * @param dir The directory that the file resides in.
+ * @param namep The name of the security attribute (only the suffix without
+ *     the "security." preifx) is allocated and stored here. The caller will
+ *     free the memory.
+ * @param valuep The text representation of the security label is stored
+ *     here. The memory for the label ist allocated and must be freed
+ *     by the caller.
+ * @param lenp The length of the data returned in @valuep is stored here.
+ * @return Zero in case of success, -EOPNOTSUPP if no security attribute
+ *     is needed and -ENOMEM if memory allocation failed.
+ */
+static int pg_inode_init_security(struct inode *inode, struct inode *dir,
+				  char **namep, void **valuep, size_t *lenp)
+{
+	struct pg_inode_sec *sec;
+	anoubis_cookie_t pgid = anoubis_get_playgroundid();
+	char *name;
+	void *value;
+	const char *ftype;
+	int i;
+
+	if (!inode)
+		return -EOPNOTSUPP;
+	sec = ISEC(inode);
+	if (!sec)
+		return -EOPNOTSUPP;
+	sec->havexattr = 1;
+	/* Do not label sockets ... */
+	if (S_ISSOCK(inode->i_mode))
+		sec->pgid = 0;
+	else
+		sec->pgid = pgid;
+	sec->pgenabled = 1;
+	sec->readdirok = 1;
+	sec->stacktype = INODE_STACKTYPE_NONE;
+	ftype = inode->i_sb->s_type->name;
+	if (strcmp(ftype, "dazukofs") == 0)
+		sec->stacktype = INODE_STACKTYPE_DAZUKO;
+	else if (strcmp(ftype, "ecryptfs") == 0)
+		sec->stacktype = INODE_STACKTYPE_ECRYPTFS;
+	for (i=0; nopg_fs[i]; ++i) {
+		if (strcmp(ftype, nopg_fs[i]) == 0) {
+			sec->pgenabled = 0;
+			break;
+		}
+	}
+	for (i=0; broken_readdir_fs[i]; ++i) {
+		if (strcmp(ftype, broken_readdir_fs[i]) == 0) {
+			sec->readdirok = 0;
+			break;
+		}
+	}
+	if (sec->pgid == 0)
+		return -EOPNOTSUPP;
+	name = kstrdup(XATTR_ANOUBIS_PG_SUFFIX, GFP_KERNEL);
+	if (!name)
+		return -ENOMEM;
+	value = kmalloc(128, GFP_KERNEL);
+	if (!value) {
+		kfree(name);
+		return -ENOMEM;
+	}
+	sprintf(value, "%llx", (long long)pgid);
+	if (namep)
+		(*namep) = name;
+	else
+		kfree(name);
+	if (lenp)
+		(*lenp) = strlen(value) + 1;
+	if (valuep)
+		(*valuep) = value;
+	else
+		kfree(value);
+	return 0;
+}
+
+/**
+ * This implements the inode_delete security hook. This hook is called
+ * immediately before an on disk inode is released. We use this to notify
+ * the anoubis daemon about the deleted inode. The anoubis daemon can use
+ * this to remove the inode from its playground.
+ *
+ * @param inode The inode that is deleted.
+ * @return None.
+ */
+static void pg_inode_delete(struct inode *inode)
+{
+	struct pg_inode_sec *sec = ISEC(inode);
+
+	if (sec && sec->pgid)
+		pg_notify_file(NULL, inode, ANOUBIS_PGFILE_DELETE,
+		    sec->pgid, NULL);
+}
+
+/**
+ * This implements the pg_cred_prepare security hook. We use this
+ * to track playground-IDs. The playground-ID of the new credentials
+ * is copied from the old credentials. If the old credentials do not
+ * have a security label, the playground-ID of the new credentials is
+ * zero.
+ *
+ * @param cred The new credentials.
+ * @param ocred The old credentials.
+ * @param gfp Memory allocation flags to use for any memory allocation.
+ * @return Zero in case of success, a negative error code, in case of
+ *     an error.
+ */
+static int pg_cred_prepare(struct cred *cred, const struct cred *ocred,
+							gfp_t gfp)
+{
+	struct pg_task_sec *sec, *old;
+
+	sec = kmalloc(sizeof(struct pg_task_sec), gfp);
+	if (!sec)
+		return -ENOMEM;
+	sec->pgcreate = 0;
+	old = CSEC(ocred);
+	if (old)
+		sec->pgid = old->pgid;
+	else
+		sec->pgid = 0;
+	old = SETCSEC(cred, sec);
+	BUG_ON(old);
+	return 0;
+}
+
+/**
+ * This function implements the cred_commit security hook.
+ * We copy the playground-ID from the old to the new creditials.
+ *
+ * @param nc The new credentials.
+ * @param odl The old credentials.
+ * @return None.
+ */
+static void pg_cred_commit(struct cred *nc, const struct cred* old)
+{
+	struct pg_task_sec *nsec = CSEC(nc);
+	struct pg_task_sec *osec = CSEC(old);
+
+	if (nsec && osec && nsec->pgid != osec->pgid) {
+		nsec->pgid = osec->pgid;
+		if (nsec->pgid)
+			pg_notify_pgid_change();
+	}
+}
+
+/**
+ * This implements the cred_free security hook.
+ * We free the playground security label associated with the creditials.
+ *
+ * @param cred The credentials.
+ * @return None.
+ */
+static void pg_cred_free(struct cred * cred)
+{
+	struct pg_task_sec *sec = SETCSEC(cred, NULL);
+
+	if (sec)
+		kfree(sec);
+}
+
+/**
+ * Release the handle of the lower file (if any) in the given file
+ * security label.
+ *
+ * @param fsec A pointer to the security label.
+ * @return None.
+ */
+static inline void pg_release_lowerfile(struct pg_file_sec *fsec)
+{
+	if (fsec->lower) {
+		allow_write_access(fsec->lower);
+		fput(fsec->lower);
+		fsec->lower = NULL;
+	}
+}
+
+/**
+ * This implements the file_alloc_security security hook.
+ * We allocate space for the file security label and initialize the
+ * lower file to NULL.
+ *
+ * @param file The file handle.
+ * @return Zero in case of success, a negative error code in case of an error.
+ */
+static int pg_file_alloc_security(struct file *file)
+{
+	struct pg_file_sec *fsec, *old;
+
+	fsec = kmalloc(sizeof(struct pg_file_sec), GFP_KERNEL);
+	if (fsec == NULL)
+		return -ENOMEM;
+	fsec->lower = NULL;
+	old = SETFSEC(file, fsec);
+	BUG_ON(old);
+	return 0;
+}
+
+/**
+ * This implements the file_free_security security hook.
+ * We release the label and the file handle of the lower file if it is
+ * still there.
+ *
+ * @param file The (upper) file handle.
+ */
+static void pg_file_free_security(struct file *file)
+{
+	struct pg_file_sec *fsec = SETFSEC(file, NULL);
+
+	if (!fsec)
+		return;
+	pg_release_lowerfile(fsec);
+	kfree(fsec);
+}
+
+/**
+ * This implements the pg_socket_connect hook. We do not allow socket
+ * connects of a playground process if the user does not confirm that this
+ * is ok.
+ *
+ * @param sock The socket.
+ * @param address The target address of the connect.
+ * @param addlen The length of the address.
+ * @return Zero if access is allowed or a negative error code.
+ */
+static int pg_socket_connect(struct socket *sock, struct sockaddr *address,
+    int addrlen)
+{
+	struct sockaddr_un *sunname = (struct sockaddr_un *)address;
+	struct path path;
+	int err = 0, len;
+	anoubis_cookie_t pgid = anoubis_get_playgroundid();
+	void *msg;
+
+	if (!sock || !sock->sk)
+		return -EBADF;
+	if (sock->sk->sk_family != AF_UNIX)
+		return 0;
+	if (sunname->sun_path[0] == 0)
+		return 0;
+	if (!pgid)
+		return 0;
+
+	err = kern_path(sunname->sun_path, LOOKUP_FOLLOW, &path);
+	if (err)
+		return err;
+	pg_stat_devicewrite_ask++;
+	len = pg_open_message_fill(&msg, ANOUBIS_PLAYGROUND_OP_OPEN,
+							&path, NULL);
+	if (len < 0) {
+		path_put(&path);
+		return len;
+	}
+	err = anoubis_raise(msg, len, ANOUBIS_SOURCE_PLAYGROUND);
+	if (err == -EPIPE)
+		err = -EIO;
+	if (err)
+		pg_stat_devicewrite_deny++;
+	path_put(&path);
+	return err;
+}
+
+/**
+ * This implements the dentry_open security hook. We use this to copy
+ * data from the lower file to the playground. Additionally, we do a
+ * delayed check for open of special files in this function. These open
+ * requests must trigger an event with a path name, which is not possible
+ * in inode_permission. Note that we can shortcut these checks compared
+ * to inode_permission, because inode_permission already denied stuff
+ * that does not require events.
+ *
+ * @param file The upper file.
+ * @cred Credentials, unused here.
+ * @return Zero in case of success, a negative error code in case of an error.
+ */
+static int pg_dentry_open(struct file *file, const struct cred *cred)
+{
+	struct pg_file_sec *fsec = FSEC(file);
+	struct inode *lowerinode;
+	struct inode *upperinode;
+	mm_segment_t oldfs;
+	loff_t size, rpos = 0, wpos = 0;
+	struct page *p;
+	anoubis_cookie_t pgid = anoubis_get_playgroundid();
+	struct pg_inode_sec *uppersec;
+	int err;
+
+	upperinode = file->f_path.dentry->d_inode;
+	/* These cases were properly handled by inode_permission. */
+	if (!anoubis_playground_enabled(file->f_path.dentry) || pgid == 0) {
+		BUG_ON(fsec->lower);
+		return 0;
+	}
+	BUG_ON(!upperinode || (fsec->lower && !S_ISREG(upperinode->i_mode)));
+	/*
+	 * We don't mediate access to character devices for now.
+	 * A typical program needs at least access to /dev/tty, /dev/ptmx
+	 */
+	if (S_ISCHR(upperinode->i_mode))
+		return 0;
+	uppersec = ISEC(upperinode);
+	/*
+	 * inode_permission should have cleared the scanstatus. However,
+	 * this can race with the anoubisd starting (and potentially
+	 * completing) a scan. Catch this and return ETXTBSY in this case.
+	 */
+	if (uppersec && (file->f_mode & FMODE_WRITE) &&
+	    atomic_read(&uppersec->scanstatus) != PG_SCANSTATUS_NONE) {
+		return -ETXTBSY;
+	}
+	if (S_ISSOCK(upperinode->i_mode) || S_ISCHR(upperinode->i_mode)
+	    || S_ISBLK(upperinode->i_mode) || S_ISFIFO(upperinode->i_mode)) {
+		struct pg_inode_sec *sec;
+		void *msg = NULL;
+		int len, ret;
+
+		/* Non-write opens were handled in inode_permission. */
+		if ((file->f_mode & FMODE_WRITE) == 0)
+			return 0;
+		sec = ISEC(upperinode);
+		/* Access to playground files is handled in inode_permission. */
+		if (sec && sec->havexattr && sec->pgid)
+			return 0;
+		/*
+		 * Ok, this is a production file. Access is only allowed, if
+		 * the user agrees.
+		 */
+		pg_stat_devicewrite_ask++;
+		len = pg_open_message_fill(&msg, ANOUBIS_PLAYGROUND_OP_OPEN,
+						&file->f_path, NULL);
+		if (len < 0)
+			return len;
+		ret = anoubis_raise(msg, len, ANOUBIS_SOURCE_PLAYGROUND);
+		if (ret == -EPIPE)
+			ret = -EIO;
+		if (ret)
+			pg_stat_devicewrite_deny++;
+		return ret;
+	}
+	if (fsec->lower == NULL)
+		return 0;
+	lowerinode = fsec->lower->f_path.dentry->d_inode;
+	p = alloc_page(GFP_KERNEL);
+	err = -ENOMEM;
+	if (!p)
+		goto err_fput;
+	size = i_size_read(lowerinode);
+	oldfs = get_fs();
+	set_fs(get_ds());
+	err = -EIO;
+	while (rpos < size) {
+		ssize_t ret;
+		int count = PAGE_SIZE;
+
+		if (unlikely(fatal_signal_pending(current)))
+			goto err;
+		if (size - rpos < count)
+			count = size - rpos;
+		ret = vfs_read(fsec->lower, page_address(p), count, &rpos);
+		if (ret != count)
+			goto err;
+		ret = vfs_write(file, page_address(p), count, &wpos);
+		if (ret != count)
+			goto err;
+	}
+	BUG_ON(rpos != wpos);
+	err = 0;
+err:
+	set_fs(oldfs);
+	__free_page(p);
+err_fput:
+	pg_release_lowerfile(fsec);
+	return err;
+}
+
+/**
+ * Return the playground-ID of the current process.
+ *
+ * @param None.
+ * @return The playground-ID of the current process. Zero means that
+ *     the process is not in a playground.
+ */
+anoubis_cookie_t anoubis_get_playgroundid_tsk(struct task_struct *tsk)
+{
+	const struct cred *cred = __task_cred(tsk);
+	struct pg_task_sec *sec;
+
+	if (unlikely(!cred))
+		return 0;
+	sec = CSEC(cred);
+	if (unlikely(!sec))
+		return 0;
+	return sec->pgid;
+}
+
+/**
+ * Return true if the current process has the pgcreate flag set in
+ * its task label.
+ *
+ * @param None.
+ * @return True if the flag is set.
+ */
+int anoubis_playground_get_pgcreate(void)
+{
+	const struct cred *cred = __task_cred(current);
+	struct pg_task_sec *sec;
+
+	if (unlikely(!cred))
+		return 0;
+	sec = CSEC(cred);
+	return sec && sec->pgcreate;
+}
+
+/**
+ * Move the current process into a new playground. This is done
+ * by assigning a playground-ID to the current process if it does not
+ * have one.
+ *
+ * @param rename True if the playground should just be renamed.
+ * @return Zero if a new playground was created, -EBUSY if the current
+ *     process is already in a playground, a negative error code if something
+ *     else went wrong.
+ */
+int anoubis_playground_create(int rename)
+{
+	const struct cred *cred = __task_cred(current);
+	struct pg_task_sec *sec;
+
+	if (unlikely(!cred))
+		return -ESRCH;
+	sec = CSEC(cred);
+	if (unlikely(!sec))
+		return -ESRCH;
+	if (rename) {
+		if (sec->pgid == 0)
+			return -ESRCH;
+		pg_notify_pgid_change();
+		return 0;
+	}
+	if (sec->pgid)
+		return -EBUSY;
+	/*
+	 * Playground creation is not allowed if the task
+	 * used super user privileges.
+	 */
+	if (current->flags & PF_SUPERPRIV)
+		return -EPERM;
+	/*
+	 * A process that already has multiple threads cannot start a
+	 * new playground.
+	 */
+	if (!thread_group_empty(current))
+		return -EPERM;
+	sec->pgid = anoubis_alloc_pgid();
+	pg_notify_pgid_change();
+	return 0;
+}
+
+/**
+ * Return true if the playground feature is enabled for this dentry.
+ * Lookups and access checks will work exactly as normal for this dentry
+ * if this function returns false. This is useful for file systems that
+ * do not support playground features (proc, sysfs).
+ *
+ * @param dentry The directory entry to check.
+ * @return True if playground features are enabled for this dentry.
+ *     False if this is not the case.
+ */
+int anoubis_playground_enabled(struct dentry *dentry)
+{
+	struct pg_inode_sec *sec;
+
+	if (!dentry->d_inode)
+		return 0;
+	sec = ISEC(dentry->d_inode);
+	if (!sec) {
+		printk(KERN_ERR "anoubis_pg: NULL security attribute\n");
+		return 0;
+	}
+	return sec->pgenabled;
+}
+
+/**
+ * Return true if a lookup during filldir/readdir is ok on this inode.
+ *
+ * @param inode The inode to check.
+ * @return True if lookup during readdir is ok.
+ */
+int anoubis_playground_readdirok(struct inode *inode)
+{
+	struct pg_inode_sec	*sec;
+
+	if (!inode)
+		return 1;
+	sec = _ISEC(inode);
+	if (!sec)
+		return 1;
+	return sec->readdirok;
+}
+
+/**
+ * Assign a lower file handle to the given playground file. The data of
+ * the lower handle will be copied to the upper file handle if open is
+ * successful.
+ *
+ * @param upper The upper file handle.
+ * @param lower The lower file hanlde.
+ * @return Zero in case of success, a negative error code (usually -EBUSY)
+ *     if an error occured.
+ */
+int anoubis_playground_set_lowerfile(struct file *upper, struct file *lower)
+{
+	struct pg_file_sec *fsec = FSEC(upper);
+	int err;
+
+	BUG_ON(fsec == NULL);
+	pg_release_lowerfile(fsec);
+	err = deny_write_access(lower);
+	if (err < 0)
+		return err;
+	fsec->lower = lower;
+	return 0;
+}
+
+/**
+ * Open the regular file given by oldname (interpreted relative to atfd)
+ * for writing. This should only happend for playground processes and will
+ * trigger a copy of the file into the playground. The file is closed
+ * immediately after opening because we are only interested in the side
+ * effect. Only regular files can be copied with this function.
+ *
+ * @param atfd The filedescriptor of the base directory. Relative paths in
+ *     oldname are interpreted relative to this directory (see openat(2)).
+ * @param oldname The name of the file that is to be copied.
+ * @return Zero if the file is now cloned, either because this function
+ *    call initiated the copy or because some other process did.
+ *    A negative error code if an error occured.
+ */
+int anoubis_playground_clone_reg(int atfd, const char __user *oldname)
+{
+	int fd;
+
+	fd = sys_openat(atfd, oldname, O_WRONLY, 0);
+	if (fd < 0)
+		return fd;
+	sys_close(fd);
+	return 0;
+}
+
+/**
+ * This function clones an existing production file symlink into
+ * the currently active playground. This is done by creating a new
+ * symlink with the same link target.
+ *
+ * @param atfd The file descriptor of the start directory. Relative
+ *     pathnames in __oldname are interpreted relative to this directory.
+ * @param __oldname The non-playground name of the symlink to clone.
+ * @return Zero if the link was created, a negative error code if something
+ *     went wrong.
+ */
+int anoubis_playground_clone_symlink(int atfd, const char __user *__oldname)
+{
+	char *oldname = getname(__oldname);
+	char *link = __getname();
+	int err;
+	mm_segment_t oldfs;
+	const struct cred *cred = __task_cred(current);
+	struct pg_task_sec *sec;
+
+
+	if (unlikely(!cred))
+		return -EACCES;
+	sec = CSEC(cred);
+	if (unlikely(!sec))
+		return -EACCES;
+	if (!sec->pgid)
+		return -EIO;
+	err = -ENOMEM;
+	if (!oldname || !link)
+		goto err_free;
+	oldfs = get_fs();
+	set_fs(get_ds());
+	err = sys_readlinkat(atfd, oldname, link, PATH_MAX-1);
+	if (err < 0)
+		goto err;
+	link[err] = 0;
+	BUG_ON(sec->pgcreate);
+	sec->pgcreate = 1;
+	err = sys_symlinkat(link, atfd, oldname);
+	sec->pgcreate = 0;
+err:
+	set_fs(oldfs);
+err_free:
+	if (oldname)
+		__putname(oldname);
+	if (link)
+		__putname(link);
+	return err;
+}
+
+void anoubis_playground_clear_accessok(struct inode *inode)
+{
+	struct pg_inode_sec *sec;
+
+	if (!inode)
+		return;
+	sec = ISEC(inode);
+	if (!sec)
+		return;
+	sec->accesstask = 0;
+	sec->renameok = 0;
+}
+
+/**
+ * Try to change the scan status of the inode associated with the given
+ * file from oldstate to newstate. The return value is zero if the
+ * scan status has the new value either because it already had the new value
+ * or because the old value was replaced by the value. The scan status
+ * is never modifed if it differs from oldstate. Additionally, there
+ * must not be any file handle that have the inode open for writing.
+ *
+ * @param file The file that will have its scan status changed.
+ * @param oldstate The old expected scan status that should be replaced.
+ * @param newstate The new scan status.
+ * @return Zero if the scan status has the value newstate and all writers
+ *     have been locked out. A negative error code if the scan status
+ *     could not be set or if there still is a writer.
+ */
+static inline int anoubis_playground_scanioctl(struct file *file,
+					int oldstate, int newstate)
+{
+	struct pg_inode_sec *sec;
+	int ret;
+
+	if (file->f_path.dentry == NULL || file->f_path.dentry->d_inode == NULL)
+		return -EINVAL;
+	sec = ISEC(file->f_path.dentry->d_inode);
+	if (!sec || !sec->pgenabled)
+		return -EINVAL;
+	/* Lock out writers. */
+	ret = anoubis_deny_write_access(file);
+	if (ret < 0)
+		return ret;
+	ret = -EBUSY;
+	atomic_cmpxchg(&sec->scanstatus, oldstate, newstate);
+	if (atomic_read(&sec->scanstatus) == newstate)
+		ret = 0;
+	anoubis_allow_write_access(file);
+	return ret;
+}
+
+/**
+ * This implements the ANOUBIS_SCAN_STARTED ioctl. We change the
+ * scan status of the file from PG_SCANSTATUS_NONE to PG_SCANSTATUS_INPROGRESS.
+ *
+ * @param file The file affected by the ioctl.
+ * @return Zero in case of success, a negative error code in case of an
+ *     error, usually because the file is open for writing.
+ */
+int anoubis_playground_scanstarted(struct file *file)
+{
+	return anoubis_playground_scanioctl(file, PG_SCANSTATUS_NONE,
+	    PG_SCANSTATUS_INPROGRESS);
+}
+
+/**
+ * This implements the ANOUBIS_SCAN_STARTED ioctl. We change the
+ * scan status of the file from PG_SCANSTATUS_INPROGRESS to
+ * PG_SCANSTATUS_SUCCESS.
+ *
+ * @param file The file affected by the ioctl.
+ * @return Zero in case of success, a negative error code in case of an
+ *     error, usually because the file is open for writing.
+ */
+int anoubis_playground_scansuccess(struct file *file)
+{
+	return anoubis_playground_scanioctl(file, PG_SCANSTATUS_INPROGRESS,
+	    PG_SCANSTATUS_SUCCESS);
+}
+
+/**
+ * Security operations for the anoubis playground module.
+ */
+static struct anoubis_hooks pg_ops = {
+	.version = ANOUBISCORE_VERSION,
+	.inode_alloc_security = pg_inode_alloc_security,
+	.inode_free_security = pg_inode_free_security,
+	.inode_permission = pg_inode_permission,
+	.inode_create = pg_inode_create,
+	.inode_mknod = pg_inode_mknod,
+	.inode_mkdir = pg_inode_mkdir,
+	.inode_link = pg_inode_link,
+	.inode_symlink = pg_inode_symlink,
+	.inode_unlink = pg_inode_unlink,
+	.inode_rmdir = pg_inode_unlink,
+	.inode_rename = pg_inode_rename,
+	.path_rename = pg_path_rename,
+	.inode_readlink = pg_inode_readlink,
+	.inode_setxattr = pg_inode_setxattr,
+	.inode_removexattr = pg_inode_removexattr,
+	.d_instantiate = pg_d_instantiate,
+	.inode_init_security = pg_inode_init_security,
+	.inode_delete = pg_inode_delete,
+	.cred_prepare = pg_cred_prepare,
+	.cred_free = pg_cred_free,
+	.cred_commit = pg_cred_commit,
+	.file_alloc_security = pg_file_alloc_security,
+	.file_free_security = pg_file_free_security,
+	.dentry_open = pg_dentry_open,
+	.socket_connect = pg_socket_connect,
+	.anoubis_stats = pg_getstats,
+};
+
+/**
+ * Do the rest of the anoubis playground module initialization. The hooks
+ * have been registered earlier to make sure that /proc and /sysfs files
+ * get security labels, too. The load time cannot be set in the early
+ * initialization because the clock might not be set up.
+ *
+ * @param None.
+ * return Zero in case of success, a negative error code in case of an error.
+ */
+static int __init pg_init_late(void)
+{
+	struct timeval tv;
+
+	/* register ourselves with the security framework */
+	if (ac_index >= 0) {
+		do_gettimeofday(&tv);
+		pg_stat_loadtime = tv.tv_sec;
+		printk(KERN_INFO "anoubis_pg: Successfully initialized.\n");
+	}
+	return 0;
+}
+
+/**
+ * Register the playground security hooks. We do this early because we
+ * want inodes that are created early (/proc, /sysfs) to get labels, too.
+ *
+ * @param None.
+ * @return Zero in case of success, a negative error code in case of errors.
+ */
+static int __init pg_init_early(void)
+{
+	int rc;
+
+	if ((rc = anoubis_register(&pg_ops, &ac_index)) < 0) {
+		ac_index = -1;
+		printk(KERN_ERR "anoubis_pg: Failure registering\n");
+		return rc;
+	}
+	printk(KERN_INFO "anoubis_pg: Early initialization complete.\n");
+	return 0;
+}
+
+security_initcall(pg_init_early);
+module_init(pg_init_late);
+
+EXPORT_SYMBOL(anoubis_get_playgroundid_tsk);
+EXPORT_SYMBOL(anoubis_playground_create);
+
+MODULE_AUTHOR("Christian Ehrhardt <ehrhardt@genua.de>");
+MODULE_DESCRIPTION("Anoubis playground module");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/security/anoubis/sfs.c b/security/anoubis/sfs.c
new file mode 100644
index 0000000..a1bd8e7
--- /dev/null
+++ b/security/anoubis/sfs.c
@@ -0,0 +1,1380 @@
+/*
+ * Copyright (c) 2008 GeNUA mbH <info@genua.de>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/* Anoubis Security Module. */
+
+/*
+ * NOTE:
+ * This module cannot be safely unloaded while a security hook is in
+ * progress. This basically means that the module cannot be unloaded safely
+ * at all. Currently we do not bump the module count in order to ease
+ * development. However, this may cause oopses at unload time.
+ */
+
+#include <linux/crypto.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/gfp.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mman.h>
+#include <linux/module.h>
+#include <linux/namei.h>
+#include <linux/sched.h>
+#include <linux/scatterlist.h>
+#include <linux/security.h>
+#include <linux/xattr.h>
+#include <linux/net.h>
+#include <linux/socket.h>
+#include <linux/un.h>
+#include <net/sock.h>
+#include <net/af_unix.h>
+
+#include <linux/anoubis.h>
+#include <linux/anoubis_sfs.h>
+#include <linux/anoubis_playground.h>
+
+#define XATTR_ANOUBIS_SYSSIG_SUFFIX "anoubis_syssig"
+#define XATTR_ANOUBIS_SKIPSUM_SUFFIX "anoubis_skipsum"
+#define XATTR_ANOUBIS_SYSSIG XATTR_SECURITY_PREFIX XATTR_ANOUBIS_SYSSIG_SUFFIX
+#define XATTR_ANOUBIS_SKIPSUM XATTR_SECURITY_PREFIX XATTR_ANOUBIS_SKIPSUM_SUFFIX
+
+static unsigned int checksum_max_size = 0;
+static int ac_index = -1;
+static char allow_path_buf[PAGE_SIZE] __initdata;
+
+struct allow_path_entry {
+	struct allow_path_entry *next;
+	unsigned int prefixlen;
+	char prefix[];
+};
+
+static struct allow_path_entry *allow_path_entries;
+
+/* Statistics */
+
+static u_int64_t sfs_stat_loadtime;
+static u_int64_t sfs_stat_csum_recalc;
+static u_int64_t sfs_stat_csum_recalc_fail;
+static u_int64_t sfs_stat_ev;
+static u_int64_t sfs_stat_ev_deny;
+#ifdef CONFIG_SECURITY_PATH
+static u_int64_t sfs_stat_path;
+static u_int64_t sfs_stat_path_deny;
+#endif
+static u_int64_t sfs_stat_late_alloc;
+
+static struct anoubis_internal_stat_value sfs_stats[] = {
+	{ ANOUBIS_SOURCE_SFS, SFS_STAT_LOADTIME, &sfs_stat_loadtime },
+	{ ANOUBIS_SOURCE_SFS, SFS_STAT_CSUM_RECALC, &sfs_stat_csum_recalc },
+	{ ANOUBIS_SOURCE_SFS, SFS_STAT_CSUM_RECALC_FAIL,
+	    &sfs_stat_csum_recalc_fail },
+	{ ANOUBIS_SOURCE_SFS, SFS_STAT_EV, &sfs_stat_ev },
+	{ ANOUBIS_SOURCE_SFS, SFS_STAT_EV_DENY, &sfs_stat_ev_deny },
+#ifdef CONFIG_SECURITY_PATH
+	{ ANOUBIS_SOURCE_SFSPATH, SFS_STAT_PATH, &sfs_stat_path },
+	{ ANOUBIS_SOURCE_SFSPATH, SFS_STAT_PATH_DENY, &sfs_stat_path_deny },
+#endif
+	{ ANOUBIS_SOURCE_SFS, SFS_STAT_LATE_ALLOC, &sfs_stat_late_alloc },
+};
+
+static void sfs_getstats(struct anoubis_internal_stat_value **ptr, int * count)
+{
+	(*ptr) = sfs_stats;
+	(*count) = sizeof(sfs_stats)/sizeof(struct anoubis_internal_stat_value);
+}
+
+static inline int
+sfs_is_allow_path(const char *path)
+{
+	struct allow_path_entry	*entry;
+
+	for (entry = allow_path_entries; entry; entry = entry->next) {
+		if (strncmp(path, entry->prefix, entry->prefixlen) == 0)
+			return 1;
+	}
+	return 0;
+}
+
+/* Flags for @sfsmask in @sfs_inode_sec */
+#define SFS_CS_REQUIRED		0x01UL	/* Checksum should be calculated */
+#define SFS_CS_UPTODATE		0x02UL	/* Checksum in ISEC is uptodate */
+#define SFS_HAS_SYSSIG		0x04UL	/* inode has system signature */
+#define SFS_SYSSIG_CHECKED	0x08UL	/* presence of syssig checked */
+#define SFS_CS_OK		0x10UL	/* Checksum calculation possible */
+#define SFS_CS_CACHEOK		0x20UL	/* Checksum caching possible */
+#define SFS_ALWAYSFOLLOW	0x40UL	/* Always follow this link */
+#define SFS_LOCKWATCH		0x80UL	/* Report lock events for this file */
+
+/* Inode security label */
+struct sfs_inode_sec {
+	spinlock_t lock;
+	unsigned long sfsmask;
+	u8 hash[ANOUBIS_SFS_CS_LEN];
+	u8 syssig[ANOUBIS_SFS_CS_LEN];
+};
+
+/* Bprm security label */
+struct sfs_bprm_sec {
+	struct sfs_open_message * msg;
+	int len;
+	unsigned int need_secureexec:1;
+};
+
+/* Macros to access the security labels with their approriate type. */
+#define _SEC(TYPE,X) ((TYPE)anoubis_get_sublabel(&(X), ac_index))
+#define _SECCONST(TYPE,X) ((TYPE)anoubis_get_sublabel_const(X, ac_index))
+#define ISEC(X) _SEC(struct sfs_inode_sec *, (X)->i_security)
+#define CSEC(X) _SECCONST(struct sfs_bprm_sec *, (X)->security)
+
+#define _SETSEC(TYPE,X,V) ((TYPE)anoubis_set_sublabel(&(X), ac_index, (V)))
+#define SETISEC(X,V) _SETSEC(struct sfs_inode_sec *, ((X)->i_security), (V))
+#define SETCSEC(X,V) _SETSEC(struct sfs_bprm_sec *, ((X)->security), (V))
+
+/*
+ * Allow checksum calculations on these filesystem types but do not cache
+ * the result.
+ */
+static const char * csnocache[] = {
+	"nfs",
+	"nfs1",
+	"nfs2",
+	"nfs3",
+	"nfs4",
+	"smbfs",
+	NULL
+};
+
+/*
+ * Allow checksum calculations on these filesystem types and allow
+ * caching.
+ */
+static const char * csnodev[]  = {
+	"tmpfs",
+	"dazukofs",
+	"ecryptfs",
+	"aufs",
+	NULL,
+};
+
+/*
+ * Allow follow link on these file systems.
+ */
+static const char * alwaysfollow[] = {
+	"proc",
+	NULL,
+};
+
+/*
+ * Allocate a new inode security structure. This is might be called with
+ * spinlocks held. In this case gfp must be make sure that the memory
+ * allocation does not sleep. However, this also means that any other
+ * tasks that are performed by the function must not sleep.
+ */
+static inline struct sfs_inode_sec *
+__sfs_inode_alloc_security_common(struct inode * inode, gfp_t gfp)
+{
+	int i;
+	struct sfs_inode_sec * sec, * old;
+	sec = kmalloc(sizeof (struct sfs_inode_sec), gfp);
+	if (!sec)
+		return NULL;
+	spin_lock_init(&sec->lock);
+	sec->sfsmask = SFS_CS_REQUIRED;
+	if ((inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV)) {
+		sec->sfsmask |= (SFS_CS_OK|SFS_CS_CACHEOK);
+	} else {
+		const char * ftype = inode->i_sb->s_type->name;
+		for (i=0; csnocache[i]; ++i) {
+			if (strcmp(ftype, csnocache[i]) == 0)
+				sec->sfsmask |= SFS_CS_OK;
+		}
+		for (i=0; csnodev[i]; ++i) {
+			if (strcmp(ftype, csnodev[i]) == 0)
+				sec->sfsmask |= (SFS_CS_OK|SFS_CS_CACHEOK);
+		}
+		for (i=0; alwaysfollow[i]; ++i) {
+			if (strcmp(ftype, alwaysfollow[i]) == 0)
+				sec->sfsmask |= SFS_ALWAYSFOLLOW;
+		}
+	}
+	old = SETISEC(inode, sec);
+	BUG_ON(old);
+	return sec;
+}
+
+/* Allocate security information for an in-kernel inode.  */
+static int sfs_inode_alloc_security(struct inode * inode)
+{
+	if (likely(__sfs_inode_alloc_security_common(inode, GFP_KERNEL)))
+		return 0;
+	return -ENOMEM;
+}
+
+
+static spinlock_t late_alloc_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Allocate inode security information for an inode that already existed
+ * before the security modules were loaded. We have to be careful with regards
+ * to locking because several callers might try to allocate a new inode
+ * structure at the same time.
+ */
+static inline struct sfs_inode_sec *
+sfs_late_inode_alloc_security(struct inode * inode)
+{
+	struct sfs_inode_sec * sec = ISEC(inode);
+	if (likely(sec))
+		return sec;
+	sfs_stat_late_alloc++;
+	spin_lock(&late_alloc_lock);
+	sec = ISEC(inode);
+	if (likely(!sec)) {
+		sec = __sfs_inode_alloc_security_common(inode, GFP_ATOMIC);
+	}
+	spin_unlock(&late_alloc_lock);
+	return sec;
+}
+
+/* Free security information of an in-kernel inode. */
+static void sfs_inode_free_security (struct inode * inode)
+{
+	struct sfs_inode_sec * sec = SETISEC(inode, NULL);
+	if (!sec)
+		return;
+	kfree (sec);
+}
+
+static inline int csum_uptodate(struct sfs_inode_sec * sec)
+{
+	int uptodate;
+	spin_lock(&sec->lock);
+	uptodate = sec->sfsmask & SFS_CS_UPTODATE;
+	spin_unlock(&sec->lock);
+	return uptodate;
+}
+
+/*
+ * Calculate the SHA-256 digest of the file given by file and inode.
+ * If the calculation is successful SFS_CS_UPTODATE is set. Checksum
+ * calculation is only done if the file can be protected from write
+ * accesses during the calculation using deny_write_access and if
+ * SFS_CS_UPTODATE is not already set.
+ */
+static int sfs_do_csum(struct file * file, struct inode * inode,
+    struct sfs_inode_sec * sec)
+{
+	struct hash_desc cdesc;
+	loff_t size, pos = 0;
+	u8 csum[ANOUBIS_SFS_CS_LEN];
+	int err;
+	mm_segment_t oldfs;
+	struct page * p;
+
+	BUG_ON(!sec);
+	err = anoubis_deny_write_access(file);
+	if (err)
+		return err;
+	if (csum_uptodate(sec)) {
+		anoubis_allow_write_access(file);
+		return 0;
+	}
+	sfs_stat_csum_recalc++;
+	p = alloc_page(GFP_KERNEL);
+	if (!p)
+		goto out_allow_write;
+	size = i_size_read(inode);
+	cdesc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+	cdesc.tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(cdesc.tfm)) {
+		err = PTR_ERR(cdesc.tfm);
+		goto out_allow_write;
+	}
+	err = crypto_hash_init(&cdesc);
+	if (err)
+		goto out;
+	oldfs = get_fs();
+	set_fs(get_ds());
+	while(pos < size) {
+		ssize_t ret;
+		int count = PAGE_SIZE;
+		struct scatterlist sg[1];
+
+		if (unlikely(fatal_signal_pending(current))) {
+			err = EIO;
+			set_fs(oldfs);
+			goto out;
+		}
+		if (size - pos < count)
+			count = size - pos;
+		ret = vfs_read(file, page_address(p), count, &pos);
+		if (ret != count) {
+			err = EIO;
+			set_fs(oldfs);
+			goto out;
+		}
+		sg_set_page(sg, p, count, 0);
+		err = crypto_hash_update(&cdesc, sg, count);
+		if (err) {
+			err = EIO;
+			set_fs(oldfs);
+			goto out;
+		}
+	}
+	set_fs(oldfs);
+	err = crypto_hash_final(&cdesc, csum);
+	if (err)
+		goto out;
+	spin_lock(&sec->lock);
+	memcpy(&sec->hash, csum, ANOUBIS_SFS_CS_LEN);
+	sec->sfsmask |= SFS_CS_UPTODATE;
+	spin_unlock(&sec->lock);
+	err = 0;
+out:
+	crypto_free_hash(cdesc.tfm);
+out_allow_write:
+	anoubis_allow_write_access(file);
+	if (p)
+		__free_page(p);
+	return err;
+}
+
+/*
+ * Return true if checksum calculation for this file should be skipped.
+ * Configured either via the module parameter, or an extended attribute.
+ */
+static inline int skipsum_ok(struct inode * inode, struct dentry * dentry)
+{
+	struct sfs_inode_sec * sec;
+
+	if (!dentry || !inode)
+		return 0;
+	if (!S_ISREG(inode->i_mode))
+		return 0;
+	sec = ISEC(inode);
+	if (!sec)
+		return 0;
+
+	if (checksum_max_size && (i_size_read(inode) > checksum_max_size))
+		goto skip;
+	if (inode->i_op->getxattr &&
+	    (inode->i_op->getxattr(dentry, XATTR_ANOUBIS_SKIPSUM, NULL, 0) > 0))
+		goto skip;
+
+	spin_lock(&sec->lock);
+	sec->sfsmask |= SFS_CS_REQUIRED;
+	spin_unlock(&sec->lock);
+	return 0;
+skip:
+	spin_lock(&sec->lock);
+	sec->sfsmask ^= SFS_CS_REQUIRED;
+	spin_unlock(&sec->lock);
+	return 1;
+}
+
+/*
+ * Return true if checksum calculation for this file is possible. The file
+ * must be a regular file on a device backed file system. The latter
+ * restriction basically excludes pseudo file systems like /proc and
+ * network file systems such as NFS.
+ */
+static inline int checksum_ok(struct inode * inode)
+{
+	int ret;
+	struct sfs_inode_sec * sec;
+	if (!inode)
+		return 0;
+	if (!S_ISREG(inode->i_mode))
+		return 0;
+	sec = ISEC(inode);
+	if (!sec)
+		return 0;
+	spin_lock(&sec->lock);
+	ret = (sec->sfsmask & SFS_CS_OK);
+	spin_unlock(&sec->lock);
+	return ret;
+}
+
+/*
+ * Update checksum of file using @sfs_do_csum if the inode is marked
+ * with the SFS_CS_REQUIRED flag.
+ */
+static inline void sfs_csum(struct file * file, struct inode * inode)
+{
+	int required, ret;
+	struct sfs_inode_sec * sec = ISEC(inode);
+
+	if (!sec)
+		return;
+	spin_lock(&sec->lock);
+	required = (sec->sfsmask & SFS_CS_REQUIRED);
+	spin_unlock(&sec->lock);
+	if (!required)
+		return;
+	ret = sfs_do_csum(file, inode, sec);
+	if (ret)
+		sfs_stat_csum_recalc_fail++;
+}
+
+/*
+ * Read the system signature of the inode assiocated with dentry into
+ * the inode's security label if it is not already there.
+ * Returns
+ *    - a positive value if the inode has a system signature,
+ *    - zero if it does not have one and
+ *    - a negative value if an error occured while reading the signature.
+ */
+static int sfs_read_syssig(struct dentry * dentry)
+{
+	struct inode * inode = dentry->d_inode;
+	u8 buf[ANOUBIS_SFS_CS_LEN];
+	int ret;
+	struct sfs_inode_sec * sec;
+
+	sec = sfs_late_inode_alloc_security(inode);
+	if (!sec)
+		return -ENOMEM;
+	/* we only validate syssig on checksum_ok filesystems */
+	if (!checksum_ok(inode))
+		return 0;
+	spin_lock(&sec->lock);
+	ret = sec->sfsmask;
+	spin_unlock(&sec->lock);
+	if (ret & SFS_SYSSIG_CHECKED)
+		return ret & SFS_HAS_SYSSIG;
+	if (!inode->i_op->getxattr)
+		goto nosig;
+	ret = inode->i_op->getxattr(dentry, XATTR_ANOUBIS_SYSSIG, NULL, 0);
+	if (ret == -ENODATA || ret == -ENOTSUPP || ret == -EOPNOTSUPP)
+		goto nosig;
+	if (ret != ANOUBIS_SFS_CS_LEN) {
+		printk(KERN_ERR "anoubis_sfs: Error while reading "
+		    "system signature (%d)\n", ret);
+		return -EIO;
+	}
+	ret = inode->i_op->getxattr(dentry, XATTR_ANOUBIS_SYSSIG,
+	    buf, ANOUBIS_SFS_CS_LEN);
+	if (ret != ANOUBIS_SFS_CS_LEN) {
+		printk(KERN_ERR "anoubis_sfs: Error while reading "
+		    "system signature\n");
+		return -EIO;
+	}
+	spin_lock(&sec->lock);
+	memcpy(sec->syssig, buf, ANOUBIS_SFS_CS_LEN);
+	sec->sfsmask |= (SFS_SYSSIG_CHECKED|SFS_HAS_SYSSIG);
+	spin_unlock(&sec->lock);
+	return 1;
+nosig:
+	spin_lock(&sec->lock);
+	sec->sfsmask |= SFS_SYSSIG_CHECKED;
+	spin_unlock(&sec->lock);
+	return 0;
+}
+
+static int sfs_check_syssig(struct file * file, int mask)
+{
+	struct dentry * dentry = file->f_path.dentry;
+	struct inode * inode;
+	struct sfs_inode_sec * sec;
+	int ret, sfsmask;
+
+	if (!dentry)
+		return 0;
+	inode = dentry->d_inode;
+	if (!inode)
+		return 0;
+	/* We only validate syssig on checksum_ok filesystems */
+	if (!checksum_ok(inode))
+		return 0;
+	ret = sfs_read_syssig(dentry);
+	if (ret <= 0)
+		return ret;
+	/* We do have a system signature. */
+	if (mask & MAY_WRITE)
+		return -EACCES;
+	sec = sfs_late_inode_alloc_security(inode);
+	if (!sec)
+		return -ENOMEM;
+	ret = sfs_do_csum(file, inode, sec);
+	if (ret) {
+		sfs_stat_csum_recalc_fail++;
+		return ret;
+	}
+	spin_lock(&sec->lock);
+	ret = 0;
+	sfsmask = sec->sfsmask & (SFS_HAS_SYSSIG|SFS_CS_UPTODATE);
+	if (sfsmask != (SFS_HAS_SYSSIG|SFS_CS_UPTODATE)
+	    || memcmp(sec->syssig, sec->hash, ANOUBIS_SFS_CS_LEN) != 0)
+		ret = -EBUSY;
+	spin_unlock(&sec->lock);
+	return ret;
+}
+
+/*
+ * Clear the SFS_CS_UPTODATE flag on every open for write and on
+ * if SFS_CS_CACHEOK is not set. The latter will suck wrt. performance
+ * on SFS but this is as good as we can do for now.
+ */
+static int sfs_inode_permission(struct inode * inode, int mask)
+{
+	struct sfs_inode_sec * sec;
+	sec = sfs_late_inode_alloc_security(inode);
+	if (sec) {
+		spin_lock(&sec->lock);
+		if ((mask & (MAY_WRITE|MAY_APPEND))
+		    || (sec->sfsmask & SFS_CS_CACHEOK) == 0) {
+			sec->sfsmask &= ~SFS_CS_UPTODATE;
+		}
+		spin_unlock(&sec->lock);
+	}
+	return 0;
+}
+
+static struct sfs_open_message * sfs_open_fill(struct path * f_path, int mask,
+    int * lenp)
+{
+	struct sfs_open_message * msg;
+	char * path = NULL;
+	char * buf = NULL;
+	struct sfs_inode_sec * sec = NULL;
+	int pathlen, alloclen;
+	struct dentry * dentry = f_path->dentry;
+	struct inode * inode = dentry->d_inode;
+
+	buf = (char *)__get_free_page(GFP_KERNEL);
+	if (buf == NULL)
+		return NULL;
+	path = global_dpath(f_path, buf, PAGE_SIZE);
+	if (path && !IS_ERR(path)) {
+		pathlen = PAGE_SIZE - (path-buf);
+	} else {
+		path = NULL;
+		pathlen = 1;
+	}
+	alloclen = sizeof(struct sfs_open_message) - 1 + pathlen;
+	msg = kmalloc(alloclen, GFP_KERNEL);
+	msg->flags = 0;
+	if (mask & (MAY_READ|MAY_EXEC))
+		msg->flags |= ANOUBIS_OPEN_FLAG_READ;
+	if (mask & MAY_EXEC)
+		msg->flags |= ANOUBIS_OPEN_FLAG_EXEC;
+	if (mask & MAY_WRITE)
+		msg->flags |= ANOUBIS_OPEN_FLAG_WRITE;
+	if (path) {
+		memcpy(msg->pathhint, path, pathlen);
+		msg->flags |= ANOUBIS_OPEN_FLAG_PATHHINT;
+	} else {
+		msg->pathhint[0] = 0;
+	}
+	if (buf)
+		free_page((unsigned long)buf);
+	msg->ino = 0;
+	msg->dev = 0;
+	if (dentry && inode) {
+		msg->ino = inode->i_ino;
+		msg->dev = inode->i_sb->s_dev;
+		msg->flags |= ANOUBIS_OPEN_FLAG_STATDATA;
+	}
+	if (inode)
+		sec = ISEC(inode);
+	if (sec) {
+		spin_lock(&sec->lock);
+		if (sec->sfsmask & SFS_CS_UPTODATE) {
+			memcpy(msg->csum, sec->hash, ANOUBIS_SFS_CS_LEN);
+			msg->flags |= ANOUBIS_OPEN_FLAG_CSUM;
+		}
+		spin_unlock(&sec->lock);
+	}
+	(*lenp) = alloclen;
+	return msg;
+}
+
+static int sfs_open_checks(struct file * file, int mask, int *flags)
+{
+	int ret;
+	struct sfs_open_message * msg;
+	int err, len = 0;
+
+	err = sfs_check_syssig(file, mask);
+	if (err < 0)
+		return err;
+	msg = sfs_open_fill(&file->f_path, mask, &len);
+	if (!msg)
+		return -ENOMEM;
+	sfs_stat_ev++;
+	if (sfs_is_allow_path(msg->pathhint)) {
+		kfree(msg);
+		return 0;
+	}
+	ret = anoubis_raise_flags(msg, len, ANOUBIS_SOURCE_SFS, flags);
+	if (ret == -EPIPE /* &&  operation_mode != strict XXX */)
+		return 0;
+	if (ret)
+		sfs_stat_ev_deny++;
+	return ret;
+}
+
+static int sfs_dentry_open(struct file * file, const struct cred * cred)
+{
+	struct sfs_inode_sec * sec;
+	struct dentry * dentry = file->f_path.dentry;
+	struct inode * inode;
+	int mask, ret, flags;
+
+	if (!dentry)
+		return 0;
+	inode = dentry->d_inode;
+	if (!inode)
+		return 0;
+	sec = sfs_late_inode_alloc_security(inode);
+	if (!sec)
+		return -ENOMEM;
+	/*
+	 * Do no perform any open checks on file systems that do not
+	 * support checksum calculation.
+	 */
+	spin_lock(&sec->lock);
+	ret = ((sec->sfsmask & SFS_CS_OK) == 0);
+	spin_unlock(&sec->lock);
+	if (ret)
+		return 0;
+	mask = 0;
+	if (file->f_mode & FMODE_READ)
+		mask |= MAY_READ;
+	if (file->f_mode & FMODE_WRITE)
+		mask |= MAY_WRITE;
+	if (mask & MAY_WRITE) {
+		spin_lock(&sec->lock);
+		sec->sfsmask &= ~SFS_CS_UPTODATE;
+		spin_unlock(&sec->lock);
+	} else {
+		if (!skipsum_ok(inode, dentry))
+			sfs_csum(file, inode);
+	}
+
+	ret = sfs_open_checks(file, mask, &flags);
+
+	if (flags & ANOUBIS_RET_OPEN_LOCKWATCH) {
+		spin_lock(&sec->lock);
+		sec->sfsmask |= SFS_LOCKWATCH;
+		spin_unlock(&sec->lock);
+	}
+
+	return ret;
+}
+
+static int sfs_inode_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+	struct path p;
+	struct sfs_inode_sec * sec;
+	struct hash_desc cdesc;
+	struct page * page;
+	u_int8_t csum[ANOUBIS_SFS_CS_LEN];
+	struct scatterlist sg[1];
+	int err, count, alloclen;
+	struct inode * inode;
+	const char * path;
+	struct sfs_open_message * msg;
+	mm_segment_t oldfs;
+
+	if (!dentry || !dentry->d_inode || !nd)
+		return -ENOENT;
+	inode = dentry->d_inode;
+	if (!inode->i_op || !inode->i_op->readlink)
+		return -EINVAL;
+	sec = sfs_late_inode_alloc_security(inode);
+	if (sec) {
+		int ret;
+		spin_lock(&sec->lock);
+		ret = sec->sfsmask & SFS_ALWAYSFOLLOW;
+		spin_unlock(&sec->lock);
+		if (ret)
+			return 0;
+	}
+	page = alloc_page(GFP_KERNEL);
+	oldfs = get_fs();
+	set_fs(get_ds());
+	err = inode->i_op->readlink(dentry, page_address(page), PAGE_SIZE);
+	set_fs(oldfs);
+	if (err < 0)
+		goto out;
+	count = err;
+	cdesc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+	cdesc.tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(cdesc.tfm)) {
+		err = PTR_ERR(cdesc.tfm);
+		goto out;
+	}
+	err = crypto_hash_init(&cdesc);
+	if (err) {
+		crypto_free_hash(cdesc.tfm);
+		goto out;
+	}
+	sg_set_page(sg, page, count, 0);
+	err = crypto_hash_update(&cdesc, sg, count);
+	if (err) {
+		err = EIO;
+		crypto_free_hash(cdesc.tfm);
+		goto out;
+	}
+	err = crypto_hash_final(&cdesc, csum);
+	crypto_free_hash(cdesc.tfm);
+	if (err)
+		goto out;
+	p.mnt = nd->path.mnt;
+	p.dentry = dentry;
+	path = global_dpath(&p, page_address(page), PAGE_SIZE);
+	if (path && !IS_ERR(path)) {
+		/* page_address returns void *, hence the need for the cast */
+		count = PAGE_SIZE - (path - (char *)page_address(page));
+	} else {
+		path = NULL;
+		count = 1;
+	}
+	alloclen = sizeof(struct sfs_open_message) - 1 + count;
+	msg = kmalloc(alloclen, GFP_KERNEL);
+	msg->flags = ANOUBIS_OPEN_FLAG_FOLLOW | ANOUBIS_OPEN_FLAG_CSUM;
+	if (path) {
+		memcpy(msg->pathhint, path, count);
+		msg->flags |= ANOUBIS_OPEN_FLAG_PATHHINT;
+	} else {
+		msg->pathhint[0] = 0;
+	}
+	__free_page(page);
+	msg->ino = 0;
+	msg->dev = 0;
+	memcpy(msg->csum, csum, ANOUBIS_SFS_CS_LEN);
+	if (sfs_is_allow_path(msg->pathhint)) {
+		kfree(msg);
+		return 0;
+	}
+	err = anoubis_raise(msg, alloclen, ANOUBIS_SOURCE_SFS);
+	if (err == -EPIPE /* XXX and mode != strict */)
+		err = 0;
+	return err;
+out:
+	__free_page(page);
+	return err;
+}
+
+/*
+ * LSM hooks that have VFS information (available in 2.6.29+)
+ * used for path-based permission checks
+ */
+static int sfs_path_write(struct path *path)
+{
+	struct sfs_open_message * msg;
+	int len, ret;
+
+	/*
+	 * If the target file exists make sure it does not have a system
+	 * signature.
+	 */
+	if (path->dentry && path->dentry->d_inode &&
+	    checksum_ok(path->dentry->d_inode)) {
+		ret = sfs_read_syssig(path->dentry);
+		if (ret < 0)
+			return ret;
+		if (ret > 0)
+			return -EACCES;
+	}
+	msg = sfs_open_fill(path, MAY_WRITE, &len);
+	if (sfs_is_allow_path(msg->pathhint)) {
+		kfree(msg);
+		return 0;
+	}
+	ret = anoubis_raise(msg, len, ANOUBIS_SOURCE_SFS);
+	if (ret == -EPIPE /* &&  operation_mode != strict XXX */)
+		ret = 0;
+	return ret;
+}
+
+
+/*
+ * Populate a sfs_path_message with an operation and one or two paths
+ */
+static struct sfs_path_message * sfs_path_fill(unsigned int op,
+	struct path *new_dir, struct dentry *new_dentry,
+	struct dentry *old_dentry, int * lenp)
+{
+	struct sfs_path_message * msg = NULL;
+	unsigned int pathlen[2] = { 0, 0 };
+	unsigned int pathcnt, i;
+	char * pathstr[2];
+	char * bufs[2] = { NULL, NULL };
+	int alloclen;
+
+	struct path paths[] = {
+		{ new_dir->mnt, new_dentry },
+		{ new_dir->mnt, old_dentry }
+	};
+
+	if ((new_dir == NULL) || (new_dentry == NULL))
+		return NULL;
+	else if (old_dentry == NULL)
+		pathcnt = 1;
+	else
+		pathcnt = 2;
+
+	for (i=0; i<pathcnt; i++) {
+		bufs[i] = (char *)__get_free_page(GFP_KERNEL);
+		if (bufs[i] == NULL)
+			goto nomem;
+		pathstr[i] = global_dpath(&paths[i], bufs[i], PAGE_SIZE);
+		if (pathstr[i] == NULL || IS_ERR(pathstr[i]))
+			goto nomem;
+		pathlen[i] = PAGE_SIZE - (pathstr[i]-bufs[i]);
+	}
+
+	alloclen = sizeof(struct sfs_path_message) + pathlen[0] + pathlen[1];
+
+	msg = kmalloc(alloclen, GFP_KERNEL);
+	if (msg == NULL)
+		goto nomem;
+	msg->op = op;
+
+	msg->pathlen[0] =  pathlen[0];
+	msg->pathlen[1] =  pathlen[1];
+
+	memcpy(msg->paths, pathstr[0], pathlen[0]);
+	free_page((unsigned long)bufs[0]);
+
+	if (pathlen[1]) {
+		memcpy(msg->paths + pathlen[0], pathstr[1], pathlen[1]);
+		free_page((unsigned long)bufs[1]);
+	}
+
+	(*lenp) = alloclen;
+	return msg;
+nomem:
+	if (bufs[0])
+		free_page((unsigned long)bufs[0]);
+	if (bufs[1])
+		free_page((unsigned long)bufs[1]);
+	if (msg)
+		kfree(msg);
+	return NULL;
+}
+
+static int sfs_path_checks(struct sfs_path_message * msg, int len)
+{
+	int ret;
+
+	sfs_stat_path++;
+
+	if (msg->pathlen[0] && sfs_is_allow_path(msg->paths)) {
+		kfree(msg);
+		return 0;
+	}
+	if (msg->pathlen[1] && sfs_is_allow_path(msg->paths +
+							msg->pathlen[0])) {
+		kfree(msg);
+		return 0;
+	}
+	ret = anoubis_raise(msg, len, ANOUBIS_SOURCE_SFSPATH);
+
+	if (ret == -EPIPE /* &&  operation_mode != strict XXX */)
+		return 0;
+	if (ret)
+		sfs_stat_path_deny++;
+
+	return ret;
+}
+
+#ifdef CONFIG_SECURITY_PATH
+static int sfs_path_link(struct dentry *old_dentry, struct path *parent_dir,
+    struct dentry *new_dentry)
+{
+	struct path link;
+	unsigned int op = ANOUBIS_PATH_OP_LINK;
+	struct sfs_path_message * msg;
+	int ret, len;
+
+	link.mnt = parent_dir->mnt;
+	link.dentry = new_dentry;
+	if ((ret = sfs_path_write(&link)) != 0)
+		return ret;
+
+	msg = sfs_path_fill(op, parent_dir, new_dentry, old_dentry, &len);
+	if (!msg)
+		return -ENOMEM;
+	return sfs_path_checks(msg, len);
+}
+
+static int sfs_path_rename(struct path *old_dir, struct dentry *old_dentry,
+    struct path *new_dir, struct dentry *new_dentry)
+{
+	unsigned int op = ANOUBIS_PATH_OP_RENAME;
+	struct sfs_path_message * msg;
+	struct path file;
+	int len, ret;
+
+	file.mnt = old_dir->mnt;
+	file.dentry = old_dentry;
+	if ((ret = sfs_path_write(&file)) != 0)
+		return ret;
+	file.mnt = new_dir->mnt;
+	file.dentry = new_dentry;
+	if ((ret = sfs_path_write(&file)) != 0)
+		return ret;
+
+	msg = sfs_path_fill(op, new_dir, new_dentry, old_dentry, &len);
+	if (!msg)
+		return -ENOMEM;
+
+	if ((ret = sfs_path_checks(msg, len)) != 0)
+		return ret;
+
+	return ret;
+}
+
+/*
+ * XXX: SSP these aren't real opens but we'll treat
+ * them like that in the daemon for now
+ */
+static int sfs_path_unlink(struct path *dir, struct dentry *dentry)
+{
+	struct path file = { dir->mnt, dentry };
+
+	if (!dentry || !dentry->d_inode)
+		return 0;
+	return sfs_path_write(&file);
+}
+
+static int sfs_path_rmdir(struct path *dir, struct dentry *dentry)
+{
+	struct path file = { dir->mnt, dentry };
+
+	if (!dentry || !dentry->d_inode)
+		return 0;
+	return sfs_path_write(&file);
+}
+
+static int sfs_path_symlink(struct path *dir, struct dentry *dentry,
+    const char *old_name)
+{
+	struct path symlink = { dir->mnt, dentry };
+	return sfs_path_write(&symlink);
+}
+
+static int sfs_path_truncate(struct path *path, loff_t length,
+    unsigned int time_attrs)
+{
+	return sfs_path_write(path);
+}
+
+static int sfs_path_mknod(struct path *dir, struct dentry *dentry,
+    int mode, unsigned int dev)
+{
+	struct path file = { dir->mnt, dentry };
+
+	if (!dentry)
+		return 0;
+
+	return sfs_path_write(&file);
+}
+
+static int sfs_path_mkdir(struct path *dir, struct dentry *dentry, int mode)
+{
+	struct path file = { dir->mnt, dentry };
+
+	if (!dentry)
+		return 0;
+
+	return sfs_path_write(&file);
+}
+
+#endif
+
+/*
+ * send (un)lock messages if the file was marked via LOCKWATCH
+ */
+static int sfs_file_lock(struct file * file, unsigned int cmd) {
+	struct dentry * dentry = file->f_path.dentry;
+	struct inode * inode;
+	struct sfs_path_message * msg;
+	unsigned int op;
+	int len, ret;
+	struct sfs_inode_sec * sec;
+
+	if (!dentry)
+		return 0;
+	inode = dentry->d_inode;
+	if (!inode)
+		return 0;
+	sec = sfs_late_inode_alloc_security(inode);
+	if (!sec)
+		return -ENOMEM;
+
+	spin_lock(&sec->lock);
+	ret = sec->sfsmask;
+	spin_unlock(&sec->lock);
+
+	if (!(ret & SFS_LOCKWATCH))
+		return 0;
+
+	if (cmd == F_UNLCK)
+		op = ANOUBIS_PATH_OP_UNLOCK;
+	else
+		op = ANOUBIS_PATH_OP_LOCK;
+
+	msg = sfs_path_fill(op, &file->f_path, dentry, NULL, &len);
+	if (!msg)
+		return -ENOMEM;
+
+	return sfs_path_checks(msg, len);
+}
+
+/*
+ * Part of the external interface:
+ * Calculate the checksum of the file and return the result in @csum.
+ * The return value is zero upon success. In case of an error @csum
+ * is not touched.
+ */
+int anoubis_sfs_get_csum(struct file * file, u8 * csum)
+{
+	struct dentry * dentry = file->f_path.dentry;
+	struct inode * inode = dentry->d_inode;
+	struct sfs_inode_sec * sec;
+	int err;
+
+	sec = sfs_late_inode_alloc_security(inode);
+	if (!sec)
+		return -ENOMEM;
+	if (!checksum_ok(inode) || skipsum_ok(inode, dentry))
+		return -EINVAL;
+	err = sfs_do_csum(file, inode, sec);
+	if (err < 0) {
+		sfs_stat_csum_recalc_fail++;
+		return err;
+	}
+	err = -EBUSY;
+	spin_lock(&sec->lock);
+	if (sec->sfsmask & SFS_CS_UPTODATE) {
+		err = 0;
+		memcpy(csum, sec->hash, ANOUBIS_SFS_CS_LEN);
+	}
+	spin_unlock(&sec->lock);
+	return err;
+}
+
+static int sfs_getcsum(struct file * file, u8 * csum)
+{
+	return anoubis_sfs_get_csum(file, csum);
+}
+
+static int sfs_cred_prepare(struct cred * cred, const struct cred *ocred,
+				gfp_t gfp)
+{
+	struct sfs_bprm_sec * sec, * old;
+
+	sec = kmalloc(sizeof(struct sfs_bprm_sec), gfp);
+	if (!sec)
+		return -ENOMEM;
+	sec->msg = NULL;
+	sec->need_secureexec = 0;
+	old = SETCSEC(cred, sec);
+	BUG_ON(old);
+	return 0;
+}
+
+static void sfs_cred_free(struct cred * cred)
+{
+	struct sfs_bprm_sec * sec = SETCSEC(cred, NULL);
+
+	if (!sec)
+		return;
+	if (sec->msg != NULL)
+		kfree(sec->msg);
+	kfree(sec);
+}
+
+/*
+ * Inform anoubisd about exec calls using an open-request
+ */
+static int sfs_bprm_set_creds(struct linux_binprm * bprm)
+{
+	struct sfs_bprm_sec * sec = CSEC(bprm->cred);
+	struct file * file = bprm->file;
+	struct dentry * dentry;
+	struct inode * inode;
+	struct sfs_open_message * msg;
+	int len, flags = 0, ret;
+
+	BUG_ON(!file);
+	BUG_ON(file->f_mode & FMODE_WRITE);
+	dentry = file->f_path.dentry;
+	if (!dentry)
+		return 0;
+	inode = dentry->d_inode;
+	if (!inode)
+		return 0;
+	if (!sec)
+		return -ENOMEM;
+	if (checksum_ok(inode) && !skipsum_ok(inode, dentry))
+		sfs_csum(file, inode);
+	if (sec->msg == NULL) {
+		msg = sfs_open_fill(&file->f_path, MAY_READ|MAY_EXEC, &len);
+		if (!msg)
+			return -ENOMEM;
+		sec->msg = msg;
+		sec->len = len;
+	}
+	ret = sfs_open_checks(file, MAY_READ|MAY_EXEC, &flags);
+	if (flags & ANOUBIS_RET_NEED_SECUREEXEC)
+		sec->need_secureexec = 1;
+	if (ret == 0 && (flags & ANOUBIS_RET_NEED_PLAYGROUND)) {
+		ret = anoubis_playground_create(0);
+		/* Process is already in a playground. This is ok. */
+		if (ret == -EBUSY)
+			ret = 0;
+	}
+
+	return ret;
+}
+
+/*
+ * Inform anoubisd about exec system calls. Note that bprm->cred is already
+ * committed to current_cred() and brpm->cred is NULL.
+ */
+static void sfs_bprm_committed_creds(struct linux_binprm * bprm)
+{
+	struct sfs_bprm_sec * sec = CSEC(current_cred());
+	struct file * file = bprm->file;
+	struct sfs_open_message * msg;
+	int len;
+
+	if (sec && sec->msg) {
+		msg = sec->msg;
+		len = sec->len;
+		sec->msg = NULL;
+	} else {
+		msg = sfs_open_fill(&file->f_path, MAY_READ|MAY_EXEC, &len);
+	}
+	BUG_ON(msg == NULL);
+	if (anoubis_need_secureexec(bprm))
+		msg->flags |= ANOUBIS_OPEN_FLAG_SECUREEXEC;
+	anoubis_notify(msg, len, ANOUBIS_SOURCE_SFSEXEC);
+}
+
+
+/* Propagate local unix socket to Sandbox/SFS */
+static int sfs_socket_connect(struct socket * sock, struct sockaddr * address,
+    int addrlen)
+{
+	struct sockaddr_un *sunname = (struct sockaddr_un *)address;
+	struct path path;
+	int err = 0;
+
+	if (!sock || !sock->sk)
+		return -EBADF;
+	if (sock->sk->sk_family != AF_UNIX)
+		return 0;
+	if (sunname->sun_path[0] == 0)
+		return 0;
+
+	err = kern_path(sunname->sun_path, LOOKUP_FOLLOW, &path);
+	if (err)
+		return 0;
+	err = sfs_path_write(&path);
+	path_put(&path);
+	return err;
+}
+
+
+/*
+ * Deny access to the syssig security attribute while the SFS module
+ * is loaded.
+ */
+static int sfs_inode_setxattr(struct dentry * dentry, const char * name,
+    const void * value, size_t size, int flags)
+{
+	if (strcmp(name, XATTR_ANOUBIS_SYSSIG) == 0)
+		return -EPERM;
+	return 0;
+}
+
+static int sfs_inode_removexattr(struct dentry *dentry, const char *name)
+{
+	if (strcmp(name, XATTR_ANOUBIS_SYSSIG) == 0)
+		return -EPERM;
+	return 0;
+}
+
+/*
+ * Return true if the anoubis-SFS module requires a secure exec. The
+ * sec pointer might be NULL if the sfs module was loaded in the middle
+ * of an exec.
+ * NOTE: brpm->cred might be NULL at this point. Use current_cred() instead.
+ */
+static int sfs_bprm_secureexec(struct linux_binprm *bprm)
+{
+	struct sfs_bprm_sec * sec = CSEC(current_cred());
+
+	return sec && sec->need_secureexec;
+}
+
+/* Security operations. */
+static struct anoubis_hooks sfs_ops = {
+	.version = ANOUBISCORE_VERSION,
+	.inode_alloc_security = sfs_inode_alloc_security,
+	.inode_free_security = sfs_inode_free_security,
+	.cred_prepare = sfs_cred_prepare,
+	.cred_free = sfs_cred_free,
+	.bprm_set_creds = sfs_bprm_set_creds,
+	.bprm_committed_creds = sfs_bprm_committed_creds,
+	.bprm_secureexec = sfs_bprm_secureexec,
+	.inode_permission = sfs_inode_permission,
+	.inode_follow_link = sfs_inode_follow_link,
+	.dentry_open = sfs_dentry_open,
+	.inode_setxattr = sfs_inode_setxattr,
+	.inode_removexattr = sfs_inode_removexattr,
+	.file_lock = sfs_file_lock,
+#ifdef CONFIG_SECURITY_PATH
+	.path_link = sfs_path_link,
+	.path_unlink = sfs_path_unlink,
+	.path_rmdir = sfs_path_rmdir,
+	.path_rename = sfs_path_rename,
+	.path_symlink = sfs_path_symlink,
+	.path_truncate = sfs_path_truncate,
+	.path_mknod = sfs_path_mknod,
+	.path_mkdir = sfs_path_mkdir,
+#endif
+	.socket_connect = sfs_socket_connect,
+	.anoubis_stats = sfs_getstats,
+	.anoubis_getcsum = sfs_getcsum,
+};
+
+#ifdef MODULE
+/*
+ * Dummy hash to make sure that the checksum crypto module is loaded
+ * while our security modules runs.
+ */
+static struct crypto_hash * dummy_tfm;
+#endif
+
+/*
+ * Remove the sfs module.
+ */
+
+static void __exit sfs_exit(void)
+{
+	struct allow_path_entry *tmp;
+
+	if (ac_index >= 0)
+		anoubis_unregister(ac_index);
+#ifdef MODULE
+	if (dummy_tfm && !IS_ERR(dummy_tfm))
+		crypto_free_hash(dummy_tfm);
+#endif
+	while(allow_path_entries) {
+		tmp = allow_path_entries;
+		allow_path_entries = tmp->next;
+		kfree(tmp);
+	}
+}
+
+static void
+sfs_add_allow_path(const char *ptr, int len)
+{
+	struct allow_path_entry *allow;
+
+	if (*ptr != '/') {
+		printk(KERN_ERR "sfs.allow_path: Paths must be absolute\n");
+		return;
+	}
+	allow = kmalloc(sizeof(*allow) + len + 1, GFP_KERNEL);
+	if (!allow) {
+		printk(KERN_CRIT "sfs: Out of memory while parsing "
+					"module command line\n");
+		return;
+	}
+	allow->next = allow_path_entries;
+	allow->prefixlen = len;
+	memcpy(allow->prefix, ptr, len);
+	allow->prefix[len] = 0;
+	allow_path_entries = allow;
+}
+
+
+/*
+ * Initialize the anoubis module.
+ */
+static int __init sfs_init(void)
+{
+	int rc = 0;
+	struct timeval tv;
+	char *p, *last;
+
+	/* register ourselves with the security framework */
+	do_gettimeofday(&tv);
+	sfs_stat_loadtime = tv.tv_sec;
+#ifdef MODULE
+	dummy_tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
+#endif
+	last = allow_path_buf;
+	for (p=allow_path_buf; *p; p++) {
+		if (*p == ',' && p - last > 0) {
+			sfs_add_allow_path(last, p-last);
+			last = p+1;
+		}
+	}
+	if (p - last > 0)
+		sfs_add_allow_path(last, p-last);
+#ifdef MODULE
+	if (IS_ERR(dummy_tfm)) {
+		printk(KERN_ERR "Cannot allocate sha256 hash "
+		    "(try modprobe sha256)\n");
+		return PTR_ERR(dummy_tfm);
+	}
+#endif
+	if ((rc = anoubis_register(&sfs_ops, &ac_index)) < 0) {
+		ac_index = -1;
+		printk(KERN_ERR "anoubis_sfs: Failure registering\n");
+#ifdef MODULE
+		crypto_free_hash(dummy_tfm);
+#endif
+		return rc;
+	}
+	printk(KERN_INFO "anoubis_sfs: Successfully initialized.\n");
+	return 0;
+}
+
+module_init(sfs_init);
+module_param(checksum_max_size, int, 0644);
+MODULE_PARM_DESC(checksum_max_size,
+    "Maximum filesize for SFS checksum calculations");
+
+/* allow_path_buf is marked as __initdata, thus we disallow read. */
+module_param_string(allow_path, allow_path_buf, sizeof(allow_path_buf), 0);
+MODULE_PARM_DESC(allow_path,
+    "Do not perform file system access checks for these path prefixes");
+
+module_exit(sfs_exit);
+
+MODULE_AUTHOR("Christian Ehrhardt <ehrhardt@genua.de>");
+MODULE_DESCRIPTION("Anoubis SFS module");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/security/security.c b/security/security.c
index c4c6732..ace035d 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1039,6 +1039,11 @@ int security_socket_accept(struct socket *sock, struct socket *newsock)
 	return security_ops->socket_accept(sock, newsock);
 }
 
+int security_socket_accepted(struct socket *sock, struct socket *newsock)
+{
+	return security_ops->socket_accepted(sock, newsock);
+}
+
 int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size)
 {
 	return security_ops->socket_sendmsg(sock, msg, size);
@@ -1081,6 +1086,12 @@ int security_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
 }
 EXPORT_SYMBOL(security_sock_rcv_skb);
 
+int security_socket_skb_recv_datagram(struct sock * sk, struct sk_buff * skb)
+{
+	return security_ops->socket_skb_recv_datagram (sk, skb);
+}
+EXPORT_SYMBOL(security_socket_skb_recv_datagram);
+
 int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
 				      int __user *optlen, unsigned len)
 {

