While using our network traffic monitoring tool (which uses WinPcap on
Windows) on a single processor Win2000 machine running an appserver under
load, we've run into a problem which one of our developers has subsequently
analyzed and formulated a theory as to the possible cause:

------------------------------------------------------
An unexpected exception has been detected in native code outside the VM.
Unexpected Signal : EXCEPTION_ACCESS_VIOLATION occurred at PC=0xa1a975f
Function name=pcap_read
Library=C:\WINNT\System32\wpcap.dll

Current Java thread:
        at
com.sitraka.alto.agent.plugin.NetworkTrafficMonitorPlugIn$DeviceMonit
or.readPackets(Native Method)
        at
com.sitraka.alto.agent.plugin.NetworkTrafficMonitorPlugIn$DeviceMonit
or.run(NetworkTrafficMonitorPlugIn.java:413)
        at java.lang.Thread.run(Thread.java:484)

Dynamic libraries:
0x00400000 - 0x00405000         c:\bea61sp2\jdk131\bin\java.exe
0x77F80000 - 0x77FFB000         C:\WINNT\System32\ntdll.dll
0x77DB0000 - 0x77E0B000         C:\WINNT\system32\ADVAPI32.dll
0x77E80000 - 0x77F35000         C:\WINNT\system32\KERNEL32.DLL
0x77D40000 - 0x77DB0000         C:\WINNT\system32\RPCRT4.DLL
0x78000000 - 0x78046000         C:\WINNT\system32\MSVCRT.dll
0x6D420000 - 0x6D4EE000         c:\bea61sp2\jdk131\jre\bin\hotspot\jvm.dll
0x77E10000 - 0x77E74000         C:\WINNT\system32\USER32.dll
0x77F40000 - 0x77F7C000         C:\WINNT\system32\GDI32.DLL
0x77570000 - 0x775A0000         C:\WINNT\System32\WINMM.dll
0x6D220000 - 0x6D227000         c:\bea61sp2\jdk131\jre\bin\hpi.dll
0x6D3B0000 - 0x6D3BD000         c:\bea61sp2\jdk131\jre\bin\verify.dll
0x6D250000 - 0x6D266000         c:\bea61sp2\jdk131\jre\bin\java.dll
0x6D3C0000 - 0x6D3CD000         c:\bea61sp2\jdk131\jre\bin\zip.dll
0x6D340000 - 0x6D348000         C:\bea61sp2\jdk131\jre\bin\net.dll
0x75050000 - 0x75058000         C:\WINNT\System32\WSOCK32.dll
0x75030000 - 0x75043000         C:\WINNT\System32\WS2_32.DLL
0x75020000 - 0x75028000         C:\WINNT\System32\WS2HELP.DLL
0x785C0000 - 0x785CC000         C:\WINNT\System32\rnr20.dll
0x77980000 - 0x779A4000         C:\WINNT\System32\DNSAPI.DLL
0x77340000 - 0x77353000         C:\WINNT\System32\iphlpapi.dll
0x77520000 - 0x77525000         C:\WINNT\System32\ICMP.DLL
0x77320000 - 0x77337000         C:\WINNT\System32\MPRAPI.DLL
0x75150000 - 0x75160000         C:\WINNT\System32\SAMLIB.DLL
0x75170000 - 0x751BF000         C:\WINNT\System32\NETAPI32.DLL
0x77BE0000 - 0x77BEF000         C:\WINNT\System32\SECUR32.DLL
0x751C0000 - 0x751C6000         C:\WINNT\System32\NETRAP.DLL
0x77950000 - 0x77979000         C:\WINNT\system32\WLDAP32.DLL
0x77A50000 - 0x77B46000         C:\WINNT\system32\OLE32.DLL
0x779B0000 - 0x77A4B000         C:\WINNT\system32\OLEAUT32.DLL
0x773B0000 - 0x773DE000         C:\WINNT\System32\ACTIVEDS.DLL
0x77380000 - 0x773A2000         C:\WINNT\System32\ADSLDPC.DLL
0x77830000 - 0x7783E000         C:\WINNT\System32\RTUTILS.DLL
0x77880000 - 0x7790D000         C:\WINNT\System32\SETUPAPI.DLL
0x77C10000 - 0x77C6D000         C:\WINNT\System32\USERENV.DLL
0x774E0000 - 0x77512000         C:\WINNT\System32\RASAPI32.DLL
0x774C0000 - 0x774D1000         C:\WINNT\System32\RASMAN.DLL
0x77530000 - 0x77552000         C:\WINNT\system32\TAPI32.DLL
0x716F0000 - 0x7177A000         C:\WINNT\system32\COMCTL32.DLL
0x70BD0000 - 0x70C1C000         C:\WINNT\system32\SHLWAPI.DLL
0x77360000 - 0x77379000         C:\WINNT\System32\DHCPCSVC.DLL
0x775A0000 - 0x77625000         C:\WINNT\System32\CLBCATQ.DLL
0x777E0000 - 0x777E8000         C:\WINNT\System32\winrnr.dll
0x777F0000 - 0x777F5000         C:\WINNT\System32\rasadhlp.dll
0x74FD0000 - 0x74FEF000         C:\WINNT\system32\msafd.dll
0x75010000 - 0x75017000         C:\WINNT\System32\wshtcpip.dll
0x10000000 - 0x10011000
C:\PerformaSure1.6\CAPE-20020703.0400\bin\Window
sPDH.dll
0x692E0000 - 0x69307000         C:\WINNT\System32\pdh.dll
0x76B30000 - 0x76B6E000         C:\WINNT\system32\comdlg32.dll
0x782F0000 - 0x78532000         C:\WINNT\system32\SHELL32.DLL
0x78280000 - 0x782B3000         C:\WINNT\system32\kerberos.dll
0x76670000 - 0x7667E000         C:\WINNT\System32\CRYPTDLL.DLL
0x77430000 - 0x77440000         C:\WINNT\System32\MSASN1.DLL
0x692B0000 - 0x692B8000         C:\WINNT\System32\perfdisk.dll
0x69280000 - 0x69289000         C:\WINNT\System32\perfos.dll
0x0A180000 - 0x0A195000
C:\PerformaSure1.6\CAPE-20020703.0400\bin\Networ
kTrafficMonitorPlugIn.dll
0x0A1A0000 - 0x0A1C9000         C:\WINNT\System32\wpcap.dll
0x0A1D0000 - 0x0A1D8000         C:\WINNT\System32\packet.dll
0x0BB60000 - 0x0BB65000         C:\bea61sp2\wlserver6.1\bin\wlntio.dll
0x6D240000 - 0x6D246000         C:\bea61sp2\jdk131\jre\bin\ioser12.dll
0x77920000 - 0x77943000         C:\WINNT\system32\imagehlp.dll
0x72A00000 - 0x72A2D000         C:\WINNT\system32\DBGHELP.dll
0x690A0000 - 0x690AB000         C:\WINNT\System32\PSAPI.DLL

