mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
Reassem: Reject blocks overflowing 64bit upper
The reassembler logic isn't wrap around safe, so just truncate or reject such blocks. For files specifically, a byte offset in the 2**64 bytes represents 16EiB which is the maximum size supported by BTRFS or NTFS (and probably nothing we'd ever see in practice).
This commit is contained in:
parent
9f8eb682b1
commit
ea80f21e1d
3 changed files with 71 additions and 1 deletions
|
@ -5,8 +5,10 @@
|
||||||
#include "zeek/zeek-config.h"
|
#include "zeek/zeek-config.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
#include "zeek/Desc.h"
|
#include "zeek/Desc.h"
|
||||||
|
#include "zeek/Reporter.h"
|
||||||
|
|
||||||
using std::min;
|
using std::min;
|
||||||
|
|
||||||
|
@ -322,6 +324,17 @@ void Reassembler::CheckOverlap(const DataBlockList& list, uint64_t seq, uint64_t
|
||||||
|
|
||||||
void Reassembler::NewBlock(double t, uint64_t seq, uint64_t len, const u_char* data)
|
void Reassembler::NewBlock(double t, uint64_t seq, uint64_t len, const u_char* data)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// Check for overflows - this should be handled by the caller
|
||||||
|
// and possibly reported as a weird or violation if applicable.
|
||||||
|
if ( std::numeric_limits<uint64_t>::max() - seq < len )
|
||||||
|
{
|
||||||
|
zeek::reporter->InternalWarning("Reassembler::NewBlock() truncating block at seq %" PRIx64
|
||||||
|
" from length %" PRIu64 " to %" PRIu64,
|
||||||
|
seq, len, std::numeric_limits<uint64_t>::max() - seq);
|
||||||
|
len = std::numeric_limits<uint64_t>::max() - seq;
|
||||||
|
}
|
||||||
|
|
||||||
if ( len == 0 )
|
if ( len == 0 )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -371,6 +371,7 @@ void TCP_Reassembler::BlockInserted(DataBlockMap::const_iterator it)
|
||||||
{
|
{
|
||||||
const auto& start_block = it->second;
|
const auto& start_block = it->second;
|
||||||
|
|
||||||
|
assert(start_block.seq < start_block.upper);
|
||||||
if ( start_block.seq > last_reassem_seq || start_block.upper <= last_reassem_seq )
|
if ( start_block.seq > last_reassem_seq || start_block.upper <= last_reassem_seq )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "zeek/file_analysis/FileReassembler.h"
|
#include "zeek/file_analysis/FileReassembler.h"
|
||||||
|
|
||||||
|
#include "zeek/3rdparty/doctest.h"
|
||||||
#include "zeek/file_analysis/File.h"
|
#include "zeek/file_analysis/File.h"
|
||||||
|
|
||||||
namespace zeek::file_analysis
|
namespace zeek::file_analysis
|
||||||
|
@ -46,7 +47,7 @@ uint64_t FileReassembler::FlushTo(uint64_t sequence)
|
||||||
void FileReassembler::BlockInserted(DataBlockMap::const_iterator it)
|
void FileReassembler::BlockInserted(DataBlockMap::const_iterator it)
|
||||||
{
|
{
|
||||||
const auto& start_block = it->second;
|
const auto& start_block = it->second;
|
||||||
|
assert(start_block.seq < start_block.upper);
|
||||||
if ( start_block.seq > last_reassem_seq || start_block.upper <= last_reassem_seq )
|
if ( start_block.seq > last_reassem_seq || start_block.upper <= last_reassem_seq )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -113,3 +114,58 @@ void FileReassembler::Overlap(const u_char* b1, const u_char* b2, uint64_t n)
|
||||||
// Not doing anything here yet.
|
// Not doing anything here yet.
|
||||||
}
|
}
|
||||||
} // end file_analysis
|
} // end file_analysis
|
||||||
|
|
||||||
|
// Test reassembler logic through FileReassembler.
|
||||||
|
TEST_CASE("file reassembler")
|
||||||
|
{
|
||||||
|
// Can not construct due to protected constructor.
|
||||||
|
class TestFile : public zeek::file_analysis::File
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TestFile(const std::string& file_id, const std::string& source_name)
|
||||||
|
: zeek::file_analysis::File(file_id, source_name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto f = std::make_unique<TestFile>("test_file_id", "test_source_name");
|
||||||
|
auto r = std::make_unique<zeek::file_analysis::FileReassembler>(f.get(), 0);
|
||||||
|
|
||||||
|
const u_char* data = (u_char*)("0123456789ABCDEF");
|
||||||
|
|
||||||
|
SUBCASE("block overlap and 64bit overflow")
|
||||||
|
{
|
||||||
|
r->NewBlock(0.0, 0xfffffffffffffff7, 3, data);
|
||||||
|
r->NewBlock(0.0, 0xfffffffffffffff7, 15, data);
|
||||||
|
r->NewBlock(0.0, 0xfffffffffffffff3, 15, data);
|
||||||
|
|
||||||
|
// 0xfffffffffffffff3 through 0xffffffffffffffff
|
||||||
|
CHECK_EQ(r->TotalSize(), 12);
|
||||||
|
|
||||||
|
// This previously hung with an endless loop.
|
||||||
|
r->Flush();
|
||||||
|
CHECK_FALSE(r->HasBlocks());
|
||||||
|
CHECK_EQ(r->TotalSize(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
SUBCASE("reject NewBlock() at 64 bit limit")
|
||||||
|
{
|
||||||
|
r->NewBlock(0.0, 0xffffffffffffffff, 4, data);
|
||||||
|
CHECK_FALSE(r->HasBlocks());
|
||||||
|
CHECK_EQ(r->TotalSize(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
SUBCASE("truncate NewBlock() to upper 64 bit limit")
|
||||||
|
{
|
||||||
|
r->NewBlock(0.0, 0xfffffffffffffffa, 8, data);
|
||||||
|
CHECK(r->HasBlocks());
|
||||||
|
CHECK_EQ(r->TotalSize(), 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
SUBCASE("no truncation")
|
||||||
|
{
|
||||||
|
r->NewBlock(0.0, 0xfffffffffffffff7, 8, data);
|
||||||
|
CHECK(r->HasBlocks());
|
||||||
|
CHECK_EQ(r->TotalSize(), 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue