summaryrefslogtreecommitdiffstats
path: root/lib/libc
diff options
context:
space:
mode:
authorflorian <florian@openbsd.org>2021-01-19 16:43:44 +0000
committerflorian <florian@openbsd.org>2021-01-19 16:43:44 +0000
commit73159aebc3abfb2b38a6bde8cc4c693d93b287f9 (patch)
tree20324678a4ade69837454889234804a05e3f8fa3 /lib/libc
parentusb_init_task() wants a struct usb_task as the first argument (diff)
downloadwireguard-openbsd-73159aebc3abfb2b38a6bde8cc4c693d93b287f9.tar.xz
wireguard-openbsd-73159aebc3abfb2b38a6bde8cc4c693d93b287f9.zip
Prevent an overflow in inet_net_pton(3) when the passed in buffer is
too small in the AF_INET6 case. Spotted by Brad House (brad AT brad-house.com) with the c-ares regression test. The man page says Caution: The dst field should be zeroed before calling inet_net_pton() as the function will only fill the number of bytes necessary to encode the network number in network byte order. Which seems to suggest that the function should work if the passed in storage is big enough to hold the prefix, which might be smaller than sizeof(in6_addr). Input & OK tb
Diffstat (limited to 'lib/libc')
-rw-r--r--lib/libc/net/inet_net_pton.c29
1 files changed, 18 insertions, 11 deletions
diff --git a/lib/libc/net/inet_net_pton.c b/lib/libc/net/inet_net_pton.c
index 2aaeac4048a..aaffc1802a6 100644
--- a/lib/libc/net/inet_net_pton.c
+++ b/lib/libc/net/inet_net_pton.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: inet_net_pton.c,v 1.10 2017/03/06 18:16:27 millert Exp $ */
+/* $OpenBSD: inet_net_pton.c,v 1.11 2021/01/19 16:43:44 florian Exp $ */
/*
* Copyright (c) 2012 by Gilles Chehade <gilles@openbsd.org>
@@ -205,9 +205,10 @@ inet_net_pton_ipv4(const char *src, u_char *dst, size_t size)
static int
inet_net_pton_ipv6(const char *src, u_char *dst, size_t size)
{
- int ret;
- int bits;
- char buf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255:255:255:255/128")];
+ struct in6_addr in6;
+ int ret;
+ int bits;
+ char buf[INET6_ADDRSTRLEN + sizeof("/128")];
char *sep;
const char *errstr;
@@ -220,18 +221,24 @@ inet_net_pton_ipv6(const char *src, u_char *dst, size_t size)
if (sep != NULL)
*sep++ = '\0';
- ret = inet_pton(AF_INET6, buf, dst);
+ ret = inet_pton(AF_INET6, buf, &in6);
if (ret != 1)
return (-1);
if (sep == NULL)
- return 128;
+ bits = 128;
+ else {
+ bits = strtonum(sep, 0, 128, &errstr);
+ if (errstr) {
+ errno = EINVAL;
+ return (-1);
+ }
+ }
- bits = strtonum(sep, 0, 128, &errstr);
- if (errstr) {
- errno = EINVAL;
+ if ((bits + 7) / 8 > size) {
+ errno = EMSGSIZE;
return (-1);
}
-
- return bits;
+ memcpy(dst, &in6.s6_addr, size);
+ return (bits);
}