diff --git a/grsecurity/Makefile b/grsecurity/Makefile
index 0bc0a5c..85beb79 100644
--- a/grsecurity/Makefile
+++ b/grsecurity/Makefile
@@ -15,7 +15,7 @@ obj-y = grsec_chdir.o grsec_chroot.o grsec_exec.o grsec_fifo.o grsec_fork.o \
 
 obj-$(CONFIG_GRKERNSEC) += grsec_init.o grsum.o gracl.o gracl_segv.o \
 	gracl_cap.o gracl_alloc.o gracl_shm.o grsec_mem.o gracl_fs.o \
-	gracl_learn.o grsec_log.o
+	gracl_learn.o grsec_log.o gracl_policy.o
 ifdef CONFIG_COMPAT
 obj-$(CONFIG_GRKERNSEC) += gracl_compat.o
 endif
diff --git a/grsecurity/gracl.c b/grsecurity/gracl.c
index c0793fd..10e5cff 100644
--- a/grsecurity/gracl.c
+++ b/grsecurity/gracl.c
@@ -39,48 +39,31 @@
 #include <asm/errno.h>
 #include <asm/mman.h>
 
-extern struct lglock vfsmount_lock;
+#define FOR_EACH_ROLE_START(role) \
+	role = running_polstate.role_list; \
+	while (role) {
+
+#define FOR_EACH_ROLE_END(role) \
+		role = role->prev; \
+	}
 
-static struct acl_role_db acl_role_set;
-static struct name_db name_set;
-static struct inodev_db inodev_set;
+extern struct lglock vfsmount_lock;
 
 /* for keeping track of userspace pointers used for subjects, so we
    can share references in the kernel as well
 */
 
-static struct path real_root;
+extern struct path gr_real_root;
 
-static struct acl_subj_map_db subj_map_set;
-
-static struct acl_role_label *default_role;
-
-static struct acl_role_label *role_list;
-
-static u16 acl_sp_role_value;
+static struct gr_policy_state running_polstate;
+struct gr_policy_state *polstate = &running_polstate;
+extern struct gr_alloc_state *current_alloc_state;
 
 extern char *gr_shared_page[4];
-static DEFINE_MUTEX(gr_dev_mutex);
 DEFINE_RWLOCK(gr_inode_lock);
 
-struct gr_arg *gr_usermode;
-
 static unsigned int gr_status __read_only = GR_STATUS_INIT;
 
-extern int chkpw(struct gr_arg *entry, unsigned char *salt, unsigned char *sum);
-extern void gr_clear_learn_entries(void);
-
-unsigned char *gr_system_salt;
-unsigned char *gr_system_sum;
-
-static struct sprole_pw **acl_special_roles = NULL;
-static __u16 num_sprole_pws = 0;
-
-static struct acl_role_label *kernel_role = NULL;
-
-static unsigned int gr_auth_attempts = 0;
-static unsigned long gr_auth_expires = 0UL;
-
 #ifdef CONFIG_NET
 extern struct vfsmount *sock_mnt;
 #endif
@@ -92,156 +75,29 @@ extern struct vfsmount *shm_mnt;
 extern struct vfsmount *hugetlbfs_vfsmount[HUGE_MAX_HSTATE];
 #endif
 
-static struct acl_object_label *fakefs_obj_rw;
-static struct acl_object_label *fakefs_obj_rwx;
-
-extern int gr_init_uidset(void);
-extern void gr_free_uidset(void);
-extern void gr_remove_uid(uid_t uid);
-extern int gr_find_uid(uid_t uid);
-
-static int copy_acl_object_label_normal(struct acl_object_label *obj, const struct acl_object_label *userp)
-{
-	if (copy_from_user(obj, userp, sizeof(struct acl_object_label)))
-		return -EFAULT;
-
-	return 0;
-}
-
-static int copy_acl_ip_label_normal(struct acl_ip_label *ip, const struct acl_ip_label *userp)
-{
-	if (copy_from_user(ip, userp, sizeof(struct acl_ip_label)))
-		return -EFAULT;
-
-	return 0;
-}
-
-static int copy_acl_subject_label_normal(struct acl_subject_label *subj, const struct acl_subject_label *userp)
-{
-	if (copy_from_user(subj, userp, sizeof(struct acl_subject_label)))
-		return -EFAULT;
-
-	return 0;
-}
-
-static int copy_acl_role_label_normal(struct acl_role_label *role, const struct acl_role_label *userp)
-{
-	if (copy_from_user(role, userp, sizeof(struct acl_role_label)))
-		return -EFAULT;
-
-	return 0;
-}
-
-static int copy_role_allowed_ip_normal(struct role_allowed_ip *roleip, const struct role_allowed_ip *userp)
-{
-	if (copy_from_user(roleip, userp, sizeof(struct role_allowed_ip)))
-		return -EFAULT;
-
-	return 0;
-}
-
-static int copy_sprole_pw_normal(struct sprole_pw *pw, unsigned long idx, const struct sprole_pw *userp)
-{
-	if (copy_from_user(pw, userp + idx, sizeof(struct sprole_pw)))
-		return -EFAULT;
-
-	return 0;
-}
-
-static int copy_gr_hash_struct_normal(struct gr_hash_struct *hash, const struct gr_hash_struct *userp)
-{
-	if (copy_from_user(hash, userp, sizeof(struct gr_hash_struct)))
-		return -EFAULT;
-
-	return 0;
-}
-
-static int copy_role_transition_normal(struct role_transition *trans, const struct role_transition *userp)
-{
-	if (copy_from_user(trans, userp, sizeof(struct role_transition)))
-		return -EFAULT;
-
-	return 0;
-}
-
-int copy_pointer_from_array_normal(void *ptr, unsigned long idx, const void *userp)
-{
-	if (copy_from_user(ptr, userp + (idx * sizeof(void *)), sizeof(void *)))
-		return -EFAULT;
+extern u16 acl_sp_role_value;
+extern struct acl_object_label *fakefs_obj_rw;
+extern struct acl_object_label *fakefs_obj_rwx;
 
-	return 0;
-}
-
-static int copy_gr_arg_wrapper_normal(const char __user *buf, struct gr_arg_wrapper *uwrap)
+int gr_acl_is_enabled(void)
 {
-	if (copy_from_user(uwrap, buf, sizeof (struct gr_arg_wrapper)))
-		return -EFAULT;
-
-	if ((uwrap->version != GRSECURITY_VERSION) || (uwrap->size != sizeof(struct gr_arg)))
-		return -EINVAL;
-
-	return 0;
+	return (gr_status & GR_READY);
 }
 
-static int copy_gr_arg_normal(const struct gr_arg __user *buf, struct gr_arg *arg)
+void gr_enable_rbac_system(void)
 {
-	if (copy_from_user(arg, buf, sizeof (struct gr_arg)))
-		return -EFAULT;
-
-	return 0;
+	pax_open_kernel();
+	gr_status |= GR_READY;
+	pax_close_kernel();
 }
 
-static size_t get_gr_arg_wrapper_size_normal(void)
+int gr_rbac_disable(void *unused)
 {
-	return sizeof(struct gr_arg_wrapper);
-}
-
-#ifdef CONFIG_COMPAT
-extern int copy_gr_arg_wrapper_compat(const char *buf, struct gr_arg_wrapper *uwrap);
-extern int copy_gr_arg_compat(const struct gr_arg __user *buf, struct gr_arg *arg);
-extern int copy_acl_object_label_compat(struct acl_object_label *obj, const struct acl_object_label *userp);
-extern int copy_acl_subject_label_compat(struct acl_subject_label *subj, const struct acl_subject_label *userp);
-extern int copy_acl_role_label_compat(struct acl_role_label *role, const struct acl_role_label *userp);
-extern int copy_role_allowed_ip_compat(struct role_allowed_ip *roleip, const struct role_allowed_ip *userp);
-extern int copy_role_transition_compat(struct role_transition *trans, const struct role_transition *userp);
-extern int copy_gr_hash_struct_compat(struct gr_hash_struct *hash, const struct gr_hash_struct *userp);
-extern int copy_pointer_from_array_compat(void *ptr, unsigned long idx, const void *userp);
-extern int copy_acl_ip_label_compat(struct acl_ip_label *ip, const struct acl_ip_label *userp);
-extern int copy_sprole_pw_compat(struct sprole_pw *pw, unsigned long idx, const struct sprole_pw *userp);
-extern size_t get_gr_arg_wrapper_size_compat(void);
-
-int (* copy_gr_arg_wrapper)(const char *buf, struct gr_arg_wrapper *uwrap) __read_only;
-int (* copy_gr_arg)(const struct gr_arg *buf, struct gr_arg *arg) __read_only;
-int (* copy_acl_object_label)(struct acl_object_label *obj, const struct acl_object_label *userp) __read_only;
-int (* copy_acl_subject_label)(struct acl_subject_label *subj, const struct acl_subject_label *userp) __read_only;
-int (* copy_acl_role_label)(struct acl_role_label *role, const struct acl_role_label *userp) __read_only;
-int (* copy_acl_ip_label)(struct acl_ip_label *ip, const struct acl_ip_label *userp) __read_only;
-int (* copy_pointer_from_array)(void *ptr, unsigned long idx, const void *userp) __read_only;
-int (* copy_sprole_pw)(struct sprole_pw *pw, unsigned long idx, const struct sprole_pw *userp) __read_only;
-int (* copy_gr_hash_struct)(struct gr_hash_struct *hash, const struct gr_hash_struct *userp) __read_only;
-int (* copy_role_transition)(struct role_transition *trans, const struct role_transition *userp) __read_only;
-int (* copy_role_allowed_ip)(struct role_allowed_ip *roleip, const struct role_allowed_ip *userp) __read_only;
-size_t (* get_gr_arg_wrapper_size)(void) __read_only;
-
-#else
-#define copy_gr_arg_wrapper copy_gr_arg_wrapper_normal
-#define copy_gr_arg copy_gr_arg_normal
-#define copy_gr_hash_struct copy_gr_hash_struct_normal
-#define copy_acl_object_label copy_acl_object_label_normal
-#define copy_acl_subject_label copy_acl_subject_label_normal
-#define copy_acl_role_label copy_acl_role_label_normal
-#define copy_acl_ip_label copy_acl_ip_label_normal
-#define copy_pointer_from_array copy_pointer_from_array_normal
-#define copy_sprole_pw copy_sprole_pw_normal
-#define copy_role_transition copy_role_transition_normal
-#define copy_role_allowed_ip copy_role_allowed_ip_normal
-#define get_gr_arg_wrapper_size get_gr_arg_wrapper_size_normal
-#endif
+        pax_open_kernel();
+        gr_status &= ~GR_READY;
+        pax_close_kernel();
 
-__inline__ int
-gr_acl_is_enabled(void)
-{
-	return (gr_status & GR_READY);
+        return 0;
 }
 
 static inline dev_t __get_dev(const struct dentry *dentry)
@@ -305,7 +161,7 @@ gr_handle_rawio(const struct inode *inode)
 	return 0;
 }
 
