mirror of
https://github.com/torvalds/linux.git
synced 2026-05-12 16:18:45 +02:00
Merge branch 'bpf-tcp-fix-type-confusion-in-bpf-helper-functions'
Kuniyuki Iwashima says:
====================
bpf: tcp: Fix type confusion in bpf helper functions.
bpf_tcp_sock() only check if sk->sk_protocol is IPPROTO_TCP,
but RAW socket can bypass it:
socket(AF_INET, SOCK_RAW, IPPROTO_TCP)
The same issues exist in other bpf functions:
* bpf_mptcp_sock_from_subflow()
* bpf_skc_to_tcp_sock()
* bpf_skc_to_tcp6_sock()
* sol_tcp_sockopt()
Patch 1 fixes bpf_tcp_sock() and Patch 2 adds a test for it.
Patch 3 ~ 6 fix the rest of the functions above.
Changes:
v2:
* Inverse if (err) to if (!err) in the selftest
* Add patch 3 ~ 6
v1: https://lore.kernel.org/bpf/20260430184405.1227386-1-kuniyu@google.com/
https://lore.kernel.org/mptcp/20260430-mptcp-bpf-mptcp-sock-type-v1-1-d2ed5cda7da9@kernel.org/
====================
Link: https://patch.msgid.link/20260504210610.180150-1-kuniyu@google.com
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
This commit is contained in:
commit
f3b8c28135
|
|
@ -5481,7 +5481,7 @@ static int sol_tcp_sockopt(struct sock *sk, int optname,
|
|||
char *optval, int *optlen,
|
||||
bool getopt)
|
||||
{
|
||||
if (sk->sk_protocol != IPPROTO_TCP)
|
||||
if (!sk_is_tcp(sk))
|
||||
return -EINVAL;
|
||||
|
||||
switch (optname) {
|
||||
|
|
@ -7475,7 +7475,7 @@ u32 bpf_tcp_sock_convert_ctx_access(enum bpf_access_type type,
|
|||
|
||||
BPF_CALL_1(bpf_tcp_sock, struct sock *, sk)
|
||||
{
|
||||
if (sk_fullsock(sk) && sk->sk_protocol == IPPROTO_TCP)
|
||||
if (sk_fullsock(sk) && sk_is_tcp(sk))
|
||||
return (unsigned long)sk;
|
||||
|
||||
return (unsigned long)NULL;
|
||||
|
|
@ -11947,7 +11947,7 @@ BPF_CALL_1(bpf_skc_to_tcp6_sock, struct sock *, sk)
|
|||
*/
|
||||
BTF_TYPE_EMIT(struct tcp6_sock);
|
||||
if (sk && sk_fullsock(sk) && sk->sk_protocol == IPPROTO_TCP &&
|
||||
sk->sk_family == AF_INET6)
|
||||
sk->sk_type == SOCK_STREAM && sk->sk_family == AF_INET6)
|
||||
return (unsigned long)sk;
|
||||
|
||||
return (unsigned long)NULL;
|
||||
|
|
@ -11963,7 +11963,7 @@ const struct bpf_func_proto bpf_skc_to_tcp6_sock_proto = {
|
|||
|
||||
BPF_CALL_1(bpf_skc_to_tcp_sock, struct sock *, sk)
|
||||
{
|
||||
if (sk && sk_fullsock(sk) && sk->sk_protocol == IPPROTO_TCP)
|
||||
if (sk && sk_fullsock(sk) && sk_is_tcp(sk))
|
||||
return (unsigned long)sk;
|
||||
|
||||
return (unsigned long)NULL;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
struct mptcp_sock *bpf_mptcp_sock_from_subflow(struct sock *sk)
|
||||
{
|
||||
if (sk && sk_fullsock(sk) && sk->sk_protocol == IPPROTO_TCP && sk_is_mptcp(sk))
|
||||
if (sk && sk_fullsock(sk) && sk_is_tcp(sk) && sk_is_mptcp(sk))
|
||||
return mptcp_sk(mptcp_subflow_ctx(sk)->conn);
|
||||
|
||||
return NULL;
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ static int getsetsockopt(void)
|
|||
fd = socket(AF_NETLINK, SOCK_RAW, 0);
|
||||
if (fd < 0) {
|
||||
log_err("Failed to create AF_NETLINK socket");
|
||||
return -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
buf.u32 = 1;
|
||||
|
|
@ -211,6 +211,21 @@ static int getsetsockopt(void)
|
|||
}
|
||||
ASSERT_EQ(optlen, 8, "Unexpected NETLINK_LIST_MEMBERSHIPS value");
|
||||
|
||||
/* Trick bpf_tcp_sock() with IPPROTO_TCP */
|
||||
close(fd);
|
||||
fd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
|
||||
if (!ASSERT_OK_FD(fd, "socket"))
|
||||
goto err;
|
||||
|
||||
/* The BPF prog intercepts this before the kernel sees it, any
|
||||
* optlen works. Go with 4 bytes for simplicity.
|
||||
*/
|
||||
buf.u32 = 1;
|
||||
optlen = sizeof(buf.u32);
|
||||
err = setsockopt(fd, SOL_TCP, TCP_SAVED_SYN, &buf, optlen);
|
||||
if (!ASSERT_ERR(err, "setsockopt(TCP_SAVED_SYN)"))
|
||||
goto err;
|
||||
|
||||
free(big_buf);
|
||||
close(fd);
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -149,6 +149,20 @@ int _setsockopt(struct bpf_sockopt *ctx)
|
|||
if (sk && sk->family == AF_NETLINK)
|
||||
goto out;
|
||||
|
||||
if (sk && sk->family == AF_INET && sk->type == SOCK_RAW) {
|
||||
struct bpf_tcp_sock *tp = bpf_tcp_sock(sk);
|
||||
|
||||
if (tp) {
|
||||
char saved_syn[60];
|
||||
|
||||
bpf_getsockopt(sk, SOL_TCP, TCP_SAVED_SYN,
|
||||
&saved_syn, sizeof(saved_syn));
|
||||
goto consumed;
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Make sure bpf_get_netns_cookie is callable.
|
||||
*/
|
||||
if (bpf_get_netns_cookie(NULL) == 0)
|
||||
|
|
@ -224,6 +238,8 @@ int _setsockopt(struct bpf_sockopt *ctx)
|
|||
return 0; /* couldn't get sk storage */
|
||||
|
||||
storage->val = optval[0];
|
||||
|
||||
consumed:
|
||||
ctx->optlen = -1; /* BPF has consumed this option, don't call kernel
|
||||
* setsockopt handler.
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user