Local Time = Wed Jul 03 17:08:15 2002
Elapsed Time = 1957
#
# The exception above was detected in native code outside the VM
#
# Java VM: Java HotSpot(TM) Client VM (1.3.1_01 mixed mode)
#
# An error report file has been saved as hs_err_pid824.log.
# Please refer to the file for further information.
#

------------------------------------------------------


After digging around in the WinPcap source code the following theory was
proposed:


------------------------------------------------------
1. The description of the system exception (EXCEPTION_ACCESS_VIOLATION
occurred at PC=0xa1a975f
Function name=pcap_read) points to the following code fragment (from the
disasm of wpcap.dll -- wpcap.dll.dump):


   pcap_read:
    10009700: 51                 push        ecx
    10009701: 53                 push        ebx
    10009702: 55                 push        ebp
    10009703: 56                 push        esi
    10009704: 57                 push        edi
    10009705: 8B 7C 24 18        mov         edi,dword ptr [esp+18h]
    10009709: 33 ED              xor         ebp,ebp
    1000970B: 8B 47 5C           mov         eax,dword ptr [edi+5Ch]
    1000970E: 85 C0              test        eax,eax
    10009710: 75 3A              jne         1000974C
    10009712: 8B 47 04           mov         eax,dword ptr [edi+4]
    10009715: 8B 0F              mov         ecx,dword ptr [edi]
    10009717: 6A 01              push        1
    10009719: 50                 push        eax
    1000971A: 51                 push        ecx
    1000971B: E8 F4 1B 00 00     call        1000B314
    10009720: 83 C4 0C           add         esp,0Ch
    10009723: 84 C0              test        al,al
    10009725: 75 1A              jne         10009741
    10009727: 83 C7 6C           add         edi,6Ch
    1000972A: 68 9C CE 01 10     push        1001CE9Ch
    1000972F: 57                 push        edi
    10009730: E8 3E 1C 00 00     call        1000B373
    10009735: 83 C4 08           add         esp,8
    10009738: 83 C8 FF           or          eax,0FFFFFFFFh
    1000973B: 5F                 pop         edi
    1000973C: 5E                 pop         esi
    1000973D: 5D                 pop         ebp
    1000973E: 5B                 pop         ebx
    1000973F: 59                 pop         ecx
    10009740: C3                 ret
    10009741: 8B 4F 04           mov         ecx,dword ptr [edi+4]
    10009744: 8B 41 20           mov         eax,dword ptr [ecx+20h]
    10009747: 8B 71 18           mov         esi,dword ptr [ecx+18h]
    1000974A: EB 03              jmp         1000974F
    1000974C: 8B 77 58           mov         esi,dword ptr [edi+58h]
    1000974F: 03 C6              add         eax,esi
    10009751: 3B F0              cmp         esi,eax
    10009753: 89 44 24 10        mov         dword ptr [esp+10h],eax
    10009757: 73 3A              jae         10009793
    10009759: 8B 44 24 24        mov         eax,dword ptr [esp+24h]
    1000975D: 33 FF              xor         edi,edi
  **1000975F: 66 8B 7E 10        mov         di,word ptr [esi+10h]
    10009763: 8B 5E 08           mov         ebx,dword ptr [esi+8]
    10009766: 8D 14 37           lea         edx,[edi+esi]
    10009769: 52                 push        edx
    1000976A: 56                 push        esi
    1000976B: 50                 push        eax
    1000976C: FF 54 24 2C        call        dword ptr [esp+2Ch]
    10009770: 8B 44 24 28        mov         eax,dword ptr [esp+28h]
    10009774: 8D 4C 1F 03        lea         ecx,[edi+ebx+3]
    10009778: 83 E1 FC           and         ecx,0FFFFFFFCh
    1000977B: 83 C4 0C           add         esp,0Ch
    1000977E: 03 F1              add         esi,ecx
    10009780: 45                 inc         ebp
    10009781: 3B E8              cmp         ebp,eax
    10009783: 7C 04              jl          10009789
    10009785: 85 C0              test        eax,eax
    10009787: 7F 19              jg          100097A2
    10009789: 3B 74 24 10        cmp         esi,dword ptr [esp+10h]
    1000978D: 72 CA              jb          10009759
    1000978F: 8B 7C 24 18        mov         edi,dword ptr [esp+18h]
    10009793: C7 47 5C 00 00 00  mov         dword ptr [edi+5Ch],0
              00
    1000979A: 5F                 pop         edi
    1000979B: 8B C5              mov         eax,ebp
    1000979D: 5E                 pop         esi
    1000979E: 5D                 pop         ebp
    1000979F: 5B                 pop         ebx
    100097A0: 59                 pop         ecx
    100097A1: C3                 ret
    100097A2: 8B 44 24 10        mov         eax,dword ptr [esp+10h]
    100097A6: 8B 4C 24 18        mov         ecx,dword ptr [esp+18h]
    100097AA: 2B C6              sub         eax,esi
    100097AC: 5F                 pop         edi
    100097AD: 89 71 58           mov         dword ptr [ecx+58h],esi
    100097B0: 89 41 5C           mov         dword ptr [ecx+5Ch],eax
    100097B3: 8B C5              mov         eax,ebp
    100097B5: 5E                 pop         esi
    100097B6: 5D                 pop         ebp
    100097B7: 5B                 pop         ebx
    100097B8: 59                 pop         ecx
    100097B9: C3                 ret
