From fb804e34987560919ca7c94ef6b3b656d33629d2 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Wed, 20 Sep 2017 06:52:05 -0600 Subject: [PATCH] netlib_ipv[4|6]adaptor: Add a check to handle the case where the network device configuration changed asynchronously and the second IOCTL returns more data than the allocated buffer. --- include/netutils/netlib.h | 4 ++-- netutils/netlib/netlib_ipv4adaptor.c | 21 ++++++++++++++++++--- netutils/netlib/netlib_ipv6adaptor.c | 21 ++++++++++++++++++--- 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/include/netutils/netlib.h b/include/netutils/netlib.h index 51d3a94d2..5452c6756 100644 --- a/include/netutils/netlib.h +++ b/include/netutils/netlib.h @@ -160,11 +160,11 @@ int netlib_get_ipv6addr(FAR const char *ifname, FAR struct in6_addr *addr); int netlib_set_ipv6addr(FAR const char *ifname, FAR const struct in6_addr *addr); int netlib_set_dripv6addr(FAR const char *ifname, FAR const struct in6_addr *addr); int netlib_set_ipv6netmask(FAR const char *ifname, FAR const struct in6_addr *addr); +int netlib_ipv6adaptor(FAR const struct in6_addr *destipaddr, + FAR struct in6_addr *srcipaddr); uint8_t netlib_ipv6netmask2prefix(FAR const uint16_t *mask); void netlib_prefix2ipv6netmask(uint8_t preflen, FAR struct in6_addr *netmask); -int netlib_ipv6adaptor(FAR const struct in6_addr *destipaddr, - FAR struct in6_addr *srcipaddr); #endif #ifdef CONFIG_NETDEV_WIRELESS_IOCTL diff --git a/netutils/netlib/netlib_ipv4adaptor.c b/netutils/netlib/netlib_ipv4adaptor.c index abf3d8ff0..7c3f97501 100644 --- a/netutils/netlib/netlib_ipv4adaptor.c +++ b/netutils/netlib/netlib_ipv4adaptor.c @@ -91,6 +91,8 @@ int netlib_ipv4adaptor(in_addr_t destipaddr, FAR in_addr_t *srcipaddr) { FAR struct ifreq *ifr; struct ifconf ifc; + size_t allocsize; + size_t buflen; int nintf; int ret; int sd; @@ -123,7 +125,8 @@ int netlib_ipv4adaptor(in_addr_t destipaddr, FAR in_addr_t *srcipaddr) /* Allocate the buffer to hold the interface descriptions */ - ifr = (FAR struct ifreq *)malloc(ifc.ifc_len); + allocsize = ifc.ifc_len; + ifr = (FAR struct ifreq *)malloc(allocsize); if (ifr == NULL) { fprintf(stderr, "ERROR: Failed to allocate IFC buffer\n"); @@ -144,10 +147,22 @@ int netlib_ipv4adaptor(in_addr_t destipaddr, FAR in_addr_t *srcipaddr) } /* Find an interface that supports the subnet needed by the provided - * IPv4 address. + * IPv4 address. Be careful! The size of the returned buffer could + * be different if the network device configuration changed in between + * the two calls! */ - nintf = ifc.ifc_len / sizeof(struct ifreq); + buflen = ifc.ifc_len; + if (buflen > allocsize) + { + /* Something has changed. Limit to the original size (OR do the + * allocation and IOCTL again). + */ + + buflen = allocsize; + } + + nintf = buflen / sizeof(struct ifreq); ret = -EHOSTUNREACH; for (i = 0; i < nintf; i++) diff --git a/netutils/netlib/netlib_ipv6adaptor.c b/netutils/netlib/netlib_ipv6adaptor.c index 4a358de5b..45a8ac0db 100644 --- a/netutils/netlib/netlib_ipv6adaptor.c +++ b/netutils/netlib/netlib_ipv6adaptor.c @@ -92,6 +92,8 @@ int netlib_ipv6adaptor(FAR const struct in6_addr *destipaddr, { FAR struct lifreq *lifr; struct lifconf lifc; + size_t allocsize; + size_t buflen; int nintf; int ret; int sd; @@ -124,7 +126,8 @@ int netlib_ipv6adaptor(FAR const struct in6_addr *destipaddr, /* Allocate the buffer to hold the interface descriptions */ - lifr = (FAR struct lifreq *)malloc(lifc.lifc_len); + allocsize = lifc.lifc_len; + lifr = (FAR struct lifreq *)malloc(allocsize); if (lifr == NULL) { fprintf(stderr, "ERROR: Failed to allocate LIFC buffer\n"); @@ -145,10 +148,22 @@ int netlib_ipv6adaptor(FAR const struct in6_addr *destipaddr, } /* Find an interface that supports the subnet needed by the provided - * IPv6 address. + * IPv6 address. Be careful! The size of the returned buffer could + * be different if the network device configuration changed in between + * the two calls! */ - nintf = lifc.lifc_len / sizeof(struct lifreq); + buflen = lifc.lifc_len; + if (buflen > allocsize) + { + /* Something has changed. Limit to the original size (OR do the + * allocation and IOCTL again). + */ + + buflen = allocsize; + } + + nintf = buflen / sizeof(struct lifreq); ret = -EHOSTUNREACH; for (i = 0; i < nintf; i++)