From 0d738bab0d82347aa17dd3bc4a462e5c02596061 Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Thu, 16 Dec 2010 19:46:23 +0100 Subject: ares_inet_ntop: fix off by one error triggering out of bounds write ares_inet_ntop would trigger an out of bounds write when the representation of the address required 15 characters, due to not taking in account null termination character. Full import of inet_ntop.c from bind-9.5.3rc1 to pull additional fixes. --- inet_ntop.c | 335 ++++++++++++++++++++++++++++-------------------------------- 1 file changed, 155 insertions(+), 180 deletions(-) (limited to 'inet_ntop.c') diff --git a/inet_ntop.c b/inet_ntop.c index 71385cc..114ca5d 100644 --- a/inet_ntop.c +++ b/inet_ntop.c @@ -1,52 +1,39 @@ - -/* Copyright (c) 1996 by Internet Software Consortium. +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * - * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS - * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE - * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "ares_setup.h" +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: inet_ntop.c,v 1.5 2005/11/03 22:59:52 marka Exp $"; +#endif /* LIBC_SCCS and not lint */ -#ifdef HAVE_SYS_SOCKET_H -# include -#endif -#ifdef HAVE_NETINET_IN_H -# include -#endif -#ifdef HAVE_ARPA_INET_H -# include -#endif -#ifdef HAVE_ARPA_NAMESER_H -# include -#else -# include "nameser.h" -#endif -#ifdef HAVE_ARPA_NAMESER_COMPAT_H -# include -#endif +#include "port_before.h" + +#include +#include +#include + +#include +#include +#include -#include #include #include #include -#include - -#include "ares.h" -#include "ares_ipv6.h" -#include "inet_ntop.h" - -#ifndef HAVE_INET_NTOP +#include "port_after.h" #ifdef SPRINTF_CHAR # define SPRINTF(x) strlen(sprintf/**/x) @@ -54,179 +41,167 @@ # define SPRINTF(x) ((size_t)sprintf x) #endif -/* +/*% * WARNING: Don't even consider trying to compile this on a system where * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. */ -static const char *inet_ntop4(const unsigned char *src, char *dst, size_t size); -static const char *inet_ntop6(const unsigned char *src, char *dst, size_t size); +static const char *inet_ntop4 __P((const u_char *src, char *dst, size_t size)); +static const char *inet_ntop6 __P((const u_char *src, char *dst, size_t size)); /* char * * inet_ntop(af, src, dst, size) - * convert a network format address to presentation format. + * convert a network format address to presentation format. * return: - * pointer to presentation format address (`dst'), or NULL (see errno). - * note: - * On Windows we store the error in the thread errno, not - * in the winsock error code. This is to avoid loosing the - * actual last winsock error. So use macro ERRNO to fetch the - * errno this funtion sets when returning NULL, not SOCKERRNO. + * pointer to presentation format address (`dst'), or NULL (see errno). * author: - * Paul Vixie, 1996. + * Paul Vixie, 1996. */ const char * -ares_inet_ntop(int af, const void *src, char *dst, size_t size) +inet_ntop(af, src, dst, size) + int af; + const void *src; + char *dst; + size_t size; { - switch (af) - { - case AF_INET: - return (inet_ntop4(src, dst, size)); - case AF_INET6: - return (inet_ntop6(src, dst, size)); - default: - SET_ERRNO(EAFNOSUPPORT); - return (NULL); - } - /* NOTREACHED */ + switch (af) { + case AF_INET: + return (inet_ntop4(src, dst, size)); + case AF_INET6: + return (inet_ntop6(src, dst, size)); + default: + errno = EAFNOSUPPORT; + return (NULL); + } + /* NOTREACHED */ } /* const char * * inet_ntop4(src, dst, size) - * format an IPv4 address, more or less like inet_ntoa() + * format an IPv4 address * return: - * `dst' (as a const) + * `dst' (as a const) * notes: - * (1) uses no statics - * (2) takes a unsigned char* not an in_addr as input + * (1) uses no statics + * (2) takes a u_char* not an in_addr as input * author: - * Paul Vixie, 1996. + * Paul Vixie, 1996. */ static const char * -inet_ntop4(const unsigned char *src, char *dst, size_t size) +inet_ntop4(src, dst, size) + const u_char *src; + char *dst; + size_t size; { - static const char fmt[] = "%u.%u.%u.%u"; - char tmp[sizeof "255.255.255.255"]; - - if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) > size) - { - SET_ERRNO(ENOSPC); - return (NULL); - } - strcpy(dst, tmp); - return (dst); + static const char fmt[] = "%u.%u.%u.%u"; + char tmp[sizeof "255.255.255.255"]; + + if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) >= size) { + errno = ENOSPC; + return (NULL); + } + strcpy(dst, tmp); + return (dst); } /* const char * * inet_ntop6(src, dst, size) - * convert IPv6 binary address into presentation (printable) format + * convert IPv6 binary address into presentation (printable) format * author: - * Paul Vixie, 1996. + * Paul Vixie, 1996. */ static const char * -inet_ntop6(const unsigned char *src, char *dst, size_t size) +inet_ntop6(src, dst, size) + const u_char *src; + char *dst; + size_t size; { - /* - * Note that int32_t and int16_t need only be "at least" large enough - * to contain a value of the specified size. On some systems, like - * Crays, there is no such thing as an integer variable with 16 bits. - * Keep this in mind if you think this function should have been coded - * to use pointer overlays. All the world's not a VAX. - */ - char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; - char *tp; - struct { - long base; - long len; - } best, cur; - unsigned long words[NS_IN6ADDRSZ / NS_INT16SZ]; - int i; - - /* - * Preprocess: - * Copy the input (bytewise) array into a wordwise array. - * Find the longest run of 0x00's in src[] for :: shorthanding. - */ - memset(words, '\0', sizeof(words)); - for (i = 0; i < NS_IN6ADDRSZ; i++) - words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); - - best.base = -1; - cur.base = -1; - best.len = 0; - cur.len = 0; - - for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) - { - if (words[i] == 0) - { - if (cur.base == -1) - cur.base = i, cur.len = 1; - else - cur.len++; - } - else - { - if (cur.base != -1) - { - if (best.base == -1 || cur.len > best.len) - best = cur; - cur.base = -1; - } - } - } - if (cur.base != -1) - { - if (best.base == -1 || cur.len > best.len) - best = cur; - } - if (best.base != -1 && best.len < 2) - best.base = -1; - - /* - * Format the result. - */ - tp = tmp; - for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) - { - /* Are we inside the best run of 0x00's? */ - if (best.base != -1 && i >= best.base && - i < (best.base + best.len)) - { - if (i == best.base) - *tp++ = ':'; - continue; - } - /* Are we following an initial run of 0x00s or any real hex? */ - if (i != 0) - *tp++ = ':'; - /* Is this address an encapsulated IPv4? */ - if (i == 6 && best.base == 0 && - (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) - { - if (!inet_ntop4(src+12, tp, sizeof(tmp) - (tp - tmp))) - return (NULL); - tp += strlen(tp); - break; - } - tp += SPRINTF((tp, "%lx", words[i])); - } - - /* Was it a trailing run of 0x00's? */ - if (best.base != -1 && (best.base + best.len) == (NS_IN6ADDRSZ / NS_INT16SZ)) - *tp++ = ':'; - *tp++ = '\0'; - - /* - * Check for overflow, copy, and we're done. - */ - if ((size_t)(tp - tmp) > size) - { - SET_ERRNO(ENOSPC); - return (NULL); - } - strcpy(dst, tmp); - return (dst); + /* + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; + struct { int base, len; } best, cur; + u_int words[NS_IN6ADDRSZ / NS_INT16SZ]; + int i; + + /* + * Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + memset(words, '\0', sizeof words); + for (i = 0; i < NS_IN6ADDRSZ; i++) + words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); + best.base = -1; + best.len = 0; + cur.base = -1; + cur.len = 0; + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { + if (words[i] == 0) { + if (cur.base == -1) + cur.base = i, cur.len = 1; + else + cur.len++; + } else { + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + } + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + } + if (best.base != -1 && best.len < 2) + best.base = -1; + + /* + * Format the result. + */ + tp = tmp; + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { + /* Are we inside the best run of 0x00's? */ + if (best.base != -1 && i >= best.base && + i < (best.base + best.len)) { + if (i == best.base) + *tp++ = ':'; + continue; + } + /* Are we following an initial run of 0x00s or any real hex? */ + if (i != 0) + *tp++ = ':'; + /* Is this address an encapsulated IPv4? */ + if (i == 6 && best.base == 0 && (best.len == 6 || + (best.len == 7 && words[7] != 0x0001) || + (best.len == 5 && words[5] == 0xffff))) { + if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp))) + return (NULL); + tp += strlen(tp); + break; + } + tp += SPRINTF((tp, "%x", words[i])); + } + /* Was it a trailing run of 0x00's? */ + if (best.base != -1 && (best.base + best.len) == + (NS_IN6ADDRSZ / NS_INT16SZ)) + *tp++ = ':'; + *tp++ = '\0'; + + /* + * Check for overflow, copy, and we're done. + */ + if ((size_t)(tp - tmp) > size) { + errno = ENOSPC; + return (NULL); + } + strcpy(dst, tmp); + return (dst); } -#endif +/*! \file */ -- cgit v1.2.3