linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] sns: check related executable memory of binaries [3/4]
@ 2007-06-21 16:02 Alexander Wuerstlein
  0 siblings, 0 replies; 2+ messages in thread
From: Alexander Wuerstlein @ 2007-06-21 16:02 UTC (permalink / raw)
  To: linux-kernel; +Cc: Johannes Schlumberger

From: Johannes Schlumberger <spjsschl@cip.informatik.uni-erlangen.de>

Checks on mmap and mprotect (i.e. libraries) wether they are signed and adjusts
the processe's signed flag accordingly.

If a process looses its signed state it gets, in our current design, killed, for
it is no longer trustworthy. A process also looses its signed flag if it mprotects
any memory as executable.

Signed-off-by: Johannes Schlumberger <spjsschl@cip.informatik.uni-erlangen.de>
---
 include/linux/mm.h  |    3 ++
 include/linux/sns.h |   17 +++++++++++
 kernel/fork.c       |    7 ++++
 mm/mmap.c           |   79 +++++++++++++++++++++++++++++++++++++++++++++++----
 mm/mprotect.c       |   30 +++++++++++++++++++
 security/Kconfig    |   36 +++++++++++++++++++++++
 security/sns.c      |   10 ++++++
 7 files changed, 176 insertions(+), 6 deletions(-)

diff --git a/include/linux/mm.h b/include/linux/mm.h
index e4183c6..903bc45 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -112,6 +112,9 @@ struct vm_area_struct {
 #ifdef CONFIG_NUMA
 	struct mempolicy *vm_policy;	/* NUMA policy for the VMA */
 #endif
+#ifdef CONFIG_SNS_SIGNED
+	int sns_valid_sig;
+#endif
 };
 
 extern struct kmem_cache *vm_area_cachep;
diff --git a/include/linux/sns.h b/include/linux/sns.h
index ad15e4b..eefb6e7 100644
--- a/include/linux/sns.h
+++ b/include/linux/sns.h
@@ -1,3 +1,20 @@
 #ifdef CONFIG_SNS_SIGNED
 int sns_signature_valid(struct file *);
+int sns_signature_becomes_invalid(void);
+
+/*
+ * The following is unfortunately necessary, there does not seem to be a
+ * common define to find out wether some ominous DSO which somebody
+ * likes to mmap or mprotect is in fact trustworthy kernel code.
+ */
+#ifdef CONFIG_X86
+#define sns_is_gate_vdso(addr, len) (addr==0xffffe000 && len == PAGE_SIZE)
+#else
+#ifdef CONFIG_IA64
+#define sns_is_gate_vdso(addr, len) (addr==0xffffe000UL && len == PAGE_SIZE)
+#else
+#define sns_is_gate_vdso(addr, len) 0
+#endif
+#endif
+
 #endif