When compared to the source (Pcap-win32.c, lines 69--116) it most certainly
corresponds to the following C statement:
#define bhp ((struct bpf_hdr *)bp)
   hdrlen = bhp->bh_hdrlen;
           ^^^^^^^^^^^^^^^
Register mapping around line 100975f: esi = bp; edi = (short) hdrlen; edx =
bp + hdrlen
In this context the error indicates that the address in esi was invalid. But
on the other hand the value of bp is taken from
(*pcap_t)->Buffer. That buffer is allocated only once and is never
reallocated for the duration of pcap session, and data is not moved or
copied by wpcap.dll. Consequently this makes me assume that the exception is
not caused by an error in wpcap.dll, but instead there's an error in the
driver that caused the region of memory containing pcap_t structure to be
overwritten with 'bad' data.

2. Let's take a look at the driver's code (packetNtx/DRIVER/Read.c)
This file apparently contains logic to deal with transferring captured
packets from the underlying system network driver to the user memory (i.e.
wpcap.dll). The driver maintains a circular buffer for packet data: the
incoming packets are put the 'end' of it causing Btail and BlastByte to be
updated; when the data is sent to the dll Bhead is updated thus freeing
buffer space.

Read.c has two functions of interest: Packet_tap, which obviously retrieves
a packed from network driver and adds it to the circular buffer, and
PacketRead, which copies the accumulated packets to the supplied dll buffer.

