Skip to content

[Bug]: Heap-Use-After-Free and Heap-Buffer-Overflow in BgpLayer::getHeaderLen() #1864

@Rulkallos

Description

@Rulkallos

Summary

pocs.tar.gz
asan_reports.tar.gz

AddressSanitizer detected two critical memory safety issues in BgpLayer.cpp of the PcapPlusPlus project: Heap-use-after-free and Heap-buffer-overflow in BgpLayer::getHeaderLen(). These can both lead to crashes and potential security vulnerabilities.

Root Cause Analysis

Suspected Problematic Code

size_t BgpLayer::getHeaderLen() const
{
    if (m_DataLen < sizeof(bgp_common_header))
        return m_DataLen;

    uint16_t messageLen = be16toh(getBasicHeader()->length);
    if (m_DataLen < messageLen)
        return m_DataLen;

    return (size_t)messageLen;
}

Possible Explanation

  • For use-after-free: The lifecycle of the packet/layer objects and their backing memory is not tightly controlled. After freeing the buffer, the code still tries to access fields via dangling pointers.
  • For buffer-overflow: Insufficient bounds checking when parsing variable-length and potentially malformed BGP messages, especially if the internal length field is corrupted.

Suggested Fix

  • Use-after-free:

    • Ensure that all layer/packet objects referencing a RawPacket are invalidated or detached before the underlying memory is freed or cleared.
    • Consider using smart pointers or explicit memory management to enforce ownership/lifetime guarantees.
  • Buffer-overflow:

    • Always validate that accesses to m_Data and any structure members are within m_DataLen.
    • When reading the length field from the header, ensure the header is fully within the buffer, and that the field's value does not cause out-of-bounds accesses for further parsing.

Platform

  • OS: Ubuntu 22.04.5 LTS
  • Clang version: Ubuntu clang version 16.0.6 (++20231112100510+7cbf1a259152-1~exp1~20231112100554.106)
  • Version commit 0588d88eca769a02e660161f8965ef6152ada90e

Steps to Reproduce

export SRC=/src OUT=/out
mkdir $SRC $OUT

apt-get update && apt-get install -y cmake autoconf flex bison zip
export CC=clang CXX=clang++ CFLAGS='-fsanitize=address -g -O1' CXXFLAGS='-fsanitize=address -g -O1' LDFLAGS="-fuse-ld=lld" LIB_FUZZING_ENGINE='-fsanitize=fuzzer'

git clone --depth=1 https://github.com/seladb/PcapPlusPlus PcapPlusPlus
git clone --depth=1 https://github.com/the-tcpdump-group/tcpdump.git tcpdump
git clone --depth=1 https://github.com/the-tcpdump-group/libpcap.git libpcap

cd $SRC/PcapPlusPlus
$SRC/PcapPlusPlus/Tests/Fuzzers/ossfuzz.sh

$OUT/FuzzTargetNg poc

ASAN report

Use-after-free:

=================================================================
==530017==ERROR: AddressSanitizer: heap-use-after-free on address 0x613000000585 at pc 0x598652937a70 bp 0x7ffeb98a5560 sp 0x7ffeb98a5558
READ of size 2 at 0x613000000585 thread T0
    #0 0x598652937a6f in pcpp::BgpLayer::getHeaderLen() const /src/PcapPlusPlus/Packet++/src/BgpLayer.cpp:21:25
    #1 0x5986529f306c in pcpp::Packet::extendLayer(pcpp::Layer*, int, unsigned long) /src/PcapPlusPlus/Packet++/src/Packet.cpp:621:33
    #2 0x5986529d4823 in pcpp::Layer::extendLayer(int, unsigned long) /src/PcapPlusPlus/Packet++/src/Layer.cpp:85:20
    #3 0x59865293b3c4 in pcpp::BgpOpenMessageLayer::setOptionalParameters(std::vector<pcpp::BgpOpenMessageLayer::optional_parameter, std::allocator<pcpp::BgpOpenMessageLayer::optional_parameter>> const&) /src/PcapPlusPlus/Packet++/src/BgpLayer.cpp:267:15
    #4 0x5986528eb1ad in readParsedPacket(pcpp::Packet, pcpp::Layer*) /src/PcapPlusPlus/Tests/Fuzzers/ReadParsedPacket.h:440:22
    #5 0x5986528e5b50 in LLVMFuzzerTestOneInput /src/PcapPlusPlus/Tests/Fuzzers/FuzzTarget.cpp:66:5
    #6 0x5986527f4e90 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) crtstuff.c
    #7 0x5986527ded6f in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) crtstuff.c
    #8 0x5986527e4826 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) crtstuff.c
    #9 0x59865280dcf2 in main (/out/FuzzTargetNg+0x1a7cf2) (BuildId: 97bfbeafd983e755)
    #10 0x76efe31c8d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #11 0x76efe31c8e3f in __libc_start_main csu/../csu/libc-start.c:392:3
    #12 0x5986527d9c74 in _start (/out/FuzzTargetNg+0x173c74) (BuildId: 97bfbeafd983e755)

