lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:   Sun, 21 Aug 2016 21:01:34 -0700
From:   Josh Max <JMax@...l.greenriver.edu>
To:     <viro@...iv.linux.org.uk>
CC:     <linux-fsdevel@...r.kernel.org>, <linux-kernel@...r.kernel.org>,
        Josh Max <JMax@...l.greenriver.edu>
Subject: [PATCH] binfmt_misc: allow selecting the interpreter based on xattr keywords

This patch allows binfmt_misc to select the interpeter for arbitrary
binaries by comparing a specified registered keyword with the value
of a specified binary's extended attribute (user.binfmt.interp),
and then launching the program with the registered interpreter.

This is useful when wanting to launch a collection of binaries under
the same interpreter, even when they do not necessarily share a common
extension or magic bits, or when their magic conflics with the operation
of binfmt_elf. Some examples of its use would be to launch some executables
of various different architectures in a directory, or for running some
native binaries under a sandbox (like firejail) automatically during their
launch.

Signed-off-by: Josh Max <JMax@...l.greenriver.edu>
---
 fs/binfmt_misc.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 47 insertions(+), 4 deletions(-)

diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index 6103a63..86d93c7 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -24,6 +24,7 @@
 #include <linux/mount.h>
 #include <linux/syscalls.h>
 #include <linux/fs.h>
+#include <linux/xattr.h>
 #include <linux/uaccess.h>
 
 #include "internal.h"
@@ -41,12 +42,17 @@ enum {
 static LIST_HEAD(entries);
 static int enabled = 1;
 
-enum {Enabled, Magic};
+enum {Enabled, Magic, Keyword};
 #define MISC_FMT_PRESERVE_ARGV0 (1 << 31)
 #define MISC_FMT_OPEN_BINARY (1 << 30)
 #define MISC_FMT_CREDENTIALS (1 << 29)
 #define MISC_FMT_OPEN_FILE (1 << 28)
 
+#define XATTR_BINFMT_PREFIX XATTR_USER_PREFIX "binfmt."
+#define XATTR_BINFMT_INTERPRETER_SUFFIX "interp"
+#define XATTR_NAME_BINFMT (XATTR_BINFMT_PREFIX XATTR_BINFMT_INTERPRETER_SUFFIX)
+#define XATTR_VALUE_MAX_LENGTH 128
+
 typedef struct {
 	struct list_head list;
 	unsigned long flags;		/* type, status, etc. */
@@ -61,6 +67,7 @@ typedef struct {
 } Node;
 
 static DEFINE_RWLOCK(entries_lock);
+static int get_xattr_interp_keyword(struct file *file, char *buf, size_t count);
 static struct file_system_type bm_fs_type;
 static struct vfsmount *bm_mnt;
 static int entry_count;
@@ -87,6 +94,8 @@ static int entry_count;
  */
 static Node *check_file(struct linux_binprm *bprm)
 {
+	char k[XATTR_VALUE_MAX_LENGTH];
+	int k_len = get_xattr_interp_keyword(bprm->file, k, sizeof(k)-1);
 	char *p = strrchr(bprm->interp, '.');
 	struct list_head *l;
 
@@ -100,6 +109,16 @@ static Node *check_file(struct linux_binprm *bprm)
 		if (!test_bit(Enabled, &e->flags))
 			continue;
 
+		/* Do matching based on xattrs keyword */
+		if (test_bit(Keyword, &e->flags)) {
+			if (k_len <= 0)
+				continue;
+			k[k_len] = 0;
+			if (!strcmp(e->magic, k))
+				return e;
+			continue;
+		}
+
 		/* Do matching based on extension if applicable. */
 		if (!test_bit(Magic, &e->flags)) {
 			if (p && !strcmp(e->magic, p + 1))
@@ -309,6 +328,20 @@ static char *check_special_flags(char *sfs, Node *e)
 }
 
 /*
+ * Check to see if the filesystem supports xattrs
+ * and grab the value so it can be checked against
+ * the list of keywords in binfmt_misc for a match
+ */
+static int get_xattr_interp_keyword(struct file *file, char *buf, size_t count)
+{
+
+	if (unlikely(!file->f_inode->i_op->getxattr))
+		return -ENOENT;
+	return file->f_inode->i_op->getxattr(file->f_path.dentry, file->f_inode,
+		XATTR_NAME_BINFMT, buf, count);
+}
+
+/*
  * This registers a new binary format, it recognises the syntax
  * ':name:type:offset:magic:mask:interpreter:flags'
  * where the ':' is the IFS, that can be chosen with the first char
@@ -366,6 +399,10 @@ static Node *create_entry(const char __user *buffer, size_t count)
 		pr_debug("register: type: E (extension)\n");
 		e->flags = 1 << Enabled;
 		break;
+	case 'K':
+		pr_debug("register: type: K (xattrs keyword)\n");
+		e->flags = (1 << Enabled) | (1 << Keyword);
+		break;
 	case 'M':
 		pr_debug("register: type: M (magic)\n");
 		e->flags = (1 << Enabled) | (1 << Magic);
@@ -453,7 +490,7 @@ static Node *create_entry(const char __user *buffer, size_t count)
 			}
 		}
 	} else {
-		/* Handle the 'E' (extension) format. */
+		/* Handle the 'E' (extension) and 'K' (keyword) format. */
 
 		/* Skip the 'offset' field. */
 		p = strchr(p, del);
@@ -469,7 +506,10 @@ static Node *create_entry(const char __user *buffer, size_t count)
 		*p++ = '\0';
 		if (!e->magic[0] || strchr(e->magic, '/'))
 			goto einval;
-		pr_debug("register: extension: {%s}\n", e->magic);
+		if (test_bit(Keyword, &e->flags))
+			pr_debug("register: keyword: {%s}\n", e->magic);
+		else
+			pr_debug("register: extension: {%s}\n", e->magic);
 
 		/* Skip the 'mask' field. */
 		p = strchr(p, del);
@@ -563,7 +603,10 @@ static void entry_status(Node *e, char *page)
 	*dp++ = '\n';
 
 	if (!test_bit(Magic, &e->flags)) {
-		sprintf(dp, "extension .%s\n", e->magic);
+		if (test_bit(Keyword, &e->flags))
+			sprintf(dp, "keyword %s\n", e->magic);
+		else
+			sprintf(dp, "extension .%s\n", e->magic);
 	} else {
 		dp += sprintf(dp, "offset %i\nmagic ", e->offset);
 		dp = bin2hex(dp, e->magic, e->size);
-- 
2.8.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