Skip to content

Commit 2489348

Browse files
committed
netstacklat: Add sanity checks for rcv_nxt and copied_seq
In addition to the out-of-order sequence number in the previous commit, two more key members that are read from the tcp_sock (outside of the socket lock) is rcv_nxt and copied_seq. Add sanity checks to these two members that ensure that they are monotonically increasing (in a u32 wrap-around space). To enable this sanity check, track the last seen (sane) value for both of them together with the other ooo-state in the socket storage map. At each read, compare the recorded values from the last read with their current values to determine if the current values are ahead of the previously seen values or not. Unlike the ooo sequence number, do not consider sequence 0 invalid for these checks. As they are direct members of the tcp_sock their values should always be valid (although possibly concurrently updated elsewhere), as long as the probe read succeeds (and failure is directly detected from the return value of bpf_core_read()). Skip adding similar monotonic growth checks for rcv_wup field to avoid also having to probe and update that value every time. For the rcv_wnd field I am no aware of any simple validity checks than can be performed. Signed-off-by: Simon Sundberg <[email protected]>
1 parent c8d50c2 commit 2489348

File tree

1 file changed

+66
-23
lines changed

1 file changed

+66
-23
lines changed

netstacklat/netstacklat.bpf.c

Lines changed: 66 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* SPDX-License-Identifier: GPL-2.0-or-later */
22
#include "vmlinux_local.h"
33
#include <linux/bpf.h>
4+
#include <linux/errno.h>
45

56
#include <bpf/bpf_helpers.h>
67
#include <bpf/bpf_tracing.h>
@@ -46,6 +47,8 @@ struct sk_buff___old {
4647
struct tcp_sock_ooo_range {
4748
u32 prev_n_ooopkts;
4849
u32 ooo_seq_end;
50+
u32 last_rcv_nxt;
51+
u32 last_copied_seq;
4952
/* indicates if ooo_seq_end is still valid (as 0 can be valid seq) */
5053
bool active;
5154
};
@@ -361,18 +364,13 @@ static int get_current_rcv_wnd_seq(struct tcp_sock *tp, u32 rcv_nxt, u32 *seq)
361364
return err;
362365
}
363366

