diff options
author | florian <> | 2021-01-19 16:43:44 +0000 |
---|---|---|
committer | florian <> | 2021-01-19 16:43:44 +0000 |
commit | 11fb2101811061cab904382a8a9392a1451bc040 (patch) | |
tree | ab34a192f1f66619f942099a65504d0d55b6001c | |
parent | d5a424e282cee10e2123a6454e4ab9c6df85724d (diff) | |
download | openbsd-11fb2101811061cab904382a8a9392a1451bc040.tar.gz openbsd-11fb2101811061cab904382a8a9392a1451bc040.tar.bz2 openbsd-11fb2101811061cab904382a8a9392a1451bc040.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
-rw-r--r-- | src/lib/libc/net/inet_net_pton.c | 29 |
1 files changed, 18 insertions, 11 deletions
diff --git a/src/lib/libc/net/inet_net_pton.c b/src/lib/libc/net/inet_net_pton.c index 2aaeac4048..aaffc1802a 100644 --- a/src/lib/libc/net/inet_net_pton.c +++ b/src/lib/libc/net/inet_net_pton.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: inet_net_pton.c,v 1.10 2017/03/06 18:16:27 millert Exp $ */ | 1 | /* $OpenBSD: inet_net_pton.c,v 1.11 2021/01/19 16:43:44 florian Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2012 by Gilles Chehade <gilles@openbsd.org> | 4 | * 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) | |||
205 | static int | 205 | static int |
206 | inet_net_pton_ipv6(const char *src, u_char *dst, size_t size) | 206 | inet_net_pton_ipv6(const char *src, u_char *dst, size_t size) |
207 | { | 207 | { |
208 | int ret; | 208 | struct in6_addr in6; |
209 | int bits; | 209 | int ret; |
210 | char buf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255:255:255:255/128")]; | 210 | int bits; |
211 | char buf[INET6_ADDRSTRLEN + sizeof("/128")]; | ||
211 | char *sep; | 212 | char *sep; |
212 | const char *errstr; | 213 | const char *errstr; |
213 | 214 | ||
@@ -220,18 +221,24 @@ inet_net_pton_ipv6(const char *src, u_char *dst, size_t size) | |||
220 | if (sep != NULL) | 221 | if (sep != NULL) |
221 | *sep++ = '\0'; | 222 | *sep++ = '\0'; |
222 | 223 | ||
223 | ret = inet_pton(AF_INET6, buf, dst); | 224 | ret = inet_pton(AF_INET6, buf, &in6); |
224 | if (ret != 1) | 225 | if (ret != 1) |
225 | return (-1); | 226 | return (-1); |
226 | 227 | ||
227 | if (sep == NULL) | 228 | if (sep == NULL) |
228 | return 128; | 229 | bits = 128; |
230 | else { | ||
231 | bits = strtonum(sep, 0, 128, &errstr); | ||
232 | if (errstr) { | ||
233 | errno = EINVAL; | ||
234 | return (-1); | ||
235 | } | ||
236 | } | ||
229 | 237 | ||
230 | bits = strtonum(sep, 0, 128, &errstr); | 238 | if ((bits + 7) / 8 > size) { |
231 | if (errstr) { | 239 | errno = EMSGSIZE; |
232 | errno = EINVAL; | ||
233 | return (-1); | 240 | return (-1); |
234 | } | 241 | } |
235 | 242 | memcpy(dst, &in6.s6_addr, size); | |
236 | return bits; | 243 | return (bits); |
237 | } | 244 | } |