0x613000000585 is located 5 bytes inside of 337-byte region [0x613000000580,0x6130000006d1)
freed by thread T0 here:
    #0 0x5986528e2d5d in operator delete[](void*) (/out/FuzzTargetNg+0x27cd5d) (BuildId: 97bfbeafd983e755)
    #1 0x598652a23a08 in pcpp::RawPacket::clear() /src/PcapPlusPlus/Packet++/src/RawPacket.cpp:100:4
    #2 0x598652a23a08 in pcpp::RawPacket::~RawPacket() /src/PcapPlusPlus/Packet++/src/RawPacket.cpp:24:3
    #3 0x5986527f4e90 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) crtstuff.c
    #4 0x5986527ded6f in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) crtstuff.c
    #5 0x5986527e4826 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) crtstuff.c
    #6 0x59865280dcf2 in main (/out/FuzzTargetNg+0x1a7cf2) (BuildId: 97bfbeafd983e755)
    #7 0x76efe31c8d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16

previously allocated by thread T0 here:
    #0 0x5986528e250d in operator new[](unsigned long) (/out/FuzzTargetNg+0x27c50d) (BuildId: 97bfbeafd983e755)
    #1 0x598652a23bc7 in pcpp::RawPacket::copyDataFrom(pcpp::RawPacket const&, bool) /src/PcapPlusPlus/Packet++/src/RawPacket.cpp:60:16
    #2 0x598652a23bc7 in pcpp::RawPacket::RawPacket(pcpp::RawPacket const&) /src/PcapPlusPlus/Packet++/src/RawPacket.cpp:30:3

SUMMARY: AddressSanitizer: heap-use-after-free /src/PcapPlusPlus/Packet++/src/BgpLayer.cpp:21:25 in pcpp::BgpLayer::getHeaderLen() const
Shadow bytes around the buggy address:
  0x613000000300: 00 00 00 00 00 00 00 00 00 00 00 00 00 fa fa fa
  0x613000000380: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x613000000400: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x613000000480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x613000000500: 00 00 01 fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x613000000580:[fd]fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x613000000600: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x613000000680: fd fd fd fd fd fd fd fd fd fd fd fa fa fa fa fa
  0x613000000700: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x613000000780: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x613000000800: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==530017==ABORTING

Buffer-overflow:

=================================================================
==530034==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6170000004d0 at pc 0x64a8cc0b5a70 bp 0x7fff24c584a0 sp 0x7fff24c58498
READ of size 2 at 0x6170000004d0 thread T0
    #0 0x64a8cc0b5a6f in pcpp::BgpLayer::getHeaderLen() const /src/PcapPlusPlus/Packet++/src/BgpLayer.cpp:21:25
    #1 0x64a8cc17256c in pcpp::Packet::shortenLayer(pcpp::Layer*, int, unsigned long) /src/PcapPlusPlus/Packet++/src/Packet.cpp:673:33
    #2 0x64a8cc1535e8 in pcpp::Layer::shortenLayer(int, unsigned long) /src/PcapPlusPlus/Packet++/src/Layer.cpp:114:20
    #3 0x64a8cc0bd645 in pcpp::BgpUpdateMessageLayer::setWithdrawnRoutes(std::vector<pcpp::BgpUpdateMessageLayer::prefix_and_ip, std::allocator<pcpp::BgpUpdateMessageLayer::prefix_and_ip>> const&) /src/PcapPlusPlus/Packet++/src/BgpLayer.cpp:581:15
    #4 0x64a8cc069b62 in readParsedPacket(pcpp::Packet, pcpp::Layer*) /src/PcapPlusPlus/Tests/Fuzzers/ReadParsedPacket.h:451:24
    #5 0x64a8cc063b50 in LLVMFuzzerTestOneInput /src/PcapPlusPlus/Tests/Fuzzers/FuzzTarget.cpp:66:5
    #6 0x64a8cbf72e90 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) crtstuff.c
    #7 0x64a8cbf5cd6f in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) crtstuff.c
    #8 0x64a8cbf62826 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) crtstuff.c
    #9 0x64a8cbf8bcf2 in main (/out/FuzzTargetNg+0x1a7cf2) (BuildId: 97bfbeafd983e755)
    #10 0x7429e2b78d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #11 0x7429e2b78e3f in __libc_start_main csu/../csu/libc-start.c:392:3
    #12 0x64a8cbf57c74 in _start (/out/FuzzTargetNg+0x173c74) (BuildId: 97bfbeafd983e755)

