Skip to content

Commit

Permalink
Merge branch 'mptcp-fixes'
Browse files Browse the repository at this point in the history
Matthieu Baerts says:

====================
mptcp: misc. fixes for v6.8

This series includes 4 types of fixes:

Patches 1 and 2 force the path-managers not to allocate a new address
entry when dealing with the "special" ID 0, reserved to the address of
the initial subflow. These patches can be backported up to v5.19 and
v5.12 respectively.

Patch 3 to 6 fix the in-kernel path-manager not to create duplicated
subflows. Patch 6 is the main fix, but patches 3 to 5 are some kind of
pre-requisities: they fix some data races that could also lead to the
creation of unexpected subflows. These patches can be backported up to
v5.7, v5.10, v6.0, and v5.15 respectively.

Note that patch 3 modifies the existing ULP API. No better solutions
have been found for -net, and there is some similar prior art, see
commit 0df48c2 ("tcp: add tcpi_bytes_acked to tcp_info"). Please
also note that TLS ULP Diag has likely the same issue.

Patches 7 to 9 fix issues in the selftests, when executing them on older
kernels, e.g. when testing the last version of these kselftests on the
v5.15.148 kernel as it is done by LKFT when validating stable kernels.
These patches only avoid printing expected errors the console and
marking some tests as "OK" while they have been skipped. Patches 7 and 8
can be backported up to v6.6.

Patches 10 to 13 make sure all MPTCP selftests subtests have a unique
name. It is important to have a unique (sub)test name in TAP, because
that's the test identifier. Some CI environments might drop tests with
duplicated names. Patches 10 to 12 can be backported up to v6.6.
====================

Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Feb 18, 2024
2 parents 59a646d + 4103d84 commit 398b7c3
Show file tree
Hide file tree
Showing 12 changed files with 116 additions and 68 deletions.
2 changes: 1 addition & 1 deletion include/net/tcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -2506,7 +2506,7 @@ struct tcp_ulp_ops {
/* cleanup ulp */
void (*release)(struct sock *sk);
/* diagnostic */
int (*get_info)(const struct sock *sk, struct sk_buff *skb);
int (*get_info)(struct sock *sk, struct sk_buff *skb);
size_t (*get_info_size)(const struct sock *sk);
/* clone ulp */
void (*clone)(const struct request_sock *req, struct sock *newsk,
Expand Down
8 changes: 6 additions & 2 deletions net/mptcp/diag.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,19 @@
#include <uapi/linux/mptcp.h>
#include "protocol.h"

static int subflow_get_info(const struct sock *sk, struct sk_buff *skb)
static int subflow_get_info(struct sock *sk, struct sk_buff *skb)
{
struct mptcp_subflow_context *sf;
struct nlattr *start;
u32 flags = 0;
bool slow;
int err;

start = nla_nest_start_noflag(skb, INET_ULP_INFO_MPTCP);
if (!start)
return -EMSGSIZE;

slow = lock_sock_fast(sk);
rcu_read_lock();
sf = rcu_dereference(inet_csk(sk)->icsk_ulp_data);
if (!sf) {
Expand Down Expand Up @@ -63,17 +65,19 @@ static int subflow_get_info(const struct sock *sk, struct sk_buff *skb)
sf->map_data_len) ||
nla_put_u32(skb, MPTCP_SUBFLOW_ATTR_FLAGS, flags) ||
nla_put_u8(skb, MPTCP_SUBFLOW_ATTR_ID_REM, sf->remote_id) ||
nla_put_u8(skb, MPTCP_SUBFLOW_ATTR_ID_LOC, sf->local_id)) {
nla_put_u8(skb, MPTCP_SUBFLOW_ATTR_ID_LOC, subflow_get_local_id(sf))) {
err = -EMSGSIZE;
goto nla_failure;
}

rcu_read_unlock();
unlock_sock_fast(sk, slow);
nla_nest_end(skb, start);
return 0;

nla_failure:
rcu_read_unlock();
unlock_sock_fast(sk, slow);
nla_nest_cancel(skb, start);
return err;
}
Expand Down
69 changes: 43 additions & 26 deletions net/mptcp/pm_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -396,19 +396,6 @@ void mptcp_pm_free_anno_list(struct mptcp_sock *msk)
}
}

