+2011-10-25 Corinna Vinschen <corinna@vinschen.de>
+
+ * hookapi.cc (hook_or_detect_cygwin): Take additional handle
+ to a file mapping as parameter. If this handle is not NULL,
+ create another file mapping for the IAT.
+ * spawn.cc (av::fixup): Only map the first 64K of an image and
+ keep the mapping handle to use as argument to hook_or_detect_cygwin.
+ * winsup.h (hook_or_detect_cygwin): Add mapping handle as default
+ parameter in declaration.
+
2011-10-24 Corinna Vinschen <corinna@vinschen.de>
* syscalls.cc (unlink_nt): Fix a bug which overwrites the NT status
#include "winsup.h"
#include <stdlib.h>
+#include <sys/param.h>
#include "ntdll.h"
#include "cygerrno.h"
#include "security.h"
// Top level routine to find the EXE's imports and redirect them
void *
-hook_or_detect_cygwin (const char *name, const void *fn, WORD& subsys)
+hook_or_detect_cygwin (const char *name, const void *fn, WORD& subsys, HANDLE h)
{
HMODULE hm = fn ? GetModuleHandle (NULL) : (HMODULE) name;
PIMAGE_NT_HEADERS pExeNTHdr = PEHeaderFromHModule (hm);
DWORD importRVA = pExeNTHdr->OptionalHeader.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
+ DWORD importRVASize = pExeNTHdr->OptionalHeader.DataDirectory
+ [IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
if (!importRVA)
return false;
long delta = fn ? 0 : rvadelta (pExeNTHdr, importRVA);
if (delta < 0)
return false;
+ importRVA -= delta;
// Convert imports RVA to a usable pointer
- PIMAGE_IMPORT_DESCRIPTOR pdfirst = rva (PIMAGE_IMPORT_DESCRIPTOR, hm, importRVA - delta);
+ PIMAGE_IMPORT_DESCRIPTOR pdfirst;
+ char *map = NULL;
+ DWORD offset = 0;
+ if (h && importRVA + importRVASize > wincap.allocation_granularity ())
+ {
+ /* If h is not NULL, the calling function only mapped at most the first
+ 64K of the image. The IAT is usually at the end of the image, so
+ what we do here is to map the IAT into our address space if it doesn't
+ reside in the first 64K anyway. The offset must be a multiple of the
+ allocation granularity, though, so we have to map a bit more. */
+ offset = rounddown (importRVA, wincap.allocation_granularity ());
+ DWORD size = importRVA - offset + importRVASize;
+ map = (char *) MapViewOfFile (h, FILE_MAP_READ, 0, offset, size);
+ if (!map)
+ return false;
+ pdfirst = rva (PIMAGE_IMPORT_DESCRIPTOR, map, importRVA - offset);
+ }
+ else
+ pdfirst = rva (PIMAGE_IMPORT_DESCRIPTOR, hm, importRVA);
function_hook fh;
fh.origfn = NULL;
// Iterate through each import descriptor, and redirect if appropriate
for (PIMAGE_IMPORT_DESCRIPTOR pd = pdfirst; pd->FirstThunk; pd++)
{
- if (!ascii_strcasematch (rva (PSTR, hm, pd->Name - delta), "cygwin1.dll"))
+ if (!ascii_strcasematch (rva (PSTR, map ?: (char *) hm,
+ pd->Name - delta - offset), "cygwin1.dll"))
continue;
if (!fn)
- return (void *) "found it"; // just checking if executable used cygwin1.dll
+ {
+ if (map)
+ UnmapViewOfFile (map);
+ return (void *) "found it"; // just checking if executable used cygwin1.dll
+ }
i = -1;
while (!fh.origfn && (fh.name = makename (name, buf, i, 1)))
RedirectIAT (fh, pd, hm);
break;
}
+ if (map)
+ UnmapViewOfFile (map);
+
while (!fh.origfn && (fh.name = makename (name, buf, i, -1)))
get_export (fh);
IO_STATUS_BLOCK io;
HANDLE h;
NTSTATUS status;
+ LARGE_INTEGER size;
status = NtOpenFile (&h, SYNCHRONIZE | GENERIC_READ,
real_path.get_object_attr (attr, sec_none_nih),
if (!NT_SUCCESS (status))
{
/* File is not readable? Doesn't mean it's not executable.
- Test for executablility and if so, just assume the file is
+ Test for executability and if so, just assume the file is
a cygwin executable and go ahead. */
if (status == STATUS_ACCESS_DENIED && real_path.has_acls ()
&& check_file_access (real_path, X_OK, true) == 0)
}
goto err;
}
+ if (!GetFileSizeEx (h, &size))
+ {
+ NtClose (h);
+ goto err;
+ }
+ if (size.QuadPart > wincap.allocation_granularity ())
+ size.LowPart = wincap.allocation_granularity ();
- HANDLE hm = CreateFileMapping (h, &sec_none_nih, PAGE_READONLY, 0, 0, NULL);
+ HANDLE hm = CreateFileMapping (h, &sec_none_nih, PAGE_READONLY,
+ 0, 0, NULL);
NtClose (h);
if (!hm)
{
}
goto err;
}
- buf = (char *) MapViewOfFile(hm, FILE_MAP_READ, 0, 0, 0);
- CloseHandle (hm);
+ /* Try to map the first 64K of the image. That's enough for the local
+ tests, and it's enough for hook_or_detect_cygwin to compute the IAT
+ address. */
+ buf = (char *) MapViewOfFile (hm, FILE_MAP_READ, 0, 0, size.LowPart);
if (!buf)
- goto err;
+ {
+ CloseHandle (hm);
+ goto err;
+ }
{
myfault efault;
if (efault.faulted ())
{
UnmapViewOfFile (buf);
+ CloseHandle (hm);
real_path.set_cygexec (false);
break;
}
unsigned off = (unsigned char) buf[0x18] | (((unsigned char) buf[0x19]) << 8);
win16_exe = off < sizeof (IMAGE_DOS_HEADER);
if (!win16_exe)
- real_path.set_cygexec (!!hook_or_detect_cygwin (buf, NULL, subsys));
+ real_path.set_cygexec (!!hook_or_detect_cygwin (buf, NULL,
+ subsys, hm));
else
real_path.set_cygexec (false);
UnmapViewOfFile (buf);
+ CloseHandle (hm);
break;
}
}
+ CloseHandle (hm);
debug_printf ("%s is possibly a script", real_path.get_win32 ());
__ino64_t __stdcall hash_path_name (__ino64_t hash, const char *name) __attribute__ ((regparm(2)));
void __stdcall nofinalslash (const char *src, char *dst) __attribute__ ((regparm(2)));
-void *hook_or_detect_cygwin (const char *, const void *, WORD&) __attribute__ ((regparm (3)));
+void *hook_or_detect_cygwin (const char *, const void *, WORD&, HANDLE h = NULL) __attribute__ ((regparm (3)));
/* Time related */
void __stdcall totimeval (struct timeval *, FILETIME *, int, int);