e69aa1c
--- libselinux-2.0.94/src/matchpathcon.c.leak	2011-02-04 08:49:46.498334051 +0100
e69aa1c
+++ libselinux-2.0.94/src/matchpathcon.c	2011-02-04 08:52:48.979090294 +0100
e69aa1c
@@ -16,6 +16,9 @@
e69aa1c
 static __thread int con_array_size;
e69aa1c
 static __thread int con_array_used;
e69aa1c
 
e69aa1c
+static pthread_once_t once = PTHREAD_ONCE_INIT;
e69aa1c
+static pthread_key_t destructor_key;
e69aa1c
+
e69aa1c
 static int add_array_elt(char *con)
e69aa1c
 {
e69aa1c
 	if (con_array_size) {
e69aa1c
@@ -283,11 +286,19 @@
e69aa1c
 	fl_head = NULL;
e69aa1c
 }
e69aa1c
 
e69aa1c
+static void matchpathcon_init_once(void)
e69aa1c
+{
e69aa1c
+	__selinux_key_create(&destructor_key, free_array_elts);
e69aa1c
+}
e69aa1c
+
e69aa1c
 int matchpathcon_init_prefix(const char *path, const char *subset)
e69aa1c
 {
e69aa1c
 	if (!mycanoncon)
e69aa1c
 		mycanoncon = default_canoncon;
e69aa1c
 
e69aa1c
+	__selinux_once(once, matchpathcon_init_once);
e69aa1c
+	__selinux_setspecific(destructor_key, (void *)1);
e69aa1c
+
e69aa1c
 	options[SELABEL_OPT_SUBSET].type = SELABEL_OPT_SUBSET;
e69aa1c
 	options[SELABEL_OPT_SUBSET].value = subset;
e69aa1c
 	options[SELABEL_OPT_PATH].type = SELABEL_OPT_PATH;
e69aa1c
--- libselinux-2.0.94/src/selinux_internal.h.leak	2011-02-04 08:53:00.618332791 +0100
e69aa1c
+++ libselinux-2.0.94/src/selinux_internal.h	2011-02-04 08:56:24.917090558 +0100
e69aa1c
@@ -97,6 +97,8 @@
e69aa1c
 
e69aa1c
 /* Make pthread_once optional */
e69aa1c
 #pragma weak pthread_once
e69aa1c
+#pragma weak pthread_key_create
e69aa1c
+#pragma weak pthread_setspecific
e69aa1c
 
e69aa1c
 /* Call handler iff the first call.  */
e69aa1c
 #define __selinux_once(ONCE_CONTROL, INIT_FUNCTION)	\
e69aa1c
@@ -109,4 +111,15 @@
e69aa1c
 		}					\
e69aa1c
 	} while (0)
e69aa1c
 
e69aa1c
+/* Pthread key macros */
e69aa1c
+#define __selinux_key_create(KEY, DESTRUCTOR)			\
e69aa1c
+	do {							\
e69aa1c
+		if (pthread_key_create != NULL)			\
e69aa1c
+			pthread_key_create(KEY, DESTRUCTOR);	\
e69aa1c
+	} while (0)
e69aa1c
 
e69aa1c
+#define __selinux_setspecific(KEY, VALUE)			\
e69aa1c
+	do {							\
e69aa1c
+		if (pthread_setspecific != NULL)		\
e69aa1c
+			pthread_setspecific(KEY, VALUE);	\
e69aa1c
+	} while (0)
e69aa1c
--- libselinux-2.0.94/src/setrans_client.c.leak	2011-02-04 08:56:43.229330202 +0100
e69aa1c
+++ libselinux-2.0.94/src/setrans_client.c	2011-02-04 09:00:04.176174970 +0100
e69aa1c
@@ -34,6 +34,8 @@
e69aa1c
 static __thread security_context_t prev_r2c_raw = NULL;
e69aa1c
 
e69aa1c
 static pthread_once_t once = PTHREAD_ONCE_INIT;
e69aa1c
+static pthread_key_t destructor_key;
e69aa1c
+static __thread char destructor_initialized;
e69aa1c
 
e69aa1c
 /*
e69aa1c
  * setransd_open
e69aa1c
@@ -240,8 +242,27 @@
e69aa1c
 	return ret;
e69aa1c
 }
e69aa1c
 
e69aa1c
+static void setrans_thread_destructor(void __attribute__((unused)) *unused)
e69aa1c
+{
e69aa1c
+	free(prev_t2r_trans);
e69aa1c
+	free(prev_t2r_raw);
e69aa1c
+	free(prev_r2t_trans);
e69aa1c
+	free(prev_r2t_raw);
e69aa1c
+	free(prev_r2c_trans);
e69aa1c
+	free(prev_r2c_raw);
e69aa1c
+}
e69aa1c
+
e69aa1c
+static inline void init_thread_destructor(void)
e69aa1c
+{
e69aa1c
+	if (destructor_initialized == 0) {
e69aa1c
+		__selinux_setspecific(destructor_key, (void *)1);
e69aa1c
+		destructor_initialized = 1;
e69aa1c
+	}
e69aa1c
+}
e69aa1c
+
e69aa1c
 static void init_context_translations(void)
e69aa1c
 {
e69aa1c
+	__selinux_key_create(&destructor_key, setrans_thread_destructor);
e69aa1c
 	mls_enabled = is_selinux_mls_enabled();
e69aa1c
 }
e69aa1c
 
e69aa1c
@@ -254,6 +275,7 @@
e69aa1c
 	}
e69aa1c
 
e69aa1c
 	__selinux_once(once, init_context_translations);
e69aa1c
+	init_thread_destructor();
e69aa1c
 
e69aa1c
 	if (!mls_enabled) {
e69aa1c
 		*rawp = strdup(trans);
e69aa1c
@@ -295,6 +317,7 @@
e69aa1c
 	}
e69aa1c
 
e69aa1c
 	__selinux_once(once, init_context_translations);
e69aa1c
+	init_thread_destructor();
e69aa1c
 
e69aa1c
 	if (!mls_enabled) {
e69aa1c
 		*transp = strdup(raw);
e69aa1c
@@ -334,6 +357,9 @@
e69aa1c
 		return -1;
e69aa1c
 	}
e69aa1c
 
e69aa1c
+	__selinux_once(once, init_context_translations);
e69aa1c
+	init_thread_destructor();
e69aa1c
+
e69aa1c
 	if (prev_r2c_raw && strcmp(prev_r2c_raw, raw) == 0) {
e69aa1c
 		*transp = strdup(prev_r2c_trans);
e69aa1c
 	} else {