Skip to content

Commit 3990408

Browse files
lmbAlexei Starovoitov
authored and
Alexei Starovoitov
committed
bpf: add helper to check for a valid SYN cookie
Using bpf_skc_lookup_tcp it's possible to ascertain whether a packet belongs to a known connection. However, there is one corner case: no sockets are created if SYN cookies are active. This means that the final ACK in the 3WHS is misclassified. Using the helper, we can look up the listening socket via bpf_skc_lookup_tcp and then check whether a packet is a valid SYN cookie ACK. Signed-off-by: Lorenz Bauer <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent edbf8c0 commit 3990408

File tree

2 files changed

+89
-1
lines changed

2 files changed

+89
-1
lines changed

include/uapi/linux/bpf.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2448,6 +2448,21 @@ union bpf_attr {
24482448
* Pointer to **struct bpf_sock**, or **NULL** in case of failure.
24492449
* For sockets with reuseport option, the **struct bpf_sock**
24502450
* result is from **reuse->socks**\ [] using the hash of the tuple.
2451+
*
2452+
* int bpf_tcp_check_syncookie(struct bpf_sock *sk, void *iph, u32 iph_len, struct tcphdr *th, u32 th_len)
2453+
* Description
2454+
* Check whether iph and th contain a valid SYN cookie ACK for
2455+
* the listening socket in sk.
2456+
*
2457+
* iph points to the start of the IPv4 or IPv6 header, while
2458+
* iph_len contains sizeof(struct iphdr) or sizeof(struct ip6hdr).
2459+
*
2460+
* th points to the start of the TCP header, while th_len contains
2461+
* sizeof(struct tcphdr).
2462+
*
2463+
* Return
2464+
* 0 if iph and th are a valid SYN cookie ACK, or a negative error
2465+
* otherwise.
24512466
*/
24522467
#define __BPF_FUNC_MAPPER(FN) \
24532468
FN(unspec), \
@@ -2549,7 +2564,8 @@ union bpf_attr {
25492564
FN(tcp_sock), \
25502565
FN(skb_ecn_set_ce), \
25512566
FN(get_listener_sock), \
2552-
FN(skc_lookup_tcp),
2567+
FN(skc_lookup_tcp), \
2568+
FN(tcp_check_syncookie),
25532569

25542570
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
25552571
* function eBPF program intends to call

net/core/filter.c

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5553,6 +5553,74 @@ static const struct bpf_func_proto bpf_skb_ecn_set_ce_proto = {
55535553
.ret_type = RET_INTEGER,
55545554
.arg1_type = ARG_PTR_TO_CTX,
55555555
};
5556+
5557+
BPF_CALL_5(bpf_tcp_check_syncookie, struct sock *, sk, void *, iph, u32, iph_len,
5558+
struct tcphdr *, th, u32, th_len)
5559+
{
5560+
#ifdef CONFIG_SYN_COOKIES
5561+
u32 cookie;
5562+
int ret;
5563+
5564+
if (unlikely(th_len < sizeof(*th)))
5565+
return -EINVAL;
5566+
5567+
/* sk_listener() allows TCP_NEW_SYN_RECV, which makes no sense here. */
5568+
if (sk->sk_protocol != IPPROTO_TCP || sk->sk_state != TCP_LISTEN)
5569+
return -EINVAL;
5570+
5571+
if (!sock_net(sk)->ipv4.sysctl_tcp_syncookies)
5572+
return -EINVAL;
5573+
5574+
if (!th->ack || th->rst || th->syn)
5575+
return -ENOENT;
5576+
5577+
if (tcp_synq_no_recent_overflow(sk))
5578+
return -ENOENT;
5579+
5580+
cookie = ntohl(th->ack_seq) - 1;
5581+
5582+
switch (sk->sk_family) {
5583+
case AF_INET:
5584+
if (unlikely(iph_len < sizeof(struct iphdr)))
5585+
return -EINVAL;
5586+
5587+
ret = __cookie_v4_check((struct iphdr *)iph, th, cookie);
5588+
break;
5589+
5590+
#if IS_BUILTIN(CONFIG_IPV6)
5591+
case AF_INET6:
5592+
if (unlikely(iph_len < sizeof(struct ipv6hdr)))
5593+
return -EINVAL;
5594+
5595+
ret = __cookie_v6_check((struct ipv6hdr *)iph, th, cookie);
5596+
break;
5597+
#endif /* CONFIG_IPV6 */
5598+
5599+
default:
5600+
return -EPROTONOSUPPORT;
5601+
}
5602+
5603+
if (ret > 0)
5604+
return 0;
5605+
5606+
return -ENOENT;
5607+
#else
5608+
return -ENOTSUPP;
5609+
#endif
5610+
}
5611+
5612+
static const struct bpf_func_proto bpf_tcp_check_syncookie_proto = {
5613+
.func = bpf_tcp_check_syncookie,
5614+
.gpl_only = true,
5615+
.pkt_access = true,
5616+
.ret_type = RET_INTEGER,
5617+
.arg1_type = ARG_PTR_TO_SOCK_COMMON,
5618+
.arg2_type = ARG_PTR_TO_MEM,
5619+
.arg3_type = ARG_CONST_SIZE,
5620+
.arg4_type = ARG_PTR_TO_MEM,
5621+
.arg5_type = ARG_CONST_SIZE,
5622+
};
5623+
55565624
#endif /* CONFIG_INET */
55575625

55585626
bool bpf_helper_changes_pkt_data(void *func)
@@ -5815,6 +5883,8 @@ tc_cls_act_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
58155883
return &bpf_get_listener_sock_proto;
58165884
case BPF_FUNC_skc_lookup_tcp:
58175885
return &bpf_skc_lookup_tcp_proto;
5886+
case BPF_FUNC_tcp_check_syncookie:
5887+
return &bpf_tcp_check_syncookie_proto;
58185888
#endif
58195889
default:
58205890
return bpf_base_func_proto(func_id);
@@ -5852,6 +5922,8 @@ xdp_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
58525922
return &bpf_sk_release_proto;
58535923
case BPF_FUNC_skc_lookup_tcp:
58545924
return &bpf_xdp_skc_lookup_tcp_proto;
5925+
case BPF_FUNC_tcp_check_syncookie:
5926+
return &bpf_tcp_check_syncookie_proto;
58555927
#endif
58565928
default:
58575929
return bpf_base_func_proto(func_id);

0 commit comments

Comments
 (0)