aboutsummaryrefslogtreecommitdiffstats
path: root/libselinux/src/procattr.c
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2013-01-09 11:37:43 +0100
committerEric Paris <eparis@redhat.com>2013-02-05 20:14:47 -0500
commit1d403326aecd92dfa0120cfd2e9c3c52a2a3cdf1 (patch)
treefff61d859452f71be3ee5292d0c95d75b9883bbe /libselinux/src/procattr.c
parent7b3a9a30ebf3188aa086571728da3496ca186451 (diff)
downloadandroid_external_selinux-1d403326aecd92dfa0120cfd2e9c3c52a2a3cdf1.tar.gz
android_external_selinux-1d403326aecd92dfa0120cfd2e9c3c52a2a3cdf1.tar.bz2
android_external_selinux-1d403326aecd92dfa0120cfd2e9c3c52a2a3cdf1.zip
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@redhat.com> Acked-by: Dan Walsh <dwalsh@redhat.com>
Diffstat (limited to 'libselinux/src/procattr.c')
-rw-r--r--libselinux/src/procattr.c188
1 files changed, 162 insertions, 26 deletions
diff --git a/libselinux/src/procattr.c b/libselinux/src/procattr.c
index 83381e4b..6c5b45a3 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,32 +9,137 @@
#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 int getprocattrcon_raw(security_context_t * context,
- pid_t pid, const char *attr)
+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);
+ tid = 0;
+ cpid = getpid();
+ 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 openattr(pid_t pid, const char *attr, int flags)
{
- char *path, *buf;
- size_t size;
int fd, rc;
- ssize_t ret;
- pid_t tid;
- int errno_hold;
+ char *path;
+
+ 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)
return -1;
- fd = open(path, O_RDONLY);
+ fd = open(path, flags | O_CLOEXEC);
free(path);
+ return fd;
+}
+
+static int getprocattrcon_raw(security_context_t * context,
+ pid_t pid, const char *attr)
+{
+ char *buf;
+ size_t size;
+ int fd;
+ 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;
+ case 'p':
+ prev_context = NULL;
+ break;
+ default:
+ errno = ENOENT;
+ return -1;
+ };
+
+ if (prev_context) {
+ *context = strdup(prev_context);
+ if (!(*context)) {
+ return -1;
+ }
+ return 0;
+ }
+
+ fd = openattr(pid, attr, O_RDONLY);
if (fd < 0)
return -1;
@@ -90,40 +196,70 @@ static int getprocattrcon(security_context_t * context,
static int setprocattrcon_raw(security_context_t context,
pid_t pid, const char *attr)
{
- char *path;
- int fd, rc;
- pid_t tid;
+ int fd;
ssize_t ret;
int errno_hold;
+ security_context_t *prev_context;
- if (pid > 0)
- rc = asprintf(&path, "/proc/%d/attr/%s", pid, attr);
- else {
- tid = gettid();
- rc = asprintf(&path, "/proc/self/task/%d/attr/%s", tid, attr);
- }
- if (rc < 0)
- return -1;
+ __selinux_once(once, init_procattr);
+ init_thread_destructor();
- fd = open(path, O_RDWR);
- free(path);
+ 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:
+ errno = ENOENT;
+ return -1;
+ };
+
+ if (!context && !*prev_context)
+ return 0;
+ if (context && *prev_context && !strcmp(context, *prev_context))
+ return 0;
+
+ fd = openattr(pid, attr, O_RDWR);
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,