From c7c0ac1e1e089cf808139b32a55730ae61949770 Mon Sep 17 00:00:00 2001 From: guy Date: Wed, 29 Jun 2005 06:43:31 +0000 Subject: [PATCH] Checking whether the amount of data returned by SIOCGIFCONF is less than the size of the buffer we handed to it is insufficient to determine whether we have the entire list of interfaces or not - if the amount of space left in the buffer after adding an entry is non-zero but less than the amount of space required by the next entry, the ioctl will stop before adding the next entry, and not necessarily return an error. The only way to ensure that we got all the data is to pass a buffer large enough that the amount of space in the buffer *not* filled in is greater than the largest possible entry. We assume that's "sizeof(ifreq.ifr_name)" plus 255, under the assumption that no address is more than 255 bytes (on systems where the "sa_len" field in a "struct sockaddr" is 1 byte, e.g. newer BSDs, that's the case, and addresses are unlikely to be bigger than that in any case). --- fad-gifc.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/fad-gifc.c b/fad-gifc.c index c9c7f69..5f867fe 100644 --- a/fad-gifc.c +++ b/fad-gifc.c @@ -34,7 +34,7 @@ #ifndef lint static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/fad-gifc.c,v 1.8.2.1 2005-04-10 18:04:50 hannes Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/fad-gifc.c,v 1.8.2.2 2005-06-29 06:43:31 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -102,6 +102,27 @@ struct rtentry; /* declarations in */ #endif /* HAVE_SOCKADDR_SA_LEN */ #endif /* SA_LEN */ +/* + * This is also fun. + * + * There is no ioctl that returns the amount of space required for all + * the data that SIOCGIFCONF could return, and if a buffer is supplied + * that's not large enough for all the data SIOCGIFCONF could return, + * on at least some platforms it just returns the data that'd fit with + * no indication that there wasn't enough room for all the data, much + * less an indication of how much more room is required. + * + * The only way to ensure that we got all the data is to pass a buffer + * large enough that the amount of space in the buffer *not* filled in + * is greater than the largest possible entry. + * + * We assume that's "sizeof(ifreq.ifr_name)" plus 255, under the assumption + * that no address is more than 255 bytes (on systems where the "sa_len" + * field in a "struct sockaddr" is 1 byte, e.g. newer BSDs, that's the + * case, and addresses are unlikely to be bigger than that in any case). + */ +#define MAX_SA_LEN 255 + #ifdef HAVE_PROC_NET_DEV /* * Get from "/proc/net/dev" all interfaces listed there; if they're @@ -275,9 +296,10 @@ pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf) /* * Start with an 8K buffer, and keep growing the buffer until - * we get the entire interface list or fail to get it for some - * reason other than EINVAL (which is presumed here to mean - * "buffer is too small"). + * we have more than "sizeof(ifrp->ifr_name) + MAX_SA_LEN" + * bytes left over in the buffer or we fail to get the + * interface list for some reason other than EINVAL (which is + * presumed here to mean "buffer is too small"). */ buf_size = 8192; for (;;) { @@ -300,7 +322,8 @@ pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf) free(buf); return (-1); } - if (ifc.ifc_len < buf_size) + if (ifc.ifc_len < buf_size && + (buf_size - ifc.ifc_len) > sizeof(ifrp->ifr_name) + MAX_SA_LEN) break; free(buf); buf_size *= 2;