static bool lookup_address_in_vec(const struct mptcp_addr_info *addrs, unsigned int nr,
const struct mptcp_addr_info *addr)
{
int i;

for (i = 0; i < nr; i++) {
if (addrs[i].id == addr->id)
return true;
}

return false;
}

/* Fill all the remote addresses into the array addrs[],
* and return the array size.
*/
Expand Down Expand Up @@ -440,18 +427,34 @@ static unsigned int fill_remote_addresses_vec(struct mptcp_sock *msk,
msk->pm.subflows++;
addrs[i++] = remote;
} else {
DECLARE_BITMAP(unavail_id, MPTCP_PM_MAX_ADDR_ID + 1);

/* Forbid creation of new subflows matching existing
* ones, possibly already created by incoming ADD_ADDR
*/
bitmap_zero(unavail_id, MPTCP_PM_MAX_ADDR_ID + 1);
mptcp_for_each_subflow(msk, subflow)
if (READ_ONCE(subflow->local_id) == local->id)
__set_bit(subflow->remote_id, unavail_id);

mptcp_for_each_subflow(msk, subflow) {
ssk = mptcp_subflow_tcp_sock(subflow);
remote_address((struct sock_common *)ssk, &addrs[i]);
addrs[i].id = subflow->remote_id;
addrs[i].id = READ_ONCE(subflow->remote_id);
if (deny_id0 && !addrs[i].id)
continue;

if (test_bit(addrs[i].id, unavail_id))
continue;

if (!mptcp_pm_addr_families_match(sk, local, &addrs[i]))
continue;

if (!lookup_address_in_vec(addrs, i, &addrs[i]) &&
msk->pm.subflows < subflows_max) {
if (msk->pm.subflows < subflows_max) {
/* forbid creating multiple address towards
* this id
*/
__set_bit(addrs[i].id, unavail_id);
msk->pm.subflows++;
i++;
}
Expand Down Expand Up @@ -799,18 +802,18 @@ static void mptcp_pm_nl_rm_addr_or_subflow(struct mptcp_sock *msk,

mptcp_for_each_subflow_safe(msk, subflow, tmp) {
struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
u8 remote_id = READ_ONCE(subflow->remote_id);
int how = RCV_SHUTDOWN | SEND_SHUTDOWN;
u8 id = subflow->local_id;
u8 id = subflow_get_local_id(subflow);

if (rm_type == MPTCP_MIB_RMADDR && subflow->remote_id != rm_id)
if (rm_type == MPTCP_MIB_RMADDR && remote_id != rm_id)
continue;
if (rm_type == MPTCP_MIB_RMSUBFLOW && !mptcp_local_id_match(msk, id, rm_id))
continue;

pr_debug(" -> %s rm_list_ids[%d]=%u local_id=%u remote_id=%u mpc_id=%u",
rm_type == MPTCP_MIB_RMADDR ? "address" : "subflow",
i, rm_id, subflow->local_id, subflow->remote_id,
msk->mpc_endpoint_id);
i, rm_id, id, remote_id, msk->mpc_endpoint_id);
spin_unlock_bh(&msk->pm.lock);
mptcp_subflow_shutdown(sk, ssk, how);

Expand Down Expand Up @@ -901,7 +904,8 @@ static void __mptcp_pm_release_addr_entry(struct mptcp_pm_addr_entry *entry)
}

static int mptcp_pm_nl_append_new_local_addr(struct pm_nl_pernet *pernet,
struct mptcp_pm_addr_entry *entry)
struct mptcp_pm_addr_entry *entry,
bool needs_id)
{
struct mptcp_pm_addr_entry *cur, *del_entry = NULL;
unsigned int addr_max;
Expand Down Expand Up @@ -949,7 +953,7 @@ static int mptcp_pm_nl_append_new_local_addr(struct pm_nl_pernet *pernet,
}
}

if (!entry->addr.id) {
if (!entry->addr.id && needs_id) {
find_next:
entry->addr.id = find_next_zero_bit(pernet->id_bitmap,
MPTCP_PM_MAX_ADDR_ID + 1,
Expand All @@ -960,7 +964,7 @@ static int mptcp_pm_nl_append_new_local_addr(struct pm_nl_pernet *pernet,
}
}

if (!entry->addr.id)
if (!entry->addr.id && needs_id)
goto out;

__set_bit(entry->addr.id, pernet->id_bitmap);
Expand Down Expand Up @@ -1092,7 +1096,7 @@ int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct mptcp_addr_info *skc
entry->ifindex = 0;
entry->flags = MPTCP_PM_ADDR_FLAG_IMPLICIT;
entry->lsk = NULL;
ret = mptcp_pm_nl_append_new_local_addr(pernet, entry);
ret = mptcp_pm_nl_append_new_local_addr(pernet, entry, true);
if (ret < 0)
kfree(entry);

Expand Down Expand Up @@ -1285,6 +1289,18 @@ static int mptcp_nl_add_subflow_or_signal_addr(struct net *net)
return 0;
}

static bool mptcp_pm_has_addr_attr_id(const struct nlattr *attr,
struct genl_info *info)
{
struct nlattr *tb[MPTCP_PM_ADDR_ATTR_MAX + 1];

if (!nla_parse_nested_deprecated(tb, MPTCP_PM_ADDR_ATTR_MAX, attr,
mptcp_pm_address_nl_policy, info->extack) &&
tb[MPTCP_PM_ADDR_ATTR_ID])
return true;
return false;
}

int mptcp_pm_nl_add_addr_doit(struct sk_buff *skb, struct genl_info *info)
{
struct nlattr *attr = info->attrs[MPTCP_PM_ENDPOINT_ADDR];
Expand Down Expand Up @@ -1326,7 +1342,8 @@ int mptcp_pm_nl_add_addr_doit(struct sk_buff *skb, struct genl_info *info)
goto out_free;
}
}
ret = mptcp_pm_nl_append_new_local_addr(pernet, entry);
ret = mptcp_pm_nl_append_new_local_addr(pernet, entry,
!mptcp_pm_has_addr_attr_id(attr, info));
if (ret < 0) {
GENL_SET_ERR_MSG_FMT(info, "too many addresses or duplicate one: %d", ret);
goto out_free;
Expand Down Expand Up @@ -1980,7 +1997,7 @@ static int mptcp_event_add_subflow(struct sk_buff *skb, const struct sock *ssk)
if (WARN_ON_ONCE(!sf))
return -EINVAL;

if (nla_put_u8(skb, MPTCP_ATTR_LOC_ID, sf->local_id))
if (nla_put_u8(skb, MPTCP_ATTR_LOC_ID, subflow_get_local_id(sf)))
return -EMSGSIZE;

if (nla_put_u8(skb, MPTCP_ATTR_REM_ID, sf->remote_id))
Expand Down
15 changes: 8 additions & 7 deletions net/mptcp/pm_userspace.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ void mptcp_free_local_addr_list(struct mptcp_sock *msk)
}

static int mptcp_userspace_pm_append_new_local_addr(struct mptcp_sock *msk,
struct mptcp_pm_addr_entry *entry)
struct mptcp_pm_addr_entry *entry,
bool needs_id)
{
DECLARE_BITMAP(id_bitmap, MPTCP_PM_MAX_ADDR_ID + 1);
struct mptcp_pm_addr_entry *match = NULL;
Expand All @@ -41,7 +42,7 @@ static int mptcp_userspace_pm_append_new_local_addr(struct mptcp_sock *msk,
spin_lock_bh(&msk->pm.lock);
list_for_each_entry(e, &msk->pm.userspace_pm_local_addr_list, list) {
addr_match = mptcp_addresses_equal(&e->addr, &entry->addr, true);
if (addr_match && entry->addr.id == 0)
if (addr_match && entry->addr.id == 0 && needs_id)
entry->addr.id = e->addr.id;
id_match = (e->addr.id == entry->addr.id);
if (addr_match && id_match) {
Expand All @@ -64,7 +65,7 @@ static int mptcp_userspace_pm_append_new_local_addr(struct mptcp_sock *msk,
}

*e = *entry;
if (!e->addr.id)
if (!e->addr.id && needs_id)
e->addr.id = find_next_zero_bit(id_bitmap,
MPTCP_PM_MAX_ADDR_ID + 1,
1);
Expand Down Expand Up @@ -153,7 +154,7 @@ int mptcp_userspace_pm_get_local_id(struct mptcp_sock *msk,
if (new_entry.addr.port == msk_sport)
new_entry.addr.port = 0;

return mptcp_userspace_pm_append_new_local_addr(msk, &new_entry);
return mptcp_userspace_pm_append_new_local_addr(msk, &new_entry, true);
}

int mptcp_pm_nl_announce_doit(struct sk_buff *skb, struct genl_info *info)
Expand Down Expand Up @@ -198,7 +199,7 @@ int mptcp_pm_nl_announce_doit(struct sk_buff *skb, struct genl_info *info)
goto announce_err;
}

err = mptcp_userspace_pm_append_new_local_addr(msk, &addr_val);
err = mptcp_userspace_pm_append_new_local_addr(msk, &addr_val, false);
if (err < 0) {
GENL_SET_ERR_MSG(info, "did not match address and id");
goto announce_err;
Expand Down Expand Up @@ -233,7 +234,7 @@ static int mptcp_userspace_pm_remove_id_zero_address(struct mptcp_sock *msk,

lock_sock(sk);
mptcp_for_each_subflow(msk, subflow) {
if (subflow->local_id == 0) {
if (READ_ONCE(subflow->local_id) == 0) {
has_id_0 = true;
break;
}
Expand Down Expand Up @@ -378,7 +379,7 @@ int mptcp_pm_nl_subflow_create_doit(struct sk_buff *skb, struct genl_info *info)
}

local.addr = addr_l;
err = mptcp_userspace_pm_append_new_local_addr(msk, &local);
err = mptcp_userspace_pm_append_new_local_addr(msk, &local, false);
if (err < 0) {
GENL_SET_ERR_MSG(info, "did not match address and id");
goto create_err;
Expand Down
2 changes: 1 addition & 1 deletion net/mptcp/protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ static int __mptcp_socket_create(struct mptcp_sock *msk)
subflow->subflow_id = msk->subflow_id++;

/* This is the first subflow, always with id 0 */
subflow->local_id_valid = 1;
WRITE_ONCE(subflow->local_id, 0);
mptcp_sock_graft(msk->first, sk->sk_socket);
iput(SOCK_INODE(ssock));

Expand Down
15 changes: 12 additions & 3 deletions net/mptcp/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -491,10 +491,9 @@ struct mptcp_subflow_context {
remote_key_valid : 1, /* received the peer key from */
disposable : 1, /* ctx can be free at ulp release time */
stale : 1, /* unable to snd/rcv data, do not use for xmit */
local_id_valid : 1, /* local_id is correctly initialized */
valid_csum_seen : 1, /* at least one csum validated */
is_mptfo : 1, /* subflow is doing TFO */
__unused : 9;
__unused : 10;
bool data_avail;
bool scheduled;
u32 remote_nonce;
Expand All @@ -505,7 +504,7 @@ struct mptcp_subflow_context {
u8 hmac[MPTCPOPT_HMAC_LEN]; /* MPJ subflow only */
u64 iasn; /* initial ack sequence number, MPC subflows only */
};
u8 local_id;
s16 local_id; /* if negative not initialized yet */
u8 remote_id;
u8 reset_seen:1;
u8 reset_transient:1;
Expand Down Expand Up @@ -556,6 +555,7 @@ mptcp_subflow_ctx_reset(struct mptcp_subflow_context *subflow)
{
memset(&subflow->reset, 0, sizeof(subflow->reset));
subflow->request_mptcp = 1;
WRITE_ONCE(subflow->local_id, -1);
}

static inline u64
Expand Down Expand Up @@ -1022,6 +1022,15 @@ int mptcp_pm_get_local_id(struct mptcp_sock *msk, struct sock_common *skc);
int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct mptcp_addr_info *skc);
int mptcp_userspace_pm_get_local_id(struct mptcp_sock *msk, struct mptcp_addr_info *skc);

static inline u8 subflow_get_local_id(const struct mptcp_subflow_context *subflow)
{
int local_id = READ_ONCE(subflow->local_id);

if (local_id < 0)
return 0;
return local_id;
}

void __init mptcp_pm_nl_init(void);
void mptcp_pm_nl_work(struct mptcp_sock *msk);
void mptcp_pm_nl_rm_subflow_received(struct mptcp_sock *msk,
Expand Down
15 changes: 8 additions & 7 deletions net/mptcp/subflow.c
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,7 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb)
subflow->backup = mp_opt.backup;
subflow->thmac = mp_opt.thmac;
subflow->remote_nonce = mp_opt.nonce;
subflow->remote_id = mp_opt.join_id;
WRITE_ONCE(subflow->remote_id, mp_opt.join_id);
pr_debug("subflow=%p, thmac=%llu, remote_nonce=%u backup=%d",
subflow, subflow->thmac, subflow->remote_nonce,
subflow->backup);
Expand Down Expand Up @@ -577,8 +577,8 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb)

static void subflow_set_local_id(struct mptcp_subflow_context *subflow, int local_id)
{
subflow->local_id = local_id;
subflow->local_id_valid = 1;
WARN_ON_ONCE(local_id < 0 || local_id > 255);
WRITE_ONCE(subflow->local_id, local_id);
}

static int subflow_chk_local_id(struct sock *sk)
Expand All @@ -587,7 +587,7 @@ static int subflow_chk_local_id(struct sock *sk)
struct mptcp_sock *msk = mptcp_sk(subflow->conn);
int err;

if (likely(subflow->local_id_valid))
if (likely(subflow->local_id >= 0))
return 0;

err = mptcp_pm_get_local_id(msk, (struct sock_common *)sk);
Expand Down Expand Up @@ -1567,7 +1567,7 @@ int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_addr_info *loc,
pr_debug("msk=%p remote_token=%u local_id=%d remote_id=%d", msk,
remote_token, local_id, remote_id);
subflow->remote_token = remote_token;
subflow->remote_id = remote_id;
WRITE_ONCE(subflow->remote_id, remote_id);
subflow->request_join = 1;
subflow->request_bkup = !!(flags & MPTCP_PM_ADDR_FLAG_BACKUP);
subflow->subflow_id = msk->subflow_id++;
Expand Down Expand Up @@ -1731,6 +1731,7 @@ static struct mptcp_subflow_context *subflow_create_ctx(struct sock *sk,
pr_debug("subflow=%p", ctx);

ctx->tcp_sock = sk;
WRITE_ONCE(ctx->local_id, -1);

return ctx;
}
Expand Down Expand Up @@ -1966,14 +1967,14 @@ static void subflow_ulp_clone(const struct request_sock *req,
new_ctx->idsn = subflow_req->idsn;

/* this is the first subflow, id is always 0 */
new_ctx->local_id_valid = 1;
subflow_set_local_id(new_ctx, 0);
} else if (subflow_req->mp_join) {
new_ctx->ssn_offset = subflow_req->ssn_offset;
new_ctx->mp_join = 1;
new_ctx->fully_established = 1;
new_ctx->remote_key_valid = 1;
new_ctx->backup = subflow_req->backup;
new_ctx->remote_id = subflow_req->remote_id;
WRITE_ONCE(new_ctx->remote_id, subflow_req->remote_id);
new_ctx->token = subflow_req->token;
new_ctx->thmac = subflow_req->thmac;

Expand Down
2 changes: 1 addition & 1 deletion net/tls/tls_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1003,7 +1003,7 @@ static u16 tls_user_config(struct tls_context *ctx, bool tx)
return 0;
}

static int tls_get_info(const struct sock *sk, struct sk_buff *skb)
static int tls_get_info(struct sock *sk, struct sk_buff *skb)
{
u16 version, cipher_type;
struct tls_context *ctx;
Expand Down
Loading

0 comments on commit 398b7c3

Please sign in to comment.