Skip to content

Commit cd0eb48

Browse files
author
Martin KaFai Lau
committed
Merge branch 'bpf-reject-tcp_nodelay-in-tcp-header-option'
KaFai Wan says: ==================== bpf: Reject TCP_NODELAY in TCP header option This small patchset is about avoid infinite recursion in TCP header option callbacks and bpf-tcp-cc callbacks via TCP_NODELAY setsockopt. v4: - Fix the test case for TCP header option callbacks (Martin and Jiayuan) - Reject TCP_NODELAY in bpf-tcp-cc callbacks (AI and Martin) - Add a test case for bpf-tcp-cc v3: - Remove CONFIG_INET check and add comment (Martin and Jiayuan) - Fix the test case (Martin) https://lore.kernel.org/bpf/20260417092035.2299913-1-kafai.wan@linux.dev/ v2: - Reject TCP_NODELAY in bpf_sock_ops_setsockopt() (AI and Martin) https://lore.kernel.org/bpf/20260416112308.1820332-1-kafai.wan@linux.dev/ v1: https://lore.kernel.org/bpf/20260414112310.1285783-1-kafai.wan@linux.dev/ ==================== Link: https://patch.msgid.link/20260421155804.135786-1-kafai.wan@linux.dev Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
2 parents eb5249b + 2c7e33f commit cd0eb48

7 files changed

Lines changed: 68 additions & 2 deletions

File tree

include/linux/bpf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3725,6 +3725,7 @@ extern const struct bpf_func_proto bpf_for_each_map_elem_proto;
37253725
extern const struct bpf_func_proto bpf_btf_find_by_name_kind_proto;
37263726
extern const struct bpf_func_proto bpf_sk_setsockopt_proto;
37273727
extern const struct bpf_func_proto bpf_sk_getsockopt_proto;
3728+
extern const struct bpf_func_proto bpf_sk_setsockopt_nodelay_proto;
37283729
extern const struct bpf_func_proto bpf_unlocked_sk_setsockopt_proto;
37293730
extern const struct bpf_func_proto bpf_unlocked_sk_getsockopt_proto;
37303731
extern const struct bpf_func_proto bpf_find_vma_proto;

net/core/filter.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5688,6 +5688,30 @@ const struct bpf_func_proto bpf_sk_getsockopt_proto = {
56885688
.arg5_type = ARG_CONST_SIZE,
56895689
};
56905690

