diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index e60c79d..09977a9 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -152,18 +152,14 @@ static void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tcla
 	rc = security_sid_to_context(ssid, &scontext, &scontext_len);
 	if (rc)
 		audit_log_format(ab, "ssid=%d", ssid);
-	else {
+	else
 		audit_log_format(ab, "scontext=%s", scontext);
-		kfree(scontext);
-	}
 
 	rc = security_sid_to_context(tsid, &scontext, &scontext_len);
 	if (rc)
 		audit_log_format(ab, " tsid=%d", tsid);
-	else {
+	else
 		audit_log_format(ab, " tcontext=%s", scontext);
-		kfree(scontext);
-	}
 
 	BUG_ON(!tclass || tclass >= ARRAY_SIZE(secclass_map));
 	audit_log_format(ab, " tclass=%s", secclass_map[tclass-1].name);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 03717c2..e8c6c5d 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2872,7 +2872,9 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
 		rc = security_sid_to_context_force(newsid, &context, &clen);
 		if (rc)
 			return rc;
-		*value = context;
+		*value = kstrdup(context, GFP_KERNEL);
+		if (*value == NULL)
+			return -ENOMEM;
 		*len = clen;
 	}
 
@@ -3231,12 +3233,13 @@ static int selinux_inode_getsecurity(struct inode *inode, const char *name, void
 	if (error)
 		return error;
 	error = size;
-	if (alloc) {
+
+	/*
+	 * context will not be freed because selinux_release_context
+	 * does not free anything.
+	 */
+	if (alloc)
 		*buffer = context;
-		goto out_nofree;
-	}
-	kfree(context);
-out_nofree:
 	return error;
 }
 
@@ -4621,7 +4624,6 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op
 out_len:
 	if (put_user(scontext_len, optlen))
 		err = -EFAULT;
-	kfree(scontext);
 	return err;
 }
 
@@ -5674,6 +5676,7 @@ static int selinux_getprocattr(struct task_struct *p,
 	u32 sid;
 	int error;
 	unsigned len;
+	char *vp;
 
 	if (current != p) {
 		error = current_has_perm(p, PROCESS__GETATTR);
@@ -5705,21 +5708,17 @@ static int selinux_getprocattr(struct task_struct *p,
 	if (!sid)
 		return 0;
 
-	if (strcmp(name, "context")) {
-		error = security_sid_to_context(sid, value, &len);
-	} else {
-		char *vp;
-
-		error = security_sid_to_context(sid, &vp, &len);
-		if (!error) {
-			*value = kasprintf(GFP_KERNEL, "selinux='%s'", vp);
-			if (*value == NULL)
-				error = -ENOMEM;
-		}
-	}
-
+	error = security_sid_to_context(sid, &vp, &len);
 	if (error)
 		return error;
+
+	if (strcmp(name, "context"))
+		*value = kstrdup(vp, GFP_KERNEL);
+	else
+		*value = kasprintf(GFP_KERNEL, "selinux='%s'", vp);
+
+	if (*value == NULL)
+		return -ENOMEM;
 	return len;
 
 invalid:
@@ -5876,11 +5875,6 @@ static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
 	return security_context_to_sid(secdata, seclen, secid, GFP_KERNEL);
 }
 
-static void selinux_release_secctx(char *secdata, u32 seclen)
-{
-	kfree(secdata);
-}
-
 static void selinux_inode_invalidate_secctx(struct inode *inode)
 {
 	struct inode_security_struct *isec = inode->i_security;
@@ -5978,7 +5972,9 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer)
 	rc = security_sid_to_context(ksec->sid, &context, &len);
 	if (!rc)
 		rc = len;
-	*_buffer = context;
+	*_buffer = kstrdup(context, GFP_KERNEL);
+	if (*_buffer == NULL)
+		rc = -ENOMEM;
 	return rc;
 }
 
@@ -6123,7 +6119,6 @@ static struct security_hook_list selinux_hooks[] = {
 	LSM_HOOK_INIT(ismaclabel, selinux_ismaclabel),
 	LSM_HOOK_INIT(secid_to_secctx, selinux_secid_to_secctx),
 	LSM_HOOK_INIT(secctx_to_secid, selinux_secctx_to_secid),
-	LSM_HOOK_INIT(release_secctx, selinux_release_secctx),
 	LSM_HOOK_INIT(inode_invalidate_secctx, selinux_inode_invalidate_secctx),
 	LSM_HOOK_INIT(inode_notifysecctx, selinux_inode_notifysecctx),
 	LSM_HOOK_INIT(inode_setsecctx, selinux_inode_setsecctx),
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 2519e26..96674d8 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -582,7 +582,6 @@ static ssize_t sel_write_context(struct file *file, char *buf, size_t size)
 	memcpy(buf, canon, len);
 	length = len;
 out:
-	kfree(canon);
 	return length;
 }
 
@@ -902,7 +901,6 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
 	memcpy(buf, newcon, len);
 	length = len;
 out:
-	kfree(newcon);
 	kfree(namebuf);
 	kfree(tcon);
 	kfree(scon);
@@ -959,7 +957,6 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
 	memcpy(buf, newcon, len);
 	length = len;
 out:
-	kfree(newcon);
 	kfree(tcon);
 	kfree(scon);
 	return length;
@@ -1009,12 +1006,10 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
 			goto out;
 		}
 		if ((length + len) >= SIMPLE_TRANSACTION_LIMIT) {
-			kfree(newcon);
 			length = -ERANGE;
 			goto out;
 		}
 		memcpy(ptr, newcon, len);
