From: sashiko-bot@kernel.org
To: "Amery Hung" <ameryhung@gmail.com>
Cc: bpf@vger.kernel.org
Subject: Re: [PATCH bpf-next v2 12/15] bpf: tcp: Support parse/len/write header option hooks in bpf_tcp_ops
Date: Tue, 23 Jun 2026 23:40:58 +0000 [thread overview]
Message-ID: <20260623234059.132101F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260623175006.3136053-13-ameryhung@gmail.com>
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] Incorrect pointer arithmetic on the BPF context array causes NULL pointer dereferences on 32-bit architectures.
- [High] A missing bounds check in TCP option parsing combined with a TOCTOU double-fetch allows a malicious BPF program to cause a heap buffer overflow.
- [Medium] The struct_ops TCP option reservation is gated by a completely unrelated cgroup BPF static key, breaking the feature for established connections.
- [Low] Multi-line comments in BPF subsystem files violate the required comment style.
--
commit d91122a96beff2abb78548435a7fd30a3c89c2ac
Author: Amery Hung <ameryhung@gmail.com>
Add the TCP header option callbacks to the bpf_tcp_ops struct_ops type
This patch exposes TCP header option callbacks as struct_ops members to
allow BPF programs to parse, reserve, and write TCP header options. It
mirrors the legacy BPF_SOCK_OPS callbacks and shares the reserved window.
> The hdr_opt_len fast path in tcp_established_options() is gated by
> cgroup_bpf_enabled(CGROUP_TCP_SOCK_OPS). Note this is a global,
> per-attach-type static branch: it is enabled whenever any bpf_tcp_ops is
> attached, even one that does not implement hdr_opt_len or that is attached
> to a different cgroup.
[Severity: Medium]
Is this description accurate? Struct_ops do not enable this cgroup static
key. Will this check evaluate to false in non-cgroup-bpf deployments,
skipping space reservation for established connections but still calling
write_hdr_opt later?
> diff --git a/include/net/tcp.h b/include/net/tcp.h
> --- a/include/net/tcp.h
> +++ b/include/net/tcp.h
[ ... ]
> @@ -3005,6 +3005,45 @@ struct bpf_tcp_ops {
>
> /* Called on listen(2), right after the socket enters TCP_LISTEN. */
> void (*listen)(struct sock *sk);
> +
[Severity: Low]
This isn't a bug, but does the BPF subsystem prefer the opening /* to be on
its own line for multi-line comments?
> + /* Parse the TCP header options of an incoming skb received on an
> + * established connection. Use bpf_dynptr_from_skb()/bpf_skb_load_bytes()
> + * to access the options.
> + */
> + void (*parse_hdr)(struct sock *sk, struct sk_buff *skb);
> +
[ ... ]
> diff --git a/net/ipv4/bpf_tcp_ops.c b/net/ipv4/bpf_tcp_ops.c
> --- a/net/ipv4/bpf_tcp_ops.c
> +++ b/net/ipv4/bpf_tcp_ops.c
[ ... ]
> @@ -66,6 +87,99 @@ static struct bpf_tcp_ops __bpf_tcp_ops = {
> .retrans = retrans_stub,
> .connect = connect_stub,
> .listen = listen_stub,
> + .parse_hdr = parse_hdr_stub,
> + .hdr_opt_len = hdr_opt_len_stub,
> + .write_hdr_opt = write_hdr_opt_stub,
> +};
> +
> +BPF_CALL_4(bpf_tcp_ops_store_hdr_opt, void *, ctx, const void *, from,
> + u32, len, u64, flags)
> +{
[Severity: High]
Can this pointer cast lead to reading the wrong offset on 32-bit systems?
The ctx array contains 64-bit integers, so casting directly to a pointer
array might result in reading the upper 32 bits (which are zero) on
little-endian architectures, causing a NULL pointer dereference.
> + struct sk_buff *skb = ((struct sk_buff **)ctx)[1];
> + struct bpf_sock_ops_kern sock_ops = {};
> + u32 opt_off = ((u64 *)ctx)[5];
> + u8 *op, *opend;
> +
[Severity: Low]
This isn't a bug, but multi-line comments in the BPF subsystem typically
place the opening /* on a separate line.
> + /* bpf_tcp_ops does not keep track of the end of the written TCP header
> + * options, so search for it every time the helper is called. The free
> + * space is NOP-filled, so a TCPOPT_NOP ends the search rather than being
> + * skipped as in a normal option walk in sockops.
> + */
> + op = skb->data + opt_off;
> + opend = skb->data + tcp_hdrlen(skb);
> + while (op < opend && *op != TCPOPT_NOP) {
[Severity: High]
Does this loop prevent op from advancing past opend if the option length
byte is forged? If op[1] is maliciously modified concurrently in the BPF
map memory before __bpf_sock_ops_store_hdr_opt() does its memcpy, could
the next call to bpf_tcp_ops_store_hdr_opt() advance op past opend and
cause an out-of-bounds memcpy?
> + if (*op == TCPOPT_EOL || op + 1 >= opend || op[1] < 2)
> + break;
> + op += op[1];
> + }
> +
> + sock_ops.skb = skb;
> + sock_ops.skb_data_end = op;
> + sock_ops.remaining_opt_len = opend - op;
> +
> + return __bpf_sock_ops_store_hdr_opt(&sock_ops, from, len, flags);
> +}
[ ... ]
> +BPF_CALL_4(bpf_tcp_ops_load_hdr_opt, void *, ctx, void *, search_res,
> + u32, len, u64, flags)
> +{
[Severity: High]
Will this cast misalign the array index on 32-bit architectures? Treating
the 64-bit integer array as an array of 32-bit pointers will cause the
wrong bytes to be read for the context argument.
> + struct sk_buff *skb = ((struct sk_buff **)ctx)[1];
> + struct bpf_sock_ops_kern sock_ops = {};
[ ... ]
> +BPF_CALL_3(bpf_tcp_ops_reserve_hdr_opt, void *, ctx, u32, len, u64, flags)
> +{
[Severity: High]
Could casting ctx to a pointer array here also lead to a NULL pointer
dereference on 32-bit systems due to reading the upper 32 bits of the
previous 64-bit argument?
> + unsigned int *remaining = ((unsigned int **)ctx)[5];
> +
> + if (flags || len < 2)
> + return -EINVAL;
[ ... ]
> diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
> --- a/net/ipv4/tcp_output.c
> +++ b/net/ipv4/tcp_output.c
[ ... ]
> @@ -1244,6 +1281,15 @@ static unsigned int tcp_established_options(struct sock *sk, struct sk_buff *skb
> size = MAX_TCP_OPTION_SPACE - remaining;
> }
>
[Severity: Medium]
Does this cgroup check evaluate to false for struct_ops in non-cgroup-bpf
deployments? If so, does it silently skip reserving space in
bpf_tcp_ops_hdr_opt_len() for established connections, while still calling
write_hdr_opt unconditionally later?
> + if (cgroup_bpf_enabled(CGROUP_TCP_SOCK_OPS)) {
> + unsigned int remaining = MAX_TCP_OPTION_SPACE - size;
> +
> + remaining = bpf_tcp_ops_hdr_opt_len(sk, skb, NULL, NULL, 0, opts,
> + remaining);
> +
> + size = MAX_TCP_OPTION_SPACE - remaining;
> + }
> +
> return size;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260623175006.3136053-1-ameryhung@gmail.com?part=12
next prev parent reply other threads:[~2026-06-23 23:40 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-23 17:49 [PATCH bpf-next v2 00/15] bpf: A common way to attach struct_ops to a cgroup Amery Hung
2026-06-23 17:49 ` [PATCH bpf-next v2 01/15] bpf: Remove __rcu tagging in st_link->map Amery Hung
2026-06-23 17:49 ` [PATCH bpf-next v2 02/15] bpf: Make struct_ops tasks_rcu grace period optional Amery Hung
2026-06-23 17:49 ` [PATCH bpf-next v2 03/15] bpf: Add bpf_struct_ops accessor helpers Amery Hung
2026-06-23 21:40 ` sashiko-bot
2026-06-23 17:49 ` [PATCH bpf-next v2 04/15] bpf: Remove unnecessary prog_list_prog() check Amery Hung
2026-06-23 17:49 ` [PATCH bpf-next v2 05/15] bpf: Replace prog_list_prog() check with direct pl->prog and pl->link check Amery Hung
2026-06-23 17:49 ` [PATCH bpf-next v2 06/15] bpf: Add prog_list_init_item(), prog_list_replace_item(), and prog_list_id() Amery Hung
2026-06-23 17:49 ` [PATCH bpf-next v2 07/15] bpf: Move LSM trampoline unlink into bpf_cgroup_link_auto_detach() Amery Hung
2026-06-23 17:49 ` [PATCH bpf-next v2 08/15] bpf: Add a few bpf_cgroup_array_* helper functions Amery Hung
2026-06-23 22:25 ` sashiko-bot
2026-06-23 17:49 ` [PATCH bpf-next v2 09/15] bpf: Add infrastructure to support attaching struct_ops to cgroups Amery Hung
2026-06-23 22:53 ` sashiko-bot
2026-06-23 17:49 ` [PATCH bpf-next v2 10/15] bpf: Allow all struct_ops to use bpf_dynptr_from_skb() Amery Hung
2026-06-23 17:49 ` [PATCH bpf-next v2 11/15] bpf: tcp: Support selected sock_ops callbacks as struct_ops Amery Hung
2026-06-23 23:22 ` sashiko-bot
2026-06-23 17:50 ` [PATCH bpf-next v2 12/15] bpf: tcp: Support parse/len/write header option hooks in bpf_tcp_ops Amery Hung
2026-06-23 23:40 ` sashiko-bot [this message]
2026-06-23 17:50 ` [PATCH bpf-next v2 13/15] libbpf: Support attaching struct_ops to a cgroup Amery Hung
2026-06-23 23:53 ` sashiko-bot
2026-06-23 17:50 ` [PATCH bpf-next v2 14/15] selftests/bpf: Test " Amery Hung
2026-06-24 0:03 ` sashiko-bot
2026-06-23 17:50 ` [PATCH bpf-next v2 15/15] selftests/bpf: Add test for bpf_tcp_ops header option hooks Amery Hung
2026-06-24 0:14 ` sashiko-bot
[not found] ` <0e6fb8d7eca4b5494e08a2230056e333bdd814d97c16784b3e1f7687b3640990@mail.kernel.org>
2026-06-23 21:11 ` [PATCH bpf-next v2 00/15] bpf: A common way to attach struct_ops to a cgroup Amery Hung
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260623234059.132101F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=ameryhung@gmail.com \
--cc=bpf@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.