-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 This patch looks good to me. acked. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.13 (GNU/Linux) Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/ iEYEARECAAYFAlD+qX4ACgkQrlYvE4MpobO9VQCffAy0N7x2NCiln61Tv6gPLIcp UtMAnjGJa+ex95zTiFB0j73P+yh3IaeJ =6rZI -----END PGP SIGNATURE-----
>From 3b1c4c3b06f2d98611d3ef0982e5429198783795 Mon Sep 17 00:00:00 2001 From: Ondrej Oprala <ooprala@xxxxxxxxxx> Date: Wed, 9 Jan 2013 11:37:43 +0100 Subject: [PATCH 82/84] libselinux: optimize set*con functions Set*con now caches the security context and only re-sets it if it changes. Signed-off-by: Eric Paris <eparis@xxxxxxxxxx> --- libselinux/src/Makefile | 10 ++-- libselinux/src/procattr.c | 118 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 115 insertions(+), 13 deletions(-) diff --git a/libselinux/src/Makefile b/libselinux/src/Makefile index ac019df..613a4ed 100644 --- a/libselinux/src/Makefile +++ b/libselinux/src/Makefile @@ -20,7 +20,7 @@ RUBYINC ?= $(shell pkg-config --cflags ruby-$(RUBYLIBVER)) RUBYINSTALL ?= $(LIBDIR)/ruby/site_ruby/$(RUBYLIBVER)/$(RUBYPLATFORM) LIBBASE=$(shell basename $(LIBDIR)) -LDFLAGS ?= -lpcre +LDFLAGS ?= -lpcre -lpthread VERSION = $(shell cat ../VERSION) LIBVERSION = 1 @@ -106,17 +106,17 @@ $(SWIGRUBYLOBJ): $(SWIGRUBYCOUT) $(CC) $(CFLAGS) $(SWIG_CFLAGS) $(RUBYINC) -fPIC -DSHARED -c -o $@ $< $(SWIGSO): $(SWIGLOBJ) - $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $< -L. -lselinux -L$(LIBDIR) + $(CC) $(CFLAGS) -shared -o $@ $< -L. -lselinux $(LDFLAGS) -L$(LIBDIR) $(SWIGRUBYSO): $(SWIGRUBYLOBJ) - $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^ -L. -lselinux -L$(LIBDIR) + $(CC) $(CFLAGS) -shared -o $@ $^ -L. -lselinux $(LDFLAGS) -L$(LIBDIR) $(LIBA): $(OBJS) $(AR) rcs $@ $^ $(RANLIB) $@ $(LIBSO): $(LOBJS) - $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^ -ldl -L$(LIBDIR) -Wl,-soname,$(LIBSO),-z,defs,-z,relro + $(CC) $(CFLAGS) -shared -o $@ $^ -ldl $(LDFLAGS) -L$(LIBDIR) -Wl,-soname,$(LIBSO),-z,defs,-z,relro ln -sf $@ $(TARGET) $(LIBPC): $(LIBPC).in ../VERSION @@ -129,7 +129,7 @@ $(AUDIT2WHYLOBJ): audit2why.c $(CC) $(filter-out -Werror, $(CFLAGS)) $(PYINC) -fPIC -DSHARED -c -o $@ $< $(AUDIT2WHYSO): $(AUDIT2WHYLOBJ) - $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^ -L. -lselinux $(LIBDIR)/libsepol.a -L$(LIBDIR) + $(CC) $(CFLAGS) -shared -o $@ $^ -L. $(LDFLAGS) -lselinux $(LIBDIR)/libsepol.a -L$(LIBDIR) %.o: %.c policy.h $(CC) $(CFLAGS) $(TLSFLAGS) -c -o $@ $< diff --git a/libselinux/src/procattr.c b/libselinux/src/procattr.c index 83381e4..bac6a63 100644 --- a/libselinux/src/procattr.c +++ b/libselinux/src/procattr.c @@ -1,6 +1,7 @@ #include <sys/syscall.h> #include <unistd.h> #include <fcntl.h> +#include <pthread.h> #include <string.h> #include <stdlib.h> #include <stdio.h> @@ -8,11 +9,64 @@ #include "selinux_internal.h" #include "policy.h" +static __thread pid_t cpid; +static __thread pid_t tid; +static __thread security_context_t prev_current; +static __thread security_context_t prev_exec; +static __thread security_context_t prev_fscreate; +static __thread security_context_t prev_keycreate; +static __thread security_context_t prev_sockcreate; + +static pthread_once_t once = PTHREAD_ONCE_INIT; +static pthread_key_t destructor_key; +static int destructor_key_initialized = 0; +static __thread char destructor_initialized; + static pid_t gettid(void) { return syscall(__NR_gettid); } +static void procattr_thread_destructor(void __attribute__((unused)) *unused) +{ + free(prev_current); + free(prev_exec); + free(prev_fscreate); + free(prev_keycreate); + free(prev_sockcreate); +} + +static void free_procattr(void) +{ + procattr_thread_destructor(NULL); + cpid = tid = 0; + prev_current = prev_exec = prev_fscreate = prev_keycreate = prev_sockcreate = NULL; +} + +void __attribute__((destructor)) procattr_destructor(void); + +void hidden __attribute__((destructor)) procattr_destructor(void) +{ + if (destructor_key_initialized) + __selinux_key_delete(destructor_key); +} + +static inline void init_thread_destructor(void) +{ + if (destructor_initialized == 0) { + __selinux_setspecific(destructor_key, (void *)1); + destructor_initialized = 1; + } +} + +static void init_procattr(void) +{ + if (__selinux_key_create(&destructor_key, procattr_thread_destructor) == 0) { + pthread_atfork(NULL, NULL, free_procattr); + destructor_key_initialized = 1; + } +} + static int getprocattrcon_raw(security_context_t * context, pid_t pid, const char *attr) { @@ -20,13 +74,19 @@ static int getprocattrcon_raw(security_context_t * context, size_t size; int fd, rc; ssize_t ret; - pid_t tid; int errno_hold; + __selinux_once(once, init_procattr); + init_thread_destructor(); + + if (cpid != getpid()) + free_procattr(); + if (pid > 0) rc = asprintf(&path, "/proc/%d/attr/%s", pid, attr); else { - tid = gettid(); + if (!tid) + tid = gettid(); rc = asprintf(&path, "/proc/self/task/%d/attr/%s", tid, attr); } if (rc < 0) @@ -92,14 +152,47 @@ static int setprocattrcon_raw(security_context_t context, { char *path; int fd, rc; - pid_t tid; ssize_t ret; int errno_hold; + security_context_t *prev_context; + + __selinux_once(once, init_procattr); + init_thread_destructor(); + + if (cpid != getpid()) + free_procattr(); + + switch (attr[0]) { + case 'c': + prev_context = &prev_current; + break; + case 'e': + prev_context = &prev_exec; + break; + case 'f': + prev_context = &prev_fscreate; + break; + case 'k': + prev_context = &prev_keycreate; + break; + case 's': + prev_context = &prev_sockcreate; + break; + default: + return -1; + }; + + if (!context && !*prev_context) + return 0; + if (context && *prev_context && !strcmp(context, *prev_context)) + return 0; if (pid > 0) rc = asprintf(&path, "/proc/%d/attr/%s", pid, attr); else { - tid = gettid(); + if (!tid) + tid = gettid(); + rc = asprintf(&path, "/proc/self/task/%d/attr/%s", tid, attr); } if (rc < 0) @@ -109,21 +202,30 @@ static int setprocattrcon_raw(security_context_t context, free(path); if (fd < 0) return -1; - if (context) + if (context) { + ret = -1; + context = strdup(context); + if (!context) + goto out; do { ret = write(fd, context, strlen(context) + 1); } while (ret < 0 && errno == EINTR); - else + } else { do { ret = write(fd, NULL, 0); /* clear */ } while (ret < 0 && errno == EINTR); + } +out: errno_hold = errno; close(fd); errno = errno_hold; - if (ret < 0) + if (ret < 0) { + free(context); return -1; - else + } else { + *prev_context = context; return 0; + } } static int setprocattrcon(const security_context_t context, -- 1.8.1