diff --git a/src/add-ons/kernel/network/stack/datalink.cpp b/src/add-ons/kernel/network/stack/datalink.cpp index e2670390c9..6688a3d4a9 100644 --- a/src/add-ons/kernel/network/stack/datalink.cpp +++ b/src/add-ons/kernel/network/stack/datalink.cpp @@ -280,7 +280,12 @@ datalink_control(net_domain *_domain, int32 option, void *value, if (user_memcpy(&config, value, sizeof(struct ifconf)) < B_OK) return B_BAD_ADDRESS; - return list_domain_interfaces(config.ifc_buf, config.ifc_len); + status_t result = list_domain_interfaces(config.ifc_buf, + (size_t *)&config.ifc_len); + if (result != B_OK) + return result; + + return user_memcpy(value, &config, sizeof(struct ifconf)); } case SIOCGRTSIZE: diff --git a/src/add-ons/kernel/network/stack/domains.cpp b/src/add-ons/kernel/network/stack/domains.cpp index 078e7160fb..3085078257 100644 --- a/src/add-ons/kernel/network/stack/domains.cpp +++ b/src/add-ons/kernel/network/stack/domains.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2007, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -99,12 +99,13 @@ count_domain_interfaces() returned. */ status_t -list_domain_interfaces(void *buffer, size_t size) +list_domain_interfaces(void *buffer, size_t *_bufferSize) { BenaphoreLocker locker(sDomainLock); + uint8 *current = (uint8 *)buffer; + const uint8 *bufferEnd = current + (*_bufferSize); net_domain_private *domain = NULL; - size_t spaceLeft = size; while (true) { domain = (net_domain_private *)list_get_next_item(&sDomains, domain); @@ -118,8 +119,8 @@ list_domain_interfaces(void *buffer, size_t size) if (interface == NULL) break; - size = IF_NAMESIZE + (interface->address ? interface->address->sa_len : 2); - if (spaceLeft < size) + size_t size = IF_NAMESIZE + (interface->address ? interface->address->sa_len : 2); + if ((current + size) > bufferEnd) return ENOBUFS; ifreq request; @@ -132,14 +133,14 @@ list_domain_interfaces(void *buffer, size_t size) request.ifr_addr.sa_family = AF_UNSPEC; } - if (user_memcpy(buffer, &request, size) < B_OK) + if (user_memcpy(current, &request, size) < B_OK) return B_BAD_ADDRESS; - buffer = (void *)((addr_t)buffer + size); - spaceLeft -= size; + current += size; } } + *_bufferSize = current - (uint8 *)buffer; return B_OK; } diff --git a/src/add-ons/kernel/network/stack/domains.h b/src/add-ons/kernel/network/stack/domains.h index 7750fcb53f..6b9d43d751 100644 --- a/src/add-ons/kernel/network/stack/domains.h +++ b/src/add-ons/kernel/network/stack/domains.h @@ -1,5 +1,5 @@ /* - * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2007, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -30,7 +30,7 @@ status_t init_domains(); status_t uninit_domains(); uint32 count_domain_interfaces(); -status_t list_domain_interfaces(void *buffer, size_t size); +status_t list_domain_interfaces(void *buffer, size_t *_bufferSize); status_t add_interface_to_domain(net_domain *domain, struct ifreq& request); status_t remove_interface_from_domain(net_interface *interface); diff --git a/src/add-ons/kernel/network/stack/interfaces.cpp b/src/add-ons/kernel/network/stack/interfaces.cpp index 11537a9f20..da28a327f1 100644 --- a/src/add-ons/kernel/network/stack/interfaces.cpp +++ b/src/add-ons/kernel/network/stack/interfaces.cpp @@ -258,12 +258,13 @@ count_device_interfaces() returned. */ status_t -list_device_interfaces(void *buffer, size_t size) +list_device_interfaces(void *buffer, size_t *_bufferSize) { BenaphoreLocker locker(sInterfaceLock); + uint8 *current = (uint8 *)buffer; + const uint8 *bufferEnd = current + (*_bufferSize); net_device_interface *interface = NULL; - size_t spaceLeft = size; while (true) { interface = (net_device_interface *)list_get_next_item(&sInterfaces, @@ -275,17 +276,17 @@ list_device_interfaces(void *buffer, size_t size) strlcpy(request.ifr_name, interface->name, IF_NAMESIZE); get_device_interface_address(interface, &request.ifr_addr); - size = IF_NAMESIZE + request.ifr_addr.sa_len; - if (spaceLeft < size) + size_t size = IF_NAMESIZE + request.ifr_addr.sa_len; + if ((current + size) > bufferEnd) return ENOBUFS; - if (user_memcpy(buffer, &request, size) < B_OK) + if (user_memcpy(current, &request, size) < B_OK) return B_BAD_ADDRESS; - buffer = (void *)((addr_t)buffer + size); - spaceLeft -= size; + current += size; } + *_bufferSize = current - (uint8 *)buffer;; return B_OK; } diff --git a/src/add-ons/kernel/network/stack/interfaces.h b/src/add-ons/kernel/network/stack/interfaces.h index d780549357..e801ded8a9 100644 --- a/src/add-ons/kernel/network/stack/interfaces.h +++ b/src/add-ons/kernel/network/stack/interfaces.h @@ -72,7 +72,7 @@ void delete_interface(net_interface_private *interface); void get_device_interface_address(net_device_interface *interface, sockaddr *address); uint32 count_device_interfaces(); -status_t list_device_interfaces(void *buffer, size_t size); +status_t list_device_interfaces(void *buffer, size_t *_bufferSize); void put_device_interface(struct net_device_interface *interface); struct net_device_interface *get_device_interface(uint32 index); struct net_device_interface *get_device_interface(const char *name); diff --git a/src/add-ons/kernel/network/stack/link.cpp b/src/add-ons/kernel/network/stack/link.cpp index 7f127c8463..a6bc89aeb8 100644 --- a/src/add-ons/kernel/network/stack/link.cpp +++ b/src/add-ons/kernel/network/stack/link.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2007, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -174,12 +174,17 @@ link_control(net_protocol *_protocol, int level, int option, void *value, case SIOCGIFCONF: { - // count number of interfaces + // retrieve available interfaces struct ifconf config; if (user_memcpy(&config, value, sizeof(struct ifconf)) < B_OK) return B_BAD_ADDRESS; - return list_device_interfaces(config.ifc_buf, config.ifc_len); + status_t result = list_device_interfaces(config.ifc_buf, + (size_t *)&config.ifc_len); + if (result != B_OK) + return result; + + return user_memcpy(value, &config, sizeof(struct ifconf)); } case SIOCGIFADDR: