diff --git a/libselinux/src/Makefile b/libselinux/src/Makefile index f5fd6307..b68d586d 100644 --- a/libselinux/src/Makefile +++ b/libselinux/src/Makefile @@ -79,7 +79,7 @@ $(SWIGRUBYSO): $(SWIGRUBYLOBJ) $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^ -L. -lselinux -L$(LIBDIR) -Wl,-soname,$@ $(LIBSO): $(LOBJS) - $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^ -ldl -L$(LIBDIR) -Wl,-soname,$(LIBSO),-z,defs,-z,relro + $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^ -ldl -lpthread -L$(LIBDIR) -Wl,-soname,$(LIBSO),-z,defs,-z,relro ln -sf $@ $(TARGET) audit2why.lo: audit2why.c diff --git a/libselinux/src/setrans_client.c b/libselinux/src/setrans_client.c index 500225e7..bb213c6f 100644 --- a/libselinux/src/setrans_client.c +++ b/libselinux/src/setrans_client.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "dso.h" #include "selinux_internal.h" #include "setrans_internal.h" @@ -26,12 +27,13 @@ static int mls_enabled = -1; // Simple cache -static __thread security_context_t prev_t2r_trans = NULL; -static __thread security_context_t prev_t2r_raw = NULL; -static __thread security_context_t prev_r2t_trans = NULL; -static __thread security_context_t prev_r2t_raw = NULL; -static __thread char *prev_r2c_trans = NULL; -static __thread security_context_t prev_r2c_raw = NULL; +static pthread_key_t prev_t2r_trans_key; +static pthread_key_t prev_t2r_raw_key; +static pthread_key_t prev_r2t_trans_key; +static pthread_key_t prev_r2t_raw_key; +static pthread_key_t prev_r2c_trans_key; +static pthread_key_t prev_r2c_raw_key; +static pthread_once_t make_keys_once = PTHREAD_ONCE_INIT; /* * setransd_open @@ -238,22 +240,89 @@ out: return ret; } +static void delete_value(void *value) +{ + free(value); +} + +static void drop_cached_value(pthread_key_t cache_key) +{ + void *value; + value = pthread_getspecific(cache_key); + if (value) { + pthread_setspecific(cache_key, NULL); + delete_value(value); + } +} + hidden void fini_context_translations(void) { - free(prev_r2t_trans); - free(prev_r2t_raw); - free(prev_t2r_trans); - free(prev_t2r_raw); - free(prev_r2c_trans); - free(prev_r2c_raw); +/* this is not necessary but if we are single threaded + we can free the data earlier than on exit */ + drop_cached_value(prev_r2t_trans_key); + drop_cached_value(prev_r2t_raw_key); + drop_cached_value(prev_t2r_trans_key); + drop_cached_value(prev_t2r_raw_key); + drop_cached_value(prev_r2c_trans_key); + drop_cached_value(prev_r2c_raw_key); +} + +static void make_keys(void) +{ + (void)pthread_key_create(&prev_t2r_trans_key, delete_value); + (void)pthread_key_create(&prev_t2r_raw_key, delete_value); + (void)pthread_key_create(&prev_r2t_trans_key, delete_value); + (void)pthread_key_create(&prev_r2t_raw_key, delete_value); + (void)pthread_key_create(&prev_r2c_trans_key, delete_value); + (void)pthread_key_create(&prev_r2c_raw_key, delete_value); } hidden int init_context_translations(void) { mls_enabled = is_selinux_mls_enabled(); + (void)pthread_once(&make_keys_once, make_keys); return 0; } +static void *match_cached_value(pthread_key_t cache_from, + pthread_key_t cache_to, + const char *match_from) +{ + void *from, *to; + + from = pthread_getspecific(cache_from); + to = pthread_getspecific(cache_to); + if (from && strcmp(from, match_from) == 0) { + return strdup(to); + } else { + pthread_setspecific(cache_from, NULL); + delete_value(from); + pthread_setspecific(cache_to, NULL); + delete_value(to); + errno = 0; + return NULL; + } +} + +void set_cached_value(pthread_key_t cache_from, + pthread_key_t cache_to, + void *from, + void *to) +{ + from = strdup(from); + if (from == NULL) + return; + + to = strdup(to); + if (to == NULL) { + free(from); + return; + } + + pthread_setspecific(cache_from, from); + pthread_setspecific(cache_to, to); +} + int selinux_trans_to_raw_context(security_context_t trans, security_context_t * rawp) { @@ -267,24 +336,13 @@ int selinux_trans_to_raw_context(security_context_t trans, goto out; } - if (prev_t2r_trans && strcmp(prev_t2r_trans, trans) == 0) { - *rawp = strdup(prev_t2r_raw); - } else { - free(prev_t2r_trans); - prev_t2r_trans = NULL; - free(prev_t2r_raw); - prev_t2r_raw = NULL; + if ((*rawp = match_cached_value(prev_t2r_trans_key, prev_t2r_raw_key, trans)) == NULL + && errno == 0) { if (trans_to_raw_context(trans, rawp)) *rawp = strdup(trans); if (*rawp) { - prev_t2r_trans = strdup(trans); - if (!prev_t2r_trans) - goto out; - prev_t2r_raw = strdup(*rawp); - if (!prev_t2r_raw) { - free(prev_t2r_trans); - prev_t2r_trans = NULL; - } + set_cached_value(prev_t2r_trans_key, prev_t2r_raw_key, + trans, *rawp); } } out: @@ -306,24 +364,13 @@ int selinux_raw_to_trans_context(security_context_t raw, goto out; } - if (prev_r2t_raw && strcmp(prev_r2t_raw, raw) == 0) { - *transp = strdup(prev_r2t_trans); - } else { - free(prev_r2t_raw); - prev_r2t_raw = NULL; - free(prev_r2t_trans); - prev_r2t_trans = NULL; + if ((*transp = match_cached_value(prev_r2t_raw_key, prev_r2t_trans_key, raw)) == NULL + && errno == 0) { if (raw_to_trans_context(raw, transp)) *transp = strdup(raw); if (*transp) { - prev_r2t_raw = strdup(raw); - if (!prev_r2t_raw) - goto out; - prev_r2t_trans = strdup(*transp); - if (!prev_r2t_trans) { - free(prev_r2t_raw); - prev_r2t_raw = NULL; - } + set_cached_value(prev_r2t_raw_key, prev_r2t_trans_key, + raw, *transp); } } out: @@ -339,27 +386,15 @@ int selinux_raw_context_to_color(security_context_t raw, char **transp) return -1; } - if (prev_r2c_raw && strcmp(prev_r2c_raw, raw) == 0) { - *transp = strdup(prev_r2c_trans); - } else { - free(prev_r2c_raw); - prev_r2c_raw = NULL; - free(prev_r2c_trans); - prev_r2c_trans = NULL; + if ((*transp = match_cached_value(prev_r2c_raw_key, prev_r2c_trans_key, raw)) == NULL + && errno == 0) { if (raw_context_to_color(raw, transp)) return -1; if (*transp) { - prev_r2c_raw = strdup(raw); - if (!prev_r2c_raw) - goto out; - prev_r2c_trans = strdup(*transp); - if (!prev_r2c_trans) { - free(prev_r2c_raw); - prev_r2c_raw = NULL; - } + set_cached_value(prev_r2c_raw_key, prev_r2c_trans_key, + raw, *transp); } } - out: return *transp ? 0 : -1; }