From 6bfde9b4291ed1605c75fe961c040bec48d7dd46 Mon Sep 17 00:00:00 2001 From: Iliia Khaprov Date: Tue, 20 Oct 2026 11:57:20 +0200 Subject: [PATCH] Reject IPv4 prefix lengths that overflow int The IPv4 parsers accumulate the prefix length in an int and check "bits > 32" only after the last digit, so a long enough number wraps and passes the check: '192.168.0.0/4294967320'::inet is accepted as 192.168.0.0/24, and '10.0.0.0/4294967304'::cidr as 10.0.0.0/8. Check the range inside the digit loop, as getbits() does for IPv6. --- src/backend/utils/adt/inet_net_pton.c | 8 ++++---- src/test/regress/expected/inet.out | 13 +++++++++++++ src/test/regress/sql/inet.sql | 3 +++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/backend/utils/adt/inet_net_pton.c b/src/backend/utils/adt/inet_net_pton.c index 3b0db2a3799..0b8a007c921 100644 --- a/src/backend/utils/adt/inet_net_pton.c +++ b/src/backend/utils/adt/inet_net_pton.c @@ -180,11 +180,11 @@ inet_cidr_pton_ipv4(const char *src, u_char *dst, size_t size) assert(n >= 0 && n <= 9); bits *= 10; bits += n; + if (bits > 32) + goto emsgsize; } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch)); if (ch != '\0') goto enoent; - if (bits > 32) - goto emsgsize; } /* Fiery death and destruction unless we prefetched EOS. */ @@ -300,11 +300,11 @@ inet_net_pton_ipv4(const char *src, u_char *dst) assert(n >= 0 && n <= 9); bits *= 10; bits += n; + if (bits > 32) + goto emsgsize; } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch)); if (ch != '\0') goto enoent; - if (bits > 32) - goto emsgsize; } /* Fiery death and destruction unless we prefetched EOS. */ diff --git a/src/test/regress/expected/inet.out b/src/test/regress/expected/inet.out index 1705bff4dd3..01cc0967e8b 100644 --- a/src/test/regress/expected/inet.out +++ b/src/test/regress/expected/inet.out @@ -1156,6 +1156,19 @@ SELECT * FROM pg_input_error_info('192.168.198.200/24', 'cidr'); invalid cidr value: "192.168.198.200/24" | Value has bits set to right of mask. | | 22P02 (1 row) +-- prefix length that overflows int +SELECT pg_input_is_valid('192.168.0.0/4294967320', 'inet'); + pg_input_is_valid +------------------- + f +(1 row) + +SELECT pg_input_is_valid('10.0.0.0/4294967304', 'cidr'); + pg_input_is_valid +------------------- + f +(1 row) + SELECT pg_input_is_valid('1234', 'inet'); pg_input_is_valid ------------------- diff --git a/src/test/regress/sql/inet.sql b/src/test/regress/sql/inet.sql index 8f276856df9..104d5eb51fb 100644 --- a/src/test/regress/sql/inet.sql +++ b/src/test/regress/sql/inet.sql @@ -270,5 +270,8 @@ SELECT * FROM pg_input_error_info('1234', 'cidr'); SELECT pg_input_is_valid('192.168.198.200/24', 'cidr'); SELECT * FROM pg_input_error_info('192.168.198.200/24', 'cidr'); +-- prefix length that overflows int +SELECT pg_input_is_valid('192.168.0.0/4294967320', 'inet'); +SELECT pg_input_is_valid('10.0.0.0/4294967304', 'cidr'); SELECT pg_input_is_valid('1234', 'inet'); SELECT * FROM pg_input_error_info('1234', 'inet'); -- 2.53.0