[Bug 21624] MJ12node.exe crashes with StackOverflowException

wine-bugs at winehq.org wine-bugs at winehq.org
Sun Feb 7 15:16:27 CST 2010


http://bugs.winehq.org/show_bug.cgi?id=21624





--- Comment #9 from Anastasius Focht <focht at gmx.net>  2010-02-07 15:16:26 ---
Hello,

thanks for the logs.
My instinct for interesting bugs did not let me down ;-)

The problem is most likely buried within iphlpapi.GetNetworkParams() and use of
dns resolver API.

Query the buffer size:

--- snip ---
002d:Call iphlpapi.GetNetworkParams(00000000,0457df5c) ret=03994f7e
002d:Ret  iphlpapi.GetNetworkParams() retval=0000006f ret=03994f7e 
...
002d:trace:heap:RtlAllocateHeap (0x110000,70000062,00000270): returning
0x400a138
...
--- snip ---

Fill the network/dns info into provided buffer:

--- snip ---
002d:Call iphlpapi.GetNetworkParams(0400a138,0457df5c) ret=03994f7e
...
002d:Call advapi32.RegQueryValueExA(000002e4,7e058bb9
"ScopeID",00000000,00000000,0400a270,0457dde4) ret=7e053c8b
002d:Ret  advapi32.RegQueryValueExA() retval=00000002 ret=7e053c8b
...
002d:Ret  iphlpapi.GetNetworkParams() retval=00000000 ret=03994f7e
--- snip ---

Relevant structures to calculate sizes (needed later):

--- snip include/iptypes.h ---
typedef struct {
    char String[4 * 4];
} IP_ADDRESS_STRING, *PIP_ADDRESS_STRING, IP_MASK_STRING, *PIP_MASK_STRING;

typedef struct _IP_ADDR_STRING {
    struct _IP_ADDR_STRING* Next;
    IP_ADDRESS_STRING IpAddress;
    IP_MASK_STRING IpMask;
    DWORD Context;
} IP_ADDR_STRING, *PIP_ADDR_STRING;

...

typedef struct {
    char HostName[MAX_HOSTNAME_LEN + 4] ;
    char DomainName[MAX_DOMAIN_NAME_LEN + 4];
    PIP_ADDR_STRING CurrentDnsServer;
    IP_ADDR_STRING DnsServerList;
    UINT NodeType;
    char ScopeId[MAX_SCOPE_ID_LEN + 4];
    UINT EnableRouting;
    UINT EnableProxy;
    UINT EnableDns;
} FIXED_INFO, *PFIXED_INFO;
--- snip include/iptypes.h ---

Sizes:

128+4 HostName
128+4 DomainName
4 CurrentDnsServer
40 DnsServerList
4 NodeType
256+4 ScopeId
4 EnableRouting
4 EnableProxy
4 EnableDns

Sum: 584 bytes -> 0x248 hex bytes

0x270 bytes from previous iphlpapi.GetNetworkParams() calls:

sizeof(FIXED_INFO) + sizeof(IP_ADDR_STRING) = two dns server entries.
Additional dns server entries (_res.nscount > 1) are appended to struct
FIXED_INFO.

Some time later (on different thread 0x3d):

--- snip ---
003d:Call iphlpapi.GetNetworkParams(00000000,0b7ddc50) ret=03994f7e
003d:Ret  iphlpapi.GetNetworkParams() retval=0000006f ret=03994f7e
...
003d:trace:heap:RtlAllocateHeap (0x110000,70000062,00000248): returning
0x4009aa0
...
003d:Call iphlpapi.GetNetworkParams(04009aa0,0b7ddc50) ret=03994f7e 
...
003d:Call KERNEL32.GetComputerNameExA(00000001,04009aa0,0b7ddadc) ret=7e053b75
...
003d:Ret  KERNEL32.GetComputerNameExA() retval=00000001 ret=7e053b75
003d:Call KERNEL32.GetComputerNameExA(00000002,04009b24,0b7ddadc) ret=7e053b9c 
...
003d:Ret  KERNEL32.GetComputerNameExA() retval=00000001 ret=7e053b9c 
003d:Call advapi32.RegOpenKeyExA(80000002,7e058870
"SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP",00000000,00020019,0b7ddad8)
ret=7e053c43
003d:Ret  advapi32.RegOpenKeyExA() retval=00000000 ret=7e053c43
003d:Call advapi32.RegQueryValueExA(000003b4,7e058bb9
"ScopeID",00000000,00000000,04009bd8,0b7ddad4) ret=7e053c8b
0009:err:heap:HEAP_ValidateInUseArena Heap 0x110000: block 0x4009aa0 tail
overwritten at 0x4009ce8 (byte 0/8 == 0x00)
003d:Ret  advapi32.RegQueryValueExA() retval=00000002 ret=7e053c8b
--- snip ---

