]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[elf] Reject ELFBoot images requiring virtual addressing
authorMichael Brown <mcb30@ipxe.org>
Wed, 29 Jul 2015 13:09:34 +0000 (14:09 +0100)
committerMichael Brown <mcb30@ipxe.org>
Wed, 29 Jul 2015 13:17:09 +0000 (14:17 +0100)
We do not set up any kind of virtual addressing before invoking an
ELFBoot image.  Reject if the image's program headers indicate that
virtual addresses are not equal to physical addresses.

This avoids problems when loading some RHEL5 kernels, which seem to
include ELFBoot headers using virtual addressing.  With this change,
these kernels are no longer detected as ELFBoot, and so may be
(correctly) detected as bzImage instead.

Reported-by: Torgeir.Wulfsberg@kongsberg.com
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/arch/i386/image/elfboot.c
src/image/elf.c
src/include/ipxe/elf.h

index 3ff762031b77ba0972cf8f7e5d21efa15a238c74..dc35689293e5df097655029b1d409a1c0d0ff3b7 100644 (file)
@@ -78,6 +78,27 @@ static int elfboot_exec ( struct image *image ) {
        return -ECANCELED;  /* -EIMPOSSIBLE, anyone? */
 }
 
+/**
+ * Check that ELF segment uses flat physical addressing
+ *
+ * @v image            ELF file
+ * @v phdr             ELF program header
+ * @v dest             Destination address
+ * @ret rc             Return status code
+ */
+static int elfboot_check_segment ( struct image *image, Elf_Phdr *phdr,
+                                  physaddr_t dest ) {
+
+       /* Check that ELF segment uses flat physical addressing */
+       if ( phdr->p_vaddr != dest ) {
+               DBGC ( image, "ELF %p uses virtual addressing (phys %x, "
+                      "virt %x)\n", image, phdr->p_paddr, phdr->p_vaddr );
+               return -ENOEXEC;
+       }
+
+       return 0;
+}
+
 /**
  * Probe ELF image
  *
@@ -95,14 +116,24 @@ static int elfboot_probe ( struct image *image ) {
                [EI_DATA]       = ELFDATA2LSB,
                [EI_VERSION]    = EV_CURRENT,
        };
+       physaddr_t entry;
+       physaddr_t max;
+       int rc;
 
        /* Read ELF header */
        copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) );
        if ( memcmp ( ehdr.e_ident, e_ident, sizeof ( e_ident ) ) != 0 ) {
-               DBG ( "Invalid ELF identifier\n" );
+               DBGC ( image, "Invalid ELF identifier\n" );
                return -ENOEXEC;
        }
 
+       /* Check that this image uses flat physical addressing */
+       if ( ( rc = elf_segments ( image, &ehdr, elfboot_check_segment,
+                                  &entry, &max ) ) != 0 ) {
+               DBGC ( image, "Unloadable ELF image\n" );
+               return rc;
+       }
+
        return 0;
 }
 
index 533f94c1004db30b69aa1a3958c5dd41be5cf07b..5c2f9db255dd452f170276e5aebc65003048e4ac 100644 (file)
@@ -40,27 +40,54 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 #include <ipxe/image.h>
 #include <ipxe/elf.h>
 
