-
Notifications
You must be signed in to change notification settings - Fork 60
Description
Bug report
Issue details
The GNSSTk library’s FileHandling module contains a heap buffer overflow vulnerability involving an out-of-bounds read when parsing RINEX observation files with incomplete satellite observation count records. This flaw arises during the conversion from RINEX version 2 to version 3, where the code expects observation counts matching the declared observation types. Missing auxiliary lines in the RINEX v2 header cause the vector holding observation counts for a satellite to be shorter than expected. The unchecked access to this vector index leads to an out-of-bounds read resulting in heap memory corruption. An attacker can exploit this to cause Denial of Service (DoS) or potentially arbitrary code execution (RCE).
Steps to reproduce
For demonstration purposes, the minimal test program Rinex3Header_read.cpp was used to perform simple reading of a RINEX v3 file, parsing its header and printing it out to the terminal.
#include "Rinex3ObsHeader.hpp"
#include "Rinex3ObsStream.hpp"
using namespace std;
using namespace gnsstk;
int main(int argc, char *argv[])
{
// Initialize RINEX stream from a file
Rinex3ObsStream roffs(argv[1]);
// Initialize RINEX header
Rinex3ObsHeader roh;
// Read RINEX header
roffs >> roh;
// Print RINEX header
roh.dump(cout);
return 0;
} The issue is triggered when a specially crafted RINEX v2 observation file with a malformed header provided as input. File defines 10 observation types, which for format compatibility requires additional auxiliary lines are per PRN (as for satellite G07 below). The issue arises when record simply misses the auxiliary line, specifing less observations that expected (like for G09).
2.10 OBSERVATION DATA M (MIXED) RINEX VERSION / TYPE
gLAB gAGE 17-MAR-10 12:14 PGM / RUN BY / DATE
MRKR MARKER NAME
gAGE UPC: Technical University of Catalonia OBSERVER / AGENCY
IR2200716006 ASHTECH UZ-12 CQ00 REC # / TYPE / VERS
482 AOAD/M_T NONE ANT # / TYPE
4789028.4701 176610.0133 4195017.0310 APPROX POSITION XYZ
0.9030 0.0000 0.0000 ANTENNA: DELTA H/E/N
10 L1 L2 P1 P2 C1 S1 S2 D1 D2# / TYPES OF OBSERV
C2 # / TYPES OF OBSERV
2010 3 5 0 0 0.0000000 GPS TIME OF FIRST OBS
G07 815 815 815 815 815 815 815 815 815PRN / # OF OBS
815 PRN / # OF OBS
G09 246 246 246 246 246 246 246 246 246PRN / # OF OBS
END OF HEADER
Running the test program using a crafted file as input resulted in heap-buffer overflow detected by AddressSanitizer, caused by out-of-band read, that occurred in reallyGetRecord function, responsible for parsing the header.
Root cause analysis
The root cause lies in insufficient validation of the vector size when accessing the satellite observation counts during header parsing and conversion. The vector holding counts (it->second) for each PRN is expected to have a length equal to the number of declared observation types (R2ObsTypes.size()). However, if the RINEX v2 input omits required auxiliary observation count lines for a satellite, this vector becomes shorter than expected. In reallyGetRecord (Rinex3ObsHeader.cpp), the code iterates over R2ObsTypes and performs vec.push_back operation without bounds checking on iterator i relative to it->second.size(). This unchecked access results in reading beyond the allocated buffer for it->second vector, triggering memory corruption.
Debugging the program state a single instruction step before overflow occurrence, shows that heap memory address of it->second[9] exactly matches the 4-byte region pointed by AddressSanitizer.
The presented scenario does not produce a segmentation fault despite unsafe memory access because reading only 4 bytes past a small vector often lands in valid heap memory, causing silent corruption rather than immediate crash. ASAN's instrumentation detects this by maintaining shadow memory that tracks valid/invalid byte ranges. Nevertheless, this remains a serious issue as such silent heap overflows can corrupt adjacent data or heap management structures, destabilizing the program.