From 7a69ca5bc94d1705a4ce0cddcf3fed212e68b51e Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Sat, 4 Apr 2026 22:35:40 +0200 Subject: [PATCH] Refactor IPv6 zone ID parsing and reject malformed zone identifiers --- src/libsodium/sodium/codecs.c | 25 +++++++++++++++---------- test/default/codecs.c | 4 ++++ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/libsodium/sodium/codecs.c b/src/libsodium/sodium/codecs.c index 33f081b1..39418bab 100644 --- a/src/libsodium/sodium/codecs.c +++ b/src/libsodium/sodium/codecs.c @@ -485,29 +485,34 @@ sodium_ip2bin(unsigned char bin[16], const char *ip, size_t ip_len_) /* Some AIX versions define a macro named "ip_len" */ { const char *ip_end = ip + ip_len_; - const char *end; + const char *end = ip; + const char *zone = NULL; const char *z; unsigned char v4[4]; + int is_ipv6; - for (end = ip; end < ip_end && *end != 0 && *end != '%'; end++) { + for (; end < ip_end && *end != 0; end++) { /* empty */ } - if (end < ip_end && *end == '%') { - for (z = end + 1; z < ip_end && *z != 0; z++) { - if (isspace((unsigned char) *z)) { + zone = memchr(ip, '%', (size_t) (end - ip)); + if (zone != NULL) { + for (z = zone + 1; z < end; z++) { + if (*z == '%' || isspace((unsigned char) *z)) { return -1; } } - if (z == end + 1) { + if (zone + 1 >= end) { return -1; } + end = zone; } - if (memchr(ip, ':', (size_t) (end - ip)) != NULL) { - return parse_ipv6(ip, end, bin) != 0 ? 0 : -1; - } - if (end < ip_end && *end == '%') { + is_ipv6 = memchr(ip, ':', (size_t) (end - ip)) != NULL; + if (zone != NULL && !is_ipv6) { return -1; } + if (is_ipv6) { + return parse_ipv6(ip, end, bin) != 0 ? 0 : -1; + } if (parse_ipv4(ip, end, v4) == 0) { return -1; } diff --git a/test/default/codecs.c b/test/default/codecs.c index 6119e28f..2814ee23 100644 --- a/test/default/codecs.c +++ b/test/default/codecs.c @@ -307,6 +307,10 @@ main(void) assert(sodium_ip2bin(ip_bytes, "fe80::1%eth0", strlen("fe80::1%eth0")) == 0); assert(sodium_ip2bin(ip_bytes, "fe80::1%15", strlen("fe80::1%15")) == 0); + assert(sodium_ip2bin(ip_bytes, "fe80::1%%eth0", strlen("fe80::1%%eth0")) == -1); + assert(sodium_ip2bin(ip_bytes, "fe80::1%eth0%1", strlen("fe80::1%eth0%1")) == -1); + assert(sodium_ip2bin(ip_bytes, "fe80::1%eth 0", strlen("fe80::1%eth 0")) == -1); + assert(sodium_ip2bin(ip_bytes, "192.168.1.1%eth0", strlen("192.168.1.1%eth0")) == -1); printf("ip2bytes IPv6 zone: OK\n"); assert(sodium_ip2bin(ip_bytes, "2001:::1", strlen("2001:::1")) == -1);