Bug 677797 - Implement mandatory ASLR on Windows; r=bsmedberg

This commit is contained in:
Ehsan Akhgari 2011-10-11 10:50:57 -04:00
Родитель a9f3ec8811
Коммит c0e2936af0
1 изменённых файлов: 72 добавлений и 19 удалений

Просмотреть файл

@ -148,6 +148,59 @@ typedef NTSTATUS (NTAPI *LdrLoadDll_func) (PWCHAR filePath, PULONG flags, PUNICO
static LdrLoadDll_func stub_LdrLoadDll = 0;
namespace {
template <class T>
struct RVAMap {
RVAMap(HANDLE map, unsigned offset) {
mMappedView = reinterpret_cast<T*>
(::MapViewOfFile(map, FILE_MAP_READ, 0, offset, sizeof(T)));
}
~RVAMap() {
if (mMappedView) {
::UnmapViewOfFile(mMappedView);
}
}
operator const T*() const { return mMappedView; }
const T* operator->() const { return mMappedView; }
private:
const T* mMappedView;
};
void
ForceASLR(const wchar_t* path)
{
HANDLE file = ::CreateFileW(path, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
NULL);
if (file != INVALID_HANDLE_VALUE) {
HANDLE map = ::CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
if (map) {
RVAMap<IMAGE_DOS_HEADER> peHeader(map, 0);
if (peHeader) {
RVAMap<IMAGE_NT_HEADERS> ntHeader(map, peHeader->e_lfanew);
if (ntHeader) {
// If we're dealing with a DLL which has code inside it, but does not have the
// ASLR bit set, allocate a page at its base address.
if (((ntHeader->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) == 0) &&
(ntHeader->OptionalHeader.SizeOfCode > 0)) {
void* page = ::VirtualAlloc((LPVOID)ntHeader->OptionalHeader.ImageBase, 1,
MEM_RESERVE, PAGE_NOACCESS);
// Note that we will leak this page, but it's ok since it's just one page in
// the virtual address space, with no physical page backing it.
// We're done at this point!
}
}
}
::CloseHandle(map);
}
::CloseHandle(file);
}
}
}
static NTSTATUS NTAPI
patched_LdrLoadDll (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileName, PHANDLE handle)
{
@ -160,6 +213,23 @@ patched_LdrLoadDll (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileNam
int len = moduleFileName->Length / 2;
wchar_t *fname = moduleFileName->Buffer;
// figure out the length of the string that we need
DWORD pathlen = SearchPathW(filePath, fname, L".dll", 0, NULL, NULL);
if (pathlen == 0) {
// uh, we couldn't find the DLL at all, so...
printf_stderr("LdrLoadDll: Blocking load of '%s' (SearchPathW didn't find it?)\n", dllName);
return STATUS_DLL_NOT_FOUND;
}
nsAutoArrayPtr<wchar_t> full_fname(new wchar_t[pathlen+1]);
if (!full_fname) {
// couldn't allocate memory?
return STATUS_DLL_NOT_FOUND;
}
// now actually grab it
SearchPathW(filePath, fname, L".dll", pathlen+1, full_fname, NULL);
// The filename isn't guaranteed to be null terminated, but in practice
// it always will be; ensure that this is so, and bail if not.
// This is done instead of the more robust approach because of bug 527122,
@ -235,23 +305,6 @@ patched_LdrLoadDll (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileNam
#endif
if (info->maxVersion != ALL_VERSIONS) {
// figure out the length of the string that we need
DWORD pathlen = SearchPathW(filePath, fname, L".dll", 0, NULL, NULL);
if (pathlen == 0) {
// uh, we couldn't find the DLL at all, so...
printf_stderr("LdrLoadDll: Blocking load of '%s' (SearchPathW didn't find it?)\n", dllName);
return STATUS_DLL_NOT_FOUND;
}
wchar_t *full_fname = (wchar_t*) malloc(sizeof(wchar_t)*(pathlen+1));
if (!full_fname) {
// couldn't allocate memory?
return STATUS_DLL_NOT_FOUND;
}
// now actually grab it
SearchPathW(filePath, fname, L".dll", pathlen+1, full_fname, NULL);
DWORD zero;
DWORD infoSize = GetFileVersionInfoSizeW(full_fname, &zero);
@ -275,8 +328,6 @@ patched_LdrLoadDll (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileNam
load_ok = true;
}
}
free(full_fname);
}
if (!load_ok) {
@ -292,6 +343,8 @@ continue_loading:
NS_SetHasLoadedNewDLLs();
ForceASLR(full_fname);
return stub_LdrLoadDll(filePath, flags, moduleFileName, handle);
}