-
Notifications
You must be signed in to change notification settings - Fork 895
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
Conversation
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 > .&checktime(4800,0,18,':')1: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 > .&checktime(4800,0,18,':')1:fec9:5da8:b2f8:c0a8:1eb: DSTOPT 162 > 54467: [!init SEQ]-2113797630
Is this OK?
With the pcap:
snmp.pcap.txt
(fuzzed file)
print-snmp.c
Outdated
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.
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
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.
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. */
7f180e4
to
28afdbc
Compare
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 > .&checktime(4800,0,18,':')1:fec9:5da8:b2f8:c0a8:1eb: DSTOPT [remaining length 14 < 236] (invalid)
And no SNMP code path.
I will look at that.
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 > .&checktime(4800,0,18,':')1: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 > .&checktime(4800,0,18,':')1:fec9:5da8:b2f8:c0a8:1eb: DSTOPT (unknown opt-type 0x38 len=12) 162 > 54467: [!init SEQ]-2113797630
Is this OK?
New capture file
snmp1.pcap.txt
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.
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.
28afdbc
to
2eb5203
Compare
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