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
This commit is contained in:
parent
dd0b138f18
commit
6140104fb2
@ -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
|
||||
*/
|
||||
|
@ -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)) {
|
||||
|
@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
@ -88,8 +89,7 @@ extern const char *__progname;
|
||||
#define SET_HDRS(x) \
|
||||
dos_hdr = (image_dos_header *)x; \
|
||||
nt_hdr = (image_nt_header *)(x + 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);
|
||||
|
||||
static
|
||||
int insert_padding(imgbase, imglen)
|
||||
|
Loading…
Reference in New Issue
Block a user