david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

[elf] Reject ELFBoot images requiring virtual addressing

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>
This commit is contained in:
Michael Brown 2015-07-29 14:09:34 +01:00
parent 1e4ff872be
commit ae7f22eb28
3 changed files with 135 additions and 56 deletions

View 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;
}

View 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 ) {
@ -127,6 +141,55 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
return 0;
}
/**
* Process ELF segments
*
* @v image ELF file
* @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_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;
/* Initialise maximum used address */
*max = 0;
/* Invalidate entry point */
*entry = 0;
/* 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_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 ) );
return -ENOEXEC;
}
return 0;
}
/**
* Load ELF image into memory
*
@ -144,9 +207,6 @@ int elf_load ( struct image *image, physaddr_t *entry, physaddr_t *max ) {
[EI_CLASS] = ELFCLASS,
};
Elf_Ehdr ehdr;
Elf_Phdr phdr;
Elf_Off phoff;
unsigned int phnum;
int rc;
/* Read ELF header */
@ -157,33 +217,10 @@ int elf_load ( struct image *image, physaddr_t *entry, physaddr_t *max ) {
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-- ) {
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 ) {
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 ) );
return -ENOEXEC;
}
/* Load ELF segments into memory */
if ( ( rc = elf_segments ( image, &ehdr, elf_load_segment,
entry, max ) ) != 0 )
return rc;
return 0;
}

View File

@ -10,8 +10,19 @@
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 */