From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail.netfilter.org (mail.netfilter.org [217.70.190.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C16FE219A91 for ; Tue, 22 Apr 2025 19:53:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.70.190.124 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745351592; cv=none; b=t4YfQuxniStkMAU8ul92ae39fIya0uKArrqpl0jw8ri/94WW1YJG8O16bEL8B2IyngYEojr2hvsk4yIXtmXfnlPpZ3tupf+3kYCj2N/v759JernH4xdqjgX8DC9oBMrap5/sR/Yxae9j2xu6f+MNM9H7H0EhafO6K8D+1MBh9/k= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745351592; c=relaxed/simple; bh=BoXcHRxvemPKi5Vxgl5TerqN9zK/8YMgh6fhGwxjmLg=; h=From:To:Cc:Subject:Date:Message-Id:MIME-Version; b=tQq13fYbqtxI55g1tODLJarDJ7YpGBsr5ytDRkIhdsWf8SEr3JSa7oMRJUoD4JUHkZyEc4CtdGzBpREimP9DaSGukBBv1HZoc6EhyiRKZUwOkCm3dyr8NMtkWbe4V/m4Ojq8vAI3yYiZ8ehF1PTQvv0CNK27TpD4RaV3I7R7Cas= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=netfilter.org; spf=pass smtp.mailfrom=netfilter.org; dkim=pass (2048-bit key) header.d=netfilter.org header.i=@netfilter.org header.b=nHmE7oQF; dkim=pass (2048-bit key) header.d=netfilter.org header.i=@netfilter.org header.b=fWcfE/nc; arc=none smtp.client-ip=217.70.190.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=netfilter.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=netfilter.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=netfilter.org header.i=@netfilter.org header.b="nHmE7oQF"; dkim=pass (2048-bit key) header.d=netfilter.org header.i=@netfilter.org header.b="fWcfE/nc" Received: by mail.netfilter.org (Postfix, from userid 109) id 501CF60911; Tue, 22 Apr 2025 21:53:01 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=netfilter.org; s=2025; t=1745351581; bh=F5cw75YpZKy2MTFRz7EOMDMq8Qfwe3KzCabgx/vXmwo=; h=From:To:Cc:Subject:Date:From; b=nHmE7oQFNV5W6PX5yN1Mzro/Mqvmfh1aAW6LzrsK/GqHm9WR7h0gON3BffKh+fpY5 G/qK3jzvnL5voAQElxbEB2nKUPaCN3bN1/+1vwhSzTIOWkQKEPw/iIwv9BA9quKQlH FIEASTg8CfFw36Z84z4+xbYQ92N7wWTH53gVep2P/JGx1PXnkFep6gerB2tPuCGa31 nx2rlx0k2huL2IoAoIaxkqANMjKmpngGxO843rHwIU98vBqBpCAnY0Z5dTX4V0LfFC cs0VJuhxvzT7KOqqO72PVgLukn9LOk3y46Lxsb6EFNF7PSlfeza5aWhMvSap9q0T1a aKCXNB0ZSAraQ== X-Spam-Level: Received: from localhost.localdomain (mail-agni [217.70.190.124]) by mail.netfilter.org (Postfix) with ESMTPSA id 6F03B60911; Tue, 22 Apr 2025 21:53:00 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=netfilter.org; s=2025; t=1745351580; bh=F5cw75YpZKy2MTFRz7EOMDMq8Qfwe3KzCabgx/vXmwo=; h=From:To:Cc:Subject:Date:From; b=fWcfE/ncERFLwEGbaIWyS8IwTwkYaJQUvi6mXgcDW8RCb+AUu9LqWSgS8FI6ipKxz Uih5EgkatSoCx4HOcp1AS7B3luLEsrW297zs4LinGF9VxZdk6Ws9GzBSmNEzE799n6 XURFh0tlShSMK4sKVKKzqfz8tWyU2vxVdrDm/Sag4KiKnYcGicbrLk8IWUQOVjPTA1 dGSfU2i+WPN1bts8BY5KGrFxjEXL7p9c/KvkDT188ozlffYyJKYgXTduOYjNu7LBiM s8lL0v3csPlgPITRu9hVUOipVsdImrIt5SyecIlhGCRW29CGa2v/nWCrR3hJIUDeED b5kj6mgNVV0zA== From: Pablo Neira Ayuso To: netfilter-devel@vger.kernel.org Cc: sbrivio@redhat.com Subject: [PATCH nf-next,v2 1/2] netfilter: nft_set_pipapo: prevent overflow in lookup table allocation Date: Tue, 22 Apr 2025 21:52:43 +0200 Message-Id: <20250422195244.269803-1-pablo@netfilter.org> X-Mailer: git-send-email 2.30.2 Precedence: bulk X-Mailing-List: netfilter-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit When calculating the lookup table size, ensure the following multiplication does not overflow: - desc->field_len[] maximum value is U8_MAX multiplied by NFT_PIPAPO_GROUPS_PER_BYTE(f) that can be 2, worst case. - NFT_PIPAPO_BUCKETS(f->bb) is 2^8, worst case. - sizeof(unsigned long), from sizeof(*f->lt), lt in struct nft_pipapo_field. Then, use check_mul_overflow() to multiply by bucket size and then use check_add_overflow() to the alignment for avx2 (if needed). Finally, add lt_size_check_overflow() helper and use it to consolidate this. While at it, replace leftover allocation using the GFP_KERNEL to GFP_KERNEL_ACCOUNT for consistency, in pipapo_resize(). Fixes: 3c4287f62044 ("nf_tables: Add set type for arbitrary concatenation of ranges") Signed-off-by: Pablo Neira Ayuso --- v2: changes requested by Stefano. net/netfilter/nft_set_pipapo.c | 58 ++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c index 7be342b495f5..0529e4ef7520 100644 --- a/net/netfilter/nft_set_pipapo.c +++ b/net/netfilter/nft_set_pipapo.c @@ -683,6 +683,30 @@ static int pipapo_realloc_mt(struct nft_pipapo_field *f, return 0; } + +/** + * lt_calculate_size() - Get storage size for lookup table with overflow check + * @groups: Amount of bit groups + * @bb: Number of bits grouped together in lookup table buckets + * @bsize: Size of each bucket in lookup table, in longs + * + * Return: allocation size including alignment overhead, negative on overflow + */ +static ssize_t lt_calculate_size(unsigned int groups, unsigned int bb, + unsigned int bsize) +{ + ssize_t ret = groups * NFT_PIPAPO_BUCKETS(bb) * sizeof(long); + + if (check_mul_overflow(ret, bsize, &ret)) + return -1; + if (check_add_overflow(ret, NFT_PIPAPO_ALIGN_HEADROOM, &ret)) + return -1; + if (ret > INT_MAX) + return -1; + + return ret; +} + /** * pipapo_resize() - Resize lookup or mapping table, or both * @f: Field containing lookup and mapping tables @@ -701,6 +725,7 @@ static int pipapo_resize(struct nft_pipapo_field *f, long *new_lt = NULL, *new_p, *old_lt = f->lt, *old_p; unsigned int new_bucket_size, copy; int group, bucket, err; + ssize_t lt_size; if (rules >= NFT_PIPAPO_RULE0_MAX) return -ENOSPC; @@ -719,10 +744,11 @@ static int pipapo_resize(struct nft_pipapo_field *f, else copy = new_bucket_size; - new_lt = kvzalloc(f->groups * NFT_PIPAPO_BUCKETS(f->bb) * - new_bucket_size * sizeof(*new_lt) + - NFT_PIPAPO_ALIGN_HEADROOM, - GFP_KERNEL); + lt_size = lt_calculate_size(f->groups, f->bb, new_bucket_size); + if (lt_size < 0) + return -ENOMEM; + + new_lt = kvzalloc(lt_size, GFP_KERNEL_ACCOUNT); if (!new_lt) return -ENOMEM; @@ -907,7 +933,7 @@ static void pipapo_lt_bits_adjust(struct nft_pipapo_field *f) { unsigned int groups, bb; unsigned long *new_lt; - size_t lt_size; + ssize_t lt_size; lt_size = f->groups * NFT_PIPAPO_BUCKETS(f->bb) * f->bsize * sizeof(*f->lt); @@ -917,15 +943,17 @@ static void pipapo_lt_bits_adjust(struct nft_pipapo_field *f) groups = f->groups * 2; bb = NFT_PIPAPO_GROUP_BITS_LARGE_SET; - lt_size = groups * NFT_PIPAPO_BUCKETS(bb) * f->bsize * - sizeof(*f->lt); + lt_size = lt_calculate_size(groups, bb, f->bsize); + if (lt_size < 0) + return; } else if (f->bb == NFT_PIPAPO_GROUP_BITS_LARGE_SET && lt_size < NFT_PIPAPO_LT_SIZE_LOW) { groups = f->groups / 2; bb = NFT_PIPAPO_GROUP_BITS_SMALL_SET; - lt_size = groups * NFT_PIPAPO_BUCKETS(bb) * f->bsize * - sizeof(*f->lt); + lt_size = lt_calculate_size(groups, bb, f->bsize); + if (lt_size < 0) + return; /* Don't increase group width if the resulting lookup table size * would exceed the upper size threshold for a "small" set. @@ -936,7 +964,7 @@ static void pipapo_lt_bits_adjust(struct nft_pipapo_field *f) return; } - new_lt = kvzalloc(lt_size + NFT_PIPAPO_ALIGN_HEADROOM, GFP_KERNEL_ACCOUNT); + new_lt = kvzalloc(lt_size, GFP_KERNEL_ACCOUNT); if (!new_lt) return; @@ -1451,13 +1479,15 @@ static struct nft_pipapo_match *pipapo_clone(struct nft_pipapo_match *old) for (i = 0; i < old->field_count; i++) { unsigned long *new_lt; + ssize_t lt_size; memcpy(dst, src, offsetof(struct nft_pipapo_field, lt)); - new_lt = kvzalloc(src->groups * NFT_PIPAPO_BUCKETS(src->bb) * - src->bsize * sizeof(*dst->lt) + - NFT_PIPAPO_ALIGN_HEADROOM, - GFP_KERNEL_ACCOUNT); + lt_size = lt_calculate_size(src->groups, src->bb, src->bsize); + if (lt_size < 0) + goto out_lt; + + new_lt = kvzalloc(lt_size, GFP_KERNEL_ACCOUNT); if (!new_lt) goto out_lt; -- 2.30.2