Skip to content

Commit 712cd42

Browse files
committed
Reject unsupported sockaddr families
1 parent 47e3a40 commit 712cd42

7 files changed

Lines changed: 79 additions & 3 deletions

File tree

Changes.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## next release
2+
3+
- Fixed an out-of-bounds read in `MMDB_lookup_sockaddr()` when callers passed a
4+
`sockaddr` with an unsupported address family. The function now rejects any
5+
family other than `AF_INET` and `AF_INET6` with
6+
`MMDB_INVALID_NETWORK_ADDRESS_ERROR`.
7+
18
## 1.13.3 - 2026-03-05
29

310
- Fixed validation of empty maps and arrays at the end of the metadata section.

doc/libmaxminddb.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,8 @@ status codes are:
393393
array index larger than an array or smaller than the minimum offset from the
394394
end of an array. It can also happen when the path expects to find a map or
395395
array where none exist.
396+
- `MMDB_INVALID_NETWORK_ADDRESS_ERROR` - `MMDB_lookup_sockaddr()` was given a
397+
`sockaddr` whose family is neither `AF_INET` nor `AF_INET6`.
396398

397399
All status codes should be treated as `int` values.
398400

@@ -518,7 +520,8 @@ MMDB_lookup_result_s MMDB_lookup_sockaddr(
518520
```
519521
520522
This function looks up an IP address that has already been resolved by
521-
`getaddrinfo()`.
523+
`getaddrinfo()`. The `sockaddr` passed to this function must be an `AF_INET` or
524+
`AF_INET6` address.
522525
523526
Other than not calling `getaddrinfo()` itself, this function is identical to the
524527
`MMDB_lookup_string()` function.

include/maxminddb.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ extern "C" {
8686
#define MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR (9)
8787
#define MMDB_INVALID_NODE_NUMBER_ERROR (10)
8888
#define MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR (11)
89+
#define MMDB_INVALID_NETWORK_ADDRESS_ERROR (12)
8990

9091
#if !(MMDB_UINT128_IS_BYTE_ARRAY)
9192
#if MMDB_UINT128_USING_MODE

src/maxminddb.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -926,23 +926,33 @@ MMDB_lookup_result_s MMDB_lookup_sockaddr(const MMDB_s *const mmdb,
926926

927927
uint8_t mapped_address[16];
928928
uint8_t const *address;
929+
// Reject families other than AF_INET/AF_INET6 before casting to
930+
// sockaddr_in/sockaddr_in6, which would otherwise read past the
931+
// truncated struct sockaddr the caller passed in.
929932
if (mmdb->metadata.ip_version == 4) {
930933
if (sockaddr->sa_family == AF_INET6) {
931934
*mmdb_error = MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR;
932935
return result;
933936
}
937+
if (sockaddr->sa_family != AF_INET) {
938+
*mmdb_error = MMDB_INVALID_NETWORK_ADDRESS_ERROR;
939+
return result;
940+
}
934941
address = (uint8_t const *)&((struct sockaddr_in const *)sockaddr)
935942
->sin_addr.s_addr;
936943
} else {
937944
if (sockaddr->sa_family == AF_INET6) {
938945
address = (uint8_t const *)&((struct sockaddr_in6 const *)sockaddr)
939946
->sin6_addr.s6_addr;
940-
} else {
947+
} else if (sockaddr->sa_family == AF_INET) {
941948
address = mapped_address;
942949
memset(mapped_address, 0, 12);
943950
memcpy(mapped_address + 12,
944951
&((struct sockaddr_in const *)sockaddr)->sin_addr.s_addr,
945952
4);
953+
} else {
954+
*mmdb_error = MMDB_INVALID_NETWORK_ADDRESS_ERROR;
955+
return result;
946956
}
947957
}
948958

@@ -2254,6 +2264,9 @@ const char *MMDB_strerror(int error_code) {
22542264
case MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR:
22552265
return "You attempted to look up an IPv6 address in an IPv4-only "
22562266
"database";
2267+
case MMDB_INVALID_NETWORK_ADDRESS_ERROR:
2268+
return "The sockaddr family is unsupported; only AF_INET and "
2269+
"AF_INET6 are accepted";
22572270
default:
22582271
return "Unknown error code";
22592272
}

t/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ if(UNIX) # or if (NOT WIN32)
3232
bad_epoch_t
3333
bad_indent_t
3434
empty_container_metadata_t
35+
invalid_sockaddr_t
3536
max_depth_t
3637
threads_t
3738
)

t/Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ check_PROGRAMS = \
2121
basic_lookup_t data_entry_list_t \
2222
data-pool-t data_types_t double_close_t dump_t empty_container_metadata_t \
2323
gai_error_t get_value_t \
24-
get_value_pointer_bug_t \
24+
get_value_pointer_bug_t invalid_sockaddr_t \
2525
ipv4_start_cache_t ipv6_lookup_in_ipv4_t max_depth_t metadata_t \
2626
metadata_pointers_t no_map_get_value_t overflow_bounds_t read_node_t \
2727
threads_t version_t

t/invalid_sockaddr_t.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#include "maxminddb_test_helper.h"
2+
3+
static void test_invalid_sockaddr_family(const char *filename,
4+
sa_family_t family,
5+
const char *open_msg,
6+
const char *family_msg) {
7+
char *db_file = test_database_path(filename);
8+
MMDB_s *mmdb = open_ok(db_file, MMDB_MODE_MMAP, open_msg);
9+
free(db_file);
10+
11+
if (!mmdb) {
12+
return;
13+
}
14+
15+
struct sockaddr addr = {.sa_family = family};
16+
int mmdb_error = MMDB_SUCCESS;
17+
MMDB_lookup_result_s result =
18+
MMDB_lookup_sockaddr(mmdb, &addr, &mmdb_error);
19+
20+
ok(!result.found_entry, "%s: no entry returned", family_msg);
21+
cmp_ok(result.netmask, "==", 0, "%s: netmask left at zero", family_msg);
22+
cmp_ok(mmdb_error,
23+
"==",
24+
MMDB_INVALID_NETWORK_ADDRESS_ERROR,
25+
"%s: MMDB_lookup_sockaddr rejects unsupported family",
26+
family_msg);
27+
28+
MMDB_close(mmdb);
29+
free(mmdb);
30+
}
31+
32+
int main(void) {
33+
plan(NO_PLAN);
34+
test_invalid_sockaddr_family("MaxMind-DB-test-ipv4-24.mmdb",
35+
AF_UNIX,
36+
"opened IPv4 test database (AF_UNIX)",
37+
"AF_UNIX against IPv4 db");
38+
test_invalid_sockaddr_family("MaxMind-DB-test-ipv4-24.mmdb",
39+
AF_UNSPEC,
40+
"opened IPv4 test database (AF_UNSPEC)",
41+
"AF_UNSPEC against IPv4 db");
42+
test_invalid_sockaddr_family("MaxMind-DB-test-ipv6-24.mmdb",
43+
AF_UNIX,
44+
"opened IPv6 test database (AF_UNIX)",
45+
"AF_UNIX against IPv6 db");
46+
test_invalid_sockaddr_family("MaxMind-DB-test-ipv6-24.mmdb",
47+
AF_UNSPEC,
48+
"opened IPv6 test database (AF_UNSPEC)",
49+
"AF_UNSPEC against IPv6 db");
50+
done_testing();
51+
}

0 commit comments

Comments
 (0)