5691+
BPF_CALL_5(bpf_sk_setsockopt_nodelay, struct sock *, sk, int, level,
5692+
int, optname, char *, optval, int, optlen)
5693+
{
5694+
/*
5695+
* TCP_NODELAY triggers tcp_push_pending_frames() and re-enters
5696+
* CA_EVENT_TX_START in bpf_tcp_cc.
5697+
*/
5698+
if (level == SOL_TCP && optname == TCP_NODELAY)
5699+
return -EOPNOTSUPP;
5700+
5701+
return _bpf_setsockopt(sk, level, optname, optval, optlen);
5702+
}
5703+
5704+
const struct bpf_func_proto bpf_sk_setsockopt_nodelay_proto = {
5705+
.func = bpf_sk_setsockopt_nodelay,
5706+
.gpl_only = false,
5707+
.ret_type = RET_INTEGER,
5708+
.arg1_type = ARG_PTR_TO_BTF_ID_SOCK_COMMON,
5709+
.arg2_type = ARG_ANYTHING,
5710+
.arg3_type = ARG_ANYTHING,
5711+
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
5712+
.arg5_type = ARG_CONST_SIZE,
5713+
};
5714+
56915715
BPF_CALL_5(bpf_unlocked_sk_setsockopt, struct sock *, sk, int, level,
56925716
int, optname, char *, optval, int, optlen)
56935717
{
@@ -5833,6 +5857,12 @@ BPF_CALL_5(bpf_sock_ops_setsockopt, struct bpf_sock_ops_kern *, bpf_sock,
58335857
if (!is_locked_tcp_sock_ops(bpf_sock))
58345858
return -EOPNOTSUPP;
58355859

5860+
/* TCP_NODELAY triggers tcp_push_pending_frames() and re-enters these callbacks. */
5861+
if ((bpf_sock->op == BPF_SOCK_OPS_HDR_OPT_LEN_CB ||
5862+
bpf_sock->op == BPF_SOCK_OPS_WRITE_HDR_OPT_CB) &&
5863+
level == SOL_TCP && optname == TCP_NODELAY)
5864+
return -EOPNOTSUPP;
5865+
58365866
return _bpf_setsockopt(bpf_sock->sk, level, optname, optval, optlen);
58375867
}
58385868

net/ipv4/bpf_tcp_ca.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ bpf_tcp_ca_get_func_proto(enum bpf_func_id func_id,
168168
*/
169169
if (prog_ops_moff(prog) !=
170170
offsetof(struct tcp_congestion_ops, release))
171-
return &bpf_sk_setsockopt_proto;
171+
return &bpf_sk_setsockopt_nodelay_proto;
172172
return NULL;
173173
case BPF_FUNC_getsockopt:
174174
/* Since get/setsockopt is usually expected to

tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ static void test_cubic(void)
112112

113113
ASSERT_EQ(cubic_skel->bss->bpf_cubic_acked_called, 1, "pkts_acked called");
114114

115+
ASSERT_TRUE(cubic_skel->bss->nodelay_init_reject, "init reject nodelay option");
116+
ASSERT_TRUE(cubic_skel->bss->nodelay_cwnd_event_tx_start_reject,
117+
"cwnd_event_tx_start reject nodelay option");
118+
115119
bpf_link__destroy(link);
116120
bpf_cubic__destroy(cubic_skel);
117121
}

tools/testing/selftests/bpf/prog_tests/tcp_hdr_options.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,10 @@ static void misc(void)
507507

508508
ASSERT_EQ(misc_skel->bss->nr_hwtstamp, 0, "nr_hwtstamp");
509509

510+
ASSERT_TRUE(misc_skel->bss->nodelay_est_ok, "nodelay_est_ok");
511+
ASSERT_TRUE(misc_skel->bss->nodelay_hdr_len_reject, "nodelay_hdr_len_reject");
512+
ASSERT_TRUE(misc_skel->bss->nodelay_write_hdr_reject, "nodelay_write_hdr_reject");
513+
510514
check_linum:
511515
ASSERT_FALSE(check_error_linum(&sk_fds), "check_error_linum");
512516
sk_fds_close(&sk_fds);

tools/testing/selftests/bpf/progs/bpf_cubic.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "bpf_tracing_net.h"
1818
#include <bpf/bpf_tracing.h>
19+
#include <errno.h>
1920

2021
char _license[] SEC("license") = "GPL";
2122

@@ -170,10 +171,18 @@ static void bictcp_hystart_reset(struct sock *sk)
170171
ca->sample_cnt = 0;
171172
}
172173

174+
bool nodelay_init_reject = false;
175+
bool nodelay_cwnd_event_tx_start_reject = false;
176+
173177
SEC("struct_ops")
174178
void BPF_PROG(bpf_cubic_init, struct sock *sk)
175179
{
176180
struct bpf_bictcp *ca = inet_csk_ca(sk);
181+
int true_val = 1, ret;
182+
183+
ret = bpf_setsockopt(sk, SOL_TCP, TCP_NODELAY, &true_val, sizeof(true_val));
184+
if (ret == -EOPNOTSUPP)
185+
nodelay_init_reject = true;
177186

178187
bictcp_reset(ca);
179188

@@ -189,8 +198,13 @@ void BPF_PROG(bpf_cubic_cwnd_event_tx_start, struct sock *sk)
189198
{
190199
struct bpf_bictcp *ca = inet_csk_ca(sk);
191200
__u32 now = tcp_jiffies32;
201+
int true_val = 1, ret;
192202
__s32 delta;
193203

204+
ret = bpf_setsockopt(sk, SOL_TCP, TCP_NODELAY, &true_val, sizeof(true_val));
205+
if (ret == -EOPNOTSUPP)
206+
nodelay_cwnd_event_tx_start_reject = true;
207+
194208
delta = now - tcp_sk(sk)->lsndtime;
195209

196210
/* We were application limited (idle) for a while.

tools/testing/selftests/bpf/progs/test_misc_tcp_hdr_options.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ unsigned int nr_syn = 0;
2929
unsigned int nr_fin = 0;
3030
unsigned int nr_hwtstamp = 0;
3131

32+
bool nodelay_est_ok = false;
33+
bool nodelay_hdr_len_reject = false;
34+
bool nodelay_write_hdr_reject = false;
35+
3236
/* Check the header received from the active side */
3337
static int __check_active_hdr_in(struct bpf_sock_ops *skops, bool check_syn)
3438
{
@@ -300,7 +304,7 @@ static int handle_passive_estab(struct bpf_sock_ops *skops)
300304
SEC("sockops")
301305
int misc_estab(struct bpf_sock_ops *skops)
302306
{
303-
int true_val = 1;
307+
int true_val = 1, false_val = 0, ret;
304308

305309
switch (skops->op) {
306310
case BPF_SOCK_OPS_TCP_LISTEN_CB:
@@ -316,10 +320,19 @@ int misc_estab(struct bpf_sock_ops *skops)
316320
case BPF_SOCK_OPS_PARSE_HDR_OPT_CB:
317321
return handle_parse_hdr(skops);
318322
case BPF_SOCK_OPS_HDR_OPT_LEN_CB:
323+
ret = bpf_setsockopt(skops, SOL_TCP, TCP_NODELAY, &true_val, sizeof(true_val));
324+
if (ret == -EOPNOTSUPP)
325+
nodelay_hdr_len_reject = true;
319326
return handle_hdr_opt_len(skops);
320327
case BPF_SOCK_OPS_WRITE_HDR_OPT_CB:
328+
ret = bpf_setsockopt(skops, SOL_TCP, TCP_NODELAY, &true_val, sizeof(true_val));
329+
if (ret == -EOPNOTSUPP)
330+
nodelay_write_hdr_reject = true;
321331
return handle_write_hdr_opt(skops);
322332
case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB:
333+
ret = bpf_setsockopt(skops, SOL_TCP, TCP_NODELAY, &false_val, sizeof(false_val));
334+
if (!ret)
335+
nodelay_est_ok = true;
323336
return handle_passive_estab(skops);
324337
}
325338

0 commit comments

Comments
 (0)