-typedef Elf32_Ehdr     Elf_Ehdr;
-typedef Elf32_Phdr     Elf_Phdr;
-typedef Elf32_Off      Elf_Off;
-#define ELFCLASS       ELFCLASS32
-
 /**
  * Load ELF segment into memory
  *
  * @v image            ELF file
  * @v phdr             ELF program header
+ * @v dest             Destination address
+ * @ret rc             Return status code
+ */
+static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
+                             physaddr_t dest ) {
+       userptr_t buffer = phys_to_user ( dest );
+       int rc;
+
+       DBGC ( image, "ELF %p loading segment [%x,%x) to [%lx,%lx,%lx)\n",
+              image, phdr->p_offset, ( phdr->p_offset + phdr->p_filesz ),
+              dest, ( dest + phdr->p_filesz ), ( dest + phdr->p_memsz ) );
+
+       /* Verify and prepare segment */
+       if ( ( rc = prep_segment ( buffer, phdr->p_filesz,
+                                  phdr->p_memsz ) ) != 0 ) {
+               DBGC ( image, "ELF %p could not prepare segment: %s\n",
+                      image, strerror ( rc ) );
+               return rc;
+       }
+
+       /* Copy image to segment */
+       memcpy_user ( buffer, 0, image->data, phdr->p_offset, phdr->p_filesz );
+
+       return 0;
+}
+
+/**
+ * Process ELF segment
+ *
+ * @v image            ELF file
  * @v ehdr             ELF executable header
+ * @v phdr             ELF program header
+ * @v process          Segment processor
  * @ret entry          Entry point, if found
  * @ret max            Maximum used address
  * @ret rc             Return status code
  */
-static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
-                             Elf_Ehdr *ehdr, physaddr_t *entry,
-                             physaddr_t *max ) {
+static int elf_segment ( struct image *image, Elf_Ehdr *ehdr, Elf_Phdr *phdr,
+                        int ( * process ) ( struct image *image,
+                                            Elf_Phdr *phdr, physaddr_t dest ),
+                        physaddr_t *entry, physaddr_t *max ) {
        physaddr_t dest;
        physaddr_t end;
-       userptr_t buffer;
        unsigned long e_offset;
        int rc;
 
@@ -86,28 +113,15 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
                       image );
                return -ENOEXEC;
        }
-       buffer = phys_to_user ( dest );
        end = ( dest + phdr->p_memsz );
 
-       DBGC ( image, "ELF %p loading segment [%x,%x) to [%x,%x,%x)\n", image,
-              phdr->p_offset, ( phdr->p_offset + phdr->p_filesz ),
-              phdr->p_paddr, ( phdr->p_paddr + phdr->p_filesz ),
-              ( phdr->p_paddr + phdr->p_memsz ) );
-
-       /* Verify and prepare segment */
-       if ( ( rc = prep_segment ( buffer, phdr->p_filesz,
-                                  phdr->p_memsz ) ) != 0 ) {
-               DBGC ( image, "ELF %p could not prepare segment: %s\n",
-                      image, strerror ( rc ) );
-               return rc;
-       }
-
        /* Update maximum used address, if applicable */
        if ( end > *max )
                *max = end;
 
-       /* Copy image to segment */
-       memcpy_user ( buffer, 0, image->data, phdr->p_offset, phdr->p_filesz );
+       /* Process segment */
+       if ( ( rc = process ( image, phdr, dest ) ) != 0 )
+               return rc;
 
        /* Set execution address, if it lies within this segment */
        if ( ( e_offset = ( ehdr->e_entry - dest ) ) < phdr->p_filesz ) {
@@ -128,62 +142,85 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
 }
 
 /**
- * Load ELF image into memory
+ * Process ELF segments
  *
  * @v image            ELF file
- * @ret entry          Entry point
+ * @v ehdr             ELF executable header
+ * @v process          Segment processor
+ * @ret entry          Entry point, if found
  * @ret max            Maximum used address
  * @ret rc             Return status code
  */
-int elf_load ( struct image *image, physaddr_t *entry, physaddr_t *max ) {
-       static const uint8_t e_ident[] = {
-               [EI_MAG0]       = ELFMAG0,
-               [EI_MAG1]       = ELFMAG1,
-               [EI_MAG2]       = ELFMAG2,
-               [EI_MAG3]       = ELFMAG3,
-               [EI_CLASS]      = ELFCLASS,
-       };
-       Elf_Ehdr ehdr;
+int elf_segments ( struct image *image, Elf_Ehdr *ehdr,
+                  int ( * process ) ( struct image *image, Elf_Phdr *phdr,
+                                      physaddr_t dest ),
+                  physaddr_t *entry, physaddr_t *max ) {
        Elf_Phdr phdr;
        Elf_Off phoff;
        unsigned int phnum;
        int rc;
 
-       /* Read ELF header */
-       copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) );
-       if ( memcmp ( &ehdr.e_ident[EI_MAG0], e_ident,
-                     sizeof ( e_ident ) ) != 0 ) {
-               DBGC ( image, "ELF %p has invalid signature\n", image );
-               return -ENOEXEC;
-       }
-
        /* Initialise maximum used address */
        *max = 0;
 
        /* Invalidate entry point */
        *entry = 0;
 