diff --git a/kernel/fork.c b/kernel/fork.c
index c12cf61..b1afa57 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -260,6 +260,9 @@ static inline int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
 		file = tmp->vm_file;
 		if (file) {
 			struct inode *inode = file->f_path.dentry->d_inode;
+#ifdef CONFIG_SNS_SIGNED
+			tmp->sns_valid_sig = mpnt->sns_valid_sig;
+#endif
 			get_file(file);
 			if (tmp->vm_flags & VM_DENYWRITE)
 				atomic_dec(&inode->i_writecount);
@@ -271,6 +274,10 @@ static inline int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
 			vma_prio_tree_add(tmp, mpnt);
 			flush_dcache_mmap_unlock(file->f_mapping);
 			spin_unlock(&file->f_mapping->i_mmap_lock);
+#ifdef CONFIG_SNS_SIGNED
+		} else {
+			tmp->sns_valid_sig = 0;
+#endif
 		}
 
 		/*
diff --git a/mm/mmap.c b/mm/mmap.c
index 68b9ad2..1f4bdf0 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -25,6 +25,9 @@
 #include <linux/mount.h>
 #include <linux/mempolicy.h>
 #include <linux/rmap.h>
+#ifdef CONFIG_SNS_SIGNED
+#include <linux/sns.h>
+#endif
 
 #include <asm/uaccess.h>
 #include <asm/cacheflush.h>
@@ -1101,10 +1104,33 @@ munmap_back:
 		error = file->f_op->mmap(file, vma);
 		if (error)
 			goto unmap_and_free_vma;
-	} else if (vm_flags & VM_SHARED) {
-		error = shmem_zero_setup(vma);
-		if (error)
-			goto free_vma;
+#ifdef CONFIG_SNS_SIGNED
+		if (current->sns_valid_sig && (vm_flags & VM_EXEC)) {
+			if (vm_flags & VM_WRITE){
+				vma->sns_valid_sig = 0;
+				current->sns_valid_sig = 0;
+				sns_signature_becomes_invalid();
+			} else {
+				vma->sns_valid_sig = sns_signature_valid(file);
+				current->sns_valid_sig = vma->sns_valid_sig;
+				if(!current->sns_valid_sig)
+					sns_signature_becomes_invalid();
+			}
+		}
+#endif
+	} else {
+#ifdef CONFIG_SNS_SIGNED
+		/* JIT could have written some evil code here, which we are unable to verify */
+		if (prot & PROT_EXEC && current->sns_valid_sig) {
+			if ((vma->sns_valid_sig = (current->sns_valid_sig = (sns_is_gate_vdso(addr, len)))))
+				sns_signature_becomes_invalid();
+		}
+#endif
+		if (vm_flags & VM_SHARED) {
+			error = shmem_zero_setup(vma);
+			if (error)
+				goto free_vma;
+		}
 	}
 
 	/* We set VM_ACCOUNT in a shared mapping's vm_flags, to inform
@@ -1946,8 +1972,49 @@ unsigned long do_brk(unsigned long addr, unsigned long len)
 	vma->vm_end = addr + len;
 	vma->vm_pgoff = pgoff;
 	vma->vm_flags = flags;
-	vma->vm_page_prot = protection_map[flags &
-				(VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)];
+
+#ifdef CONFIG_SNS_SIGNED
+	/*
+	 * A signed process could put executable code into an area
+	 * it got from brk(). We can either disable the exec-bit on
+	 * that area, which might break some programs, or we can
+	 * allow the exec bit but remove the signed status, thereby
+	 * unsigning any program that does some malloc()...
+	 *
+	 * Choose your poison.
+	 */
+
+	if (current->sns_valid_sig){
+#ifdef CONFIG_SNS_BRK_ALLOW_EXEC
+		vma->vm_page_prot = protection_map[flags &
+			(VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)];
+
+
+#ifdef CONFIG_SNS_BRK_UNSIGN
+		current->sns_valid_sig = 0;
+		sns_signature_becomes_invalid();
+		vma->sns_valid_sig = 0;
+#endif /* CONFIG_SNS_BRK_UNSIGN */
+
+
+
+#else /* not CONFIG_SNS_BRK_ALLOW_EXEC */
+		vma->vm_page_prot = protection_map[flags &
+			(VM_READ|VM_WRITE|VM_SHARED)];
+#endif /* CONFIG_SNS_BRK_ALLOW_EXEC */
+	} else {
+		vma->vm_page_prot = protection_map[flags & (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)];
+	}
+
+
+#else /* not CONFIG_SNS_SIGNED */
+	vma->vm_page_prot = protection_map[flags & (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)];
+
+
+
+
+#endif /* CONFIG_SNS_SIGNED */
+
 	vma_link(mm, vma, prev, rb_link, rb_parent);
 out:
 	mm->total_vm += len >> PAGE_SHIFT;
diff --git a/mm/mprotect.c b/mm/mprotect.c
index 3b8f3c0..db17887 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -26,6 +26,10 @@
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 
+#ifdef CONFIG_SNS_SIGNED
+#include <linux/sns.h>
+#endif
+
 static void change_pte_range(struct mm_struct *mm, pmd_t *pmd,
 		unsigned long addr, unsigned long end, pgprot_t newprot,
 		int dirty_accountable)
@@ -289,6 +293,32 @@ sys_mprotect(unsigned long start, size_t len, unsigned long prot)
 		if (error)
 			goto out;
 
+#ifdef CONFIG_SNS_SIGNED
+		if (! sns_is_gate_vdso(start, len)) {
+			if ((newflags & VM_EXEC) && current->sns_valid_sig){
+				if ((newflags & VM_WRITE) == 0) {
+					if (current->sns_valid_sig && vma->vm_file) {
+						vma->sns_valid_sig = sns_signature_valid(vma->vm_file);
+						current->sns_valid_sig = vma->sns_valid_sig;
+						if (!current->sns_valid_sig)
+							sns_signature_becomes_invalid();
+					} else {
+						vma->sns_valid_sig = 0;
+						current->sns_valid_sig = 0;
+						sns_signature_becomes_invalid();
+					}
+				} else {
+					vma->sns_valid_sig = 0;
+					current->sns_valid_sig = 0;
+					sns_signature_becomes_invalid();
+				}
+			}
+		} else {
+			/* always trust kernelspace */
+			vma->sns_valid_sig = 1;
+		}
+#endif
+
 		tmp = vma->vm_end;
 		if (tmp > end)
 			tmp = end;