This is where wine's heap detector raises its hand first time because the
FIXED_INFO buffer was written past the end.

If you look closely you notice this time the GetNetworkParams() query for
buffer size returned only 0x248 bytes - which is just sizeof(FIXED_INFO) = 1
dns server entry?!

Looking at the corresponding code:

--- snip dlls/iphlpapi/ ---
DWORD WINAPI GetNetworkParams(PFIXED_INFO pFixedInfo, PULONG pOutBufLen)
{
  DWORD ret, size;
  LONG regReturn;
  HKEY hKey;

  TRACE("pFixedInfo %p, pOutBufLen %p\n", pFixedInfo, pOutBufLen);
  if (!pOutBufLen)
    return ERROR_INVALID_PARAMETER;

  initialise_resolver();
  size = sizeof(FIXED_INFO) + (_res.nscount > 0 ? (_res.nscount  - 1) *
   sizeof(IP_ADDR_STRING) : 0);
  if (!pFixedInfo || *pOutBufLen < size) {
    *pOutBufLen = size;
    return ERROR_BUFFER_OVERFLOW;
  }

  memset(pFixedInfo, 0, size);
  size = sizeof(pFixedInfo->HostName);
  GetComputerNameExA(ComputerNameDnsHostname, pFixedInfo->HostName, &size);
  size = sizeof(pFixedInfo->DomainName);
  GetComputerNameExA(ComputerNameDnsDomain, pFixedInfo->DomainName, &size);
  if (_res.nscount > 0) {
    PIP_ADDR_STRING ptr;
    int i;

    for (i = 0, ptr = &pFixedInfo->DnsServerList; i < _res.nscount && ptr;
     i++, ptr = ptr->Next) {
      toIPAddressString(_res.nsaddr_list[i].sin_addr.s_addr,
       ptr->IpAddress.String);
      if (i == _res.nscount - 1)
        ptr->Next = NULL;
      else if (i == 0)
        ptr->Next = (PIP_ADDR_STRING)((LPBYTE)pFixedInfo + sizeof(FIXED_INFO));
      else
        ptr->Next = (PIP_ADDR_STRING)((PBYTE)ptr + sizeof(IP_ADDR_STRING));
    }
  }
  pFixedInfo->NodeType = HYBRID_NODETYPE;
  regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
   "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &hKey);
  if (regReturn != ERROR_SUCCESS)
    regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
     "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters", 0, KEY_READ,
     &hKey);
  if (regReturn == ERROR_SUCCESS)
  {
    DWORD size = sizeof(pFixedInfo->ScopeId);

    RegQueryValueExA(hKey, "ScopeID", NULL, NULL, (LPBYTE)pFixedInfo->ScopeId,
&size);
    RegCloseKey(hKey);
  } 
...
--- snip dlls/iphlpapi/ ---

The only code that is able to write past the FIXED_INFO buffer is the dns
server entries list population loop.
If for some reason "_res.nscount" changes between overall buffer size
calculation and dns server entries list population it could be possible to
corrupt nearby block.

Now the question is: who can change "_res.nscount"?
The API that might be the culprit is GetComputerNameExA(
ComputerNameDnsHostname, ...) which is called in between "_res.nscount"
queries.

dlls/kernel32/computername.c:
dns_hostname() -> dns_fqdn() -> gethostname() and
dns_gethostbyname()/gethostbyname_r()

So this code path seems potentially harmful to GetNetworkParams() as it might
change "_res" dns resolver struct members implicitly.

Again this is just my theory how the memory corruption might be caused.
I could be wrong as I can't reproduce the problem on my machine.
For testing you could place a consistency check, comparing "_res.nscount"
before and after GetComputerNameExA().

Regards

-- 
Configure bugmail: http://bugs.winehq.org/userprefs.cgi?tab=email
Do not reply to this email, post in Bugzilla using the
above URL to reply.
------- You are receiving this mail because: -------
You are watching all bug changes.



More information about the wine-bugs mailing list