diff options
Diffstat (limited to 'gpxe/src/image')
-rw-r--r-- | gpxe/src/image/efi_image.c | 2 | ||||
-rw-r--r-- | gpxe/src/image/elf.c | 57 | ||||
-rw-r--r-- | gpxe/src/image/embedded.c | 2 | ||||
-rw-r--r-- | gpxe/src/image/script.c | 10 | ||||
-rw-r--r-- | gpxe/src/image/segment.c | 13 |
5 files changed, 67 insertions, 17 deletions
diff --git a/gpxe/src/image/efi_image.c b/gpxe/src/image/efi_image.c index ae95debc..60d150a9 100644 --- a/gpxe/src/image/efi_image.c +++ b/gpxe/src/image/efi_image.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <errno.h> #include <gpxe/efi/efi.h> #include <gpxe/image.h> diff --git a/gpxe/src/image/elf.c b/gpxe/src/image/elf.c index cb2b0f5b..a0ec065e 100644 --- a/gpxe/src/image/elf.c +++ b/gpxe/src/image/elf.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + /** * @file * @@ -42,11 +44,14 @@ typedef Elf32_Off Elf_Off; * * @v image ELF file * @v phdr ELF program header + * @v ehdr ELF executable header * @ret rc Return status code */ -static int elf_load_segment ( struct image *image, Elf_Phdr *phdr ) { +static int elf_load_segment ( struct image *image, Elf_Phdr *phdr, + Elf_Ehdr *ehdr ) { physaddr_t dest; userptr_t buffer; + unsigned long e_offset; int rc; /* Do nothing for non-PT_LOAD segments */ @@ -55,7 +60,7 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr ) { /* Check segment lies within image */ if ( ( phdr->p_offset + phdr->p_filesz ) > image->len ) { - DBG ( "ELF segment outside ELF file\n" ); + DBGC ( image, "ELF %p segment outside image\n", image ); return -ENOEXEC; } @@ -67,26 +72,43 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr ) { if ( ! dest ) dest = phdr->p_vaddr; if ( ! dest ) { - DBG ( "ELF segment loads to physical address 0\n" ); + DBGC ( image, "ELF %p segment loads to physical address 0\n", + image ); return -ENOEXEC; } buffer = phys_to_user ( dest ); - DBG ( "ELF loading segment [%x,%x) to [%x,%x,%x)\n", - phdr->p_offset, ( phdr->p_offset + phdr->p_filesz ), - phdr->p_paddr, ( phdr->p_paddr + phdr->p_filesz ), - ( phdr->p_paddr + 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 ) { - DBG ( "ELF could not prepare segment: %s\n", strerror ( rc ) ); + 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 ); + /* Set execution address, if it lies within this segment */ + if ( ( e_offset = ( ehdr->e_entry - dest ) ) < phdr->p_filesz ) { + image->priv.phys = ehdr->e_entry; + DBGC ( image, "ELF %p found physical entry point at %lx\n", + image, image->priv.phys ); + } else if ( ( e_offset = ( ehdr->e_entry - phdr->p_vaddr ) ) + < phdr->p_filesz ) { + if ( ! image->priv.phys ) { + image->priv.phys = ( dest + e_offset ); + DBGC ( image, "ELF %p found virtual entry point at %lx" + " (virt %lx)\n", image, image->priv.phys, + ( ( unsigned long ) ehdr->e_entry ) ); + } + } + return 0; } @@ -109,25 +131,32 @@ int elf_load ( struct image *image ) { /* Read ELF header */ copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) ); if ( memcmp ( &ehdr.e_ident[EI_MAG0], ELFMAG, SELFMAG ) != 0 ) { - DBG ( "Invalid ELF signature\n" ); + DBGC ( image, "ELF %p has invalid signature\n", image ); return -ENOEXEC; } + /* Invalidate execution address */ + image->priv.phys = 0; + /* Read ELF program headers */ for ( phoff = ehdr.e_phoff , phnum = ehdr.e_phnum ; phnum ; phoff += ehdr.e_phentsize, phnum-- ) { if ( phoff > image->len ) { - DBG ( "ELF program header %d outside ELF image\n", - phnum ); + 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 ) ) != 0 ) + if ( ( rc = elf_load_segment ( image, &phdr, &ehdr ) ) != 0 ) return rc; } - /* Record execution entry point in image private data field */ - image->priv.phys = ehdr.e_entry; + /* Check for a valid execution address */ + if ( ! image->priv.phys ) { + DBGC ( image, "ELF %p entry point %lx outside image\n", + image, ( ( unsigned long ) ehdr.e_entry ) ); + return -ENOEXEC; + } return 0; } diff --git a/gpxe/src/image/embedded.c b/gpxe/src/image/embedded.c index 4f763578..58a14ea4 100644 --- a/gpxe/src/image/embedded.c +++ b/gpxe/src/image/embedded.c @@ -6,6 +6,8 @@ * fetching over the network. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <string.h> #include <gpxe/image.h> #include <gpxe/uaccess.h> diff --git a/gpxe/src/image/script.c b/gpxe/src/image/script.c index 2d242746..0835ecb5 100644 --- a/gpxe/src/image/script.c +++ b/gpxe/src/image/script.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + /** * @file * @@ -25,6 +27,7 @@ #include <string.h> #include <stdlib.h> +#include <ctype.h> #include <errno.h> #include <gpxe/image.h> @@ -88,8 +91,8 @@ static int script_exec ( struct image *image ) { * @ret rc Return status code */ static int script_load ( struct image *image ) { - static const char magic[] = "#!gpxe\n"; - char test[ sizeof ( magic ) - 1 ]; + static const char magic[] = "#!gpxe"; + char test[ sizeof ( magic ) - 1 /* NUL */ + 1 /* terminating space */]; /* Sanity check */ if ( image->len < sizeof ( test ) ) { @@ -99,7 +102,8 @@ static int script_load ( struct image *image ) { /* Check for magic signature */ copy_from_user ( test, image->data, 0, sizeof ( test ) ); - if ( memcmp ( test, magic, sizeof ( test ) ) != 0 ) { + if ( ( memcmp ( test, magic, ( sizeof ( test ) - 1 ) ) != 0 ) || + ! isspace ( test[ sizeof ( test ) - 1 ] ) ) { DBG ( "Invalid magic signature\n" ); return -ENOEXEC; } diff --git a/gpxe/src/image/segment.c b/gpxe/src/image/segment.c index 9bd60f9c..e2474536 100644 --- a/gpxe/src/image/segment.c +++ b/gpxe/src/image/segment.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + /** * @file * @@ -26,6 +28,7 @@ #include <errno.h> #include <gpxe/uaccess.h> #include <gpxe/memmap.h> +#include <gpxe/errortab.h> #include <gpxe/segment.h> /** @@ -72,3 +75,13 @@ int prep_segment ( userptr_t segment, size_t filesz, size_t memsz ) { start, mid, end ); return -ERANGE; } + +/** + * Segment-specific error messages + * + * This error happens sufficiently often to merit a user-friendly + * description. + */ +struct errortab segment_errors[] __errortab = { + { ERANGE, "Requested memory not available" }, +}; |