Commit da263fcb authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'mptcp-userspace-pm-create-sockets-for-the-right-family'

Matthieu Baerts says:

====================
mptcp: userspace pm: create sockets for the right family

Before these patches, the Userspace Path Manager would allow the
creation of subflows with wrong families: taking the one of the MPTCP
socket instead of the provided ones and resulting in the creation of
subflows with likely not the right source and/or destination IPs. It
would also allow the creation of subflows between different families or
not respecting v4/v6-only socket attributes.

Patch 1 lets the userspace PM select the proper family to avoid creating
subflows with the wrong source and/or destination addresses because the
family is not the expected one.

Patch 2 makes sure the userspace PM doesn't allow the userspace to
create subflows for a family that is not allowed.

Patch 3 validates scenarios with a mix of v4 and v6 subflows for the
same MPTCP connection.

These patches fix issues introduced in v5.19 when the userspace path
manager has been introduced.
====================

Link: https://lore.kernel.org/r/20230112-upstream-net-20230112-netlink-v4-v6-v1-0-6a8363a221d2@tessares.net


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 925f3deb 4656d72c
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -420,6 +420,31 @@ void mptcp_pm_subflow_chk_stale(const struct mptcp_sock *msk, struct sock *ssk)
	}
}

/* if sk is ipv4 or ipv6_only allows only same-family local and remote addresses,
 * otherwise allow any matching local/remote pair
 */
bool mptcp_pm_addr_families_match(const struct sock *sk,
				  const struct mptcp_addr_info *loc,
				  const struct mptcp_addr_info *rem)
{
	bool mptcp_is_v4 = sk->sk_family == AF_INET;

#if IS_ENABLED(CONFIG_MPTCP_IPV6)
	bool loc_is_v4 = loc->family == AF_INET || ipv6_addr_v4mapped(&loc->addr6);
	bool rem_is_v4 = rem->family == AF_INET || ipv6_addr_v4mapped(&rem->addr6);

	if (mptcp_is_v4)
		return loc_is_v4 && rem_is_v4;

	if (ipv6_only_sock(sk))
		return !loc_is_v4 && !rem_is_v4;

	return loc_is_v4 == rem_is_v4;
#else
	return mptcp_is_v4 && loc->family == AF_INET && rem->family == AF_INET;
#endif
}

void mptcp_pm_data_reset(struct mptcp_sock *msk)
{
	u8 pm_type = mptcp_get_pm_type(sock_net((struct sock *)msk));
+7 −0
Original line number Diff line number Diff line
@@ -294,6 +294,13 @@ int mptcp_nl_cmd_sf_create(struct sk_buff *skb, struct genl_info *info)
	}

	sk = (struct sock *)msk;

	if (!mptcp_pm_addr_families_match(sk, &addr_l, &addr_r)) {
		GENL_SET_ERR_MSG(info, "families mismatch");
		err = -EINVAL;
		goto create_err;
	}

	lock_sock(sk);

	err = __mptcp_subflow_connect(sk, &addr_l, &addr_r);
+1 −1
Original line number Diff line number Diff line
@@ -98,7 +98,7 @@ static int __mptcp_socket_create(struct mptcp_sock *msk)
	struct socket *ssock;
	int err;

	err = mptcp_subflow_create_socket(sk, &ssock);
	err = mptcp_subflow_create_socket(sk, sk->sk_family, &ssock);
	if (err)
		return err;

+5 −1
Original line number Diff line number Diff line
@@ -641,7 +641,8 @@ bool mptcp_addresses_equal(const struct mptcp_addr_info *a,
/* called with sk socket lock held */
int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_addr_info *loc,
			    const struct mptcp_addr_info *remote);
int mptcp_subflow_create_socket(struct sock *sk, struct socket **new_sock);
int mptcp_subflow_create_socket(struct sock *sk, unsigned short family,
				struct socket **new_sock);
void mptcp_info2sockaddr(const struct mptcp_addr_info *info,
			 struct sockaddr_storage *addr,
			 unsigned short family);
@@ -776,6 +777,9 @@ int mptcp_pm_parse_addr(struct nlattr *attr, struct genl_info *info,
int mptcp_pm_parse_entry(struct nlattr *attr, struct genl_info *info,
			 bool require_family,
			 struct mptcp_pm_addr_entry *entry);
bool mptcp_pm_addr_families_match(const struct sock *sk,
				  const struct mptcp_addr_info *loc,
				  const struct mptcp_addr_info *rem);
void mptcp_pm_subflow_chk_stale(const struct mptcp_sock *msk, struct sock *ssk);
void mptcp_pm_nl_subflow_chk_stale(const struct mptcp_sock *msk, struct sock *ssk);
void mptcp_pm_new_connection(struct mptcp_sock *msk, const struct sock *ssk, int server_side);
+5 −4
Original line number Diff line number Diff line
@@ -1547,7 +1547,7 @@ int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_addr_info *loc,
	if (!mptcp_is_fully_established(sk))
		goto err_out;

	err = mptcp_subflow_create_socket(sk, &sf);
	err = mptcp_subflow_create_socket(sk, loc->family, &sf);
	if (err)
		goto err_out;

@@ -1660,7 +1660,9 @@ static void mptcp_subflow_ops_undo_override(struct sock *ssk)
#endif
		ssk->sk_prot = &tcp_prot;
}
int mptcp_subflow_create_socket(struct sock *sk, struct socket **new_sock)

int mptcp_subflow_create_socket(struct sock *sk, unsigned short family,
				struct socket **new_sock)
{
	struct mptcp_subflow_context *subflow;
	struct net *net = sock_net(sk);
@@ -1673,8 +1675,7 @@ int mptcp_subflow_create_socket(struct sock *sk, struct socket **new_sock)
	if (unlikely(!sk->sk_socket))
		return -EINVAL;

	err = sock_create_kern(net, sk->sk_family, SOCK_STREAM, IPPROTO_TCP,
			       &sf);
	err = sock_create_kern(net, family, SOCK_STREAM, IPPROTO_TCP, &sf);
	if (err)
		return err;

Loading