diff options
author | wpaul <wpaul@FreeBSD.org> | 2005-10-26 18:46:27 +0000 |
---|---|---|
committer | wpaul <wpaul@FreeBSD.org> | 2005-10-26 18:46:27 +0000 |
commit | 6140104fb25ade1d87d1a48609c93b44dc02a9f0 (patch) | |
tree | 0c397977232cbc0777c9a022d4281e7efd4c59c8 /sys/compat | |
parent | dd0b138f18603b3d51e64334964067392aa51f7a (diff) | |
download | FreeBSD-src-6140104fb25ade1d87d1a48609c93b44dc02a9f0.zip FreeBSD-src-6140104fb25ade1d87d1a48609c93b44dc02a9f0.tar.gz |
Clean up and apply the fix for PR 83477. The calculation for locating
the start of the section headers has to take into account the fact
that the image_nt_header is really variable sized. It happens that
the existing calculation is correct for _most_ production binaries
produced by the Windows DDK, but if we get a binary with oddball
offsets, the PE loader could crash.
Changes from the supplied patch are:
- We don't really need to use the IMAGE_SIZEOF_NT_HEADER() macro when
computing how much of the header to return to callers of
pe_get_optional_header(). While it's important to take the variable
size of the header into account in other calculations, we never
actually look at anything outside the non-variable portion of the
header. This saves callers from having to allocate a variable sized
buffer off the heap (I purposely tried to avoid using malloc()
in subr_pe.c to make it easier to compile in both the -D_KERNEL and
!-D_KERNEL case), and since we're copying into a buffer on the
stack, we always have to copy the same amount of data or else
we'll trash the stack something fierce.
- We need <stddef.h> to get offsetof() in the !-D_KERNEL case.
- ndiscvt.c needs the IMAGE_FIRST_SECTION() macro too, since it does
a little bit of section pre-processing.
PR: kern/83477
Diffstat (limited to 'sys/compat')
-rw-r--r-- | sys/compat/ndis/pe_var.h | 9 | ||||
-rw-r--r-- | sys/compat/ndis/subr_pe.c | 20 |
2 files changed, 22 insertions, 7 deletions
diff --git a/sys/compat/ndis/pe_var.h b/sys/compat/ndis/pe_var.h index 1717f32..e778b58 100644 --- a/sys/compat/ndis/pe_var.h +++ b/sys/compat/ndis/pe_var.h @@ -214,6 +214,10 @@ struct image_nt_header { typedef struct image_nt_header image_nt_header; +#define IMAGE_SIZEOF_NT_HEADER(nthdr) \ + (offsetof(image_nt_header, inh_optionalhdr) + \ + ((image_nt_header *)(nthdr))->inh_filehdr.ifh_optionalhdrlen) + /* Directory Entries */ #define IMAGE_DIRECTORY_ENTRY_EXPORT 0 /* Export Directory */ @@ -281,6 +285,11 @@ typedef struct image_section_header image_section_header; #define IMAGE_SIZEOF_SECTION_HEADER 40 +#define IMAGE_FIRST_SECTION(nthdr) \ + ((image_section_header *)((vm_offset_t)(nthdr) + \ + offsetof(image_nt_header, inh_optionalhdr) + \ + ((image_nt_header *)(nthdr))->inh_filehdr.ifh_optionalhdrlen)) + /* * Import format */ diff --git a/sys/compat/ndis/subr_pe.c b/sys/compat/ndis/subr_pe.c index a3f5071..ee8c0fe 100644 --- a/sys/compat/ndis/subr_pe.c +++ b/sys/compat/ndis/subr_pe.c @@ -57,6 +57,7 @@ extern int ndis_strncasecmp(const char *, const char *, size_t); #define strncasecmp(a, b, c) ndis_strncasecmp(a, b, c) #else #include <stdio.h> +#include <stddef.h> #include <stdlib.h> #include <unistd.h> #include <string.h> @@ -142,7 +143,7 @@ pe_get_optional_header(imgbase, hdr) nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); bcopy ((char *)&nt_hdr->inh_optionalhdr, (char *)hdr, - sizeof(image_optional_header)); + nt_hdr->inh_filehdr.ifh_optionalhdrlen); return(0); } @@ -169,6 +170,14 @@ pe_get_file_header(imgbase, hdr) dos_hdr = (image_dos_header *)imgbase; nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); + /* + * Note: the size of the nt_header is variable since it + * can contain optional fields, as indicated by ifh_optionalhdrlen. + * However it happens we're only interested in fields in the + * non-variant portion of the nt_header structure, so we don't + * bother copying the optional parts here. + */ + bcopy ((char *)&nt_hdr->inh_filehdr, (char *)hdr, sizeof(image_file_header)); @@ -197,8 +206,7 @@ pe_get_section_header(imgbase, hdr) dos_hdr = (image_dos_header *)imgbase; nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); - sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr + - sizeof(image_nt_header)); + sect_hdr = IMAGE_FIRST_SECTION(nt_hdr); bcopy ((char *)sect_hdr, (char *)hdr, sizeof(image_section_header)); @@ -280,8 +288,7 @@ pe_translate_addr(imgbase, rva) dos_hdr = (image_dos_header *)imgbase; nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); - sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr + - sizeof(image_nt_header)); + sect_hdr = IMAGE_FIRST_SECTION(nt_hdr); /* * The test here is to see if the RVA falls somewhere @@ -339,8 +346,7 @@ pe_get_section(imgbase, hdr, name) dos_hdr = (image_dos_header *)imgbase; nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); - sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr + - sizeof(image_nt_header)); + sect_hdr = IMAGE_FIRST_SECTION(nt_hdr); for (i = 0; i < sections; i++) { if (!strcmp ((char *)§_hdr->ish_name, name)) { |