Skip to content

Commit bc04853

Browse files
committed
Add some checks to prevent overruns on broken input.
1 parent 9df6e7d commit bc04853

File tree

6 files changed

+80
-26
lines changed

6 files changed

+80
-26
lines changed

MemoryModule.c

Lines changed: 71 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ typedef struct {
6868

6969
#define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader.DataDirectory[idx]
7070
#define ALIGN_DOWN(address, alignment) (LPVOID)((uintptr_t)(address) & ~((alignment) - 1))
71+
#define ALIGN_VALUE_UP(value, alignment) (((value) + (alignment) - 1) & ~((alignment) - 1))
7172

7273
#ifdef DEBUG_OUTPUT
7374
static void
@@ -86,20 +87,30 @@ OutputLastError(const char *msg)
8687
#endif
8788

8889
static BOOL
89-
CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module)
90+
CheckSize(size_t size, size_t expected) {
91+
if (size < expected) {
92+
SetLastError(ERROR_INVALID_DATA);
93+
return FALSE;
94+
}
95+
96+
return TRUE;
97+
}
98+
99+
static BOOL
100+
CopySections(const unsigned char *data, size_t size, PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module)
90101
{
91-
int i, size;
102+
int i, section_size;
92103
unsigned char *codeBase = module->codeBase;
93104
unsigned char *dest;
94105
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers);
95106
for (i=0; i<module->headers->FileHeader.NumberOfSections; i++, section++) {
96107
if (section->SizeOfRawData == 0) {
97108
// section doesn't contain data in the dll itself, but may define
98109
// uninitialized data
99-
size = old_headers->OptionalHeader.SectionAlignment;
100-
if (size > 0) {
110+
section_size = old_headers->OptionalHeader.SectionAlignment;
111+
if (section_size > 0) {
101112
dest = (unsigned char *)VirtualAlloc(codeBase + section->VirtualAddress,
102-
size,
113+
section_size,
103114
MEM_COMMIT,
104115
PAGE_READWRITE);
105116
if (dest == NULL) {
@@ -110,13 +121,17 @@ CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMO
110121
// than page size.
111122
dest = codeBase + section->VirtualAddress;
112123
section->Misc.PhysicalAddress = (DWORD) (uintptr_t) dest;
113-
memset(dest, 0, size);
124+
memset(dest, 0, section_size);
114125
}
115126

116127
// section is empty
117128
continue;
118129
}
119130

131+
if (!CheckSize(size, section->PointerToRawData + section->SizeOfRawData)) {
132+
return FALSE;
133+
}
134+
120135
// commit memory block and copy data from dll
121136
dest = (unsigned char *)VirtualAlloc(codeBase + section->VirtualAddress,
122137
section->SizeOfRawData,
@@ -285,7 +300,7 @@ ExecuteTLS(PMEMORYMODULE module)
285300
}
286301

287302
static BOOL
288-
PerformBaseRelocation(PMEMORYMODULE module, SIZE_T delta)
303+
PerformBaseRelocation(PMEMORYMODULE module, ptrdiff_t delta)
289304
{
290305
unsigned char *codeBase = module->codeBase;
291306
PIMAGE_BASE_RELOCATION relocation;
@@ -428,30 +443,43 @@ static void _FreeLibrary(HCUSTOMMODULE module, void *userdata)
428443
FreeLibrary((HMODULE) module);
429444
}
430445

431-
HMEMORYMODULE MemoryLoadLibrary(const void *data)
446+
HMEMORYMODULE MemoryLoadLibrary(const void *data, size_t size)
432447
{
433-
return MemoryLoadLibraryEx(data, _LoadLibrary, _GetProcAddress, _FreeLibrary, NULL);
448+
return MemoryLoadLibraryEx(data, size, _LoadLibrary, _GetProcAddress, _FreeLibrary, NULL);
434449
}
435450

436-
HMEMORYMODULE MemoryLoadLibraryEx(const void *data,
451+
#include <stdio.h>
452+
453+
HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size,
437454
CustomLoadLibraryFunc loadLibrary,
438455
CustomGetProcAddressFunc getProcAddress,
439456
CustomFreeLibraryFunc freeLibrary,
440457
void *userdata)
441458
{
442-
PMEMORYMODULE result;
459+
PMEMORYMODULE result = NULL;
443460
PIMAGE_DOS_HEADER dos_header;
444461
PIMAGE_NT_HEADERS old_header;
445462
unsigned char *code, *headers;
446-
SIZE_T locationDelta;
463+
ptrdiff_t locationDelta;
447464
SYSTEM_INFO sysInfo;
465+
PIMAGE_SECTION_HEADER section;
466+
DWORD i;
467+
size_t optionalSectionSize;
468+
size_t lastSectionEnd = 0;
469+
size_t alignedImageSize;
448470

471+
if (!CheckSize(size, sizeof(IMAGE_DOS_HEADER))) {
472+
return NULL;
473+
}
449474
dos_header = (PIMAGE_DOS_HEADER)data;
450475
if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) {
451476
SetLastError(ERROR_BAD_EXE_FORMAT);
452477
return NULL;
453478
}
454479

480+
if (!CheckSize(size, dos_header->e_lfanew + sizeof(IMAGE_NT_HEADERS))) {
481+
return NULL;
482+
}
455483
old_header = (PIMAGE_NT_HEADERS)&((const unsigned char *)(data))[dos_header->e_lfanew];
456484
if (old_header->Signature != IMAGE_NT_SIGNATURE) {
457485
SetLastError(ERROR_BAD_EXE_FORMAT);
@@ -473,18 +501,41 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data,
473501
return NULL;
474502
}
475503

504+
section = IMAGE_FIRST_SECTION(old_header);
505+
optionalSectionSize = old_header->OptionalHeader.SectionAlignment;
506+
for (i=0; i<old_header->FileHeader.NumberOfSections; i++, section++) {
507+
size_t endOfSection;
508+
if (section->SizeOfRawData == 0) {
509+
// Section without data in the DLL
510+
endOfSection = section->VirtualAddress + optionalSectionSize;
511+
} else {
512+
endOfSection = section->VirtualAddress + section->SizeOfRawData;
513+
}
514+
515+
if (endOfSection > lastSectionEnd) {
516+
lastSectionEnd = endOfSection;
517+
}
518+
}
519+
520+
GetNativeSystemInfo(&sysInfo);
521+
alignedImageSize = ALIGN_VALUE_UP(old_header->OptionalHeader.SizeOfImage, sysInfo.dwPageSize);
522+
if (alignedImageSize != ALIGN_VALUE_UP(lastSectionEnd, sysInfo.dwPageSize)) {
523+
SetLastError(ERROR_BAD_EXE_FORMAT);
524+
return NULL;
525+
}
526+
476527
// reserve memory for image of library
477528
// XXX: is it correct to commit the complete memory region at once?
478529
// calling DllEntry raises an exception if we don't...
479530
code = (unsigned char *)VirtualAlloc((LPVOID)(old_header->OptionalHeader.ImageBase),
480-
old_header->OptionalHeader.SizeOfImage,
531+
alignedImageSize,
481532
MEM_RESERVE | MEM_COMMIT,
482533
PAGE_READWRITE);
483534

484535
if (code == NULL) {
485536
// try to allocate memory at arbitrary position
486537
code = (unsigned char *)VirtualAlloc(NULL,
487-
old_header->OptionalHeader.SizeOfImage,
538+
alignedImageSize,
488539
MEM_RESERVE | MEM_COMMIT,
489540
PAGE_READWRITE);
490541
if (code == NULL) {
@@ -506,10 +557,12 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data,
506557
result->getProcAddress = getProcAddress;
507558
result->freeLibrary = freeLibrary;
508559
result->userdata = userdata;
509-
510-
GetNativeSystemInfo(&sysInfo);
511560
result->pageSize = sysInfo.dwPageSize;
512561

562+
if (!CheckSize(size, old_header->OptionalHeader.SizeOfHeaders)) {
563+
goto error;
564+
}
565+
513566
// commit memory for headers
514567
headers = (unsigned char *)VirtualAlloc(code,
515568
old_header->OptionalHeader.SizeOfHeaders,
@@ -524,12 +577,12 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data,
524577
result->headers->OptionalHeader.ImageBase = (uintptr_t)code;
525578

526579
// copy sections from DLL file block to new memory location
527-
if (!CopySections((const unsigned char *) data, old_header, result)) {
580+
if (!CopySections((const unsigned char *) data, size, old_header, result)) {
528581
goto error;
529582
}
530583

531584
// adjust base address of imported data
532-
locationDelta = (SIZE_T)(code - old_header->OptionalHeader.ImageBase);
585+
locationDelta = (ptrdiff_t)(result->headers->OptionalHeader.ImageBase - old_header->OptionalHeader.ImageBase);
533586
if (locationDelta != 0) {
534587
result->isRelocated = PerformBaseRelocation(result, locationDelta);
535588
} else {

MemoryModule.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,19 +44,20 @@ typedef FARPROC (*CustomGetProcAddressFunc)(HCUSTOMMODULE, LPCSTR, void *);
4444
typedef void (*CustomFreeLibraryFunc)(HCUSTOMMODULE, void *);
4545

4646
/**
47-
* Load EXE/DLL from memory location.
47+
* Load EXE/DLL from memory location with the given size.
4848
*
4949
* All dependencies are resolved using default LoadLibrary/GetProcAddress
5050
* calls through the Windows API.
5151
*/
52-
HMEMORYMODULE MemoryLoadLibrary(const void *);
52+
HMEMORYMODULE MemoryLoadLibrary(const void *, size_t);
5353

5454
/**
55-
* Load EXE/DLL from memory location using custom dependency resolvers.
55+
* Load EXE/DLL from memory location with the given size using custom dependency
56+
* resolvers.
5657
*
5758
* Dependencies will be resolved using passed callback methods.
5859
*/
59-
HMEMORYMODULE MemoryLoadLibraryEx(const void *,
60+
HMEMORYMODULE MemoryLoadLibraryEx(const void *, size_t,
6061
CustomLoadLibraryFunc,
6162
CustomGetProcAddressFunc,
6263
CustomFreeLibraryFunc,

doc/readme.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,7 @@ The interface is very similar to the standard methods for loading of libraries::
511511

512512
typedef void *HMEMORYMODULE;
513513

514-
HMEMORYMODULE MemoryLoadLibrary(const void *);
514+
HMEMORYMODULE MemoryLoadLibrary(const void *, size_t);
515515
FARPROC MemoryGetProcAddress(HMEMORYMODULE, const char *);
516516
void MemoryFreeLibrary(HMEMORYMODULE);
517517

example/DllLoader/DllLoader.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ void LoadFromMemory(void)
7373
assert(read == static_cast<size_t>(size));
7474
fclose(fp);
7575

76-
handle = MemoryLoadLibrary(data);
76+
handle = MemoryLoadLibrary(data, size);
7777
if (handle == NULL)
7878
{
7979
_tprintf(_T("Can't load library from memory.\n"));

example/DllLoader/DllLoaderLoader.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ int RunFromMemory(void)
3636
assert(read == static_cast<size_t>(size));
3737
fclose(fp);
3838

39-
handle = MemoryLoadLibrary(data);
39+
handle = MemoryLoadLibrary(data, size);
4040
if (handle == NULL)
4141
{
4242
_tprintf(_T("Can't load library from memory.\n"));

tests/LoadDll.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ BOOL LoadFromMemory(char *filename)
101101
assert(read == static_cast<size_t>(size));
102102
fclose(fp);
103103

104-
handle = MemoryLoadLibrary(data);
104+
handle = MemoryLoadLibrary(data, size);
105105
if (handle == NULL)
106106
{
107107
_tprintf(_T("Can't load library from memory.\n"));

0 commit comments

Comments
 (0)