Skip to contentSkip to conversation

selinux: apply execstack check on thread stacks

RFC PATCH In review Stephen Smalley 2 participants 3 messages Apr 6, 2016 SELinux security module

lore
Share & tools
lore
#0 lore raw

RFC PATCH 1/1 selinux: apply execstack check on thread stacks

The execstack check was only being applied on the main process stack.  Thread stacks allocated via mmap were only subject to the execmem permission check.  Augment the check to apply to the current thread stack as well. Note that this does NOT prevent making a different thread's stack executable.

---
 security/selinux/hooks.c | 5 +++--

 1 file changed, 3 insertions(+), 2 deletions(-)
security/selinux/hooks.c +0 -0
index a9ca5ee..0271be4 100644
@@ -3465,8 +3465,9 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,

      vma->vm_end <= vma->vm_mm->brk) {
  rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP); } else if (!vma->vm_file &&
-    vma->vm_start <= vma->vm_mm->start_stack &&
-    vma->vm_end >= vma->vm_mm->start_stack) {
+    ((vma->vm_start <= vma->vm_mm->start_stack &&
+      vma->vm_end >= vma->vm_mm->start_stack) ||
+     vma_is_stack_for_task(vma, current))) {
  rc = current_has_perm(current, PROCESS__EXECSTACK); } else if (vma->vm_file && vma->anon_vma) {
  /*
--
2.8.0

#1 lore raw

RFC PATCH 1/1 selinux-testsuite: Add test for execstack on thread stack

Test execstack permission checking for thread stacks. This depends on the corresponding kernel patch to apply the check for thread stacks in addition to the main process stack.

---
 tests/mmap/Makefile                |  2 ++ tests/mmap/mprotect_stack_thread.c | 33 +++++++++++++++++++++++++++++++++ tests/mmap/test                    |  8 +++++++-

 3 files changed, 42 insertions(+), 1 deletion(-)

 create mode 100644 tests/mmap/mprotect_stack_thread.c

tests/mmap/Makefile +0 -0
index f2f486c..e330f3e 100644
@@ -1,5 +1,7 @@

 TARGETS=$(patsubst %.c,%,$(wildcard *.c))

+LDLIBS += -lpthread
+
 all: $(TARGETS)

 clean:

tests/mmap/mprotect_stack_thread.c new file +33 -0
new file mode 100644
index 0000000..457b294
@@ -0,0 +1,33 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <pthread.h>
+
+static void *test_thread(void *p)
+{
+	char buf[4096];
+	int rc;
+	void *ptr;
+	long pagesize = sysconf(_SC_PAGESIZE);
+
+	ptr = (void *) (((unsigned long) buf) & ~(pagesize - 1));
+
+	rc = mprotect(ptr, pagesize, PROT_READ | PROT_WRITE | PROT_EXEC);
+	if (rc < 0) {
+		perror("mprotect");
+		exit(1);
+	}
+	return NULL;
+}
+
+int main(void)
+{
+	pthread_t thread;
+
+	pthread_create(&thread, NULL, test_thread, NULL);
+	pthread_join(thread, NULL);
+	exit(0);
+}
+
tests/mmap/test +0 -0
index 6b1de55..89badda 100755
@@ -1,7 +1,7 @@

 #!/usr/bin/perl

 use Test;
-BEGIN { plan tests => 30}
+BEGIN { plan tests => 32}

 $basedir = $0;  $basedir =~ s|(.*)/[^/]*|$1|;

@@ -68,6 +68,12 @@ ok($result, 0);
 $result = system "runcon -t test_execmem_t $basedir/mprotect_stack 2>&1"; ok($result);

+# Test success and failure for thread execstack, independent of execmem. +$result = system "runcon -t test_execstack_t $basedir/mprotect_stack_thread"; +ok($result, 0);
+$result = system "runcon -t test_execmem_t $basedir/mprotect_stack_thread 2>&1"; +ok($result);
+
 # Test success and failure for file execute on mmap w/ file shared mapping. $result = system "runcon -t test_file_rwx_t $basedir/mmap_file_shared $basedir/temp_file"; ok($result, 0);
--
2.8.0

Acked-by on v1 1/1
#2 lore raw
In reply to Stephen Smalley

Thanks!

Quoted 8 lines · Stephen Smalley

The execstack check was only being applied on the main process stack. Thread stacks allocated via mmap were only subject to the execmem permission check. Augment the check to apply to the current thread stack as well. Note that this does NOT prevent making a different thread's stack executable.

Quoted 24 lines
---
 security/selinux/hooks.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
security/selinux/hooks.c +3 -3
index a9ca5ee..0271be4 100644
@@ -3465,8 +3465,9 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
                    vma->vm_end <= vma->vm_mm->brk) {
                        rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP);
                } else if (!vma->vm_file &&
-                          vma->vm_start <= vma->vm_mm->start_stack &&
-                          vma->vm_end >= vma->vm_mm->start_stack) {
+                          ((vma->vm_start <= vma->vm_mm->start_stack &&
+                            vma->vm_end >= vma->vm_mm->start_stack) ||
+                           vma_is_stack_for_task(vma, current))) {
                        rc = current_has_perm(current, PROCESS__EXECSTACK);
                } else if (vma->vm_file && vma->anon_vma) {
                        /*
--

2.8.0

Signature · 1 line
Nick Kralevich | Android Security | [email protected] | 650.214.4037