-       /* Read ELF program headers */
-       for ( phoff = ehdr.e_phoff , phnum = ehdr.e_phnum ; phnum ;
-             phoff += ehdr.e_phentsize, phnum-- ) {
+       /* Read and process ELF program headers */
+       for ( phoff = ehdr->e_phoff , phnum = ehdr->e_phnum ; phnum ;
+             phoff += ehdr->e_phentsize, phnum-- ) {
                if ( phoff > image->len ) {
                        DBGC ( image, "ELF %p program header %d outside "
                               "image\n", image, phnum );
                        return -ENOEXEC;
                }
                copy_from_user ( &phdr, image->data, phoff, sizeof ( phdr ) );
-               if ( ( rc = elf_load_segment ( image, &phdr, &ehdr,
-                                              entry, max ) ) != 0 ) {
+               if ( ( rc = elf_segment ( image, ehdr, &phdr, process,
+                                         entry, max ) ) != 0 )
                        return rc;
-               }
        }
 
        /* Check for a valid execution address */
        if ( ! *entry ) {
                DBGC ( image, "ELF %p entry point %lx outside image\n",
-                      image, ( ( unsigned long ) ehdr.e_entry ) );
+                      image, ( ( unsigned long ) ehdr->e_entry ) );
+               return -ENOEXEC;
+       }
+
+       return 0;
+}
+
+/**
+ * Load ELF image into memory
+ *
+ * @v image            ELF file
+ * @ret entry          Entry point
+ * @ret max            Maximum used address
+ * @ret rc             Return status code
+ */
+int elf_load ( struct image *image, physaddr_t *entry, physaddr_t *max ) {
+       static const uint8_t e_ident[] = {
+               [EI_MAG0]       = ELFMAG0,
+               [EI_MAG1]       = ELFMAG1,
+               [EI_MAG2]       = ELFMAG2,
+               [EI_MAG3]       = ELFMAG3,
+               [EI_CLASS]      = ELFCLASS,
+       };
+       Elf_Ehdr ehdr;
+       int rc;
+
+       /* Read ELF header */
+       copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) );
+       if ( memcmp ( &ehdr.e_ident[EI_MAG0], e_ident,
+                     sizeof ( e_ident ) ) != 0 ) {
+               DBGC ( image, "ELF %p has invalid signature\n", image );
                return -ENOEXEC;
        }
 
+       /* Load ELF segments into memory */
+       if ( ( rc = elf_segments ( image, &ehdr, elf_load_segment,
+                                  entry, max ) ) != 0 )
+               return rc;
+
        return 0;
 }
index e83a0cf12767d0878a4cd7a02dbb4090d52d8052..033c3f7a80d7495aa5f784a8e7936453d78bc320 100644 (file)
 
 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 
+#include <stdint.h>
+#include <ipxe/image.h>
 #include <elf.h>
 
+typedef Elf32_Ehdr     Elf_Ehdr;
+typedef Elf32_Phdr     Elf_Phdr;
+typedef Elf32_Off      Elf_Off;
+#define ELFCLASS       ELFCLASS32
+
+extern int elf_segments ( struct image *image, Elf_Ehdr *ehdr,
+                         int ( * process ) ( struct image *image,
+                                             Elf_Phdr *phdr, physaddr_t dest ),
+                         physaddr_t *entry, physaddr_t *max );
 extern int elf_load ( struct image *image, physaddr_t *entry, physaddr_t *max );
 
 #endif /* _IPXE_ELF_H */