Hi, On 09/06/2020 10:02, Gert Doering wrote: > Remove separate ipv4.size and ipv6.size in the pool structure, return > to a single pool_size, which is also the allocated array size. > > All calls to ifconfig_pool_size() change to "pool->size" now. > > pool->size is set to the size of the active pool, or if both IPv4 and IPv6 > are in use, to the smaller size (same underlying logic as in 452113155e7, > but really put it into the size field). > > This fixes a SIGSEGV crash if an ifconfig-pool-persist file is loaded > that has IPv6 and no IPv4 (= ipv6 handle is used) and that has more > entries than the IPv4 pool size (comparison was done with ipv6.size, > not with actual pool size), introduced by commit 6a8cd033b18. > > While at it, fix pool size calculation for IPv6 pools >= /112 > (too many -1), introduced by commit 452113155e7.
Thanks for taking care of these issues :-) > > Signed-off-by: Gert Doering <g...@greenie.muc.de> > --- > src/openvpn/pool.c | 96 ++++++++++++++++++++-------------------------- > src/openvpn/pool.h | 3 +- > 2 files changed, 42 insertions(+), 57 deletions(-) > > diff --git a/src/openvpn/pool.c b/src/openvpn/pool.c > index 29667623..f60cf291 100644 > --- a/src/openvpn/pool.c > +++ b/src/openvpn/pool.c > @@ -59,29 +59,6 @@ ifconfig_pool_entry_free(struct ifconfig_pool_entry *ipe, > bool hard) > } > } > > -static const int > -ifconfig_pool_size(const struct ifconfig_pool *pool) > -{ > - int min = INT_MAX; > - > - if (!pool || (!pool->ipv4.enabled && !pool->ipv6.enabled)) > - { > - return 0; > - } > - > - if (pool->ipv4.enabled) > - { > - min = pool->ipv4.size; > - } > - > - if (pool->ipv6.enabled && pool->ipv6.size < min) > - { > - min = pool->ipv6.size; > - } > - > - return min; > -} > - > static int > ifconfig_pool_find(struct ifconfig_pool *pool, const char *common_name) > { > @@ -89,9 +66,8 @@ ifconfig_pool_find(struct ifconfig_pool *pool, const char > *common_name) > time_t earliest_release = 0; > int previous_usage = -1; > int new_usage = -1; > - int pool_size = ifconfig_pool_size(pool); > > - for (i = 0; i < pool_size; ++i) > + for (i = 0; i < pool->size; ++i) > { > struct ifconfig_pool_entry *ipe = &pool->list[i]; > if (!ipe->in_use) > @@ -179,12 +155,13 @@ ifconfig_pool_init(const bool ipv4_pool, enum pool_type > type, in_addr_t start, > { > struct gc_arena gc = gc_new(); > struct ifconfig_pool *pool = NULL; > - int pool_size = -1; > + int pool_ipv4_size = -1, pool_ipv6_size = -1; > > ASSERT(start <= end && end - start < IFCONFIG_POOL_MAX); > ALLOC_OBJ_CLEAR(pool, struct ifconfig_pool); > > pool->duplicate_cn = duplicate_cn; > + pool->size = 0; This is not needed. The object is already cleared out after allocation by the ALLOC_OBJ_CLEAR() macro. > > pool->ipv4.enabled = ipv4_pool; > > @@ -195,26 +172,28 @@ ifconfig_pool_init(const bool ipv4_pool, enum pool_type > type, in_addr_t start, > { > case IFCONFIG_POOL_30NET: > pool->ipv4.base = start & ~3; > - pool->ipv4.size = (((end | 3) + 1) - pool->ipv4.base) >> 2; > + pool_ipv4_size = (((end | 3) + 1) - pool->ipv4.base) >> 2; > break; > > case IFCONFIG_POOL_INDIV: > pool->ipv4.base = start; > - pool->ipv4.size = end - start + 1; > + pool_ipv4_size = end - start + 1; > break; > > default: > ASSERT(0); > } > > - if (pool->ipv4.size < 2) > + if (pool_ipv4_size < 2) > { > msg(M_FATAL, "IPv4 pool size is too small (%d), must be at least > 2", > - pool->ipv4.size); > + pool_ipv4_size); > } > > msg(D_IFCONFIG_POOL, "IFCONFIG POOL IPv4: base=%s size=%d", > - print_in_addr_t(pool->ipv4.base, 0, &gc), pool->ipv4.size); > + print_in_addr_t(pool->ipv4.base, 0, &gc), pool_ipv4_size); > + > + pool->size = pool_ipv4_size; > } > > /* IPv6 pools are always "INDIV" type */ > @@ -239,49 +218,57 @@ ifconfig_pool_init(const bool ipv4_pool, enum pool_type > type, in_addr_t start, > * the address. > * > * Example: if we have netbits=31, the first bit has to be > zero'd, > - * the following operation first computes off=0x3fffff and then > uses > - * mask to extract the wanted bits from base > + * the following operation first computes mask=0x3fffff and then > + * uses mask to extract the wanted bits from base > */ > - uint32_t mask = (1 << (128 - ipv6_netbits - 1)) - 1; > + uint32_t mask = (1 << (128 - ipv6_netbits) ) - 1; please remove the space between the 2 parenthesis. The computation now looks correct :-) > base &= mask; > } > > pool->ipv6.base = ipv6_base; > - pool->ipv6.size = ipv6_netbits > 112 > + pool_ipv6_size = ipv6_netbits >= 112 > ? (1 << (128 - ipv6_netbits)) - base > : IFCONFIG_POOL_MAX; > > - if (pool->ipv6.size < 2) > + if (pool_ipv6_size < 2) > { > msg(M_FATAL, "IPv6 pool size is too small (%d), must be at least > 2", > - pool->ipv6.size); > + pool_ipv6_size); > } > > msg(D_IFCONFIG_POOL, "IFCONFIG POOL IPv6: base=%s size=%d > netbits=%d", > - print_in6_addr(pool->ipv6.base, 0, &gc), pool->ipv6.size, > + print_in6_addr(pool->ipv6.base, 0, &gc), pool_ipv6_size, > ipv6_netbits); > + > + /* if there is no v4 pool, or the v6 pool is smaller, use > + * v6 pool size as "unified pool size" > + */ > + if ( pool->size <= 0 || pool_ipv6_size < pool->size ) please remove the spaces after the opening and before the closing parenthesis. > + { > + pool->size = pool_ipv6_size; > + } > } > > if (pool->ipv4.enabled && pool->ipv6.enabled) > { > - if (pool->ipv4.size < pool->ipv6.size) > + if (pool_ipv4_size < pool_ipv6_size) > { > msg(M_INFO, "NOTE: IPv4 pool size is %d, IPv6 pool size is %d. " > "IPv4 pool size limits the number of clients that can be " > - "served from the pool", pool->ipv4.size, pool->ipv6.size); > + "served from the pool", pool_ipv4_size, pool_ipv6_size); > } > - else if (pool->ipv4.size > pool->ipv6.size) > + else if (pool_ipv4_size > pool_ipv6_size) > { > msg(M_WARN, "WARNING: IPv4 pool size is %d, IPv6 pool size is > %d. " > "IPv6 pool size limits the number of clients that can be " > "served from the pool. This is likely a MISTAKE - please > check " > - "your configuration", pool->ipv4.size, pool->ipv6.size); > + "your configuration", pool_ipv4_size, pool_ipv6_size); > } > } > > - pool_size = ifconfig_pool_size(pool); > + ASSERT(pool->size>0); please add spaces around the '>' operator. Asserting it sounds good - this happens during initialization and it's ok to abort in that case. However, we don't expect this to happen unless this function is misused by new code. > > - ALLOC_ARRAY_CLEAR(pool->list, struct ifconfig_pool_entry, pool_size); > + ALLOC_ARRAY_CLEAR(pool->list, struct ifconfig_pool_entry, pool->size); > > gc_free(&gc); > return pool; > @@ -292,9 +279,9 @@ ifconfig_pool_free(struct ifconfig_pool *pool) > { > if (pool) > { > - int i, pool_size = ifconfig_pool_size(pool); > + int i; > > - for (i = 0; i < pool_size; ++i) > + for (i = 0; i < pool->size; ++i) > { > ifconfig_pool_entry_free(&pool->list[i], true); > } > @@ -358,9 +345,8 @@ bool > ifconfig_pool_release(struct ifconfig_pool *pool, ifconfig_pool_handle hand, > const bool hard) > { > bool ret = false; > - int pool_size = ifconfig_pool_size(pool); > > - if (pool && hand >= 0 && hand < pool_size) > + if (pool && hand >= 0 && hand < pool->size) > { > ifconfig_pool_entry_free(&pool->list[hand], hard); > ret = true; > @@ -396,7 +382,7 @@ ifconfig_pool_ip_base_to_handle(const struct > ifconfig_pool *pool, const in_addr_ > ASSERT(0); > } > > - if (ret < 0 || ret >= pool->ipv4.size) > + if (ret < 0 || ret >= pool->size) > { > ret = -1; > } > @@ -436,7 +422,7 @@ ifconfig_pool_ipv6_base_to_handle(const struct > ifconfig_pool *pool, > | in_addr->s6_addr[15]; > > ret = addr - base; > - if (ret < 0 || ret >= pool->ipv6.size) > + if (ret < 0 || ret >= pool->size) > { > ret = -1; > } > @@ -449,7 +435,7 @@ ifconfig_pool_handle_to_ip_base(const struct > ifconfig_pool *pool, ifconfig_pool_ > { > in_addr_t ret = 0; > > - if (pool->ipv4.enabled && hand >= 0 && hand < pool->ipv4.size) > + if (pool->ipv4.enabled && hand >= 0 && hand < pool->size) > { > switch (pool->ipv4.type) > { > @@ -479,7 +465,7 @@ ifconfig_pool_handle_to_ipv6_base(const struct > ifconfig_pool *pool, ifconfig_poo > struct in6_addr ret = IN6ADDR_ANY_INIT; > > /* IPv6 pools are always INDIV (--linear) */ > - if (pool->ipv6.enabled && hand >= 0 && hand < pool->ipv6.size) > + if (pool->ipv6.enabled && hand >= 0 && hand < pool->size) > { > ret = add_in6_addr( pool->ipv6.base, hand ); > } > @@ -504,9 +490,9 @@ ifconfig_pool_list(const struct ifconfig_pool *pool, > struct status_output *out) > if (pool && out) > { > struct gc_arena gc = gc_new(); > - int i, pool_size = ifconfig_pool_size(pool); > + int i; > > - for (i = 0; i < pool_size; ++i) > + for (i = 0; i < pool->size; ++i) > { > const struct ifconfig_pool_entry *e = &pool->list[i]; > struct in6_addr ip6; > @@ -720,7 +706,7 @@ ifconfig_pool_read(struct ifconfig_pool_persist *persist, > struct ifconfig_pool * > */ > if (h >= 0) > { > - msg(M_INFO, "succeeded -> ifconfig_pool_set()"); > + msg(M_INFO, "succeeded -> ifconfig_pool_set(hand=%d)",h); > ifconfig_pool_set(pool, cn_buf, h, persist->fixed); > } > } > diff --git a/src/openvpn/pool.h b/src/openvpn/pool.h > index 6af04645..b06424c9 100644 > --- a/src/openvpn/pool.h > +++ b/src/openvpn/pool.h > @@ -55,13 +55,12 @@ struct ifconfig_pool > bool enabled; > enum pool_type type; > in_addr_t base; > - int size; > } ipv4; > struct { > bool enabled; > struct in6_addr base; > - unsigned int size; > } ipv6; > + int size; > struct ifconfig_pool_entry *list; > }; > > The rest looks good, thanks! I am ACKing this patch under the assumption that those little changes are applied before merging: Acked-by: Antonio Quartulli <a...@unstable.cc> -- Antonio Quartulli _______________________________________________ Openvpn-devel mailing list Openvpn-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openvpn-devel