Fix thinko in /proc/<PID>/maps TEB detection on W10 1511

* fhandler_process.cc (thread_info::thread_info): Accommodate the fact
        that TEBs take two pages.
        (thread_info::fill_if_match): Rewrite the method for post W10 1511 TEB
        detection.
        (format_process_maps): Add a state member to region.  Fix the code
        to handle PEB/TEB region since W10 1511.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen 2015-12-03 16:54:08 +01:00
parent f1ed5bfa83
commit 8f4da28eb6
2 changed files with 62 additions and 28 deletions

View File

@ -1,3 +1,12 @@
2015-12-03 Corinna Vinschen <corinna@vinschen.de>
* fhandler_process.cc (thread_info::thread_info): Accommodate the fact
that TEBs take two pages.
(thread_info::fill_if_match): Rewrite the method for post W10 1511 TEB
detection.
(format_process_maps): Add a state member to region. Fix the code
to handle PEB/TEB region since W10 1511.
2015-12-03 Corinna Vinschen <corinna@vinschen.de> 2015-12-03 Corinna Vinschen <corinna@vinschen.de>
* fhandler_process.cc (heap_info::fill_if_match): Return NULL, not 0. * fhandler_process.cc (heap_info::fill_if_match): Return NULL, not 0.

View File

@ -731,7 +731,8 @@ struct thread_info
{ {
*r = (region) { regions, (ULONG) (ULONG_PTR) thread[i].ClientId.UniqueThread, *r = (region) { regions, (ULONG) (ULONG_PTR) thread[i].ClientId.UniqueThread,
(char *) tbi.TebBaseAddress, (char *) tbi.TebBaseAddress,
(char *) tbi.TebBaseAddress + wincap.page_size (), (char *) tbi.TebBaseAddress
+ 2 * wincap.page_size (),
true }; true };
regions = r; regions = r;
} }
@ -771,17 +772,14 @@ struct thread_info
} }
return NULL; return NULL;
} }
char *fill_if_match (char *start, char *end, ULONG type, char *dest) /* Helper to look for TEBs inside single allocated region since W10 1511. */
char *fill_if_match (char *start, char *dest)
{ {
for (region *r = regions; r; r = r->next) for (region *r = regions; r; r = r->next)
if (r->teb && start <= r->start && r->end <= end) if (r->teb && start == r->start)
{ {
char *p = dest + __small_sprintf (dest, "[teb (tid %ld)", __small_sprintf (dest, "[teb (tid %ld)]", r->thread_id);
r->thread_id); return r->end;
if (type & MEM_MAPPED)
p = stpcpy (p, " shared");
stpcpy (p, "]");
return dest;
} }
return NULL; return NULL;
} }
@ -839,6 +837,7 @@ format_process_maps (void *data, char *&destbuf)
char *abase; char *abase;
char *rbase; char *rbase;
char *rend; char *rend;
DWORD state;
} cur = {{{'\0'}}, (char *)1, 0, 0}; } cur = {{{'\0'}}, (char *)1, 0, 0};
MEMORY_BASIC_INFORMATION mb; MEMORY_BASIC_INFORMATION mb;
@ -852,6 +851,7 @@ format_process_maps (void *data, char *&destbuf)
PMEMORY_SECTION_NAME msi = (PMEMORY_SECTION_NAME) tp.w_get (); PMEMORY_SECTION_NAME msi = (PMEMORY_SECTION_NAME) tp.w_get ();
char *posix_modname = tp.c_get (); char *posix_modname = tp.c_get ();
size_t maxsize = 0; size_t maxsize = 0;
char *peb_teb_abase = NULL;
if (destbuf) if (destbuf)
{ {
@ -897,7 +897,8 @@ format_process_maps (void *data, char *&destbuf)
region next = { a, region next = { a,
(char *) mb.AllocationBase, (char *) mb.AllocationBase,
(char *) mb.BaseAddress, (char *) mb.BaseAddress,
(char *) mb.BaseAddress+mb.RegionSize (char *) mb.BaseAddress+mb.RegionSize,
mb.State
}; };
/* Windows permissions are more fine-grained than the unix rwxp, /* Windows permissions are more fine-grained than the unix rwxp,
@ -915,24 +916,48 @@ peb_teb_rinse_repeat:
the region starting at the PEB address page-wise. */ the region starting at the PEB address page-wise. */
if (wincap.has_new_pebteb_region ()) if (wincap.has_new_pebteb_region ())
{ {
if (!newbase && cur.rbase == (char *) peb) if (peb_teb_abase && !peb_teb_end && cur.abase == peb_teb_abase)
{
strcpy (posix_modname, "[peb]");
peb_teb_end = cur.rend;
cur.rend = cur.rbase + wincap.page_size ();
}
else if (peb_teb_end)
{ {
posix_modname[0] = '\0'; posix_modname[0] = '\0';
if (!threads.fill_if_match (cur.rbase, cur.rend, peb_teb_end = cur.rend;
mb.Type, posix_modname)) if (cur.state == MEM_COMMIT)
do cur.rend = cur.rbase + wincap.page_size ();
{ }
cur.rend += wincap.page_size (); if (cur.state == MEM_COMMIT)
} {
while (!threads.fill_if_match (cur.rbase, cur.rend, if (!peb_teb_abase && cur.rbase == (char *) peb)
mb.Type, posix_modname) {
&& cur.rend < peb_teb_end); peb_teb_abase = cur.abase;
peb_teb_end = cur.rend;
cur.rend = cur.rbase + wincap.page_size ();
strcpy (posix_modname, "[peb]");
}
else if (peb_teb_end)
{
char *end;
posix_modname[0] = '\0';
end = threads.fill_if_match (cur.rbase, posix_modname);
if (end)
cur.rend = end;
else
{
char *base = cur.rbase;
do
{
base += wincap.page_size ();
}
while (!threads.fill_if_match (base, posix_modname)
&& base < peb_teb_end);
if (posix_modname[0])
{
posix_modname[0] = '\0';
cur.rend = base;
}
else
cur.rend = peb_teb_end;
}
}
} }
} }
/* output the current region if it's "interesting". */ /* output the current region if it's "interesting". */
@ -956,7 +981,7 @@ peb_teb_rinse_repeat:
len += __small_sprintf (destbuf + len, "%s\n", posix_modname); len += __small_sprintf (destbuf + len, "%s\n", posix_modname);
} }
if (peb_teb_end) if (peb_teb_end && cur.state == MEM_COMMIT)
{ {
cur.rbase = cur.rend; cur.rbase = cur.rend;
cur.rend += wincap.page_size (); cur.rend += wincap.page_size ();
@ -966,7 +991,7 @@ peb_teb_rinse_repeat:
/* start of a new region (but possibly still the same allocation). */ /* start of a new region (but possibly still the same allocation). */
cur = next; cur = next;
/* if a new allocation, figure out what kind it is. */ /* if a new allocation, figure out what kind it is. */
if (newbase && !last_pass && mb.State != MEM_FREE) if (newbase && !last_pass && cur.state != MEM_FREE)
{ {
/* If the return length pointer is missing, NtQueryVirtualMemory /* If the return length pointer is missing, NtQueryVirtualMemory
returns with STATUS_ACCESS_VIOLATION on Windows 2000. */ returns with STATUS_ACCESS_VIOLATION on Windows 2000. */