From f7b4b5aac088c3a105e454bb0bfa98f09f6fc7c9 Mon Sep 17 00:00:00 2001 From: Janos Follath Date: Thu, 2 Oct 2025 15:52:59 +0100 Subject: [PATCH 1/6] Add malicious ip test for inet_pton Signed-off-by: Janos Follath --- tests/suites/test_suite_x509parse.data | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data index 0ca27a9d68..4fc5054b49 100644 --- a/tests/suites/test_suite_x509parse.data +++ b/tests/suites/test_suite_x509parse.data @@ -1170,6 +1170,9 @@ x509_crt_parse_cn_inet_pton:"\:\:ffff\:1111.2.3.4":"":0 X509 CRT parse CN: IPv6 invalid address IPv4-mapped #3 x509_crt_parse_cn_inet_pton:"\:\:1.2.3.4\:ffff":"":0 +X509 CRT parse CN: IPv6 invalid address IPv4-mapped #4 +x509_crt_parse_cn_inet_pton:"1.2.3.4\:":"":0 + X509 CRT verification with ca callback: failure depends_on:MBEDTLS_PEM_PARSE_C:PSA_WANT_ALG_SHA_1:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK x509_verify_ca_cb_failure:"../framework/data_files/server1.crt":"../framework/data_files/test-ca.crt":"NULL":MBEDTLS_ERR_X509_FATAL_ERROR From 346720d674728b8600a8e8d2696a00dd5c38592d Mon Sep 17 00:00:00 2001 From: Janos Follath Date: Thu, 2 Oct 2025 15:53:56 +0100 Subject: [PATCH 2/6] Add ASan to test_sw_inet_pton Signed-off-by: Janos Follath --- tests/scripts/components-configuration-x509.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/scripts/components-configuration-x509.sh b/tests/scripts/components-configuration-x509.sh index 8010a2a2e6..66e9b16da8 100644 --- a/tests/scripts/components-configuration-x509.sh +++ b/tests/scripts/components-configuration-x509.sh @@ -28,8 +28,9 @@ component_test_sw_inet_pton () { # MBEDTLS_TEST_HOOKS required for x509_crt_parse_cn_inet_pton scripts/config.py set MBEDTLS_TEST_HOOKS - $MAKE_COMMAND CFLAGS="-DMBEDTLS_TEST_SW_INET_PTON" + CC=$ASAN_CC CFLAGS="-DMBEDTLS_TEST_SW_INET_PTON" cmake -D CMAKE_BUILD_TYPE:String=Asan . + make msg "test: default plus MBEDTLS_TEST_SW_INET_PTON" - $MAKE_COMMAND test + make test } From d5e7465ea07bb708c82a1710a2867596e7e78b2e Mon Sep 17 00:00:00 2001 From: Janos Follath Date: Tue, 20 Jan 2026 18:19:33 +0000 Subject: [PATCH 3/6] inet_pton: help ASan find the underflow The generated unit tests have the input parameters in large stack buffers and therefore ASan doesn't notice under or overflows in them. Copy the input parameter into a locally allocated buffer to trigger ASan if something goes wrong. Signed-off-by: Janos Follath --- tests/suites/test_suite_x509parse.function | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function index e892ab9a9e..25d229d6f1 100644 --- a/tests/suites/test_suite_x509parse.function +++ b/tests/suites/test_suite_x509parse.function @@ -488,12 +488,22 @@ exit: void x509_crt_parse_cn_inet_pton(const char *cn, data_t *exp, int ref_ret) { uint32_t addr[4]; - size_t addrlen = mbedtls_x509_crt_parse_cn_inet_pton(cn, addr); + + char *cn_local = NULL; + size_t cn_local_len = strlen(cn) + 1; + TEST_CALLOC(cn_local, cn_local_len); + memcpy(cn_local, cn, cn_local_len); + + size_t addrlen = mbedtls_x509_crt_parse_cn_inet_pton(cn_local, addr); TEST_EQUAL(addrlen, (size_t) ref_ret); if (addrlen) { TEST_MEMORY_COMPARE(exp->x, exp->len, addr, addrlen); } + +exit: + mbedtls_free(cn_local); + } /* END_CASE */ From 1a127e3c892076dd9725fce2ee10015eb20448f4 Mon Sep 17 00:00:00 2001 From: Janos Follath Date: Tue, 20 Jan 2026 18:46:52 +0000 Subject: [PATCH 4/6] inet_pton: fix buggy condition The flawed condition made us accept invalid IPv6 addresses and in some cases lead to a buffer underread. Signed-off-by: Janos Follath --- library/x509_crt.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 59c3204467..25a4bbaf68 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -2719,8 +2719,12 @@ static int x509_inet_pton_ipv6(const char *src, void *dst) if (*p == '\0') { break; } else if (*p == '.') { - /* Don't accept IPv4 too early or late */ - if ((nonzero_groups == 0 && zero_group_start == -1) || + /* Don't accept IPv4 too early or late: + * - The first 6 nonzero groups must be 16 bit pieces of address delimited by ':' + * - This might be fully or partially represented with compressed syntax (a zero + * group "::") + */ + if ((nonzero_groups < 6 && zero_group_start == -1) || nonzero_groups >= 7) { break; } From 57f189887bf72268d3de042cf1437e324f022708 Mon Sep 17 00:00:00 2001 From: Janos Follath Date: Wed, 21 Jan 2026 09:16:07 +0000 Subject: [PATCH 5/6] Add ChangeLog entry Signed-off-by: Janos Follath --- ChangeLog.d/inet_pton.txt | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 ChangeLog.d/inet_pton.txt diff --git a/ChangeLog.d/inet_pton.txt b/ChangeLog.d/inet_pton.txt new file mode 100644 index 0000000000..526cd9be5f --- /dev/null +++ b/ChangeLog.d/inet_pton.txt @@ -0,0 +1,4 @@ +Security + * Fix a limited buffer underflow in x509_inet_pton_ipv6(). In rare cases + (e.g. on platforms with memory protection when the overread crosses page + boundary) this could lead to DoS. Found and reported by Haruto Kimura. From 50376926a7356c25da12f1d2e66cacf2d3e9bbcb Mon Sep 17 00:00:00 2001 From: Janos Follath Date: Wed, 21 Jan 2026 17:29:07 +0000 Subject: [PATCH 6/6] inet_pton: simplify IPv4 walkback loop Signed-off-by: Janos Follath --- library/x509_crt.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 25a4bbaf68..028ae8bf14 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -2729,16 +2729,15 @@ static int x509_inet_pton_ipv6(const char *src, void *dst) break; } - /* Walk back to prior ':', then parse as IPv4-mapped */ - int steps = 4; + /* Walk back to prior ':', then parse as IPv4-mapped. + * At this point nonzero_groups == 6 or zero_group_start >= 0. Either way we have a + * ':' before the current position and still inside the buffer. Thus it is safe to + * search back for that ':' without any further checks. + */ do { p--; - steps--; - } while (*p != ':' && steps > 0); + } while (*p != ':'); - if (*p != ':') { - break; - } p++; nonzero_groups--; if (x509_inet_pton_ipv4((const char *) p,