Now the problem:

The following fragment is executed when a new packet needs to be added to
the buffer.
Packet_tap (lines 331-341):

   maxbufspace=fres+sizeof(struct bpf_hdr);
   if(Ttail+maxbufspace>=Open->BufSize){
    if(Thead<=maxbufspace)
    {
     //the buffer is full: the packet is lost
     Open->Dropped++;
     return NDIS_STATUS_NOT_ACCEPTED;
    }
    else{
     Ttail=0;
    }
   }
Let's consider the situation when 0 < Ttail < Thead < TLastByte <
BufferLength
plus (Thead - Ttail) is small and (BufferLength - Ttail) is small (*), that
is the buffer is almost full and wraps around the end.
Buffer occupancy:
   X X X X X X * * * X X
               ^     ^
               |     Thead
               Ttail
where X indicates occupied space, * - free space
This situation seems possible according to the code of Packet_tap and
PacketRead.
Then it is quite possible that for the incoming packet
"Ttail+maxbufspace>=Open->BufSize" is true
and "Thead<=maxbufspace" is false
Normally this means that the buffer was not wrapped and we are getting close
to its end,
but under conditions *) it may occur with a wrapped buffer too.
Consequently Ttail will be reset to the beginning of the buffer and the old
data there will be overwritten with new packet:

        !
  Y Y Y x X X * * * X X
        ^           ^
        |           Thead
        Ttail
where Y - new data, X - old data, * - free space
Apparently nothing can guarantee that the bytes stating with small 'x'
contain valid struct bpf_hdr now.

Let's consider PacketRead.
Only the read access to Bhead, Btail and BLastByte is synchronized with
Packet_tap, so it can happen that the two functions get called at about the
same time, retrieve the same values for Bhead, Btail and BLastByte and then
while Packet_tap overwrites the beginning of the buffer, PacketRead sends
the (corrupt) data to the DLL:

                        Ttail   Thead
  PacketRead:           !       !
              Y Y Y x X X * * * X X
  Packet_tap:       ^           ^
                    |           Thead
                    Ttail
Who knows what will happen in the following fragment (PacketRead, lines
204--231) if it is processing invalid data.
   //the buffer must be scannned to determine the number of bytes to copy
   CpStart=Thead;
   while(TRUE){
    if(Thead==Ttail)break;
    if(Thead==TLastByte){
     PacketMoveMem(packp,CurrBuff+CpStart,Thead-CpStart,&(Open->Bhead));
     packp+=(Thead-CpStart);
     Open->Bhead=0;
     Thead=0;
     CpStart=0;
    }
    cplen=((struct bpf_hdr*)(CurrBuff+Thead))->bh_caplen+sizeof(struct
bpf_hdr);

    if((i+cplen > Input_Buffer_Length)){//no more space in the application's
buffer
     PacketMoveMem(packp,CurrBuff+CpStart,Thead-CpStart,&(Open->Bhead));

     Irp->IoStatus.Information = i;
     Irp->IoStatus.Status = STATUS_SUCCESS;
     IoCompleteRequest(Irp, IO_NO_INCREMENT);

     return(STATUS_SUCCESS);
    }
    cplen=Packet_WORDALIGN(cplen);
    i+=cplen;
    Thead+=cplen;
   }

It seems to me that the situation described above can lead to DLL memory
corruption as a result of PacketRead's sending more data than the size of
DLL buffer.
Please note that winpcap sources that I used may not be the latest since
http://netgroup-serv.polito.it/winpcap/ seems to be down today so I could
not update.

------------------------------------------------------

Any thoughts?

Ciao,
Gordon

Sitraka -- the Java advantage
http://www.sitraka.com/

Reply via email to