[RFC][PATCH 2/3] SLIM

From: David Safford (safford@private)
Date: Tue Nov 15 2005 - 06:08:59 PST


Patch 2/3 - SLIM (Simple Linux Integrity Model)

SLIM is an LSM kernel module which performs a simple low water-mark
form of integrity mandatory access control. In this  model, files are
labeled with  the security.slim.level extended attribute, which, along
with the hash of the file’s data, is authenticated by EVM. Values for
the integrity level are SYSTEM, USER, and UNTRUSTED.

In the low water-mark model, processes inherit their level from their
parent.  A process may read and execute files of equal or higher level. A
process may read and execute files of a lower integrity level, but it
is demoted to the lower level as a result. A process may write to equal
or lower integrity levels, but it will be blocked if it tries to write
to a higher level file. Network sockets are by definition UNTRUSTED.

SLIM also performs a corresponding high water-mark privacy model, with
levels PUBLIC, USER, USER-SENSITIVE and SYSTEM-SENSITIVE, although these
labels are not yet well tested. In the high water-mark privacy model,
a process may read files of equal or lesser sensitivity. It is also
allowed to read a file of higher sensitivity, but is promoted to that
level of sensitivity. A process may not write to less sensitive files.

Executable files can be designated as integrity guard programs with
additional labels for the lower and upper watermarks allowed.
The value of a security.slim.level attribute is ascii, in the form:

  Integrity_Level Privacy_Level [Guard_Low_level Guard_High_Level][UNLIMITED]

A typical system executable will be labeled with "SYSTEM PUBLIC".
A "limited" integrity guard process is allowed to remain at its
current level, up to Guard_High_Level, even while reading data
labeled as low as Guard_Low_Level. An "unlimited" guard program
will be invoked at Guard_High_Level, even if this is higher than
the level of the invoking process. Due to the inherent race condition,
interpreted languages/scripts are not allowed to have unlimited
guard privileges, as this would provide a simple privilege escalation
attack.

Files are initially labeled during installation/update with a modified
version of rpm, which uses the /etc/slim.conf configuration file to
determine the appropriate level for a file. For labeling an existing
filesystem, the tpm-3.0.3 package includes tc_label, a labeling
application, which can clear, initialize from the rpm database,
initialize from /etc/slim.conf, and manually set individual files,
files in one or more rpm packages, or directories recursively.


