From 6d2b67c004889dbcd2b89e1e888b78487d64011f Mon Sep 17 00:00:00 2001
From: Zexin Li <lizi.openmind@gmail.com>
Date: Fri, 31 Jul 2026 06:21:19 +0000
Subject: [PATCH] Reject overlong hex fields in macaddr input

macaddr_in() parsed the colon- and dash-separated formats with
unbounded sscanf %x conversions, so a field with more than eight hex
digits overflowed the int variable.  The C standard leaves such an
overflow undefined; with glibc the value wraps modulo 2^32, so inputs
like '100000001:0:0:0:0:0' were silently accepted and stored as a
different MAC address (01:00:00:00:00:00), bypassing the 0..255 range
check.  A signed field such as '-ffffff01:0:0:0:0:0' was likewise
accepted through the same wraparound.

Fix by bounding the conversions with %2x, matching the five condensed
formats in the same function.  Overlong fields now fail the format
match and draw "invalid input syntax", deterministically instead of
depending on where the wrapped value happens to land.  Overlong fields
that already drew an error before, such as '1ff:0:0:0:0:0', now fail
with SQLSTATE 22P02 (invalid_text_representation) instead of 22003,
since the format match fails before the range check runs.

Two undocumented input forms change behavior as a side effect: fields
zero-padded past two digits ('001:00:2b:01:02:03') and 0x-prefixed
fields ('0xff:0:0:0:0:0') were previously accepted with the correct
value and are now rejected.  Neither is ever produced by macaddr
output, so dumps and restores are unaffected.

Bug: #19583
Reported-by: Michael Malis <malis@pgrust.com>
Discussion: https://postgr.es/m/19583-ca7c85d40164f18b@postgresql.org
---
 src/backend/utils/adt/mac.c           |  4 +--
 src/test/regress/expected/macaddr.out | 39 +++++++++++++++++++++++++++
 src/test/regress/sql/macaddr.sql      | 12 +++++++++
 3 files changed, 53 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/adt/mac.c b/src/backend/utils/adt/mac.c
index 923c5af5..f243f785 100644
--- a/src/backend/utils/adt/mac.c
+++ b/src/backend/utils/adt/mac.c
@@ -57,10 +57,10 @@ macaddr_in(PG_FUNCTION_ARGS)
 
 	/* %1s matches iff there is trailing non-whitespace garbage */
 
