fix integer underflow in handling of Navcom packets (CVE-2025-67269)
Resolves: CVE-2025-67269 RHEL-138260
This commit is contained in:
parent
5bf823ae13
commit
2cadff7d3c
194
gpsd-cve-2025-67269.patch
Normal file
194
gpsd-cve-2025-67269.patch
Normal file
@ -0,0 +1,194 @@
|
||||
commit c46d5119736af455835dd2dca304a8cb651d03b9
|
||||
Author: Gary E. Miller <gem@rellim.com>
|
||||
Date: Wed Dec 3 19:04:03 2025 -0800
|
||||
|
||||
gpsd/packet.c: Fix integer underflow is malicious Navcom packet
|
||||
|
||||
Causes DoS. Fix issue 358
|
||||
|
||||
diff --git a/gpsd/packet.c b/gpsd/packet.c
|
||||
index f9a7db8d0..0c2350072 100644
|
||||
--- a/gpsd/packet.c
|
||||
+++ b/gpsd/packet.c
|
||||
@@ -1141,18 +1141,22 @@ static bool nextstate(struct gps_lexer_t *lexer, unsigned char c)
|
||||
#endif // SIRF_ENABLE || SKYTRAQ_ENABLE
|
||||
#ifdef SIRF_ENABLE
|
||||
case SIRF_LEADER_2:
|
||||
- // first part of length
|
||||
- lexer->length = (size_t) (c << 8);
|
||||
+ // first part of length, MSB
|
||||
+ lexer->length = (c & 0x7f) << 8;
|
||||
+ if (lexer->length > MAX_PACKET_LENGTH) {
|
||||
+ lexer->length = 0;
|
||||
+ return character_pushback(lexer, GROUND_STATE);
|
||||
+ } // else
|
||||
lexer->state = SIRF_LENGTH_1;
|
||||
break;
|
||||
case SIRF_LENGTH_1:
|
||||
// second part of length
|
||||
lexer->length += c + 2;
|
||||
- if (lexer->length <= MAX_PACKET_LENGTH) {
|
||||
- lexer->state = SIRF_PAYLOAD;
|
||||
- } else {
|
||||
+ if (lexer->length > MAX_PACKET_LENGTH) {
|
||||
+ lexer->length = 0;
|
||||
return character_pushback(lexer, GROUND_STATE);
|
||||
- }
|
||||
+ } // else
|
||||
+ lexer->state = SIRF_PAYLOAD;
|
||||
break;
|
||||
case SIRF_PAYLOAD:
|
||||
if (0 == --lexer->length) {
|
||||
@@ -1194,6 +1198,7 @@ static bool nextstate(struct gps_lexer_t *lexer, unsigned char c)
|
||||
return character_pushback(lexer, GROUND_STATE);
|
||||
}
|
||||
if (MAX_PACKET_LENGTH < lexer->length) {
|
||||
+ lexer->length = 0;
|
||||
return character_pushback(lexer, GROUND_STATE);
|
||||
}
|
||||
lexer->state = SKY_PAYLOAD;
|
||||
@@ -1376,14 +1381,29 @@ static bool nextstate(struct gps_lexer_t *lexer, unsigned char c)
|
||||
}
|
||||
break;
|
||||
case NAVCOM_LEADER_3:
|
||||
+ // command ID
|
||||
lexer->state = NAVCOM_ID;
|
||||
break;
|
||||
case NAVCOM_ID:
|
||||
- lexer->length = (size_t)c - 4;
|
||||
+ /* Length LSB
|
||||
+ * Navcom length includes command ID, length bytes. and checksum.
|
||||
+ * So for more than just the payload length.
|
||||
+ * Minimum 4 bytes */
|
||||
+ if (4 > c) {
|
||||
+ return character_pushback(lexer, GROUND_STATE);
|
||||
+ }
|
||||
+ lexer->length = c;
|
||||
lexer->state = NAVCOM_LENGTH_1;
|
||||
break;
|
||||
case NAVCOM_LENGTH_1:
|
||||
+ // Length USB. Navcom allows payload length up to 65,531
|
||||
lexer->length += (c << 8);
|
||||
+ // don't count ID, length and checksum in payload length
|
||||
+ lexer->length -= 4;
|
||||
+ if (MAX_PACKET_LENGTH < lexer->length) {
|
||||
+ lexer->length = 0;
|
||||
+ return character_pushback(lexer, GROUND_STATE);
|
||||
+ } // else
|
||||
lexer->state = NAVCOM_LENGTH_2;
|
||||
break;
|
||||
case NAVCOM_LENGTH_2:
|
||||
@@ -1510,11 +1530,11 @@ static bool nextstate(struct gps_lexer_t *lexer, unsigned char c)
|
||||
lexer->length += 2; // checksum
|
||||
// 10 bytes is the length of the Zodiac header
|
||||
// no idea what Zodiac max length really is
|
||||
- if ((MAX_PACKET_LENGTH - 10) >= lexer->length) {
|
||||
- lexer->state = ZODIAC_PAYLOAD;
|
||||
- } else {
|
||||
+ if ((MAX_PACKET_LENGTH - 10) < lexer->length) {
|
||||
+ lexer->length = 0;
|
||||
return character_pushback(lexer, GROUND_STATE);
|
||||
- }
|
||||
+ } // else
|
||||
+ lexer->state = ZODIAC_PAYLOAD;
|
||||
break;
|
||||
case ZODIAC_PAYLOAD:
|
||||
if (0 == --lexer->length) {
|
||||
@@ -1549,6 +1569,7 @@ static bool nextstate(struct gps_lexer_t *lexer, unsigned char c)
|
||||
lexer->state = UBX_LENGTH_2;
|
||||
} else {
|
||||
// bad length
|
||||
+ lexer->length = 0;
|
||||
return character_pushback(lexer, GROUND_STATE);
|
||||
}
|
||||
break;
|
||||
@@ -1604,6 +1625,7 @@ static bool nextstate(struct gps_lexer_t *lexer, unsigned char c)
|
||||
lexer->length += (c << 8);
|
||||
if (MAX_PACKET_LENGTH <= lexer->length) {
|
||||
// bad length
|
||||
+ lexer->length = 0;
|
||||
return character_pushback(lexer, GROUND_STATE);
|
||||
} // else
|
||||
|
||||
@@ -1841,16 +1863,16 @@ static bool nextstate(struct gps_lexer_t *lexer, unsigned char c)
|
||||
lexer->state = GEOSTAR_MESSAGE_ID_2;
|
||||
break;
|
||||
case GEOSTAR_MESSAGE_ID_2:
|
||||
- lexer->length = (size_t)c * 4;
|
||||
+ lexer->length = c * 4;
|
||||
lexer->state = GEOSTAR_LENGTH_1;
|
||||
break;
|
||||
case GEOSTAR_LENGTH_1:
|
||||
lexer->length += (c << 8) * 4;
|
||||
- if (MAX_PACKET_LENGTH >= lexer->length) {
|
||||
- lexer->state = GEOSTAR_LENGTH_2;
|
||||
- } else {
|
||||
+ if (MAX_PACKET_LENGTH < lexer->length) {
|
||||
+ lexer->length = 0;
|
||||
return character_pushback(lexer, GROUND_STATE);
|
||||
- }
|
||||
+ } // else
|
||||
+ lexer->state = GEOSTAR_LENGTH_2;
|
||||
break;
|
||||
case GEOSTAR_LENGTH_2:
|
||||
lexer->state = GEOSTAR_PAYLOAD;
|
||||
@@ -2160,6 +2182,16 @@ static bool nextstate(struct gps_lexer_t *lexer, unsigned char c)
|
||||
#endif // STASH_ENABLE
|
||||
}
|
||||
|
||||
+ /* Catch length overflow. Should not happen.
|
||||
+ * length is size_t, so underflow looks like overflow too. */
|
||||
+ if (MAX_PACKET_LENGTH <= lexer->length) {
|
||||
+ GPSD_LOG(LOG_WARN, &lexer->errout,
|
||||
+ "Too long: %zu state %u %s c x%x\n",
|
||||
+ lexer->length, lexer->state, state_table[lexer->state], c);
|
||||
+ // exit(255);
|
||||
+ lexer->length = 0;
|
||||
+ return character_pushback(lexer, GROUND_STATE);
|
||||
+ }
|
||||
return true; // no pushback
|
||||
}
|
||||
|
||||
|
||||
commit 90f5558a8dc364bed8e2f3e2e4ecdd84f04dde46
|
||||
Author: Gary E. Miller <gem@rellim.com>
|
||||
Date: Thu Dec 4 13:56:43 2025 -0800
|
||||
|
||||
gpsd/packet.c: Fix a logic hole in previous commit.
|
||||
|
||||
Before your reject 0x103 and well as 0x03. Now only rejects, really,
|
||||
when length less than 4.
|
||||
|
||||
diff --git a/gpsd/packet.c b/gpsd/packet.c
|
||||
index 0c2350072..99109e388 100644
|
||||
--- a/gpsd/packet.c
|
||||
+++ b/gpsd/packet.c
|
||||
@@ -1385,19 +1385,20 @@ static bool nextstate(struct gps_lexer_t *lexer, unsigned char c)
|
||||
lexer->state = NAVCOM_ID;
|
||||
break;
|
||||
case NAVCOM_ID:
|
||||
- /* Length LSB
|
||||
- * Navcom length includes command ID, length bytes. and checksum.
|
||||
- * So for more than just the payload length.
|
||||
- * Minimum 4 bytes */
|
||||
- if (4 > c) {
|
||||
- return character_pushback(lexer, GROUND_STATE);
|
||||
- }
|
||||
+ // Length LSB
|
||||
lexer->length = c;
|
||||
lexer->state = NAVCOM_LENGTH_1;
|
||||
break;
|
||||
case NAVCOM_LENGTH_1:
|
||||
- // Length USB. Navcom allows payload length up to 65,531
|
||||
+ /* Length USB. Navcom allows payload length up to 32767 - 4
|
||||
+ * Navcom length includes command ID, length bytes. and checksum.
|
||||
+ * More than just the payload length.
|
||||
+ * Minimum 4 bytes */
|
||||
lexer->length += (c << 8);
|
||||
+ if (4 >lexer->length ) {
|
||||
+ // too short
|
||||
+ return character_pushback(lexer, GROUND_STATE);
|
||||
+ }
|
||||
// don't count ID, length and checksum in payload length
|
||||
lexer->length -= 4;
|
||||
if (MAX_PACKET_LENGTH < lexer->length) {
|
||||
Loading…
Reference in New Issue
Block a user