bpf: tcp: Stop bpf_setsockopt(TCP_CONGESTION) in init ops to recur itself
authorMartin KaFai Lau <martin.lau@kernel.org>
Thu, 29 Sep 2022 07:04:06 +0000 (00:04 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Thu, 29 Sep 2022 16:25:47 +0000 (09:25 -0700)
commit061ff040710e9f6f043d1fa80b1b362d2845b17a
tree44151aaed142402e16a8b6b2d356f02cd720d207
parent1e7d217faa11ac027f622124a3842aafbd0c4a42
bpf: tcp: Stop bpf_setsockopt(TCP_CONGESTION) in init ops to recur itself

When a bad bpf prog '.init' calls
bpf_setsockopt(TCP_CONGESTION, "itself"), it will trigger this loop:

.init => bpf_setsockopt(tcp_cc) => .init => bpf_setsockopt(tcp_cc) ...
... => .init => bpf_setsockopt(tcp_cc).

It was prevented by the prog->active counter before but the prog->active
detection cannot be used in struct_ops as explained in the earlier
patch of the set.

In this patch, the second bpf_setsockopt(tcp_cc) is not allowed
in order to break the loop.  This is done by using a bit of
an existing 1 byte hole in tcp_sock to check if there is
on-going bpf_setsockopt(TCP_CONGESTION) in this tcp_sock.

Note that this essentially limits only the first '.init' can
call bpf_setsockopt(TCP_CONGESTION) to pick a fallback cc (eg. peer
does not support ECN) and the second '.init' cannot fallback to
another cc.  This applies even the second
bpf_setsockopt(TCP_CONGESTION) will not cause a loop.

Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Link: https://lore.kernel.org/r/20220929070407.965581-5-martin.lau@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
include/linux/tcp.h
net/core/filter.c
net/ipv4/tcp_minisocks.c