-static int
+int
 gr_streq(const char *a, const char *b, const unsigned int lena, const unsigned int lenb)
 {
 	if (likely(lena != lenb))
@@ -412,9 +268,9 @@ __d_real_path(const struct dentry *dentry, const struct vfsmount *vfsmnt,
 	path.dentry = (struct dentry *)dentry;
 	path.mnt = (struct vfsmount *)vfsmnt;
 
-	/* we can use real_root.dentry, real_root.mnt, because this is only called
+	/* we can use gr_real_root.dentry, gr_real_root.mnt, because this is only called
 	   by the RBAC system */
-	res = gen_full_path(&path, &real_root, buf, buflen);
+	res = gen_full_path(&path, &gr_real_root, buf, buflen);
 
 	return res;
 }
@@ -431,7 +287,7 @@ d_real_path(const struct dentry *dentry, const struct vfsmount *vfsmnt,
 	path.dentry = (struct dentry *)dentry;
 	path.mnt = (struct vfsmount *)vfsmnt;
 
-	/* we can't use real_root.dentry, real_root.mnt, because they belong only to the RBAC system */
+	/* we can't use gr_real_root.dentry, gr_real_root.mnt, because they belong only to the RBAC system */
 	get_fs_root(reaper->fs, &root);
 
 	br_read_lock(&vfsmount_lock);
@@ -444,7 +300,7 @@ d_real_path(const struct dentry *dentry, const struct vfsmount *vfsmnt,
 	return res;
 }
 
-static char *
+char *
 gr_to_filename_rbac(const struct dentry *dentry, const struct vfsmount *mnt)
 {
 	char *ret;
@@ -522,46 +378,11 @@ to_gr_audit(const __u32 reqmode)
 	return (((reqmode & ~GR_AUDITS) << 10) | ((reqmode & GR_WRITE) ? GR_AUDIT_APPEND : 0));
 }
 
-struct acl_subject_label *
-lookup_subject_map(const struct acl_subject_label *userp)
-{
-	unsigned int index = gr_shash(userp, subj_map_set.s_size);
-	struct subject_map *match;
-
-	match = subj_map_set.s_hash[index];
-
-	while (match && match->user != userp)
-		match = match->next;
-
-	if (match != NULL)
-		return match->kernel;
-	else
-		return NULL;
-}
-
-static void
-insert_subj_map_entry(struct subject_map *subjmap)
-{
-	unsigned int index = gr_shash(subjmap->user, subj_map_set.s_size);
-	struct subject_map **curr;
-
-	subjmap->prev = NULL;
-
-	curr = &subj_map_set.s_hash[index];
-	if (*curr != NULL)
-		(*curr)->prev = subjmap;
-
-	subjmap->next = *curr;
-	*curr = subjmap;
-
-	return;
-}
-
-static struct acl_role_label *
-lookup_acl_role_label(const struct task_struct *task, const uid_t uid,
+struct acl_role_label *
+__lookup_acl_role_label(const struct gr_policy_state *state, const struct task_struct *task, const uid_t uid,
 		      const gid_t gid)
 {
-	unsigned int index = gr_rhash(uid, GR_ROLE_USER, acl_role_set.r_size);
+	unsigned int index = gr_rhash(uid, GR_ROLE_USER, state->acl_role_set.r_size);
 	struct acl_role_label *match;
 	struct role_allowed_ip *ipp;
 	unsigned int x;
@@ -569,7 +390,7 @@ lookup_acl_role_label(const struct task_struct *task, const uid_t uid,
 
 	task->signal->saved_ip = curr_ip;
 
-	match = acl_role_set.r_hash[index];
+	match = state->acl_role_set.r_hash[index];
 
 	while (match) {
 		if ((match->roletype & (GR_ROLE_DOMAIN | GR_ROLE_USER)) == (GR_ROLE_DOMAIN | GR_ROLE_USER)) {
@@ -584,8 +405,8 @@ lookup_acl_role_label(const struct task_struct *task, const uid_t uid,
 found:
 	if (match == NULL) {
 	      try_group:
-		index = gr_rhash(gid, GR_ROLE_GROUP, acl_role_set.r_size);
-		match = acl_role_set.r_hash[index];
+		index = gr_rhash(gid, GR_ROLE_GROUP, state->acl_role_set.r_size);
+		match = state->acl_role_set.r_hash[index];
 
 		while (match) {
 			if ((match->roletype & (GR_ROLE_DOMAIN | GR_ROLE_GROUP)) == (GR_ROLE_DOMAIN | GR_ROLE_GROUP)) {
@@ -599,7 +420,7 @@ found:
 		}
 found2:
 		if (match == NULL)
-			match = default_role;
+			match = state->default_role;
 		if (match->allowed_ips == NULL)
 			return match;
 		else {
@@ -609,7 +430,7 @@ found2:
 				     (ntohl(ipp->addr) & ipp->netmask)))
 					return match;
 			}
-			match = default_role;
+			match = state->default_role;
 		}
 	} else if (match->allowed_ips == NULL) {
 		return match;
@@ -626,6 +447,13 @@ found2:
 	return match;
 }
 
+static struct acl_role_label *
+lookup_acl_role_label(const struct task_struct *task, const uid_t uid,
+		      const gid_t gid)
+{
+	return __lookup_acl_role_label(&running_polstate, task, uid, gid);
+}
+
 struct acl_subject_label *
 lookup_acl_subj_label(const ino_t ino, const dev_t dev,
 		      const struct acl_role_label *role)
@@ -716,15 +544,15 @@ lookup_acl_obj_label_create(const ino_t ino, const dev_t dev,
 		return NULL;
 }
 
-static struct name_entry *
-lookup_name_entry(const char *name)
+struct name_entry *
+__lookup_name_entry(const struct gr_policy_state *state, const char *name)
 {
 	unsigned int len = strlen(name);
 	unsigned int key = full_name_hash(name, len);
-	unsigned int index = key % name_set.n_size;
+	unsigned int index = key % state->name_set.n_size;
 	struct name_entry *match;
 
-	match = name_set.n_hash[index];
+	match = state->name_set.n_hash[index];
 
 	while (match && (match->key != key || !gr_streq(match->name, name, match->len, len)))
 		match = match->next;
@@ -733,14 +561,20 @@ lookup_name_entry(const char *name)
 }
 
 static struct name_entry *
+lookup_name_entry(const char *name)
+{
+	return __lookup_name_entry(&running_polstate, name);
+}
+
+static struct name_entry *
 lookup_name_entry_create(const char *name)
 {
 	unsigned int len = strlen(name);
 	unsigned int key = full_name_hash(name, len);
-	unsigned int index = key % name_set.n_size;
+	unsigned int index = key % running_polstate.name_set.n_size;
 	struct name_entry *match;
 
-	match = name_set.n_hash[index];
+	match = running_polstate.name_set.n_hash[index];
 
 	while (match && (match->key != key || !gr_streq(match->name, name, match->len, len) ||
 			 !match->deleted))
@@ -749,7 +583,7 @@ lookup_name_entry_create(const char *name)
 	if (match && match->deleted)
 		return match;
 
-	match = name_set.n_hash[index];
+	match = running_polstate.name_set.n_hash[index];
 
 	while (match && (match->key != key || !gr_streq(match->name, name, match->len, len) ||
 			 match->deleted))
@@ -764,10 +598,10 @@ lookup_name_entry_create(const char *name)
 static struct inodev_entry *
 lookup_inodev_entry(const ino_t ino, const dev_t dev)
 {
-	unsigned int index = gr_fhash(ino, dev, inodev_set.i_size);
+	unsigned int index = gr_fhash(ino, dev, running_polstate.inodev_set.i_size);
 	struct inodev_entry *match;
 
-	match = inodev_set.i_hash[index];
+	match = running_polstate.inodev_set.i_hash[index];
 
 	while (match && (match->nentry->inode != ino || match->nentry->device != dev))
 		match = match->next;
@@ -775,16 +609,16 @@ lookup_inodev_entry(const ino_t ino, const dev_t dev)
 	return match;
 }
 
-static void
-insert_inodev_entry(struct inodev_entry *entry)
+void
+__insert_inodev_entry(const struct gr_policy_state *state, struct inodev_entry *entry)
 {
 	unsigned int index = gr_fhash(entry->nentry->inode, entry->nentry->device,
-				    inodev_set.i_size);
+				    state->inodev_set.i_size);
 	struct inodev_entry **curr;
 
 	entry->prev = NULL;
 
-	curr = &inodev_set.i_hash[index];
+	curr = &state->inodev_set.i_hash[index];
 	if (*curr != NULL)
 		(*curr)->prev = entry;
 	
@@ -795,138 +629,12 @@ insert_inodev_entry(struct inodev_entry *entry)
 }
 
 static void
-__insert_acl_role_label(struct acl_role_label *role, uid_t uidgid)
-{
-	unsigned int index =
-	    gr_rhash(uidgid, role->roletype & (GR_ROLE_USER | GR_ROLE_GROUP), acl_role_set.r_size);
-	struct acl_role_label **curr;
-	struct acl_role_label *tmp, *tmp2;
-
-	curr = &acl_role_set.r_hash[index];
-
-	/* simple case, slot is empty, just set it to our role */
-	if (*curr == NULL) {
-		*curr = role;
-	} else {
-		/* example:
-		   1 -> 2 -> 3 (adding 2 -> 3 to here)
-		   2 -> 3
-		*/
-		/* first check to see if we can already be reached via this slot */
-		tmp = *curr;
-		while (tmp && tmp != role)
-			tmp = tmp->next;
-		if (tmp == role) {
-			/* we don't need to add ourselves to this slot's chain */
-			return;
-		}
-		/* we need to add ourselves to this chain, two cases */
-		if (role->next == NULL) {
-			/* simple case, append the current chain to our role */
-			role->next = *curr;
-			*curr = role;
-		} else {
-			/* 1 -> 2 -> 3 -> 4
-			   2 -> 3 -> 4
-			   3 -> 4 (adding 1 -> 2 -> 3 -> 4 to here)
-			*/			   
-			/* trickier case: walk our role's chain until we find
-			   the role for the start of the current slot's chain */
-			tmp = role;
-			tmp2 = *curr;
-			while (tmp->next && tmp->next != tmp2)
-				tmp = tmp->next;
-			if (tmp->next == tmp2) {
-				/* from example above, we found 3, so just
-				   replace this slot's chain with ours */
-				*curr = role;
-			} else {
-				/* we didn't find a subset of our role's chain
-				   in the current slot's chain, so append their
-				   chain to ours, and set us as the first role in
-				   the slot's chain
-
-				   we could fold this case with the case above,
-				   but making it explicit for clarity
-				*/
-				tmp->next = tmp2;
-				*curr = role;
-			}
-		}
-	}
-
-	return;
-}
-
-static void
-insert_acl_role_label(struct acl_role_label *role)
-{
-	int i;
-
-	if (role_list == NULL) {
-		role_list = role;
-		role->prev = NULL;
-	} else {
-		role->prev = role_list;
-		role_list = role;
-	}
-	
-	/* used for hash chains */
-	role->next = NULL;
-
-	if (role->roletype & GR_ROLE_DOMAIN) {
-		for (i = 0; i < role->domain_child_num; i++)
-			__insert_acl_role_label(role, role->domain_children[i]);
-	} else
-		__insert_acl_role_label(role, role->uidgid);
-}
-					
-static int
-insert_name_entry(char *name, const ino_t inode, const dev_t device, __u8 deleted)
+insert_inodev_entry(struct inodev_entry *entry)
 {
-	struct name_entry **curr, *nentry;
-	struct inodev_entry *ientry;
-	unsigned int len = strlen(name);
-	unsigned int key = full_name_hash(name, len);
-	unsigned int index = key % name_set.n_size;
-
-	curr = &name_set.n_hash[index];
-
-	while (*curr && ((*curr)->key != key || !gr_streq((*curr)->name, name, (*curr)->len, len)))
-		curr = &((*curr)->next);
-
-	if (*curr != NULL)
-		return 1;
-
-	nentry = acl_alloc(sizeof (struct name_entry));
-	if (nentry == NULL)
-		return 0;
-	ientry = acl_alloc(sizeof (struct inodev_entry));
-	if (ientry == NULL)
-		return 0;
-	ientry->nentry = nentry;
-
-	nentry->key = key;
-	nentry->name = name;
-	nentry->inode = inode;
-	nentry->device = device;
-	nentry->len = len;
-	nentry->deleted = deleted;
-
-	nentry->prev = NULL;
-	curr = &name_set.n_hash[index];
-	if (*curr != NULL)
-		(*curr)->prev = nentry;
-	nentry->next = *curr;
-	*curr = nentry;
-
-	/* insert us into the table searchable by inode/dev */
-	insert_inodev_entry(ientry);
-
-	return 1;
+	__insert_inodev_entry(&running_polstate, entry);
 }
 
-static void
+void
 insert_acl_obj_label(struct acl_object_label *obj,
 		     struct acl_subject_label *subj)
 {
@@ -934,7 +642,6 @@ insert_acl_obj_label(struct acl_object_label *obj,
 	    gr_fhash(obj->inode, obj->device, subj->obj_hash_size);
 	struct acl_object_label **curr;
 
-	
 	obj->prev = NULL;
 
 	curr = &subj->obj_hash[index];
@@ -947,7 +654,7 @@ insert_acl_obj_label(struct acl_object_label *obj,
 	return;
 }
 
-static void
+void
 insert_acl_subj_label(struct acl_subject_label *obj,
 		      struct acl_role_label *role)
 {
@@ -966,2670 +673,1420 @@ insert_acl_subj_label(struct acl_subject_label *obj,
 	return;
 }
 
-/* allocating chained hash tables, so optimal size is where lambda ~ 1 */
-
-static void *
-create_table(__u32 * len, int elementsize)
-{
-	unsigned int table_sizes[] = {
-		7, 13, 31, 61, 127, 251, 509, 1021, 2039, 4093, 8191, 16381,
-		32749, 65521, 131071, 262139, 524287, 1048573, 2097143,
-		4194301, 8388593, 16777213, 33554393, 67108859
-	};
-	void *newtable = NULL;
-	unsigned int pwr = 0;
-
-	while ((pwr < ((sizeof (table_sizes) / sizeof (table_sizes[0])) - 1)) &&
-	       table_sizes[pwr] <= *len)
-		pwr++;
-
-	if (table_sizes[pwr] <= *len || (table_sizes[pwr] > ULONG_MAX / elementsize))
-		return newtable;
-
-	if ((table_sizes[pwr] * elementsize) <= PAGE_SIZE)
-		newtable =
-		    kmalloc(table_sizes[pwr] * elementsize, GFP_KERNEL);
-	else
-		newtable = vmalloc(table_sizes[pwr] * elementsize);
-
-	*len = table_sizes[pwr];
-
-	return newtable;
-}
+/* derived from glibc fnmatch() 0: match, 1: no match*/
 
 static int
-init_variables(const struct gr_arg *arg)
+glob_match(const char *p, const char *n)
 {
-	struct task_struct *reaper = init_pid_ns.child_reaper;
-	unsigned int stacksize;
+	char c;
 
-	subj_map_set.s_size = arg->role_db.num_subjects;
-	acl_role_set.r_size = arg->role_db.num_roles + arg->role_db.num_domain_children;
-	name_set.n_size = arg->role_db.num_objects;
-	inodev_set.i_size = arg->role_db.num_objects;
+	while ((c = *p++) != '\0') {
+	switch (c) {
+		case '?':
+			if (*n == '\0')
+				return 1;
+			else if (*n == '/')
+				return 1;
+			break;
+		case '\\':
+			if (*n != c)
+				return 1;
+			break;
+		case '*':
+			for (c = *p++; c == '?' || c == '*'; c = *p++) {
+				if (*n == '/')
+					return 1;
+				else if (c == '?') {
+					if (*n == '\0')
+						return 1;
+					else
+						++n;
+				}
+			}
+			if (c == '\0') {
+				return 0;
+			} else {
+				const char *endp;
 
-	if (!subj_map_set.s_size || !acl_role_set.r_size ||
-	    !name_set.n_size || !inodev_set.i_size)
-		return 1;
+				if ((endp = strchr(n, '/')) == NULL)
+					endp = n + strlen(n);
 
-	if (!gr_init_uidset())
-		return 1;
+				if (c == '[') {
+					for (--p; n < endp; ++n)
+						if (!glob_match(p, n))
+							return 0;
+				} else if (c == '/') {
+					while (*n != '\0' && *n != '/')
+						++n;
+					if (*n == '/' && !glob_match(p, n + 1))
+						return 0;
+				} else {
+					for (--p; n < endp; ++n)
+						if (*n == c && !glob_match(p, n))
+							return 0;
+				}
 
-	/* set up the stack that holds allocation info */
+				return 1;
+			}
+		case '[':
+			{
+			int not;
+			char cold;
 
-	stacksize = arg->role_db.num_pointers + 5;
+			if (*n == '\0' || *n == '/')
+				return 1;
 
-	if (!acl_alloc_stack_init(stacksize))
-		return 1;
+			not = (*p == '!' || *p == '^');
+			if (not)
+				++p;
 
-	/* grab reference for the real root dentry and vfsmount */
-	get_fs_root(reaper->fs, &real_root);
-	
-#ifdef CONFIG_GRKERNSEC_RBAC_DEBUG
-	printk(KERN_ALERT "Obtained real root device=%d, inode=%lu\n", __get_dev(real_root.dentry), real_root.dentry->d_inode->i_ino);
-#endif
+			c = *p++;
+			for (;;) {
+				unsigned char fn = (unsigned char)*n;
 
-	fakefs_obj_rw = acl_alloc(sizeof(struct acl_object_label));
-	if (fakefs_obj_rw == NULL)
-		return 1;
-	fakefs_obj_rw->mode = GR_FIND | GR_READ | GR_WRITE;
+				if (c == '\0')
+					return 1;
+				else {
+					if (c == fn)
+						goto matched;
+					cold = c;
+					c = *p++;
 
-	fakefs_obj_rwx = acl_alloc(sizeof(struct acl_object_label));
-	if (fakefs_obj_rwx == NULL)
-		return 1;
-	fakefs_obj_rwx->mode = GR_FIND | GR_READ | GR_WRITE | GR_EXEC;
-
-	subj_map_set.s_hash =
-	    (struct subject_map **) create_table(&subj_map_set.s_size, sizeof(void *));
-	acl_role_set.r_hash =
-	    (struct acl_role_label **) create_table(&acl_role_set.r_size, sizeof(void *));
-	name_set.n_hash = (struct name_entry **) create_table(&name_set.n_size, sizeof(void *));
-	inodev_set.i_hash =
-	    (struct inodev_entry **) create_table(&inodev_set.i_size, sizeof(void *));
-
-	if (!subj_map_set.s_hash || !acl_role_set.r_hash ||
-	    !name_set.n_hash || !inodev_set.i_hash)
-		return 1;
+					if (c == '-' && *p != ']') {
+						unsigned char cend = *p++;
 
-	memset(subj_map_set.s_hash, 0,
-	       sizeof(struct subject_map *) * subj_map_set.s_size);
-	memset(acl_role_set.r_hash, 0,
-	       sizeof (struct acl_role_label *) * acl_role_set.r_size);
-	memset(name_set.n_hash, 0,
-	       sizeof (struct name_entry *) * name_set.n_size);
-	memset(inodev_set.i_hash, 0,
-	       sizeof (struct inodev_entry *) * inodev_set.i_size);
+						if (cend == '\0')
+							return 1;
 
-	return 0;
-}
+						if (cold <= fn && fn <= cend)
+							goto matched;
 
-/* free information not needed after startup
-   currently contains user->kernel pointer mappings for subjects
-*/
+						c = *p++;
+					}
+				}
 
-static void
-free_init_variables(void)
-{
-	__u32 i;
+				if (c == ']')
+					break;
+			}
+			if (!not)
+				return 1;
+			break;
+		matched:
+			while (c != ']') {
+				if (c == '\0')
+					return 1;
 
-	if (subj_map_set.s_hash) {
-		for (i = 0; i < subj_map_set.s_size; i++) {
-			if (subj_map_set.s_hash[i]) {
-				kfree(subj_map_set.s_hash[i]);
-				subj_map_set.s_hash[i] = NULL;
+				c = *p++;
 			}
+			if (not)
+				return 1;
 		}
-
-		if ((subj_map_set.s_size * sizeof (struct subject_map *)) <=
-		    PAGE_SIZE)
-			kfree(subj_map_set.s_hash);
-		else
-			vfree(subj_map_set.s_hash);
-	}
-
-	return;
-}
-
-static void
-free_variables(void)
-{
-	struct acl_subject_label *s;
-	struct acl_role_label *r;
-	struct task_struct *task, *task2;
-	unsigned int x;
-
-	gr_clear_learn_entries();
-
-	read_lock(&tasklist_lock);
-	do_each_thread(task2, task) {
-		task->acl_sp_role = 0;
-		task->acl_role_id = 0;
-		task->acl = NULL;
-		task->role = NULL;
-	} while_each_thread(task2, task);
-	read_unlock(&tasklist_lock);
-
-	/* release the reference to the real root dentry and vfsmount */
-	path_put(&real_root);
-	memset(&real_root, 0, sizeof(real_root));
-
-	/* free all object hash tables */
-
-	FOR_EACH_ROLE_START(r)
-		if (r->subj_hash == NULL)
-			goto next_role;
-		FOR_EACH_SUBJECT_START(r, s, x)
-			if (s->obj_hash == NULL)
-				break;
-			if ((s->obj_hash_size * sizeof (struct acl_object_label *)) <= PAGE_SIZE)
-				kfree(s->obj_hash);
-			else
-				vfree(s->obj_hash);
-		FOR_EACH_SUBJECT_END(s, x)
-		FOR_EACH_NESTED_SUBJECT_START(r, s)
-			if (s->obj_hash == NULL)
-				break;
-			if ((s->obj_hash_size * sizeof (struct acl_object_label *)) <= PAGE_SIZE)
-				kfree(s->obj_hash);
-			else
-				vfree(s->obj_hash);
-		FOR_EACH_NESTED_SUBJECT_END(s)
-		if ((r->subj_hash_size * sizeof (struct acl_subject_label *)) <= PAGE_SIZE)
-			kfree(r->subj_hash);
-		else
-			vfree(r->subj_hash);
-		r->subj_hash = NULL;
-next_role:
-	FOR_EACH_ROLE_END(r)
-
-	acl_free_all();
-
-	if (acl_role_set.r_hash) {
-		if ((acl_role_set.r_size * sizeof (struct acl_role_label *)) <=
-		    PAGE_SIZE)
-			kfree(acl_role_set.r_hash);
-		else
-			vfree(acl_role_set.r_hash);
-	}
-	if (name_set.n_hash) {
-		if ((name_set.n_size * sizeof (struct name_entry *)) <=
-		    PAGE_SIZE)
-			kfree(name_set.n_hash);
-		else
-			vfree(name_set.n_hash);
+		break;
+	default:
+		if (c != *n)
+			return 1;
 	}
 
-	if (inodev_set.i_hash) {
-		if ((inodev_set.i_size * sizeof (struct inodev_entry *)) <=
-		    PAGE_SIZE)
-			kfree(inodev_set.i_hash);
-		else
-			vfree(inodev_set.i_hash);
+	++n;
 	}
 
-	gr_free_uidset();
-
-	memset(&name_set, 0, sizeof (struct name_db));
-	memset(&inodev_set, 0, sizeof (struct inodev_db));
-	memset(&acl_role_set, 0, sizeof (struct acl_role_db));
-	memset(&subj_map_set, 0, sizeof (struct acl_subj_map_db));
-
-	default_role = NULL;
-	kernel_role = NULL;
-	role_list = NULL;
-
-	return;
-}
-
-static struct acl_subject_label *
-do_copy_user_subj(struct acl_subject_label *userp, struct acl_role_label *role, int *already_copied);
-
-static int alloc_and_copy_string(char **name, unsigned int maxlen)
-{
-	unsigned int len = strnlen_user(*name, maxlen);
-	char *tmp;
-
-	if (!len || len >= maxlen)
-		return -EINVAL;
-
-	if ((tmp = (char *) acl_alloc(len)) == NULL)
-		return -ENOMEM;
-
-	if (copy_from_user(tmp, *name, len))
-		return -EFAULT;
+	if (*n == '\0')
+		return 0;
 
-	tmp[len-1] = '\0';
-	*name = tmp;
+	if (*n == '/')
+		return 0;
 
-	return 0;
+	return 1;
 }
 
-static int
-copy_user_glob(struct acl_object_label *obj)
+static struct acl_object_label *
+chk_glob_label(struct acl_object_label *globbed,
+	const struct dentry *dentry, const struct vfsmount *mnt, char **path)
 {
-	struct acl_object_label *g_tmp, **guser;
-	int error;
-
-	if (obj->globbed == NULL)
-		return 0;
-
-	guser = &obj->globbed;
-	while (*guser) {
-		g_tmp = (struct acl_object_label *)
-			acl_alloc(sizeof (struct acl_object_label));
-		if (g_tmp == NULL)
-			return -ENOMEM;
+	struct acl_object_label *tmp;
 
-		if (copy_acl_object_label(g_tmp, *guser))
-			return -EFAULT;
+	if (*path == NULL)
+		*path = gr_to_filename_nolock(dentry, mnt);
 
-		error = alloc_and_copy_string(&g_tmp->filename, PATH_MAX);
-		if (error)
-			return error;
+	tmp = globbed;
 
-		*guser = g_tmp;
-		guser = &(g_tmp->next);
+	while (tmp) {
+		if (!glob_match(tmp->filename, *path))
+			return tmp;
+		tmp = tmp->next;
 	}
 
-	return 0;
+	return NULL;
 }
 
-static int
-copy_user_objs(struct acl_object_label *userp, struct acl_subject_label *subj,
-	       struct acl_role_label *role)
+static struct acl_object_label *
+__full_lookup(const struct dentry *orig_dentry, const struct vfsmount *orig_mnt,
+	    const ino_t curr_ino, const dev_t curr_dev,
+	    const struct acl_subject_label *subj, char **path, const int checkglob)
 {
-	struct acl_object_label *o_tmp;
-	int ret;
-
-	while (userp) {
-		if ((o_tmp = (struct acl_object_label *)
-		     acl_alloc(sizeof (struct acl_object_label))) == NULL)
-			return -ENOMEM;
-
-		if (copy_acl_object_label(o_tmp, userp))
-			return -EFAULT;
-
-		userp = o_tmp->prev;
-
-		ret = alloc_and_copy_string(&o_tmp->filename, PATH_MAX);
-		if (ret)
-			return ret;
-
-		insert_acl_obj_label(o_tmp, subj);
-		if (!insert_name_entry(o_tmp->filename, o_tmp->inode,
-				       o_tmp->device, (o_tmp->mode & GR_DELETED) ? 1 : 0))
-			return -ENOMEM;
-
-		ret = copy_user_glob(o_tmp);
-		if (ret)
-			return ret;
-
-		if (o_tmp->nested) {
-			int already_copied;
-
-			o_tmp->nested = do_copy_user_subj(o_tmp->nested, role, &already_copied);
-			if (IS_ERR(o_tmp->nested))
-				return PTR_ERR(o_tmp->nested);
+	struct acl_subject_label *tmpsubj;
+	struct acl_object_label *retval;
+	struct acl_object_label *retval2;
 
-			/* insert into nested subject list if we haven't copied this one yet
-			   to prevent duplicate entries */
-			if (!already_copied) {
-				o_tmp->nested->next = role->hash->first;
-				role->hash->first = o_tmp->nested;
+	tmpsubj = (struct acl_subject_label *) subj;
+	read_lock(&gr_inode_lock);
+	do {
+		retval = lookup_acl_obj_label(curr_ino, curr_dev, tmpsubj);
+		if (retval) {
+			if (checkglob && retval->globbed) {
+				retval2 = chk_glob_label(retval->globbed, orig_dentry, orig_mnt, path);
+				if (retval2)
+					retval = retval2;
 			}
+			break;
 		}
-	}
+	} while ((tmpsubj = tmpsubj->parent_subject));
+	read_unlock(&gr_inode_lock);
 
-	return 0;
+	return retval;
 }
 
-static __u32
-count_user_subjs(struct acl_subject_label *userp)
+static __inline__ struct acl_object_label *
+full_lookup(const struct dentry *orig_dentry, const struct vfsmount *orig_mnt,
+	    struct dentry *curr_dentry,
+	    const struct acl_subject_label *subj, char **path, const int checkglob)
 {
-	struct acl_subject_label s_tmp;
-	__u32 num = 0;
+	int newglob = checkglob;
+	ino_t inode;
+	dev_t device;
 
-	while (userp) {
-		if (copy_acl_subject_label(&s_tmp, userp))
-			break;
+	/* if we aren't checking a subdirectory of the original path yet, don't do glob checking
+	   as we don't want a / * rule to match instead of the / object
+	   don't do this for create lookups that call this function though, since they're looking up
+	   on the parent and thus need globbing checks on all paths
+	*/
+	if (orig_dentry == curr_dentry && newglob != GR_CREATE_GLOB)
+		newglob = GR_NO_GLOB;
 
-		userp = s_tmp.prev;
-	}
+	spin_lock(&curr_dentry->d_lock);
+	inode = curr_dentry->d_inode->i_ino;
+	device = __get_dev(curr_dentry);
+	spin_unlock(&curr_dentry->d_lock);
 
-	return num;
+	return __full_lookup(orig_dentry, orig_mnt, inode, device, subj, path, newglob);
 }
 
-static int
-copy_user_allowedips(struct acl_role_label *rolep)
+#ifdef CONFIG_HUGETLBFS
+static inline bool
+is_hugetlbfs_mnt(const struct vfsmount *mnt)
 {
-	struct role_allowed_ip *ruserip, *rtmp = NULL, *rlast;
-
-	ruserip = rolep->allowed_ips;
-
-	while (ruserip) {
-		rlast = rtmp;
-
-		if ((rtmp = (struct role_allowed_ip *)
-		     acl_alloc(sizeof (struct role_allowed_ip))) == NULL)
-			return -ENOMEM;
-
-		if (copy_role_allowed_ip(rtmp, ruserip))
-			return -EFAULT;
-
-		ruserip = rtmp->prev;
-
-		if (!rlast) {
-			rtmp->prev = NULL;
-			rolep->allowed_ips = rtmp;
-		} else {
-			rlast->next = rtmp;
-			rtmp->prev = rlast;
-		}
-
-		if (!ruserip)
-			rtmp->next = NULL;
+	int i;
+	for (i = 0; i < HUGE_MAX_HSTATE; i++) {
+		if (unlikely(hugetlbfs_vfsmount[i] == mnt))
+			return true;
 	}
 
-	return 0;
+	return false;
 }
+#endif
 
-static int
-copy_user_transitions(struct acl_role_label *rolep)
+static struct acl_object_label *
+__chk_obj_label(const struct dentry *l_dentry, const struct vfsmount *l_mnt,
+	      const struct acl_subject_label *subj, char *path, const int checkglob)
 {
-	struct role_transition *rusertp, *rtmp = NULL, *rlast;
-	int error;
-
-	rusertp = rolep->transitions;
+	struct dentry *dentry = (struct dentry *) l_dentry;
+	struct vfsmount *mnt = (struct vfsmount *) l_mnt;
+	struct mount *real_mnt = real_mount(mnt);
+	struct acl_object_label *retval;
+	struct dentry *parent;
 
-	while (rusertp) {
-		rlast = rtmp;
+	br_read_lock(&vfsmount_lock);
+	write_seqlock(&rename_lock);
 
-		if ((rtmp = (struct role_transition *)
-		     acl_alloc(sizeof (struct role_transition))) == NULL)
-			return -ENOMEM;
+	if (unlikely((mnt == shm_mnt && dentry->d_inode->i_nlink == 0) || mnt == pipe_mnt ||
+#ifdef CONFIG_NET
+	    mnt == sock_mnt ||
+#endif
+#ifdef CONFIG_HUGETLBFS
+	    (is_hugetlbfs_mnt(mnt) && dentry->d_inode->i_nlink == 0) ||
+#endif
+		/* ignore Eric Biederman */
+	    IS_PRIVATE(l_dentry->d_inode))) {
+		retval = (subj->mode & GR_SHMEXEC) ? fakefs_obj_rwx : fakefs_obj_rw;
+		goto out;
+	}
 
-		if (copy_role_transition(rtmp, rusertp))
-			return -EFAULT;
+	for (;;) {
+		if (dentry == gr_real_root.dentry && mnt == gr_real_root.mnt)
+			break;
 
-		rusertp = rtmp->prev;
+		if (dentry == mnt->mnt_root || IS_ROOT(dentry)) {
+			if (!mnt_has_parent(real_mnt))
+				break;
 
-		error = alloc_and_copy_string(&rtmp->rolename, GR_SPROLE_LEN);
-		if (error)
-			return error;
+			retval = full_lookup(l_dentry, l_mnt, dentry, subj, &path, checkglob);
+			if (retval != NULL)
+				goto out;
 
-		if (!rlast) {
-			rtmp->prev = NULL;
-			rolep->transitions = rtmp;
-		} else {
-			rlast->next = rtmp;
-			rtmp->prev = rlast;
+			dentry = real_mnt->mnt_mountpoint;
+			real_mnt = real_mnt->mnt_parent;
+			mnt = &real_mnt->mnt;
+			continue;
 		}
 
-		if (!rusertp)
-			rtmp->next = NULL;
-	}
+		parent = dentry->d_parent;
+		retval = full_lookup(l_dentry, l_mnt, dentry, subj, &path, checkglob);
+		if (retval != NULL)
+			goto out;
 
-	return 0;
-}
+		dentry = parent;
+	}
 
-static __u32 count_user_objs(const struct acl_object_label __user *userp)
-{
-	struct acl_object_label o_tmp;
-	__u32 num = 0;
+	retval = full_lookup(l_dentry, l_mnt, dentry, subj, &path, checkglob);
 
-	while (userp) {
-		if (copy_acl_object_label(&o_tmp, userp))
-			break;
+	/* gr_real_root is pinned so we don't have to hold a reference */
+	if (retval == NULL)
+		retval = full_lookup(l_dentry, l_mnt, gr_real_root.dentry, subj, &path, checkglob);
+out:
+	write_sequnlock(&rename_lock);
+	br_read_unlock(&vfsmount_lock);
 
-		userp = o_tmp.prev;
-		num++;
-	}
+	BUG_ON(retval == NULL);
 
-	return num;
+	return retval;
 }
 
-static struct acl_subject_label *
-do_copy_user_subj(struct acl_subject_label *userp, struct acl_role_label *role, int *already_copied)
+static __inline__ struct acl_object_label *
+chk_obj_label(const struct dentry *l_dentry, const struct vfsmount *l_mnt,
+	      const struct acl_subject_label *subj)
 {
-	struct acl_subject_label *s_tmp = NULL, *s_tmp2;
-	__u32 num_objs;
-	struct acl_ip_label **i_tmp, *i_utmp2;
-	struct gr_hash_struct ghash;
-	struct subject_map *subjmap;
-	unsigned int i_num;
-	int err;
+	char *path = NULL;
+	return __chk_obj_label(l_dentry, l_mnt, subj, path, GR_REG_GLOB);
+}
 
-	if (already_copied != NULL)
-		*already_copied = 0;
+static __inline__ struct acl_object_label *
+chk_obj_label_noglob(const struct dentry *l_dentry, const struct vfsmount *l_mnt,
+	      const struct acl_subject_label *subj)
+{
+	char *path = NULL;
+	return __chk_obj_label(l_dentry, l_mnt, subj, path, GR_NO_GLOB);
+}
 
-	s_tmp = lookup_subject_map(userp);
+static __inline__ struct acl_object_label *
+chk_obj_create_label(const struct dentry *l_dentry, const struct vfsmount *l_mnt,
+		     const struct acl_subject_label *subj, char *path)
+{
+	return __chk_obj_label(l_dentry, l_mnt, subj, path, GR_CREATE_GLOB);
+}
 
-	/* we've already copied this subject into the kernel, just return
-	   the reference to it, and don't copy it over again
-	*/
-	if (s_tmp) {
-		if (already_copied != NULL)
-			*already_copied = 1;
-		return(s_tmp);
-	}
+struct acl_subject_label *
+chk_subj_label(const struct dentry *l_dentry, const struct vfsmount *l_mnt,
+	       const struct acl_role_label *role)
+{
+	struct dentry *dentry = (struct dentry *) l_dentry;
+	struct vfsmount *mnt = (struct vfsmount *) l_mnt;
+	struct mount *real_mnt = real_mount(mnt);
+	struct acl_subject_label *retval;
+	struct dentry *parent;
 
-	if ((s_tmp = (struct acl_subject_label *)
-	    acl_alloc(sizeof (struct acl_subject_label))) == NULL)
-		return ERR_PTR(-ENOMEM);
+	br_read_lock(&vfsmount_lock);
+	write_seqlock(&rename_lock);
 
-	subjmap = (struct subject_map *)kmalloc(sizeof (struct subject_map), GFP_KERNEL);
-	if (subjmap == NULL)
-		return ERR_PTR(-ENOMEM);
+	for (;;) {
+		if (dentry == gr_real_root.dentry && mnt == gr_real_root.mnt)
+			break;
+		if (dentry == mnt->mnt_root || IS_ROOT(dentry)) {
+			if (!mnt_has_parent(real_mnt))
+				break;
 
-	subjmap->user = userp;
-	subjmap->kernel = s_tmp;
-	insert_subj_map_entry(subjmap);
-
-	if (copy_acl_subject_label(s_tmp, userp))
-		return ERR_PTR(-EFAULT);
-
-	err = alloc_and_copy_string(&s_tmp->filename, PATH_MAX);
-	if (err)
-		return ERR_PTR(err);
-
-	if (!strcmp(s_tmp->filename, "/"))
-		role->root_label = s_tmp;
-
-	if (copy_gr_hash_struct(&ghash, s_tmp->hash))
-		return ERR_PTR(-EFAULT);
+			spin_lock(&dentry->d_lock);
+			read_lock(&gr_inode_lock);
+			retval =
+				lookup_acl_subj_label(dentry->d_inode->i_ino,
+						__get_dev(dentry), role);
+			read_unlock(&gr_inode_lock);
+			spin_unlock(&dentry->d_lock);
+			if (retval != NULL)
+				goto out;
 
-	/* copy user and group transition tables */
+			dentry = real_mnt->mnt_mountpoint;
+			real_mnt = real_mnt->mnt_parent;
+			mnt = &real_mnt->mnt;
+			continue;
+		}
 
-	if (s_tmp->user_trans_num) {
-		uid_t *uidlist;
+		spin_lock(&dentry->d_lock);
+		read_lock(&gr_inode_lock);
+		retval = lookup_acl_subj_label(dentry->d_inode->i_ino,
+					  __get_dev(dentry), role);
+		read_unlock(&gr_inode_lock);
+		parent = dentry->d_parent;
+		spin_unlock(&dentry->d_lock);
 
-		uidlist = (uid_t *)acl_alloc_num(s_tmp->user_trans_num, sizeof(uid_t));
-		if (uidlist == NULL)
-			return ERR_PTR(-ENOMEM);
-		if (copy_from_user(uidlist, s_tmp->user_transitions, s_tmp->user_trans_num * sizeof(uid_t)))
-			return ERR_PTR(-EFAULT);
+		if (retval != NULL)
+			goto out;
 
-		s_tmp->user_transitions = uidlist;
+		dentry = parent;
 	}
 
-	if (s_tmp->group_trans_num) {
-		gid_t *gidlist;
-
-		gidlist = (gid_t *)acl_alloc_num(s_tmp->group_trans_num, sizeof(gid_t));
-		if (gidlist == NULL)
-			return ERR_PTR(-ENOMEM);
-		if (copy_from_user(gidlist, s_tmp->group_transitions, s_tmp->group_trans_num * sizeof(gid_t)))
-			return ERR_PTR(-EFAULT);
+	spin_lock(&dentry->d_lock);
+	read_lock(&gr_inode_lock);
+	retval = lookup_acl_subj_label(dentry->d_inode->i_ino,
+				  __get_dev(dentry), role);
+	read_unlock(&gr_inode_lock);
+	spin_unlock(&dentry->d_lock);
 
-		s_tmp->group_transitions = gidlist;
+	if (unlikely(retval == NULL)) {
+		/* gr_real_root is pinned, we don't need to hold a reference */
+		read_lock(&gr_inode_lock);
+		retval = lookup_acl_subj_label(gr_real_root.dentry->d_inode->i_ino,
+					  __get_dev(gr_real_root.dentry), role);
+		read_unlock(&gr_inode_lock);
 	}
+out:
+	write_sequnlock(&rename_lock);
+	br_read_unlock(&vfsmount_lock);
 
-	/* set up object hash table */
-	num_objs = count_user_objs(ghash.first);
-
-	s_tmp->obj_hash_size = num_objs;
-	s_tmp->obj_hash =
-	    (struct acl_object_label **)
-	    create_table(&(s_tmp->obj_hash_size), sizeof(void *));
-
-	if (!s_tmp->obj_hash)
-		return ERR_PTR(-ENOMEM);
-
-	memset(s_tmp->obj_hash, 0,
-	       s_tmp->obj_hash_size *
-	       sizeof (struct acl_object_label *));
+	BUG_ON(retval == NULL);
 
-	/* add in objects */
-	err = copy_user_objs(ghash.first, s_tmp, role);
+	return retval;
+}
 
-	if (err)
-		return ERR_PTR(err);
+void
+assign_special_role(const char *rolename)
+{
+	struct acl_object_label *obj;
+	struct acl_role_label *r;
+	struct acl_role_label *assigned = NULL;
+	struct task_struct *tsk;
+	struct file *filp;
 
-	/* set pointer for parent subject */
-	if (s_tmp->parent_subject) {
-		s_tmp2 = do_copy_user_subj(s_tmp->parent_subject, role, NULL);
+	FOR_EACH_ROLE_START(r)
+		if (!strcmp(rolename, r->rolename) &&
+		    (r->roletype & GR_ROLE_SPECIAL)) {
+			assigned = r;
+			break;
+		}
+	FOR_EACH_ROLE_END(r)
 
-		if (IS_ERR(s_tmp2))
-			return s_tmp2;
+	if (!assigned)
+		return;
 
-		s_tmp->parent_subject = s_tmp2;
-	}
+	read_lock(&tasklist_lock);
+	read_lock(&grsec_exec_file_lock);
 
-	/* add in ip acls */
+	tsk = current->real_parent;
+	if (tsk == NULL)
+		goto out_unlock;
 
-	if (!s_tmp->ip_num) {
-		s_tmp->ips = NULL;
-		goto insert;
-	}
+	filp = tsk->exec_file;
+	if (filp == NULL)
+		goto out_unlock;
 
-	i_tmp =
-	    (struct acl_ip_label **) acl_alloc_num(s_tmp->ip_num,
-					       sizeof (struct acl_ip_label *));
+	tsk->is_writable = 0;
+	tsk->inherited = 0;
 
-	if (!i_tmp)
-		return ERR_PTR(-ENOMEM);
+	tsk->acl_sp_role = 1;
+	tsk->acl_role_id = ++acl_sp_role_value;
+	tsk->role = assigned;
+	tsk->acl = chk_subj_label(filp->f_path.dentry, filp->f_path.mnt, tsk->role);
 
-	for (i_num = 0; i_num < s_tmp->ip_num; i_num++) {
-		*(i_tmp + i_num) =
-		    (struct acl_ip_label *)
-		    acl_alloc(sizeof (struct acl_ip_label));
-		if (!*(i_tmp + i_num))
-			return ERR_PTR(-ENOMEM);
+	/* ignore additional mmap checks for processes that are writable
+	   by the default ACL */
+	obj = chk_obj_label(filp->f_path.dentry, filp->f_path.mnt, running_polstate.default_role->root_label);
+	if (unlikely(obj->mode & GR_WRITE))
+		tsk->is_writable = 1;
+	obj = chk_obj_label(filp->f_path.dentry, filp->f_path.mnt, tsk->role->root_label);
+	if (unlikely(obj->mode & GR_WRITE))
+		tsk->is_writable = 1;
 
-		if (copy_pointer_from_array(&i_utmp2, i_num, s_tmp->ips))
-			return ERR_PTR(-EFAULT);
+#ifdef CONFIG_GRKERNSEC_RBAC_DEBUG
+	printk(KERN_ALERT "Assigning special role:%s subject:%s to process (%s:%d)\n", tsk->role->rolename,
+			tsk->acl->filename, tsk->comm, task_pid_nr(tsk));
+#endif
 
-		if (copy_acl_ip_label(*(i_tmp + i_num), i_utmp2))
-			return ERR_PTR(-EFAULT);
-		
-		if ((*(i_tmp + i_num))->iface == NULL)
-			continue;
+out_unlock:
+	read_unlock(&grsec_exec_file_lock);
+	read_unlock(&tasklist_lock);
+	return;
+}
 
-		err = alloc_and_copy_string(&(*(i_tmp + i_num))->iface, IFNAMSIZ);
-		if (err)
-			return ERR_PTR(err);
-	}
 
-	s_tmp->ips = i_tmp;
+static void
+gr_log_learn(const struct dentry *dentry, const struct vfsmount *mnt, const __u32 mode)
+{
+	struct task_struct *task = current;
+	const struct cred *cred = current_cred();
 
-insert:
-	if (!insert_name_entry(s_tmp->filename, s_tmp->inode,
-			       s_tmp->device, (s_tmp->mode & GR_DELETED) ? 1 : 0))
-		return ERR_PTR(-ENOMEM);
+	security_learn(GR_LEARN_AUDIT_MSG, task->role->rolename, task->role->roletype,
+		       GR_GLOBAL_UID(cred->uid), GR_GLOBAL_GID(cred->gid), task->exec_file ? gr_to_filename1(task->exec_file->f_path.dentry,
+		       task->exec_file->f_path.mnt) : task->acl->filename, task->acl->filename,
+		       1UL, 1UL, gr_to_filename(dentry, mnt), (unsigned long) mode, &task->signal->saved_ip);
 
-	return s_tmp;
+	return;
 }
 
-static int
-copy_user_subjs(struct acl_subject_label *userp, struct acl_role_label *role)
+static void
+gr_log_learn_uid_change(const kuid_t real, const kuid_t effective, const kuid_t fs)
 {
-	struct acl_subject_label s_pre;
-	struct acl_subject_label * ret;
-	int err;
+	struct task_struct *task = current;
+	const struct cred *cred = current_cred();
 
-	while (userp) {
-		if (copy_acl_subject_label(&s_pre, userp))
-			return -EFAULT;
-		
-		ret = do_copy_user_subj(userp, role, NULL);
+	security_learn(GR_ID_LEARN_MSG, task->role->rolename, task->role->roletype,
+		       GR_GLOBAL_UID(cred->uid), GR_GLOBAL_GID(cred->gid), task->exec_file ? gr_to_filename1(task->exec_file->f_path.dentry,
+		       task->exec_file->f_path.mnt) : task->acl->filename, task->acl->filename,
+		       'u', GR_GLOBAL_UID(real), GR_GLOBAL_UID(effective), GR_GLOBAL_UID(fs), &task->signal->saved_ip);
 
-		err = PTR_ERR(ret);
-		if (IS_ERR(ret))
-			return err;
+	return;
+}
 
-		insert_acl_subj_label(ret, role);
+static void
+gr_log_learn_gid_change(const kgid_t real, const kgid_t effective, const kgid_t fs)
+{
+	struct task_struct *task = current;
+	const struct cred *cred = current_cred();
 
-		userp = s_pre.prev;
-	}
+	security_learn(GR_ID_LEARN_MSG, task->role->rolename, task->role->roletype,
+		       GR_GLOBAL_UID(cred->uid), GR_GLOBAL_GID(cred->gid), task->exec_file ? gr_to_filename1(task->exec_file->f_path.dentry,
+		       task->exec_file->f_path.mnt) : task->acl->filename, task->acl->filename,
+		       'g', GR_GLOBAL_GID(real), GR_GLOBAL_GID(effective), GR_GLOBAL_GID(fs), &task->signal->saved_ip);
 
-	return 0;
+	return;
 }
 
-static int
-copy_user_acl(struct gr_arg *arg)
+static void
+gr_set_proc_res(struct task_struct *task)
 {
-	struct acl_role_label *r_tmp = NULL, **r_utmp, *r_utmp2;
-	struct acl_subject_label *subj_list;
-	struct sprole_pw *sptmp;
-	struct gr_hash_struct *ghash;
-	uid_t *domainlist;
-	unsigned int r_num;
-	int err = 0;
-	__u16 i;
-	__u32 num_subjs;
-
-	/* we need a default and kernel role */
-	if (arg->role_db.num_roles < 2)
-		return -EINVAL;
-
-	/* copy special role authentication info from userspace */
-
-	num_sprole_pws = arg->num_sprole_pws;
-	acl_special_roles = (struct sprole_pw **) acl_alloc_num(num_sprole_pws, sizeof(struct sprole_pw *));
-
-	if (!acl_special_roles && num_sprole_pws)
-		return -ENOMEM;
-
-	for (i = 0; i < num_sprole_pws; i++) {
-		sptmp = (struct sprole_pw *) acl_alloc(sizeof(struct sprole_pw));
-		if (!sptmp)
-			return -ENOMEM;
-		if (copy_sprole_pw(sptmp, i, arg->sprole_pws))
-			return -EFAULT;
-
-		err = alloc_and_copy_string((char **)&sptmp->rolename, GR_SPROLE_LEN);
-		if (err)
-			return err;
+	struct acl_subject_label *proc;
+	unsigned short i;
 
-#ifdef CONFIG_GRKERNSEC_RBAC_DEBUG
-		printk(KERN_ALERT "Copying special role %s\n", sptmp->rolename);
-#endif
+	proc = task->acl;
 
-		acl_special_roles[i] = sptmp;
-	}
+	if (proc->mode & (GR_LEARN | GR_INHERITLEARN))
+		return;
 
-	r_utmp = (struct acl_role_label **) arg->role_db.r_table;
+	for (i = 0; i < RLIM_NLIMITS; i++) {
+		if (!(proc->resmask & (1U << i)))
+			continue;
 
-	for (r_num = 0; r_num < arg->role_db.num_roles; r_num++) {
-		r_tmp = acl_alloc(sizeof (struct acl_role_label));
+		task->signal->rlim[i].rlim_cur = proc->res[i].rlim_cur;
+		task->signal->rlim[i].rlim_max = proc->res[i].rlim_max;
 
-		if (!r_tmp)
-			return -ENOMEM;
+		if (i == RLIMIT_CPU)
+			update_rlimit_cpu(task, proc->res[i].rlim_cur);
+	}
 
-		if (copy_pointer_from_array(&r_utmp2, r_num, r_utmp))
-			return -EFAULT;
+	return;
+}
 
-		if (copy_acl_role_label(r_tmp, r_utmp2))
-			return -EFAULT;
+/* both of the below must be called with
+	rcu_read_lock();
+	read_lock(&tasklist_lock);
+	read_lock(&grsec_exec_file_lock);
+*/
 
-		err = alloc_and_copy_string(&r_tmp->rolename, GR_SPROLE_LEN);
-		if (err)
-			return err;
+void __gr_apply_subject_to_task(const struct gr_policy_state *state, struct task_struct *task, struct acl_subject_label *subj)
+{
+	struct acl_object_label *obj;
+	struct file *filp;
 
-		if (!strcmp(r_tmp->rolename, "default")
-		    && (r_tmp->roletype & GR_ROLE_DEFAULT)) {
-			default_role = r_tmp;
-		} else if (!strcmp(r_tmp->rolename, ":::kernel:::")) {
-			kernel_role = r_tmp;
-		}
+	filp = task->exec_file;
 
-		if ((ghash = (struct gr_hash_struct *) acl_alloc(sizeof(struct gr_hash_struct))) == NULL)
-			return -ENOMEM;
+	task->acl = subj;
+	task->is_writable = 0;
+	/* ignore additional mmap checks for processes that are writable 
+	   by the default ACL */
+	obj = chk_obj_label(filp->f_path.dentry, filp->f_path.mnt, state->default_role->root_label);
+	if (unlikely(obj->mode & GR_WRITE))
+		task->is_writable = 1;
+	obj = chk_obj_label(filp->f_path.dentry, filp->f_path.mnt, task->role->root_label);
+	if (unlikely(obj->mode & GR_WRITE))
+		task->is_writable = 1;
 
-		if (copy_gr_hash_struct(ghash, r_tmp->hash))
-			return -EFAULT;
+	gr_set_proc_res(task);
 
-		r_tmp->hash = ghash;
+#ifdef CONFIG_GRKERNSEC_RBAC_DEBUG
+	printk(KERN_ALERT "gr_set_acls for (%s:%d): role:%s, subject:%s\n", task->comm, task_pid_nr(task), task->role->rolename, task->acl->filename);
+#endif
+}
 
-		num_subjs = count_user_subjs(r_tmp->hash->first);
+static void gr_apply_subject_to_task(struct task_struct *task, struct acl_subject_label *subj)
+{
+	__gr_apply_subject_to_task(&running_polstate, task, subj);
+}
 
-		r_tmp->subj_hash_size = num_subjs;
-		r_tmp->subj_hash =
-		    (struct acl_subject_label **)
-		    create_table(&(r_tmp->subj_hash_size), sizeof(void *));
+__u32
+gr_search_file(const struct dentry * dentry, const __u32 mode,
+	       const struct vfsmount * mnt)
+{
+	__u32 retval = mode;
+	struct acl_subject_label *curracl;
+	struct acl_object_label *currobj;
 
-		if (!r_tmp->subj_hash)
-			return -ENOMEM;
+	if (unlikely(!(gr_status & GR_READY)))
+		return (mode & ~GR_AUDITS);
 
-		err = copy_user_allowedips(r_tmp);
-		if (err)
-			return err;
+	curracl = current->acl;
 
-		/* copy domain info */
-		if (r_tmp->domain_children != NULL) {
-			domainlist = acl_alloc_num(r_tmp->domain_child_num, sizeof(uid_t));
-			if (domainlist == NULL)
-				return -ENOMEM;
+	currobj = chk_obj_label(dentry, mnt, curracl);
+	retval = currobj->mode & mode;
 
-			if (copy_from_user(domainlist, r_tmp->domain_children, r_tmp->domain_child_num * sizeof(uid_t)))
-				return -EFAULT;
+	/* if we're opening a specified transfer file for writing
+	   (e.g. /dev/initctl), then transfer our role to init
+	*/
+	if (unlikely(currobj->mode & GR_INIT_TRANSFER && retval & GR_WRITE &&
+		     current->role->roletype & GR_ROLE_PERSIST)) {
+		struct task_struct *task = init_pid_ns.child_reaper;
 
-			r_tmp->domain_children = domainlist;
+		if (task->role != current->role) {
+			task->acl_sp_role = 0;
+			task->acl_role_id = current->acl_role_id;
+			task->role = current->role;
+			rcu_read_lock();
+			read_lock(&grsec_exec_file_lock);
+			gr_apply_subject_to_task(task, NULL);
+			read_unlock(&grsec_exec_file_lock);
+			rcu_read_unlock();
+			gr_log_noargs(GR_DONT_AUDIT_GOOD, GR_INIT_TRANSFER_MSG);
 		}
+	}
 
-		err = copy_user_transitions(r_tmp);
-		if (err)
-			return err;
-
-		memset(r_tmp->subj_hash, 0,
-		       r_tmp->subj_hash_size *
-		       sizeof (struct acl_subject_label *));
-
-		/* acquire the list of subjects, then NULL out
-		   the list prior to parsing the subjects for this role,
-		   as during this parsing the list is replaced with a list
-		   of *nested* subjects for the role
-		*/
-		subj_list = r_tmp->hash->first;
+	if (unlikely
+	    ((curracl->mode & (GR_LEARN | GR_INHERITLEARN)) && !(mode & GR_NOPTRACE)
+	     && (retval != (mode & ~(GR_AUDITS | GR_SUPPRESS))))) {
+		__u32 new_mode = mode;
 
-		/* set nested subject list to null */
-		r_tmp->hash->first = NULL;
+		new_mode &= ~(GR_AUDITS | GR_SUPPRESS);
 
-		err = copy_user_subjs(subj_list, r_tmp);
+		retval = new_mode;
 
-		if (err)
-			return err;
+		if (new_mode & GR_EXEC && curracl->mode & GR_INHERITLEARN)
+			new_mode |= GR_INHERIT;
 
-		insert_acl_role_label(r_tmp);
+		if (!(mode & GR_NOLEARN))
+			gr_log_learn(dentry, mnt, new_mode);
 	}
 
-	if (default_role == NULL || kernel_role == NULL)
-		return -EINVAL;
-
-	return err;
+	return retval;
 }
 
-static int
-gracl_init(struct gr_arg *args)
+struct acl_object_label *gr_get_create_object(const struct dentry *new_dentry,
+					      const struct dentry *parent,
+					      const struct vfsmount *mnt)
 {
-	int error = 0;
+	struct name_entry *match;
+	struct acl_object_label *matchpo;
+	struct acl_subject_label *curracl;
+	char *path;
+
+	if (unlikely(!(gr_status & GR_READY)))
+		return NULL;
 
-	memcpy(gr_system_salt, args->salt, GR_SALT_LEN);
-	memcpy(gr_system_sum, args->sum, GR_SHA_LEN);
+	preempt_disable();
+	path = gr_to_filename_rbac(new_dentry, mnt);
+	match = lookup_name_entry_create(path);
 
-	if (init_variables(args)) {
-		gr_log_str(GR_DONT_AUDIT_GOOD, GR_INITF_ACL_MSG, GR_VERSION);
-		error = -ENOMEM;
-		free_variables();
-		goto out;
-	}
+	curracl = current->acl;
 
-	error = copy_user_acl(args);
-	free_init_variables();
-	if (error) {
-		free_variables();
-		goto out;
-	}
+	if (match) {
+		read_lock(&gr_inode_lock);
+		matchpo = lookup_acl_obj_label_create(match->inode, match->device, curracl);
+		read_unlock(&gr_inode_lock);
 
-	if ((error = gr_set_acls(0))) {
-		free_variables();
-		goto out;
+		if (matchpo) {
+			preempt_enable();
+			return matchpo;
+		}
 	}
 
-	pax_open_kernel();
-	gr_status |= GR_READY;
-	pax_close_kernel();
+	// lookup parent
 
-      out:
-	return error;
-}
+	matchpo = chk_obj_create_label(parent, mnt, curracl, path);
 
-/* derived from glibc fnmatch() 0: match, 1: no match*/
+	preempt_enable();
+	return matchpo;
+}
 
-static int
-glob_match(const char *p, const char *n)
+__u32
+gr_check_create(const struct dentry * new_dentry, const struct dentry * parent,
+		const struct vfsmount * mnt, const __u32 mode)
 {
-	char c;
+	struct acl_object_label *matchpo;
+	__u32 retval;
 
-	while ((c = *p++) != '\0') {
-	switch (c) {
-		case '?':
-			if (*n == '\0')
-				return 1;
-			else if (*n == '/')
-				return 1;
-			break;
-		case '\\':
-			if (*n != c)
-				return 1;
-			break;
-		case '*':
-			for (c = *p++; c == '?' || c == '*'; c = *p++) {
-				if (*n == '/')
-					return 1;
-				else if (c == '?') {
-					if (*n == '\0')
-						return 1;
-					else
-						++n;
-				}
-			}
-			if (c == '\0') {
-				return 0;
-			} else {
-				const char *endp;
+	if (unlikely(!(gr_status & GR_READY)))
+		return (mode & ~GR_AUDITS);
 
-				if ((endp = strchr(n, '/')) == NULL)
-					endp = n + strlen(n);
+	matchpo = gr_get_create_object(new_dentry, parent, mnt);
 
-				if (c == '[') {
-					for (--p; n < endp; ++n)
-						if (!glob_match(p, n))
-							return 0;
-				} else if (c == '/') {
-					while (*n != '\0' && *n != '/')
-						++n;
-					if (*n == '/' && !glob_match(p, n + 1))
-						return 0;
-				} else {
-					for (--p; n < endp; ++n)
-						if (*n == c && !glob_match(p, n))
-							return 0;
-				}
+	retval = matchpo->mode & mode;
 
-				return 1;
-			}
-		case '[':
-			{
-			int not;
-			char cold;
+	if ((retval != (mode & ~(GR_AUDITS | GR_SUPPRESS)))
+	    && (current->acl->mode & (GR_LEARN | GR_INHERITLEARN))) {
+		__u32 new_mode = mode;
 
-			if (*n == '\0' || *n == '/')
-				return 1;
+		new_mode &= ~(GR_AUDITS | GR_SUPPRESS);
 
-			not = (*p == '!' || *p == '^');
-			if (not)
-				++p;
+		gr_log_learn(new_dentry, mnt, new_mode);
+		return new_mode;
+	}
 
-			c = *p++;
-			for (;;) {
-				unsigned char fn = (unsigned char)*n;
+	return retval;
+}
 
-				if (c == '\0')
-					return 1;
-				else {
-					if (c == fn)
-						goto matched;
-					cold = c;
-					c = *p++;
+__u32
+gr_check_link(const struct dentry * new_dentry,
+	      const struct dentry * parent_dentry,
+	      const struct vfsmount * parent_mnt,
+	      const struct dentry * old_dentry, const struct vfsmount * old_mnt)
+{
+	struct acl_object_label *obj;
+	__u32 oldmode, newmode;
+	__u32 needmode;
+	__u32 checkmodes = GR_FIND | GR_APPEND | GR_WRITE | GR_EXEC | GR_SETID | GR_READ |
+			   GR_DELETE | GR_INHERIT;
 
-					if (c == '-' && *p != ']') {
-						unsigned char cend = *p++;
+	if (unlikely(!(gr_status & GR_READY)))
+		return (GR_CREATE | GR_LINK);
 
-						if (cend == '\0')
-							return 1;
+	obj = chk_obj_label(old_dentry, old_mnt, current->acl);
+	oldmode = obj->mode;
 
-						if (cold <= fn && fn <= cend)
-							goto matched;
+	obj = gr_get_create_object(new_dentry, parent_dentry, parent_mnt);
+	newmode = obj->mode;
 
-						c = *p++;
-					}
-				}
+	needmode = newmode & checkmodes;
 
-				if (c == ']')
-					break;
-			}
-			if (!not)
-				return 1;
-			break;
-		matched:
-			while (c != ']') {
-				if (c == '\0')
-					return 1;
+	// old name for hardlink must have at least the permissions of the new name
+	if ((oldmode & needmode) != needmode)
+		goto bad;
 
-				c = *p++;
-			}
-			if (not)
-				return 1;
-		}
-		break;
-	default:
-		if (c != *n)
-			return 1;
-	}
+	// if old name had restrictions/auditing, make sure the new name does as well
+	needmode = oldmode & (GR_NOPTRACE | GR_PTRACERD | GR_INHERIT | GR_AUDITS);
 
-	++n;
-	}
+	// don't allow hardlinking of suid/sgid/fcapped files without permission
+	if (is_privileged_binary(old_dentry))
+		needmode |= GR_SETID;
 
-	if (*n == '\0')
-		return 0;
+	if ((newmode & needmode) != needmode)
+		goto bad;
 
-	if (*n == '/')
+	// enforce minimum permissions
+	if ((newmode & (GR_CREATE | GR_LINK)) == (GR_CREATE | GR_LINK))
+		return newmode;
+bad:
+	needmode = oldmode;
+	if (is_privileged_binary(old_dentry))
+		needmode |= GR_SETID;
+	
+	if (current->acl->mode & (GR_LEARN | GR_INHERITLEARN)) {
+		gr_log_learn(old_dentry, old_mnt, needmode | GR_CREATE | GR_LINK);
+		return (GR_CREATE | GR_LINK);
+	} else if (newmode & GR_SUPPRESS)
+		return GR_SUPPRESS;
+	else
 		return 0;
-
-	return 1;
 }
 
-static struct acl_object_label *
-chk_glob_label(struct acl_object_label *globbed,
-	const struct dentry *dentry, const struct vfsmount *mnt, char **path)
+int
+gr_check_hidden_task(const struct task_struct *task)
 {
-	struct acl_object_label *tmp;
+	if (unlikely(!(gr_status & GR_READY)))
+		return 0;
 
-	if (*path == NULL)
-		*path = gr_to_filename_nolock(dentry, mnt);
+	if (!(task->acl->mode & GR_PROCFIND) && !(current->acl->mode & GR_VIEW))
+		return 1;
 
-	tmp = globbed;
+	return 0;
+}
 
-	while (tmp) {
-		if (!glob_match(tmp->filename, *path))
-			return tmp;
-		tmp = tmp->next;
-	}
+int
+gr_check_protected_task(const struct task_struct *task)
+{
+	if (unlikely(!(gr_status & GR_READY) || !task))
+		return 0;
 
-	return NULL;
+	if ((task->acl->mode & GR_PROTECTED) && !(current->acl->mode & GR_KILL) &&
+	    task->acl != current->acl)
+		return 1;
+
+	return 0;
 }
 
-static struct acl_object_label *
-__full_lookup(const struct dentry *orig_dentry, const struct vfsmount *orig_mnt,
-	    const ino_t curr_ino, const dev_t curr_dev,
-	    const struct acl_subject_label *subj, char **path, const int checkglob)
+int
+gr_check_protected_task_fowner(struct pid *pid, enum pid_type type)
 {
-	struct acl_subject_label *tmpsubj;
-	struct acl_object_label *retval;
-	struct acl_object_label *retval2;
+	struct task_struct *p;
+	int ret = 0;
 
-	tmpsubj = (struct acl_subject_label *) subj;
-	read_lock(&gr_inode_lock);
-	do {
-		retval = lookup_acl_obj_label(curr_ino, curr_dev, tmpsubj);
-		if (retval) {
-			if (checkglob && retval->globbed) {
-				retval2 = chk_glob_label(retval->globbed, orig_dentry, orig_mnt, path);
-				if (retval2)
-					retval = retval2;
-			}
-			break;
+	if (unlikely(!(gr_status & GR_READY) || !pid))
+		return ret;
+
+	read_lock(&tasklist_lock);
+	do_each_pid_task(pid, type, p) {
+		if ((p->acl->mode & GR_PROTECTED) && !(current->acl->mode & GR_KILL) &&
+		    p->acl != current->acl) {
+			ret = 1;
+			goto out;
 		}
-	} while ((tmpsubj = tmpsubj->parent_subject));
-	read_unlock(&gr_inode_lock);
+	} while_each_pid_task(pid, type, p);
+out:
+	read_unlock(&tasklist_lock);
 
-	return retval;
+	return ret;
 }
 
-static __inline__ struct acl_object_label *
-full_lookup(const struct dentry *orig_dentry, const struct vfsmount *orig_mnt,
-	    struct dentry *curr_dentry,
-	    const struct acl_subject_label *subj, char **path, const int checkglob)
+void
+gr_copy_label(struct task_struct *tsk)
 {
-	int newglob = checkglob;
-	ino_t inode;
-	dev_t device;
-
-	/* if we aren't checking a subdirectory of the original path yet, don't do glob checking
-	   as we don't want a / * rule to match instead of the / object
-	   don't do this for create lookups that call this function though, since they're looking up
-	   on the parent and thus need globbing checks on all paths
-	*/
-	if (orig_dentry == curr_dentry && newglob != GR_CREATE_GLOB)
-		newglob = GR_NO_GLOB;
+	struct task_struct *p = current;
 
-	spin_lock(&curr_dentry->d_lock);
-	inode = curr_dentry->d_inode->i_ino;
-	device = __get_dev(curr_dentry);
-	spin_unlock(&curr_dentry->d_lock);
+	tsk->inherited = p->inherited;
+	tsk->acl_sp_role = 0;
+	tsk->acl_role_id = p->acl_role_id;
+	tsk->acl = p->acl;
+	tsk->role = p->role;
+	tsk->signal->used_accept = 0;
+	tsk->signal->curr_ip = p->signal->curr_ip;
+	tsk->signal->saved_ip = p->signal->saved_ip;
+	if (p->exec_file)
+		get_file(p->exec_file);
+	tsk->exec_file = p->exec_file;
+	tsk->is_writable = p->is_writable;
+	if (unlikely(p->signal->used_accept)) {
+		p->signal->curr_ip = 0;
+		p->signal->saved_ip = 0;
+	}
 
-	return __full_lookup(orig_dentry, orig_mnt, inode, device, subj, path, newglob);
+	return;
 }
 
-#ifdef CONFIG_HUGETLBFS
-static inline bool
-is_hugetlbfs_mnt(const struct vfsmount *mnt)
-{
-	int i;
-	for (i = 0; i < HUGE_MAX_HSTATE; i++) {
-		if (unlikely(hugetlbfs_vfsmount[i] == mnt))
-			return true;
-	}
-
-	return false;
-}
-#endif
-
-static struct acl_object_label *
-__chk_obj_label(const struct dentry *l_dentry, const struct vfsmount *l_mnt,
-	      const struct acl_subject_label *subj, char *path, const int checkglob)
-{
-	struct dentry *dentry = (struct dentry *) l_dentry;
-	struct vfsmount *mnt = (struct vfsmount *) l_mnt;
-	struct mount *real_mnt = real_mount(mnt);
-	struct acl_object_label *retval;
-	struct dentry *parent;
-
-	br_read_lock(&vfsmount_lock);
-	write_seqlock(&rename_lock);
-
-	if (unlikely((mnt == shm_mnt && dentry->d_inode->i_nlink == 0) || mnt == pipe_mnt ||
-#ifdef CONFIG_NET
-	    mnt == sock_mnt ||
-#endif
-#ifdef CONFIG_HUGETLBFS
-	    (is_hugetlbfs_mnt(mnt) && dentry->d_inode->i_nlink == 0) ||
-#endif
-		/* ignore Eric Biederman */
-	    IS_PRIVATE(l_dentry->d_inode))) {
-		retval = (subj->mode & GR_SHMEXEC) ? fakefs_obj_rwx : fakefs_obj_rw;
-		goto out;
-	}
-
-	for (;;) {
-		if (dentry == real_root.dentry && mnt == real_root.mnt)
-			break;
-
-		if (dentry == mnt->mnt_root || IS_ROOT(dentry)) {
-			if (!mnt_has_parent(real_mnt))
-				break;
-
-			retval = full_lookup(l_dentry, l_mnt, dentry, subj, &path, checkglob);
-			if (retval != NULL)
-				goto out;
-
-			dentry = real_mnt->mnt_mountpoint;
-			real_mnt = real_mnt->mnt_parent;
-			mnt = &real_mnt->mnt;
-			continue;
-		}
-
-		parent = dentry->d_parent;
-		retval = full_lookup(l_dentry, l_mnt, dentry, subj, &path, checkglob);
-		if (retval != NULL)
-			goto out;
-
-		dentry = parent;
-	}
-
-	retval = full_lookup(l_dentry, l_mnt, dentry, subj, &path, checkglob);
-
-	/* real_root is pinned so we don't have to hold a reference */
-	if (retval == NULL)
-		retval = full_lookup(l_dentry, l_mnt, real_root.dentry, subj, &path, checkglob);
-out:
-	write_sequnlock(&rename_lock);
-	br_read_unlock(&vfsmount_lock);
-
-	BUG_ON(retval == NULL);
-
-	return retval;
-}
-
-static __inline__ struct acl_object_label *
-chk_obj_label(const struct dentry *l_dentry, const struct vfsmount *l_mnt,
-	      const struct acl_subject_label *subj)
-{
-	char *path = NULL;
-	return __chk_obj_label(l_dentry, l_mnt, subj, path, GR_REG_GLOB);
-}
-
-static __inline__ struct acl_object_label *
-chk_obj_label_noglob(const struct dentry *l_dentry, const struct vfsmount *l_mnt,
-	      const struct acl_subject_label *subj)
-{
-	char *path = NULL;
-	return __chk_obj_label(l_dentry, l_mnt, subj, path, GR_NO_GLOB);
-}
-
-static __inline__ struct acl_object_label *
-chk_obj_create_label(const struct dentry *l_dentry, const struct vfsmount *l_mnt,
-		     const struct acl_subject_label *subj, char *path)
-{
-	return __chk_obj_label(l_dentry, l_mnt, subj, path, GR_CREATE_GLOB);
-}
-
-static struct acl_subject_label *
-chk_subj_label(const struct dentry *l_dentry, const struct vfsmount *l_mnt,
-	       const struct acl_role_label *role)
-{
-	struct dentry *dentry = (struct dentry *) l_dentry;
-	struct vfsmount *mnt = (struct vfsmount *) l_mnt;
-	struct mount *real_mnt = real_mount(mnt);
-	struct acl_subject_label *retval;
-	struct dentry *parent;
-
-	br_read_lock(&vfsmount_lock);
-	write_seqlock(&rename_lock);
-
-	for (;;) {
-		if (dentry == real_root.dentry && mnt == real_root.mnt)
-			break;
-		if (dentry == mnt->mnt_root || IS_ROOT(dentry)) {
-			if (!mnt_has_parent(real_mnt))
-				break;
-
-			spin_lock(&dentry->d_lock);
-			read_lock(&gr_inode_lock);
-			retval =
-				lookup_acl_subj_label(dentry->d_inode->i_ino,
-						__get_dev(dentry), role);
-			read_unlock(&gr_inode_lock);
-			spin_unlock(&dentry->d_lock);
-			if (retval != NULL)
-				goto out;
-
-			dentry = real_mnt->mnt_mountpoint;
-			real_mnt = real_mnt->mnt_parent;
-			mnt = &real_mnt->mnt;
-			continue;
-		}
-
-		spin_lock(&dentry->d_lock);
-		read_lock(&gr_inode_lock);
-		retval = lookup_acl_subj_label(dentry->d_inode->i_ino,
-					  __get_dev(dentry), role);
-		read_unlock(&gr_inode_lock);
-		parent = dentry->d_parent;
-		spin_unlock(&dentry->d_lock);
-
-		if (retval != NULL)
-			goto out;
-
-		dentry = parent;
-	}
-
-	spin_lock(&dentry->d_lock);
-	read_lock(&gr_inode_lock);
-	retval = lookup_acl_subj_label(dentry->d_inode->i_ino,
-				  __get_dev(dentry), role);
-	read_unlock(&gr_inode_lock);
-	spin_unlock(&dentry->d_lock);
-
-	if (unlikely(retval == NULL)) {
-		/* real_root is pinned, we don't need to hold a reference */
-		read_lock(&gr_inode_lock);
-		retval = lookup_acl_subj_label(real_root.dentry->d_inode->i_ino,
-					  __get_dev(real_root.dentry), role);
-		read_unlock(&gr_inode_lock);
-	}
-out:
-	write_sequnlock(&rename_lock);
-	br_read_unlock(&vfsmount_lock);
-
-	BUG_ON(retval == NULL);
-
-	return retval;
-}
-
-static void
-gr_log_learn(const struct dentry *dentry, const struct vfsmount *mnt, const __u32 mode)
-{
-	struct task_struct *task = current;
-	const struct cred *cred = current_cred();
-
-	security_learn(GR_LEARN_AUDIT_MSG, task->role->rolename, task->role->roletype,
-		       GR_GLOBAL_UID(cred->uid), GR_GLOBAL_GID(cred->gid), task->exec_file ? gr_to_filename1(task->exec_file->f_path.dentry,
-		       task->exec_file->f_path.mnt) : task->acl->filename, task->acl->filename,
-		       1UL, 1UL, gr_to_filename(dentry, mnt), (unsigned long) mode, &task->signal->saved_ip);
-
-	return;
-}
-
-static void
-gr_log_learn_uid_change(const kuid_t real, const kuid_t effective, const kuid_t fs)
-{
-	struct task_struct *task = current;
-	const struct cred *cred = current_cred();
-
-	security_learn(GR_ID_LEARN_MSG, task->role->rolename, task->role->roletype,
-		       GR_GLOBAL_UID(cred->uid), GR_GLOBAL_GID(cred->gid), task->exec_file ? gr_to_filename1(task->exec_file->f_path.dentry,
-		       task->exec_file->f_path.mnt) : task->acl->filename, task->acl->filename,
-		       'u', GR_GLOBAL_UID(real), GR_GLOBAL_UID(effective), GR_GLOBAL_UID(fs), &task->signal->saved_ip);
-
-	return;
-}
-
-static void
-gr_log_learn_gid_change(const kgid_t real, const kgid_t effective, const kgid_t fs)
-{
-	struct task_struct *task = current;
-	const struct cred *cred = current_cred();
-
-	security_learn(GR_ID_LEARN_MSG, task->role->rolename, task->role->roletype,
-		       GR_GLOBAL_UID(cred->uid), GR_GLOBAL_GID(cred->gid), task->exec_file ? gr_to_filename1(task->exec_file->f_path.dentry,
-		       task->exec_file->f_path.mnt) : task->acl->filename, task->acl->filename,
-		       'g', GR_GLOBAL_GID(real), GR_GLOBAL_GID(effective), GR_GLOBAL_GID(fs), &task->signal->saved_ip);
-
-	return;
-}
-
-__u32
-gr_search_file(const struct dentry * dentry, const __u32 mode,
-	       const struct vfsmount * mnt)
-{
-	__u32 retval = mode;
-	struct acl_subject_label *curracl;
-	struct acl_object_label *currobj;
-
-	if (unlikely(!(gr_status & GR_READY)))
-		return (mode & ~GR_AUDITS);
-
-	curracl = current->acl;
-
-	currobj = chk_obj_label(dentry, mnt, curracl);
-	retval = currobj->mode & mode;
-
-	/* if we're opening a specified transfer file for writing
-	   (e.g. /dev/initctl), then transfer our role to init
-	*/
-	if (unlikely(currobj->mode & GR_INIT_TRANSFER && retval & GR_WRITE &&
-		     current->role->roletype & GR_ROLE_PERSIST)) {
-		struct task_struct *task = init_pid_ns.child_reaper;
-
-		if (task->role != current->role) {
-			task->acl_sp_role = 0;
-			task->acl_role_id = current->acl_role_id;
-			task->role = current->role;
-			rcu_read_lock();
-			read_lock(&grsec_exec_file_lock);
-			gr_apply_subject_to_task(task);
-			read_unlock(&grsec_exec_file_lock);
-			rcu_read_unlock();
-			gr_log_noargs(GR_DONT_AUDIT_GOOD, GR_INIT_TRANSFER_MSG);
-		}
-	}
-
-	if (unlikely
-	    ((curracl->mode & (GR_LEARN | GR_INHERITLEARN)) && !(mode & GR_NOPTRACE)
-	     && (retval != (mode & ~(GR_AUDITS | GR_SUPPRESS))))) {
-		__u32 new_mode = mode;
-
-		new_mode &= ~(GR_AUDITS | GR_SUPPRESS);
-
-		retval = new_mode;
-
-		if (new_mode & GR_EXEC && curracl->mode & GR_INHERITLEARN)
-			new_mode |= GR_INHERIT;
-
-		if (!(mode & GR_NOLEARN))
-			gr_log_learn(dentry, mnt, new_mode);
-	}
-
-	return retval;
-}
-
-struct acl_object_label *gr_get_create_object(const struct dentry *new_dentry,
-					      const struct dentry *parent,
-					      const struct vfsmount *mnt)
-{
-	struct name_entry *match;
-	struct acl_object_label *matchpo;
-	struct acl_subject_label *curracl;
-	char *path;
-
-	if (unlikely(!(gr_status & GR_READY)))
-		return NULL;
-
-	preempt_disable();
-	path = gr_to_filename_rbac(new_dentry, mnt);
-	match = lookup_name_entry_create(path);
-
-	curracl = current->acl;
-
-	if (match) {
-		read_lock(&gr_inode_lock);
-		matchpo = lookup_acl_obj_label_create(match->inode, match->device, curracl);
-		read_unlock(&gr_inode_lock);
-
-		if (matchpo) {
-			preempt_enable();
-			return matchpo;
-		}
-	}
-
-	// lookup parent
-
-	matchpo = chk_obj_create_label(parent, mnt, curracl, path);
-
-	preempt_enable();
-	return matchpo;
-}
-
-__u32
-gr_check_create(const struct dentry * new_dentry, const struct dentry * parent,
-		const struct vfsmount * mnt, const __u32 mode)
-{
-	struct acl_object_label *matchpo;
-	__u32 retval;
-
-	if (unlikely(!(gr_status & GR_READY)))
-		return (mode & ~GR_AUDITS);
-
-	matchpo = gr_get_create_object(new_dentry, parent, mnt);
-
-	retval = matchpo->mode & mode;
-
-	if ((retval != (mode & ~(GR_AUDITS | GR_SUPPRESS)))
-	    && (current->acl->mode & (GR_LEARN | GR_INHERITLEARN))) {
-		__u32 new_mode = mode;
-
-		new_mode &= ~(GR_AUDITS | GR_SUPPRESS);
-
-		gr_log_learn(new_dentry, mnt, new_mode);
-		return new_mode;
-	}
-
-	return retval;
-}
-
-__u32
-gr_check_link(const struct dentry * new_dentry,
-	      const struct dentry * parent_dentry,
-	      const struct vfsmount * parent_mnt,
-	      const struct dentry * old_dentry, const struct vfsmount * old_mnt)
-{
-	struct acl_object_label *obj;
-	__u32 oldmode, newmode;
-	__u32 needmode;
-	__u32 checkmodes = GR_FIND | GR_APPEND | GR_WRITE | GR_EXEC | GR_SETID | GR_READ |
-			   GR_DELETE | GR_INHERIT;
-
-	if (unlikely(!(gr_status & GR_READY)))
-		return (GR_CREATE | GR_LINK);
-
-	obj = chk_obj_label(old_dentry, old_mnt, current->acl);
-	oldmode = obj->mode;
-
-	obj = gr_get_create_object(new_dentry, parent_dentry, parent_mnt);
-	newmode = obj->mode;
-
-	needmode = newmode & checkmodes;
-
-	// old name for hardlink must have at least the permissions of the new name
-	if ((oldmode & needmode) != needmode)
-		goto bad;
-
-	// if old name had restrictions/auditing, make sure the new name does as well
-	needmode = oldmode & (GR_NOPTRACE | GR_PTRACERD | GR_INHERIT | GR_AUDITS);
-
-	// don't allow hardlinking of suid/sgid/fcapped files without permission
-	if (is_privileged_binary(old_dentry))
-		needmode |= GR_SETID;
-
-	if ((newmode & needmode) != needmode)
-		goto bad;
-
-	// enforce minimum permissions
-	if ((newmode & (GR_CREATE | GR_LINK)) == (GR_CREATE | GR_LINK))
-		return newmode;
-bad:
-	needmode = oldmode;
-	if (is_privileged_binary(old_dentry))
-		needmode |= GR_SETID;
-	
-	if (current->acl->mode & (GR_LEARN | GR_INHERITLEARN)) {
-		gr_log_learn(old_dentry, old_mnt, needmode | GR_CREATE | GR_LINK);
-		return (GR_CREATE | GR_LINK);
-	} else if (newmode & GR_SUPPRESS)
-		return GR_SUPPRESS;
-	else
-		return 0;
-}
-
-int
-gr_check_hidden_task(const struct task_struct *task)
-{
-	if (unlikely(!(gr_status & GR_READY)))
-		return 0;
-
-	if (!(task->acl->mode & GR_PROCFIND) && !(current->acl->mode & GR_VIEW))
-		return 1;
-
-	return 0;
-}
-
-int
-gr_check_protected_task(const struct task_struct *task)
-{
-	if (unlikely(!(gr_status & GR_READY) || !task))
-		return 0;
-
-	if ((task->acl->mode & GR_PROTECTED) && !(current->acl->mode & GR_KILL) &&
-	    task->acl != current->acl)
-		return 1;
-
-	return 0;
-}
-
-int
-gr_check_protected_task_fowner(struct pid *pid, enum pid_type type)
-{
-	struct task_struct *p;
-	int ret = 0;
-
-	if (unlikely(!(gr_status & GR_READY) || !pid))
-		return ret;
-
-	read_lock(&tasklist_lock);
-	do_each_pid_task(pid, type, p) {
-		if ((p->acl->mode & GR_PROTECTED) && !(current->acl->mode & GR_KILL) &&
-		    p->acl != current->acl) {
-			ret = 1;
-			goto out;
-		}
-	} while_each_pid_task(pid, type, p);
-out:
-	read_unlock(&tasklist_lock);
-
-	return ret;
-}
-
-void
-gr_copy_label(struct task_struct *tsk)
-{
-	tsk->signal->used_accept = 0;
-	tsk->acl_sp_role = 0;
-	tsk->acl_role_id = current->acl_role_id;
-	tsk->acl = current->acl;
-	tsk->role = current->role;
-	tsk->signal->curr_ip = current->signal->curr_ip;
-	tsk->signal->saved_ip = current->signal->saved_ip;
-	if (current->exec_file)
-		get_file(current->exec_file);
-	tsk->exec_file = current->exec_file;
-	tsk->is_writable = current->is_writable;
-	if (unlikely(current->signal->used_accept)) {
-		current->signal->curr_ip = 0;
-		current->signal->saved_ip = 0;
-	}
-
-	return;
-}
-
-static void
-gr_set_proc_res(struct task_struct *task)
-{
-	struct acl_subject_label *proc;
-	unsigned short i;
-
-	proc = task->acl;
-
-	if (proc->mode & (GR_LEARN | GR_INHERITLEARN))
-		return;
-
-	for (i = 0; i < RLIM_NLIMITS; i++) {
-		if (!(proc->resmask & (1U << i)))
-			continue;
-
-		task->signal->rlim[i].rlim_cur = proc->res[i].rlim_cur;
-		task->signal->rlim[i].rlim_max = proc->res[i].rlim_max;
-
-		if (i == RLIMIT_CPU)
-			update_rlimit_cpu(task, proc->res[i].rlim_cur);
-	}
-
-	return;
-}
-
-extern int gr_process_kernel_setuid_ban(struct user_struct *user);
-
-int
-gr_check_user_change(kuid_t real, kuid_t effective, kuid_t fs)
-{
-	unsigned int i;
-	__u16 num;
-	uid_t *uidlist;
-	uid_t curuid;
-	int realok = 0;
-	int effectiveok = 0;
-	int fsok = 0;
-	uid_t globalreal, globaleffective, globalfs;
-
-#if defined(CONFIG_GRKERNSEC_KERN_LOCKOUT)
-	struct user_struct *user;
-
-	if (!uid_valid(real))
-		goto skipit;
-
-	/* find user based on global namespace */
-
-	globalreal = GR_GLOBAL_UID(real);
-
-	user = find_user(make_kuid(&init_user_ns, globalreal));
-	if (user == NULL)
-		goto skipit;
-
-	if (gr_process_kernel_setuid_ban(user)) {
-		/* for find_user */
-		free_uid(user);
-		return 1;
-	}
-
-	/* for find_user */
-	free_uid(user);
-
-skipit:
-#endif
-
-	if (unlikely(!(gr_status & GR_READY)))
-		return 0;
-
-	if (current->acl->mode & (GR_LEARN | GR_INHERITLEARN))
-		gr_log_learn_uid_change(real, effective, fs);
-
-	num = current->acl->user_trans_num;
-	uidlist = current->acl->user_transitions;
-
-	if (uidlist == NULL)
-		return 0;
-
-	if (!uid_valid(real)) {
-		realok = 1;
-		globalreal = (uid_t)-1;		
-	} else {
-		globalreal = GR_GLOBAL_UID(real);		
-	}
-	if (!uid_valid(effective)) {
-		effectiveok = 1;
-		globaleffective = (uid_t)-1;
-	} else {
-		globaleffective = GR_GLOBAL_UID(effective);
-	}
-	if (!uid_valid(fs)) {
-		fsok = 1;
-		globalfs = (uid_t)-1;
-	} else {
-		globalfs = GR_GLOBAL_UID(fs);
-	}
-
-	if (current->acl->user_trans_type & GR_ID_ALLOW) {
-		for (i = 0; i < num; i++) {
-			curuid = uidlist[i];
-			if (globalreal == curuid)
-				realok = 1;
-			if (globaleffective == curuid)
-				effectiveok = 1;
-			if (globalfs == curuid)
-				fsok = 1;
-		}
-	} else if (current->acl->user_trans_type & GR_ID_DENY) {
-		for (i = 0; i < num; i++) {
-			curuid = uidlist[i];
-			if (globalreal == curuid)
-				break;
-			if (globaleffective == curuid)
-				break;
-			if (globalfs == curuid)
-				break;
-		}
-		/* not in deny list */
-		if (i == num) {
-			realok = 1;
-			effectiveok = 1;
-			fsok = 1;
-		}
-	}
-
-	if (realok && effectiveok && fsok)
-		return 0;
-	else {
-		gr_log_int(GR_DONT_AUDIT, GR_USRCHANGE_ACL_MSG, realok ? (effectiveok ? (fsok ? 0 : globalfs) : globaleffective) : globalreal);
-		return 1;
-	}
-}
-
-int
-gr_check_group_change(kgid_t real, kgid_t effective, kgid_t fs)
-{
-	unsigned int i;
-	__u16 num;
-	gid_t *gidlist;
-	gid_t curgid;
-	int realok = 0;
-	int effectiveok = 0;
-	int fsok = 0;
-	gid_t globalreal, globaleffective, globalfs;
-
-	if (unlikely(!(gr_status & GR_READY)))
-		return 0;
-
-	if (current->acl->mode & (GR_LEARN | GR_INHERITLEARN))
-		gr_log_learn_gid_change(real, effective, fs);
-
-	num = current->acl->group_trans_num;
-	gidlist = current->acl->group_transitions;
-
-	if (gidlist == NULL)
-		return 0;
-
-	if (!gid_valid(real)) {
-		realok = 1;
-		globalreal = (gid_t)-1;		
-	} else {
-		globalreal = GR_GLOBAL_GID(real);
-	}
-	if (!gid_valid(effective)) {
-		effectiveok = 1;
-		globaleffective = (gid_t)-1;		
-	} else {
-		globaleffective = GR_GLOBAL_GID(effective);
-	}
-	if (!gid_valid(fs)) {
-		fsok = 1;
-		globalfs = (gid_t)-1;		
-	} else {
-		globalfs = GR_GLOBAL_GID(fs);
-	}
-
-	if (current->acl->group_trans_type & GR_ID_ALLOW) {
-		for (i = 0; i < num; i++) {
-			curgid = gidlist[i];
-			if (globalreal == curgid)
-				realok = 1;
-			if (globaleffective == curgid)
-				effectiveok = 1;
-			if (globalfs == curgid)
-				fsok = 1;
-		}
-	} else if (current->acl->group_trans_type & GR_ID_DENY) {
-		for (i = 0; i < num; i++) {
-			curgid = gidlist[i];
-			if (globalreal == curgid)
-				break;
-			if (globaleffective == curgid)
-				break;
-			if (globalfs == curgid)
-				break;
-		}
-		/* not in deny list */
-		if (i == num) {
-			realok = 1;
-			effectiveok = 1;
-			fsok = 1;
-		}
-	}
-
-	if (realok && effectiveok && fsok)
-		return 0;
-	else {
-		gr_log_int(GR_DONT_AUDIT, GR_GRPCHANGE_ACL_MSG, realok ? (effectiveok ? (fsok ? 0 : globalfs) : globaleffective) : globalreal);
-		return 1;
-	}
-}
-
-extern int gr_acl_is_capable(const int cap);
-
-void
-gr_set_role_label(struct task_struct *task, const kuid_t kuid, const kgid_t kgid)
-{
-	struct acl_role_label *role = task->role;
-	struct acl_subject_label *subj = NULL;
-	struct acl_object_label *obj;
-	struct file *filp;
-	uid_t uid;
-	gid_t gid;
-
-	if (unlikely(!(gr_status & GR_READY)))
-		return;
-
-	uid = GR_GLOBAL_UID(kuid);
-	gid = GR_GLOBAL_GID(kgid);
-
-	filp = task->exec_file;
-
-	/* kernel process, we'll give them the kernel role */
-	if (unlikely(!filp)) {
-		task->role = kernel_role;
-		task->acl = kernel_role->root_label;
-		return;
-	} else if (!task->role || !(task->role->roletype & GR_ROLE_SPECIAL))
-		role = lookup_acl_role_label(task, uid, gid);
-
-	/* don't change the role if we're not a privileged process */
-	if (role && task->role != role &&
-	    (((role->roletype & GR_ROLE_USER) && !gr_acl_is_capable(CAP_SETUID)) ||
-	     ((role->roletype & GR_ROLE_GROUP) && !gr_acl_is_capable(CAP_SETGID))))
-		return;
-
-	/* perform subject lookup in possibly new role
-	   we can use this result below in the case where role == task->role
-	*/
-	subj = chk_subj_label(filp->f_path.dentry, filp->f_path.mnt, role);
-
-	/* if we changed uid/gid, but result in the same role
-	   and are using inheritance, don't lose the inherited subject
-	   if current subject is other than what normal lookup
-	   would result in, we arrived via inheritance, don't
-	   lose subject
-	*/
-	if (role != task->role || (!(task->acl->mode & GR_INHERITLEARN) &&
-				   (subj == task->acl)))
-		task->acl = subj;
-
-	task->role = role;
-
-	task->is_writable = 0;
-
-	/* ignore additional mmap checks for processes that are writable 
-	   by the default ACL */
-	obj = chk_obj_label(filp->f_path.dentry, filp->f_path.mnt, default_role->root_label);
-	if (unlikely(obj->mode & GR_WRITE))
-		task->is_writable = 1;
-	obj = chk_obj_label(filp->f_path.dentry, filp->f_path.mnt, task->role->root_label);
-	if (unlikely(obj->mode & GR_WRITE))
-		task->is_writable = 1;
-
-#ifdef CONFIG_GRKERNSEC_RBAC_DEBUG
-	printk(KERN_ALERT "Set role label for (%s:%d): role:%s, subject:%s\n", task->comm, task_pid_nr(task), task->role->rolename, task->acl->filename);
-#endif
-
-	gr_set_proc_res(task);
-
-	return;
-}
+extern int gr_process_kernel_setuid_ban(struct user_struct *user);
 
 int
-gr_set_proc_label(const struct dentry *dentry, const struct vfsmount *mnt,
-		  const int unsafe_flags)
-{
-	struct task_struct *task = current;
-	struct acl_subject_label *newacl;
-	struct acl_object_label *obj;
-	__u32 retmode;
-
-	if (unlikely(!(gr_status & GR_READY)))
-		return 0;
-
-	newacl = chk_subj_label(dentry, mnt, task->role);
-
-	/* special handling for if we did an strace -f -p <pid> from an admin role, where pid then
-	   did an exec
-	*/
-	rcu_read_lock();
-	read_lock(&tasklist_lock);
-	if (task->ptrace && task->parent && ((task->parent->role->roletype & GR_ROLE_GOD) ||
-	    (task->parent->acl->mode & GR_POVERRIDE))) {
-		read_unlock(&tasklist_lock);
-		rcu_read_unlock();
-		goto skip_check;
-	}
-	read_unlock(&tasklist_lock);
-	rcu_read_unlock();
-
-	if (unsafe_flags && !(task->acl->mode & GR_POVERRIDE) && (task->acl != newacl) &&
-	     !(task->role->roletype & GR_ROLE_GOD) &&
-	     !gr_search_file(dentry, GR_PTRACERD, mnt) &&
-	     !(task->acl->mode & (GR_LEARN | GR_INHERITLEARN))) {
-		if (unsafe_flags & LSM_UNSAFE_SHARE)
-			gr_log_fs_generic(GR_DONT_AUDIT, GR_UNSAFESHARE_EXEC_ACL_MSG, dentry, mnt);
-		else
-			gr_log_fs_generic(GR_DONT_AUDIT, GR_PTRACE_EXEC_ACL_MSG, dentry, mnt);
-		return -EACCES;
-	}
-
-skip_check:
-
-	obj = chk_obj_label(dentry, mnt, task->acl);
-	retmode = obj->mode & (GR_INHERIT | GR_AUDIT_INHERIT);
-
-	if (!(task->acl->mode & GR_INHERITLEARN) &&
-	    ((newacl->mode & GR_LEARN) || !(retmode & GR_INHERIT))) {
-		if (obj->nested)
-			task->acl = obj->nested;
-		else
-			task->acl = newacl;
-	} else if (retmode & GR_INHERIT && retmode & GR_AUDIT_INHERIT)
-		gr_log_str_fs(GR_DO_AUDIT, GR_INHERIT_ACL_MSG, task->acl->filename, dentry, mnt);
-
-	task->is_writable = 0;
-
-	/* ignore additional mmap checks for processes that are writable 
-	   by the default ACL */
-	obj = chk_obj_label(dentry, mnt, default_role->root_label);
-	if (unlikely(obj->mode & GR_WRITE))
-		task->is_writable = 1;
-	obj = chk_obj_label(dentry, mnt, task->role->root_label);
-	if (unlikely(obj->mode & GR_WRITE))
-		task->is_writable = 1;
-
-	gr_set_proc_res(task);
-
-#ifdef CONFIG_GRKERNSEC_RBAC_DEBUG
-	printk(KERN_ALERT "Set subject label for (%s:%d): role:%s, subject:%s\n", task->comm, task_pid_nr(task), task->role->rolename, task->acl->filename);
-#endif
-	return 0;
-}
-
-/* always called with valid inodev ptr */
-static void
-do_handle_delete(struct inodev_entry *inodev, const ino_t ino, const dev_t dev)
-{
-	struct acl_object_label *matchpo;
-	struct acl_subject_label *matchps;
-	struct acl_subject_label *subj;
-	struct acl_role_label *role;
-	unsigned int x;
-
-	FOR_EACH_ROLE_START(role)
-		FOR_EACH_SUBJECT_START(role, subj, x)
-			if ((matchpo = lookup_acl_obj_label(ino, dev, subj)) != NULL)
-				matchpo->mode |= GR_DELETED;
-		FOR_EACH_SUBJECT_END(subj,x)
-		FOR_EACH_NESTED_SUBJECT_START(role, subj)
-			/* nested subjects aren't in the role's subj_hash table */
-			if ((matchpo = lookup_acl_obj_label(ino, dev, subj)) != NULL)
-				matchpo->mode |= GR_DELETED;
-		FOR_EACH_NESTED_SUBJECT_END(subj)
-		if ((matchps = lookup_acl_subj_label(ino, dev, role)) != NULL)
-			matchps->mode |= GR_DELETED;
-	FOR_EACH_ROLE_END(role)
-
-	inodev->nentry->deleted = 1;
-
-	return;
-}
-
-void
-gr_handle_delete(const ino_t ino, const dev_t dev)
-{
-	struct inodev_entry *inodev;
-
-	if (unlikely(!(gr_status & GR_READY)))
-		return;
-
-	write_lock(&gr_inode_lock);
-	inodev = lookup_inodev_entry(ino, dev);
-	if (inodev != NULL)
-		do_handle_delete(inodev, ino, dev);
-	write_unlock(&gr_inode_lock);
-
-	return;
-}
-
-static void
-update_acl_obj_label(const ino_t oldinode, const dev_t olddevice,
-		     const ino_t newinode, const dev_t newdevice,
-		     struct acl_subject_label *subj)
-{
-	unsigned int index = gr_fhash(oldinode, olddevice, subj->obj_hash_size);
-	struct acl_object_label *match;
-
-	match = subj->obj_hash[index];
-
-	while (match && (match->inode != oldinode ||
-	       match->device != olddevice ||
-	       !(match->mode & GR_DELETED)))
-		match = match->next;
-
-	if (match && (match->inode == oldinode)
-	    && (match->device == olddevice)
-	    && (match->mode & GR_DELETED)) {
-		if (match->prev == NULL) {
-			subj->obj_hash[index] = match->next;
-			if (match->next != NULL)
-				match->next->prev = NULL;
-		} else {
-			match->prev->next = match->next;
-			if (match->next != NULL)
-				match->next->prev = match->prev;
-		}
-		match->prev = NULL;
-		match->next = NULL;
-		match->inode = newinode;
-		match->device = newdevice;
-		match->mode &= ~GR_DELETED;
-
-		insert_acl_obj_label(match, subj);
-	}
-
-	return;
-}
-
-static void
-update_acl_subj_label(const ino_t oldinode, const dev_t olddevice,
-		      const ino_t newinode, const dev_t newdevice,
-		      struct acl_role_label *role)
-{
-	unsigned int index = gr_fhash(oldinode, olddevice, role->subj_hash_size);
-	struct acl_subject_label *match;
-
-	match = role->subj_hash[index];
-
-	while (match && (match->inode != oldinode ||
-	       match->device != olddevice ||
-	       !(match->mode & GR_DELETED)))
-		match = match->next;
-
-	if (match && (match->inode == oldinode)
-	    && (match->device == olddevice)
-	    && (match->mode & GR_DELETED)) {
-		if (match->prev == NULL) {
-			role->subj_hash[index] = match->next;
-			if (match->next != NULL)
-				match->next->prev = NULL;
-		} else {
-			match->prev->next = match->next;
-			if (match->next != NULL)
-				match->next->prev = match->prev;
-		}
-		match->prev = NULL;
-		match->next = NULL;
-		match->inode = newinode;
-		match->device = newdevice;
-		match->mode &= ~GR_DELETED;
-
-		insert_acl_subj_label(match, role);
-	}
-
-	return;
-}
-
-static void
-update_inodev_entry(const ino_t oldinode, const dev_t olddevice,
-		    const ino_t newinode, const dev_t newdevice)
+gr_check_user_change(kuid_t real, kuid_t effective, kuid_t fs)
 {
-	unsigned int index = gr_fhash(oldinode, olddevice, inodev_set.i_size);
-	struct inodev_entry *match;
-
-	match = inodev_set.i_hash[index];
-
-	while (match && (match->nentry->inode != oldinode ||
-	       match->nentry->device != olddevice || !match->nentry->deleted))
-		match = match->next;
-
-	if (match && (match->nentry->inode == oldinode)
-	    && (match->nentry->device == olddevice) &&
-	    match->nentry->deleted) {
-		if (match->prev == NULL) {
-			inodev_set.i_hash[index] = match->next;
-			if (match->next != NULL)
-				match->next->prev = NULL;
-		} else {
-			match->prev->next = match->next;
-			if (match->next != NULL)
-				match->next->prev = match->prev;
-		}
-		match->prev = NULL;
-		match->next = NULL;
-		match->nentry->inode = newinode;
-		match->nentry->device = newdevice;
-		match->nentry->deleted = 0;
-
-		insert_inodev_entry(match);
-	}
+	unsigned int i;
+	__u16 num;
+	uid_t *uidlist;
+	uid_t curuid;
+	int realok = 0;
+	int effectiveok = 0;
+	int fsok = 0;
+	uid_t globalreal, globaleffective, globalfs;
 
-	return;
-}
+#if defined(CONFIG_GRKERNSEC_KERN_LOCKOUT)
+	struct user_struct *user;
 
-static void
-__do_handle_create(const struct name_entry *matchn, ino_t ino, dev_t dev)
-{
-	struct acl_subject_label *subj;
-	struct acl_role_label *role;
-	unsigned int x;
+	if (!uid_valid(real))
+		goto skipit;
 
-	FOR_EACH_ROLE_START(role)
-		update_acl_subj_label(matchn->inode, matchn->device, ino, dev, role);
+	/* find user based on global namespace */
 
-		FOR_EACH_NESTED_SUBJECT_START(role, subj)
-			if ((subj->inode == ino) && (subj->device == dev)) {
-				subj->inode = ino;
-				subj->device = dev;
-			}
-			/* nested subjects aren't in the role's subj_hash table */
-			update_acl_obj_label(matchn->inode, matchn->device,
-					     ino, dev, subj);
-		FOR_EACH_NESTED_SUBJECT_END(subj)
-		FOR_EACH_SUBJECT_START(role, subj, x)
-			update_acl_obj_label(matchn->inode, matchn->device,
-					     ino, dev, subj);
-		FOR_EACH_SUBJECT_END(subj,x)
-	FOR_EACH_ROLE_END(role)
+	globalreal = GR_GLOBAL_UID(real);
 
-	update_inodev_entry(matchn->inode, matchn->device, ino, dev);
+	user = find_user(make_kuid(&init_user_ns, globalreal));
+	if (user == NULL)
+		goto skipit;
 
-	return;
-}
+	if (gr_process_kernel_setuid_ban(user)) {
+		/* for find_user */
+		free_uid(user);
+		return 1;
+	}
 
-static void
-do_handle_create(const struct name_entry *matchn, const struct dentry *dentry,
-		 const struct vfsmount *mnt)
-{
-	ino_t ino = dentry->d_inode->i_ino;
-	dev_t dev = __get_dev(dentry);
+	/* for find_user */
+	free_uid(user);
 
-	__do_handle_create(matchn, ino, dev);	
+skipit:
+#endif
 
-	return;
-}
+	if (unlikely(!(gr_status & GR_READY)))
+		return 0;
 
-void
-gr_handle_create(const struct dentry *dentry, const struct vfsmount *mnt)
-{
-	struct name_entry *matchn;
+	if (current->acl->mode & (GR_LEARN | GR_INHERITLEARN))
+		gr_log_learn_uid_change(real, effective, fs);
 
-	if (unlikely(!(gr_status & GR_READY)))
-		return;
+	num = current->acl->user_trans_num;
+	uidlist = current->acl->user_transitions;
 
-	preempt_disable();
-	matchn = lookup_name_entry(gr_to_filename_rbac(dentry, mnt));
+	if (uidlist == NULL)
+		return 0;
 
-	if (unlikely((unsigned long)matchn)) {
-		write_lock(&gr_inode_lock);
-		do_handle_create(matchn, dentry, mnt);
-		write_unlock(&gr_inode_lock);
+	if (!uid_valid(real)) {
+		realok = 1;
+		globalreal = (uid_t)-1;		
+	} else {
+		globalreal = GR_GLOBAL_UID(real);		
+	}
+	if (!uid_valid(effective)) {
+		effectiveok = 1;
+		globaleffective = (uid_t)-1;
+	} else {
+		globaleffective = GR_GLOBAL_UID(effective);
+	}
+	if (!uid_valid(fs)) {
+		fsok = 1;
+		globalfs = (uid_t)-1;
+	} else {
+		globalfs = GR_GLOBAL_UID(fs);
 	}
-	preempt_enable();
 
-	return;
+	if (current->acl->user_trans_type & GR_ID_ALLOW) {
+		for (i = 0; i < num; i++) {
+			curuid = uidlist[i];
+			if (globalreal == curuid)
+				realok = 1;
+			if (globaleffective == curuid)
+				effectiveok = 1;
+			if (globalfs == curuid)
+				fsok = 1;
+		}
+	} else if (current->acl->user_trans_type & GR_ID_DENY) {
+		for (i = 0; i < num; i++) {
+			curuid = uidlist[i];
+			if (globalreal == curuid)
+				break;
+			if (globaleffective == curuid)
+				break;
+			if (globalfs == curuid)
+				break;
+		}
+		/* not in deny list */
+		if (i == num) {
+			realok = 1;
+			effectiveok = 1;
+			fsok = 1;
+		}
+	}
+
+	if (realok && effectiveok && fsok)
+		return 0;
+	else {
+		gr_log_int(GR_DONT_AUDIT, GR_USRCHANGE_ACL_MSG, realok ? (effectiveok ? (fsok ? 0 : globalfs) : globaleffective) : globalreal);
+		return 1;
+	}
 }
 
-void
-gr_handle_proc_create(const struct dentry *dentry, const struct inode *inode)
+int
+gr_check_group_change(kgid_t real, kgid_t effective, kgid_t fs)
 {
-	struct name_entry *matchn;
+	unsigned int i;
+	__u16 num;
+	gid_t *gidlist;
+	gid_t curgid;
+	int realok = 0;
+	int effectiveok = 0;
+	int fsok = 0;
+	gid_t globalreal, globaleffective, globalfs;
 
 	if (unlikely(!(gr_status & GR_READY)))
-		return;
+		return 0;
 
-	preempt_disable();
-	matchn = lookup_name_entry(gr_to_proc_filename_rbac(dentry, init_pid_ns.proc_mnt));
+	if (current->acl->mode & (GR_LEARN | GR_INHERITLEARN))
+		gr_log_learn_gid_change(real, effective, fs);
 
-	if (unlikely((unsigned long)matchn)) {
-		write_lock(&gr_inode_lock);
-		__do_handle_create(matchn, inode->i_ino, inode->i_sb->s_dev);
-		write_unlock(&gr_inode_lock);
+	num = current->acl->group_trans_num;
+	gidlist = current->acl->group_transitions;
+
+	if (gidlist == NULL)
+		return 0;
+
+	if (!gid_valid(real)) {
+		realok = 1;
+		globalreal = (gid_t)-1;		
+	} else {
+		globalreal = GR_GLOBAL_GID(real);
+	}
+	if (!gid_valid(effective)) {
+		effectiveok = 1;
+		globaleffective = (gid_t)-1;		
+	} else {
+		globaleffective = GR_GLOBAL_GID(effective);
+	}
+	if (!gid_valid(fs)) {
+		fsok = 1;
+		globalfs = (gid_t)-1;		
+	} else {
+		globalfs = GR_GLOBAL_GID(fs);
 	}
-	preempt_enable();
 
-	return;
+	if (current->acl->group_trans_type & GR_ID_ALLOW) {
+		for (i = 0; i < num; i++) {
+			curgid = gidlist[i];
+			if (globalreal == curgid)
+				realok = 1;
+			if (globaleffective == curgid)
+				effectiveok = 1;
+			if (globalfs == curgid)
+				fsok = 1;
+		}
+	} else if (current->acl->group_trans_type & GR_ID_DENY) {
+		for (i = 0; i < num; i++) {
+			curgid = gidlist[i];
+			if (globalreal == curgid)
+				break;
+			if (globaleffective == curgid)
+				break;
+			if (globalfs == curgid)
+				break;
+		}
+		/* not in deny list */
+		if (i == num) {
+			realok = 1;
+			effectiveok = 1;
+			fsok = 1;
+		}
+	}
+
+	if (realok && effectiveok && fsok)
+		return 0;
+	else {
+		gr_log_int(GR_DONT_AUDIT, GR_GRPCHANGE_ACL_MSG, realok ? (effectiveok ? (fsok ? 0 : globalfs) : globaleffective) : globalreal);
+		return 1;
+	}
 }
 
+extern int gr_acl_is_capable(const int cap);
+
 void
-gr_handle_rename(struct inode *old_dir, struct inode *new_dir,
-		 struct dentry *old_dentry,
-		 struct dentry *new_dentry,
-		 struct vfsmount *mnt, const __u8 replace)
+gr_set_role_label(struct task_struct *task, const kuid_t kuid, const kgid_t kgid)
 {
-	struct name_entry *matchn;
-	struct inodev_entry *inodev;
-	struct inode *inode = new_dentry->d_inode;
-	ino_t old_ino = old_dentry->d_inode->i_ino;
-	dev_t old_dev = __get_dev(old_dentry);
-
-	/* vfs_rename swaps the name and parent link for old_dentry and
-	   new_dentry
-	   at this point, old_dentry has the new name, parent link, and inode
-	   for the renamed file
-	   if a file is being replaced by a rename, new_dentry has the inode
-	   and name for the replaced file
-	*/
+	struct acl_role_label *role = task->role;
+	struct acl_subject_label *subj = NULL;
+	struct acl_object_label *obj;
+	struct file *filp;
+	uid_t uid;
+	gid_t gid;
 
 	if (unlikely(!(gr_status & GR_READY)))
 		return;
 
-	preempt_disable();
-	matchn = lookup_name_entry(gr_to_filename_rbac(old_dentry, mnt));
-
-	/* we wouldn't have to check d_inode if it weren't for
-	   NFS silly-renaming
-	 */
-
-	write_lock(&gr_inode_lock);
-	if (unlikely(replace && inode)) {
-		ino_t new_ino = inode->i_ino;
-		dev_t new_dev = __get_dev(new_dentry);
-
-		inodev = lookup_inodev_entry(new_ino, new_dev);
-		if (inodev != NULL && ((inode->i_nlink <= 1) || S_ISDIR(inode->i_mode)))
-			do_handle_delete(inodev, new_ino, new_dev);
-	}
-
-	inodev = lookup_inodev_entry(old_ino, old_dev);
-	if (inodev != NULL && ((old_dentry->d_inode->i_nlink <= 1) || S_ISDIR(old_dentry->d_inode->i_mode)))
-		do_handle_delete(inodev, old_ino, old_dev);
-
-	if (unlikely((unsigned long)matchn))
-		do_handle_create(matchn, old_dentry, mnt);
+	uid = GR_GLOBAL_UID(kuid);
+	gid = GR_GLOBAL_GID(kgid);
 
-	write_unlock(&gr_inode_lock);
-	preempt_enable();
+	filp = task->exec_file;
 
-	return;
-}
+	/* kernel process, we'll give them the kernel role */
+	if (unlikely(!filp)) {
+		task->role = running_polstate.kernel_role;
+		task->acl = running_polstate.kernel_role->root_label;
+		return;
+	} else if (!task->role || !(task->role->roletype & GR_ROLE_SPECIAL))
+		role = lookup_acl_role_label(task, uid, gid);
 
-static int
-lookup_special_role_auth(__u16 mode, const char *rolename, unsigned char **salt,
-			 unsigned char **sum)
-{
-	struct acl_role_label *r;
-	struct role_allowed_ip *ipp;
-	struct role_transition *trans;
-	unsigned int i;
-	int found = 0;
-	u32 curr_ip = current->signal->curr_ip;
+	/* don't change the role if we're not a privileged process */
+	if (role && task->role != role &&
+	    (((role->roletype & GR_ROLE_USER) && !gr_acl_is_capable(CAP_SETUID)) ||
+	     ((role->roletype & GR_ROLE_GROUP) && !gr_acl_is_capable(CAP_SETGID))))
+		return;
 
-	current->signal->saved_ip = curr_ip;
+	/* perform subject lookup in possibly new role
+	   we can use this result below in the case where role == task->role
+	*/
+	subj = chk_subj_label(filp->f_path.dentry, filp->f_path.mnt, role);
 
-	/* check transition table */
+	/* if we changed uid/gid, but result in the same role
+	   and are using inheritance, don't lose the inherited subject
+	   if current subject is other than what normal lookup
+	   would result in, we arrived via inheritance, don't
+	   lose subject
+	*/
+	if (role != task->role || (!(task->acl->mode & GR_INHERITLEARN) &&
+				   (subj == task->acl)))
+		task->acl = subj;
 
-	for (trans = current->role->transitions; trans; trans = trans->next) {
-		if (!strcmp(rolename, trans->rolename)) {
-			found = 1;
-			break;
-		}
-	}
+	/* leave task->inherited unaffected */
 
-	if (!found)
-		return 0;
+	task->role = role;
 
-	/* handle special roles that do not require authentication
-	   and check ip */
+	task->is_writable = 0;
 
-	FOR_EACH_ROLE_START(r)
-		if (!strcmp(rolename, r->rolename) &&
-		    (r->roletype & GR_ROLE_SPECIAL)) {
-			found = 0;
-			if (r->allowed_ips != NULL) {
-				for (ipp = r->allowed_ips; ipp; ipp = ipp->next) {
-					if ((ntohl(curr_ip) & ipp->netmask) ==
-					     (ntohl(ipp->addr) & ipp->netmask))
-						found = 1;
-				}
-			} else
-				found = 2;
-			if (!found)
-				return 0;
+	/* ignore additional mmap checks for processes that are writable 
+	   by the default ACL */
+	obj = chk_obj_label(filp->f_path.dentry, filp->f_path.mnt, running_polstate.default_role->root_label);
+	if (unlikely(obj->mode & GR_WRITE))
+		task->is_writable = 1;
+	obj = chk_obj_label(filp->f_path.dentry, filp->f_path.mnt, task->role->root_label);
+	if (unlikely(obj->mode & GR_WRITE))
+		task->is_writable = 1;
 
-			if (((mode == GR_SPROLE) && (r->roletype & GR_ROLE_NOPW)) ||
-			    ((mode == GR_SPROLEPAM) && (r->roletype & GR_ROLE_PAM))) {
-				*salt = NULL;
-				*sum = NULL;
-				return 1;
-			}
-		}
-	FOR_EACH_ROLE_END(r)
+#ifdef CONFIG_GRKERNSEC_RBAC_DEBUG
+	printk(KERN_ALERT "Set role label for (%s:%d): role:%s, subject:%s\n", task->comm, task_pid_nr(task), task->role->rolename, task->acl->filename);
+#endif
 
-	for (i = 0; i < num_sprole_pws; i++) {
-		if (!strcmp(rolename, acl_special_roles[i]->rolename)) {
-			*salt = acl_special_roles[i]->salt;
-			*sum = acl_special_roles[i]->sum;
-			return 1;
-		}
-	}
+	gr_set_proc_res(task);
 
-	return 0;
+	return;
 }
 
-static void
-assign_special_role(char *rolename)
+int
+gr_set_proc_label(const struct dentry *dentry, const struct vfsmount *mnt,
+		  const int unsafe_flags)
 {
+	struct task_struct *task = current;
+	struct acl_subject_label *newacl;
 	struct acl_object_label *obj;
-	struct acl_role_label *r;
-	struct acl_role_label *assigned = NULL;
-	struct task_struct *tsk;
-	struct file *filp;
+	__u32 retmode;
 
-	FOR_EACH_ROLE_START(r)
-		if (!strcmp(rolename, r->rolename) &&
-		    (r->roletype & GR_ROLE_SPECIAL)) {
-			assigned = r;
-			break;
-		}
-	FOR_EACH_ROLE_END(r)
+	if (unlikely(!(gr_status & GR_READY)))
+		return 0;
 
-	if (!assigned)
-		return;
+	newacl = chk_subj_label(dentry, mnt, task->role);
 
+	/* special handling for if we did an strace -f -p <pid> from an admin role, where pid then
+	   did an exec
+	*/
+	rcu_read_lock();
 	read_lock(&tasklist_lock);
-	read_lock(&grsec_exec_file_lock);
+	if (task->ptrace && task->parent && ((task->parent->role->roletype & GR_ROLE_GOD) ||
+	    (task->parent->acl->mode & GR_POVERRIDE))) {
+		read_unlock(&tasklist_lock);
+		rcu_read_unlock();
+		goto skip_check;
+	}
+	read_unlock(&tasklist_lock);
+	rcu_read_unlock();
 
-	tsk = current->real_parent;
-	if (tsk == NULL)
-		goto out_unlock;
+	if (unsafe_flags && !(task->acl->mode & GR_POVERRIDE) && (task->acl != newacl) &&
+	     !(task->role->roletype & GR_ROLE_GOD) &&
+	     !gr_search_file(dentry, GR_PTRACERD, mnt) &&
+	     !(task->acl->mode & (GR_LEARN | GR_INHERITLEARN))) {
+		if (unsafe_flags & LSM_UNSAFE_SHARE)
+			gr_log_fs_generic(GR_DONT_AUDIT, GR_UNSAFESHARE_EXEC_ACL_MSG, dentry, mnt);
+		else
+			gr_log_fs_generic(GR_DONT_AUDIT, GR_PTRACE_EXEC_ACL_MSG, dentry, mnt);
+		return -EACCES;
+	}
 
-	filp = tsk->exec_file;
-	if (filp == NULL)
-		goto out_unlock;
+skip_check:
 
-	tsk->is_writable = 0;
+	obj = chk_obj_label(dentry, mnt, task->acl);
+	retmode = obj->mode & (GR_INHERIT | GR_AUDIT_INHERIT);
 
-	tsk->acl_sp_role = 1;
-	tsk->acl_role_id = ++acl_sp_role_value;
-	tsk->role = assigned;
-	tsk->acl = chk_subj_label(filp->f_path.dentry, filp->f_path.mnt, tsk->role);
+	if (!(task->acl->mode & GR_INHERITLEARN) &&
+	    ((newacl->mode & GR_LEARN) || !(retmode & GR_INHERIT))) {
+		if (obj->nested)
+			task->acl = obj->nested;
+		else
+			task->acl = newacl;
+		task->inherited = 0;
+	} else {
+		task->inherited = 1;
+		if (retmode & GR_INHERIT && retmode & GR_AUDIT_INHERIT)
+			gr_log_str_fs(GR_DO_AUDIT, GR_INHERIT_ACL_MSG, task->acl->filename, dentry, mnt);
+	}
+
+	task->is_writable = 0;
 
 	/* ignore additional mmap checks for processes that are writable 
 	   by the default ACL */
-	obj = chk_obj_label(filp->f_path.dentry, filp->f_path.mnt, default_role->root_label);
+	obj = chk_obj_label(dentry, mnt, running_polstate.default_role->root_label);
 	if (unlikely(obj->mode & GR_WRITE))
-		tsk->is_writable = 1;
-	obj = chk_obj_label(filp->f_path.dentry, filp->f_path.mnt, tsk->role->root_label);
+		task->is_writable = 1;
+	obj = chk_obj_label(dentry, mnt, task->role->root_label);
 	if (unlikely(obj->mode & GR_WRITE))
-		tsk->is_writable = 1;
+		task->is_writable = 1;
+
+	gr_set_proc_res(task);
 
 #ifdef CONFIG_GRKERNSEC_RBAC_DEBUG
-	printk(KERN_ALERT "Assigning special role:%s subject:%s to process (%s:%d)\n", tsk->role->rolename, tsk->acl->filename, tsk->comm, task_pid_nr(tsk));
+	printk(KERN_ALERT "Set subject label for (%s:%d): role:%s, subject:%s\n", task->comm, task_pid_nr(task), task->role->rolename, task->acl->filename);
 #endif
-
-out_unlock:
-	read_unlock(&grsec_exec_file_lock);
-	read_unlock(&tasklist_lock);
-	return;
+	return 0;
 }
 
-int gr_check_secure_terminal(struct task_struct *task)
+/* always called with valid inodev ptr */
+static void
+do_handle_delete(struct inodev_entry *inodev, const ino_t ino, const dev_t dev)
 {
-	struct task_struct *p, *p2, *p3;
-	struct files_struct *files;
-	struct fdtable *fdt;
-	struct file *our_file = NULL, *file;
-	int i;
+	struct acl_object_label *matchpo;
+	struct acl_subject_label *matchps;
+	struct acl_subject_label *subj;
+	struct acl_role_label *role;
+	unsigned int x;
 
-	if (task->signal->tty == NULL)
-		return 1;
+	FOR_EACH_ROLE_START(role)
+		FOR_EACH_SUBJECT_START(role, subj, x)
+			if ((matchpo = lookup_acl_obj_label(ino, dev, subj)) != NULL)
+				matchpo->mode |= GR_DELETED;
+		FOR_EACH_SUBJECT_END(subj,x)
+		FOR_EACH_NESTED_SUBJECT_START(role, subj)
+			/* nested subjects aren't in the role's subj_hash table */
+			if ((matchpo = lookup_acl_obj_label(ino, dev, subj)) != NULL)
+				matchpo->mode |= GR_DELETED;
+		FOR_EACH_NESTED_SUBJECT_END(subj)
+		if ((matchps = lookup_acl_subj_label(ino, dev, role)) != NULL)
+			matchps->mode |= GR_DELETED;
+	FOR_EACH_ROLE_END(role)
 
-	files = get_files_struct(task);
-	if (files != NULL) {
-		rcu_read_lock();
-		fdt = files_fdtable(files);
-		for (i=0; i < fdt->max_fds; i++) {
-			file = fcheck_files(files, i);
-			if (file && (our_file == NULL) && (file->private_data == task->signal->tty)) {
-				get_file(file);
-				our_file = file;
-			}
-		}
-		rcu_read_unlock();
-		put_files_struct(files);
-	}
+	inodev->nentry->deleted = 1;
 
-	if (our_file == NULL)
-		return 1;
+	return;
+}
 
-	read_lock(&tasklist_lock);
-	do_each_thread(p2, p) {
-		files = get_files_struct(p);
-		if (files == NULL ||
-		    (p->signal && p->signal->tty == task->signal->tty)) {
-			if (files != NULL)
-				put_files_struct(files);
-			continue;
-		}
-		rcu_read_lock();
-		fdt = files_fdtable(files);
-		for (i=0; i < fdt->max_fds; i++) {
-			file = fcheck_files(files, i);
-			if (file && S_ISCHR(file->f_path.dentry->d_inode->i_mode) &&
-			    file->f_path.dentry->d_inode->i_rdev == our_file->f_path.dentry->d_inode->i_rdev) {
-				p3 = task;
-				while (task_pid_nr(p3) > 0) {
-					if (p3 == p)
-						break;
-					p3 = p3->real_parent;
-				}
-				if (p3 == p)
-					break;
-				gr_log_ttysniff(GR_DONT_AUDIT_GOOD, GR_TTYSNIFF_ACL_MSG, p);
-				gr_handle_alertkill(p);
-				rcu_read_unlock();
-				put_files_struct(files);
-				read_unlock(&tasklist_lock);
-				fput(our_file);
-				return 0;
-			}
-		}
-		rcu_read_unlock();
-		put_files_struct(files);
-	} while_each_thread(p2, p);
-	read_unlock(&tasklist_lock);
+void
+gr_handle_delete(const ino_t ino, const dev_t dev)
+{
+	struct inodev_entry *inodev;
 
-	fput(our_file);
-	return 1;
+	if (unlikely(!(gr_status & GR_READY)))
+		return;
+
+	write_lock(&gr_inode_lock);
+	inodev = lookup_inodev_entry(ino, dev);
+	if (inodev != NULL)
+		do_handle_delete(inodev, ino, dev);
+	write_unlock(&gr_inode_lock);
+
+	return;
 }
 
-static int gr_rbac_disable(void *unused)
+static void
+update_acl_obj_label(const ino_t oldinode, const dev_t olddevice,
+		     const ino_t newinode, const dev_t newdevice,
+		     struct acl_subject_label *subj)
 {
-	pax_open_kernel();
-	gr_status &= ~GR_READY;
-	pax_close_kernel();
+	unsigned int index = gr_fhash(oldinode, olddevice, subj->obj_hash_size);
+	struct acl_object_label *match;
 
-	return 0;
+	match = subj->obj_hash[index];
+
+	while (match && (match->inode != oldinode ||
+	       match->device != olddevice ||
+	       !(match->mode & GR_DELETED)))
+		match = match->next;
+
+	if (match && (match->inode == oldinode)
+	    && (match->device == olddevice)
+	    && (match->mode & GR_DELETED)) {
+		if (match->prev == NULL) {
+			subj->obj_hash[index] = match->next;
+			if (match->next != NULL)
+				match->next->prev = NULL;
+		} else {
+			match->prev->next = match->next;
+			if (match->next != NULL)
+				match->next->prev = match->prev;
+		}
+		match->prev = NULL;
+		match->next = NULL;
+		match->inode = newinode;
+		match->device = newdevice;
+		match->mode &= ~GR_DELETED;
+
+		insert_acl_obj_label(match, subj);
+	}
+
+	return;
 }
 
-ssize_t
-write_grsec_handler(struct file *file, const char __user * buf, size_t count, loff_t *ppos)
+static void
+update_acl_subj_label(const ino_t oldinode, const dev_t olddevice,
+		      const ino_t newinode, const dev_t newdevice,
+		      struct acl_role_label *role)
 {
-	struct gr_arg_wrapper uwrap;
-	unsigned char *sprole_salt = NULL;
-	unsigned char *sprole_sum = NULL;
-	int error = 0;
-	int error2 = 0;
-	size_t req_count = 0;
-
-	mutex_lock(&gr_dev_mutex);
+	unsigned int index = gr_fhash(oldinode, olddevice, role->subj_hash_size);
+	struct acl_subject_label *match;
 
-	if ((gr_status & GR_READY) && !(current->acl->mode & GR_KERNELAUTH)) {
-		error = -EPERM;
-		goto out;
-	}
+	match = role->subj_hash[index];
 
-#ifdef CONFIG_COMPAT
-	pax_open_kernel();
-	if (is_compat_task()) {
-		copy_gr_arg_wrapper = &copy_gr_arg_wrapper_compat;
-		copy_gr_arg = &copy_gr_arg_compat;
-		copy_acl_object_label = &copy_acl_object_label_compat;
-		copy_acl_subject_label = &copy_acl_subject_label_compat;
-		copy_acl_role_label = &copy_acl_role_label_compat;
-		copy_acl_ip_label = &copy_acl_ip_label_compat;
-		copy_role_allowed_ip = &copy_role_allowed_ip_compat;
-		copy_role_transition = &copy_role_transition_compat;
-		copy_sprole_pw = &copy_sprole_pw_compat;
-		copy_gr_hash_struct = &copy_gr_hash_struct_compat;
-		copy_pointer_from_array = &copy_pointer_from_array_compat;
-		get_gr_arg_wrapper_size = &get_gr_arg_wrapper_size_compat;
-	} else {
-		copy_gr_arg_wrapper = &copy_gr_arg_wrapper_normal;
-		copy_gr_arg = &copy_gr_arg_normal;
-		copy_acl_object_label = &copy_acl_object_label_normal;
-		copy_acl_subject_label = &copy_acl_subject_label_normal;
-		copy_acl_role_label = &copy_acl_role_label_normal;
-		copy_acl_ip_label = &copy_acl_ip_label_normal;
-		copy_role_allowed_ip = &copy_role_allowed_ip_normal;
-		copy_role_transition = &copy_role_transition_normal;
-		copy_sprole_pw = &copy_sprole_pw_normal;
-		copy_gr_hash_struct = &copy_gr_hash_struct_normal;
-		copy_pointer_from_array = &copy_pointer_from_array_normal;
-		get_gr_arg_wrapper_size = &get_gr_arg_wrapper_size_normal;
-	}
-	pax_close_kernel();
-#endif
+	while (match && (match->inode != oldinode ||
+	       match->device != olddevice ||
+	       !(match->mode & GR_DELETED)))
+		match = match->next;
 
-	req_count = get_gr_arg_wrapper_size();
+	if (match && (match->inode == oldinode)
+	    && (match->device == olddevice)
+	    && (match->mode & GR_DELETED)) {
+		if (match->prev == NULL) {
+			role->subj_hash[index] = match->next;
+			if (match->next != NULL)
+				match->next->prev = NULL;
+		} else {
+			match->prev->next = match->next;
+			if (match->next != NULL)
+				match->next->prev = match->prev;
+		}
+		match->prev = NULL;
+		match->next = NULL;
+		match->inode = newinode;
+		match->device = newdevice;
+		match->mode &= ~GR_DELETED;
 
-	if (count != req_count) {
-		gr_log_int_int(GR_DONT_AUDIT_GOOD, GR_DEV_ACL_MSG, (int)count, (int)req_count);
-		error = -EINVAL;
-		goto out;
+		insert_acl_subj_label(match, role);
 	}
 
-	
-	if (gr_auth_expires && time_after_eq(get_seconds(), gr_auth_expires)) {
-		gr_auth_expires = 0;
-		gr_auth_attempts = 0;
-	}
+	return;
+}
 
-	error = copy_gr_arg_wrapper(buf, &uwrap);
-	if (error)
-		goto out;
+static void
+update_inodev_entry(const ino_t oldinode, const dev_t olddevice,
+		    const ino_t newinode, const dev_t newdevice)
+{
+	unsigned int index = gr_fhash(oldinode, olddevice, running_polstate.inodev_set.i_size);
+	struct inodev_entry *match;
 
-	error = copy_gr_arg(uwrap.arg, gr_usermode);
-	if (error)
-		goto out;
+	match = running_polstate.inodev_set.i_hash[index];
 
-	if (gr_usermode->mode != GR_SPROLE && gr_usermode->mode != GR_SPROLEPAM &&
-	    gr_auth_attempts >= CONFIG_GRKERNSEC_ACL_MAXTRIES &&
-	    time_after(gr_auth_expires, get_seconds())) {
-		error = -EBUSY;
-		goto out;
-	}
+	while (match && (match->nentry->inode != oldinode ||
+	       match->nentry->device != olddevice || !match->nentry->deleted))
+		match = match->next;
 
-	/* if non-root trying to do anything other than use a special role,
-	   do not attempt authentication, do not count towards authentication
-	   locking
-	 */
+	if (match && (match->nentry->inode == oldinode)
+	    && (match->nentry->device == olddevice) &&
+	    match->nentry->deleted) {
+		if (match->prev == NULL) {
+			running_polstate.inodev_set.i_hash[index] = match->next;
+			if (match->next != NULL)
+				match->next->prev = NULL;
+		} else {
+			match->prev->next = match->next;
+			if (match->next != NULL)
+				match->next->prev = match->prev;
+		}
+		match->prev = NULL;
+		match->next = NULL;
+		match->nentry->inode = newinode;
+		match->nentry->device = newdevice;
+		match->nentry->deleted = 0;
 
-	if (gr_usermode->mode != GR_SPROLE && gr_usermode->mode != GR_STATUS &&
-	    gr_usermode->mode != GR_UNSPROLE && gr_usermode->mode != GR_SPROLEPAM &&
-	    gr_is_global_nonroot(current_uid())) {
-		error = -EPERM;
-		goto out;
+		insert_inodev_entry(match);
 	}
 
-	/* ensure pw and special role name are null terminated */
+	return;
+}
 
-	gr_usermode->pw[GR_PW_LEN - 1] = '\0';
-	gr_usermode->sp_role[GR_SPROLE_LEN - 1] = '\0';
+static void
+__do_handle_create(const struct name_entry *matchn, ino_t ino, dev_t dev)
+{
+	struct acl_subject_label *subj;
+	struct acl_role_label *role;
+	unsigned int x;
 
-	/* Okay. 
-	 * We have our enough of the argument structure..(we have yet
-	 * to copy_from_user the tables themselves) . Copy the tables
-	 * only if we need them, i.e. for loading operations. */
+	FOR_EACH_ROLE_START(role)
+		update_acl_subj_label(matchn->inode, matchn->device, ino, dev, role);
 
-	switch (gr_usermode->mode) {
-	case GR_STATUS:
-			if (gr_status & GR_READY) {
-				error = 1;
-				if (!gr_check_secure_terminal(current))
-					error = 3;
-			} else
-				error = 2;
-			goto out;
-	case GR_SHUTDOWN:
-		if ((gr_status & GR_READY)
-		    && !(chkpw(gr_usermode, gr_system_salt, gr_system_sum))) {
-			stop_machine(gr_rbac_disable, NULL, NULL);
-			free_variables();
-			memset(gr_usermode, 0, sizeof (struct gr_arg));
-			memset(gr_system_salt, 0, GR_SALT_LEN);
-			memset(gr_system_sum, 0, GR_SHA_LEN);
-			gr_log_noargs(GR_DONT_AUDIT_GOOD, GR_SHUTS_ACL_MSG);
-		} else if (gr_status & GR_READY) {
-			gr_log_noargs(GR_DONT_AUDIT, GR_SHUTF_ACL_MSG);
-			error = -EPERM;
-		} else {
-			gr_log_noargs(GR_DONT_AUDIT_GOOD, GR_SHUTI_ACL_MSG);
-			error = -EAGAIN;
-		}
-		break;
-	case GR_ENABLE:
-		if (!(gr_status & GR_READY) && !(error2 = gracl_init(gr_usermode)))
-			gr_log_str(GR_DONT_AUDIT_GOOD, GR_ENABLE_ACL_MSG, GR_VERSION);
-		else {
-			if (gr_status & GR_READY)
-				error = -EAGAIN;
-			else
-				error = error2;
-			gr_log_str(GR_DONT_AUDIT, GR_ENABLEF_ACL_MSG, GR_VERSION);
-		}
-		break;
-	case GR_RELOAD:
-		if (!(gr_status & GR_READY)) {
-			gr_log_str(GR_DONT_AUDIT_GOOD, GR_RELOADI_ACL_MSG, GR_VERSION);
-			error = -EAGAIN;
-		} else if (!(chkpw(gr_usermode, gr_system_salt, gr_system_sum))) {
-			stop_machine(gr_rbac_disable, NULL, NULL);
-			free_variables();
-			error2 = gracl_init(gr_usermode);
-			if (!error2)
-				gr_log_str(GR_DONT_AUDIT_GOOD, GR_RELOAD_ACL_MSG, GR_VERSION);
-			else {
-				gr_log_str(GR_DONT_AUDIT, GR_RELOADF_ACL_MSG, GR_VERSION);
-				error = error2;
+		FOR_EACH_NESTED_SUBJECT_START(role, subj)
+			if ((subj->inode == ino) && (subj->device == dev)) {
+				subj->inode = ino;
+				subj->device = dev;
 			}
-		} else {
-			gr_log_str(GR_DONT_AUDIT, GR_RELOADF_ACL_MSG, GR_VERSION);
-			error = -EPERM;
-		}
-		break;
-	case GR_SEGVMOD:
-		if (unlikely(!(gr_status & GR_READY))) {
-			gr_log_noargs(GR_DONT_AUDIT_GOOD, GR_SEGVMODI_ACL_MSG);
-			error = -EAGAIN;
-			break;
-		}
+			/* nested subjects aren't in the role's subj_hash table */
+			update_acl_obj_label(matchn->inode, matchn->device,
+					     ino, dev, subj);
+		FOR_EACH_NESTED_SUBJECT_END(subj)
+		FOR_EACH_SUBJECT_START(role, subj, x)
+			update_acl_obj_label(matchn->inode, matchn->device,
+					     ino, dev, subj);
+		FOR_EACH_SUBJECT_END(subj,x)
+	FOR_EACH_ROLE_END(role)
 
-		if (!(chkpw(gr_usermode, gr_system_salt, gr_system_sum))) {
-			gr_log_noargs(GR_DONT_AUDIT_GOOD, GR_SEGVMODS_ACL_MSG);
-			if (gr_usermode->segv_device && gr_usermode->segv_inode) {
-				struct acl_subject_label *segvacl;
-				segvacl =
-				    lookup_acl_subj_label(gr_usermode->segv_inode,
-							  gr_usermode->segv_device,
-							  current->role);
-				if (segvacl) {
-					segvacl->crashes = 0;
-					segvacl->expires = 0;
-				}
-			} else if (gr_find_uid(gr_usermode->segv_uid) >= 0) {
-				gr_remove_uid(gr_usermode->segv_uid);
-			}
-		} else {
-			gr_log_noargs(GR_DONT_AUDIT, GR_SEGVMODF_ACL_MSG);
-			error = -EPERM;
-		}
-		break;
-	case GR_SPROLE:
-	case GR_SPROLEPAM:
-		if (unlikely(!(gr_status & GR_READY))) {
-			gr_log_noargs(GR_DONT_AUDIT_GOOD, GR_SPROLEI_ACL_MSG);
-			error = -EAGAIN;
-			break;
-		}
+	update_inodev_entry(matchn->inode, matchn->device, ino, dev);
 
-		if (current->role->expires && time_after_eq(get_seconds(), current->role->expires)) {
-			current->role->expires = 0;
-			current->role->auth_attempts = 0;
-		}
+	return;
+}
 
-		if (current->role->auth_attempts >= CONFIG_GRKERNSEC_ACL_MAXTRIES &&
-		    time_after(current->role->expires, get_seconds())) {
-			error = -EBUSY;
-			goto out;
-		}
+static void
+do_handle_create(const struct name_entry *matchn, const struct dentry *dentry,
+		 const struct vfsmount *mnt)
+{
+	ino_t ino = dentry->d_inode->i_ino;
+	dev_t dev = __get_dev(dentry);
 
-		if (lookup_special_role_auth
-		    (gr_usermode->mode, gr_usermode->sp_role, &sprole_salt, &sprole_sum)
-		    && ((!sprole_salt && !sprole_sum)
-			|| !(chkpw(gr_usermode, sprole_salt, sprole_sum)))) {
-			char *p = "";
-			assign_special_role(gr_usermode->sp_role);
-			read_lock(&tasklist_lock);
-			if (current->real_parent)
-				p = current->real_parent->role->rolename;
-			read_unlock(&tasklist_lock);
-			gr_log_str_int(GR_DONT_AUDIT_GOOD, GR_SPROLES_ACL_MSG,
-					p, acl_sp_role_value);
-		} else {
-			gr_log_str(GR_DONT_AUDIT, GR_SPROLEF_ACL_MSG, gr_usermode->sp_role);
-			error = -EPERM;
-			if(!(current->role->auth_attempts++))
-				current->role->expires = get_seconds() + CONFIG_GRKERNSEC_ACL_TIMEOUT;
+	__do_handle_create(matchn, ino, dev);	
 
-			goto out;
-		}
-		break;
-	case GR_UNSPROLE:
-		if (unlikely(!(gr_status & GR_READY))) {
-			gr_log_noargs(GR_DONT_AUDIT_GOOD, GR_UNSPROLEI_ACL_MSG);
-			error = -EAGAIN;
-			break;
-		}
+	return;
+}
 
-		if (current->role->roletype & GR_ROLE_SPECIAL) {
-			char *p = "";
-			int i = 0;
+void
+gr_handle_create(const struct dentry *dentry, const struct vfsmount *mnt)
+{
+	struct name_entry *matchn;
 
-			read_lock(&tasklist_lock);
-			if (current->real_parent) {
-				p = current->real_parent->role->rolename;
-				i = current->real_parent->acl_role_id;
-			}
-			read_unlock(&tasklist_lock);
+	if (unlikely(!(gr_status & GR_READY)))
+		return;
 
-			gr_log_str_int(GR_DONT_AUDIT_GOOD, GR_UNSPROLES_ACL_MSG, p, i);
-			gr_set_acls(1);
-		} else {
-			error = -EPERM;
-			goto out;
-		}
-		break;
-	default:
-		gr_log_int(GR_DONT_AUDIT, GR_INVMODE_ACL_MSG, gr_usermode->mode);
-		error = -EINVAL;
-		break;
+	preempt_disable();
+	matchn = lookup_name_entry(gr_to_filename_rbac(dentry, mnt));
+
+	if (unlikely((unsigned long)matchn)) {
+		write_lock(&gr_inode_lock);
+		do_handle_create(matchn, dentry, mnt);
+		write_unlock(&gr_inode_lock);
 	}
+	preempt_enable();
 
-	if (error != -EPERM)
-		goto out;
+	return;
+}
+
+void
+gr_handle_proc_create(const struct dentry *dentry, const struct inode *inode)
+{
+	struct name_entry *matchn;
 
-	if(!(gr_auth_attempts++))
-		gr_auth_expires = get_seconds() + CONFIG_GRKERNSEC_ACL_TIMEOUT;
+	if (unlikely(!(gr_status & GR_READY)))
+		return;
 
-      out:
-	mutex_unlock(&gr_dev_mutex);
+	preempt_disable();
+	matchn = lookup_name_entry(gr_to_proc_filename_rbac(dentry, init_pid_ns.proc_mnt));
 
-	if (!error)
-		error = req_count;
+	if (unlikely((unsigned long)matchn)) {
+		write_lock(&gr_inode_lock);
+		__do_handle_create(matchn, inode->i_ino, inode->i_sb->s_dev);
+		write_unlock(&gr_inode_lock);
+	}
+	preempt_enable();
 
-	return error;
+	return;
 }
 
-/* must be called with
-	rcu_read_lock();
-	read_lock(&tasklist_lock);
-	read_lock(&grsec_exec_file_lock);
-*/
-int gr_apply_subject_to_task(struct task_struct *task)
+void
+gr_handle_rename(struct inode *old_dir, struct inode *new_dir,
+		 struct dentry *old_dentry,
+		 struct dentry *new_dentry,
+		 struct vfsmount *mnt, const __u8 replace)
 {
-	struct acl_object_label *obj;
-	char *tmpname;
-	struct acl_subject_label *tmpsubj;
-	struct file *filp;
-	struct name_entry *nmatch;
-
-	filp = task->exec_file;
-	if (filp == NULL)
-		return 0;
+	struct name_entry *matchn;
+	struct inodev_entry *inodev;
+	struct inode *inode = new_dentry->d_inode;
+	ino_t old_ino = old_dentry->d_inode->i_ino;
+	dev_t old_dev = __get_dev(old_dentry);
 
-	/* the following is to apply the correct subject 
-	   on binaries running when the RBAC system 
-	   is enabled, when the binaries have been 
-	   replaced or deleted since their execution
-	   -----
-	   when the RBAC system starts, the inode/dev
-	   from exec_file will be one the RBAC system
-	   is unaware of.  It only knows the inode/dev
-	   of the present file on disk, or the absence
-	   of it.
+	/* vfs_rename swaps the name and parent link for old_dentry and
+	   new_dentry
+	   at this point, old_dentry has the new name, parent link, and inode
+	   for the renamed file
+	   if a file is being replaced by a rename, new_dentry has the inode
+	   and name for the replaced file
 	*/
+
+	if (unlikely(!(gr_status & GR_READY)))
+		return;
+
 	preempt_disable();
-	tmpname = gr_to_filename_rbac(filp->f_path.dentry, filp->f_path.mnt);
-			
-	nmatch = lookup_name_entry(tmpname);
-	preempt_enable();
-	tmpsubj = NULL;
-	if (nmatch) {
-		if (nmatch->deleted)
-			tmpsubj = lookup_acl_subj_label_deleted(nmatch->inode, nmatch->device, task->role);
-		else
-			tmpsubj = lookup_acl_subj_label(nmatch->inode, nmatch->device, task->role);
-		if (tmpsubj != NULL)
-			task->acl = tmpsubj;
-	}
-	if (tmpsubj == NULL)
-		task->acl = chk_subj_label(filp->f_path.dentry, filp->f_path.mnt,
-					   task->role);
-	if (task->acl) {
-		task->is_writable = 0;
-		/* ignore additional mmap checks for processes that are writable 
-		   by the default ACL */
-		obj = chk_obj_label(filp->f_path.dentry, filp->f_path.mnt, default_role->root_label);
-		if (unlikely(obj->mode & GR_WRITE))
-			task->is_writable = 1;
-		obj = chk_obj_label(filp->f_path.dentry, filp->f_path.mnt, task->role->root_label);
-		if (unlikely(obj->mode & GR_WRITE))
-			task->is_writable = 1;
-
-		gr_set_proc_res(task);
+	matchn = lookup_name_entry(gr_to_filename_rbac(old_dentry, mnt));
 
-#ifdef CONFIG_GRKERNSEC_RBAC_DEBUG
-		printk(KERN_ALERT "gr_set_acls for (%s:%d): role:%s, subject:%s\n", task->comm, task_pid_nr(task), task->role->rolename, task->acl->filename);
-#endif
-	} else {
-		return 1;
-	}
+	/* we wouldn't have to check d_inode if it weren't for
+	   NFS silly-renaming
+	 */
 
-	return 0;
-}
+	write_lock(&gr_inode_lock);
+	if (unlikely(replace && inode)) {
+		ino_t new_ino = inode->i_ino;
+		dev_t new_dev = __get_dev(new_dentry);
 
-int
-gr_set_acls(const int type)
-{
-	struct task_struct *task, *task2;
-	struct acl_role_label *role = current->role;
-	__u16 acl_role_id = current->acl_role_id;
-	const struct cred *cred;
-	int ret;
+		inodev = lookup_inodev_entry(new_ino, new_dev);
+		if (inodev != NULL && ((inode->i_nlink <= 1) || S_ISDIR(inode->i_mode)))
+			do_handle_delete(inodev, new_ino, new_dev);
+	}
 
-	rcu_read_lock();
-	read_lock(&tasklist_lock);
-	read_lock(&grsec_exec_file_lock);
-	do_each_thread(task2, task) {
-		/* check to see if we're called from the exit handler,
-		   if so, only replace ACLs that have inherited the admin
-		   ACL */
+	inodev = lookup_inodev_entry(old_ino, old_dev);
+	if (inodev != NULL && ((old_dentry->d_inode->i_nlink <= 1) || S_ISDIR(old_dentry->d_inode->i_mode)))
+		do_handle_delete(inodev, old_ino, old_dev);
 
-		if (type && (task->role != role ||
-			     task->acl_role_id != acl_role_id))
-			continue;
+	if (unlikely((unsigned long)matchn))
+		do_handle_create(matchn, old_dentry, mnt);
 
-		task->acl_role_id = 0;
-		task->acl_sp_role = 0;
-
-		if (task->exec_file) {
-			cred = __task_cred(task);
-			task->role = lookup_acl_role_label(task, GR_GLOBAL_UID(cred->uid), GR_GLOBAL_GID(cred->gid));
-			ret = gr_apply_subject_to_task(task);
-			if (ret) {
-				read_unlock(&grsec_exec_file_lock);
-				read_unlock(&tasklist_lock);
-				rcu_read_unlock();
-				gr_log_str_int(GR_DONT_AUDIT_GOOD, GR_DEFACL_MSG, task->comm, task_pid_nr(task));
-				return ret;
-			}
-		} else {
-			// it's a kernel process
-			task->role = kernel_role;
-			task->acl = kernel_role->root_label;
-#ifdef CONFIG_GRKERNSEC_ACL_HIDEKERN
-			task->acl->mode &= ~GR_PROCFIND;
-#endif
-		}
-	} while_each_thread(task2, task);
-	read_unlock(&grsec_exec_file_lock);
-	read_unlock(&tasklist_lock);
-	rcu_read_unlock();
+	write_unlock(&gr_inode_lock);
+	preempt_enable();
 
-	return 0;
+	return;
 }
 
 #if defined(CONFIG_GRKERNSEC_RESLOG) || !defined(CONFIG_GRKERNSEC_NO_RBAC)
@@ -3894,7 +2351,7 @@ static int is_writable_mmap(const struct file *filp)
 
 	if (gr_status & GR_READY && !(task->acl->mode & GR_OVERRIDE) &&
 	    !task->is_writable && S_ISREG(filp->f_path.dentry->d_inode->i_mode) && (filp->f_path.mnt != shm_mnt || (filp->f_path.dentry->d_inode->i_nlink > 0))) {
-		obj = chk_obj_label(filp->f_path.dentry, filp->f_path.mnt, default_role->root_label);
+		obj = chk_obj_label(filp->f_path.dentry, filp->f_path.mnt, running_polstate.default_role->root_label);
 		obj2 = chk_obj_label(filp->f_path.dentry, filp->f_path.mnt,
 				     task->role->root_label);
 		if (unlikely((obj->mode & GR_WRITE) || (obj2->mode & GR_WRITE))) {
@@ -4008,15 +2465,6 @@ gr_acl_handle_psacct(struct task_struct *task, const long code)
 	return;
 }
 
-void gr_set_kernel_label(struct task_struct *task)
-{
-	if (gr_status & GR_READY) {
-		task->role = kernel_role;
-		task->acl = kernel_role->root_label;
-	}
-	return;
-}
-
 #ifdef CONFIG_TASKSTATS
 int gr_is_taskstats_denied(int pid)
 {
@@ -4170,7 +2618,6 @@ void gr_put_exec_file(struct task_struct *task)
 #ifdef CONFIG_NETFILTER_XT_MATCH_GRADM_MODULE
 EXPORT_SYMBOL(gr_acl_is_enabled);
 #endif
-EXPORT_SYMBOL(gr_set_kernel_label);
 #ifdef CONFIG_SECURITY
 EXPORT_SYMBOL(gr_check_user_change);
 EXPORT_SYMBOL(gr_check_group_change);
diff --git a/grsecurity/gracl_alloc.c b/grsecurity/gracl_alloc.c
index 34fefda..18ffbbd 100644
--- a/grsecurity/gracl_alloc.c
+++ b/grsecurity/gracl_alloc.c
@@ -5,19 +5,18 @@
 #include <linux/gracl.h>
 #include <linux/grsecurity.h>
 
-static unsigned long alloc_stack_next = 1;
-static unsigned long alloc_stack_size = 1;
-static void **alloc_stack;
+static struct gr_alloc_state __current_alloc_state = { 1, 1, NULL };
+struct gr_alloc_state *current_alloc_state = &__current_alloc_state;
 
 static __inline__ int
 alloc_pop(void)
 {
-	if (alloc_stack_next == 1)
+	if (current_alloc_state->alloc_stack_next == 1)
 		return 0;
 
-	kfree(alloc_stack[alloc_stack_next - 2]);
+	kfree(current_alloc_state->alloc_stack[current_alloc_state->alloc_stack_next - 2]);
 
-	alloc_stack_next--;
+	current_alloc_state->alloc_stack_next--;
 
 	return 1;
 }
@@ -25,12 +24,12 @@ alloc_pop(void)
 static __inline__ int
 alloc_push(void *buf)
 {
-	if (alloc_stack_next >= alloc_stack_size)
+	if (current_alloc_state->alloc_stack_next >= current_alloc_state->alloc_stack_size)
 		return 1;
 
-	alloc_stack[alloc_stack_next - 1] = buf;
+	current_alloc_state->alloc_stack[current_alloc_state->alloc_stack_next - 1] = buf;
 
-	alloc_stack_next++;
+	current_alloc_state->alloc_stack_next++;
 
 	return 0;
 }
@@ -68,21 +67,21 @@ acl_alloc_num(unsigned long num, unsigned long len)
 void
 acl_free_all(void)
 {
-	if (gr_acl_is_enabled() || !alloc_stack)
+	if (!current_alloc_state->alloc_stack)
 		return;
 
 	while (alloc_pop()) ;
 
-	if (alloc_stack) {
-		if ((alloc_stack_size * sizeof (void *)) <= PAGE_SIZE)
-			kfree(alloc_stack);
+	if (current_alloc_state->alloc_stack) {
+		if ((current_alloc_state->alloc_stack_size * sizeof (void *)) <= PAGE_SIZE)
+			kfree(current_alloc_state->alloc_stack);
 		else
-			vfree(alloc_stack);
+			vfree(current_alloc_state->alloc_stack);
 	}
 
-	alloc_stack = NULL;
-	alloc_stack_size = 1;
-	alloc_stack_next = 1;
+	current_alloc_state->alloc_stack = NULL;
+	current_alloc_state->alloc_stack_size = 1;
+	current_alloc_state->alloc_stack_next = 1;
 
 	return;
 }
@@ -91,14 +90,15 @@ int
 acl_alloc_stack_init(unsigned long size)
 {
 	if ((size * sizeof (void *)) <= PAGE_SIZE)
-		alloc_stack =
+		current_alloc_state->alloc_stack =
 		    (void **) kmalloc(size * sizeof (void *), GFP_KERNEL);
 	else
-		alloc_stack = (void **) vmalloc(size * sizeof (void *));
+		current_alloc_state->alloc_stack = (void **) vmalloc(size * sizeof (void *));
 
-	alloc_stack_size = size;
+	current_alloc_state->alloc_stack_size = size;
+	current_alloc_state->alloc_stack_next = 1;
 
-	if (!alloc_stack)
+	if (!current_alloc_state->alloc_stack)
 		return 0;
 	else
 		return 1;
diff --git a/grsecurity/gracl_compat.c b/grsecurity/gracl_compat.c
index a43dd06..ca25605 100644
--- a/grsecurity/gracl_compat.c
+++ b/grsecurity/gracl_compat.c
@@ -12,7 +12,8 @@ int copy_gr_arg_wrapper_compat(const char *buf, struct gr_arg_wrapper *uwrap)
         if (copy_from_user(&uwrapcompat, buf, sizeof(uwrapcompat)))
                 return -EFAULT;
 
-        if ((uwrapcompat.version != GRSECURITY_VERSION) ||
+        if (((uwrapcompat.version != GRSECURITY_VERSION) &&
+	     (uwrapcompat.version != 0x2901)) ||
 	    (uwrapcompat.size != sizeof(struct gr_arg_compat)))  
                 return -EINVAL;
 
diff --git a/grsecurity/gracl_policy.c b/grsecurity/gracl_policy.c
new file mode 100644
index 0000000..2d29047
--- /dev/null
+++ b/grsecurity/gracl_policy.c
@@ -0,0 +1,1838 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
+#include <linux/mount.h>
+#include <linux/tty.h>
+#include <linux/proc_fs.h>
+#include <linux/lglock.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/types.h>
+#include <linux/sysctl.h>
+#include <linux/netdevice.h>
+#include <linux/ptrace.h>
+#include <linux/gracl.h>
+#include <linux/gralloc.h>
+#include <linux/security.h>
+#include <linux/grinternal.h>
+#include <linux/pid_namespace.h>
+#include <linux/stop_machine.h>
+#include <linux/fdtable.h>
+#include <linux/percpu.h>
+#include <linux/lglock.h>
+#include <linux/hugetlb.h>
+#include <linux/posix-timers.h>
+#if defined(CONFIG_BTRFS_FS) || defined(CONFIG_BTRFS_FS_MODULE)
+#include <linux/magic.h>
+#include <linux/pagemap.h>
+#include "../fs/btrfs/async-thread.h"
+#include "../fs/btrfs/ctree.h"
+#include "../fs/btrfs/btrfs_inode.h"
+#endif
+#include "../fs/mount.h"
+
+#include <asm/uaccess.h>
+#include <asm/errno.h>
+#include <asm/mman.h>
+
+extern struct gr_policy_state *polstate;
+
+#define FOR_EACH_ROLE_START(role) \
+	role = polstate->role_list; \
+	while (role) {
+
+#define FOR_EACH_ROLE_END(role) \
+		role = role->prev; \
+	}
+
+extern struct lglock vfsmount_lock;
+
+/* for keeping track of userspace pointers used for subjects, so we
+   can share references in the kernel as well
+*/
+
+struct path gr_real_root;
+
+extern struct gr_alloc_state *current_alloc_state;
+
+u16 acl_sp_role_value;
+
+static DEFINE_MUTEX(gr_dev_mutex);
+
+extern int chkpw(struct gr_arg *entry, unsigned char *salt, unsigned char *sum);
+extern void gr_clear_learn_entries(void);
+
+static struct gr_arg gr_usermode;
+static unsigned char gr_system_salt[GR_SALT_LEN];
+static unsigned char gr_system_sum[GR_SHA_LEN];
+
+static unsigned int gr_auth_attempts = 0;
+static unsigned long gr_auth_expires = 0UL;
+
+struct acl_object_label *fakefs_obj_rw;
+struct acl_object_label *fakefs_obj_rwx;
+
+extern int gr_init_uidset(void);
+extern void gr_free_uidset(void);
+extern void gr_remove_uid(uid_t uid);
+extern int gr_find_uid(uid_t uid);
+
+extern void __gr_apply_subject_to_task(struct gr_policy_state *state, struct task_struct *task, struct acl_subject_label *subj);
+extern int gr_streq(const char *a, const char *b, const unsigned int lena, const unsigned int lenb);
+extern void __insert_inodev_entry(const struct gr_policy_state *state, struct inodev_entry *entry);
+extern struct acl_role_label *__lookup_acl_role_label(const struct gr_policy_state *state, const struct task_struct *task, const uid_t uid, const gid_t gid);
+extern void insert_acl_obj_label(struct acl_object_label *obj, struct acl_subject_label *subj);
+extern void insert_acl_subj_label(struct acl_subject_label *obj, struct acl_role_label *role);
+extern struct name_entry * __lookup_name_entry(const struct gr_policy_state *state, const char *name);
+extern char *gr_to_filename_rbac(const struct dentry *dentry, const struct vfsmount *mnt);
+extern struct acl_subject_label *lookup_acl_subj_label(const ino_t ino, const dev_t dev, const struct acl_role_label *role);
+extern struct acl_subject_label *lookup_acl_subj_label_deleted(const ino_t ino, const dev_t dev, const struct acl_role_label *role);
+extern void assign_special_role(const char *rolename);
+extern struct acl_subject_label *chk_subj_label(const struct dentry *l_dentry, const struct vfsmount *l_mnt, const struct acl_role_label *role);
+extern int gr_rbac_disable(void *unused);
+extern void gr_enable_rbac_system(void);
+
+static int copy_acl_object_label_normal(struct acl_object_label *obj, const struct acl_object_label *userp)
+{
+	if (copy_from_user(obj, userp, sizeof(struct acl_object_label)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int copy_acl_ip_label_normal(struct acl_ip_label *ip, const struct acl_ip_label *userp)
+{
+	if (copy_from_user(ip, userp, sizeof(struct acl_ip_label)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int copy_acl_subject_label_normal(struct acl_subject_label *subj, const struct acl_subject_label *userp)
+{
+	if (copy_from_user(subj, userp, sizeof(struct acl_subject_label)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int copy_acl_role_label_normal(struct acl_role_label *role, const struct acl_role_label *userp)
+{
+	if (copy_from_user(role, userp, sizeof(struct acl_role_label)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int copy_role_allowed_ip_normal(struct role_allowed_ip *roleip, const struct role_allowed_ip *userp)
+{
+	if (copy_from_user(roleip, userp, sizeof(struct role_allowed_ip)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int copy_sprole_pw_normal(struct sprole_pw *pw, unsigned long idx, const struct sprole_pw *userp)
+{
+	if (copy_from_user(pw, userp + idx, sizeof(struct sprole_pw)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int copy_gr_hash_struct_normal(struct gr_hash_struct *hash, const struct gr_hash_struct *userp)
+{
+	if (copy_from_user(hash, userp, sizeof(struct gr_hash_struct)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int copy_role_transition_normal(struct role_transition *trans, const struct role_transition *userp)
+{
+	if (copy_from_user(trans, userp, sizeof(struct role_transition)))
+		return -EFAULT;
+
+	return 0;
+}
+
+int copy_pointer_from_array_normal(void *ptr, unsigned long idx, const void *userp)
+{
+	if (copy_from_user(ptr, userp + (idx * sizeof(void *)), sizeof(void *)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int copy_gr_arg_wrapper_normal(const char __user *buf, struct gr_arg_wrapper *uwrap)
+{
+	if (copy_from_user(uwrap, buf, sizeof (struct gr_arg_wrapper)))
+		return -EFAULT;
+
+	if (((uwrap->version != GRSECURITY_VERSION) &&
+	     (uwrap->version != 0x2901)) ||
+	    (uwrap->size != sizeof(struct gr_arg)))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int copy_gr_arg_normal(const struct gr_arg __user *buf, struct gr_arg *arg)
+{
+	if (copy_from_user(arg, buf, sizeof (struct gr_arg)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static size_t get_gr_arg_wrapper_size_normal(void)
+{
+	return sizeof(struct gr_arg_wrapper);
+}
+
+#ifdef CONFIG_COMPAT
+extern int copy_gr_arg_wrapper_compat(const char *buf, struct gr_arg_wrapper *uwrap);
+extern int copy_gr_arg_compat(const struct gr_arg __user *buf, struct gr_arg *arg);
+extern int copy_acl_object_label_compat(struct acl_object_label *obj, const struct acl_object_label *userp);
+extern int copy_acl_subject_label_compat(struct acl_subject_label *subj, const struct acl_subject_label *userp);
+extern int copy_acl_role_label_compat(struct acl_role_label *role, const struct acl_role_label *userp);
+extern int copy_role_allowed_ip_compat(struct role_allowed_ip *roleip, const struct role_allowed_ip *userp);
+extern int copy_role_transition_compat(struct role_transition *trans, const struct role_transition *userp);
+extern int copy_gr_hash_struct_compat(struct gr_hash_struct *hash, const struct gr_hash_struct *userp);
+extern int copy_pointer_from_array_compat(void *ptr, unsigned long idx, const void *userp);
+extern int copy_acl_ip_label_compat(struct acl_ip_label *ip, const struct acl_ip_label *userp);
+extern int copy_sprole_pw_compat(struct sprole_pw *pw, unsigned long idx, const struct sprole_pw *userp);
+extern size_t get_gr_arg_wrapper_size_compat(void);
+
+int (* copy_gr_arg_wrapper)(const char *buf, struct gr_arg_wrapper *uwrap) __read_only;
+int (* copy_gr_arg)(const struct gr_arg *buf, struct gr_arg *arg) __read_only;
+int (* copy_acl_object_label)(struct acl_object_label *obj, const struct acl_object_label *userp) __read_only;
+int (* copy_acl_subject_label)(struct acl_subject_label *subj, const struct acl_subject_label *userp) __read_only;
+int (* copy_acl_role_label)(struct acl_role_label *role, const struct acl_role_label *userp) __read_only;
+int (* copy_acl_ip_label)(struct acl_ip_label *ip, const struct acl_ip_label *userp) __read_only;
+int (* copy_pointer_from_array)(void *ptr, unsigned long idx, const void *userp) __read_only;
+int (* copy_sprole_pw)(struct sprole_pw *pw, unsigned long idx, const struct sprole_pw *userp) __read_only;
+int (* copy_gr_hash_struct)(struct gr_hash_struct *hash, const struct gr_hash_struct *userp) __read_only;
+int (* copy_role_transition)(struct role_transition *trans, const struct role_transition *userp) __read_only;
+int (* copy_role_allowed_ip)(struct role_allowed_ip *roleip, const struct role_allowed_ip *userp) __read_only;
+size_t (* get_gr_arg_wrapper_size)(void) __read_only;
+
+#else
+#define copy_gr_arg_wrapper copy_gr_arg_wrapper_normal
+#define copy_gr_arg copy_gr_arg_normal
+#define copy_gr_hash_struct copy_gr_hash_struct_normal
+#define copy_acl_object_label copy_acl_object_label_normal
+#define copy_acl_subject_label copy_acl_subject_label_normal
+#define copy_acl_role_label copy_acl_role_label_normal
+#define copy_acl_ip_label copy_acl_ip_label_normal
+#define copy_pointer_from_array copy_pointer_from_array_normal
+#define copy_sprole_pw copy_sprole_pw_normal
+#define copy_role_transition copy_role_transition_normal
+#define copy_role_allowed_ip copy_role_allowed_ip_normal
+#define get_gr_arg_wrapper_size get_gr_arg_wrapper_size_normal
+#endif
+
+static struct acl_subject_label *
+lookup_subject_map(const struct acl_subject_label *userp)
+{
+	unsigned int index = gr_shash(userp, polstate->subj_map_set.s_size);
+	struct subject_map *match;
+
+	match = polstate->subj_map_set.s_hash[index];
+
+	while (match && match->user != userp)
+		match = match->next;
+
+	if (match != NULL)
+		return match->kernel;
+	else
+		return NULL;
+}
+
+static void
+insert_subj_map_entry(struct subject_map *subjmap)
+{
+	unsigned int index = gr_shash(subjmap->user, polstate->subj_map_set.s_size);
+	struct subject_map **curr;
+
+	subjmap->prev = NULL;
+
+	curr = &polstate->subj_map_set.s_hash[index];
+	if (*curr != NULL)
+		(*curr)->prev = subjmap;
+
+	subjmap->next = *curr;
+	*curr = subjmap;
+
+	return;
+}
+
+static void
+__insert_acl_role_label(struct acl_role_label *role, uid_t uidgid)
+{
+	unsigned int index =
+	    gr_rhash(uidgid, role->roletype & (GR_ROLE_USER | GR_ROLE_GROUP), polstate->acl_role_set.r_size);
+	struct acl_role_label **curr;
+	struct acl_role_label *tmp, *tmp2;
+
+	curr = &polstate->acl_role_set.r_hash[index];
+
+	/* simple case, slot is empty, just set it to our role */
+	if (*curr == NULL) {
+		*curr = role;
+	} else {
+		/* example:
+		   1 -> 2 -> 3 (adding 2 -> 3 to here)
+		   2 -> 3
+		*/
+		/* first check to see if we can already be reached via this slot */
+		tmp = *curr;
+		while (tmp && tmp != role)
+			tmp = tmp->next;
+		if (tmp == role) {
+			/* we don't need to add ourselves to this slot's chain */
+			return;
+		}
+		/* we need to add ourselves to this chain, two cases */
+		if (role->next == NULL) {
+			/* simple case, append the current chain to our role */
+			role->next = *curr;
+			*curr = role;
+		} else {
+			/* 1 -> 2 -> 3 -> 4
+			   2 -> 3 -> 4
+			   3 -> 4 (adding 1 -> 2 -> 3 -> 4 to here)
+			*/			   
+			/* trickier case: walk our role's chain until we find
+			   the role for the start of the current slot's chain */
+			tmp = role;
+			tmp2 = *curr;
+			while (tmp->next && tmp->next != tmp2)
+				tmp = tmp->next;
+			if (tmp->next == tmp2) {
+				/* from example above, we found 3, so just
+				   replace this slot's chain with ours */
+				*curr = role;
+			} else {
+				/* we didn't find a subset of our role's chain
+				   in the current slot's chain, so append their
+				   chain to ours, and set us as the first role in
+				   the slot's chain
+
+				   we could fold this case with the case above,
+				   but making it explicit for clarity
+				*/
+				tmp->next = tmp2;
+				*curr = role;
+			}
+		}
+	}
+
+	return;
+}
+
+static void
+insert_acl_role_label(struct acl_role_label *role)
+{
+	int i;
+
+	if (polstate->role_list == NULL) {
+		polstate->role_list = role;
+		role->prev = NULL;
+	} else {
+		role->prev = polstate->role_list;
+		polstate->role_list = role;
+	}
+	
+	/* used for hash chains */
+	role->next = NULL;
+
+	if (role->roletype & GR_ROLE_DOMAIN) {
+		for (i = 0; i < role->domain_child_num; i++)
+			__insert_acl_role_label(role, role->domain_children[i]);
+	} else
+		__insert_acl_role_label(role, role->uidgid);
+}
+					
+static int
+insert_name_entry(char *name, const ino_t inode, const dev_t device, __u8 deleted)
+{
+	struct name_entry **curr, *nentry;
+	struct inodev_entry *ientry;
+	unsigned int len = strlen(name);
+	unsigned int key = full_name_hash(name, len);
+	unsigned int index = key % polstate->name_set.n_size;
+
+	curr = &polstate->name_set.n_hash[index];
+
+	while (*curr && ((*curr)->key != key || !gr_streq((*curr)->name, name, (*curr)->len, len)))
+		curr = &((*curr)->next);
+
+	if (*curr != NULL)
+		return 1;
+
+	nentry = acl_alloc(sizeof (struct name_entry));
+	if (nentry == NULL)
+		return 0;
+	ientry = acl_alloc(sizeof (struct inodev_entry));
+	if (ientry == NULL)
+		return 0;
+	ientry->nentry = nentry;
+
+	nentry->key = key;
+	nentry->name = name;
+	nentry->inode = inode;
+	nentry->device = device;
+	nentry->len = len;
+	nentry->deleted = deleted;
+
+	nentry->prev = NULL;
+	curr = &polstate->name_set.n_hash[index];
+	if (*curr != NULL)
+		(*curr)->prev = nentry;
+	nentry->next = *curr;
+	*curr = nentry;
+
+	/* insert us into the table searchable by inode/dev */
+	__insert_inodev_entry(polstate, ientry);
+
+	return 1;
+}
+
+/* allocating chained hash tables, so optimal size is where lambda ~ 1 */
+
+static void *
+create_table(__u32 * len, int elementsize)
+{
+	unsigned int table_sizes[] = {
+		7, 13, 31, 61, 127, 251, 509, 1021, 2039, 4093, 8191, 16381,
+		32749, 65521, 131071, 262139, 524287, 1048573, 2097143,
+		4194301, 8388593, 16777213, 33554393, 67108859
+	};
+	void *newtable = NULL;
+	unsigned int pwr = 0;
+
+	while ((pwr < ((sizeof (table_sizes) / sizeof (table_sizes[0])) - 1)) &&
+	       table_sizes[pwr] <= *len)
+		pwr++;
+
+	if (table_sizes[pwr] <= *len || (table_sizes[pwr] > ULONG_MAX / elementsize))
+		return newtable;
+
+	if ((table_sizes[pwr] * elementsize) <= PAGE_SIZE)
+		newtable =
+		    kmalloc(table_sizes[pwr] * elementsize, GFP_KERNEL);
+	else
+		newtable = vmalloc(table_sizes[pwr] * elementsize);
+
+	*len = table_sizes[pwr];
+
+	return newtable;
+}
+
+static int
+init_variables(const struct gr_arg *arg, bool reload)
+{
+	struct task_struct *reaper = init_pid_ns.child_reaper;
+	unsigned int stacksize;
+
+	polstate->subj_map_set.s_size = arg->role_db.num_subjects;
+	polstate->acl_role_set.r_size = arg->role_db.num_roles + arg->role_db.num_domain_children;
+	polstate->name_set.n_size = arg->role_db.num_objects;
+	polstate->inodev_set.i_size = arg->role_db.num_objects;
+
+	if (!polstate->subj_map_set.s_size || !polstate->acl_role_set.r_size ||
+	    !polstate->name_set.n_size || !polstate->inodev_set.i_size)
+		return 1;
+
+	if (!reload) {
+		if (!gr_init_uidset())
+			return 1;
+	}
+
+	/* set up the stack that holds allocation info */
+
+	stacksize = arg->role_db.num_pointers + 5;
+
+	if (!acl_alloc_stack_init(stacksize))
+		return 1;
+
+	if (!reload) {
+		/* grab reference for the real root dentry and vfsmount */
+		get_fs_root(reaper->fs, &gr_real_root);
+	
+#ifdef CONFIG_GRKERNSEC_RBAC_DEBUG
+	printk(KERN_ALERT "Obtained real root device=%d, inode=%lu\n", __get_dev(gr_real_root.dentry), gr_real_root.dentry->d_inode->i_ino);
+#endif
+
+		fakefs_obj_rw = acl_alloc(sizeof(struct acl_object_label));
+		if (fakefs_obj_rw == NULL)
+			return 1;
+		fakefs_obj_rw->mode = GR_FIND | GR_READ | GR_WRITE;
+	
+		fakefs_obj_rwx = acl_alloc(sizeof(struct acl_object_label));
+		if (fakefs_obj_rwx == NULL)
+			return 1;
+		fakefs_obj_rwx->mode = GR_FIND | GR_READ | GR_WRITE | GR_EXEC;
+	}
+
+	polstate->subj_map_set.s_hash =
+	    (struct subject_map **) create_table(&polstate->subj_map_set.s_size, sizeof(void *));
+	polstate->acl_role_set.r_hash =
+	    (struct acl_role_label **) create_table(&polstate->acl_role_set.r_size, sizeof(void *));
+	polstate->name_set.n_hash = (struct name_entry **) create_table(&polstate->name_set.n_size, sizeof(void *));
+	polstate->inodev_set.i_hash =
+	    (struct inodev_entry **) create_table(&polstate->inodev_set.i_size, sizeof(void *));
+
+	if (!polstate->subj_map_set.s_hash || !polstate->acl_role_set.r_hash ||
+	    !polstate->name_set.n_hash || !polstate->inodev_set.i_hash)
+		return 1;
+
+	memset(polstate->subj_map_set.s_hash, 0,
+	       sizeof(struct subject_map *) * polstate->subj_map_set.s_size);
+	memset(polstate->acl_role_set.r_hash, 0,
+	       sizeof (struct acl_role_label *) * polstate->acl_role_set.r_size);
+	memset(polstate->name_set.n_hash, 0,
+	       sizeof (struct name_entry *) * polstate->name_set.n_size);
+	memset(polstate->inodev_set.i_hash, 0,
+	       sizeof (struct inodev_entry *) * polstate->inodev_set.i_size);
+
+	return 0;
+}
+
+/* free information not needed after startup
+   currently contains user->kernel pointer mappings for subjects
+*/
+
+static void
+free_init_variables(void)
+{
+	__u32 i;
+
+	if (polstate->subj_map_set.s_hash) {
+		for (i = 0; i < polstate->subj_map_set.s_size; i++) {
+			if (polstate->subj_map_set.s_hash[i]) {
+				kfree(polstate->subj_map_set.s_hash[i]);
+				polstate->subj_map_set.s_hash[i] = NULL;
+			}
+		}
+
+		if ((polstate->subj_map_set.s_size * sizeof (struct subject_map *)) <=
+		    PAGE_SIZE)
+			kfree(polstate->subj_map_set.s_hash);
+		else
+			vfree(polstate->subj_map_set.s_hash);
+	}
+
+	return;
+}
+
+static void
+free_variables(bool reload)
+{
+	struct acl_subject_label *s;
+	struct acl_role_label *r;
+	struct task_struct *task, *task2;
+	unsigned int x;
+
+	if (!reload) {
+		gr_clear_learn_entries();
+
+		read_lock(&tasklist_lock);
+		do_each_thread(task2, task) {
+			task->acl_sp_role = 0;
+			task->acl_role_id = 0;
+			task->inherited = 0;
+			task->acl = NULL;
+			task->role = NULL;
+		} while_each_thread(task2, task);
+		read_unlock(&tasklist_lock);
+
+		/* release the reference to the real root dentry and vfsmount */
+		path_put(&gr_real_root);
+		memset(&gr_real_root, 0, sizeof(gr_real_root));
+	}
+
+	/* free all object hash tables */
+
+	FOR_EACH_ROLE_START(r)
+		if (r->subj_hash == NULL)
+			goto next_role;
+		FOR_EACH_SUBJECT_START(r, s, x)
+			if (s->obj_hash == NULL)
+				break;
+			if ((s->obj_hash_size * sizeof (struct acl_object_label *)) <= PAGE_SIZE)
+				kfree(s->obj_hash);
+			else
+				vfree(s->obj_hash);
+		FOR_EACH_SUBJECT_END(s, x)
+		FOR_EACH_NESTED_SUBJECT_START(r, s)
+			if (s->obj_hash == NULL)
+				break;
+			if ((s->obj_hash_size * sizeof (struct acl_object_label *)) <= PAGE_SIZE)
+				kfree(s->obj_hash);
+			else
+				vfree(s->obj_hash);
+		FOR_EACH_NESTED_SUBJECT_END(s)
+		if ((r->subj_hash_size * sizeof (struct acl_subject_label *)) <= PAGE_SIZE)
+			kfree(r->subj_hash);
+		else
+			vfree(r->subj_hash);
+		r->subj_hash = NULL;
+next_role:
+	FOR_EACH_ROLE_END(r)
+
+	acl_free_all();
+
+	if (polstate->acl_role_set.r_hash) {
+		if ((polstate->acl_role_set.r_size * sizeof (struct acl_role_label *)) <=
+		    PAGE_SIZE)
+			kfree(polstate->acl_role_set.r_hash);
+		else
+			vfree(polstate->acl_role_set.r_hash);
+	}
+	if (polstate->name_set.n_hash) {
+		if ((polstate->name_set.n_size * sizeof (struct name_entry *)) <=
+		    PAGE_SIZE)
+			kfree(polstate->name_set.n_hash);
+		else
+			vfree(polstate->name_set.n_hash);
+	}
+
+	if (polstate->inodev_set.i_hash) {
+		if ((polstate->inodev_set.i_size * sizeof (struct inodev_entry *)) <=
+		    PAGE_SIZE)
+			kfree(polstate->inodev_set.i_hash);
+		else
+			vfree(polstate->inodev_set.i_hash);
+	}
+
+	if (!reload)
+		gr_free_uidset();
+
+	memset(&polstate->name_set, 0, sizeof (struct name_db));
+	memset(&polstate->inodev_set, 0, sizeof (struct inodev_db));
+	memset(&polstate->acl_role_set, 0, sizeof (struct acl_role_db));
+	memset(&polstate->subj_map_set, 0, sizeof (struct acl_subj_map_db));
+
+	polstate->default_role = NULL;
+	polstate->kernel_role = NULL;
+	polstate->role_list = NULL;
+
+	return;
+}
+
+static struct acl_subject_label *
+do_copy_user_subj(struct acl_subject_label *userp, struct acl_role_label *role, int *already_copied);
+
+static int alloc_and_copy_string(char **name, unsigned int maxlen)
+{
+	unsigned int len = strnlen_user(*name, maxlen);
+	char *tmp;
+
+	if (!len || len >= maxlen)
+		return -EINVAL;
+
+	if ((tmp = (char *) acl_alloc(len)) == NULL)
+		return -ENOMEM;
+
+	if (copy_from_user(tmp, *name, len))
+		return -EFAULT;
+
+	tmp[len-1] = '\0';
+	*name = tmp;
+
+	return 0;
+}
+
+static int
+copy_user_glob(struct acl_object_label *obj)
+{
+	struct acl_object_label *g_tmp, **guser;
+	int error;
+
+	if (obj->globbed == NULL)
+		return 0;
+
+	guser = &obj->globbed;
+	while (*guser) {
+		g_tmp = (struct acl_object_label *)
+			acl_alloc(sizeof (struct acl_object_label));
+		if (g_tmp == NULL)
+			return -ENOMEM;
+
+		if (copy_acl_object_label(g_tmp, *guser))
+			return -EFAULT;
+
+		error = alloc_and_copy_string(&g_tmp->filename, PATH_MAX);
+		if (error)
+			return error;
+
+		*guser = g_tmp;
+		guser = &(g_tmp->next);
+	}
+
+	return 0;
+}
+
+static int
+copy_user_objs(struct acl_object_label *userp, struct acl_subject_label *subj,
+	       struct acl_role_label *role)
+{
+	struct acl_object_label *o_tmp;
+	int ret;
+
+	while (userp) {
+		if ((o_tmp = (struct acl_object_label *)
+		     acl_alloc(sizeof (struct acl_object_label))) == NULL)
+			return -ENOMEM;
+
+		if (copy_acl_object_label(o_tmp, userp))
+			return -EFAULT;
+
+		userp = o_tmp->prev;
+
+		ret = alloc_and_copy_string(&o_tmp->filename, PATH_MAX);
+		if (ret)
+			return ret;
+
+		insert_acl_obj_label(o_tmp, subj);
+		if (!insert_name_entry(o_tmp->filename, o_tmp->inode,
+				       o_tmp->device, (o_tmp->mode & GR_DELETED) ? 1 : 0))
+			return -ENOMEM;
+
+		ret = copy_user_glob(o_tmp);
+		if (ret)
+			return ret;
+
+		if (o_tmp->nested) {
+			int already_copied;
+
+			o_tmp->nested = do_copy_user_subj(o_tmp->nested, role, &already_copied);
+			if (IS_ERR(o_tmp->nested))
+				return PTR_ERR(o_tmp->nested);
+
+			/* insert into nested subject list if we haven't copied this one yet
+			   to prevent duplicate entries */
+			if (!already_copied) {
+				o_tmp->nested->next = role->hash->first;
+				role->hash->first = o_tmp->nested;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static __u32
+count_user_subjs(struct acl_subject_label *userp)
+{
+	struct acl_subject_label s_tmp;
+	__u32 num = 0;
+
+	while (userp) {
+		if (copy_acl_subject_label(&s_tmp, userp))
+			break;
+
+		userp = s_tmp.prev;
+	}
+
+	return num;
+}
+
+static int
+copy_user_allowedips(struct acl_role_label *rolep)
+{
+	struct role_allowed_ip *ruserip, *rtmp = NULL, *rlast;
+
+	ruserip = rolep->allowed_ips;
+
+	while (ruserip) {
+		rlast = rtmp;
+
+		if ((rtmp = (struct role_allowed_ip *)
+		     acl_alloc(sizeof (struct role_allowed_ip))) == NULL)
+			return -ENOMEM;
+
+		if (copy_role_allowed_ip(rtmp, ruserip))
+			return -EFAULT;
+
+		ruserip = rtmp->prev;
+
+		if (!rlast) {
+			rtmp->prev = NULL;
+			rolep->allowed_ips = rtmp;
+		} else {
+			rlast->next = rtmp;
+			rtmp->prev = rlast;
+		}
+
+		if (!ruserip)
+			rtmp->next = NULL;
+	}
+
+	return 0;
+}
+
+static int
+copy_user_transitions(struct acl_role_label *rolep)
+{
+	struct role_transition *rusertp, *rtmp = NULL, *rlast;
+	int error;
+
+	rusertp = rolep->transitions;
+
+	while (rusertp) {
+		rlast = rtmp;
+
+		if ((rtmp = (struct role_transition *)
+		     acl_alloc(sizeof (struct role_transition))) == NULL)
+			return -ENOMEM;
+
+		if (copy_role_transition(rtmp, rusertp))
+			return -EFAULT;
+
+		rusertp = rtmp->prev;
+
+		error = alloc_and_copy_string(&rtmp->rolename, GR_SPROLE_LEN);
+		if (error)
+			return error;
+
+		if (!rlast) {
+			rtmp->prev = NULL;
+			rolep->transitions = rtmp;
+		} else {
+			rlast->next = rtmp;
+			rtmp->prev = rlast;
+		}
+
+		if (!rusertp)
+			rtmp->next = NULL;
+	}
+
+	return 0;
+}
+
+static __u32 count_user_objs(const struct acl_object_label __user *userp)
+{
+	struct acl_object_label o_tmp;
+	__u32 num = 0;
+
+	while (userp) {
+		if (copy_acl_object_label(&o_tmp, userp))
+			break;
+
+		userp = o_tmp.prev;
+		num++;
+	}
+
+	return num;
+}
+
+static struct acl_subject_label *
+do_copy_user_subj(struct acl_subject_label *userp, struct acl_role_label *role, int *already_copied)
+{
+	struct acl_subject_label *s_tmp = NULL, *s_tmp2;
+	__u32 num_objs;
+	struct acl_ip_label **i_tmp, *i_utmp2;
+	struct gr_hash_struct ghash;
+	struct subject_map *subjmap;
+	unsigned int i_num;
+	int err;
+
+	if (already_copied != NULL)
+		*already_copied = 0;
+
+	s_tmp = lookup_subject_map(userp);
+
+	/* we've already copied this subject into the kernel, just return
+	   the reference to it, and don't copy it over again
+	*/
+	if (s_tmp) {
+		if (already_copied != NULL)
+			*already_copied = 1;
+		return(s_tmp);
+	}
+
+	if ((s_tmp = (struct acl_subject_label *)
+	    acl_alloc(sizeof (struct acl_subject_label))) == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	subjmap = (struct subject_map *)kmalloc(sizeof (struct subject_map), GFP_KERNEL);
+	if (subjmap == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	subjmap->user = userp;
+	subjmap->kernel = s_tmp;
+	insert_subj_map_entry(subjmap);
+
+	if (copy_acl_subject_label(s_tmp, userp))
+		return ERR_PTR(-EFAULT);
+
+	err = alloc_and_copy_string(&s_tmp->filename, PATH_MAX);
+	if (err)
+		return ERR_PTR(err);
+
+	if (!strcmp(s_tmp->filename, "/"))
+		role->root_label = s_tmp;
+
+	if (copy_gr_hash_struct(&ghash, s_tmp->hash))
+		return ERR_PTR(-EFAULT);
+
+	/* copy user and group transition tables */
+
+	if (s_tmp->user_trans_num) {
+		uid_t *uidlist;
+
+		uidlist = (uid_t *)acl_alloc_num(s_tmp->user_trans_num, sizeof(uid_t));
+		if (uidlist == NULL)
+			return ERR_PTR(-ENOMEM);
+		if (copy_from_user(uidlist, s_tmp->user_transitions, s_tmp->user_trans_num * sizeof(uid_t)))
+			return ERR_PTR(-EFAULT);
+
+		s_tmp->user_transitions = uidlist;
+	}
+
+	if (s_tmp->group_trans_num) {
+		gid_t *gidlist;
+
+		gidlist = (gid_t *)acl_alloc_num(s_tmp->group_trans_num, sizeof(gid_t));
+		if (gidlist == NULL)
+			return ERR_PTR(-ENOMEM);
+		if (copy_from_user(gidlist, s_tmp->group_transitions, s_tmp->group_trans_num * sizeof(gid_t)))
+			return ERR_PTR(-EFAULT);
+
+		s_tmp->group_transitions = gidlist;
+	}
+
+	/* set up object hash table */
+	num_objs = count_user_objs(ghash.first);
+
+	s_tmp->obj_hash_size = num_objs;
+	s_tmp->obj_hash =
+	    (struct acl_object_label **)
+	    create_table(&(s_tmp->obj_hash_size), sizeof(void *));
+
+	if (!s_tmp->obj_hash)
+		return ERR_PTR(-ENOMEM);
+
+	memset(s_tmp->obj_hash, 0,
+	       s_tmp->obj_hash_size *
+	       sizeof (struct acl_object_label *));
+
+	/* add in objects */
+	err = copy_user_objs(ghash.first, s_tmp, role);
+
+	if (err)
+		return ERR_PTR(err);
+
+	/* set pointer for parent subject */
+	if (s_tmp->parent_subject) {
+		s_tmp2 = do_copy_user_subj(s_tmp->parent_subject, role, NULL);
+
+		if (IS_ERR(s_tmp2))
+			return s_tmp2;
+
+		s_tmp->parent_subject = s_tmp2;
+	}
+
+	/* add in ip acls */
+
+	if (!s_tmp->ip_num) {
+		s_tmp->ips = NULL;
+		goto insert;
+	}
+
+	i_tmp =
+	    (struct acl_ip_label **) acl_alloc_num(s_tmp->ip_num,
+					       sizeof (struct acl_ip_label *));
+
+	if (!i_tmp)
+		return ERR_PTR(-ENOMEM);
+
+	for (i_num = 0; i_num < s_tmp->ip_num; i_num++) {
+		*(i_tmp + i_num) =
+		    (struct acl_ip_label *)
+		    acl_alloc(sizeof (struct acl_ip_label));
+		if (!*(i_tmp + i_num))
+			return ERR_PTR(-ENOMEM);
+
+		if (copy_pointer_from_array(&i_utmp2, i_num, s_tmp->ips))
+			return ERR_PTR(-EFAULT);
+
+		if (copy_acl_ip_label(*(i_tmp + i_num), i_utmp2))
+			return ERR_PTR(-EFAULT);
+		
+		if ((*(i_tmp + i_num))->iface == NULL)
+			continue;
+
+		err = alloc_and_copy_string(&(*(i_tmp + i_num))->iface, IFNAMSIZ);
+		if (err)
+			return ERR_PTR(err);
+	}
+
+	s_tmp->ips = i_tmp;
+
+insert:
+	if (!insert_name_entry(s_tmp->filename, s_tmp->inode,
+			       s_tmp->device, (s_tmp->mode & GR_DELETED) ? 1 : 0))
+		return ERR_PTR(-ENOMEM);
+
+	return s_tmp;
+}
+
+static int
+copy_user_subjs(struct acl_subject_label *userp, struct acl_role_label *role)
+{
+	struct acl_subject_label s_pre;
+	struct acl_subject_label * ret;
+	int err;
+
+	while (userp) {
+		if (copy_acl_subject_label(&s_pre, userp))
+			return -EFAULT;
+		
+		ret = do_copy_user_subj(userp, role, NULL);
+
+		err = PTR_ERR(ret);
+		if (IS_ERR(ret))
+			return err;
+
+		insert_acl_subj_label(ret, role);
+
+		userp = s_pre.prev;
+	}
+
+	return 0;
+}
+
+static int
+copy_user_acl(struct gr_arg *arg)
+{
+	struct acl_role_label *r_tmp = NULL, **r_utmp, *r_utmp2;
+	struct acl_subject_label *subj_list;
+	struct sprole_pw *sptmp;
+	struct gr_hash_struct *ghash;
+	uid_t *domainlist;
+	unsigned int r_num;
+	int err = 0;
+	__u16 i;
+	__u32 num_subjs;
+
+	/* we need a default and kernel role */
+	if (arg->role_db.num_roles < 2)
+		return -EINVAL;
+
+	/* copy special role authentication info from userspace */
+
+	polstate->num_sprole_pws = arg->num_sprole_pws;
+	polstate->acl_special_roles = (struct sprole_pw **) acl_alloc_num(polstate->num_sprole_pws, sizeof(struct sprole_pw *));
+
+	if (!polstate->acl_special_roles && polstate->num_sprole_pws)
+		return -ENOMEM;
+
+	for (i = 0; i < polstate->num_sprole_pws; i++) {
+		sptmp = (struct sprole_pw *) acl_alloc(sizeof(struct sprole_pw));
+		if (!sptmp)
+			return -ENOMEM;
+		if (copy_sprole_pw(sptmp, i, arg->sprole_pws))
+			return -EFAULT;
+
+		err = alloc_and_copy_string((char **)&sptmp->rolename, GR_SPROLE_LEN);
+		if (err)
+			return err;
+
+#ifdef CONFIG_GRKERNSEC_RBAC_DEBUG
+		printk(KERN_ALERT "Copying special role %s\n", sptmp->rolename);
+#endif
+
+		polstate->acl_special_roles[i] = sptmp;
+	}
+
+	r_utmp = (struct acl_role_label **) arg->role_db.r_table;
+
+	for (r_num = 0; r_num < arg->role_db.num_roles; r_num++) {
+		r_tmp = acl_alloc(sizeof (struct acl_role_label));
+
+		if (!r_tmp)
+			return -ENOMEM;
+
+		if (copy_pointer_from_array(&r_utmp2, r_num, r_utmp))
+			return -EFAULT;
+
+		if (copy_acl_role_label(r_tmp, r_utmp2))
+			return -EFAULT;
+
+		err = alloc_and_copy_string(&r_tmp->rolename, GR_SPROLE_LEN);
+		if (err)
+			return err;
+
+		if (!strcmp(r_tmp->rolename, "default")
+		    && (r_tmp->roletype & GR_ROLE_DEFAULT)) {
+			polstate->default_role = r_tmp;
+		} else if (!strcmp(r_tmp->rolename, ":::kernel:::")) {
+			polstate->kernel_role = r_tmp;
+		}
+
+		if ((ghash = (struct gr_hash_struct *) acl_alloc(sizeof(struct gr_hash_struct))) == NULL)
+			return -ENOMEM;
+
+		if (copy_gr_hash_struct(ghash, r_tmp->hash))
+			return -EFAULT;
+
+		r_tmp->hash = ghash;
+
+		num_subjs = count_user_subjs(r_tmp->hash->first);
+
+		r_tmp->subj_hash_size = num_subjs;
+		r_tmp->subj_hash =
+		    (struct acl_subject_label **)
+		    create_table(&(r_tmp->subj_hash_size), sizeof(void *));
+
+		if (!r_tmp->subj_hash)
+			return -ENOMEM;
+
+		err = copy_user_allowedips(r_tmp);
+		if (err)
+			return err;
+
+		/* copy domain info */
+		if (r_tmp->domain_children != NULL) {
+			domainlist = acl_alloc_num(r_tmp->domain_child_num, sizeof(uid_t));
+			if (domainlist == NULL)
+				return -ENOMEM;
+
+			if (copy_from_user(domainlist, r_tmp->domain_children, r_tmp->domain_child_num * sizeof(uid_t)))
+				return -EFAULT;
+
+			r_tmp->domain_children = domainlist;
+		}
+
+		err = copy_user_transitions(r_tmp);
+		if (err)
+			return err;
+
+		memset(r_tmp->subj_hash, 0,
+		       r_tmp->subj_hash_size *
+		       sizeof (struct acl_subject_label *));
+
+		/* acquire the list of subjects, then NULL out
+		   the list prior to parsing the subjects for this role,
+		   as during this parsing the list is replaced with a list
+		   of *nested* subjects for the role
+		*/
+		subj_list = r_tmp->hash->first;
+
+		/* set nested subject list to null */
+		r_tmp->hash->first = NULL;
+
+		err = copy_user_subjs(subj_list, r_tmp);
+
+		if (err)
+			return err;
+
+		insert_acl_role_label(r_tmp);
+	}
+
+	if (polstate->default_role == NULL || polstate->kernel_role == NULL)
+		return -EINVAL;
+
+	return err;
+}
+
+static struct acl_subject_label *gr_get_subject_for_task(struct task_struct *task, const char *filename)
+{
+	char *tmpname;
+	struct acl_subject_label *tmpsubj;
+	struct file *filp;
+	struct name_entry *nmatch;
+
+	filp = task->exec_file;
+	if (filp == NULL)
+		return NULL;
+
+	/* the following is to apply the correct subject 
+	   on binaries running when the RBAC system 
+	   is enabled, when the binaries have been 
+	   replaced or deleted since their execution
+	   -----
+	   when the RBAC system starts, the inode/dev
+	   from exec_file will be one the RBAC system
+	   is unaware of.  It only knows the inode/dev
+	   of the present file on disk, or the absence
+	   of it.
+	*/
+
+	if (filename)
+		nmatch = __lookup_name_entry(polstate, filename);
+	else {
+		preempt_disable();
+		tmpname = gr_to_filename_rbac(filp->f_path.dentry, filp->f_path.mnt);
+			
+		nmatch = __lookup_name_entry(polstate, tmpname);
+		preempt_enable();
+	}
+	tmpsubj = NULL;
+	if (nmatch) {
+		if (nmatch->deleted)
+			tmpsubj = lookup_acl_subj_label_deleted(nmatch->inode, nmatch->device, task->role);
+		else
+			tmpsubj = lookup_acl_subj_label(nmatch->inode, nmatch->device, task->role);
+	}
+	/* this also works for the reload case -- if we don't match a potentially inherited subject
+	   then we fall back to a normal lookup based on the binary's ino/dev
+	*/
+	if (tmpsubj == NULL)
+		tmpsubj = chk_subj_label(filp->f_path.dentry, filp->f_path.mnt,
+					   task->role);
+
+	return tmpsubj;
+}
+
+static int gracl_reload_apply_policies(void *reload)
+{
+	struct gr_reload_state *reload_state = (struct gr_reload_state *)reload;
+	struct task_struct *task, *task2;
+	struct acl_role_label *role, *rtmp;
+	struct acl_subject_label *subj;
+	const struct cred *cred;
+	int role_applied;
+	int ret = 0;
+
+	memcpy(&reload_state->oldpolicy, reload_state->oldpolicy_ptr, sizeof(struct gr_reload_state));
+	memcpy(&reload_state->oldalloc, reload_state->oldalloc_ptr, sizeof(struct gr_alloc_state));
+
+	/* first make sure we'll be able to apply the new policy cleanly */
+	do_each_thread(task2, task) {
+		if (task->exec_file == NULL)
+			continue;
+		role_applied = 0;
+		if (!reload_state->oldmode && task->role->roletype & GR_ROLE_SPECIAL) {
+			/* preserve special roles */
+			FOR_EACH_ROLE_START(role)
+				if ((role->roletype & GR_ROLE_SPECIAL) && !strcmp(task->role->rolename, role->rolename)) {
+					rtmp = task->role;
+					task->role = role;
+					role_applied = 1;
+					break;
+				}
+			FOR_EACH_ROLE_END(role)
+		}
+		if (!role_applied) {
+			cred = __task_cred(task);
+			rtmp = task->role;
+			task->role = __lookup_acl_role_label(polstate, task, GR_GLOBAL_UID(cred->uid), GR_GLOBAL_GID(cred->gid));
+		}
+		/* this handles non-nested inherited subjects, nested subjects will still
+		   be dropped currently */
+		subj = gr_get_subject_for_task(task, task->acl->filename);
+		task->tmpacl = gr_get_subject_for_task(task, NULL);
+		/* change the role back so that we've made no modifications to the policy */
+		task->role = rtmp;
+
+		if (subj == NULL || task->tmpacl == NULL) {
+			ret = -EINVAL;
+			goto out;
+		}
+	} while_each_thread(task2, task);
+
+	/* now actually apply the policy */
+
+	do_each_thread(task2, task) {
+		if (task->exec_file) {
+			role_applied = 0;
+			if (!reload_state->oldmode && task->role->roletype & GR_ROLE_SPECIAL) {
+				/* preserve special roles */
+				FOR_EACH_ROLE_START(role)
+					if ((role->roletype & GR_ROLE_SPECIAL) && !strcmp(task->role->rolename, role->rolename)) {
+						task->role = role;
+						role_applied = 1;
+						break;
+					}
+				FOR_EACH_ROLE_END(role)
+			}
+			if (!role_applied) {
+				cred = __task_cred(task);
+				task->role = __lookup_acl_role_label(polstate, task, GR_GLOBAL_UID(cred->uid), GR_GLOBAL_GID(cred->gid));
+			}
+			/* this handles non-nested inherited subjects, nested subjects will still
+			   be dropped currently */
+			if (!reload_state->oldmode && task->inherited)
+				subj = gr_get_subject_for_task(task, task->acl->filename);
+			else {
+				/* looked up and tagged to the task previously */
+				subj = task->tmpacl;
+			}
+			/* subj will be non-null */
+			__gr_apply_subject_to_task(polstate, task, subj);
+			if (reload_state->oldmode) {
+				task->acl_role_id = 0;
+				task->acl_sp_role = 0;
+				task->inherited = 0;
+			}
+		} else {
+			// it's a kernel process
+			task->role = polstate->kernel_role;
+			task->acl = polstate->kernel_role->root_label;
+#ifdef CONFIG_GRKERNSEC_ACL_HIDEKERN
+			task->acl->mode &= ~GR_PROCFIND;
+#endif
+		}
+	} while_each_thread(task2, task);
+
+	memcpy(reload_state->oldpolicy_ptr, &reload_state->newpolicy, sizeof(struct gr_policy_state));
+	memcpy(reload_state->oldalloc_ptr, &reload_state->newalloc, sizeof(struct gr_alloc_state));
+
+out:
+
+	return ret;
+}
+
+static int gracl_reload(struct gr_arg *args, unsigned char oldmode)
+{
+	struct gr_reload_state new_reload_state = { };
+	int err;
+
+	new_reload_state.oldpolicy_ptr = polstate;
+	new_reload_state.oldalloc_ptr = current_alloc_state;
+	new_reload_state.oldmode = oldmode;
+
+	current_alloc_state = &new_reload_state.newalloc;
+	polstate = &new_reload_state.newpolicy;
+
+	/* everything relevant is now saved off, copy in the new policy */
+	if (init_variables(args, true)) {
+		gr_log_str(GR_DONT_AUDIT_GOOD, GR_INITF_ACL_MSG, GR_VERSION);
+		err = -ENOMEM;
+		goto error;
+	}
+
+	err = copy_user_acl(args);
+	free_init_variables();
+	if (err)
+		goto error;
+	/* the new policy is copied in, with the old policy available via saved_state
+	   first go through applying roles, making sure to preserve special roles
+	   then apply new subjects, making sure to preserve inherited and nested subjects,
+	   though currently only inherited subjects will be preserved
+	*/
+	err = stop_machine(gracl_reload_apply_policies, &new_reload_state, NULL);
+	if (err)
+		goto error;
+
+	/* we've now applied the new policy, so restore the old policy state to free it */
+	polstate = &new_reload_state.oldpolicy;
+	current_alloc_state = &new_reload_state.oldalloc;
+	free_variables(true);
+
+	/* oldpolicy/oldalloc_ptr point to the new policy/alloc states as they were copied
+	   to running_polstate/current_alloc_state inside stop_machine
+	*/
+	err = 0;
+	goto out;
+error:
+	/* on error of loading the new policy, we'll just keep the previous
+	   policy set around
+	*/
+	free_variables(true);
+
+	/* doesn't affect runtime, but maintains consistent state */
+out:
+	polstate = new_reload_state.oldpolicy_ptr;
+	current_alloc_state = new_reload_state.oldalloc_ptr;
+
+	return err;
+}
+
+static int
+gracl_init(struct gr_arg *args)
+{
+	int error = 0;
+
+	memcpy(&gr_system_salt, args->salt, sizeof(gr_system_salt));
+	memcpy(&gr_system_sum, args->sum, sizeof(gr_system_sum));
+
+	if (init_variables(args, false)) {
+		gr_log_str(GR_DONT_AUDIT_GOOD, GR_INITF_ACL_MSG, GR_VERSION);
+		error = -ENOMEM;
+		goto out;
+	}
+
+	error = copy_user_acl(args);
+	free_init_variables();
+	if (error)
+		goto out;
+
+	error = gr_set_acls(0);
+	if (error)
+		goto out;
+
+	gr_enable_rbac_system();
+
+	return 0;
+
+out:
+	free_variables(false);
+	return error;
+}
+
+static int
+lookup_special_role_auth(__u16 mode, const char *rolename, unsigned char **salt,
+			 unsigned char **sum)
+{
+	struct acl_role_label *r;
+	struct role_allowed_ip *ipp;
+	struct role_transition *trans;
+	unsigned int i;
+	int found = 0;
+	u32 curr_ip = current->signal->curr_ip;
+
+	current->signal->saved_ip = curr_ip;
+
+	/* check transition table */
+
+	for (trans = current->role->transitions; trans; trans = trans->next) {
+		if (!strcmp(rolename, trans->rolename)) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found)
+		return 0;
+
+	/* handle special roles that do not require authentication
+	   and check ip */
+
+	FOR_EACH_ROLE_START(r)
+		if (!strcmp(rolename, r->rolename) &&
+		    (r->roletype & GR_ROLE_SPECIAL)) {
+			found = 0;
+			if (r->allowed_ips != NULL) {
+				for (ipp = r->allowed_ips; ipp; ipp = ipp->next) {
+					if ((ntohl(curr_ip) & ipp->netmask) ==
+					     (ntohl(ipp->addr) & ipp->netmask))
+						found = 1;
+				}
+			} else
+				found = 2;
+			if (!found)
+				return 0;
+
+			if (((mode == GR_SPROLE) && (r->roletype & GR_ROLE_NOPW)) ||
+			    ((mode == GR_SPROLEPAM) && (r->roletype & GR_ROLE_PAM))) {
+				*salt = NULL;
+				*sum = NULL;
+				return 1;
+			}
+		}
+	FOR_EACH_ROLE_END(r)
+
+	for (i = 0; i < polstate->num_sprole_pws; i++) {
+		if (!strcmp(rolename, polstate->acl_special_roles[i]->rolename)) {
+			*salt = polstate->acl_special_roles[i]->salt;
+			*sum = polstate->acl_special_roles[i]->sum;
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+int gr_check_secure_terminal(struct task_struct *task)
+{
+	struct task_struct *p, *p2, *p3;
+	struct files_struct *files;
+	struct fdtable *fdt;
+	struct file *our_file = NULL, *file;
+	int i;
+
+	if (task->signal->tty == NULL)
+		return 1;
+
+	files = get_files_struct(task);
+	if (files != NULL) {
+		rcu_read_lock();
+		fdt = files_fdtable(files);
+		for (i=0; i < fdt->max_fds; i++) {
+			file = fcheck_files(files, i);
+			if (file && (our_file == NULL) && (file->private_data == task->signal->tty)) {
+				get_file(file);
+				our_file = file;
+			}
+		}
+		rcu_read_unlock();
+		put_files_struct(files);
+	}
+
+	if (our_file == NULL)
+		return 1;
+
+	read_lock(&tasklist_lock);
+	do_each_thread(p2, p) {
+		files = get_files_struct(p);
+		if (files == NULL ||
+		    (p->signal && p->signal->tty == task->signal->tty)) {
+			if (files != NULL)
+				put_files_struct(files);
+			continue;
+		}
+		rcu_read_lock();
+		fdt = files_fdtable(files);
+		for (i=0; i < fdt->max_fds; i++) {
+			file = fcheck_files(files, i);
+			if (file && S_ISCHR(file->f_path.dentry->d_inode->i_mode) &&
+			    file->f_path.dentry->d_inode->i_rdev == our_file->f_path.dentry->d_inode->i_rdev) {
+				p3 = task;
+				while (task_pid_nr(p3) > 0) {
+					if (p3 == p)
+						break;
+					p3 = p3->real_parent;
+				}
+				if (p3 == p)
+					break;
+				gr_log_ttysniff(GR_DONT_AUDIT_GOOD, GR_TTYSNIFF_ACL_MSG, p);
+				gr_handle_alertkill(p);
+				rcu_read_unlock();
+				put_files_struct(files);
+				read_unlock(&tasklist_lock);
+				fput(our_file);
+				return 0;
+			}
+		}
+		rcu_read_unlock();
+		put_files_struct(files);
+	} while_each_thread(p2, p);
+	read_unlock(&tasklist_lock);
+
+	fput(our_file);
+	return 1;
+}
+
+ssize_t
+write_grsec_handler(struct file *file, const char __user * buf, size_t count, loff_t *ppos)
+{
+	struct gr_arg_wrapper uwrap;
+	unsigned char *sprole_salt = NULL;
+	unsigned char *sprole_sum = NULL;
+	int error = 0;
+	int error2 = 0;
+	size_t req_count = 0;
+	unsigned char oldmode = 0;
+
+	mutex_lock(&gr_dev_mutex);
+
+	if (gr_acl_is_enabled() && !(current->acl->mode & GR_KERNELAUTH)) {
+		error = -EPERM;
+		goto out;
+	}
+
+#ifdef CONFIG_COMPAT
+	pax_open_kernel();
+	if (is_compat_task()) {
+		copy_gr_arg_wrapper = &copy_gr_arg_wrapper_compat;
+		copy_gr_arg = &copy_gr_arg_compat;
+		copy_acl_object_label = &copy_acl_object_label_compat;
+		copy_acl_subject_label = &copy_acl_subject_label_compat;
+		copy_acl_role_label = &copy_acl_role_label_compat;
+		copy_acl_ip_label = &copy_acl_ip_label_compat;
+		copy_role_allowed_ip = &copy_role_allowed_ip_compat;
+		copy_role_transition = &copy_role_transition_compat;
+		copy_sprole_pw = &copy_sprole_pw_compat;
+		copy_gr_hash_struct = &copy_gr_hash_struct_compat;
+		copy_pointer_from_array = &copy_pointer_from_array_compat;
+		get_gr_arg_wrapper_size = &get_gr_arg_wrapper_size_compat;
+	} else {
+		copy_gr_arg_wrapper = &copy_gr_arg_wrapper_normal;
+		copy_gr_arg = &copy_gr_arg_normal;
+		copy_acl_object_label = &copy_acl_object_label_normal;
+		copy_acl_subject_label = &copy_acl_subject_label_normal;
+		copy_acl_role_label = &copy_acl_role_label_normal;
+		copy_acl_ip_label = &copy_acl_ip_label_normal;
+		copy_role_allowed_ip = &copy_role_allowed_ip_normal;
+		copy_role_transition = &copy_role_transition_normal;
+		copy_sprole_pw = &copy_sprole_pw_normal;
+		copy_gr_hash_struct = &copy_gr_hash_struct_normal;
+		copy_pointer_from_array = &copy_pointer_from_array_normal;
+		get_gr_arg_wrapper_size = &get_gr_arg_wrapper_size_normal;
+	}
+	pax_close_kernel();
+#endif
+
+	req_count = get_gr_arg_wrapper_size();
+
+	if (count != req_count) {
+		gr_log_int_int(GR_DONT_AUDIT_GOOD, GR_DEV_ACL_MSG, (int)count, (int)req_count);
+		error = -EINVAL;
+		goto out;
+	}
+
+	
+	if (gr_auth_expires && time_after_eq(get_seconds(), gr_auth_expires)) {
+		gr_auth_expires = 0;
+		gr_auth_attempts = 0;
+	}
+
+	error = copy_gr_arg_wrapper(buf, &uwrap);
+	if (error)
+		goto out;
+
+	error = copy_gr_arg(uwrap.arg, &gr_usermode);
+	if (error)
+		goto out;
+
+	if (gr_usermode.mode != GR_SPROLE && gr_usermode.mode != GR_SPROLEPAM &&
+	    gr_auth_attempts >= CONFIG_GRKERNSEC_ACL_MAXTRIES &&
+	    time_after(gr_auth_expires, get_seconds())) {
+		error = -EBUSY;
+		goto out;
+	}
+
+	/* if non-root trying to do anything other than use a special role,
+	   do not attempt authentication, do not count towards authentication
+	   locking
+	 */
+
+	if (gr_usermode.mode != GR_SPROLE && gr_usermode.mode != GR_STATUS &&
+	    gr_usermode.mode != GR_UNSPROLE && gr_usermode.mode != GR_SPROLEPAM &&
+	    gr_is_global_nonroot(current_uid())) {
+		error = -EPERM;
+		goto out;
+	}
+
+	/* ensure pw and special role name are null terminated */
+
+	gr_usermode.pw[GR_PW_LEN - 1] = '\0';
+	gr_usermode.sp_role[GR_SPROLE_LEN - 1] = '\0';
+
+	/* Okay. 
+	 * We have our enough of the argument structure..(we have yet
+	 * to copy_from_user the tables themselves) . Copy the tables
+	 * only if we need them, i.e. for loading operations. */
+
+	switch (gr_usermode.mode) {
+	case GR_STATUS:
+			if (gr_acl_is_enabled()) {
+				error = 1;
+				if (!gr_check_secure_terminal(current))
+					error = 3;
+			} else
+				error = 2;
+			goto out;
+	case GR_SHUTDOWN:
+		if (gr_acl_is_enabled() && !(chkpw(&gr_usermode, (unsigned char *)&gr_system_salt, (unsigned char *)&gr_system_sum))) {
+			stop_machine(gr_rbac_disable, NULL, NULL);
+			free_variables(false);
+			memset(&gr_usermode, 0, sizeof(gr_usermode));
+			memset(&gr_system_salt, 0, sizeof(gr_system_salt));
+			memset(&gr_system_sum, 0, sizeof(gr_system_sum));
+			gr_log_noargs(GR_DONT_AUDIT_GOOD, GR_SHUTS_ACL_MSG);
+		} else if (gr_acl_is_enabled()) {
+			gr_log_noargs(GR_DONT_AUDIT, GR_SHUTF_ACL_MSG);
+			error = -EPERM;
+		} else {
+			gr_log_noargs(GR_DONT_AUDIT_GOOD, GR_SHUTI_ACL_MSG);
+			error = -EAGAIN;
+		}
+		break;
+	case GR_ENABLE:
+		if (!gr_acl_is_enabled() && !(error2 = gracl_init(&gr_usermode)))
+			gr_log_str(GR_DONT_AUDIT_GOOD, GR_ENABLE_ACL_MSG, GR_VERSION);
+		else {
+			if (gr_acl_is_enabled())
+				error = -EAGAIN;
+			else
+				error = error2;
+			gr_log_str(GR_DONT_AUDIT, GR_ENABLEF_ACL_MSG, GR_VERSION);
+		}
+		break;
+	case GR_OLDRELOAD:
+		oldmode = 1;
+	case GR_RELOAD:
+		if (!gr_acl_is_enabled()) {
+			gr_log_str(GR_DONT_AUDIT_GOOD, GR_RELOADI_ACL_MSG, GR_VERSION);
+			error = -EAGAIN;
+		} else if (!(chkpw(&gr_usermode, (unsigned char *)&gr_system_salt, (unsigned char *)&gr_system_sum))) {
+			error2 = gracl_reload(&gr_usermode, oldmode);
+			if (!error2)
+				gr_log_str(GR_DONT_AUDIT_GOOD, GR_RELOAD_ACL_MSG, GR_VERSION);
+			else {
+				gr_log_str(GR_DONT_AUDIT, GR_RELOADF_ACL_MSG, GR_VERSION);
+				error = error2;
+			}
+		} else {
+			gr_log_str(GR_DONT_AUDIT, GR_RELOADF_ACL_MSG, GR_VERSION);
+			error = -EPERM;
+		}
+		break;
+	case GR_SEGVMOD:
+		if (unlikely(!gr_acl_is_enabled())) {
+			gr_log_noargs(GR_DONT_AUDIT_GOOD, GR_SEGVMODI_ACL_MSG);
+			error = -EAGAIN;
+			break;
+		}
+
+		if (!(chkpw(&gr_usermode, (unsigned char *)&gr_system_salt, (unsigned char *)&gr_system_sum))) {
+			gr_log_noargs(GR_DONT_AUDIT_GOOD, GR_SEGVMODS_ACL_MSG);
+			if (gr_usermode.segv_device && gr_usermode.segv_inode) {
+				struct acl_subject_label *segvacl;
+				segvacl =
+				    lookup_acl_subj_label(gr_usermode.segv_inode,
+							  gr_usermode.segv_device,
+							  current->role);
+				if (segvacl) {
+					segvacl->crashes = 0;
+					segvacl->expires = 0;
+				}
+			} else if (gr_find_uid(gr_usermode.segv_uid) >= 0) {
+				gr_remove_uid(gr_usermode.segv_uid);
+			}
+		} else {
+			gr_log_noargs(GR_DONT_AUDIT, GR_SEGVMODF_ACL_MSG);
+			error = -EPERM;
+		}
+		break;
+	case GR_SPROLE:
+	case GR_SPROLEPAM:
+		if (unlikely(!gr_acl_is_enabled())) {
+			gr_log_noargs(GR_DONT_AUDIT_GOOD, GR_SPROLEI_ACL_MSG);
+			error = -EAGAIN;
+			break;
+		}
+
+		if (current->role->expires && time_after_eq(get_seconds(), current->role->expires)) {
+			current->role->expires = 0;
+			current->role->auth_attempts = 0;
+		}
+
+		if (current->role->auth_attempts >= CONFIG_GRKERNSEC_ACL_MAXTRIES &&
+		    time_after(current->role->expires, get_seconds())) {
+			error = -EBUSY;
+			goto out;
+		}
+
+		if (lookup_special_role_auth
+		    (gr_usermode.mode, gr_usermode.sp_role, &sprole_salt, &sprole_sum)
+		    && ((!sprole_salt && !sprole_sum)
+			|| !(chkpw(&gr_usermode, sprole_salt, sprole_sum)))) {
+			char *p = "";
+			assign_special_role(gr_usermode.sp_role);
+			read_lock(&tasklist_lock);
+			if (current->real_parent)
+				p = current->real_parent->role->rolename;
+			read_unlock(&tasklist_lock);
+			gr_log_str_int(GR_DONT_AUDIT_GOOD, GR_SPROLES_ACL_MSG,
+					p, acl_sp_role_value);
+		} else {
+			gr_log_str(GR_DONT_AUDIT, GR_SPROLEF_ACL_MSG, gr_usermode.sp_role);
+			error = -EPERM;
+			if(!(current->role->auth_attempts++))
+				current->role->expires = get_seconds() + CONFIG_GRKERNSEC_ACL_TIMEOUT;
+
+			goto out;
+		}
+		break;
+	case GR_UNSPROLE:
+		if (unlikely(!gr_acl_is_enabled())) {
+			gr_log_noargs(GR_DONT_AUDIT_GOOD, GR_UNSPROLEI_ACL_MSG);
+			error = -EAGAIN;
+			break;
+		}
+
+		if (current->role->roletype & GR_ROLE_SPECIAL) {
+			char *p = "";
+			int i = 0;
+
+			read_lock(&tasklist_lock);
+			if (current->real_parent) {
+				p = current->real_parent->role->rolename;
+				i = current->real_parent->acl_role_id;
+			}
+			read_unlock(&tasklist_lock);
+
+			gr_log_str_int(GR_DONT_AUDIT_GOOD, GR_UNSPROLES_ACL_MSG, p, i);
+			gr_set_acls(1);
+		} else {
+			error = -EPERM;
+			goto out;
+		}
+		break;
+	default:
+		gr_log_int(GR_DONT_AUDIT, GR_INVMODE_ACL_MSG, gr_usermode.mode);
+		error = -EINVAL;
+		break;
+	}
+
+	if (error != -EPERM)
+		goto out;
+
+	if(!(gr_auth_attempts++))
+		gr_auth_expires = get_seconds() + CONFIG_GRKERNSEC_ACL_TIMEOUT;
+
+      out:
+	mutex_unlock(&gr_dev_mutex);
+
+	if (!error)
+		error = req_count;
+
+	return error;
+}
+
+int
+gr_set_acls(const int type)
+{
+	struct task_struct *task, *task2;
+	struct acl_role_label *role = current->role;
+	struct acl_subject_label *subj;
+	__u16 acl_role_id = current->acl_role_id;
+	const struct cred *cred;
+	int ret;
+
+	rcu_read_lock();
+	read_lock(&tasklist_lock);
+	read_lock(&grsec_exec_file_lock);
+	do_each_thread(task2, task) {
+		/* check to see if we're called from the exit handler,
+		   if so, only replace ACLs that have inherited the admin
+		   ACL */
+
+		if (type && (task->role != role ||
+			     task->acl_role_id != acl_role_id))
+			continue;
+
+		task->acl_role_id = 0;
+		task->acl_sp_role = 0;
+		task->inherited = 0;
+
+		if (task->exec_file) {
+			cred = __task_cred(task);
+			task->role = __lookup_acl_role_label(polstate, task, GR_GLOBAL_UID(cred->uid), GR_GLOBAL_GID(cred->gid));
+			subj = gr_get_subject_for_task(task, NULL);
+			if (subj == NULL) {
+				ret = -EINVAL;
+				read_unlock(&grsec_exec_file_lock);
+				read_unlock(&tasklist_lock);
+				rcu_read_unlock();
+				gr_log_str_int(GR_DONT_AUDIT_GOOD, GR_DEFACL_MSG, task->comm, task_pid_nr(task));
+				return ret;
+			}
+			__gr_apply_subject_to_task(polstate, task, subj);
+		} else {
+			// it's a kernel process
+			task->role = polstate->kernel_role;
+			task->acl = polstate->kernel_role->root_label;
+#ifdef CONFIG_GRKERNSEC_ACL_HIDEKERN
+			task->acl->mode &= ~GR_PROCFIND;
+#endif
+		}
+	} while_each_thread(task2, task);
+	read_unlock(&grsec_exec_file_lock);
+	read_unlock(&tasklist_lock);
+	rcu_read_unlock();
+
+	return 0;
+}
diff --git a/grsecurity/gracl_segv.c b/grsecurity/gracl_segv.c
index 3c38bfe..2040e61 100644
--- a/grsecurity/gracl_segv.c
+++ b/grsecurity/gracl_segv.c
@@ -54,8 +54,16 @@ gr_init_uidset(void)
 void
 gr_free_uidset(void)
 {
-	if (uid_set)
-		kfree(uid_set);
+	if (uid_set) {
+		struct crash_uid *tmpset;
+		spin_lock(&gr_uid_lock);
+		tmpset = uid_set;
+		uid_set = NULL;
+		uid_used = 0;
+		spin_unlock(&gr_uid_lock);
+		if (tmpset)
+			kfree(tmpset);
+	}
 
 	return;
 }
diff --git a/grsecurity/grsec_disabled.c b/grsecurity/grsec_disabled.c
index ce65ceb..0866ab2 100644
--- a/grsecurity/grsec_disabled.c
+++ b/grsecurity/grsec_disabled.c
@@ -394,12 +394,6 @@ gr_search_udp_sendmsg(const struct sock *sk, const struct sockaddr_in *addr)
 	return 0;
 }
 
-void
-gr_set_kernel_label(struct task_struct *task)
-{
-	return;
-}
-
 int
 gr_check_user_change(kuid_t real, kuid_t effective, kuid_t fs)
 {
@@ -427,7 +421,6 @@ void gr_put_exec_file(struct task_struct *task)
 	return;
 }
 
-EXPORT_SYMBOL(gr_set_kernel_label);
 #ifdef CONFIG_SECURITY
 EXPORT_SYMBOL(gr_check_user_change);
 EXPORT_SYMBOL(gr_check_group_change);
diff --git a/grsecurity/grsec_init.c b/grsecurity/grsec_init.c
index 087cf30..a88e901 100644
--- a/grsecurity/grsec_init.c
+++ b/grsecurity/grsec_init.c
@@ -77,10 +77,6 @@ char *gr_audit_log_fmt;
 char *gr_alert_log_buf;
 char *gr_audit_log_buf;
 
-extern struct gr_arg *gr_usermode;
-extern unsigned char *gr_system_salt;
-extern unsigned char *gr_system_sum;
-
 void __init
 grsecurity_init(void)
 {
@@ -121,17 +117,6 @@ grsecurity_init(void)
 		return;
 	}
 
-	/* allocate memory for authentication structure */
-	gr_usermode = kmalloc(sizeof(struct gr_arg), GFP_KERNEL);
-	gr_system_salt = kmalloc(GR_SALT_LEN, GFP_KERNEL);
-	gr_system_sum = kmalloc(GR_SHA_LEN, GFP_KERNEL);
-
-	if (!gr_usermode || !gr_system_salt || !gr_system_sum) {
-		panic("Unable to allocate grsecurity authentication structure");
-		return;
-	}
-
-
 #ifdef CONFIG_GRKERNSEC_IO
 #if !defined(CONFIG_GRKERNSEC_SYSCTL_DISTRO)
 	grsec_disable_privio = 1;
diff --git a/include/linux/gracl.h b/include/linux/gracl.h
index ebe6d72..edb2cb6 100644
--- a/include/linux/gracl.h
+++ b/include/linux/gracl.h
@@ -9,19 +9,20 @@
 
 /* Major status information */
 
-#define GR_VERSION  "grsecurity 2.9.1"
-#define GRSECURITY_VERSION 0x2901
+#define GR_VERSION  "grsecurity 3.0"
+#define GRSECURITY_VERSION 0x3000
 
 enum {
 	GR_SHUTDOWN = 0,
 	GR_ENABLE = 1,
 	GR_SPROLE = 2,
-	GR_RELOAD = 3,
+	GR_OLDRELOAD = 3,
 	GR_SEGVMOD = 4,
 	GR_STATUS = 5,
 	GR_UNSPROLE = 6,
 	GR_PASSSET = 7,
 	GR_SPROLEPAM = 8,
+	GR_RELOAD = 9,
 };
 
 /* Password setup definitions
@@ -250,6 +251,34 @@ struct acl_subj_map_db {
 	__u32 s_size;
 };
 
+struct gr_policy_state {
+	struct sprole_pw **acl_special_roles;
+	__u16 num_sprole_pws;
+	struct acl_role_label *kernel_role;
+	struct acl_role_label *role_list;
+	struct acl_role_label *default_role;
+	struct acl_role_db acl_role_set;
+	struct acl_subj_map_db subj_map_set;
+	struct name_db name_set;
+	struct inodev_db inodev_set;
+};
+
+struct gr_alloc_state {
+	unsigned long alloc_stack_next;
+	unsigned long alloc_stack_size;
+	void **alloc_stack;
+};
+
+struct gr_reload_state {
+	struct gr_policy_state oldpolicy;
+	struct gr_alloc_state oldalloc;
+	struct gr_policy_state newpolicy;
+	struct gr_alloc_state newalloc;
+	struct gr_policy_state *oldpolicy_ptr;
+	struct gr_alloc_state *oldalloc_ptr;
+	unsigned char oldmode;
+};
+
 /* End Data Structures Section */
 
 /* Hash functions generated by empirical testing by Brad Spengler
@@ -281,14 +310,6 @@ gr_nhash(const char *name, const __u16 len, const unsigned int sz)
 	return full_name_hash((const unsigned char *)name, len) % sz;
 }
 
-#define FOR_EACH_ROLE_START(role) \
-	role = role_list; \
-	while (role) {
-
-#define FOR_EACH_ROLE_END(role) \
-		role = role->prev; \
-	}
-
 #define FOR_EACH_SUBJECT_START(role,subj,iter) \
 	subj = NULL; \
 	iter = 0; \
diff --git a/include/linux/grinternal.h b/include/linux/grinternal.h
index a5625be..d25522e 100644
--- a/include/linux/grinternal.h
+++ b/include/linux/grinternal.h
@@ -20,7 +20,6 @@ __u32 gr_check_create(const struct dentry *new_dentry,
 int gr_check_protected_task(const struct task_struct *task);
 __u32 to_gr_audit(const __u32 reqmode);
 int gr_set_acls(const int type);
-int gr_apply_subject_to_task(struct task_struct *task);
 int gr_acl_is_enabled(void);
 char gr_roletype_to_char(void);
 
diff --git a/include/linux/grsecurity.h b/include/linux/grsecurity.h
index d6f5a21..b2edfb1 100644
--- a/include/linux/grsecurity.h
+++ b/include/linux/grsecurity.h
@@ -128,7 +128,6 @@ __u32 gr_acl_handle_execve(const struct dentry *dentry,
 				  const struct vfsmount *mnt);
 int gr_check_crash_exec(const struct file *filp);
 int gr_acl_is_enabled(void);
-void gr_set_kernel_label(struct task_struct *task);
 void gr_set_role_label(struct task_struct *task, const kuid_t uid,
 			      const kgid_t gid);
 int gr_set_proc_label(const struct dentry *dentry,
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 4090b3b..d09659d 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1457,10 +1457,12 @@ struct task_struct {
 #endif
 	struct dentry *gr_chroot_dentry;
 	struct acl_subject_label *acl;
+	struct acl_subject_label *tmpacl;
 	struct acl_role_label *role;
 	struct file *exec_file;
 	unsigned long brute_expires;
 	u16 acl_role_id;
+	u8 inherited;
 	/* is this the task that authenticated to the special role */
 	u8 acl_sp_role;
 	u8 is_writable;
