Skip to content

Fixes for undefined behavior in the snmp decoder #1345

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

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

fenner
Copy link
Contributor

@fenner fenner commented Jul 22, 2025

These changes fix undefined behavior in the snmp decoder when the underlying representation is of a value larger than 32-bits. The decoder fundamentally doesn't support these values, and the original behavior is GIGO. We retain the same GIGO behavior, but avoiding undefined behavior.

Fixes #1054

@fxlb fxlb requested a review from guyharris July 24, 2025 14:01
@fxlb
Copy link
Member

fxlb commented Jul 30, 2025

Before

./tcpdump -c1 -#n -r snmp.pcap                                                                                                                                                                 
make: Nothing to be done for 'all'.
reading from file snmp.pcap, link-type RAW (Raw IP), snapshot length 71
    1  20:43:58.1279491072 (invalid us) IP6 [header+payload length 36473 > length 8192] (invalid) a102:11b:100:1:1:1:177:254b > 4800:0:181:fec9:5da8:b2f8:c0a8:1eb: DSTOPT 162 > 54467:  [!init SEQ]33686018

After

./tcpdump -c1 -#n -r snmp.pcap
make: Nothing to be done for 'all'.
reading from file snmp.pcap, link-type RAW (Raw IP), snapshot length 71
    1  20:43:58.1279491072 (invalid us) IP6 [header+payload length 36473 > length 8192] (invalid) a102:11b:100:1:1:1:177:254b > 4800:0:181:fec9:5da8:b2f8:c0a8:1eb: DSTOPT 162 > 54467:  [!init SEQ]-2113797630

Is this OK?

@fxlb
Copy link
Member

fxlb commented Jul 30, 2025

With the pcap:
snmp.pcap.txt
(fuzzed file)

print-snmp.c Outdated
signbit = 0x80000000;
}
/* We can only store the low 32 bits of the given value. If we've
* shifted the sign bit away, we will restore it below. */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some additional commentary about the method used to store only the low 32 bits (i.e., masking the upper 8 bits away before shifting left by 8 bits), and an indication that this avoids undefined behavior, might be useful

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about

                                /* In order to avoid undefined behavior, we mask off the low
                                 * 24 bits of the data before shifting up by 8 bits.  Either
                                 * way, we lose the top 8 bits, but shifting through the sign
                                 * bit results in undefined data.  If we've shifted the sign
                                 * bit away, we will restore it below. */

@fxlb fxlb force-pushed the fenner-snmp-ubsan-fixes branch from 7f180e4 to 28afdbc Compare July 31, 2025 02:49
@fxlb
Copy link
Member

fxlb commented Jul 31, 2025

Rebased.
And/or a problem in the IPv6 decoding, because with -v, the output is:

    1  20:43:58.1279491072 (invalid us) IP6 [header+payload length 36473 > length 8192] (invalid) (class 0x50, flowlabel 0x1014d, hlim 178, next-header DSTOPT (60), payload length 36433) a102:11b:100:1:1:1:177:254b > 4800:0:181:fec9:5da8:b2f8:c0a8:1eb: DSTOPT  [remaining length 14 < 236] (invalid)

And no SNMP code path.
I will look at that.

@fxlb
Copy link
Member

fxlb commented Jul 31, 2025

With a new test file without "IPv6 problem":
Before

./tcpdump --le -c1 -#nv -r snmp1.pcap                                                                                                                                                      
reading from file snmp1.pcap, link-type RAW (Raw IP), snapshot length 71
    1  caplen 71 len 71 20:43:58.1279491072 (invalid us) IP6 [header+payload length 36473 > length 71] (invalid) (class 0x50, flowlabel 0x1014d, hlim 178, next-header DSTOPT (60), payload length 36433) a102:11b:100:1:1:1:177:254b > 4800:0:181:fec9:5da8:b2f8:c0a8:1eb: DSTOPT (unknown opt-type 0x38 len=12) 162 > 54467:  [!init SEQ]33686018

After

./tcpdump --le -c1 -#nv -r snmp1.pcap
reading from file snmp1.pcap, link-type RAW (Raw IP), snapshot length 71
    1  caplen 71 len 71 20:43:58.1279491072 (invalid us) IP6 [header+payload length 36473 > length 71] (invalid) (class 0x50, flowlabel 0x1014d, hlim 178, next-header DSTOPT (60), payload length 36433) a102:11b:100:1:1:1:177:254b > 4800:0:181:fec9:5da8:b2f8:c0a8:1eb: DSTOPT (unknown opt-type 0x38 len=12) 162 > 54467:  [!init SEQ]-2113797630

Is this OK?

@fxlb
Copy link
Member

fxlb commented Jul 31, 2025

New capture file
snmp1.pcap.txt

@fenner
Copy link
Contributor Author

fenner commented Aug 4, 2025

Is this OK?

It's using the snmp printer because it's UDP port 162 (trap).

The ASN.1 value is an out of bounds negative number. The old behavior shifted the sign bit away; the new behavior retains the sign bit but the number is still not the one represented in the packet.

I think it's OK.

fenner added 2 commits August 5, 2025 09:53
Instead of shifting bits off the top of the 32-bit value,
we mask off the top 8 bits before shifting them away, and
restore the sign bit at the end.  This still results in
a result that is not what was intended, as this code can
not handle values greater than 2^31-1 or smaller than
-2^31, but this new mechanism results in a "more correct"
garbage out, with no undefined behavior.
When decoding an OID, and shifting left by 7, mask off the top
7 bits first. This still results in GIGO, but avoids undefined
behavior on the way there. OIDs with values this large are not
supported by this code.
@fenner fenner force-pushed the fenner-snmp-ubsan-fixes branch from 28afdbc to 2eb5203 Compare August 5, 2025 16:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

UBSan violations in print-pflog.c and print-snmp.c
3 participants