Repository: secdev/scapy

Issue:
struct.error when opening malformed pcap
#### Brief description

Scapy crashes when opening a malformed pcap file.



#### Environment

-   Scapy version: scapy-2.4.4rc2.dev38
-   Python version: 3.8
-   Operating System: Debian

<!-- if needed - further information to get a picture of your setup (e.g. a sketch of your network setup) -->

#### How to reproduce

```python
$ cat test.py 
import sys
import scapy
import scapy.utils

scapy.utils.rdpcap(sys.argv[1])

$ python3 test.py ./clusterfuzz-testcase-minimized-fuzz_scapy-5720462057013248 
Traceback (most recent call last):
  File "test.py", line 5, in <module>
    scapy.utils.rdpcap(sys.argv[1])
  File "/home/user/ven/lib/python3.8/site-packages/scapy/utils.py", line 951, in rdpcap
    return fdesc.read_all(count=count)
  File "/home/user/ven/lib/python3.8/site-packages/scapy/utils.py", line 1343, in read_all
    res = RawPcapNgReader.read_all(self, count)
  File "/home/user/ven/lib/python3.8/site-packages/scapy/utils.py", line 1093, in read_all
    p = self.read_packet()
  File "/home/user/ven/lib/python3.8/site-packages/scapy/utils.py", line 1322, in read_packet
    rp = super(PcapNgReader, self).read_packet(size=size)
  File "/home/user/ven/lib/python3.8/site-packages/scapy/utils.py", line 1239, in read_packet
    res = self.blocktypes.get(blocktype,
  File "/home/user/ven/lib/python3.8/site-packages/scapy/utils.py", line 1269, in read_block_idb
    self.interfaces.append(struct.unpack(self.endian + "HxxI", block[:8]) +
struct.error: unpack requires a buffer of 8 bytes
```

<!-- step-by-step explanation or a short script, may reference section 'Related resources' -->

#### Actual result

```python
Traceback (most recent call last):
  File "test.py", line 5, in <module>
    scapy.utils.rdpcap(sys.argv[1])
  File "/home/user/ven/lib/python3.8/site-packages/scapy/utils.py", line 951, in rdpcap
    return fdesc.read_all(count=count)
  File "/home/user/ven/lib/python3.8/site-packages/scapy/utils.py", line 1343, in read_all
    res = RawPcapNgReader.read_all(self, count)
  File "/home/user/ven/lib/python3.8/site-packages/scapy/utils.py", line 1093, in read_all
    p = self.read_packet()
  File "/home/user/ven/lib/python3.8/site-packages/scapy/utils.py", line 1322, in read_packet
    rp = super(PcapNgReader, self).read_packet(size=size)
  File "/home/user/ven/lib/python3.8/site-packages/scapy/utils.py", line 1239, in read_packet
    res = self.blocktypes.get(blocktype,
  File "/home/user/ven/lib/python3.8/site-packages/scapy/utils.py", line 1269, in read_block_idb
    self.interfaces.append(struct.unpack(self.endian + "HxxI", block[:8]) +
struct.error: unpack requires a buffer of 8 bytes
```
#### Expected result

Not a crash

<!-- describe the expected result and outline the difference to the actual one, could also be a screen shot (e.g. wireshark) -->

#### Related resources

<!-- traces / sample pcaps (stripped to the relevant frames), related standards, RFCs or other resources -->
[clusterfuzz-testcase-minimized-fuzz_scapy-5720462057013248.tar.gz](https://github.com/secdev/scapy/files/5149957/clusterfuzz-testcase-minimized-fuzz_scapy-5720462057013248.tar.gz)



Discussion:

Resolving patch:
diff --git a/scapy/utils.py b/scapy/utils.py
--- a/scapy/utils.py
+++ b/scapy/utils.py
@@ -1234,6 +1234,7 @@ def read_packet(self, size=MTU):
                 if (blocklen,) != struct.unpack(self.endian + 'I',
                                                 self.f.read(4)):
                     warning("PcapNg: Invalid pcapng block (bad blocklen)")
+                    raise EOFError
             except struct.error:
                 raise EOFError
             res = self.blocktypes.get(blocktype,


Test patch:
diff --git a/test/regression.uts b/test/regression.uts
--- a/test/regression.uts
+++ b/test/regression.uts
@@ -7269,6 +7269,12 @@ assert isinstance(pkt, Padding) and pkt.load == b'\xeay$\xf6'
 pkt = pkt.payload
 assert isinstance(pkt, NoPayload)
 
+= Invalid pcapng file
+
+from io import BytesIO
+invalid_pcapngfile = BytesIO(b'\n\r\r\n\r\x00\x00\x00M<+\x1a\xb2<\xb2\xa1\x01\x00\x00\x00\r\x00\x00\x00M<+\x1a\x80\xaa\xb2\x02')
+assert(len(rdpcap(invalid_pcapngfile)) == 0)
+
 = Check PcapWriter on null write
 
 f = BytesIO()