From 2c92e8ce930a428a6fd150ae1ae55c5a365543f5 Mon Sep 17 00:00:00 2001 From: Norbert Pocs Date: Tue, 28 Nov 2023 15:26:45 +0100 Subject: [PATCH] CVE-2023-6004: misc: Add ipv6 link-local check for an ip address Signed-off-by: Norbert Pocs Reviewed-by: Andreas Schneider Reviewed-by: Jakub Jelen --- src/CMakeLists.txt | 3 ++- src/connect.c | 2 +- src/misc.c | 44 ++++++++++++++++++++++++++++++++++++++------ 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b6b9cd7c..216e149a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -85,11 +85,12 @@ if (MINGW AND Threads_FOUND) ) endif() -# This needs to be last for mingw to build +# The ws2_32 needs to be last for mingw to build # https://gitlab.com/libssh/libssh-mirror/-/issues/84 if (WIN32) set(LIBSSH_LINK_LIBRARIES ${LIBSSH_LINK_LIBRARIES} + iphlpapi ws2_32 ) endif (WIN32) diff --git a/src/connect.c b/src/connect.c index fd54c511..dd3bbcf5 100644 --- a/src/connect.c +++ b/src/connect.c @@ -131,7 +131,7 @@ static int getai(const char *host, int port, struct addrinfo **ai) #endif } - if (ssh_is_ipaddr(host)) { + if (ssh_is_ipaddr(host) == 1) { /* this is an IP address */ SSH_LOG(SSH_LOG_PACKET, "host %s matches an IP address", host); hints.ai_flags |= AI_NUMERICHOST; diff --git a/src/misc.c b/src/misc.c index 0c0a2fe3..5cab9d96 100644 --- a/src/misc.c +++ b/src/misc.c @@ -32,6 +32,7 @@ #include #include #include +#include #endif /* _WIN32 */ @@ -59,6 +60,7 @@ #include #include #include +#include #ifdef HAVE_IO_H #include @@ -222,22 +224,37 @@ int ssh_is_ipaddr_v4(const char *str) int ssh_is_ipaddr(const char *str) { int rc = SOCKET_ERROR; + char *s = strdup(str); - if (strchr(str, ':')) { + if (s == NULL) { + return -1; + } + if (strchr(s, ':')) { struct sockaddr_storage ss; int sslen = sizeof(ss); + char *network_interface = strchr(s, '%'); - /* TODO link-local (IP:v6:addr%ifname). */ - rc = WSAStringToAddressA((LPSTR) str, + /* link-local (IP:v6:addr%ifname). */ + if (network_interface != NULL) { + rc = if_nametoindex(network_interface + 1); + if (rc == 0) { + free(s); + return 0; + } + *network_interface = '\0'; + } + rc = WSAStringToAddressA((LPSTR) s, AF_INET6, NULL, (struct sockaddr*)&ss, &sslen); if (rc == 0) { + free(s); return 1; } } + free(s); return ssh_is_ipaddr_v4(str); } #else /* _WIN32 */ @@ -343,17 +360,32 @@ int ssh_is_ipaddr_v4(const char *str) int ssh_is_ipaddr(const char *str) { int rc = -1; + char *s = strdup(str); - if (strchr(str, ':')) { + if (s == NULL) { + return -1; + } + if (strchr(s, ':')) { struct in6_addr dest6; + char *network_interface = strchr(s, '%'); - /* TODO link-local (IP:v6:addr%ifname). */ - rc = inet_pton(AF_INET6, str, &dest6); + /* link-local (IP:v6:addr%ifname). */ + if (network_interface != NULL) { + rc = if_nametoindex(network_interface + 1); + if (rc == 0) { + free(s); + return 0; + } + *network_interface = '\0'; + } + rc = inet_pton(AF_INET6, s, &dest6); if (rc > 0) { + free(s); return 1; } } + free(s); return ssh_is_ipaddr_v4(str); }