-		kfree(newcon);
 		ptr += len;
 		length += len;
 	}
@@ -1078,7 +1073,6 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
 	memcpy(buf, newcon, len);
 	length = len;
 out:
-	kfree(newcon);
 	kfree(tcon);
 	kfree(scon);
 	return length;
@@ -1521,7 +1515,6 @@ static ssize_t sel_read_initcon(struct file *file, char __user *buf,
 		return ret;
 
 	ret = simple_read_from_buffer(buf, count, ppos, con, len);
-	kfree(con);
 	return ret;
 }
 
diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h
index 212e347..730c886 100644
--- a/security/selinux/ss/context.h
+++ b/security/selinux/ss/context.h
@@ -30,6 +30,8 @@ struct context {
 	u32 len;        /* length of string in bytes */
 	struct mls_range range;
 	char *str;	/* string representation if context cannot be mapped. */
+	u32 seclen;
+	char *secctx;	/* string representation if context can be mapped. */
 };
 
 static inline void mls_context_init(struct context *c)
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 082b20c..feab3d5 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -89,8 +89,6 @@ int ss_initialized;
 static u32 latest_granting;
 
 /* Forward declaration. */
-static int context_struct_to_string(struct context *context, char **scontext,
-				    u32 *scontext_len);
 
 static void context_struct_compute_av(struct context *scontext,
 					struct context *tcontext,
@@ -1176,7 +1174,8 @@ allow:
  * to point to this string and set `*scontext_len' to
  * the length of the string.
  */
-static int context_struct_to_string(struct context *context, char **scontext, u32 *scontext_len)
+int context_struct_to_string(struct context *context, char **scontext,
+				u32 *scontext_len)
 {
 	char *scontextp;
 
@@ -1236,6 +1235,7 @@ const char *security_get_initial_sid_context(u32 sid)
 static int security_sid_to_context_core(u32 sid, char **scontext,
 					u32 *scontext_len, int force)
 {
+	struct sidtab_node *snode;
 	struct context *context;
 	int rc = 0;
 
@@ -1245,18 +1245,11 @@ static int security_sid_to_context_core(u32 sid, char **scontext,
 
 	if (!ss_initialized) {
 		if (sid <= SECINITSID_NUM) {
-			char *scontextp;
 
 			*scontext_len = strlen(initial_sid_to_string[sid]) + 1;
 			if (!scontext)
 				goto out;
-			scontextp = kmemdup(initial_sid_to_string[sid],
-					    *scontext_len, GFP_ATOMIC);
-			if (!scontextp) {
-				rc = -ENOMEM;
-				goto out;
-			}
-			*scontext = scontextp;
+			*scontext = (char *)initial_sid_to_string[sid];
 			goto out;
 		}
 		printk(KERN_ERR "SELinux: %s:  called before initial "
@@ -1265,6 +1258,19 @@ static int security_sid_to_context_core(u32 sid, char **scontext,
 		goto out;
 	}
 	read_lock(&policy_rwlock);
+	snode = sidtab_find(&sidtab, sid, force);
+	if (!snode) {
+		printk(KERN_ERR "SELinux: %s:  unrecognized SID tab %d\n",
+			__func__, sid);
+	} else if (snode->context.secctx == NULL ||
+		   snode->context.seclen == 0) {
+		printk(KERN_ERR "SELinux: %s:  unrecognized SID secctx %d\n",
+			__func__, sid);
+	} else {
+		*scontext = snode->context.secctx;
+		*scontext_len = snode->context.seclen;
+		goto out_unlock;
+	}
 	if (force)
 		context = sidtab_search_force(&sidtab, sid);
 	else
diff --git a/security/selinux/ss/services.h b/security/selinux/ss/services.h
index 6abcd87..dd9dffd 100644
--- a/security/selinux/ss/services.h
+++ b/security/selinux/ss/services.h
@@ -17,5 +17,9 @@ void services_compute_xperms_drivers(struct extended_perms *xperms,
 void services_compute_xperms_decision(struct extended_perms_decision *xpermd,
 					struct avtab_node *node);
 
+int context_struct_to_string(struct context *context, char **scontext,
+				u32 *scontext_len);
+
+
 #endif	/* _SS_SERVICES_H_ */
 
diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c
index 5840a35..e18c38f 100644
--- a/security/selinux/ss/sidtab.c
+++ b/security/selinux/ss/sidtab.c
@@ -9,6 +9,7 @@
 #include <linux/errno.h>
 #include "flask.h"
 #include "security.h"
+#include "services.h"
 #include "sidtab.h"
 
 #define SIDTAB_HASH(sid) \
@@ -64,6 +65,13 @@ int sidtab_insert(struct sidtab *s, u32 sid, struct context *context)
 		rc = -ENOMEM;
 		goto out;
 	}
+	if (context_struct_to_string(context, &newnode->context.secctx,
+					&newnode->context.seclen) < 0) {
+		context_destroy(&newnode->context);
+		kfree(newnode);
+		rc = -ENOMEM;
+		goto out;
+	}
 
 	if (prev) {
 		newnode->next = prev->next;
@@ -82,6 +90,36 @@ out:
 	return rc;
 }
 
+struct sidtab_node *sidtab_find(struct sidtab *s, u32 sid, int force)
+{
+	int hvalue;
+	struct sidtab_node *cur;
+
+	if (!s)
+		return NULL;
+
+	hvalue = SIDTAB_HASH(sid);
+	cur = s->htable[hvalue];
+	while (cur && sid > cur->sid)
+		cur = cur->next;
+
+	if (force && cur && sid == cur->sid && cur->context.len)
+		return cur;
+
+	if (cur == NULL || sid != cur->sid || cur->context.len) {
+		/* Remap invalid SIDs to the unlabeled SID. */
+		sid = SECINITSID_UNLABELED;
+		hvalue = SIDTAB_HASH(sid);
+		cur = s->htable[hvalue];
+		while (cur && sid > cur->sid)
+			cur = cur->next;
+		if (!cur || sid != cur->sid)
+			return NULL;
+	}
+
+	return cur;
+}
+
 static struct context *sidtab_search_core(struct sidtab *s, u32 sid, int force)
 {
 	int hvalue;
diff --git a/security/selinux/ss/sidtab.h b/security/selinux/ss/sidtab.h
index 84dc154..0d60b380 100644
--- a/security/selinux/ss/sidtab.h
+++ b/security/selinux/ss/sidtab.h
@@ -35,6 +35,7 @@ int sidtab_init(struct sidtab *s);
 int sidtab_insert(struct sidtab *s, u32 sid, struct context *context);
 struct context *sidtab_search(struct sidtab *s, u32 sid);
 struct context *sidtab_search_force(struct sidtab *s, u32 sid);
+struct sidtab_node *sidtab_find(struct sidtab *s, u32 sid, int force);
 
 int sidtab_map(struct sidtab *s,
 	       int (*apply) (u32 sid,
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
index 789d07b..ca165d3 100644
--- a/security/selinux/xfrm.c
+++ b/security/selinux/xfrm.c
@@ -357,10 +357,8 @@ int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x,
 		return rc;
 
 	ctx = kmalloc(sizeof(*ctx) + str_len, GFP_ATOMIC);
-	if (!ctx) {
-		rc = -ENOMEM;
-		goto out;
-	}
+	if (!ctx)
+		return -ENOMEM;
 
 	ctx->ctx_doi = XFRM_SC_DOI_LSM;
 	ctx->ctx_alg = XFRM_SC_ALG_SELINUX;
@@ -370,8 +368,6 @@ int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x,
 
 	x->security = ctx;
 	atomic_inc(&selinux_xfrm_refcount);
-out:
-	kfree(ctx_str);
 	return rc;
 }
 