diff --git a/security/Kconfig b/security/Kconfig
index bfaace7..9776e29 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -32,6 +32,42 @@ config SNS_SIGNED_SETGID
 
 	  If you don't know exactly what you are doing, answer N.
 
+config SNS_BRK_ALLOW_EXEC
+	bool "Allows the executable bit to be set on brk()-ed memory"
+	depends on SNS_SIGNED
+	help
+	  By default the memory a process gets from brk() is executable.
+	  This is undesirable in our situation because it would allow
+	  an evil binary to load unsigned code.
+
+	  We can either disable the exec-bit on that area (set this option to
+	  off), which might break some programs, or we can allow the exec bit
+	  but remove the signed status (this option on, next option on),
+	  thereby unsigning any program that does some malloc()...
+
+          Choose your poison.
+
+	  On old x86 (without CPU-flag NX to be exact) this option is useless
+	  because every readable page is also executable. This might apply to
+	  some other broken architectures as well. YMMV.
+
+	  The default behaviour everybody expects is probably broken
+	  either way. If you do not want any problems or you are
+	  unsure, enable this option (SNS_BREAK_ALLOW_EXEC) and
+	  disable the next one (SNS_BRK_UNSIGN).
+
+	  I repeat: Always say Y, unless you are very brave...
+
+config SNS_BRK_UNSIGN
+	bool "Unsign process after doing brk()"
+	depends on SNS_BRK_ALLOW_EXEC
+	help
+	  Remove signed bit from any process that does brk().
+
+	  See previous option (SNS_BRK_ALLOW_EXEC) for help.
+
+	  If unsure say N.
+
 config KEYS
 	bool "Enable access key retention support"
 	help
diff --git a/security/sns.c b/security/sns.c
index 4403e5a..3192a90 100644
--- a/security/sns.c
+++ b/security/sns.c
@@ -33,6 +33,16 @@ static int sns_sig_reader(read_descriptor_t *desc, struct page *page, unsigned l
 	return read;
 }
 
+int sns_signature_becomes_invalid(void)
+{
+	current->sns_valid_sig = 0;
+	/*no checking necessary because of SEND_SIG_FORCED*/
+	force_sig_info(SIGKILL, SEND_SIG_FORCED, current);
+	return 0; /*Leave the actual killing to the scheduler*/
+	/*TODO check if the process has any way left to execute any code*/
+}
+
+
 /*
  * check file signature for setuid
  */
-- 
1.5.2.1


^ permalink raw reply related	[flat|nested] 2+ messages in thread
* [PATCH] signed binaries support [0/4]
@ 2007-06-21 15:55 Johannes Schlumberger
  2007-06-22 18:25 ` [PATCH] sns: check related executable memory of binaries [3/4] Alexander Wuerstlein
  0 siblings, 1 reply; 2+ messages in thread
From: Johannes Schlumberger @ 2007-06-21 15:55 UTC (permalink / raw)
  To: linux-kernel

Hi,

We (two students of CS) built a system for signing binaries and verifying them
before executing. Our main focus was to implement a way to inhibit execution
of suid-binaries, which are not trustworthy (i.e. not signed). Of course this
can also be used to grant other access rights, capabilities, etc.

The signature (e.g. HMAC-SHA1 with a shared secret) is stored in extended
filesystem attributes (userland-signing-tool provided) [1]. Depending on the
outcome of our check (performed during exec) a newly introduced flag in
the task_struct is set. To be able to also check libraries, we introduced a
similar flag in the vm_area struct. Depending on the state of the flag, the
suid/sgid bit on the file is honored or ignored. If a process behaves badly
(e.g mapping executable memory writable or loading an untrusted library) it
is handled appropriately (killed in our current implementation).

In the current state our code is of course very expermimental and should be
handled with care.

We mainly seek comments, suggestions and wisdom before we tackle the more
difficult tasks, like proper signatures (public-key-systems, etc.).

regards,
	Johannes

[1] http://git.informatik.uni-erlangen.de/?p=ssuid-userland&a=snapshot;h=HEAD

-- 
Johannes Schlumberger                      Department of Computer Science IV
Martensstrasse 1  D-91058 Erlangen Germany  University of Erlangen-Nuremberg
             http://wwwcip.informatik.uni-erlangen.de/~spjsschl

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2007-06-22 18:26 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-06-21 16:02 [PATCH] sns: check related executable memory of binaries [3/4] Alexander Wuerstlein
  -- strict thread matches above, loose matches on Subject: below --
2007-06-21 15:55 [PATCH] signed binaries support [0/4] Johannes Schlumberger
2007-06-22 18:25 ` [PATCH] sns: check related executable memory of binaries [3/4] Alexander Wuerstlein

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).