Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757002AbZJ3CZr (ORCPT ); Thu, 29 Oct 2009 22:25:47 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1756241AbZJ3CZq (ORCPT ); Thu, 29 Oct 2009 22:25:46 -0400 Received: from icculus.org ([67.106.77.212]:55318 "EHLO icculus.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753584AbZJ3CZp (ORCPT ); Thu, 29 Oct 2009 22:25:45 -0400 Date: Thu, 29 Oct 2009 22:25:49 -0400 (EDT) From: "Ryan C. Gordon" X-X-Sender: icculus@andre.icculuslan To: linux-kernel@vger.kernel.org Subject: Re: [RFC][PATCH 2/2] binfmt_elf: FatELF support for kernel modules. In-Reply-To: <4AE5F4FB.3000506@goop.org> Message-ID: References: <4ADD0086.9060304@goop.org> <4AE22D04.50708@goop.org> <20091024121421.2e530635@lxorguk.ukuu.org.uk> <4AE5F4FB.3000506@goop.org> User-Agent: Alpine 2.00 (DEB 1167 2008-08-23) MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 4837 Lines: 144 (Hopefully-final version, now checkpatch.pl approved!) >From 16233022abfa6561b9416d374c74b4e42d7632ca Mon Sep 17 00:00:00 2001 From: Ryan C. Gordon Date: Tue, 27 Oct 2009 14:00:12 -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 --- kernel/module.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 files changed, 66 insertions(+), 5 deletions(-) diff --git a/kernel/module.c b/kernel/module.c index 8b7d880..94e0153 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2066,13 +2066,64 @@ 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 struct Fatelf_hdr *fatelf = (const struct 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 struct 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 in this record */ + if (likely(likely(end_offset >= rec_offset) && + likely(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 +2145,24 @@ 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 (unlikely(len > 64 * 1024 * 1024)) + return ERR_PTR(-ENOMEM); + + hdr_alloc = vmalloc(len); + if (unlikely(hdr_alloc == 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 +2566,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 +2599,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@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/