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