diff options
-rw-r--r-- | winsup/cygwin/ChangeLog | 10 | ||||
-rw-r--r-- | winsup/cygwin/hookapi.cc | 38 | ||||
-rw-r--r-- | winsup/cygwin/spawn.cc | 30 | ||||
-rw-r--r-- | winsup/cygwin/winsup.h | 2 |
4 files changed, 69 insertions, 11 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 20bb859e2..2e2c194d0 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,13 @@ +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 diff --git a/winsup/cygwin/hookapi.cc b/winsup/cygwin/hookapi.cc index b82e4b4c5..8137b85d2 100644 --- a/winsup/cygwin/hookapi.cc +++ b/winsup/cygwin/hookapi.cc @@ -10,6 +10,7 @@ details. */ #include "winsup.h" #include <stdlib.h> +#include <sys/param.h> #include "ntdll.h" #include "cygerrno.h" #include "security.h" @@ -226,7 +227,7 @@ out: // 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); @@ -238,15 +239,36 @@ hook_or_detect_cygwin (const char *name, const void *fn, WORD& subsys) 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; @@ -256,10 +278,15 @@ hook_or_detect_cygwin (const char *name, const void *fn, WORD& subsys) // 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); @@ -267,6 +294,9 @@ hook_or_detect_cygwin (const char *name, const void *fn, WORD& subsys) break; } + if (map) + UnmapViewOfFile (map); + while (!fh.origfn && (fh.name = makename (name, buf, i, -1))) get_export (fh); diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index 48d639a8a..f9e1504b1 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -1059,6 +1059,7 @@ av::fixup (const char *prog_arg, path_conv& real_path, const char *ext, 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), @@ -1069,7 +1070,7 @@ av::fixup (const char *prog_arg, path_conv& real_path, const char *ext, 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) @@ -1079,8 +1080,16 @@ av::fixup (const char *prog_arg, path_conv& real_path, const char *ext, } 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) { @@ -1092,16 +1101,22 @@ av::fixup (const char *prog_arg, path_conv& real_path, const char *ext, } 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; } @@ -1111,13 +1126,16 @@ av::fixup (const char *prog_arg, path_conv& real_path, const char *ext, 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 ()); diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h index e865cbc57..a7b828580 100644 --- a/winsup/cygwin/winsup.h +++ b/winsup/cygwin/winsup.h @@ -216,7 +216,7 @@ __ino64_t __stdcall hash_path_name (__ino64_t hash, PCWSTR name) __attribute__ ( __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); |