Currently, four bpf_tcp_ops callbacks are not allowed to call bpf_setsockopt() and bpf_getsockopt(). However, the deny-list is fragile, and when a new callback is added, we might re-open a can of worms. [0][1] Let's convert it to allow-list. Note that it can be written as offsetof(,X) <= moff <= offsetof(,Y) but clang can optimise to similar code anyway. Link: https://lore.kernel.org/r/20220929070407.965581-5-martin.lau@linux.dev/ #[0] Link: https://lore.kernel.org/bpf/20260421155804.135786-1-kafai.wan@linux.dev/ #[1] Signed-off-by: Kuniyuki Iwashima Reviewed-by: Emil Tsalapatis Acked-by: Stanislav Fomichev --- net/ipv4/bpf_tcp_ops.c | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/net/ipv4/bpf_tcp_ops.c b/net/ipv4/bpf_tcp_ops.c index 681fed642999..1ada3b781bf1 100644 --- a/net/ipv4/bpf_tcp_ops.c +++ b/net/ipv4/bpf_tcp_ops.c @@ -210,6 +210,24 @@ const struct bpf_func_proto bpf_tcp_ops_get_retval_proto = { .ret_type = RET_INTEGER, }; +static bool is_sockopt_supported(u32 moff) +{ + switch (moff) { + case offsetof(struct bpf_tcp_ops, active_established): + case offsetof(struct bpf_tcp_ops, passive_established): + case offsetof(struct bpf_tcp_ops, rto): + case offsetof(struct bpf_tcp_ops, rtt): + case offsetof(struct bpf_tcp_ops, set_state): + case offsetof(struct bpf_tcp_ops, retrans): + case offsetof(struct bpf_tcp_ops, connect): + case offsetof(struct bpf_tcp_ops, listen): + case offsetof(struct bpf_tcp_ops, parse_hdr): + return true; + } + + return false; +} + static const struct bpf_func_proto * get_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) { @@ -221,22 +239,13 @@ get_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) case BPF_FUNC_sk_storage_delete: return &bpf_sk_storage_delete_proto; case BPF_FUNC_setsockopt: - /* The sk may be an unlocked listener (synack path) or NULL - * fullsock; disable for members that can run unlocked. - */ - if (moff == offsetof(struct bpf_tcp_ops, rwnd_init) || - moff == offsetof(struct bpf_tcp_ops, timeout_init) || - moff == offsetof(struct bpf_tcp_ops, hdr_opt_len) || - moff == offsetof(struct bpf_tcp_ops, write_hdr_opt)) - return NULL; - return &bpf_sk_setsockopt_proto; + if (is_sockopt_supported(moff)) + return &bpf_sk_setsockopt_proto; + return NULL; case BPF_FUNC_getsockopt: - if (moff == offsetof(struct bpf_tcp_ops, rwnd_init) || - moff == offsetof(struct bpf_tcp_ops, timeout_init) || - moff == offsetof(struct bpf_tcp_ops, hdr_opt_len) || - moff == offsetof(struct bpf_tcp_ops, write_hdr_opt)) - return NULL; - return &bpf_sk_getsockopt_proto; + if (is_sockopt_supported(moff)) + return &bpf_sk_getsockopt_proto; + return NULL; case BPF_FUNC_get_retval: if (moff == offsetof(struct bpf_tcp_ops, timeout_init) || moff == offsetof(struct bpf_tcp_ops, rwnd_init)) -- 2.56.0.360.g66cac248cb-goog