[Bug 32558] New: Visual Studio 2010 (10.0) Express Edition web installer crashes due to winhttp reporting available chunk size > 32 KiB (heap corruption)

wine-bugs at winehq.org wine-bugs at winehq.org
Wed Dec 26 18:16:02 CST 2012


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

             Bug #: 32558
           Summary: Visual Studio 2010 (10.0) Express Edition web
                    installer crashes due to winhttp reporting available
                    chunk size > 32 KiB (heap corruption)
           Product: Wine
           Version: 1.5.20
          Platform: x86
        OS/Version: Linux
            Status: NEW
          Severity: normal
          Priority: P2
         Component: winhttp
        AssignedTo: wine-bugs at winehq.org
        ReportedBy: focht at gmx.net
    Classification: Unclassified


Hello folks,

I noticed strange crashes with the web installer of Visual Studio 2010 (10.0)
Express Edition.
Sometimes the installer would just bail out silently during download.

Prerequisite: 'winetricks -q dotnet20 dotnet40'

Unfortunately +relay or even repeated installer runs succeed most of the time
so it's not easily to reproduce/track down (also depends on client connection
to server).
Also running the inner installer under debugger changes symptoms.

Fortunately I managed get a crash with +relay at one time (using inner
installer).

--- snip ---
$ WINEDEBUG=+tid,+seh,+loaddll,+winhttp,+relay wine ./setup.exe /web
/CreatedTemp /NoExclude /InstalledFrom . >>log.txt 2>&1
...
002a:trace:loaddll:load_native_dll Loaded
L"Z:\\home\\focht\\Downloads\\test\\dlmgr.dll" at 0x364c0000: native 
...
0030:Call oleaut32.SysAllocString(00c00840 L"dlmgr: Starting download attempt 1
of 3 for http://go.microsoft.com/fwlink/?LinkId=165067&clcid=0x409 using Http")
ret=3593f268
0030:Ret  oleaut32.SysAllocString() retval=01560ec4 ret=3593f268
...
0030:Call ntdll.RtlAllocateHeap(00453000,00000008,00008000) ret=364e1884
0030:Ret  ntdll.RtlAllocateHeap() retval=0045bdc8 ret=364e1884 
...
0042:Call KERNEL32.CreateFileW(0186f540
L"C:\\users\\focht\\Temp\\30319.01\\1033\\VC_EXP\\wcu\\watson\\dw20shared.msi",00000002,00000000,00000000,00000002,00000080,00000000)
ret=364db8ff
0042:Ret  KERNEL32.CreateFileW() retval=000001e8 ret=364db8ff 
...
0042:Call
winhttp.WinHttpQueryHeaders(00000003,00000005,00000000,0b56e850,0b56e840,00000000)
ret=364d77ed
0042:trace:winhttp:WinHttpQueryHeaders 0x3, 0x00000005, (null), 0xb56e850,
0xb56e840, (nil)
0042:trace:winhttp:addref_object 0x1718bc0 -> refcount = 3
0042:trace:winhttp:grab_object handle 0x3 -> 0x1718bc0
0042:trace:winhttp:query_headers attribute L"Content-Length"
0042:trace:winhttp:get_header_index L"Content-Length"
0042:trace:winhttp:get_header_index returning 12
0042:trace:winhttp:query_headers returning string: L"1850368"
0042:trace:winhttp:release_object object 0x1718bc0 refcount = 2
0042:Ret  winhttp.WinHttpQueryHeaders() retval=00000001 ret=364d77ed
0042:Call winhttp.WinHttpQueryDataAvailable(00000003,00000000) ret=364d77a6
0042:trace:winhttp:WinHttpQueryDataAvailable 0x3, (nil)
0042:trace:winhttp:addref_object 0x1718bc0 -> refcount = 3
0042:trace:winhttp:grab_object handle 0x3 -> 0x1718bc0
0042:Call ntdll.RtlAllocateHeap(00110000,00000000,0000000c) ret=7e2dc554
0042:Ret  ntdll.RtlAllocateHeap() retval=0186fa68 ret=7e2dc554
0042:trace:winhttp:addref_object 0x1718bc0 -> refcount = 4
0042:Call KERNEL32.QueueUserWorkItem(7e2dc7e9,0186fa68,00000010) ret=7e2dc85b
0042:Ret  KERNEL32.QueueUserWorkItem() retval=00000001 ret=7e2dc85b
0042:trace:winhttp:release_object object 0x1718bc0 refcount = 3
0042:Ret  winhttp.WinHttpQueryDataAvailable() retval=00000001 ret=364d77a6
--- snip ---

Download for first component is 1850368 bytes in total.
The installer allocates a 32 KiB buffer and begins async download using
winhttp.

The "good" sequence reads like this:

--- snip ---
...
0044:Call winhttp.WinHttpReadData(00000003,0045bdc8,00001554,00000000)
ret=364d7787
0042:Call ntdll.RtlFreeHeap(00110000,00000000,01718950) ret=7e2dc63a
0044:trace:winhttp:WinHttpReadData 0x3, 0x45bdc8, 5460, (nil)
0042:Ret  ntdll.RtlFreeHeap() retval=00000001 ret=7e2dc63a
0044:trace:winhttp:addref_object 0x1718bc0 -> refcount = 3
0044:trace:winhttp:grab_object handle 0x3 -> 0x1718bc0
0044:Call ntdll.RtlAllocateHeap(00110000,00000000,00000014) ret=7e2dc554
0044:Ret  ntdll.RtlAllocateHeap() retval=01718cb0 ret=7e2dc554
0044:trace:winhttp:addref_object 0x1718bc0 -> refcount = 4
0044:Call KERNEL32.QueueUserWorkItem(7e2dc7e9,01718cb0,00000010) ret=7e2dc85b
0042:trace:winhttp:query_headers attribute L"Transfer-Encoding"
0042:trace:winhttp:get_header_index L"Transfer-Encoding"
0042:trace:winhttp:get_header_index returning -1
0042:trace:winhttp:read_data *** async=1, to_read=5460, num_bytes: 5460, ret=1,
callback=0x364da8e0, buffer=0x45bdc8
0042:trace:winhttp:read_data *** buf heap magic=0x455355, size=0x8000
0042:trace:winhttp:send_callback 0x1718bc0, 0x00080000, 0x45bdc8, 5460
0042:Call KERNEL32.WriteFile(000001e8,0045bdc8,00001554,0b56e814,00000000)
ret=364db83b
0042:Ret  KERNEL32.WriteFile() retval=00000001 ret=364db83b
...
0044:Ret  KERNEL32.QueueUserWorkItem() retval=00000001 ret=7e2dc85b
...
0044:trace:winhttp:release_object object 0x1718bc0 refcount = 3
0042:Ret  KERNEL32.GetLastError() retval=00002f76 ret=364dfd2f
0044:Ret  winhttp.WinHttpReadData() retval=00000001 ret=364d7787 
--- snip --- 

"trace:winhttp:read_data ***" trace message was added by me for diagnosis
immediately before the send callback (also heap magic and size dump because
+heap is not usable here).

At one point we get this interesting sequence:

--- snip ---
...
000d:Call winhttp.WinHttpQueryDataAvailable(00000003,00000000) ret=364d77a6
000d:trace:winhttp:WinHttpQueryDataAvailable 0x3, (nil)
000d:trace:winhttp:addref_object 0x1718bc0 -> refcount = 3
000d:trace:winhttp:grab_object handle 0x3 -> 0x1718bc0
000d:Call ntdll.RtlAllocateHeap(00110000,00000000,0000000c) ret=7e2dc554
000d:Ret  ntdll.RtlAllocateHeap() retval=01718cb0 ret=7e2dc554
000d:trace:winhttp:addref_object 0x1718bc0 -> refcount = 4
000d:Call KERNEL32.QueueUserWorkItem(7e2dc7e9,01718cb0,00000010) ret=7e2dc85b
000d:Ret  KERNEL32.QueueUserWorkItem() retval=00000001 ret=7e2dc85b
0042:trace:winhttp:query_data 73440 bytes available
000d:trace:winhttp:release_object object 0x1718bc0 refcount = 3
0042:trace:winhttp:send_callback 0x1718bc0, 0x00040000, 0xb56e90c, 4
000d:Ret  winhttp.WinHttpQueryDataAvailable() retval=00000001 ret=364d77a6 
...
0042:Call winhttp.WinHttpReadData(00000003,0045bdc8,00011ee0,00000000)
ret=364d7787
000d:Call ntdll.RtlFreeHeap(00110000,00000000,01870290) ret=7e2dc63a
0042:trace:winhttp:WinHttpReadData 0x3, 0x45bdc8, 73440, (nil)
000d:Ret  ntdll.RtlFreeHeap() retval=00000001 ret=7e2dc63a
0042:trace:winhttp:addref_object 0x1718bc0 -> refcount = 3
0042:trace:winhttp:grab_object handle 0x3 -> 0x1718bc0
0042:Call ntdll.RtlAllocateHeap(00110000,00000000,00000014) ret=7e2dc554
0042:Ret  ntdll.RtlAllocateHeap() retval=01870290 ret=7e2dc554
0042:trace:winhttp:addref_object 0x1718bc0 -> refcount = 4
0042:Call KERNEL32.QueueUserWorkItem(7e2dc7e9,01870290,00000010) ret=7e2dc85b
0042:Ret  KERNEL32.QueueUserWorkItem() retval=00000001 ret=7e2dc85b
0044:trace:winhttp:query_headers attribute L"Transfer-Encoding"
0042:trace:winhttp:release_object object 0x1718bc0 refcount = 3
0044:trace:winhttp:get_header_index L"Transfer-Encoding"
0042:Ret  winhttp.WinHttpReadData() retval=00000001 ret=364d7787
0044:trace:winhttp:get_header_index returning -1
0042:trace:winhttp:release_object object 0x1718bc0 refcount = 2
0042:Call ntdll.RtlFreeHeap(00110000,00000000,01718cb0) ret=7e2dc63a
0042:Ret  ntdll.RtlFreeHeap() retval=00000001 ret=7e2dc63a
0044:trace:winhttp:read_data *** async=1, to_read=73440, num_bytes: 73440,
ret=1, callback=0x364da8e0, buffer=0x45bdc8
0044:trace:winhttp:read_data *** buf heap magic=0x455355, size=0x8000
0044:trace:winhttp:send_callback 0x1718bc0, 0x00080000, 0x45bdc8, 73440 
...
--- snip ---

73440 bytes available reported and WinHttpReadData() is called from installer
with the _same_ original buffer (0x45bdc8) which was allocated with 32 KiB
(0x8000 bytes) - no realloc in between!
This obviously leads to a heap overwrite and some time later to crashes.

--- snip ---
...
000d:trace:winhttp:read_data *** async=1, to_read=5760, num_bytes: 5760, ret=1,
callback=0x364da8e0, buffer=0x45bdc8
000d:trace:winhttp:read_data *** buf heap magic=0x455355, size=0x8000
000d:trace:winhttp:send_callback 0x1718bc0, 0x00080000, 0x45bdc8, 5760
000d:Call KERNEL32.WriteFile(000001e8,0045bdc8,00001680,0b76e814,00000000)
ret=364db83b
000d:Ret  KERNEL32.WriteFile() retval=00000001 ret=364db83b
000d:Call ntdll.RtlAllocateHeap(00110000,00000000,00000080) ret=364ee12c
000d:Ret  ntdll.RtlAllocateHeap() retval=0186fc18 ret=364ee12c
000d:Call KERNEL32.GetLastError() ret=364dfd2f
000d:Ret  KERNEL32.GetLastError() retval=00002f76 ret=364dfd2f
000d:Call KERNEL32.GetLastError() ret=364dfd2f
000d:Ret  KERNEL32.GetLastError() retval=00002f76 ret=364dfd2f
000d:trace:seh:raise_exception code=c0000005 flags=0 addr=0x364e4b6f
ip=364e4b6f tid=000d
000d:trace:seh:raise_exception  info[0]=00000000
000d:trace:seh:raise_exception  info[1]=98211559
000d:trace:seh:raise_exception  eax=982114ad ebx=00000002 ecx=0b76e30c
edx=00000000 esi=0b76e53a edi=0b76e53a
000d:trace:seh:raise_exception  ebp=0b76e740 esp=0b76e2bc cs=0023 ds=002b
es=002b fs=0063 gs=006b flags=00010202 
--- snip --- 

I added a small code snippet to automatically report/truncate available chunk
size to 32 KiB if larger.

--- snip ---
...
fixme:winhttp:query_data truncating data avail from 50400 to 32768 bytes!
fixme:winhttp:query_data truncating data avail from 89632 to 32768 bytes!
fixme:winhttp:query_data truncating data avail from 71264 to 32768 bytes!
fixme:winhttp:query_data truncating data avail from 91776 to 32768 bytes!
fixme:winhttp:query_data truncating data avail from 116608 to 32768 bytes!
fixme:winhttp:query_data truncating data avail from 93920 to 32768 bytes!
fixme:winhttp:query_data truncating data avail from 69792 to 32768 bytes!
fixme:winhttp:query_data truncating data avail from 96064 to 32768 bytes!
fixme:winhttp:query_data truncating data avail from 67616 to 32768 bytes!
fixme:winhttp:query_data truncating data avail from 59328 to 32768 bytes!
...
--- snip ---

With that change in place the web installer runs rock stable, sometimes
reaching download speeds of 2-3 MiB/s using winhttp (not maxing out my
connection - that might be server-side bandwidth issue).

I've not found any useful info on MSDN about a 32 KiB limit on winhttp chunk
size.
Maybe the MS guys who wrote the installer made some assumption about some
underlying native winsock implementation limitation on Windows.

It might be interesting to see what max. chunk size native winhttp reports to
clients.

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