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-prev] [thread-next>] [day] [month] [year] [list]
Date:	Wed, 21 Oct 2009 04:06:33 -0400 (EDT)
From:	"Ryan C. Gordon" <icculus@...ulus.org>
To:	Américo Wang <xiyou.wangcong@...il.com>
cc:	linux-kernel@...r.kernel.org
Subject: Re: [RFC][PATCH 2/2] binfmt_elf: FatELF support for kernel
 modules.


> As for 'Elf_Ehdr', isn't 'Fatelf_hdr' better? :)

Yeah, I struggled with that for awhile...the structs around it in elf.h 
were all lowercase (elf32_hdr), but I moved it somewhere more appropriate 
and fixed the case.

These were all good suggestions, so here's an updated version of the patch 
with the changes you noted. Thank you for taking the time to review my 
work!

--ryan.



>From 38cbb068c3970e9981549578c20207458a2b6659 Mon Sep 17 00:00:00 2001
From: Ryan C. Gordon <icculus@...ulus.org>
Date: Tue, 20 Oct 2009 20:36:05 -0400
Subject: [PATCH] binfmt_elf: FatELF support for kernel modules.

Allows kernel modules to be FatELF binaries.

Details, rationale, tools, and patches for handling FatELF binaries can be
found at http://icculus.org/fatelf/

Please note that this requires an updated depmod and modprobe to be truly
effective, but an unmodified insmod can work with FatELF binaries.

Signed-off-by: Ryan C. Gordon <icculus@...ulus.org>
---
 kernel/module.c |   65 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 60 insertions(+), 5 deletions(-)

diff --git a/kernel/module.c b/kernel/module.c
index 8b7d880..e8b2e8f 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2066,13 +2066,62 @@ static inline void kmemleak_load_module(struct module *mod, Elf_Ehdr *hdr,
 }
 #endif
 
+/*
+ * See if we're a valid FatELF binary, find the right record, and
+ *  return the offset of that record within the binary. Returns NULL if there's
+ *  a problem, or a pointer to the real ELF header if we're okay.
+ *  If we don't see the FatELF magic number, we assume this is a regular ELF
+ *  binary and let the regular ELF checks handle it.
+ *
+ * This is a simplified version of examine_fatelf in fs/binfmt_elf.c
+ */
+static Elf_Ehdr *examine_fatelf_module(const unsigned char *hdr,
+				       const unsigned long len)
+{
+	Elf_Ehdr elf;
+	int records, i;
+	const Fatelf_hdr *fatelf = (const Fatelf_hdr *) hdr;
+
+	if (likely(le32_to_cpu(fatelf->magic) != FATELF_MAGIC))
+		return (Elf_Ehdr *) hdr;  /* not FatELF; not an error. */
+	else if (unlikely(le16_to_cpu(fatelf->version) != 1))
+		return NULL; /* Unrecognized format version. */
+
+	memset(&elf, 0, sizeof (elf));
+
+	records = (int) fatelf->num_records;  /* uint8, no byteswap needed */
+	for (i = 0; i < records; i++) {
+		const Fatelf_record *record = &fatelf->records[i];
+
+		/* Fill in the data elf_check_arch() might care about. */
+		elf.e_ident[EI_OSABI] = record->osabi;
+		elf.e_ident[EI_CLASS] = record->word_size;
+		elf.e_ident[EI_DATA] = record->byte_order;
+		elf.e_machine = le16_to_cpu(record->machine);
+
+		if (unlikely(elf_check_arch(&elf))) {
+			const __u64 rec_offset = le64_to_cpu(record->offset);
+			const __u64 rec_size = le64_to_cpu(record->size);
+			const __u64 end_offset = rec_offset + rec_size;
+			const unsigned long uloff = (unsigned long) rec_offset;
+
+			/* check for overflow and past-EOF before choosing this record */
+			if (likely((end_offset >= rec_offset) && (end_offset <= len)))
+				return (Elf_Ehdr *) (hdr + uloff);
+		}
+	}
+
+	return NULL;  /* no binaries we could use. */
+}
+
 /* Allocate and load the module: note that size of section 0 is always
    zero, and we rely on this for optional sections. */
 static noinline struct module *load_module(void __user *umod,
 				  unsigned long len,
 				  const char __user *uargs)
 {
-	Elf_Ehdr *hdr;
+	Elf_Ehdr *hdr_alloc;  /* returned from vmalloc */
+	Elf_Ehdr *hdr;  /* adjusted hdr_alloc for FatELF */
 	Elf_Shdr *sechdrs;
 	char *secstrings, *args, *modmagic, *strtab = NULL;
 	char *staging;
@@ -2094,14 +2143,20 @@ static noinline struct module *load_module(void __user *umod,
 
 	/* Suck in entire file: we'll want most of it. */
 	/* vmalloc barfs on "unusual" numbers.  Check here */
-	if (len > 64 * 1024 * 1024 || (hdr = vmalloc(len)) == NULL)
+	if (len > 64 * 1024 * 1024 || (hdr_alloc = vmalloc(len)) == NULL)
 		return ERR_PTR(-ENOMEM);
 
-	if (copy_from_user(hdr, umod, len) != 0) {
+	if (copy_from_user(hdr_alloc, umod, len) != 0) {
 		err = -EFAULT;
 		goto free_hdr;
 	}
 
+	hdr = examine_fatelf_module((unsigned char *) hdr_alloc, len);
+	if (hdr == NULL) {
+		err = -ENOEXEC;
+		goto free_hdr;
+	}
+
 	/* Sanity checks against insmoding binaries or wrong arch,
            weird elf version */
 	if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0
@@ -2505,7 +2560,7 @@ static noinline struct module *load_module(void __user *umod,
 	add_notes_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
 
 	/* Get rid of temporary copy */
-	vfree(hdr);
+	vfree(hdr_alloc);
 
 	trace_module_load(mod);
 
@@ -2538,7 +2593,7 @@ static noinline struct module *load_module(void __user *umod,
 	kfree(args);
 	kfree(strmap);
  free_hdr:
-	vfree(hdr);
+	vfree(hdr_alloc);
 	return ERR_PTR(err);
 
  truncated:
-- 
1.6.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