diff --git a/scapy/utils.py b/scapy/utils.py index 33933c83bec..c6624c87660 100644 --- a/scapy/utils.py +++ b/scapy/utils.py @@ -1603,9 +1603,14 @@ def _read_block(self, size=MTU): warning("PcapNg: Error reading blocklen before block body") raise EOFError if blocklen < 12: - warning("Invalid block length !") + warning("PcapNg: Invalid block length !") raise EOFError - block = self.f.read(blocklen - 12) + + _block_body_length = blocklen - 12 + block = self.f.read(_block_body_length) + if len(block) != _block_body_length: + raise Scapy_Exception("PcapNg: Invalid Block body length " + "(too short)") self._read_block_tail(blocklen) if blocktype in self.blocktypes: return self.blocktypes[blocktype](block, size) @@ -1635,25 +1640,41 @@ def _read_block_shb(self): elif endian == b"\x4d\x3c\x2b\x1a": self.endian = "<" else: - warning("Bad magic in Section Header block (not a pcapng file?)") + warning("PcapNg: Bad magic in Section Header Block" + " (not a pcapng file?)") raise EOFError - blocklen = struct.unpack(self.endian + "I", _blocklen)[0] + try: + blocklen = struct.unpack(self.endian + "I", _blocklen)[0] + except struct.error: + warning("PcapNg: Could not read blocklen") + raise EOFError if blocklen < 28: - warning(f"Invalid SHB block length ({blocklen})!") + warning(f"PcapNg: Invalid Section Header Block length ({blocklen})!") # noqa: E501 raise EOFError # Major version must be 1 _major = self.f.read(2) - major = struct.unpack(self.endian + "H", _major)[0] + try: + major = struct.unpack(self.endian + "H", _major)[0] + except struct.error: + warning("PcapNg: Could not read major value") + raise EOFError if major != 1: - warning(f"SHB Major version {major} unsupported !") + warning(f"PcapNg: SHB Major version {major} unsupported !") raise EOFError # Skip minor version & section length - self.f.read(10) + skipped = self.f.read(10) + if len(skipped) != 10: + warning("PcapNg: Could not read minor value & section length") + raise EOFError - options = self.f.read(blocklen - 28) + _options_len = blocklen - 28 + options = self.f.read(_options_len) + if len(options) != _options_len: + raise Scapy_Exception("PcapNg: Invalid Section Header Block " + " options (too short)") self._read_block_tail(blocklen) self._read_options(options) @@ -1673,7 +1694,12 @@ def _read_options(self, options): # type: (bytes) -> Dict[int, bytes] opts = dict() while len(options) >= 4: - code, length = struct.unpack(self.endian + "HH", options[:4]) + try: + code, length = struct.unpack(self.endian + "HH", options[:4]) + except struct.error: + warning("PcapNg: options header is too small " + "%d !" % len(options)) + raise EOFError if code != 0 and 4 + length < len(options): opts[code] = options[4:4 + length] if code == 0: @@ -1910,7 +1936,7 @@ def read_packet(self, size=MTU, **kwargs): p.comment = comment p.direction = direction if ifname is not None: - p.sniffed_on = ifname.decode('utf-8') + p.sniffed_on = ifname.decode('utf-8', 'backslashreplace') return p def recv(self, size: int = MTU, **kwargs: Any) -> 'Packet': # type: ignore diff --git a/test/regression.uts b/test/regression.uts index 189f3f60de8..868409a32ee 100644 --- a/test/regression.uts +++ b/test/regression.uts @@ -2252,6 +2252,19 @@ for i in range(len(plist)): assert type(plist_check[i]) == type(plist[0]) assert bytes(plist_check[i]) == bytes(plist[i]) += OSS-Fuzz Findings + +from io import BytesIO +# Issue 68352 +file = BytesIO(b"\n\r\r\n\x1c\x00\x00\x00M<+\x1a\x01\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x1c\x00\x00\x00\x01\x00\x00\x00\x14\x00\x00\x00\xe4\x00\x00\x00\x00\x00\x04\x00\x14\x00\x00\x00\x01\x00\x00\x00(\x00\x00\x00\xe4\x00\x00\x00\x00\x00\x04\x00\x02\x00\t\x00b'ens16\xb0'\x00\x00\x00\x00\x00\x00\x00(\x00\x00\x00\x06\x00\x00\x004\x00\x00\x00\x01\x00\x00\x00}\x17\x06\x00\xb5t\x1d\x85\x14\x00\x00\x00\x14\x00\x00\x00E\x00\x00\x14\x00\x01\x00\x00@\x00|\xe7\x7f\x00\x00\x01\x7f\x00\x00\x014\x00\x00\x00") +rdpcap(file) +# Issue 68354 +file = BytesIO(b'\n\r\r\n\xff\xfe\xfe\xffM<+\x1a') +try: + rdpcap(file) +except Scapy_Exception: + pass + = Read a pcap file with wirelen != captured len pktpcapwirelen = rdpcap(pcapwirelenfile)