summaryrefslogtreecommitdiff
path: root/net/netfilter
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-08-07 08:08:57 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-08-07 08:08:57 -0700
commita13307e97d5c54b65720bb71fa379960ded1e51a (patch)
tree2bda666bf91053890eac256d9d69236c08d80cdd /net/netfilter
parent0150da6be1c71cd0ad9262293971cb9ea371672b (diff)
parent7a3c0289c3c8eb4607dff448ae9ff9f902c813af (diff)
Merge tag 'bpf-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf
Pull BPF fixes from Daniel Borkmann: - Fix BPF verifier to preserve full pointer state for commuted scalar += pointer arithmetic (Yiyang Chen, Eduard Zingerman) - Fix a use-after-free of request sockets in the BPF TCP iterator batching (Jose Fernandez) - Fix a use-after-free of sk_redir in the BPF sockmap send verdict path (Chengfeng Ye) - Fix a netns reference imbalance in the BPF conntrack kfuncs (Chengfeng Ye) - Fix bpf_get_fsverity_digest() dynptr assumptions and silent digest truncation (Eric Biggers) - Fix bpf_tcp_{gen,check}_syncookie to check sk_state before sk_protocol to make sure it is a full socket (Luxiao Xu) - Fix rqspinlock to reset the tail when preserving the queue on deadlock (Kumar Kartikeya Dwivedi) * tag 'bpf-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf: rqspinlock: Reset tail when preserving queue on deadlock bpf: Check sk_state before sk_protocol in bpf_tcp_*_syncookie fsverity: Fix silent truncation in bpf_get_fsverity_digest() fsverity: Fix bpf_get_fsverity_digest() dynptr assumptions bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch() bpf: Fix netns reference imbalance in conntrack kfuncs bpf, sockmap: Fix sk_redir use-after-free in send verdict selftests/bpf: Cover commuted pointer state propagation bpf: Propagate untrusted pointer state in commuted arithmetic bpf: Preserve pointer state for commuted arithmetic bpf: Simplify sanitize_err() signature
Diffstat (limited to 'net/netfilter')
-rw-r--r--net/netfilter/nf_conntrack_bpf.c72
1 files changed, 48 insertions, 24 deletions
diff --git a/net/netfilter/nf_conntrack_bpf.c b/net/netfilter/nf_conntrack_bpf.c
index f98d1d4b42c3..c2df7c948281 100644
--- a/net/netfilter/nf_conntrack_bpf.c
+++ b/net/netfilter/nf_conntrack_bpf.c
@@ -122,42 +122,54 @@ __bpf_nf_ct_alloc_entry(struct net *net, struct bpf_sock_tuple *bpf_tuple,
struct nf_conntrack_tuple otuple, rtuple;
struct nf_conntrack_zone ct_zone;
struct nf_conn *ct;
+ u8 ct_zone_dir = 0;
+ u16 ct_zone_id;
+ s32 netns_id;
+ u8 l4proto;
int err;
if (!(opts_len == NF_BPF_CT_OPTS_SZ || opts_len == 12))
return ERR_PTR(-EINVAL);
+
+ netns_id = READ_ONCE(opts->netns_id);
+ l4proto = READ_ONCE(opts->l4proto);
+ ct_zone_id = READ_ONCE(opts->ct_zone_id);
if (opts_len == NF_BPF_CT_OPTS_SZ) {
- if (opts->reserved[0] || opts->reserved[1] || opts->reserved[2])
+ ct_zone_dir = READ_ONCE(opts->ct_zone_dir);
+ if (READ_ONCE(opts->reserved[0]) ||
+ READ_ONCE(opts->reserved[1]) ||
+ READ_ONCE(opts->reserved[2]))
return ERR_PTR(-EINVAL);
} else {
- if (opts->ct_zone_id)
+ if (ct_zone_id)
return ERR_PTR(-EINVAL);
}
- if (unlikely(opts->netns_id < BPF_F_CURRENT_NETNS))
+ if (unlikely(netns_id < BPF_F_CURRENT_NETNS))
return ERR_PTR(-EINVAL);
- err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, opts->l4proto,
+ err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, l4proto,
IP_CT_DIR_ORIGINAL, &otuple);
if (err < 0)
return ERR_PTR(err);
- err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, opts->l4proto,
+ err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, l4proto,
IP_CT_DIR_REPLY, &rtuple);
if (err < 0)
return ERR_PTR(err);
- if (opts->netns_id >= 0) {
- net = get_net_ns_by_id(net, opts->netns_id);
+ if (netns_id >= 0) {
+ net = get_net_ns_by_id(net, netns_id);
if (unlikely(!net))
return ERR_PTR(-ENONET);
}
if (opts_len == NF_BPF_CT_OPTS_SZ) {
- if (opts->ct_zone_dir == 0)
- opts->ct_zone_dir = NF_CT_DEFAULT_ZONE_DIR;
- nf_ct_zone_init(&ct_zone,
- opts->ct_zone_id, opts->ct_zone_dir, 0);
+ if (ct_zone_dir == 0) {
+ ct_zone_dir = NF_CT_DEFAULT_ZONE_DIR;
+ opts->ct_zone_dir = ct_zone_dir;
+ }
+ nf_ct_zone_init(&ct_zone, ct_zone_id, ct_zone_dir, 0);
} else {
ct_zone = nf_ct_zone_dflt;
}
@@ -171,7 +183,7 @@ __bpf_nf_ct_alloc_entry(struct net *net, struct bpf_sock_tuple *bpf_tuple,
__nf_ct_set_timeout(ct, timeout * HZ);
out:
- if (opts->netns_id >= 0)
+ if (netns_id >= 0)
put_net(net);
return ct;
@@ -186,46 +198,58 @@ static struct nf_conn *__bpf_nf_ct_lookup(struct net *net,
struct nf_conntrack_tuple tuple;
struct nf_conntrack_zone ct_zone;
struct nf_conn *ct;
+ u8 ct_zone_dir = 0;
+ u16 ct_zone_id;
+ s32 netns_id;
+ u8 l4proto;
int err;
if (!opts || !bpf_tuple)
return ERR_PTR(-EINVAL);
if (!(opts_len == NF_BPF_CT_OPTS_SZ || opts_len == 12))
return ERR_PTR(-EINVAL);
+
+ netns_id = READ_ONCE(opts->netns_id);
+ l4proto = READ_ONCE(opts->l4proto);
+ ct_zone_id = READ_ONCE(opts->ct_zone_id);
if (opts_len == NF_BPF_CT_OPTS_SZ) {
- if (opts->reserved[0] || opts->reserved[1] || opts->reserved[2])
+ ct_zone_dir = READ_ONCE(opts->ct_zone_dir);
+ if (READ_ONCE(opts->reserved[0]) ||
+ READ_ONCE(opts->reserved[1]) ||
+ READ_ONCE(opts->reserved[2]))
return ERR_PTR(-EINVAL);
} else {
- if (opts->ct_zone_id)
+ if (ct_zone_id)
return ERR_PTR(-EINVAL);
}
- if (unlikely(opts->l4proto != IPPROTO_TCP && opts->l4proto != IPPROTO_UDP))
+ if (unlikely(l4proto != IPPROTO_TCP && l4proto != IPPROTO_UDP))
return ERR_PTR(-EPROTO);
- if (unlikely(opts->netns_id < BPF_F_CURRENT_NETNS))
+ if (unlikely(netns_id < BPF_F_CURRENT_NETNS))
return ERR_PTR(-EINVAL);
- err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, opts->l4proto,
+ err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, l4proto,
IP_CT_DIR_ORIGINAL, &tuple);
if (err < 0)
return ERR_PTR(err);
- if (opts->netns_id >= 0) {
- net = get_net_ns_by_id(net, opts->netns_id);
+ if (netns_id >= 0) {
+ net = get_net_ns_by_id(net, netns_id);
if (unlikely(!net))
return ERR_PTR(-ENONET);
}
if (opts_len == NF_BPF_CT_OPTS_SZ) {
- if (opts->ct_zone_dir == 0)
- opts->ct_zone_dir = NF_CT_DEFAULT_ZONE_DIR;
- nf_ct_zone_init(&ct_zone,
- opts->ct_zone_id, opts->ct_zone_dir, 0);
+ if (ct_zone_dir == 0) {
+ ct_zone_dir = NF_CT_DEFAULT_ZONE_DIR;
+ opts->ct_zone_dir = ct_zone_dir;
+ }
+ nf_ct_zone_init(&ct_zone, ct_zone_id, ct_zone_dir, 0);
} else {
ct_zone = nf_ct_zone_dflt;
}
hash = nf_conntrack_find_get(net, &ct_zone, &tuple);
- if (opts->netns_id >= 0)
+ if (netns_id >= 0)
put_net(net);
if (!hash)
return ERR_PTR(-ENOENT);