-
Notifications
You must be signed in to change notification settings - Fork 756
Fix out-of-bounds reads in IcmpLayer getters on truncated packets #2240
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -118,12 +118,17 @@ namespace pcpp | |
| uint16_t id; | ||
| /// the echo (ping) request sequence number | ||
| uint16_t sequence; | ||
| /// a timestamp of when the message was sent | ||
| /// a timestamp of when the message was sent. Not part of the RFC 792 echo header, these are the first 8 | ||
| /// bytes of the echo payload, and they are absent from a message shorter than sizeof(icmp_echo_hdr) | ||
| uint64_t timestamp; | ||
| } icmp_echo_hdr; | ||
| #pragma pack(pop) | ||
| static_assert(sizeof(icmp_echo_hdr) == 16, "icmp_echo_hdr size is not 16 bytes"); | ||
|
|
||
| /// The smallest valid ICMP echo request/reply message, i.e. the RFC 792 echo header. Smaller than | ||
| /// sizeof(icmp_echo_hdr), which also covers the first 8 payload bytes | ||
| static const size_t ICMP_ECHO_MIN_LEN = sizeof(icmphdr) + 2 * sizeof(uint16_t); | ||
|
|
||
| /// @struct icmp_echo_request | ||
| /// ICMP echo (ping) request/reply message structure | ||
| typedef struct icmp_echo_request | ||
|
|
@@ -274,12 +279,15 @@ namespace pcpp | |
| { | ||
| /// a pointer to the header data on the packet | ||
| icmp_router_advertisement_hdr* header; | ||
| /// the number of bytes available on the packet from icmp_router_advertisement#header onwards, used to bound | ||
| /// the wire-controlled advertisementCount | ||
| size_t dataLength; | ||
|
|
||
| /// Extract router advertisement at a given index | ||
| /// @param[in] index The index of the router advertisement | ||
| /// @return A pointer to the router advertisement on the packet or null if index is out of range (less than zero | ||
| /// or greater than the number of router advertisement records on this message, determined by advertisementCount | ||
| /// field) | ||
| /// field), or if the record is not fully present in the packet data | ||
| icmp_router_address_structure* getRouterAddress(int index) const; | ||
| }; | ||
|
|
||
|
|
@@ -328,6 +336,18 @@ namespace pcpp | |
| icmp_echo_request m_EchoData; | ||
| mutable icmp_router_advertisement m_RouterAdvData; | ||
|
|
||
| /// Cast the layer data to a fixed-size ICMP message structure, or nullptr if the message is of a different | ||
| /// type or the layer is too short to hold the whole structure (a truncated packet) | ||
| template <typename T> T* castMessageData(IcmpMessageType type) const | ||
| { | ||
| if (!isMessageOfType(type) || m_DataLen < sizeof(T)) | ||
| return nullptr; | ||
|
|
||
| return reinterpret_cast<T*>(m_Data); | ||
| } | ||
|
|
||
| icmp_echo_request* getEchoData(IcmpMessageType echoType); | ||
|
|
||
| bool cleanIcmpLayer(); | ||
|
|
||
| bool setEchoData(IcmpMessageType echoType, uint16_t id, uint16_t sequence, uint64_t timestamp, | ||
|
|
@@ -623,10 +643,19 @@ namespace pcpp | |
|
|
||
| uint8_t type = data[0]; | ||
|
|
||
| // ICMP_ECHO_REQUEST, ICMP_ECHO_REPLY, ICMP_ROUTER_SOL, ICMP_INFO_REQUEST, ICMP_INFO_REPLY | ||
| if (type == 8 || type == 0 || type == 10 || type == 15 || type == 16) | ||
| // ICMP_ROUTER_SOL, which is just the base header | ||
| if (type == 10) | ||
| return true; | ||
|
|
||
| // ICMP_ECHO_REQUEST, ICMP_ECHO_REPLY. An echo message carries a variable-length payload, so only the RFC 792 | ||
| // echo header can be required here | ||
| if (type == 8 || type == 0) | ||
| return dataLen >= ICMP_ECHO_MIN_LEN; | ||
|
|
||
| // ICMP_INFO_REQUEST, ICMP_INFO_REPLY | ||
| if (type == 15 || type == 16) | ||
| return dataLen >= sizeof(icmp_info_request); | ||
|
|
||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I understand correctly, this is the only change that is related to the PR description. The other changes are separate. Maybe we can break this PR to multiple PRs?
|
||
| // ICMP_TIMESTAMP_REQUEST, ICMP_TIMESTAMP_REPLY | ||
| if (type == 13 || type == 14) | ||
| return dataLen >= sizeof(icmp_timestamp_request); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| 86bc7fd77f154090c5725840080045000027b8b10000400100000a000036c00f0f0f0f0f0f0f0f0f0f | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you include the pcap file for this packet? That way it'd be easier to view it in Wireshark |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't know that
timestampisn't part of the RFC. In that case we might need a breaking change here:timestampfrom the struct (that way we no longer needICMP_ECHO_MIN_LEN)icmp_echo_requestthat returns the timestamp if exists:bool hasTimestamp()uint64_t getTimetamp()