Re: [PATCH] netfilter: ipset: ipset list may return wrong member count on bitmap types

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 7/12/22 17:06, Jozsef Kadlecsik wrote:
> Hi Vishwanath,
> 
> On Wed, 29 Jun 2022, Vishwanath Pai wrote:
> 
>> We fixed a similar problem before in commit 7f4f7dd4417d ("netfilter:
>> ipset: ipset list may return wrong member count for set with timeout").
>> The same issue exists in ip_set_bitmap_gen.h as well.
> 
> Could you rework the patch to solve the issue the same way as for the hash 
> types (i.e. scanning the set without locking) like in the commit 
> 33f08da28324 (netfilter: ipset: Fix "INFO: rcu detected stall in hash_xxx" 
> reports)? I know the bitmap types have got a limited size but it'd be 
> great if the general method would be the same across the different types.
> 
> Best regards,
> Jozsef
>  
>> Test case:
>>
>> $ ipset create test bitmap:ip range 10.0.0.0/8 netmask 24 timeout 5
>> $ ipset add test 10.0.0.0
>> $ ipset add test 10.255.255.255
>> $ sleep 5s
>>
>> $ ipset list test
>> Name: test
>> Type: bitmap:ip
>> Revision: 3
>> Header: range 10.0.0.0-10.255.255.255 netmask 24 timeout 5
>> Size in memory: 532568
>> References: 0
>> Number of entries: 2
>> Members:
>>
>> We return "Number of entries: 2" but no members are listed. That is
>> because when we run mtype_head the garbage collector hasn't run yet, but
>> mtype_list checks and cleans up members with expired timeout. To avoid
>> this we can run mtype_expire before printing the number of elements in
>> mytype_head().
>>
>> Reviewed-by: Joshua Hunt <johunt@xxxxxxxxxx>
>> Signed-off-by: Vishwanath Pai <vpai@xxxxxxxxxx>
>> ---
>>  net/netfilter/ipset/ip_set_bitmap_gen.h | 46 ++++++++++++++++++-------
>>  1 file changed, 34 insertions(+), 12 deletions(-)
>>
>> diff --git a/net/netfilter/ipset/ip_set_bitmap_gen.h b/net/netfilter/ipset/ip_set_bitmap_gen.h
>> index 26ab0e9612d8..dd871305bd6e 100644
>> --- a/net/netfilter/ipset/ip_set_bitmap_gen.h
>> +++ b/net/netfilter/ipset/ip_set_bitmap_gen.h
>> @@ -28,6 +28,7 @@
>>  #define mtype_del		IPSET_TOKEN(MTYPE, _del)
>>  #define mtype_list		IPSET_TOKEN(MTYPE, _list)
>>  #define mtype_gc		IPSET_TOKEN(MTYPE, _gc)
>> +#define mtype_expire		IPSET_TOKEN(MTYPE, _expire)
>>  #define mtype			MTYPE
>>  
>>  #define get_ext(set, map, id)	((map)->extensions + ((set)->dsize * (id)))
>> @@ -88,13 +89,44 @@ mtype_memsize(const struct mtype *map, size_t dsize)
>>  	       map->elements * dsize;
>>  }
>>  
>> +/* We should grab set->lock before calling this function */
>> +static void
>> +mtype_expire(struct ip_set *set)
>> +{
>> +	struct mtype *map = set->data;
>> +	void *x;
>> +	u32 id;
>> +
>> +	for (id = 0; id < map->elements; id++)
>> +		if (mtype_gc_test(id, map, set->dsize)) {
>> +			x = get_ext(set, map, id);
>> +			if (ip_set_timeout_expired(ext_timeout(x, set))) {
>> +				clear_bit(id, map->members);
>> +				ip_set_ext_destroy(set, x);
>> +				set->elements--;
>> +			}
>> +		}
>> +}
>> +
>>  static int
>>  mtype_head(struct ip_set *set, struct sk_buff *skb)
>>  {
>>  	const struct mtype *map = set->data;
>>  	struct nlattr *nested;
>> -	size_t memsize = mtype_memsize(map, set->dsize) + set->ext_size;
>> +	size_t memsize;
>> +
>> +	/* If any members have expired, set->elements will be wrong,
>> +	 * mytype_expire function will update it with the right count.
>> +	 * set->elements can still be incorrect in the case of a huge set
>> +	 * because elements can timeout during set->list().
>> +	 */
>> +	if (SET_WITH_TIMEOUT(set)) {
>> +		spin_lock_bh(&set->lock);
>> +		mtype_expire(set);
>> +		spin_unlock_bh(&set->lock);
>> +	}
>>  
>> +	memsize = mtype_memsize(map, set->dsize) + set->ext_size;
>>  	nested = nla_nest_start(skb, IPSET_ATTR_DATA);
>>  	if (!nested)
>>  		goto nla_put_failure;
>> @@ -266,22 +298,12 @@ mtype_gc(struct timer_list *t)
>>  {
>>  	struct mtype *map = from_timer(map, t, gc);
>>  	struct ip_set *set = map->set;
>> -	void *x;
>> -	u32 id;
>>  
>>  	/* We run parallel with other readers (test element)
>>  	 * but adding/deleting new entries is locked out
>>  	 */
>>  	spin_lock_bh(&set->lock);
>> -	for (id = 0; id < map->elements; id++)
>> -		if (mtype_gc_test(id, map, set->dsize)) {
>> -			x = get_ext(set, map, id);
>> -			if (ip_set_timeout_expired(ext_timeout(x, set))) {
>> -				clear_bit(id, map->members);
>> -				ip_set_ext_destroy(set, x);
>> -				set->elements--;
>> -			}
>> -		}
>> +	mtype_expire(set);
>>  	spin_unlock_bh(&set->lock);
>>  
>>  	map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;
>> -- 
>> 2.25.1
>>
>>
> 
> -
> E-mail  : kadlec@xxxxxxxxxxxxxxxxx, kadlecsik.jozsef@xxxxxxxxx
> PGP key : https://urldefense.com/v3/__https://wigner.hu/*kadlec/pgp_public_key.txt__;fg!!GjvTz_vk!WmVWx08Jyxg7z7R4rXMUupSXptToGLCMfZ7GhOy1yP_Ty0YQZFSbPbvlocRcFRBnQqy787ijhdI-ig$ 
> Address : Wigner Research Centre for Physics
>           H-1525 Budapest 114, POB. 49, Hungary

Hi Jozsef,

Sure, I'll give it a try. It might take me a bit longer cause it looks like a
complex set of changes.

Thanks,
Vishwanath



[Index of Archives]     [Netfitler Users]     [Berkeley Packet Filter]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux