linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] signed binaries support [0/4]
@ 2007-06-21 15:55 Johannes Schlumberger
  2007-06-21 16:17 ` Adrian Bunk
                   ` (4 more replies)
  0 siblings, 5 replies; 26+ 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] 26+ messages in thread
* [PATCH] Check files' signatures before doing suid/sgid [2/4]
@ 2007-06-21 16:02 Alexander Wuerstlein
  2007-06-21 17:17 ` Arjan van de Ven
  0 siblings, 1 reply; 26+ messages in thread
From: Alexander Wuerstlein @ 2007-06-21 16:02 UTC (permalink / raw)
  To: linux-kernel; +Cc: Alexander Wuerstlein, Johannes Schlumberger

Modified task_struct to hold a 'signed flag' which is set on exec(), inherited
on fork() and checked during exec before giving the new process suid/sgid
privileges.

sns.c contains our helper functions to verify the signatures.
sns_secret_key.dat contains the 'secret key' which is used for HMAC.

Signed-off-by: Johannes Schlumberger <spjsschl@cip.informatik.uni-erlangen.de>
---
 fs/exec.c                   |   19 +++++++-
 include/linux/Kbuild        |    2 +
 include/linux/sched.h       |    3 +
 include/linux/sns.h         |    3 +
 kernel/fork.c               |    6 +++
 security/Kconfig            |   28 ++++++++++++
 security/Makefile           |    1 +
 security/sns.c              |  104 +++++++++++++++++++++++++++++++++++++++++++
 security/sns_secret_key.dat |    5 ++
 9 files changed, 169 insertions(+), 2 deletions(-)
 create mode 100644 include/linux/sns.h
 create mode 100644 security/sns.c
 create mode 100644 security/sns_secret_key.dat

diff --git a/fs/exec.c b/fs/exec.c
index f20561f..5dfa406 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -51,6 +51,9 @@
 #include <linux/cn_proc.h>
 #include <linux/audit.h>
 #include <linux/signalfd.h>
+#ifdef CONFIG_SNS_SIGNED
+#include <linux/sns.h>
+#endif
 
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
@@ -928,13 +931,21 @@ int prepare_binprm(struct linux_binprm *bprm)
 	mode = inode->i_mode;
 	if (bprm->file->f_op == NULL)
 		return -EACCES;
+#ifdef CONFIG_SNS_SIGNED
+	if (mode & S_ISUID)
+		current->sns_valid_sig = sns_signature_valid(bprm->file);
+#endif
 
 	bprm->e_uid = current->euid;
 	bprm->e_gid = current->egid;
 
 	if(!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) {
 		/* Set-uid? */
-		if (mode & S_ISUID) {
+#ifdef CONFIG_SNS_SIGNED_SETUID
+               if (mode & S_ISUID && current->sns_valid_sig) {
+#else
+               if (mode & S_ISUID) {
+#endif /*SNS_SIGNED_SETUID*/
 			current->personality &= ~PER_CLEAR_ON_SETID;
 			bprm->e_uid = inode->i_uid;
 		}
@@ -945,7 +956,11 @@ int prepare_binprm(struct linux_binprm *bprm)
 		 * is a candidate for mandatory locking, not a setgid
 		 * executable.
 		 */
-		if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
+#ifdef CONFIG_SNS_SIGNED_SETGID
+               if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP) && current->sns_valid_sig) {
+#else
+               if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
+#endif /*SNS_SIGNED_SETGID*/
 			current->personality &= ~PER_CLEAR_ON_SETID;
 			bprm->e_gid = inode->i_gid;
 		}
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index f317c27..16df5f0 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -159,6 +159,7 @@ header-y += videotext.h
 header-y += vt.h
 header-y += wireless.h
 header-y += x25.h
+header-y += sns.h
 
 unifdef-y += acct.h
 unifdef-y += adb.h
@@ -347,5 +348,6 @@ unifdef-y += watchdog.h
 unifdef-y += wireless.h
 unifdef-y += xattr.h
 unifdef-y += xfrm.h
+unifdef-y += sns.h
 
 objhdr-y += version.h
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 693f0e6..36c58d6 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1076,6 +1076,9 @@ struct task_struct {
 #ifdef CONFIG_FAULT_INJECTION
 	int make_it_fail;
 #endif
+#ifdef CONFIG_SNS_SIGNED
+	int sns_valid_sig;
+#endif
 };
 
 static inline pid_t process_group(struct task_struct *tsk)
diff --git a/include/linux/sns.h b/include/linux/sns.h
new file mode 100644
index 0000000..ad15e4b
--- /dev/null
+++ b/include/linux/sns.h
@@ -0,0 +1,3 @@
+#ifdef CONFIG_SNS_SIGNED
+int sns_signature_valid(struct file *);
+#endif
diff --git a/kernel/fork.c b/kernel/fork.c
index 73ad5cd..c12cf61 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -156,6 +156,9 @@ void __init fork_init(unsigned long mempages)
 	init_task.signal->rlim[RLIMIT_NPROC].rlim_max = max_threads/2;
 	init_task.signal->rlim[RLIMIT_SIGPENDING] =
 		init_task.signal->rlim[RLIMIT_NPROC];
+#ifdef CONFIG_SNS_SIGNED
+	init_task.sns_valid_sig = 0;
+#endif
 }
 
 static struct task_struct *dup_task_struct(struct task_struct *orig)
@@ -182,6 +185,9 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
 #ifdef CONFIG_CC_STACKPROTECTOR
 	tsk->stack_canary = get_random_int();
 #endif
+#ifdef CONFIG_SNS_SIGNED
+	tsk->sns_valid_sig = orig->sns_valid_sig;
+#endif
 
 	/* One for us, one for whoever does the "release_task()" (usually parent) */
 	atomic_set(&tsk->usage,2);
diff --git a/security/Kconfig b/security/Kconfig
index 460e5c9..bfaace7 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -4,6 +4,34 @@
 
 menu "Security options"
 
+config SNS_SIGNED
+	bool "Enable sns-signed binaries (EXPERIMENTAL)"
+	depends on (EXT2_FS_XATTR || EXT3_FS_XATTR || EXT4DEV_FS_XATTR || REISERFS_FS_XATTR || JFFS2_FS_XATTR || CIFS_XATTR) && (CRYPTO_SHA1 || CRYPTO_HMAC || CRYPTO_MD5) && MMU && EXPERIMENTAL
+	help
+	  This option turns on sns-signatures of binaries. Requires extended
+	  attributes and cryptographic hashes/HMAC support. HMAC is preferred.
+
+	  This will leave your system unusable without proper preparation of
+	  your sbit-files.
+
+	  If you don't know exactly what you are doing, answer N.
+
+config SNS_SIGNED_SETUID
+	bool "Enables sns-signed binaries mandatory for suid-bits"
+	depends on SNS_SIGNED
+	help
+	  Mandates signed binaries for suidbits.
+
+	  If you don't know exactly what you are doing, answer N.
+
+config SNS_SIGNED_SETGID
+	bool "Enables sns-signed binaries mandatory for sgid-bits"
+	depends on SNS_SIGNED
+	help
+	  Mandates signed binaries for sgidbits.
+
+	  If you don't know exactly what you are doing, answer N.
+
 config KEYS
 	bool "Enable access key retention support"
 	help
diff --git a/security/Makefile b/security/Makefile
index ef87df2..677b978 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_SECURITY)			+= security.o dummy.o inode.o
 obj-$(CONFIG_SECURITY_SELINUX)		+= selinux/built-in.o
 obj-$(CONFIG_SECURITY_CAPABILITIES)	+= commoncap.o capability.o
 obj-$(CONFIG_SECURITY_ROOTPLUG)		+= commoncap.o root_plug.o
+obj-$(CONFIG_SNS_SIGNED)		+= sns.o
diff --git a/security/sns.c b/security/sns.c
new file mode 100644
index 0000000..4403e5a
--- /dev/null
+++ b/security/sns.c
@@ -0,0 +1,104 @@
+#include <linux/crypto.h>
+#include <linux/bug.h>
+#include <linux/err.h>
+#include <linux/scatterlist.h>
+#include <linux/xattr.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/sns.h>
+
+#include "sns_secret_key.dat"
+
+#define SNS_MAX_DIGEST_SIZE	64
+
+struct sns_attr {
+	char algname[CRYPTO_MAX_ALG_NAME+1];
+	char hash_value[SNS_MAX_DIGEST_SIZE];
+};
+
+
+static int sns_sig_reader(read_descriptor_t *desc, struct page *page, unsigned long offset, unsigned long nr)
+{
+	struct scatterlist s;
+	struct hash_desc *hash_desc = (struct hash_desc *) desc->arg.data;
+	unsigned int read;
+
+	s.page = page;
+	s.offset = offset;
+	s.length = nr;
+	read = nr - offset;
+	crypto_hash_update(hash_desc, &s, read);
+	desc->written += read;
+	desc->count -= read;
+	return read;
+}
+
+/*
+ * check file signature for setuid
+ */
+
+int sns_signature_valid(struct file *file)
+{
+	unsigned long i;
+	struct inode *inode = file->f_mapping->host;
+	struct crypto_hash *tfm;
+	struct hash_desc hash_desc;
+	struct sns_attr attrdata;
+	char hash_result[SNS_MAX_DIGEST_SIZE];
+	struct xattr_handler *handler;
+	const char *namespaces[2] = { "trusted.", NULL };
+	int ret = 0;
+	loff_t pos = 0;
+	read_descriptor_t read_desc;
+
+	handler = xattr_resolve_name_sns(inode->i_sb->s_xattr, namespaces);
+	if (unlikely(!handler)) {
+		printk(KERN_DEBUG "sns_signature_valid: xattr_resolve_name failed\n");
+		return 0;
+	}
+	memset(&attrdata, 0, sizeof(struct sns_attr));
+	i = handler->get(inode, "sns", &attrdata, sizeof(struct sns_attr));
+	if (i != sizeof(struct sns_attr)) {
+		printk(KERN_DEBUG "sns_signature_valid: invalid xattr found\n");
+		return 0;
+	}
+	attrdata.algname[CRYPTO_MAX_ALG_NAME] = '\0';
+	read_desc.count = i_size_read(inode);
+	if (unlikely(!read_desc.count)) {
+		printk(KERN_DEBUG "sns_signature_valid: inode of file has invalid size\n");
+		return 0;
+	}
+	tfm = crypto_alloc_hash(attrdata.algname, 0, CRYPTO_ALG_ASYNC);
+	if (unlikely(IS_ERR(tfm))) {
+		printk("sns_signature_valid: %s unavailable\n", attrdata.algname);
+		return 0;
+		/*FIXME: failure mode should be defined at build-time */
+	}
+	memset(hash_result, 0, SNS_MAX_DIGEST_SIZE); /*Needed?*/
+	hash_desc.tfm = tfm;
+	hash_desc.flags = 0;
+	read_desc.arg.data = &hash_desc;
+	read_desc.written = 0;
+	if (crypto_hash_setkey(tfm, sns_secret_key, SNS_SECRET_KEY_SIZE)) {
+		printk("sns_signature_valid: hash function did not accept setkey\n");
+		return 0;
+	}
+	crypto_hash_init(&hash_desc);
+	do_generic_file_read(file, &pos, &read_desc, sns_sig_reader);
+	crypto_hash_final(&hash_desc, hash_result);
+	BUG_ON(read_desc.written != i_size_read(inode));
+#ifdef SNS_SIGNED_DEBUG
+	printk("sns_signature_valid: attrdata.algname = %s\n", attrdata.algname);
+	printk("sns_signature_valid: attrib: ");
+	for (i = 0; i < SNS_MAX_DIGEST_SIZE; i++)
+		printk("%02x ", (unsigned char) attrdata.hash_value[i]);
+	printk("\n");
+	printk("sns_signature_valid: result: ");
+	for (i = 0; i < SNS_MAX_DIGEST_SIZE; i++)
+		printk("%02x ", (unsigned char) hash_result[i]);
+	printk("\n");
+#endif
+	ret = !memcmp(attrdata.hash_value, hash_result, SNS_MAX_DIGEST_SIZE);
+	crypto_free_hash(tfm);
+	return ret;
+}
diff --git a/security/sns_secret_key.dat b/security/sns_secret_key.dat
new file mode 100644
index 0000000..aec09da
--- /dev/null
+++ b/security/sns_secret_key.dat
@@ -0,0 +1,5 @@
+#define SNS_SECRET_KEY_SIZE 8
+static char sns_secret_key[SNS_SECRET_KEY_SIZE] =
+	{
+		'd', 'e', 'a', 'd', 'b', 'e', 'e', 'f'
+	};
-- 
1.5.2.1


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

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

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-06-21 15:55 [PATCH] signed binaries support [0/4] Johannes Schlumberger
2007-06-21 16:17 ` Adrian Bunk
2007-06-21 16:29   ` Alexander Wuerstlein
2007-06-21 17:23     ` Adrian Bunk
2007-06-21 17:34       ` Alexander Wuerstlein
2007-06-21 18:05         ` Adrian Bunk
2007-06-21 18:21           ` Johannes Schlumberger
2007-06-22 18:25 ` [PATCH] export xattr_resolve_name_sns [1/4] Alexander Wuerstlein
2007-06-22 18:25 ` [PATCH] Check files' signatures before doing suid/sgid [2/4] Alexander Wuerstlein
2007-06-22 19:36   ` Satyam Sharma
2007-06-24 22:58     ` Alexander Wuerstlein
2007-06-25 23:53       ` Satyam Sharma
2007-06-26  0:27         ` Alexander Wuerstlein
2007-06-26  2:13           ` Satyam Sharma
2007-06-23 17:54   ` Jan Engelhardt
2007-06-22 18:25 ` [PATCH] sns: check related executable memory of binaries [3/4] Alexander Wuerstlein
2007-06-22 18:25 ` [PATCH] sns: add syscall to check signed state of a process [4/4] Alexander Wuerstlein
2007-06-21 16:02 [PATCH] Check files' signatures before doing suid/sgid [2/4] Alexander Wuerstlein
2007-06-21 17:17 ` Arjan van de Ven
2007-06-21 17:25   ` Alexander Wuerstlein
2007-06-21 17:29     ` Arjan van de Ven
2007-06-21 17:46       ` Alexander Wuerstlein
2007-06-21 18:49         ` Arjan van de Ven
2007-06-21 21:40           ` Johannes Schlumberger
2007-06-23 18:01         ` Jan Engelhardt
2007-06-25 10:54           ` Johannes Schlumberger

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).