364-
static int current_max_possible_ooo_seq(struct tcp_sock *tp, u32 *seq)
367+
static int current_max_possible_ooo_seq(struct tcp_sock *tp, u32 rcv_nxt,
368+
u32 *seq)
365369
{
366-
u32 rcv_nxt, cur_rcv_window, max_seq = 0;
370+
u32 cur_rcv_window, max_seq = 0;
367371
struct tcp_skb_cb cb;
368372
int err = 0;
369373

370-
err = bpf_core_read(&rcv_nxt, sizeof(rcv_nxt), &tp->rcv_nxt);
371-
if (err) {
372-
bpf_printk("failed reading tcp_sock->rcv_nxt, err=%d", err);
373-
goto exit;
374-
}
375-
376374
if (BPF_CORE_READ(tp, out_of_order_queue.rb_node) == NULL) {
377375
/* No ooo-segments currently in ooo-queue
378376
* Any ooo-segments must already have been merged to the
@@ -413,35 +411,68 @@ static int current_max_possible_ooo_seq(struct tcp_sock *tp, u32 *seq)
413411
return err;
414412
}
415413

416-
static bool tcp_read_in_ooo_range(struct tcp_sock *tp,
414+
static bool tcp_read_in_ooo_range(struct tcp_sock *tp, u32 copied_seq,
417415
struct tcp_sock_ooo_range *ooo_range)
418416
{
419-
u32 read_seq;
420-
int err;
421-
422417
if (!ooo_range->active)
423418
return false;
424419

425-
err = bpf_core_read(&read_seq, sizeof(read_seq), &tp->copied_seq);
426-
if (err) {
427-
bpf_printk("failed to read tcp_sock->copied_seq, err=%d", err);
428-
return true; // Assume we may be in ooo-range
429-
}
430-
431-
if (u32_lt(ooo_range->ooo_seq_end, read_seq)) {
420+
if (u32_lt(ooo_range->ooo_seq_end, copied_seq)) {
432421
ooo_range->active = false;
433422
return false;
434423
} else {
435424
return true;
436425
}
437426
}
438427

428+
static int get_and_validate_rcvnxt(struct tcp_sock *tp,
429+
struct tcp_sock_ooo_range *ooo_range,
430+
u32 *rcvnxt)
431+
{
432+
u32 rcv_nxt = 0;
433+
int err;
434+
435+
err = bpf_core_read(&rcv_nxt, sizeof(rcv_nxt), &tp->rcv_nxt);
436+
if (err || (ooo_range->last_rcv_nxt &&
437+
u32_lt(rcv_nxt, ooo_range->last_rcv_nxt))) {
438+
bpf_printk("failed to read valid tcp_sock->rcv_nxt, err=%d",
439+
err);
440+
err = err ?: -ERANGE;
441+
} else {
442+
ooo_range->last_rcv_nxt = rcv_nxt;
443+
}
444+
445+
*rcvnxt = rcv_nxt;
446+
return err;
447+
}
448+
449+
static int get_and_validate_copiedseq(struct tcp_sock *tp,
450+
struct tcp_sock_ooo_range *ooo_range,
451+
u32 *copiedseq)
452+
{
453+
u32 copied_seq = 0;
454+
int err;
455+
456+
err = bpf_core_read(&copied_seq, sizeof(copied_seq), &tp->copied_seq);
457+
if (err || (ooo_range->last_copied_seq &&
458+
u32_lt(copied_seq, ooo_range->last_copied_seq))) {
459+
bpf_printk("failed to read valid tcp_sock->copied_seq, err=%d",
460+
err);
461+
err = err ?: -ERANGE;
462+
} else {
463+
ooo_range->last_copied_seq = copied_seq;
464+
}
465+
466+
*copiedseq = copied_seq;
467+
return err;
468+
}
469+
439470
static bool tcp_read_maybe_holblocked(struct sock *sk)
440471
{
472+
u32 n_ooopkts, rcv_nxt, copied_seq, nxt_seq;
441473
struct tcp_sock_ooo_range *ooo_range;
474+
int err, err_rcvnxt, err_copiedseq;
442475
struct tcp_sock *tp = tcp_sk(sk);
443-
u32 n_ooopkts, nxt_seq;
444-
int err;
445476

446477
err = bpf_core_read(&n_ooopkts, sizeof(n_ooopkts), &tp->rcv_ooopack);
447478
if (err) {
@@ -461,18 +492,30 @@ static bool tcp_read_maybe_holblocked(struct sock *sk)
461492
return true; // Assume we may be in ooo-range
462493
}
463494

495+
/* rcv_nxt and copied_seq may not be needed, but to ensure we always
496+
* update our tracked state for them, read, sanity check and update
497+
* both their values here. Errors are only checked for in the paths
498+
* were the values are actually needed.
499+
*/
500+
err_rcvnxt = get_and_validate_rcvnxt(tp, ooo_range, &rcv_nxt);
501+
err_copiedseq = get_and_validate_copiedseq(tp, ooo_range, &copied_seq);
502+
464503
// Increase in ooo-packets since last - figure out next safe seq
465504
if (n_ooopkts > ooo_range->prev_n_ooopkts) {
466505
ooo_range->prev_n_ooopkts = n_ooopkts;
467-
err = current_max_possible_ooo_seq(tp, &nxt_seq);
506+
err = err_rcvnxt ?:
507+
current_max_possible_ooo_seq(tp, rcv_nxt,
508+
&nxt_seq);
468509
if (!err) {
469510
ooo_range->ooo_seq_end = nxt_seq;
470511
ooo_range->active = true;
471512
}
513+
472514
return true;
473515
}
474516

475-
return tcp_read_in_ooo_range(tp, ooo_range);
517+
return err_copiedseq ? true :
518+
tcp_read_in_ooo_range(tp, copied_seq, ooo_range);
476519
}
477520

478521
static void record_socket_latency(struct sock *sk, struct sk_buff *skb,

0 commit comments

Comments
 (0)