@@ -178,7 +178,8 @@ static int lookup_path_in_map(const char *path_elem,
178178 const MMDB_s * const mmdb ,
179179 MMDB_entry_data_s * entry_data );
180180static int skip_map_or_array (const MMDB_s * const mmdb ,
181- MMDB_entry_data_s * entry_data );
181+ MMDB_entry_data_s * entry_data ,
182+ int depth );
182183static int decode_one_follow (const MMDB_s * const mmdb ,
183184 uint32_t offset ,
184185 MMDB_entry_data_s * entry_data );
@@ -366,7 +367,7 @@ static LPWSTR utf8_to_utf16(const char *utf8_str) {
366367}
367368
368369static int map_file (MMDB_s * const mmdb ) {
369- DWORD size ;
370+ ssize_t size ;
370371 int status = MMDB_SUCCESS ;
371372 HANDLE mmh = NULL ;
372373 HANDLE fd = INVALID_HANDLE_VALUE ;
@@ -386,12 +387,17 @@ static int map_file(MMDB_s *const mmdb) {
386387 status = MMDB_FILE_OPEN_ERROR ;
387388 goto cleanup ;
388389 }
389- size = GetFileSize (fd , NULL );
390- if (size == INVALID_FILE_SIZE ) {
391- status = MMDB_FILE_OPEN_ERROR ;
390+ LARGE_INTEGER file_size ;
391+ if (!GetFileSizeEx (fd , & file_size )) {
392+ status = MMDB_IO_ERROR ;
393+ goto cleanup ;
394+ }
395+ if (file_size .QuadPart < 0 || file_size .QuadPart > SSIZE_MAX ) {
396+ status = MMDB_IO_ERROR ;
392397 goto cleanup ;
393398 }
394- mmh = CreateFileMapping (fd , NULL , PAGE_READONLY , 0 , size , NULL );
399+ size = (ssize_t )file_size .QuadPart ;
400+ mmh = CreateFileMapping (fd , NULL , PAGE_READONLY , 0 , 0 , NULL );
395401 /* Microsoft documentation for CreateFileMapping indicates this returns
396402 NULL not INVALID_HANDLE_VALUE on error */
397403 if (NULL == mmh ) {
@@ -882,6 +888,11 @@ MMDB_lookup_result_s MMDB_lookup_string(const MMDB_s *const mmdb,
882888
883889 if (!* gai_error ) {
884890 result = MMDB_lookup_sockaddr (mmdb , addresses -> ai_addr , mmdb_error );
891+ } else {
892+ /* No MMDB error occurred; the GAI failure is reported via
893+ * *gai_error. Set *mmdb_error to a defined value so callers
894+ * don't read indeterminate memory. */
895+ * mmdb_error = MMDB_SUCCESS ;
885896 }
886897
887898 if (NULL != addresses ) {
@@ -979,7 +990,7 @@ static int find_address_in_search_tree(const MMDB_s *const mmdb,
979990
980991 result -> netmask = current_bit ;
981992
982- if (value >= node_count + mmdb -> data_section_size ) {
993+ if (value >= ( uint64_t ) node_count + mmdb -> data_section_size ) {
983994 // The pointer points off the end of the database.
984995 return MMDB_CORRUPT_SEARCH_TREE_ERROR ;
985996 }
@@ -1039,7 +1050,8 @@ static int find_ipv4_start_node(MMDB_s *const mmdb) {
10391050 uint32_t node_count = mmdb -> metadata .node_count ;
10401051
10411052 for (netmask = 0 ; netmask < 96 && node_value < node_count ; netmask ++ ) {
1042- record_pointer = & search_tree [node_value * record_info .record_length ];
1053+ record_pointer =
1054+ & search_tree [(uint64_t )node_value * record_info .record_length ];
10431055 if (record_pointer + record_info .record_length > mmdb -> data_section ) {
10441056 return MMDB_CORRUPT_SEARCH_TREE_ERROR ;
10451057 }
@@ -1097,13 +1109,16 @@ int MMDB_read_node(const MMDB_s *const mmdb,
10971109 return MMDB_UNKNOWN_DATABASE_FORMAT_ERROR ;
10981110 }
10991111
1100- if (node_number > mmdb -> metadata .node_count ) {
1112+ if (node_number >= mmdb -> metadata .node_count ) {
11011113 return MMDB_INVALID_NODE_NUMBER_ERROR ;
11021114 }
11031115
11041116 const uint8_t * search_tree = mmdb -> file_content ;
11051117 const uint8_t * record_pointer =
1106- & search_tree [node_number * record_info .record_length ];
1118+ & search_tree [(uint64_t )node_number * record_info .record_length ];
1119+ if (record_pointer + record_info .record_length > mmdb -> data_section ) {
1120+ return MMDB_CORRUPT_SEARCH_TREE_ERROR ;
1121+ }
11071122 node -> left_record = record_info .left_record_getter (record_pointer );
11081123 record_pointer += record_info .right_record_offset ;
11091124 node -> right_record = record_info .right_record_getter (record_pointer );
@@ -1272,7 +1287,7 @@ static int lookup_path_in_array(const char *path_elem,
12721287 /* We don't want to follow a pointer here. If the next element is a
12731288 * pointer we simply skip it and keep going */
12741289 CHECKED_DECODE_ONE (mmdb , entry_data -> offset_to_next , entry_data );
1275- int status = skip_map_or_array (mmdb , entry_data );
1290+ int status = skip_map_or_array (mmdb , entry_data , 0 );
12761291 if (MMDB_SUCCESS != status ) {
12771292 return status ;
12781293 }
@@ -1314,7 +1329,7 @@ static int lookup_path_in_map(const char *path_elem,
13141329 /* We don't want to follow a pointer here. If the next element is
13151330 * a pointer we simply skip it and keep going */
13161331 CHECKED_DECODE_ONE (mmdb , offset_to_value , & value );
1317- int status = skip_map_or_array (mmdb , & value );
1332+ int status = skip_map_or_array (mmdb , & value , 0 );
13181333 if (MMDB_SUCCESS != status ) {
13191334 return status ;
13201335 }
@@ -1327,15 +1342,21 @@ static int lookup_path_in_map(const char *path_elem,
13271342}
13281343
13291344static int skip_map_or_array (const MMDB_s * const mmdb ,
1330- MMDB_entry_data_s * entry_data ) {
1345+ MMDB_entry_data_s * entry_data ,
1346+ int depth ) {
1347+ if (depth >= MAXIMUM_DATA_STRUCTURE_DEPTH ) {
1348+ DEBUG_MSG ("reached the maximum data structure depth" );
1349+ return MMDB_INVALID_DATA_ERROR ;
1350+ }
1351+
13311352 if (entry_data -> type == MMDB_DATA_TYPE_MAP ) {
13321353 uint32_t size = entry_data -> data_size ;
13331354 while (size -- > 0 ) {
13341355 CHECKED_DECODE_ONE (
13351356 mmdb , entry_data -> offset_to_next , entry_data ); // key
13361357 CHECKED_DECODE_ONE (
13371358 mmdb , entry_data -> offset_to_next , entry_data ); // value
1338- int status = skip_map_or_array (mmdb , entry_data );
1359+ int status = skip_map_or_array (mmdb , entry_data , depth + 1 );
13391360 if (MMDB_SUCCESS != status ) {
13401361 return status ;
13411362 }
@@ -1345,7 +1366,7 @@ static int skip_map_or_array(const MMDB_s *const mmdb,
13451366 while (size -- > 0 ) {
13461367 CHECKED_DECODE_ONE (
13471368 mmdb , entry_data -> offset_to_next , entry_data ); // value
1348- int status = skip_map_or_array (mmdb , entry_data );
1369+ int status = skip_map_or_array (mmdb , entry_data , depth + 1 );
13491370 if (MMDB_SUCCESS != status ) {
13501371 return status ;
13511372 }
@@ -1707,6 +1728,12 @@ static int get_entry_data_list(const MMDB_s *const mmdb,
17071728 case MMDB_DATA_TYPE_ARRAY : {
17081729 uint32_t array_size = entry_data_list -> entry_data .data_size ;
17091730 uint32_t array_offset = entry_data_list -> entry_data .offset_to_next ;
1731+ /* Each array element needs at least 1 byte. */
1732+ if (array_offset >= mmdb -> data_section_size ||
1733+ array_size > mmdb -> data_section_size - array_offset ) {
1734+ DEBUG_MSG ("array size exceeds remaining data section" );
1735+ return MMDB_INVALID_DATA_ERROR ;
1736+ }
17101737 while (array_size -- > 0 ) {
17111738 MMDB_entry_data_list_s * entry_data_list_to =
17121739 data_pool_alloc (pool );
@@ -1730,6 +1757,12 @@ static int get_entry_data_list(const MMDB_s *const mmdb,
17301757 uint32_t size = entry_data_list -> entry_data .data_size ;
17311758
17321759 offset = entry_data_list -> entry_data .offset_to_next ;
1760+ /* Each map entry needs at least a key and a value (1 byte each). */
1761+ if (offset >= mmdb -> data_section_size ||
1762+ size > (mmdb -> data_section_size - offset ) / 2 ) {
1763+ DEBUG_MSG ("map size exceeds remaining data section" );
1764+ return MMDB_INVALID_DATA_ERROR ;
1765+ }
17331766 while (size -- > 0 ) {
17341767 MMDB_entry_data_list_s * list_key = data_pool_alloc (pool );
17351768 if (!list_key ) {
@@ -1894,6 +1927,12 @@ static void free_mmdb_struct(MMDB_s *const mmdb) {
18941927 #pragma clang diagnostic pop
18951928 #endif
18961929#endif
1930+ mmdb -> file_content = NULL ;
1931+ mmdb -> file_size = 0 ;
1932+ mmdb -> data_section = NULL ;
1933+ mmdb -> data_section_size = 0 ;
1934+ mmdb -> metadata_section = NULL ;
1935+ mmdb -> metadata_section_size = 0 ;
18971936 }
18981937
18991938 if (NULL != mmdb -> metadata .database_type ) {
@@ -1931,6 +1970,7 @@ static void free_languages_metadata(MMDB_s *mmdb) {
19311970#endif
19321971 }
19331972 FREE_AND_SET_NULL (mmdb -> metadata .languages .names );
1973+ mmdb -> metadata .languages .count = 0 ;
19341974}
19351975
19361976static void free_descriptions_metadata (MMDB_s * mmdb ) {
@@ -1973,6 +2013,7 @@ static void free_descriptions_metadata(MMDB_s *mmdb) {
19732013 }
19742014
19752015 FREE_AND_SET_NULL (mmdb -> metadata .description .descriptions );
2016+ mmdb -> metadata .description .count = 0 ;
19762017}
19772018
19782019const char * MMDB_lib_version (void ) { return PACKAGE_VERSION ; }
@@ -2158,7 +2199,7 @@ dump_entry_data_list(FILE *stream,
21582199
21592200static void print_indentation (FILE * stream , int i ) {
21602201 char buffer [1024 ];
2161- int size = i >= 1024 ? 1023 : i ;
2202+ int size = i < 0 ? 0 : ( i >= 1024 ? 1023 : i ) ;
21622203 memset (buffer , 32 , (size_t )size );
21632204 buffer [size ] = '\0' ;
21642205 fputs (buffer , stream );
0 commit comments