From c0ed640a755884bd62fd09d21b72f18825539353 Mon Sep 17 00:00:00 2001 From: "Gary E. Miller" Date: Tue, 2 Dec 2025 19:36:04 -0800 Subject: [PATCH] drivers/driver_nmea2000.c: Fix issue 356, skyview buffer overrun. CVE: CVE-2025-67268 Upstream-Status: Backport [https://gitlab.com/gpsd/gpsd/-/commit/dc966aa74c075d0a6535811d98628625cbfbe3f4?view=inline] Signed-off-by: Ankur Tyagi --- drivers/driver_nmea2000.c | 77 ++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 29 deletions(-) diff --git a/drivers/driver_nmea2000.c b/drivers/driver_nmea2000.c index 66959f02d..a3b89a082 100644 --- a/drivers/driver_nmea2000.c +++ b/drivers/driver_nmea2000.c @@ -12,11 +12,11 @@ * Message contents can be had from canboat/analyzer: * analyzer -explain * - * This file is Copyright 2012 by the GPSD project + * This file is Copyright by the GPSD project * SPDX-License-Identifier: BSD-2-clause */ -#include "../include/gpsd_config.h" /* must be before all includes */ +#include "../include/gpsd_config.h" // must be before all includes #if defined(NMEA2000_ENABLE) @@ -68,7 +68,7 @@ typedef struct PGN #if LOG_FILE FILE *logFile = NULL; -#endif /* of if LOG_FILE */ +#endif // of if LOG_FILE extern bool __attribute__ ((weak)) gpsd_add_device(const char *device_name, bool flag_nowait); @@ -89,12 +89,12 @@ static int scale_int(int32_t var, const int64_t factor) static void print_data(struct gps_context_t *context, unsigned char *buffer, int len, PGN *pgn) { - if ((libgps_debuglevel >= LOG_IO) != 0) { - int l1, l2, ptr; + if (LOG_IO <= libgps_debuglevel) { + int l1; char bu[128]; - ptr = 0; - l2 = sprintf(&bu[ptr], "got data:%6u:%3d: ", pgn->pgn, len); + int ptr = 0; + int l2 = sprintf(&bu[ptr], "got data:%6u:%3d: ", pgn->pgn, len); ptr += l2; for (l1=0;l1context, bu, len, pgn); - /* FIXME? Get magnetic variation */ + // FIXME? Get magnetic variation GPSD_LOG(LOG_DATA, &session->context->errout, "pgn %6d(%3d):\n", pgn->pgn, session->driver.nmea2000.unit); return(0); @@ -358,7 +358,7 @@ static gps_mask_t hnd_126992(unsigned char *bu, int len, PGN *pgn, { // uint8_t sid; // uint8_t source; - uint64_t usecs; /* time in us */ + uint64_t usecs; // time in us print_data(session->context, bu, len, pgn); GPSD_LOG(LOG_DATA, &session->context->errout, @@ -434,6 +434,7 @@ static gps_mask_t hnd_129540(unsigned char *bu, int len, PGN *pgn, struct gps_device_t *session) { int l1; + int expected_len; print_data(session->context, bu, len, pgn); GPSD_LOG(LOG_DATA, &session->context->errout, @@ -441,24 +442,39 @@ static gps_mask_t hnd_129540(unsigned char *bu, int len, PGN *pgn, session->driver.nmea2000.sid[2] = bu[0]; session->gpsdata.satellites_visible = (int)bu[2]; + if (MAXCHANNELS <= session->gpsdata.satellites_visible) { + // Handle a CVE for overrunning skyview[] + GPSD_LOG(LOG_WARN, &session->context->errout, + "pgn %6d(%3d): Too many sats %d\n", + pgn->pgn, session->driver.nmea2000.unit, + session->gpsdata.satellites_visible); + session->gpsdata.satellites_visible = MAXCHANNELS; + } + expected_len = 3 + (12 * session->gpsdata.satellites_visible); + if (len != expected_len) { + GPSD_LOG(LOG_WARN, &session->context->errout, + "pgn %6d(%3d): wrong length %d s/b %d\n", + pgn->pgn, session->driver.nmea2000.unit, + len, expected_len); + return 0; + } memset(session->gpsdata.skyview, '\0', sizeof(session->gpsdata.skyview)); for (l1=0;l1gpsdata.satellites_visible;l1++) { - int svt; - double azi, elev, snr; - - elev = getles16(bu, 3+12*l1+1) * 1e-4 * RAD_2_DEG; - azi = getleu16(bu, 3+12*l1+3) * 1e-4 * RAD_2_DEG; - snr = getles16(bu, 3+12*l1+5) * 1e-2; + int offset = 3 + (12 * l1); + double elev = getles16(bu, offset + 1) * 1e-4 * RAD_2_DEG; + double azi = getleu16(bu, offset + 3) * 1e-4 * RAD_2_DEG; + double snr = getles16(bu, offset + 5) * 1e-2; - svt = (int)(bu[3+12*l1+11] & 0x0f); + int svt = (int)(bu[offset + 11] & 0x0f); - session->gpsdata.skyview[l1].elevation = (short) (round(elev)); - session->gpsdata.skyview[l1].azimuth = (short) (round(azi)); + session->gpsdata.skyview[l1].elevation = elev; + session->gpsdata.skyview[l1].azimuth = azi; session->gpsdata.skyview[l1].ss = snr; - session->gpsdata.skyview[l1].PRN = (short)bu[3+12*l1+0]; + session->gpsdata.skyview[l1].PRN = (int16_t)bu[offset]; session->gpsdata.skyview[l1].used = false; - if ((svt == 2) || (svt == 5)) { + if ((2 == svt) || + (5 == svt)) { session->gpsdata.skyview[l1].used = true; } } @@ -588,7 +604,7 @@ static gps_mask_t hnd_129029(unsigned char *bu, int len, PGN *pgn, struct gps_device_t *session) { gps_mask_t mask; - uint64_t usecs; /* time in us */ + uint64_t usecs; // time in us print_data(session->context, bu, len, pgn); GPSD_LOG(LOG_DATA, &session->context->errout, @@ -675,7 +691,7 @@ static gps_mask_t hnd_129038(unsigned char *bu, int len, PGN *pgn, (unsigned int)ais_direction((unsigned int)getleu16(bu, 21), 1.0); ais->type1.turn = ais_turn_rate((int)getles16(bu, 23)); ais->type1.status = (unsigned int) ((bu[25] >> 0) & 0x0f); - ais->type1.maneuver = 0; /* Not transmitted ???? */ + ais->type1.maneuver = 0; // Not transmitted ???? decode_ais_channel_info(bu, len, 163, session); return(ONLINE_SET | AIS_SET); @@ -730,8 +746,9 @@ static gps_mask_t hnd_129039(unsigned char *bu, int len, PGN *pgn, /* * PGN 129040: AIS Class B Extended Position Report + * + * No test case for this message at the moment */ -/* No test case for this message at the moment */ static gps_mask_t hnd_129040(unsigned char *bu, int len, PGN *pgn, struct gps_device_t *session) { @@ -978,7 +995,7 @@ static gps_mask_t hnd_129794(unsigned char *bu, int len, PGN *pgn, date2.tm_year+1900, ais->type5.hour, ais->type5.minute); -#endif /* of #if NMEA2000_DEBUG_AIS */ +#endif // end of #if NMEA2000_DEBUG_AIS decode_ais_channel_info(bu, len, 592, session); return(ONLINE_SET | AIS_SET); } @@ -988,8 +1005,9 @@ static gps_mask_t hnd_129794(unsigned char *bu, int len, PGN *pgn, /* * PGN 129798: AIS SAR Aircraft Position Report + * + * No test case for this message at the moment */ -/* No test case for this message at the moment */ static gps_mask_t hnd_129798(unsigned char *bu, int len, PGN *pgn, struct gps_device_t *session) { @@ -1016,8 +1034,8 @@ static gps_mask_t hnd_129798(unsigned char *bu, int len, PGN *pgn, ais->type9.alt = (unsigned int) (getleu64(bu, 21)/1000000); ais->type9.regional = (unsigned int) ((bu[29] >> 0) & 0xff); ais->type9.dte = (unsigned int) ((bu[30] >> 0) & 0x01); -/* ais->type9.spare = (bu[30] >> 1) & 0x7f; */ - ais->type9.assigned = 0; /* Not transmitted ???? */ +// ais->type9.spare = (bu[30] >> 1) & 0x7f; + ais->type9.assigned = 0; // Not transmitted ???? decode_ais_channel_info(bu, len, 163, session); return(ONLINE_SET | AIS_SET); @@ -1028,8 +1046,9 @@ static gps_mask_t hnd_129798(unsigned char *bu, int len, PGN *pgn, /* * PGN 129802: AIS Safety Related Broadcast Message + * + * No test case for this message at the moment */ -/* No test case for this message at the moment */ static gps_mask_t hnd_129802(unsigned char *bu, int len, PGN *pgn, struct gps_device_t *session) { @@ -1043,7 +1062,7 @@ static gps_mask_t hnd_129802(unsigned char *bu, int len, PGN *pgn, if (decode_ais_header(session->context, bu, len, ais, 0x3fffffff) != 0) { int l; -/* ais->type14.channel = (bu[ 5] >> 0) & 0x1f; */ +// ais->type14.channel = (bu[ 5] >> 0) & 0x1f; for (l=0;l<36;l++) { ais->type14.text[l] = (char) bu[6+l]; }