0x6170000004d0 is located 430 bytes after 674-byte region [0x617000000080,0x617000000322)
allocated by thread T0 here:
    #0 0x64a8cc06050d in operator new[](unsigned long) (/out/FuzzTargetNg+0x27c50d) (BuildId: 97bfbeafd983e755)
    #1 0x64a8cc1a2e70 in pcpp::RawPacket::reallocateData(unsigned long) /src/PcapPlusPlus/Packet++/src/RawPacket.cpp:144:24
    #2 0x64a8cc169a22 in pcpp::Packet::reallocateRawData(unsigned long) /src/PcapPlusPlus/Packet++/src/Packet.cpp:202:21
    #3 0x64a8cc170ed3 in pcpp::Packet::extendLayer(pcpp::Layer*, int, unsigned long) /src/PcapPlusPlus/Packet++/src/Packet.cpp
    #4 0x64a8cc152823 in pcpp::Layer::extendLayer(int, unsigned long) /src/PcapPlusPlus/Packet++/src/Layer.cpp:85:20
    #5 0x64a8cc0bd1f7 in pcpp::BgpUpdateMessageLayer::setWithdrawnRoutes(std::vector<pcpp::BgpUpdateMessageLayer::prefix_and_ip, std::allocator<pcpp::BgpUpdateMessageLayer::prefix_and_ip>> const&) /src/PcapPlusPlus/Packet++/src/BgpLayer.cpp:571:15
    #6 0x64a8cc069b62 in readParsedPacket(pcpp::Packet, pcpp::Layer*) /src/PcapPlusPlus/Tests/Fuzzers/ReadParsedPacket.h:451:24
    #7 0x64a8cc063b50 in LLVMFuzzerTestOneInput /src/PcapPlusPlus/Tests/Fuzzers/FuzzTarget.cpp:66:5
    #8 0x64a8cbf72e90 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) crtstuff.c
    #9 0x64a8cbf5cd6f in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) crtstuff.c
    #10 0x64a8cbf62826 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) crtstuff.c
    #11 0x64a8cbf8bcf2 in main (/out/FuzzTargetNg+0x1a7cf2) (BuildId: 97bfbeafd983e755)
    #12 0x7429e2b78d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16

SUMMARY: AddressSanitizer: heap-buffer-overflow /src/PcapPlusPlus/Packet++/src/BgpLayer.cpp:21:25 in pcpp::BgpLayer::getHeaderLen() const
Shadow bytes around the buggy address:
  0x617000000200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x617000000280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x617000000300: 00 00 00 00 02 fa fa fa fa fa fa fa fa fa fa fa
  0x617000000380: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x617000000400: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x617000000480: fa fa fa fa fa fa fa fa fa fa[fa]fa fa fa fa fa
  0x617000000500: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x617000000580: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x617000000600: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x617000000680: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x617000000700: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==530034==ABORTING

PcapPlusPlus versions tested on

PcapPlusPlus master branch

Other PcapPlusPlus version (if applicable)

hash: 0588d88eca769a02e660161f8965ef6152ada90e

Operating systems tested on

Linux

Other operation systems (if applicable)

No response

Compiler version

clang version 16.0.6

Packet capture backend (if applicable)

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions