Re: setfscreatecon optimizations

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Thank you for the pointers, it helped me out a lot. I tested the patched libselinux with
$cp -a dir1 dir2
and got an approx. 20% save in instruction count. The patch is attached.
Thanks,
Ondrej

On 01/08/2013 03:48 PM, Stephen Smalley wrote:
On 01/08/2013 08:20 AM, Ondrej Oprala wrote:
Hi, there have been some attempts on the coreutils mailing list at
optimizing cp copying by caching the selinux security context ( please
see: http://lists.gnu.org/archive/html/coreutils/2013-01/msg00012.html ).
Would it be possible to perform some kind of caching inside
setfscreatecon? For example not going through the whole process of
setfscreatecon if the context to be set equals the current one?

I think that should be possible. The relevant code that would need to be modified is in libselinux/src/procattr.c. You would likely want to modify the common helper for all of the set*con functions, setprocattrcon_raw(). A conceptually similar cache exists in libselinux/src/setrans_client.c; note the methods used to make it thread-safe and to ensure that it is properly freed. You would need a separate cache for each kind of attribute that can be set, i.e. current, exec, fscreate, keycreate, sockcreate. You could likely also cache the tid.

>From 3fd22a7e0d48a26c5ccb6b563ce6a8d2cc5383d9 Mon Sep 17 00:00:00 2001
From: Ondrej Oprala <ooprala@xxxxxxxxxx>
Date: Wed, 9 Jan 2013 11:37:43 +0100
Subject: [PATCH] libselinux: optimize set*con functions

Set*con now caches the security context and only re-sets it if it changes.
---
 libselinux/src/procattr.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 96 insertions(+), 1 deletion(-)

diff --git a/libselinux/src/procattr.c b/libselinux/src/procattr.c
index 83381e4..6aa25b8 100644
--- a/libselinux/src/procattr.c
+++ b/libselinux/src/procattr.c
@@ -8,11 +8,54 @@
 #include "selinux_internal.h"
 #include "policy.h"
 
+static __thread pid_t prev_tid = -1;
+static __thread security_context_t prev_current = NULL;
+static __thread security_context_t prev_exec = NULL;
+static __thread security_context_t prev_fscreate = NULL;
+static __thread security_context_t prev_keycreate = NULL;
+static __thread security_context_t prev_sockcreate = NULL;
+
+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);
+}
+
+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)
+		destructor_key_initialized = 1;
+}
+
 static int getprocattrcon_raw(security_context_t * context,
 			      pid_t pid, const char *attr)
 {
@@ -90,16 +133,68 @@ static int getprocattrcon(security_context_t * context,
 static int setprocattrcon_raw(security_context_t context,
 			      pid_t pid, const char *attr)
 {
+	__selinux_once(once, init_procattr);
+	init_thread_destructor();
+
 	char *path;
 	int fd, rc;
 	pid_t tid;
 	ssize_t ret;
 	int errno_hold;
 
+	switch (attr[0]) {
+		case 'c':
+			if (prev_current && !strcmp(prev_current, context))
+				return 0;
+			else {
+				free(prev_current);
+				prev_current = strdup(context);
+			}
+			break;
+		case 'e':
+			if (prev_exec && !strcmp(prev_exec, context))
+				return 0;
+			else {
+				free(prev_exec);
+				prev_exec = strdup(context);
+			}
+			break;
+		case 'f':
+			if (prev_fscreate && !strcmp(prev_fscreate, context))
+				return 0;
+			else {
+				free(prev_fscreate);
+				prev_fscreate = strdup(context);
+			}
+			break;
+		case 'k':
+			if (prev_keycreate && !strcmp(prev_keycreate, context))
+				return 0;
+			else {
+				free(prev_keycreate);
+				prev_keycreate = strdup(context);
+			}
+			break;
+		case 's':
+			if (prev_sockcreate && !strcmp(prev_sockcreate, context))
+				return 0;
+			else {
+				free(prev_sockcreate);
+				prev_sockcreate = strdup(context);
+			}
+			break;
+		default:
+			return -1;
+	};
+
 	if (pid > 0)
 		rc = asprintf(&path, "/proc/%d/attr/%s", pid, attr);
 	else {
-		tid = gettid();
+		if (prev_tid == -1)
+			prev_tid = tid = gettid();
+		else
+			tid = prev_tid;
+
 		rc = asprintf(&path, "/proc/self/task/%d/attr/%s", tid, attr);
 	}
 	if (rc < 0)
-- 
1.7.11.7


[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux