Skip to content

Commit cff088d

Browse files
author
Paolo Abeni
committed
Merge tag 'nf-23-11-15' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf
Pablo Neira Ayuso says: ==================== Netfilter fixes for net The following patchset contains Netfilter fixes for net: 1) Remove unused variable causing compilation warning in nft_set_rbtree, from Yang Li. This unused variable is a left over from previous merge window. 2) Possible return of uninitialized in nf_conntrack_bridge, from Linkui Xiao. This is there since nf_conntrack_bridge is available. 3) Fix incorrect pointer math in nft_byteorder, from Dan Carpenter. Problem has been there since 2016. 4) Fix bogus error in destroy set element command. Problem is there since this new destroy command was added. 5) Fix race condition in ipset between swap and destroy commands and add/del/test control plane. This problem is there since ipset was merged. 6) Split async and sync catchall GC in two function to fix unsafe iteration over RCU. This is a fix-for-fix that was included in the previous pull request. * tag 'nf-23-11-15' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf: netfilter: nf_tables: split async and sync catchall in two functions netfilter: ipset: fix race condition between swap/destroy and kernel side add/del/test netfilter: nf_tables: bogus ENOENT when destroying element which does not exist netfilter: nf_tables: fix pointer math issue in nft_byteorder_eval() netfilter: nf_conntrack_bridge: initialize err to 0 netfilter: nft_set_rbtree: Remove unused variable nft_net ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
2 parents 7e1caea + 8837ba3 commit cff088d

File tree

7 files changed

+47
-42
lines changed

7 files changed

+47
-42
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,9 @@ static inline __be32 nft_reg_load_be32(const u32 *sreg)
178178
return *(__force __be32 *)sreg;
179179
}
180180

181-
static inline void nft_reg_store64(u32 *dreg, u64 val)
181+
static inline void nft_reg_store64(u64 *dreg, u64 val)
182182
{
183-
put_unaligned(val, (u64 *)dreg);
183+
put_unaligned(val, dreg);
184184
}
185185

186186
static inline u64 nft_reg_load64(const u32 *sreg)

net/bridge/netfilter/nf_conntrack_bridge.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ static int nf_br_ip_fragment(struct net *net, struct sock *sk,
3737
ktime_t tstamp = skb->tstamp;
3838
struct ip_frag_state state;
3939
struct iphdr *iph;
40-
int err;
40+
int err = 0;
4141

4242
/* for offloaded checksums cleanup checksum before fragmentation */
4343
if (skb->ip_summed == CHECKSUM_PARTIAL &&

net/netfilter/ipset/ip_set_core.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_IPSET);
6161
ip_set_dereference((inst)->ip_set_list)[id]
6262
#define ip_set_ref_netlink(inst,id) \
6363
rcu_dereference_raw((inst)->ip_set_list)[id]
64+
#define ip_set_dereference_nfnl(p) \
65+
rcu_dereference_check(p, lockdep_nfnl_is_held(NFNL_SUBSYS_IPSET))
6466

6567
/* The set types are implemented in modules and registered set types
6668
* can be found in ip_set_type_list. Adding/deleting types is
@@ -708,15 +710,10 @@ __ip_set_put_netlink(struct ip_set *set)
708710
static struct ip_set *
709711
ip_set_rcu_get(struct net *net, ip_set_id_t index)
710712
{
711-
struct ip_set *set;
712713
struct ip_set_net *inst = ip_set_pernet(net);
713714

714-
rcu_read_lock();
715-
/* ip_set_list itself needs to be protected */
716-
set = rcu_dereference(inst->ip_set_list)[index];
717-
rcu_read_unlock();
718-
719-
return set;
715+
/* ip_set_list and the set pointer need to be protected */
716+
return ip_set_dereference_nfnl(inst->ip_set_list)[index];
720717
}
721718

722719
static inline void
@@ -1397,6 +1394,9 @@ static int ip_set_swap(struct sk_buff *skb, const struct nfnl_info *info,
13971394
ip_set(inst, to_id) = from;
13981395
write_unlock_bh(&ip_set_ref_lock);
13991396

1397+
/* Make sure all readers of the old set pointers are completed. */
1398+
synchronize_rcu();
1399+
14001400
return 0;
14011401
}
14021402

net/netfilter/nf_tables_api.c

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7263,10 +7263,11 @@ static int nf_tables_delsetelem(struct sk_buff *skb,
72637263

72647264
if (err < 0) {
72657265
NL_SET_BAD_ATTR(extack, attr);
7266-
break;
7266+
return err;
72677267
}
72687268
}
7269-
return err;
7269+
7270+
return 0;
72707271
}
72717272

72727273
/*
@@ -9679,16 +9680,14 @@ void nft_trans_gc_queue_sync_done(struct nft_trans_gc *trans)
96799680
call_rcu(&trans->rcu, nft_trans_gc_trans_free);
96809681
}
96819682

9682-
static struct nft_trans_gc *nft_trans_gc_catchall(struct nft_trans_gc *gc,
9683-
unsigned int gc_seq,
9684-
bool sync)
9683+
struct nft_trans_gc *nft_trans_gc_catchall_async(struct nft_trans_gc *gc,
9684+
unsigned int gc_seq)
96859685
{
9686-
struct nft_set_elem_catchall *catchall, *next;
9686+
struct nft_set_elem_catchall *catchall;
96879687
const struct nft_set *set = gc->set;
9688-
struct nft_elem_priv *elem_priv;
96899688
struct nft_set_ext *ext;
96909689

9691-
list_for_each_entry_safe(catchall, next, &set->catchall_list, list) {
9690+
list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
96929691
ext = nft_set_elem_ext(set, catchall->elem);
96939692

96949693
if (!nft_set_elem_expired(ext))
@@ -9698,35 +9697,42 @@ static struct nft_trans_gc *nft_trans_gc_catchall(struct nft_trans_gc *gc,
96989697

96999698
nft_set_elem_dead(ext);
97009699
dead_elem:
9701-
if (sync)
9702-
gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC);
9703-
else
9704-
gc = nft_trans_gc_queue_async(gc, gc_seq, GFP_ATOMIC);
9705-
9700+
gc = nft_trans_gc_queue_async(gc, gc_seq, GFP_ATOMIC);
97069701
if (!gc)
97079702
return NULL;
97089703

9709-
elem_priv = catchall->elem;
9710-
if (sync) {
9711-
nft_setelem_data_deactivate(gc->net, gc->set, elem_priv);
9712-
nft_setelem_catchall_destroy(catchall);
9713-
}
9714-
9715-
nft_trans_gc_elem_add(gc, elem_priv);
9704+
nft_trans_gc_elem_add(gc, catchall->elem);
97169705
}
97179706

97189707
return gc;
97199708
}
97209709

9721-
struct nft_trans_gc *nft_trans_gc_catchall_async(struct nft_trans_gc *gc,
9722-
unsigned int gc_seq)
9723-
{
9724-
return nft_trans_gc_catchall(gc, gc_seq, false);
9725-
}
9726-
97279710
struct nft_trans_gc *nft_trans_gc_catchall_sync(struct nft_trans_gc *gc)
97289711
{
9729-
return nft_trans_gc_catchall(gc, 0, true);
9712+
struct nft_set_elem_catchall *catchall, *next;
9713+
const struct nft_set *set = gc->set;
9714+
struct nft_elem_priv *elem_priv;
9715+
struct nft_set_ext *ext;
9716+
9717+
WARN_ON_ONCE(!lockdep_commit_lock_is_held(gc->net));
9718+
9719+
list_for_each_entry_safe(catchall, next, &set->catchall_list, list) {
9720+
ext = nft_set_elem_ext(set, catchall->elem);
9721+
9722+
if (!nft_set_elem_expired(ext))
9723+
continue;
9724+
9725+
gc = nft_trans_gc_queue_sync(gc, GFP_KERNEL);
9726+
if (!gc)
9727+
return NULL;
9728+
9729+
elem_priv = catchall->elem;
9730+
nft_setelem_data_deactivate(gc->net, gc->set, elem_priv);
9731+
nft_setelem_catchall_destroy(catchall);
9732+
nft_trans_gc_elem_add(gc, elem_priv);
9733+
}
9734+
9735+
return gc;
97309736
}
97319737

97329738
static void nf_tables_module_autoload_cleanup(struct net *net)

net/netfilter/nft_byteorder.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,21 +38,22 @@ void nft_byteorder_eval(const struct nft_expr *expr,
3838

3939
switch (priv->size) {
4040
case 8: {
41+
u64 *dst64 = (void *)dst;
4142
u64 src64;
4243

4344
switch (priv->op) {
4445
case NFT_BYTEORDER_NTOH:
4546
for (i = 0; i < priv->len / 8; i++) {
4647
src64 = nft_reg_load64(&src[i]);
47-
nft_reg_store64(&dst[i],
48+
nft_reg_store64(&dst64[i],
4849
be64_to_cpu((__force __be64)src64));
4950
}
5051
break;
5152
case NFT_BYTEORDER_HTON:
5253
for (i = 0; i < priv->len / 8; i++) {
5354
src64 = (__force __u64)
5455
cpu_to_be64(nft_reg_load64(&src[i]));
55-
nft_reg_store64(&dst[i], src64);
56+
nft_reg_store64(&dst64[i], src64);
5657
}
5758
break;
5859
}

net/netfilter/nft_meta.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ nft_meta_get_eval_time(enum nft_meta_keys key,
6363
{
6464
switch (key) {
6565
case NFT_META_TIME_NS:
66-
nft_reg_store64(dest, ktime_get_real_ns());
66+
nft_reg_store64((u64 *)dest, ktime_get_real_ns());
6767
break;
6868
case NFT_META_TIME_DAY:
6969
nft_reg_store8(dest, nft_meta_weekday());

net/netfilter/nft_set_rbtree.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -624,14 +624,12 @@ static void nft_rbtree_gc(struct nft_set *set)
624624
{
625625
struct nft_rbtree *priv = nft_set_priv(set);
626626
struct nft_rbtree_elem *rbe, *rbe_end = NULL;
627-
struct nftables_pernet *nft_net;
628627
struct rb_node *node, *next;
629628
struct nft_trans_gc *gc;
630629
struct net *net;
631630

632631
set = nft_set_container_of(priv);
633632
net = read_pnet(&set->net);
634-
nft_net = nft_pernet(net);
635633

636634
gc = nft_trans_gc_alloc(set, 0, GFP_KERNEL);
637635
if (!gc)

0 commit comments

Comments
 (0)