The conntrack lookup and allocation kfuncs take an opts pointer
together with an opts__sz argument. The verifier checks only the memory
range described by opts__sz, but the wrappers unconditionally write
opts->error whenever the internal lookup or allocation helper returns an
error.

For an invalid size smaller than the end of opts->error, that write can
land outside the verifier-checked range. Keep returning NULL for invalid
arguments, but only report the error through opts->error when the
supplied size includes the field.

This preserves error reporting for the supported 12-byte and 16-byte
layouts, and for other invalid sizes that still include opts->error.

Fixes: b4c2b9593a1c ("net/netfilter: Add unstable CT lookup helpers for XDP and 
TC-BPF")
Fixes: d7e79c97c00c ("net: netfilter: Add kfuncs to allocate and insert CT")
Signed-off-by: Yiyang Chen <[email protected]>
---
 net/netfilter/nf_conntrack_bpf.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/net/netfilter/nf_conntrack_bpf.c b/net/netfilter/nf_conntrack_bpf.c
index 40c261cd0af38..3c182024ec509 100644
--- a/net/netfilter/nf_conntrack_bpf.c
+++ b/net/netfilter/nf_conntrack_bpf.c
@@ -65,6 +65,11 @@ enum {
        NF_BPF_CT_OPTS_SZ = 16,
 };
 
+static bool bpf_ct_opts_has_error(u32 opts_len)
+{
+       return opts_len >= offsetofend(struct bpf_ct_opts, error);
+}
+
 static int bpf_nf_ct_tuple_parse(struct bpf_sock_tuple *bpf_tuple,
                                 u32 tuple_len, u8 protonum, u8 dir,
                                 struct nf_conntrack_tuple *tuple)
@@ -298,7 +303,8 @@ bpf_xdp_ct_alloc(struct xdp_md *xdp_ctx, struct 
bpf_sock_tuple *bpf_tuple,
        nfct = __bpf_nf_ct_alloc_entry(dev_net(ctx->rxq->dev), bpf_tuple, 
tuple__sz,
                                       opts, opts__sz, 10);
        if (IS_ERR(nfct)) {
-               opts->error = PTR_ERR(nfct);
+               if (bpf_ct_opts_has_error(opts__sz))
+                       opts->error = PTR_ERR(nfct);
                return NULL;
        }
 
@@ -332,7 +338,8 @@ bpf_xdp_ct_lookup(struct xdp_md *xdp_ctx, struct 
bpf_sock_tuple *bpf_tuple,
        caller_net = dev_net(ctx->rxq->dev);
        nfct = __bpf_nf_ct_lookup(caller_net, bpf_tuple, tuple__sz, opts, 
opts__sz);
        if (IS_ERR(nfct)) {
-               opts->error = PTR_ERR(nfct);
+               if (bpf_ct_opts_has_error(opts__sz))
+                       opts->error = PTR_ERR(nfct);
                return NULL;
        }
        return nfct;
@@ -364,7 +371,8 @@ bpf_skb_ct_alloc(struct __sk_buff *skb_ctx, struct 
bpf_sock_tuple *bpf_tuple,
        net = skb->dev ? dev_net(skb->dev) : sock_net(skb->sk);
        nfct = __bpf_nf_ct_alloc_entry(net, bpf_tuple, tuple__sz, opts, 
opts__sz, 10);
        if (IS_ERR(nfct)) {
-               opts->error = PTR_ERR(nfct);
+               if (bpf_ct_opts_has_error(opts__sz))
+                       opts->error = PTR_ERR(nfct);
                return NULL;
        }
 
@@ -398,7 +406,8 @@ bpf_skb_ct_lookup(struct __sk_buff *skb_ctx, struct 
bpf_sock_tuple *bpf_tuple,
        caller_net = skb->dev ? dev_net(skb->dev) : sock_net(skb->sk);
        nfct = __bpf_nf_ct_lookup(caller_net, bpf_tuple, tuple__sz, opts, 
opts__sz);
        if (IS_ERR(nfct)) {
-               opts->error = PTR_ERR(nfct);
+               if (bpf_ct_opts_has_error(opts__sz))
+                       opts->error = PTR_ERR(nfct);
                return NULL;
        }
        return nfct;
-- 
2.34.1


Reply via email to