Skip to content

Commit 791a615

Browse files
Florian Westphalummakynes
authored andcommitted
netfilter: nf_set_pipapo: fix initial map fill
The initial buffer has to be inited to all-ones, but it must restrict it to the size of the first field, not the total field size. After each round in the map search step, the result and the fill map are swapped, so if we have a set where f->bsize of the first element is smaller than m->bsize_max, those one-bits are leaked into future rounds result map. This makes pipapo find an incorrect matching results for sets where first field size is not the largest. Followup patch adds a test case to nft_concat_range.sh selftest script. Thanks to Stefano Brivio for pointing out that we need to zero out the remainder explicitly, only correcting memset() argument isn't enough. Fixes: 3c4287f ("nf_tables: Add set type for arbitrary concatenation of ranges") Reported-by: Yi Chen <[email protected]> Cc: Stefano Brivio <[email protected]> Signed-off-by: Florian Westphal <[email protected]> Reviewed-by: Stefano Brivio <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent 7821618 commit 791a615

File tree

3 files changed

+29
-6
lines changed

3 files changed

+29
-6
lines changed

net/netfilter/nft_set_pipapo.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ bool nft_pipapo_lookup(const struct net *net, const struct nft_set *set,
434434
res_map = scratch->map + (map_index ? m->bsize_max : 0);
435435
fill_map = scratch->map + (map_index ? 0 : m->bsize_max);
436436

437-
memset(res_map, 0xff, m->bsize_max * sizeof(*res_map));
437+
pipapo_resmap_init(m, res_map);
438438

439439
nft_pipapo_for_each_field(f, i, m) {
440440
bool last = i == m->field_count - 1;
@@ -542,7 +542,7 @@ static struct nft_pipapo_elem *pipapo_get(const struct net *net,
542542
goto out;
543543
}
544544

545-
memset(res_map, 0xff, m->bsize_max * sizeof(*res_map));
545+
pipapo_resmap_init(m, res_map);
546546

547547
nft_pipapo_for_each_field(f, i, m) {
548548
bool last = i == m->field_count - 1;

net/netfilter/nft_set_pipapo.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,4 +278,25 @@ static u64 pipapo_estimate_size(const struct nft_set_desc *desc)
278278
return size;
279279
}
280280

281+
/**
282+
* pipapo_resmap_init() - Initialise result map before first use
283+
* @m: Matching data, including mapping table
284+
* @res_map: Result map
285+
*
286+
* Initialize all bits covered by the first field to one, so that after
287+
* the first step, only the matching bits of the first bit group remain.
288+
*
289+
* If other fields have a large bitmap, set remainder of res_map to 0.
290+
*/
291+
static inline void pipapo_resmap_init(const struct nft_pipapo_match *m, unsigned long *res_map)
292+
{
293+
const struct nft_pipapo_field *f = m->f;
294+
int i;
295+
296+
for (i = 0; i < f->bsize; i++)
297+
res_map[i] = ULONG_MAX;
298+
299+
for (i = f->bsize; i < m->bsize_max; i++)
300+
res_map[i] = 0ul;
301+
}
281302
#endif /* _NFT_SET_PIPAPO_H */

net/netfilter/nft_set_pipapo_avx2.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,6 +1036,7 @@ static int nft_pipapo_avx2_lookup_8b_16(unsigned long *map, unsigned long *fill,
10361036

10371037
/**
10381038
* nft_pipapo_avx2_lookup_slow() - Fallback function for uncommon field sizes
1039+
* @mdata: Matching data, including mapping table
10391040
* @map: Previous match result, used as initial bitmap
10401041
* @fill: Destination bitmap to be filled with current match result
10411042
* @f: Field, containing lookup and mapping tables
@@ -1051,7 +1052,8 @@ static int nft_pipapo_avx2_lookup_8b_16(unsigned long *map, unsigned long *fill,
10511052
* Return: -1 on no match, rule index of match if @last, otherwise first long
10521053
* word index to be checked next (i.e. first filled word).
10531054
*/
1054-
static int nft_pipapo_avx2_lookup_slow(unsigned long *map, unsigned long *fill,
1055+
static int nft_pipapo_avx2_lookup_slow(const struct nft_pipapo_match *mdata,
1056+
unsigned long *map, unsigned long *fill,
10551057
const struct nft_pipapo_field *f,
10561058
int offset, const u8 *pkt,
10571059
bool first, bool last)
@@ -1060,7 +1062,7 @@ static int nft_pipapo_avx2_lookup_slow(unsigned long *map, unsigned long *fill,
10601062
int i, ret = -1, b;
10611063

10621064
if (first)
1063-
memset(map, 0xff, bsize * sizeof(*map));
1065+
pipapo_resmap_init(mdata, map);
10641066

10651067
for (i = offset; i < bsize; i++) {
10661068
if (f->bb == 8)
@@ -1186,7 +1188,7 @@ bool nft_pipapo_avx2_lookup(const struct net *net, const struct nft_set *set,
11861188
} else if (f->groups == 16) {
11871189
NFT_SET_PIPAPO_AVX2_LOOKUP(8, 16);
11881190
} else {
1189-
ret = nft_pipapo_avx2_lookup_slow(res, fill, f,
1191+
ret = nft_pipapo_avx2_lookup_slow(m, res, fill, f,
11901192
ret, rp,
11911193
first, last);
11921194
}
@@ -1202,7 +1204,7 @@ bool nft_pipapo_avx2_lookup(const struct net *net, const struct nft_set *set,
12021204
} else if (f->groups == 32) {
12031205
NFT_SET_PIPAPO_AVX2_LOOKUP(4, 32);
12041206
} else {
1205-
ret = nft_pipapo_avx2_lookup_slow(res, fill, f,
1207+
ret = nft_pipapo_avx2_lookup_slow(m, res, fill, f,
12061208
ret, rp,
12071209
first, last);
12081210
}

0 commit comments

Comments
 (0)