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