diff -rupN linux-2.6.14.2.orig/security/evm/slim/Makefile linux-2.6.14.2.tc/security/evm/slim/Makefile
--- linux-2.6.14.2.orig/security/evm/slim/Makefile	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.14.2.tc/security/evm/slim/Makefile	2005-11-11 14:00:44.000000000 -0500
@@ -0,0 +1,5 @@
+
+obj-$(CONFIG_SECURITY_SLIM) += slim.o
+slim-y 	:= slm_main.o slm_secfs.o slm_ima.o \
+	ima/ima_fs.o ima/ima_queue.o ima/ima_init.o ima/ima_main.o \
+	ima/ima_biosmeasurements.o
diff -rupN linux-2.6.14.2.orig/security/evm/slim/slim.h linux-2.6.14.2.tc/security/evm/slim/slim.h
--- linux-2.6.14.2.orig/security/evm/slim/slim.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.14.2.tc/security/evm/slim/slim.h	2005-11-11 14:10:11.000000000 -0500
@@ -0,0 +1,102 @@
+/*
+ * slim.h - simple linux integrity module
+ *
+ * SLIM's specific model is:
+ *
+ *  All objects are labeled with exteded attributes to indicate:
+ *      Integrity Access Class (IAC)
+ *      Secrecy Access Class (SAC)
+ *
+ *  All processes inherit from their parents:
+ *      Integrity Read Access Class (IRAC)
+ *      Integrity Write/Execute Access Class (IWXAC)
+ *      Secrecy Write Access Class (SWAC)
+ *      Secrecy Read/Execute Access Class (SRXAC)
+ *
+ *  SLIM enforces the following Mandatory Access Control Rules:
+ *      Read:
+ *          IRAC(process) <= IAC(object)
+ *          SRXAC(process) >= SAC(object)
+ *      Write:
+ *          IWXAC(process) >= IAC(object)
+ *          SWAC(process) <= SAC(process)
+ *      Execute:
+ *          IWXAC(process) <= IAC(object)
+ *          SRXAC(process) >= SAC(object)
+*/
+
+#include <linux/security.h>
+#include <linux/version.h>
+#include <linux/security-stack.h>
+
+enum slm_iac_level { /* integrity access class */
+	SLM_IAC_EXEMPT= -1, SLM_IAC_NOTDEFINED= 0, SLM_IAC_UNTRUSTED,
+	SLM_IAC_USER, SLM_IAC_SYSTEM, SLM_IAC_HIGHEST
+};
+extern char *slm_iac_str[];
+
+enum slm_sac_level {  /* secrecy access class */
+	SLM_SAC_EXEMPT=-1, SLM_SAC_NOTDEFINED= 0, SLM_SAC_PUBLIC, SLM_SAC_USER,
+	SLM_SAC_USER_SENSITIVE, SLM_SAC_SYSTEM_SENSITIVE, SLM_SAC_HIGHEST
+};
+
+extern char *slm_sac_str[];
+
+struct slm_tsec_data { 	/* task security data (process info) */
+	struct security_list lsm_list;
+	enum slm_iac_level iac_r; //ability to read low integrity files
+	enum slm_iac_level iac_wx;//retain ability to write/execute higher
+	enum slm_sac_level sac_w; //ability to write low secrecy files
+	enum slm_sac_level sac_rx;//after having read/executed higher
+	int unlimited;	// guard process not bounded to current process limit
+	struct dentry *filename_dentry; // used when filename != interp
+};
+
+struct slm_file_xattr { 		// file extended attributes
+	enum slm_iac_level iacLevel; 	// for integrity
+	enum slm_sac_level sacLevel; 	// for secrecy
+	struct slm_tsec_data guard; 	// guard process information
+};
+
+extern struct slm_xattr_config *slm_parse_config(char *data,
+			unsigned long datalen, int *datasize);
+
+extern int slm_init_config(void);
+
+extern void slm_init_secfs(void);
+void slm_cleanup_secfs(void);
+
+extern unsigned int slm_debug;
+enum slm_debug_level {
+		SLM_BASE = 1, SLM_INTEGRITY = 2, SLM_SECRECY = 4,
+		SLM_VERBOSE = 8,
+};
+
+extern unsigned int slm_ima;
+#undef dprintk
+#define dprintk(level, format, a...) \
+	if (slm_debug & level) \
+		printk(KERN_INFO format, ##a)
+
+extern int slm_idx;
+#define SLM_LSM_ID 0x99999999
+#define slm_get_task(head) \
+	security_get_value_type(head, SLM_LSM_ID, struct slm_tsec_data,slm_idx);
+#define slm_set_task(head, task) \
+	security_set_value_type(head, SLM_LSM_ID, task, slm_idx);
+#define slm_del_task(head) \
+	security_del_value_type(head, SLM_LSM_ID, struct slm_tsec_data,slm_idx);
+
+struct slm_isec_data { /* task security data (process info) */
+	struct security_list lsm_list;
+	int measured;
+	struct slm_file_xattr level;
+};
+#define slm_get_isec(head) \
+	security_get_value_type(head, SLM_LSM_ID, struct slm_isec_data,slm_idx);
+#define slm_set_isec(head, isec) \
+	security_set_value_type(head, SLM_LSM_ID, isec, slm_idx);
+#define slm_add_isec(head, isec) \
+	security_add_value_type(head, SLM_LSM_ID, isec, slm_idx);
+#define slm_del_isec(head) \
+	security_del_value_type(head, SLM_LSM_ID, struct slm_isec_data,slm_idx);
diff -rupN linux-2.6.14.2.orig/security/evm/slim/slm_ima.c linux-2.6.14.2.tc/security/evm/slim/slm_ima.c
--- linux-2.6.14.2.orig/security/evm/slim/slm_ima.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.14.2.tc/security/evm/slim/slm_ima.c	2005-11-11 14:10:40.000000000 -0500
@@ -0,0 +1,143 @@
+/*
+ * IMA Integrity Measurement/Attestation interface from SLIM
+ *
+ * Copyright (C) 2005 IBM Corporation
+ * Authors:
+ *	Reiner Sailer <sailer@private>
+ * 	Mimi Zohar <zohar@private>
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ */
+
+#include <asm-generic/errno-base.h>
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/namei.h>
+#include <linux/evm.h>
+#include "../evm.h"
+#include "slim.h"
+#include "ima.h"
+
+#define MD5_STR_SIZE 32 	/* String value  */
+#define MD5_DIGEST_SIZE 16 	/* MD5 is 128-bits */
+
+int _ima_measure(const unsigned char *func, const unsigned char *name,
+		  struct inode *inode, int mask, int hash_len, char *hash);
+
+void ima_measure(const unsigned char *func, const unsigned char *name,
+			struct inode *inode, int mask, char *hash)
+{
+	char hashStr[SHA1_STR_SIZE + 1];
+	int len, err;
+
+	if (!hash)
+		return;
+
+	memset(hashStr, 0, sizeof hashStr);
+	len = mem2hex(hash, hashStr, SHA1_DIGEST_SIZE);
+
+	if ((err = _ima_measure(func, name, inode, mask, SHA1_DIGEST_SIZE,hash)))
+		printk(KERN_INFO "%s: _ima_measure failed (%d).\n",
+				__func__, err);
+}
+
+/* what could we exclude
+ *   - non-executable/non-library files ?
+ *   - /proc /dev ?
+ */
+static int skip_measurement(struct inode *inode)
+{
+#define SYSFS_MAGIC 0x62656572
+
+	if ((inode->i_sb->s_magic == DEVFS_SUPER_MAGIC) ||
+	    (inode->i_sb->s_magic == PROC_SUPER_MAGIC) ||
+	    (inode->i_sb->s_magic == SYSFS_MAGIC)) {
+		return 1; 	/*can't measure */
+	}
+	if (S_ISLNK(inode->i_mode) ||
+	    S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
+	    S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode))
+		return 1;	/* don't measure */
+
+	return 0;	       	/* measure */
+}
+
+int slm_need_hash(struct evm_isec_cache *evm_isec)
+{
+	char hash[SHA1_DIGEST_SIZE +1];
+	int rc;
+
+	if (evm_isec) {
+		memset(hash, 0, SHA1_DIGEST_SIZE +1);
+		rc = memcmp(evm_isec->hash, hash, SHA1_DIGEST_SIZE);
+		return (rc == 0) ? 1 : 0;
+	}
+	return -1;
+}
+
+void slm_measure(const unsigned char *func, const unsigned char *name,
+		struct nameidata *nd, struct file *file,
+		struct inode *inode, int mask)
+{
+	struct slm_isec_data *slm_isec = NULL;
+	struct evm_isec_cache *evm_isec = NULL;
+
+	if (skip_measurement(inode))
+		return;
+
+	/* Only measure files opened for read-only or execute. */
+	if (S_ISREG(inode->i_mode)
+			&& ((mask == MAY_READ) || (mask == MAY_EXEC))
+			&& (mask != MAY_WRITE) && (mask != MAY_APPEND)) {
+		slm_isec = slm_get_isec(inode->i_security);
+		if (!slm_isec) {
+			slm_isec = kmalloc(sizeof (struct slm_isec_data),
+					GFP_KERNEL);
+                        if (!slm_isec)
+                                return;
+                        memset(slm_isec, 0, sizeof (struct slm_isec_data));
+		}
+		if (!slm_isec->measured) {
+			evm_isec = evm_get_isec(inode->i_security);
+			if (!evm_isec)
+				return;
+			if (slm_need_hash(evm_isec)) {
+				if (!file)
+					evm_calc_dhash(nd, evm_isec->hash,
+							EVM_TYPE_SHA1);
+				else
+					evm_calc_hash(file, evm_isec->hash,
+							EVM_TYPE_SHA1);
+			}
+			ima_measure(func, name, inode, mask, evm_isec->hash);
+			slm_isec->measured = 1;
+			slm_set_isec(inode->i_security, slm_isec);
+		}
+	}
+}
+
+void slm_reset_measure(struct inode *inode, const unsigned char *name)
+{
+	if (S_ISREG(inode->i_mode)) {
+		struct slm_isec_data *slm_isec;
+
+		slm_isec = slm_del_isec(inode->i_security);
+		if (slm_isec && slm_isec->measured) {
+			/* printk(KERN_INFO "%s: %s measure reset\n",
+				__FUNCTION__, name); */
+			slm_isec->measured = 0;
+		}
+	}
+}
+
+
+void ima_cleanup()
+{
+	slm_enable_ima = 0;
+}
diff -rupN linux-2.6.14.2.orig/security/evm/slim/slm_main.c linux-2.6.14.2.tc/security/evm/slim/slm_main.c
--- linux-2.6.14.2.orig/security/evm/slim/slm_main.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.14.2.tc/security/evm/slim/slm_main.c	2005-11-11 14:15:28.000000000 -0500
@@ -0,0 +1,1410 @@
+/*
+ * SLIM - Simple Linux Integrity Module
+ *
+ * Copyright (C) 2005 IBM Corporation
+ * Author: Mimi Zohar <zohar@private>
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ */
+
+#include <asm-generic/errno-base.h>
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/socket.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
+#include <linux/evm.h>
+#include "slim.h"
+
+int slm_idx;
+static int slm_inode_permission(struct inode *inode, int mask,
+				    struct nameidata *nd);
+static int slm_file_permission(struct file *file, int mask);
+static void slm_getr_xattr(struct dentry *, struct slm_file_xattr *,
+			const unsigned char *);
+static int slm_get_xattr(struct dentry *, struct slm_file_xattr *);
+static int slm_set_taskperm(int mask, struct slm_file_xattr *level,
+			const unsigned char *name, void *caller);
+static int slm_set_xattr(struct slm_file_xattr *level,
+		char **name, void **value, size_t *value_len);
+static int slm_socket_create (int family, int type, int protocol, int kern);
+
+static int slm_inode_unlink(struct inode *, struct dentry *);
+static void slm_inode_post_create (struct inode *, struct dentry *, int mask);
+static int slm_inode_setxattr (struct dentry *, char *name, void *value,
+			       size_t size, int flags);
+void slm_inode_free_security(struct inode *inode);
+
+static int slm_task_post_setuid (uid_t, uid_t, uid_t, int flags);
+static int slm_task_alloc_security(struct task_struct *);
+static int slm_alloc_security(struct task_struct *);
+extern void slm_measure(const unsigned char *func,
+			const unsigned char *debug_name,
+			struct nameidata *nd, struct file *file,
+			struct inode *inode, int mask);
+extern void slm_reset_measure(struct inode *inode, const unsigned char *name);
+extern void ima_init(void);
+extern void ima_cleanup(void);
+
+unsigned int slm_debug = 1;
+static char *slm_config = "/etc/slim.conf";
+static char *slm_xattrName = "security.slim.level";
+unsigned int slm_enable_ima = 1;
+static int secondary = 0;
+
+char *slm_iac_str[] = { "0", "UNTRUSTED", "USER", "SYSTEM" };
+char *slm_sac_str[] = {	 "0", "PUBLIC", "USER", "USER-SENSITIVE",
+				"SYSTEM-SENSITIVE"};
+
+static char *get_token(char *bufStart, char *bufEnd, char delimiter,
+		int *token_len)
+{
+	char *bufp = bufStart;
+	char *token = NULL;
+
+	while (!token && (bufp < bufEnd)) { /* Get start of token */
+			switch(*bufp) {
+		case ' ':
+		case '\n':
+		case '\t':
+			bufp++;
+			break;
+		case '#':
+			while ((*bufp != '\n') && (bufp++ < bufEnd));
+			bufp++;
+			break;
+		default:
+			token = bufp;
+			break;
+		}
+	}
+	if (!token)
+		return NULL;
+
+	*token_len = 0;
+	while ((*token_len == 0) && (bufp <= bufEnd)) {
+		if ((*bufp == delimiter) || (*bufp == '\n') )
+			*token_len = bufp - token;
+		if (bufp == bufEnd)
+			*token_len = bufp - token;
+		bufp++;
+	}
+	if (*token_len == 0)
+		token = NULL;
+	return token;
+}
+
+static int is_guardIntegrity(struct slm_file_xattr *level)
+{
+	int rc = 0;
+
+	if ((level->guard.iac_r != SLM_IAC_NOTDEFINED)
+			|| (level->guard.iac_wx != SLM_IAC_NOTDEFINED))
+		rc = 1;
+	return rc;
+}
+
+static int is_guardSecrecy(struct slm_file_xattr *level)
+{
+	int rc = 0;
+
+	if ((level->guard.sac_rx != SLM_SAC_NOTDEFINED)
+			|| (level->guard.sac_w != SLM_IAC_NOTDEFINED))
+		rc = 1;
+	return rc;
+}
+
+/*
+ * Enforce process integrity & secrecy levels.
+ * 	- update integrity process level of integrity guard program
+ * 	- update secrecy process level of secrecy guard program
+ */
+static int slm_bprm_check_security (struct linux_binprm *bprm)
+{
+	struct dentry *dentry;
+	int rc;
+	evm_status status;
+	struct inode *inode = NULL;
+
+	struct task_struct *cur_tsk = current, *parent_tsk;
+	struct slm_tsec_data *cur_tsec = NULL, *parent_tsec;
+	struct slm_file_xattr level;
+
+	cur_tsec = slm_get_task(cur_tsk->security);
+	if (!cur_tsec) {
+		if ((rc = slm_alloc_security(cur_tsk)) < 0)
+			return rc;
+		cur_tsec = slm_get_task(cur_tsk->security);
+		if (!cur_tsec) {
+			printk(KERN_INFO "bprm: NULL cur_tsec\n");
+			return 0;
+		}
+	}
+
+	/* Special case interpreters */
+	if (strcmp(bprm->filename, bprm->interp) != 0) {
+		dprintk(SLM_INTEGRITY, "%s: filename %s interp %s\n",
+				__FUNCTION__, bprm->filename, bprm->interp);
+		if (!cur_tsec->filename_dentry) {
+			dprintk(SLM_INTEGRITY, "%s: NULL filename_dentry %s\n",
+					__FUNCTION__, bprm->filename);
+			return 0;
+		} else
+			dentry = cur_tsec->filename_dentry;
+		inode = dentry->d_inode;
+	} else {
+		if (!bprm || !bprm->file || !bprm->file->f_dentry)
+			return 0;
+		else
+			dentry = bprm->file->f_dentry;
+
+		cur_tsec->filename_dentry = dentry; /* Saving incase script */
+		inode = dentry->d_inode;
+
+		/* slm_inode_permission measured all SYSTEM level
+		   integrity objects */
+		if ((level.iacLevel != SLM_IAC_SYSTEM) && slm_enable_ima)
+			slm_measure(__FUNCTION__, bprm->filename, NULL,
+					bprm->file, inode, MAY_EXEC);
+	}
+
+	/* Recursively traverse path (dentry->parent) until a level is found */
+	memset(&level, 0, sizeof(struct slm_file_xattr));
+	slm_getr_xattr(dentry, &level, bprm->filename);/* returns something */
+
+	/* Possible return codes:
+		EVM_PERMIT, EVM_DENY, EVM_SANDBOX, EVM_NOLABEL */
+	if ((status = evm_analyze_cacheinfo(dentry)) < 0) {
+		if (status == EVM_DENY) { /* Somethings very wrong */
+			dprintk(SLM_BASE, "%s: EVM_DENY requested for %s\n",
+					__FUNCTION__, bprm->filename);
+			return -EACCES;
+		} else if (status == EVM_NOLABEL) {
+			dprintk(SLM_BASE, "%s: EVM_NOLABEL for %s\n",
+					__FUNCTION__, bprm->filename);
+			level.iacLevel = SLM_IAC_UNTRUSTED;
+		} else {/* sandbox by making the iaclevel untrusted */
+			dprintk(SLM_BASE, "%s: EVM_SANDBOX requested for %s\n",
+					__FUNCTION__, bprm->filename);
+			level.iacLevel = SLM_IAC_UNTRUSTED;
+		}
+	}
+
+	/*
+	 * enforce: IWXAC(process) <= IAC(object)
+	 * Permit process to execute file of equal or greater integrity
+	 */
+	parent_tsk = cur_tsk->parent;
+	parent_tsec = slm_get_task(parent_tsk->security);
+	if ((cur_tsec->iac_wx <= level.iacLevel) || (level.iacLevel == -1)) {
+		dprintk(SLM_INTEGRITY, "%s: ppid %d(%s %d-%s) pid %d(%s %d-%s)"
+			" %s executing\n", __FUNCTION__, parent_tsk->pid,
+				parent_tsk->comm, parent_tsec->iac_wx,
+				(parent_tsec->iac_wx != parent_tsec->iac_r)
+				? "guard" : slm_iac_str[parent_tsec->iac_wx],
+				cur_tsk->pid, cur_tsk->comm, cur_tsec->iac_wx,
+				(cur_tsec->iac_wx != cur_tsec->iac_r)
+				? "guard" : slm_iac_str[cur_tsec->iac_wx],
+				bprm->filename);
+		/* Being a guard process is not inherited */
+		cur_tsec->iac_r = cur_tsec->iac_wx;
+	} else {
+		dprintk(SLM_BASE,"%s: ppid %d(%s %d-%s) pid %d(%s %d-%s)"
+			" %s executing, demoting integrity to iac=%d-%s\n",
+				__FUNCTION__, parent_tsk->pid,
+				parent_tsk->comm, parent_tsec->iac_wx,
+				(parent_tsec->iac_wx != parent_tsec->iac_r)
+				? "guard" : slm_iac_str[parent_tsec->iac_wx],
+				cur_tsk->pid, cur_tsk->comm, cur_tsec->iac_wx,
+				(cur_tsec->iac_wx != cur_tsec->iac_r)
+				? "guard" : slm_iac_str[cur_tsec->iac_wx],
+				bprm->filename, level.iacLevel,
+				slm_iac_str[level.iacLevel]);
+		cur_tsec->iac_r = level.iacLevel;
+		cur_tsec->iac_wx = level.iacLevel;
+	}
+
+	if (is_guardIntegrity(&level)) {
+		if ((strcmp(bprm->filename, bprm->interp) != 0)
+			&& (level.guard.unlimited)) {
+			dprintk(SLM_INTEGRITY, "%s:pid %d %s prohibiting "
+				"script from being an unlimited guard\n",
+				__FUNCTION__, cur_tsk->pid, bprm->filename);
+			level.guard.unlimited = 0;
+		}
+
+		dprintk(SLM_INTEGRITY, "%s: ppid %d pid %d %s (integrity guard)"
+			"cur: r %s wx %s new: r %s wx %s %s\n",
+				__FUNCTION__,
+				parent_tsk->pid, cur_tsk->pid, bprm->filename,
+				slm_iac_str[cur_tsec->iac_r],
+				slm_iac_str[cur_tsec->iac_wx],
+				slm_iac_str[level.guard.iac_r],
+				slm_iac_str[level.guard.iac_wx],
+				(level.guard.unlimited ? "unlimited" :
+				"limited"));
+		if (level.guard.unlimited) {
+			cur_tsec->iac_r =  level.guard.iac_r;
+			cur_tsec->iac_wx =  level.guard.iac_wx;
+		} else {
+			cur_tsec->iac_r = cur_tsec->iac_r < level.guard.iac_r
+				?  cur_tsec->iac_r : level.guard.iac_r;
+			cur_tsec->iac_wx = cur_tsec->iac_wx < level.guard.iac_wx
+				?  cur_tsec->iac_wx : level.guard.iac_wx;
+		}
+	}
+
+	/*
+	 * enforce: SRXAC(process) >= SAC(object)
+	 * Permit process to execute file of equal or lesser secrecy
+	 */
+	if ((cur_tsec->sac_rx >= level.sacLevel) || (level.sacLevel == -1)){
+		/* Being a guard process is not inherited */
+		cur_tsec->sac_w = cur_tsec->sac_rx;
+	} else {
+		dprintk(SLM_SECRECY, "%s: ppid %d(%s %d-%s) pid %d(%s %d-%s) %s"
+			 "executing, promoting secrecy to sac=%d-%s\n",
+				__FUNCTION__, parent_tsk->pid, parent_tsk->comm,
+				parent_tsec->sac_rx,
+				(parent_tsec->sac_w != parent_tsec->sac_rx)
+				? "guard" : slm_sac_str[parent_tsec->sac_rx],
+				cur_tsk->pid, cur_tsk->comm, cur_tsec->sac_rx,
+				(cur_tsec->sac_w != cur_tsec->sac_rx)
+				? "guard" : slm_sac_str[cur_tsec->sac_rx],
+				bprm->filename, level.sacLevel,
+				slm_sac_str[level.sacLevel]);
+		cur_tsec->sac_rx = level.sacLevel;
+		cur_tsec->sac_w = level.sacLevel;
+	}
+
+	/* Executing a secrecy guard program? Update the secrecy levels. */
+	if (is_guardSecrecy(&level)) {
+		dprintk(SLM_SECRECY, "%s: ppid %d pid %d %s (secrecy guard)"
+			"cur: rx %s w %s new: rx %s w %s\n", __FUNCTION__,
+				parent_tsk->pid,cur_tsk->pid, bprm->filename,
+				slm_sac_str[cur_tsec->sac_rx],
+				slm_sac_str[cur_tsec->sac_w],
+				slm_sac_str[level.guard.sac_rx],
+				slm_sac_str[level.guard.sac_w]);
+		/*
+		 * set low write secrecy range,
+		 *	not less than current value, prevent leaking data
+		 */
+		cur_tsec->sac_w = cur_tsec->sac_w > level.guard.sac_w
+				?  cur_tsec->sac_w : level.guard.sac_w;
+		/* limit secrecy range, never demote secrecy */
+		cur_tsec->sac_rx = cur_tsec->sac_rx > level.guard.sac_rx
+				?  cur_tsec->sac_rx : level.guard.sac_rx;
+	}
+	return 0;
+}
+
+/*
+ * Recursively traverse path (dentry->parent) until level info is found
+ */
+static void slm_getr_xattr(struct dentry *dentry, struct slm_file_xattr *level,
+		const unsigned char *fn)
+{
+	struct dentry *parent_dentry;
+	struct slm_isec_data *slm_isec = NULL;
+	struct inode *parent_inode = NULL;
+	int rc;
+
+	if (!dentry || !level)
+		return;
+
+	parent_inode = dentry->d_inode;
+	slm_isec = slm_get_isec(parent_inode->i_security);
+        if (slm_isec && (slm_isec->level.iacLevel != SLM_IAC_NOTDEFINED)) {
+                memcpy(level, &slm_isec->level,
+                        sizeof (struct slm_file_xattr));
+                dprintk(SLM_VERBOSE, "%s: %s level %d start\n",__FUNCTION__,
+                                dentry->d_name.name, level->iacLevel);
+                return;
+        }
+
+	parent_dentry = dentry;
+	if ((parent_inode->i_sb->s_magic == PROC_SUPER_MAGIC)
+		|| S_ISCHR(parent_inode->i_mode)
+		|| S_ISBLK(parent_inode->i_mode)) {
+		level->iacLevel = -1;	/* EXEMPT */
+		level->sacLevel = -1;
+	} else if (S_ISSOCK(parent_inode->i_mode)) {
+		/* retain current levels, only demote in socket_create*/
+		struct task_struct *cur_tsk = current;
+		struct slm_tsec_data *cur_tsec;
+
+		if (!cur_tsk)
+			return;
+		cur_tsec = slm_get_task(cur_tsk->security);
+		if (!cur_tsec)
+			return;
+		level->iacLevel = cur_tsec->iac_r;
+		level->sacLevel = cur_tsec->sac_rx;
+	} else { /* Get the slim extended attributes */
+		while ((parent_dentry)
+			&& ((rc = slm_get_xattr(parent_dentry, level) < 0))){
+			level->iacLevel = SLM_IAC_UNTRUSTED;
+			level->sacLevel = SLM_SAC_PUBLIC;
+
+			if (strncmp(parent_dentry->d_name.name, "/",
+					parent_dentry->d_name.len) == 0) {
+				dprintk(SLM_VERBOSE, "%s: root not labeled\n",
+						__FUNCTION__);
+				level->iacLevel = SLM_IAC_SYSTEM;
+				level->sacLevel = SLM_SAC_PUBLIC;
+			}
+
+			if (parent_dentry == parent_dentry->d_parent)
+				break;
+			else
+				parent_dentry = parent_dentry->d_parent;
+		}
+	}
+        if (!slm_isec) {
+                slm_isec = kmalloc(sizeof (struct slm_isec_data), GFP_KERNEL);
+                memset(slm_isec, 0, sizeof (struct slm_isec_data));
+                memcpy(&slm_isec->level, level,
+                                sizeof (struct slm_file_xattr));
+                slm_set_isec(parent_inode->i_security, slm_isec);
+        } else if (slm_isec->level.iacLevel != SLM_IAC_NOTDEFINED) {
+                printk(KERN_INFO "%s: %s level %d reset\n",
+                        __FUNCTION__, dentry->d_name.name, level->iacLevel);
+                slm_add_isec(parent_inode->i_security, slm_isec);
+        }
+        return;
+}
+
+static int set_iac(char *token, enum slm_iac_level *level)
+{
+	int rc = -1;
+	int iac;
+
+	if (memcmp(token, "EXEMPT", 6) == 0) {
+		*level = -1;
+		rc = 0;
+	} else {
+		for (iac = 0; iac < sizeof(slm_iac_str)/sizeof(char *); iac++){
+			if (memcmp(token, slm_iac_str[iac],
+					strlen(slm_iac_str[iac])) == 0) {
+				*level = iac;
+				rc = 0;
+				break;
+			}
+		}
+	}
+	return rc;
+}
+
+static int set_sac(char *token, enum slm_sac_level *level)
+{
+	int rc = -1;
+	int sac;
+
+	if (memcmp(token, "EXEMPT", 6) == 0) {
+		*level = -1;
+		rc = 0;
+	} else {
+		for (sac = 0; sac < sizeof(slm_sac_str)/sizeof(char *); sac++){
+			if (memcmp(token, slm_sac_str[sac],
+					strlen(slm_sac_str[sac])) == 0) {
+				*level = sac;
+				rc = 0;
+				break;
+			}
+		}
+	}
+	return rc;
+}
+
+static int set_bounds(char *token, int *unlimited)
+{
+	*unlimited = (memcmp(token, "UNLIMITED", 9) == 0) ? 1 : 0;
+	return 0;
+}
+
+static int slm_get_xattr(struct dentry *dentry, struct slm_file_xattr *level)
+{
+	int rc = -1;
+	char *token;
+	int token_len, xattr_len;
+	char *xattr_value;
+	char *buf, *buf_end;
+	int fieldno = 0;
+
+	if (!dentry || !dentry->d_inode || !dentry->d_inode->i_op
+			|| !dentry->d_inode->i_op->getxattr)
+		 return rc;
+
+	memset(level, 0, sizeof(struct slm_file_xattr));
+	if ((xattr_len = dentry->d_inode->i_op->getxattr(dentry,
+			slm_xattrName, NULL, 0)) < 0) {
+		if (xattr_len == -EOPNOTSUPP) {
+			level->iacLevel = -1;
+			level->sacLevel = -1;
+			rc = 0;
+			return rc;
+		} else {
+			dprintk(SLM_VERBOSE, "%s: %d %s getxattr failed %s\n",
+				__FUNCTION__, xattr_len, dentry->d_name.name,
+				slm_xattrName);
+			return xattr_len;
+		}
+	}
+
+	xattr_value = kmalloc(xattr_len+1, GFP_KERNEL);
+	if (!xattr_value)
+		return -ENOMEM;
+
+	memset(xattr_value, 0, xattr_len +1);
+	xattr_len = dentry->d_inode->i_op->getxattr(dentry, slm_xattrName,
+			xattr_value, xattr_len);
+
+	/* Get the 7 access class levels from the extended attribute */
+	buf = xattr_value + sizeof(time_t);
+	if (*buf == 0x20)
+		buf++; /* skip blank after timestamp */
+	buf_end = xattr_value + xattr_len;
+
+	while ((token = get_token(buf, buf_end, ' ', &token_len)) != NULL) {
+		buf = token + token_len;
+			switch(++fieldno) {
+		case 1:
+			if (set_iac(token, &level->iacLevel) == 0)
+				rc = 0;
+			break;
+		case 2:
+			set_sac(token, &level->sacLevel);
+			break;
+		case 3:
+			set_iac(token, &level->guard.iac_r);
+			break;
+		case 4:
+			set_iac(token, &level->guard.iac_wx);
+			break;
+		case 5:
+			set_bounds(token, &level->guard.unlimited);
+			set_sac(token, &level->guard.sac_w);
+			break;
+		case 6:
+			set_sac(token, &level->guard.sac_rx);
+			break;
+		case 7:
+			set_bounds(token, &level->guard.unlimited);
+		default:
+			break;
+		}
+	}
+	if (xattr_value)
+		kfree(xattr_value);
+	return rc;
+}
+
+/*
+ * slm_set_taskperm
+ */
+static int slm_set_taskperm(int mask, struct slm_file_xattr *level,
+			const unsigned char *name, void *caller)
+{
+	struct task_struct *cur_tsk = current, *parent_tsk;
+	struct slm_tsec_data *cur_tsec = NULL, *parent_tsec = NULL;
+	int rc;
+
+	if (!cur_tsk)
+		return 0;
+	cur_tsec = slm_get_task(cur_tsk->security);
+
+	parent_tsk = cur_tsk->parent;
+	if (!parent_tsk)
+		return 0;
+	parent_tsec = slm_get_task(parent_tsk->security);
+
+	if ((!cur_tsec) || (!parent_tsec)) {
+		if ((rc = slm_alloc_security(cur_tsk)) < 0)
+			return rc;
+	}
+	cur_tsec = slm_get_task(cur_tsk->security);
+	parent_tsec = slm_get_task(parent_tsk->security);
+	if ((!cur_tsec) || (!parent_tsec)) {
+		printk(KERN_INFO "set_taskperm: NULL cur_tsec/parent_tsec\n");
+		return 0;
+	}
+
+	if (!level)
+		return 0;
+
+	if (mask & MAY_READ) {
+		/*
+		 * enforce: IRAC(process) <= IAC(object)
+		 * Permit process to read file of equal or greater integrity
+		 * otherwise, demote the process.
+		 */
+		if ((cur_tsec->iac_r <= level->iacLevel)
+			|| (level->iacLevel == -1))
+		{
+			;
+		} else { /* Reading lower integrity, demote process */
+			dprintk(SLM_BASE, "ppid %d(%s p=%d-%s) "
+				" pid %d(%s p=%d-%s) demoting integrity to"
+				" iac=%d-%s(%s)\n",
+				parent_tsk->pid, parent_tsk->comm,
+				parent_tsec->iac_r,
+				(parent_tsec->iac_wx != parent_tsec->iac_r)
+				? "guard" : slm_iac_str[parent_tsec->iac_r],
+				cur_tsk->pid, cur_tsk->comm, cur_tsec->iac_r,
+				(cur_tsec->iac_wx != cur_tsec->iac_r)
+				? "guard" : slm_iac_str[cur_tsec->iac_r],
+				level->iacLevel, slm_iac_str[level->iacLevel],
+				name);
+
+			/* Even in the case of a integrity guard process. */
+			cur_tsec->iac_r = level->iacLevel;
+			cur_tsec->iac_wx = level->iacLevel;
+		}
+
+		/*
+		 * enforce: SRXAC(process) >= SAC(object)
+		 * Permit process to read file of equal or lesser secrecy;
+		 * otherwise, promote the process.
+		 */
+		if ((cur_tsec->sac_rx >= level->sacLevel)
+				|| (level->sacLevel == -1)){
+			;
+		} else { /* Reading higher secrecy, promote process */
+			dprintk(SLM_BASE, "ppid %d(%s p=%d-%s) "
+				"pid %d(%s p=%d-%s) promoting secrecy to "
+				"p=%d-%s(%s)\n", parent_tsk->pid,
+				parent_tsk->comm, parent_tsec->sac_rx,
+				(parent_tsec->sac_w != parent_tsec->sac_rx)
+				? "guard" : slm_sac_str[parent_tsec->sac_rx],
+				cur_tsk->pid, cur_tsk->comm, cur_tsec->sac_rx,
+				(cur_tsec->sac_w != cur_tsec->sac_rx)
+				? "guard" : slm_sac_str[cur_tsec->sac_rx],
+				level->sacLevel, slm_sac_str[level->sacLevel],
+				name);
+			/* Even in the case of a secrecy guard process. */
+			cur_tsec->sac_rx = level->sacLevel;
+			cur_tsec->sac_w = level->sacLevel;
+		}
+	}
+
+	if ((mask & MAY_WRITE) || (mask & MAY_APPEND)) {
+		/*
+		 * enforce: IWXAC(process) >= IAC(object)
+		 * Permit process to write a file of equal or lesser integrity.
+		 */
+		if ((cur_tsec->iac_wx >= level->iacLevel)
+				|| (level->iacLevel == -1)) {
+			;
+		} else { /* can't write higher integrity */
+			dprintk(SLM_BASE, "ppid %d(%s p=%d-%s) "
+				"pid %d(%s p=%d-%s) can't write higher "
+				"integrity iac=%d-%s(%s)\n",
+				parent_tsk->pid, parent_tsk->comm,
+				parent_tsec->iac_wx,
+				(parent_tsec->iac_wx != parent_tsec->iac_r)
+				? "guard" : slm_iac_str[parent_tsec->iac_wx],
+				cur_tsk->pid, cur_tsk->comm, cur_tsec->iac_wx,
+				(cur_tsec->iac_wx != cur_tsec->iac_r)
+				? "guard" : slm_iac_str[cur_tsec->iac_wx],
+				level->iacLevel, slm_iac_str[level->iacLevel],
+				name);
+			return -EACCES;
+		}
+
+		/*
+		 * enforce: SWAC(process) <= SAC(process)
+		 * Permit process to write a file of equal or greater secrecy
+		 */
+		if ((cur_tsec->sac_w <= level->sacLevel)
+				|| (level->sacLevel == -1)) {
+			;
+		} else { /* can't write lower secrecy */
+			dprintk(SLM_BASE, "ppid %d(%s p=%d-%s) "
+				"pid %d(%s p=%d-%s) can't write lower "
+				"secrecy sac=%d-%s(%s)\n",
+				parent_tsk->pid, parent_tsk->comm,
+				parent_tsec->sac_w,
+				(parent_tsec->sac_w != parent_tsec->sac_rx)
+				? "guard" : slm_iac_str[parent_tsec->sac_w],
+				cur_tsk->pid, cur_tsk->comm, cur_tsec->sac_w,
+				(cur_tsec->sac_w != cur_tsec->sac_rx)
+				? "guard" : slm_sac_str[cur_tsec->sac_w],
+				level->sacLevel, slm_sac_str[level->sacLevel],
+				name);
+			return -EACCES;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Premise:
+ * Can't write or execute higher integrity, can't read lower integrity
+ * Can't read or execute higher secrecy, can't write lower secrecy
+ */
+static int slm_inode_permission(struct inode *inode, int mask,
+			struct nameidata *nd)
+{
+	char *path = (char *)__get_free_page(GFP_KERNEL);
+	const unsigned char *fn;
+	struct dentry *dentry = NULL;
+	struct slm_file_xattr level;
+	int rc = 0;
+	const unsigned char *debug_name;
+
+	if (!nd || !nd->dentry){
+		if (inode)
+			dentry = d_find_alias(inode);
+	} else
+		dentry = nd->dentry;
+
+	if (!dentry || !dentry->d_name.name) {
+		if (path)
+			free_page((unsigned long)path);
+		return 0;
+	}
+
+	if (!path || !nd || !nd->dentry || !nd->mnt)
+		debug_name = dentry->d_name.name;	/* short name */
+	else {
+		fn = d_path(nd->dentry, nd->mnt, path, PAGE_SIZE);
+		debug_name = (!fn) ? dentry->d_name.name : fn; /* full name */
+	}
+
+	/* Recursively traverse path (dentry->parent) until level info found */
+	memset(&level, 0, sizeof(struct slm_file_xattr));
+	slm_getr_xattr(dentry, &level, debug_name);/* always returns something*/
+
+	/* measure all SYSTEM level integrity objects */
+	if ((level.iacLevel == SLM_IAC_SYSTEM) && slm_enable_ima)
+		slm_measure(__FUNCTION__, debug_name, nd, NULL, inode, mask);
+
+	rc = slm_set_taskperm(mask, &level, debug_name, (void *)__FUNCTION__);
+	dprintk(SLM_VERBOSE, "%s: %s - %s\n",
+			 __FUNCTION__, dentry->d_name.name, debug_name);
+	if (path)
+		free_page((unsigned long)path);
+
+
+	if (S_ISDIR(inode->i_mode) && (mask & MAY_WRITE))
+		return 0;
+	else
+		return rc;
+}
+
+static int slm_inode_unlink(struct inode *dir, struct dentry *dentry)
+{
+	struct slm_file_xattr level;
+	int mask = MAY_WRITE;
+	int rc = 0;
+
+	if (!dentry || !dentry->d_name.name)
+		return 0;
+
+	memset(&level, 0, sizeof(struct slm_file_xattr));
+	slm_getr_xattr(dentry, &level, NULL);  /* always returns something */
+
+	rc = slm_set_taskperm(mask, &level, dentry->d_name.name,
+					(void *) __FUNCTION__);
+	return rc;
+}
+
+void slm_inode_free_security(struct inode *inode)
+{
+	struct slm_isec_data *slm_isec;
+
+	slm_isec = slm_del_isec(inode->i_security);
+	if (slm_isec)
+		kfree(slm_isec);
+}
+
+static int slm_file_permission(struct file *file, int mask)
+{
+	char *path = (char *)__get_free_page(GFP_KERNEL);
+	const unsigned char *fn = NULL;
+	struct dentry *dentry;
+	struct slm_file_xattr level;	/* access control levels */
+	const unsigned char *debug_name;
+	int rc = 0;
+	struct inode *inode = NULL;
+
+	if (!file || !file->f_dentry || !file->f_dentry->d_name.name){
+		if (path)
+			free_page((unsigned long)path);
+		return 0;
+	}
+
+	dentry = file->f_dentry;
+	inode = dentry->d_inode;
+
+	if (S_ISREG(inode->i_mode)) {
+		if (!path || !file || !file->f_dentry || !file->f_vfsmnt)
+			debug_name = dentry->d_name.name; /* short name */
+		else {
+			fn = d_path(file->f_dentry, file->f_vfsmnt, path,
+					PAGE_SIZE);
+			debug_name = (!fn)
+				? dentry->d_name.name : fn;
+		}
+
+		/* Will need to measure again. */
+		if ((mask & MAY_WRITE) || (mask & MAY_APPEND)) {
+			struct inode *inode = NULL;
+
+			inode = dentry->d_inode;
+			if (slm_enable_ima && inode)
+				slm_reset_measure(inode, debug_name);
+		}
+
+		/*
+		 * Recursively traverse path (dentry->parent) until level
+		 * info is found.
+		 */
+		memset(&level, 0, sizeof(struct slm_file_xattr));
+		slm_getr_xattr(dentry, &level, debug_name);
+		rc = slm_set_taskperm(mask, &level, debug_name,
+				(void *) __FUNCTION__);
+	}
+	if (path)
+		free_page((unsigned long)path);
+	return rc;
+}
+
+static int slm_alloc_security(struct task_struct *tsk)
+{
+	struct slm_tsec_data *tsec = NULL, *cur_tsec = NULL,
+		*parent_tsec = NULL;
+	struct task_struct *cur_tsk = current, *parent_tsk;
+
+
+	/* allocate parent_tsk->security, if needed */
+	parent_tsk = cur_tsk->parent;
+	if (parent_tsk)
+		parent_tsec = slm_get_task(parent_tsk->security);
+	if (parent_tsk && !parent_tsec){
+		dprintk(SLM_VERBOSE, "%s: alloc_security pid %d "
+				"** parent_tsk->pid %d **\n", __FUNCTION__,
+				tsk->pid, parent_tsk->pid);
+		parent_tsec = (struct slm_tsec_data *)
+			kmalloc(sizeof (struct slm_tsec_data), GFP_KERNEL);
+		if (!parent_tsec)
+			return -ENOMEM;
+
+		memset(parent_tsec, 0, sizeof(struct slm_tsec_data));
+		slm_set_task(parent_tsk->security, parent_tsec);
+		parent_tsec->iac_r = SLM_IAC_HIGHEST - 1;
+		parent_tsec->iac_wx = SLM_IAC_HIGHEST - 1;
+		parent_tsec->sac_w = SLM_SAC_NOTDEFINED + 1;
+		parent_tsec->sac_rx = SLM_SAC_NOTDEFINED + 1;
+	}
+
+	/* allocate current->security, if needed */
+	cur_tsec = slm_get_task(cur_tsk->security);
+	if (!cur_tsec) {
+		dprintk(SLM_VERBOSE, "%s: alloc_security pid %d ** "
+				"cur_tsk->pid %d" " ** parent_tsk->pid %d\n",
+				__FUNCTION__,
+				tsk->pid, cur_tsk->pid, parent_tsk->pid);
+
+		/* initial process, set to highest integrity and secrecy */
+		cur_tsec = (struct slm_tsec_data *)
+			kmalloc(sizeof (struct slm_tsec_data), GFP_KERNEL);
+		if (!cur_tsec)
+			return -ENOMEM;
+
+		memset(cur_tsec, 0, sizeof(struct slm_tsec_data));
+		slm_set_task(cur_tsk->security, cur_tsec);
+		cur_tsec->iac_r = SLM_IAC_HIGHEST - 1;
+		cur_tsec->iac_wx = SLM_IAC_HIGHEST - 1;
+		cur_tsec->sac_w = SLM_SAC_NOTDEFINED + 1;
+		cur_tsec->sac_rx = SLM_SAC_NOTDEFINED + 1;
+	}
+
+	/* new tsk->security inherits from current->security */
+	tsec = slm_get_task(tsk->security);
+	if (!tsec) {
+		tsec = (struct slm_tsec_data *)
+			kmalloc(sizeof (struct slm_tsec_data), GFP_KERNEL);
+		if (!tsec)
+			return -ENOMEM;
+		memcpy(tsec, cur_tsec, sizeof (struct slm_tsec_data));
+		slm_set_task(tsk->security, tsec);
+	} else {
+		dprintk(SLM_VERBOSE, "%s: tsk->pid %d cur_tsk->pid %d\n",
+					__FUNCTION__, tsk->pid, cur_tsk->pid);
+	}
+	return 0;
+}
+
+/*
+ * Check integrity permission to create a regular file.
+ */
+static int slm_inode_create (struct inode *inode,
+	struct dentry *dentry, int mask)
+{
+	struct slm_tsec_data *cur_tsec = NULL;
+	struct task_struct *cur_tsk = current;
+	struct dentry *parent_dentry;
+	struct slm_file_xattr parent_level;
+	const unsigned char *debug_name = "???";
+
+	memset(&parent_level, 0, sizeof(struct slm_file_xattr));
+	cur_tsec = slm_get_task(cur_tsk->security);
+
+	if (!dentry)
+		return 0;
+	else
+		parent_dentry = dentry->d_parent;
+
+	if (!parent_dentry || !parent_dentry->d_name.name)
+		debug_name = parent_dentry->d_name.name;
+
+	/* get parent integrity info */
+	slm_getr_xattr(parent_dentry, &parent_level, debug_name);
+
+	/*
+	 * enforce: IWXAC(process) >= IAC(object)
+	 * Permit process to write a file of equal or lesser integrity.
+	 */
+	if ((cur_tsec->iac_wx >= parent_level.iacLevel)
+			|| (parent_level.iacLevel == -1)) {
+		;
+	} else { /* can't write higher integrity */
+		dprintk(SLM_INTEGRITY, "%s: %s - prohibit low integrity "
+			" process writing into higher level directory\n",
+			__FUNCTION__, debug_name);
+		return -EPERM;
+	}
+	return 0;
+}
+
+static int slm_set_xattr(struct slm_file_xattr *level,
+		char **name, void **value, size_t *value_len)
+{
+	int len;
+	int xattrLen;
+	char buf[76];	/* buffer for extended attribute */
+	char *bufp = buf;
+	char *xattrVal = buf;
+	struct timespec now;
+	time_t nl_time;
+
+	if (!level)
+		return 0;
+
+	memset(buf, 0, sizeof buf);
+
+	now = CURRENT_TIME;
+	len = sizeof now.tv_sec;
+	nl_time = htonl(now.tv_sec);
+	memcpy(bufp, &nl_time, len);
+	bufp += len;
+	*bufp++ = ' ';
+
+	if (level->iacLevel == -1) {
+		memcpy(bufp, "EXEMPT",6);
+		bufp += 6;
+	} else if (level->iacLevel == 0) {
+		dprintk(SLM_VERBOSE, "%s: iaclevel is 0\n", __FUNCTION__);
+		level->iacLevel = 1;
+		len = strlen(slm_iac_str[level->iacLevel]);
+		memcpy(bufp, slm_iac_str[level->iacLevel], len);
+		bufp += len;
+	} else {
+		len = strlen(slm_iac_str[level->iacLevel]);
+		memcpy(bufp, slm_iac_str[level->iacLevel], len);
+		bufp += len;
+	}
+	*bufp++ = ' ';
+	if (level->sacLevel == -1) {
+		memcpy(bufp, "EXEMPT",6);
+		bufp += 6;
+	} else {
+		len = strlen(slm_sac_str[level->sacLevel]);
+		memcpy(bufp, slm_sac_str[level->sacLevel], len);
+		bufp += len;
+	}
+	xattrLen =  bufp - buf;
+
+	*name = kmalloc(sizeof("slim.level") + 1, GFP_KERNEL);
+	if (!*name)
+		return -ENOMEM;
+	memcpy(*name, "slim.level", sizeof("slim.level"));
+	*value = kmalloc(xattrLen + 1, GFP_KERNEL);
+	if (!*value)
+		return -ENOMEM;
+	memcpy(*value, xattrVal, xattrLen);
+	*value_len = xattrLen;
+	return 0;
+}
+
+/* Create the security.slim.level extended attribute */
+static int slm_inode_init_security(struct inode *inode, struct inode *dir,
+					struct list_head *head)
+{
+        struct slm_isec_data *slm_isec = NULL;
+        struct slm_tsec_data *cur_tsec = NULL;
+        struct task_struct *cur_tsk = current;
+        struct slm_file_xattr level;
+	struct xattr_data *data;
+
+	if (!head)
+		return 0;
+
+        cur_tsec = slm_get_task(cur_tsk->security);
+
+        /* get parent level info */
+        memset(&level, 0, sizeof (struct slm_file_xattr));
+        slm_isec = slm_get_isec(dir->i_security);
+	if (!slm_isec) {
+                printk(KERN_INFO "%s: slm_isec is NULL \n",__FUNCTION__);
+		return (-EOPNOTSUPP);
+	}
+
+        if (slm_isec && (slm_isec->level.iacLevel != SLM_IAC_NOTDEFINED)) {
+                memcpy(&level, &slm_isec->level,
+                                sizeof (struct slm_file_xattr));
+                dprintk(SLM_VERBOSE, "%s: level %d\n", __FUNCTION__,
+                                 slm_isec->level.iacLevel);
+        }
+
+        /* low integrity process wrote into a higher level directory */
+        if (cur_tsec->iac_wx < level.iacLevel) {
+                level.iacLevel = cur_tsec->iac_wx;
+                level.sacLevel = cur_tsec->sac_w;
+        }
+        /* if directory is exempt, then use process level */
+        if (level.iacLevel == -1){
+                level.iacLevel = cur_tsec->iac_wx;
+                level.sacLevel = cur_tsec->sac_w;
+        }
+
+	data = kmalloc(sizeof(struct xattr_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	/* set levels, based on parent */
+	slm_set_xattr(&level, &data->name, &data->value, &data->len);
+	INIT_LIST_HEAD(&data->list);
+	list_add_tail(&data->list, head);
+
+	return 0;
+}
+
+
+/*
+ * Update the security.evm.hmac on a newly created regular file.
+ */
+static void slm_inode_post_create (struct inode *inode,
+	struct dentry *dentry, int mask)
+{
+	int rc;
+
+	if (!dentry) {
+		printk(KERN_INFO "%s: dentry is null\n", __FUNCTION__);
+		return;
+	}
+	rc = evm_update_hmac(dentry, 0);
+	if (dentry->d_name.name)
+		dprintk(SLM_VERBOSE, "%s: %s hmac calculation %s\n",
+			__FUNCTION__, dentry->d_name.name,
+			rc == 0 ? "succeeded" : "failed");
+}
+
+/*
+ * Check permissions to create a new directory in the existing directory
+ * associated with inode strcture @dir.
+ */
+static int slm_inode_mkdir (struct inode *inode,
+	    struct dentry *dentry, int mask)
+{
+	struct slm_tsec_data *cur_tsec = NULL;
+	struct slm_isec_data *slm_isec = NULL;
+	struct task_struct *cur_tsk = current;
+	struct dentry *parent_dentry;
+	struct slm_file_xattr parent_level;
+	const unsigned char *debug_name = "???";
+	int rc = 0;
+
+	memset(&parent_level, 0, sizeof(struct slm_file_xattr));
+	cur_tsec = slm_get_task(cur_tsk->security);
+
+	if (!dentry)
+		return 0;
+	else
+		parent_dentry = dentry->d_parent;
+
+	if (!parent_dentry || !parent_dentry->d_name.name)
+		debug_name = parent_dentry->d_name.name;
+
+	/* get parent level info */
+	while ((parent_dentry) && ((rc = slm_get_xattr(parent_dentry,
+				&parent_level)) < 0)){
+		parent_level.iacLevel = SLM_IAC_SYSTEM;
+		parent_level.sacLevel = SLM_SAC_PUBLIC;
+		if (parent_dentry == parent_dentry->d_parent)
+			break;
+		else
+			parent_dentry = parent_dentry->d_parent; /* try again */
+	}
+	if (cur_tsec->iac_wx < parent_level.iacLevel) {
+		if (parent_level.iacLevel == SLM_IAC_SYSTEM)
+			return -EACCES;
+		else {
+			dprintk(SLM_VERBOSE, "%s:%s - creating lower integrity"
+				" directory, than parent\n",
+				__FUNCTION__, debug_name);
+			return 0;
+		}
+	}
+        slm_isec = slm_get_isec(inode->i_security);
+        if (!slm_isec) {
+                slm_isec = kmalloc(sizeof (struct slm_isec_data), GFP_KERNEL);
+                if (!slm_isec)
+                        return -ENOMEM;
+                memset(slm_isec, 0, sizeof (struct slm_isec_data));
+        }
+        if (!slm_isec->level.iacLevel) {
+                memcpy(&slm_isec->level, &parent_level,
+                                sizeof (struct slm_file_xattr));
+        }
+	return 0;
+}
+
+/*
+ * Update the security.evm.hmac on a newly created directory.
+ */
+static void slm_inode_post_mkdir (struct inode *inode,
+	    struct dentry *dentry, int mask)
+{
+	int rc;
+
+	if (!dentry)
+		return;
+	rc = evm_update_hmac(dentry, 0);
+	if (dentry->d_name.name)
+		dprintk(SLM_VERBOSE, "%s: %s hmac calculation %s\n",
+			__FUNCTION__, dentry->d_name.name,
+			rc == 0 ? "succeeded" : "failed");
+}
+
+static int slm_inode_rename (struct inode *old_dir, struct dentry *old_dentry,
+	                     struct inode *new_dir, struct dentry *new_dentry)
+{
+	struct slm_file_xattr old_level, parent_level;
+	struct dentry *parent_dentry;
+	const unsigned char *debug_name;
+
+	memset(&old_level, 0, sizeof(struct slm_file_xattr));
+	debug_name = old_dentry->d_name.name;	/* short name */
+	slm_getr_xattr(old_dentry, &old_level, debug_name);
+	parent_dentry = new_dentry->d_parent;
+
+	memset(&parent_level, 0, sizeof(struct slm_file_xattr));
+	debug_name = parent_dentry->d_name.name;	/* short name */
+	slm_getr_xattr(parent_dentry, &parent_level, debug_name);
+	if (old_level.iacLevel < parent_level.iacLevel) {
+		dprintk(SLM_BASE, "%s: prohibit rename of %s (low"
+			" integrity) into %s (higher level directory)\n",
+			__FUNCTION__, old_dentry->d_name.name,
+			parent_dentry->d_name.name);
+		return -EPERM;
+	}
+	return 0;
+}
+
+/*
+ * Limit the integrity value of an object to be no greater than that
+ * of the current process. This is especially important for objects
+ * being promoted.
+*/
+int slm_inode_setxattr (struct dentry *dentry, char *name, void *value,
+			       size_t size, int flags)
+{
+	struct task_struct *cur_tsk = current;
+	struct slm_tsec_data *cur_tsec = NULL;
+
+	cur_tsec = slm_get_task(cur_tsk->security);
+	if (!cur_tsec)
+		return 0;
+
+	if (!value)
+		return -EINVAL;
+
+	dprintk(SLM_VERBOSE,"%s: name %s value %s process:iac_r %s iac_wx %s\n",
+		__FUNCTION__, name, (char *)value,
+		slm_iac_str[cur_tsec->iac_r], slm_iac_str[cur_tsec->iac_wx]);
+
+	if (memcmp(name, slm_xattrName, strlen(slm_xattrName)) != 0)
+		return 0;
+
+		switch(cur_tsec->iac_wx){
+	case SLM_IAC_USER:
+		if ((memcmp(value + sizeof(time_t) + 1, "USER", 4) != 0)
+			&& (memcmp(value + sizeof(time_t) + 1,
+				"UNTRUSTED", 9) != 0))
+			return -EPERM;
+		break;
+	case SLM_IAC_SYSTEM:
+		if ((memcmp(value + sizeof(time_t) + 1, "SYSTEM", 6) != 0)
+			&& (memcmp(value + sizeof(time_t) + 1, "USER", 4) != 0)
+			&& (memcmp(value + sizeof(time_t) + 1, "UNTRUSTED", 9)
+				!= 0)
+			&& (memcmp(value + sizeof(time_t) + 1, "EXEMPT", 6)
+				!= 0))
+			return -EPERM;
+		break;
+	default:
+		return -EPERM;
+	}
+	return 0;
+}
+
+/* SLIM extended attribute were modified */
+void slm_inode_post_setxattr(struct dentry *dentry, char *name,
+			     void *value, size_t size, int flags)
+{
+	struct inode *inode = NULL;
+	struct slm_isec_data *slm_isec = NULL;
+
+	if (!dentry || !dentry->d_inode)
+		return;
+
+	inode = dentry->d_inode;
+	slm_isec = slm_get_isec(inode->i_security);
+	if (slm_isec)
+                memset(slm_isec, 0, sizeof (struct slm_isec_data));
+	return;
+}
+
+/*
+ * Opening a socket demotes the integrity of a process to untrusted.
+ */
+int slm_socket_create (int family, int type, int protocol, int kern)
+{
+	struct task_struct *cur_tsk = current, *parent_tsk;
+	struct slm_tsec_data *cur_tsec = NULL, *parent_tsec = NULL;
+	int rc;
+
+	cur_tsec = slm_get_task(cur_tsk->security);
+	if (!cur_tsec) {
+		if ((rc = slm_alloc_security(cur_tsk)) < 0)
+			return rc;
+		cur_tsec = slm_get_task(cur_tsk->security);
+		if (!cur_tsec)
+			return 0;
+	}
+	/* Todo: make sure this process and the local/unix process
+	 * are running with the same iac and sac.
+	 */
+	if ((family != AF_UNIX) && (family != AF_LOCAL) &&
+			(family != AF_NETLINK)) {
+		if (cur_tsec->iac_r > SLM_IAC_UNTRUSTED) {
+			parent_tsk = cur_tsk->parent;
+			parent_tsec = slm_get_task(parent_tsk->security);
+			dprintk(SLM_INTEGRITY, "%s: ppid %d pid %d demoting "
+				"family %d type %d protocol %d kern %d"
+				" to untrusted.\n", __FUNCTION__,
+				parent_tsk->pid, cur_tsk->pid,
+				family, type, protocol, kern);
+			cur_tsec->iac_r = SLM_IAC_UNTRUSTED;
+			cur_tsec->iac_wx = SLM_IAC_UNTRUSTED;
+		}
+	}
+	return 0;
+}
+
+/*
+ * When a task gets allocated, it inherits the current IAC and SAC.
+ * Set the values and store them in p->security.
+ */
+static int slm_task_alloc_security(struct task_struct *tsk)
+{
+	int rc;
+	struct slm_tsec_data *tsec = NULL;
+
+	tsec = slm_get_task(tsk->security);
+	if (!tsec) {
+		if ((rc = slm_alloc_security(tsk)) < 0)
+			return rc;
+	};
+	return 0;
+}
+
+static void slm_task_free_security(struct task_struct *tsk)
+{
+	struct slm_tsec_data *tsec;
+
+	if (!tsk)
+		return;
+
+	tsec = slm_del_task(tsk->security);
+	if (tsec)
+		kfree(tsec);
+	return;
+}
+
+static int slm_task_post_setuid (uid_t old_ruid, uid_t old_euid,
+		uid_t old_suid, int flags)
+{
+	struct task_struct *cur_tsk = current, *parent_tsk;
+	struct slm_tsec_data *cur_tsec, *parent_tsec;
+
+	cur_tsec = slm_get_task(cur_tsk->security);
+	if (!cur_tsec)
+		;
+	else if (flags == LSM_SETID_ID) {
+		/*set process to USER level integrity for everything but root*/
+		dprintk(SLM_VERBOSE, "ruid %d euid %d suid %d "
+				"cur: uid %d euid %d suid %d\n",
+				 old_ruid, old_euid, old_suid,
+				current->uid, current->euid, current->suid);
+		if (cur_tsec->iac_r == SLM_IAC_UNTRUSTED) {
+			dprintk(SLM_VERBOSE, "Integrity: pid %d iac_r %d "
+				" iac_wx %d remains UNTRUSTED\n",
+				cur_tsk->pid, cur_tsec->iac_r,cur_tsec->iac_wx);
+		} else if (current->uid != 0) {
+			dprintk(SLM_VERBOSE, "setting: pid %d iac_r %d "
+				" iac_wx %d to USER\n",
+				cur_tsk->pid, cur_tsec->iac_r,cur_tsec->iac_wx);
+			cur_tsec->iac_r = SLM_IAC_USER;
+			cur_tsec->iac_wx = SLM_IAC_USER;
+		} else if ((current->uid == 0) && (old_ruid != 0)) {
+			dprintk(SLM_VERBOSE, "setting: pid %d iac_r %d "
+				" iac_wx %d to SYSTEM\n",
+				cur_tsk->pid, cur_tsec->iac_r,cur_tsec->iac_wx);
+			cur_tsec->iac_r = SLM_IAC_SYSTEM;
+			cur_tsec->iac_wx = SLM_IAC_SYSTEM;
+		}
+	} else {
+		parent_tsk = cur_tsk->parent;
+		if (!parent_tsk) {
+			parent_tsec = slm_get_task(parent_tsk->security);
+			dprintk(SLM_VERBOSE, "ppid %d(%s %d-%s) "
+				" pid %d(%s)iac_r %d iac_wx %d\n",
+				parent_tsk->pid, parent_tsk->comm,
+				parent_tsec->iac_wx,
+				(parent_tsec->iac_wx != parent_tsec->iac_r)
+				? "guard" : slm_iac_str[parent_tsec->iac_wx],
+				cur_tsk->pid, cur_tsk->comm,
+				cur_tsec->iac_r, cur_tsec->iac_wx);
+		}
+	}
+	return 0;
+}
+
+static inline int slm_setprocattr(struct task_struct *tsk,
+	char *name, void *value, size_t size)
+{
+	dprintk(SLM_BASE, "%s: %s \n", __FUNCTION__, name);
+	return -EACCES;
+
+}
+
+static inline int slm_getprocattr(struct task_struct *tsk,
+	char *name, void *value, size_t size)
+{
+	struct slm_tsec_data *tsec = NULL;
+	size_t len = 0;
+
+	tsec = slm_get_task(tsk->security);
+	if (!tsec)
+		len = snprintf(value, size, "unknown");
+	else {
+		if (tsec->iac_wx != tsec->iac_r)
+			len = snprintf(value, size, "guard wx:%s r:%s",
+					slm_iac_str[tsec->iac_wx],
+					slm_iac_str[tsec->iac_r]);
+		else
+			len = snprintf(value, size, "%s",
+					slm_iac_str[tsec->iac_wx]);
+	}
+	return len > size ? size : len;
+}
+
+static struct security_operations slm_security_ops = {
+	.bprm_check_security =		slm_bprm_check_security,
+	.inode_permission =		slm_inode_permission,
+	.inode_unlink =			slm_inode_unlink,
+	.inode_create =			slm_inode_create,
+	.inode_post_create =		slm_inode_post_create,
+	.inode_mkdir =			slm_inode_mkdir,
+	.inode_post_mkdir =		slm_inode_post_mkdir,
+	.inode_rename =			slm_inode_rename,
+	.inode_setxattr =		slm_inode_setxattr,
+	.inode_post_setxattr =		slm_inode_post_setxattr,
+	.inode_free_security =		slm_inode_free_security,
+	.inode_init_security =		slm_inode_init_security,
+	.file_permission =		slm_file_permission,
+	.socket_create =		slm_socket_create,
+	.task_alloc_security =		slm_task_alloc_security,
+	.task_free_security =		slm_task_free_security,
+	.task_post_setuid =		slm_task_post_setuid,
+	.getprocattr =			slm_getprocattr,
+	.setprocattr =			slm_setprocattr
+};
+
+static int __init init_slm (void)
+{
+	int error = 0;
+
+	ima_init();
+	slm_init_secfs();
+
+	slm_idx = 1;
+	if (register_security(&slm_security_ops, &slm_idx)) {
+		if (mod_reg_security ("slim", &slm_security_ops, &slm_idx)) {
+			dprintk(SLM_BASE, "%s: security hooks registration "
+					"failed\n", __FUNCTION__);
+		return -EINVAL;
+		}
+		secondary = 1;
+	}
+	dprintk(SLM_BASE, "%s: registered security hooks (idx = %d)\n",
+				 __FUNCTION__, slm_idx);
+
+	sandbox_avail = 1;
+	return error;
+}
+
+static void __exit cleanup_slm (void)
+{
+	sandbox_avail = 0;
+
+	slm_cleanup_secfs();
+	if (secondary) {
+		if (mod_unreg_security ("slim", &slm_security_ops))
+			dprintk(SLM_BASE, "%s: failure unregistering module "
+				"with primary module.\n", __FUNCTION__);
+		} else if (unregister_security (&slm_security_ops)) {
+			dprintk(SLM_BASE, "%s: failure unregistering module "
+				"with the kernel\n", __FUNCTION__);
+	}
+	ima_cleanup();
+	dprintk(SLM_BASE, "%s: completed \n", __FUNCTION__);
+}
+
+module_init(init_slm);
+module_exit (cleanup_slm);
+
+module_param(slm_config, charp, 0444);
+MODULE_PARM_DESC(slm_config, "SLIM configuration file");
+
+module_param(slm_xattrName, charp, 0444);
+MODULE_PARM_DESC(slm_config, "SLIM extended attribute");
+
+module_param(slm_enable_ima, uint, 1);
+MODULE_PARM_DESC(slm_enable_ima, "SLIM enabling IMA");
+
+module_param(slm_debug, uint, 1);
+MODULE_DESCRIPTION("Simple Linux Integrity Module");
+
+MODULE_LICENSE("GPL");
diff -rupN linux-2.6.14.2.orig/security/evm/slim/slm_secfs.c linux-2.6.14.2.tc/security/evm/slim/slm_secfs.c
--- linux-2.6.14.2.orig/security/evm/slim/slm_secfs.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.14.2.tc/security/evm/slim/slm_secfs.c	2005-11-11 14:15:55.000000000 -0500
@@ -0,0 +1,146 @@
+/*
+ * SLIM securityfs support: debuggin control files
+ *
+ * Copyright (C) 2005 IBM Corporation
+ * Author: Mimi Zohar <zohar@private>
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ */
+
+#include <asm/uaccess.h>
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/security.h>
+#include "slim.h"
+
+static struct dentry *slim_dir, *slim_level;
+static struct dentry *slim_debug_dir, *slim_integrity, *slim_secrecy,
+	*slim_verbose;
+
+static ssize_t slm_read_level(struct file *file, char __user *buf,
+			 size_t buflen, loff_t *ppos)
+{
+	struct task_struct *cur_tsk = current;
+	struct slm_tsec_data *cur_tsec = NULL;
+	ssize_t len = 0;
+	char *page;
+
+	page = (char *)__get_free_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+
+	cur_tsec = slm_get_task(cur_tsk->security);
+	if (!cur_tsec)
+		len = sprintf(page, "level: unknown\n");
+	else {
+		if (cur_tsec->iac_wx != cur_tsec->iac_r)
+			len = sprintf(page, "level: guard wx:%s r:%s\n",
+				slm_iac_str[cur_tsec->iac_wx],
+				slm_iac_str[cur_tsec->iac_r]);
+		else
+			len = sprintf(page, "level: %s\n",
+				slm_iac_str[cur_tsec->iac_wx]);
+	}
+	len = simple_read_from_buffer(buf, buflen, ppos, page, len);
+	free_page((unsigned long)page);
+	return len;
+}
+
+static int slm_open_debug(struct inode *inode, struct file *file)
+{
+	if (inode->u.generic_ip)
+		file->private_data = inode->u.generic_ip;
+	return 0;
+}
+
+static ssize_t slm_read_debug(struct file *file, char __user *buf,
+			 size_t buflen, loff_t *ppos)
+{
+	ssize_t len = 0;
+	char *page;
+
+	page = (char *)__get_free_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+
+	if (strcmp(file->private_data,"integrity") == 0)
+		len = sprintf(page, "slm_debug: integrity %s\n",
+			((slm_debug & SLM_INTEGRITY) == SLM_INTEGRITY)
+				? "ON" : "OFF");
+	else if (strcmp(file->private_data,"secrecy") == 0)
+		len = sprintf(page, "slm_debug: secrecy %s\n",
+			((slm_debug & SLM_SECRECY) == SLM_SECRECY)
+				? "ON" : "OFF");
+	else if (strcmp(file->private_data,"verbose") == 0)
+		len = sprintf(page, "evm_debug: verbose %s\n",
+			((slm_debug & SLM_VERBOSE) == SLM_VERBOSE)
+				? "ON" : "OFF");
+	len = simple_read_from_buffer(buf, buflen, ppos, page, len);
+	free_page((unsigned long)page);
+	return len;
+}
+
+static ssize_t slm_write_debug(struct file *file, const char __user *buf,
+			 size_t buflen, loff_t *ppos)
+{
+        char flag;
+
+        if (copy_from_user(&flag, buf, 1))
+                return -EFAULT;
+
+	if (strcmp(file->private_data,"integrity") == 0)
+		slm_debug = (flag == '0') ? slm_debug & ~SLM_INTEGRITY :
+			slm_debug | SLM_INTEGRITY;
+	else if (strcmp(file->private_data,"xattr") == 0)
+		slm_debug = (flag == '0') ? slm_debug & ~SLM_SECRECY :
+			slm_debug | SLM_SECRECY;
+	else if (strcmp(file->private_data,"crypto") == 0)
+		slm_debug = (flag == '0') ? slm_debug & ~SLM_VERBOSE :
+			slm_debug | SLM_VERBOSE;
+	return buflen;
+}
+
+static struct file_operations slm_level_ops = {
+	.read = slm_read_level,
+};
+
+static struct file_operations slm_debug_ops = {
+	.read = slm_read_debug,
+	.write = slm_write_debug,
+	.open = slm_open_debug,
+};
+
+void slm_init_secfs(void)
+{
+	if ((slim_dir = securityfs_create_dir("slim", NULL)) == NULL )
+		return;
+	slim_level = securityfs_create_file("level", S_IRUGO,
+			slim_dir, NULL, &slm_level_ops);
+
+	if ((slim_debug_dir = securityfs_create_dir("debug", slim_dir)) == NULL)
+		return;
+	slim_integrity = securityfs_create_file("integrity", S_IRUSR | S_IRGRP,
+			slim_debug_dir, "integrity", &slm_debug_ops);
+	slim_secrecy = securityfs_create_file("secrecy", S_IRUSR | S_IRGRP,
+			slim_debug_dir, "secrecy", &slm_debug_ops);
+	slim_verbose = securityfs_create_file("verbose", S_IRUSR | S_IRGRP,
+			slim_debug_dir, "verbose", &slm_debug_ops);
+	return;
+}
+
+
+void slm_cleanup_secfs(void)
+{
+	securityfs_remove(slim_integrity);
+	securityfs_remove(slim_secrecy);
+	securityfs_remove(slim_verbose);
+	securityfs_remove(slim_debug_dir);
+
+	securityfs_remove(slim_level);
+	securityfs_remove(slim_dir);
+}
+
diff -rupN linux-2.6.14.2.orig/security/Kconfig linux-2.6.14.2.tc/security/Kconfig
--- linux-2.6.14.2.orig/security/Kconfig	2005-11-11 13:23:40.000000000 -0500
+++ linux-2.6.14.2.tc/security/Kconfig	2005-11-11 14:00:44.000000000 -0500
@@ -129,5 +129,7 @@ config SECURITY_STACKER_NUMFIELDS
	  this number, and this number must always be at least 1.
	  That one will be the shared slot for all LSMs to share.

+source "security/evm/Kconfig"
+
 endmenu

diff -rupN linux-2.6.14.2.orig/security/Makefile linux-2.6.14.2.tc/security/Makefile
--- linux-2.6.14.2.orig/security/Makefile	2005-11-11 13:23:40.000000000 -0500
+++ linux-2.6.14.2.tc/security/Makefile	2005-11-11 14:00:44.000000000 -0500
@@ -4,6 +4,7 @@

 obj-$(CONFIG_KEYS)			+= keys/
 obj-$(CONFIG_SECURITY_STACKER)		+= stacker.o
+obj-$(CONFIG_SECURITY_EVM)		+= evm/
 subdir-$(CONFIG_SECURITY_SELINUX)	+= selinux

 # if we don't select a security model, use the default capabilities



This archive was generated by hypermail 2.1.3 : Tue Nov 15 2005 - 06:10:43 PST