Skip to content

Commit c5b54bf

Browse files
fennerfxlb
authored andcommitted
ISO: avoid undefined behavior and integer overflow in the fletcher checksum calculation
The fletcher checksum calculation would sometimes left-shift a negative number, which is an undefined operation. Rework the code to avoid this. checksum.c:186:20: runtime error: left shift of negative value -36 SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior checksum.c:186:20 Unlike some checksum routines that use the defined semantics of 2's-complement unsigned overflow to their advantage, this one gets the wrong value if it is allowed to overflow, due to the use of mod-255. Convert c1 to uint64_t to avoid overflow. checksum.c:163:16: runtime error: unsigned integer overflow: NNN + NNN cannot be represented in type 'unsigned int' Use integers during subtraction to avoid implicit conversion to unsigned when calculating both x and y checksum.c:172:18: runtime error: unsigned integer overflow: NNN - NNN cannot be represented in type 'unsigned int' checksum.c:172:9: runtime error: implicit conversion from type 'unsigned int' of value NNN (32-bit, unsigned) to type 'int' changed the value to -NNN (32-bit, signed) checksum.c:173:12: runtime error: unsigned integer overflow: NNN - NNN cannot be represented in type 'unsigned int' checksum.c:173:9: runtime error: implicit conversion from type 'unsigned int' of value NNN (32-bit, unsigned) to type 'int' changed the value to -NNN (32-bit, signed)
1 parent 431bdb5 commit c5b54bf

File tree

4 files changed

+55
-11
lines changed

4 files changed

+55
-11
lines changed

checksum.c

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,9 @@ create_osi_cksum (const uint8_t *pptr, int checksum_offset, int length)
106106

107107
int x;
108108
int y;
109-
uint32_t mul;
109+
int32_t mul;
110110
uint32_t c0;
111-
uint32_t c1;
111+
uint64_t c1;
112112
uint16_t checksum;
113113
int idx;
114114

@@ -134,21 +134,23 @@ create_osi_cksum (const uint8_t *pptr, int checksum_offset, int length)
134134

135135
mul = (length - checksum_offset)*(c0);
136136

137-
x = mul - c0 - c1;
138-
y = c1 - mul - 1;
139-
140-
if ( y >= 0 ) y++;
141-
if ( x < 0 ) x--;
137+
/*
138+
* Casting c0 and c1 here is guaranteed to be safe, because we know
139+
* they have values between 0 and 254 inclusive. These casts are
140+
* done to ensure that all of the arithmetic operations are
141+
* well-defined (i.e., not mixing signed and unsigned integers).
142+
*/
143+
x = mul - (int)c0 - (int)c1;
144+
y = (int)c1 - mul;
142145

143146
x %= 255;
144147
y %= 255;
145148

146-
147-
if (x == 0) x = 255;
148-
if (y == 0) y = 255;
149+
if (x <= 0) x += 255;
150+
if (y <= 0) y += 255;
149151

150152
y &= 0x00FF;
151-
checksum = ((x << 8) | y);
153+
checksum = (uint16_t)((x << 8) | y);
152154

153155
return checksum;
154156
}

tests/TESTLIST

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,6 +1000,7 @@ ip6-snmp-oid-unsigned ip6-snmp-oid-unsigned.pcap ip6-snmp-oid-unsigned.out
10001000
lwres-pointer-arithmetic-ub lwres-pointer-arithmetic-ub.pcap lwres-pointer-arithmetic-ub.out
10011001
ospf-signed-integer-ubsan ospf-signed-integer-ubsan.pcap ospf-signed-integer-ubsan.out -vv
10021002
bgp-ub bgp-ub.pcap bgp-ub.out -v
1003+
fletcher-checksum-negative-shift fletcher-checksum-negative-shift.pcap fletcher-checksum-negative-shift.out -v
10031004

10041005
# AccECN tests
10051006
accecn_handshake accecn_handshake.pcap accecn_handshake.out -v
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
1 2022-03-20 13:44:56.520846 IS-IS, length 495
2+
L2 LSP, hlen: 27, v: 1, pdu-v: 1, sys-id-len: 6 (0), max-area: 3 (0)
3+
lsp-id: 0192.0168.0001.00-00, seq: 0x0000000b, lifetime: 1196s
4+
chksum: 0xc074 (incorrect should be 0xdc23), PDU length: 495, Flags: [ L2 IS ]
5+
Area address(es) TLV #1, length: 4
6+
Area address (length: 3): 49.0002
7+
LSP Buffersize TLV #14, length: 2
8+
LSP Buffersize: 1426
9+
Area address(es) TLV #1, length: 104
10+
Area address (length: 0): isonsap_string: illegal length
11+
Area address (length: 1): 00
12+
Area address (length: 0): isonsap_string: illegal length
13+
Area address (length: 0): isonsap_string: illegal length
14+
Area address (length: 0): isonsap_string: illegal length
15+
Area address (length: 0): isonsap_string: illegal length
16+
Area address (length: 11): c0.7403.0104.0349.0002.0e02
17+
Area address (length: 5): d4.8102.cc8e
18+
Partition DIS TLV #4, length: 8
19+
0000.0180.0000
20+
unknown TLV #11, length: 32
21+
0x0000: 4cee 6b28 4cee 6b28 4cee 6b28 4cee 6b28
22+
0x0010: 4cee 6b28 4cee 6b28 4cee 6b28 4cee 6b28
23+
Authentication TLV #10, length: 4
24+
unknown Authentication type 0x4c:
25+
0x0000: ee6b 28
26+
LSP entries TLV #9, length: 4
27+
ES Neighbor(s) TLV #3, length: 4
28+
unknown TLV #32, length: 11
29+
0x0000: 3000 0192 0168 0002 0000 12
30+
Area address(es) TLV #1, length: 146
31+
Area address (length: 1): 68
32+
Area address (length: 0): isonsap_string: illegal length
33+
Area address (length: 3): 02.0000
34+
Area address (length: 63): isonsap_string: illegal length
35+
Area address (length: 3): 04.0000
36+
Area address (length: 0): isonsap_string: illegal length
37+
Area address (length: 0): isonsap_string: illegal length
38+
Area address (length: 32): isonsap_string: illegal length
39+
Area address (length: 8): 00.0001.8300.0000.00
40+
Area address (length: 11): 20.4cee.6b28.4cee.6b28.4cee
41+
unknown TLV #76, length: 238 [|isis]
558 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)