-	count = sscanf(str, "%x:%x:%x:%x:%x:%x%1s",
+	count = sscanf(str, "%2x:%2x:%2x:%2x:%2x:%2x%1s",
 				   &a, &b, &c, &d, &e, &f, junk);
 	if (count != 6)
-		count = sscanf(str, "%x-%x-%x-%x-%x-%x%1s",
+		count = sscanf(str, "%2x-%2x-%2x-%2x-%2x-%2x%1s",
 					   &a, &b, &c, &d, &e, &f, junk);
 	if (count != 6)
 		count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%1s",
diff --git a/src/test/regress/expected/macaddr.out b/src/test/regress/expected/macaddr.out
index 8d5b2219..ad21db72 100644
--- a/src/test/regress/expected/macaddr.out
+++ b/src/test/regress/expected/macaddr.out
@@ -17,6 +17,32 @@ INSERT INTO macaddr_data VALUES (9, 'not even close'); -- invalid
 ERROR:  invalid input syntax for type macaddr: "not even close"
 LINE 1: INSERT INTO macaddr_data VALUES (9, 'not even close');
                                             ^
+-- overlong hex fields must be rejected, not silently wrapped (bug #19583)
+SELECT '100000001:0:0:0:0:0'::macaddr;
+ERROR:  invalid input syntax for type macaddr: "100000001:0:0:0:0:0"
+LINE 1: SELECT '100000001:0:0:0:0:0'::macaddr;
+               ^
+SELECT '100000001-0-0-0-0-0'::macaddr;
+ERROR:  invalid input syntax for type macaddr: "100000001-0-0-0-0-0"
+LINE 1: SELECT '100000001-0-0-0-0-0'::macaddr;
+               ^
+SELECT '-ffffff01:0:0:0:0:0'::macaddr;
+ERROR:  invalid input syntax for type macaddr: "-ffffff01:0:0:0:0:0"
+LINE 1: SELECT '-ffffff01:0:0:0:0:0'::macaddr;
+               ^
+SELECT 'ffffffff01:0:0:0:0:0'::macaddr;
+ERROR:  invalid input syntax for type macaddr: "ffffffff01:0:0:0:0:0"
+LINE 1: SELECT 'ffffffff01:0:0:0:0:0'::macaddr;
+               ^
+SELECT '1ff:0:0:0:0:0'::macaddr;
+ERROR:  invalid input syntax for type macaddr: "1ff:0:0:0:0:0"
+LINE 1: SELECT '1ff:0:0:0:0:0'::macaddr;
+               ^
+-- an in-range-width negative field is still caught by the octet range check
+SELECT '-f:0:0:0:0:0'::macaddr;
+ERROR:  invalid octet value in "macaddr" value: "-f:0:0:0:0:0"
+LINE 1: SELECT '-f:0:0:0:0:0'::macaddr;
+               ^
 INSERT INTO macaddr_data VALUES (10, '08:00:2b:01:02:04');
 INSERT INTO macaddr_data VALUES (11, '08:00:2b:01:02:02');
 INSERT INTO macaddr_data VALUES (12, '08:00:2a:01:02:03');
@@ -183,3 +209,16 @@ SELECT * FROM pg_input_error_info('08:00:2b:01:02:', 'macaddr');
  invalid input syntax for type macaddr: "08:00:2b:01:02:" |        |      | 22P02
 (1 row)
 
+-- overlong hex field (bug #19583)
+SELECT pg_input_is_valid('100000001:0:0:0:0:0', 'macaddr');
+ pg_input_is_valid 
+-------------------
+ f
+(1 row)
+
+SELECT * FROM pg_input_error_info('1ff:0:0:0:0:0', 'macaddr');
+                        message                         | detail | hint | sql_error_code 
+--------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type macaddr: "1ff:0:0:0:0:0" |        |      | 22P02
+(1 row)
+
diff --git a/src/test/regress/sql/macaddr.sql b/src/test/regress/sql/macaddr.sql
index f61bdebe..ffc7f816 100644
--- a/src/test/regress/sql/macaddr.sql
+++ b/src/test/regress/sql/macaddr.sql
@@ -14,6 +14,15 @@ INSERT INTO macaddr_data VALUES (7, '08002b010203');
 INSERT INTO macaddr_data VALUES (8, '0800:2b01:0203'); -- invalid
 INSERT INTO macaddr_data VALUES (9, 'not even close'); -- invalid
 
+-- overlong hex fields must be rejected, not silently wrapped (bug #19583)
+SELECT '100000001:0:0:0:0:0'::macaddr;
+SELECT '100000001-0-0-0-0-0'::macaddr;
+SELECT '-ffffff01:0:0:0:0:0'::macaddr;
+SELECT 'ffffffff01:0:0:0:0:0'::macaddr;
+SELECT '1ff:0:0:0:0:0'::macaddr;
+-- an in-range-width negative field is still caught by the octet range check
+SELECT '-f:0:0:0:0:0'::macaddr;
+
 INSERT INTO macaddr_data VALUES (10, '08:00:2b:01:02:04');
 INSERT INTO macaddr_data VALUES (11, '08:00:2b:01:02:02');
 INSERT INTO macaddr_data VALUES (12, '08:00:2a:01:02:03');
@@ -47,3 +56,6 @@ SELECT pg_input_is_valid('08:00:2b:01:02:ZZ', 'macaddr');
 SELECT * FROM pg_input_error_info('08:00:2b:01:02:ZZ', 'macaddr');
 SELECT pg_input_is_valid('08:00:2b:01:02:', 'macaddr');
 SELECT * FROM pg_input_error_info('08:00:2b:01:02:', 'macaddr');
+-- overlong hex field (bug #19583)
+SELECT pg_input_is_valid('100000001:0:0:0:0:0', 'macaddr');
+SELECT * FROM pg_input_error_info('1ff:0:0:0:0:0', 'macaddr');
-- 
2.34.1

