Merge branch 'mptcp-various-small-and-unrelated-improvements'

Matthieu Baerts says:

====================
mptcp: various small and unrelated improvements

Here are various unrelated patches:

- Patch 1: sched: remove unused structure.

- Patch 2: sched: split the validation part, a preparation for later.

- Patch 3: pm: clarify code, not to think there is a possible UaF.
  Note: a previous version has already been sent individually to Netdev.

- Patch 4: subflow: simplify subflow_hmac_valid by passing subflow_req.

- Patch 5: mib: add counter for MPJoin rejected by the PM.

- Patch 6: selftests: validate this new MPJoinRejected counter.

- Patch 7: selftests: define nlh variable only where needed.

- Patch 8: selftests: show how to use IPPROTO_MPTCP with getaddrinfo.
  Note: a previous version has already been sent individually to Netdev.

v1: https://lore.kernel.org/20250411-net-next-mptcp-sched-mib-sft-misc-v1-0-85ac8c6654c3@kernel.org
====================

Link: https://patch.msgid.link/20250413-net-next-mptcp-sched-mib-sft-misc-v2-0-0f83a4350150@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2025-04-15 08:21:49 -07:00
commit cd6d627f73
11 changed files with 80 additions and 46 deletions

View File

@ -101,18 +101,9 @@ struct mptcp_out_options {
#define MPTCP_SCHED_MAX 128
#define MPTCP_SCHED_BUF_MAX (MPTCP_SCHED_NAME_MAX * MPTCP_SCHED_MAX)
#define MPTCP_SUBFLOWS_MAX 8
struct mptcp_sched_data {
u8 subflows;
struct mptcp_subflow_context *contexts[MPTCP_SUBFLOWS_MAX];
};
struct mptcp_sched_ops {
int (*get_send)(struct mptcp_sock *msk,
struct mptcp_sched_data *data);
int (*get_retrans)(struct mptcp_sock *msk,
struct mptcp_sched_data *data);
int (*get_send)(struct mptcp_sock *msk);
int (*get_retrans)(struct mptcp_sock *msk);
char name[MPTCP_SCHED_NAME_MAX];
struct module *owner;

View File

@ -28,6 +28,7 @@ static const struct snmp_mib mptcp_snmp_list[] = {
SNMP_MIB_ITEM("MPJoinSynAckHMacFailure", MPTCP_MIB_JOINSYNACKMAC),
SNMP_MIB_ITEM("MPJoinAckRx", MPTCP_MIB_JOINACKRX),
SNMP_MIB_ITEM("MPJoinAckHMacFailure", MPTCP_MIB_JOINACKMAC),
SNMP_MIB_ITEM("MPJoinRejected", MPTCP_MIB_JOINREJECTED),
SNMP_MIB_ITEM("MPJoinSynTx", MPTCP_MIB_JOINSYNTX),
SNMP_MIB_ITEM("MPJoinSynTxCreatSkErr", MPTCP_MIB_JOINSYNTXCREATSKERR),
SNMP_MIB_ITEM("MPJoinSynTxBindErr", MPTCP_MIB_JOINSYNTXBINDERR),

View File

@ -23,6 +23,7 @@ enum linux_mptcp_mib_field {
MPTCP_MIB_JOINSYNACKMAC, /* HMAC was wrong on SYN/ACK + MP_JOIN */
MPTCP_MIB_JOINACKRX, /* Received an ACK + MP_JOIN */
MPTCP_MIB_JOINACKMAC, /* HMAC was wrong on ACK + MP_JOIN */
MPTCP_MIB_JOINREJECTED, /* The PM rejected the JOIN request */
MPTCP_MIB_JOINSYNTX, /* Sending a SYN + MP_JOIN */
MPTCP_MIB_JOINSYNTXCREATSKERR, /* Not able to create a socket when sending a SYN + MP_JOIN */
MPTCP_MIB_JOINSYNTXBINDERR, /* Not able to bind() the address when sending a SYN + MP_JOIN */

View File

@ -151,10 +151,13 @@ bool mptcp_remove_anno_list_by_saddr(struct mptcp_sock *msk,
const struct mptcp_addr_info *addr)
{
struct mptcp_pm_add_entry *entry;
bool ret;
entry = mptcp_pm_del_add_timer(msk, addr, false);
ret = entry;
kfree(entry);
return entry;
return ret;
}
bool mptcp_pm_sport_in_anno_list(struct mptcp_sock *msk, const struct sock *sk)

View File

@ -3527,8 +3527,10 @@ bool mptcp_finish_join(struct sock *ssk)
return true;
}
if (!mptcp_pm_allow_new_subflow(msk))
if (!mptcp_pm_allow_new_subflow(msk)) {
MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_JOINREJECTED);
goto err_prohibited;
}
/* If we can't acquire msk socket lock here, let the release callback
* handle it

View File

@ -744,6 +744,7 @@ void mptcp_info2sockaddr(const struct mptcp_addr_info *info,
struct sockaddr_storage *addr,
unsigned short family);
struct mptcp_sched_ops *mptcp_sched_find(const char *name);
int mptcp_validate_scheduler(struct mptcp_sched_ops *sched);
int mptcp_register_scheduler(struct mptcp_sched_ops *sched);
void mptcp_unregister_scheduler(struct mptcp_sched_ops *sched);
void mptcp_sched_init(void);

View File

@ -16,8 +16,7 @@
static DEFINE_SPINLOCK(mptcp_sched_list_lock);
static LIST_HEAD(mptcp_sched_list);
static int mptcp_sched_default_get_send(struct mptcp_sock *msk,
struct mptcp_sched_data *data)
static int mptcp_sched_default_get_send(struct mptcp_sock *msk)
{
struct sock *ssk;
@ -29,8 +28,7 @@ static int mptcp_sched_default_get_send(struct mptcp_sock *msk,
return 0;
}
static int mptcp_sched_default_get_retrans(struct mptcp_sock *msk,
struct mptcp_sched_data *data)
static int mptcp_sched_default_get_retrans(struct mptcp_sock *msk)
{
struct sock *ssk;
@ -84,10 +82,23 @@ void mptcp_get_available_schedulers(char *buf, size_t maxlen)
rcu_read_unlock();
}
int mptcp_validate_scheduler(struct mptcp_sched_ops *sched)
{
if (!sched->get_send) {
pr_err("%s does not implement required ops\n", sched->name);
return -EINVAL;
}
return 0;
}
int mptcp_register_scheduler(struct mptcp_sched_ops *sched)
{
if (!sched->get_send)
return -EINVAL;
int ret;
ret = mptcp_validate_scheduler(sched);
if (ret)
return ret;
spin_lock(&mptcp_sched_list_lock);
if (mptcp_sched_find(sched->name)) {
@ -157,7 +168,6 @@ void mptcp_subflow_set_scheduled(struct mptcp_subflow_context *subflow,
int mptcp_sched_get_send(struct mptcp_sock *msk)
{
struct mptcp_subflow_context *subflow;
struct mptcp_sched_data *data = NULL;
msk_owned_by_me(msk);
@ -178,14 +188,13 @@ int mptcp_sched_get_send(struct mptcp_sock *msk)
}
if (msk->sched == &mptcp_sched_default || !msk->sched)
return mptcp_sched_default_get_send(msk, data);
return msk->sched->get_send(msk, data);
return mptcp_sched_default_get_send(msk);
return msk->sched->get_send(msk);
}
int mptcp_sched_get_retrans(struct mptcp_sock *msk)
{
struct mptcp_subflow_context *subflow;
struct mptcp_sched_data *data = NULL;
msk_owned_by_me(msk);
@ -199,8 +208,8 @@ int mptcp_sched_get_retrans(struct mptcp_sock *msk)
}
if (msk->sched == &mptcp_sched_default || !msk->sched)
return mptcp_sched_default_get_retrans(msk, data);
return mptcp_sched_default_get_retrans(msk);
if (msk->sched->get_retrans)
return msk->sched->get_retrans(msk, data);
return msk->sched->get_send(msk, data);
return msk->sched->get_retrans(msk);
return msk->sched->get_send(msk);
}

View File

@ -247,6 +247,7 @@ static int subflow_check_req(struct request_sock *req,
if (unlikely(req->syncookie)) {
if (!mptcp_can_accept_new_subflow(subflow_req->msk)) {
SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINREJECTED);
subflow_add_reset_reason(skb, MPTCP_RST_EPROHIBIT);
return -EPERM;
}
@ -745,15 +746,11 @@ struct request_sock *mptcp_subflow_reqsk_alloc(const struct request_sock_ops *op
EXPORT_SYMBOL(mptcp_subflow_reqsk_alloc);
/* validate hmac received in third ACK */
static bool subflow_hmac_valid(const struct request_sock *req,
static bool subflow_hmac_valid(const struct mptcp_subflow_request_sock *subflow_req,
const struct mptcp_options_received *mp_opt)
{
const struct mptcp_subflow_request_sock *subflow_req;
struct mptcp_sock *msk = subflow_req->msk;
u8 hmac[SHA256_DIGEST_SIZE];
struct mptcp_sock *msk;
subflow_req = mptcp_subflow_rsk(req);
msk = subflow_req->msk;
subflow_generate_hmac(READ_ONCE(msk->remote_key),
READ_ONCE(msk->local_key),
@ -899,13 +896,14 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,
goto dispose_child;
}
if (!subflow_hmac_valid(req, &mp_opt)) {
if (!subflow_hmac_valid(subflow_req, &mp_opt)) {
SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINACKMAC);
subflow_add_reset_reason(skb, MPTCP_RST_EPROHIBIT);
goto dispose_child;
}
if (!mptcp_can_accept_new_subflow(owner)) {
SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINREJECTED);
subflow_add_reset_reason(skb, MPTCP_RST_EPROHIBIT);
goto dispose_child;
}

View File

@ -180,13 +180,26 @@ static void xgetnameinfo(const struct sockaddr *addr, socklen_t addrlen,
}
static void xgetaddrinfo(const char *node, const char *service,
const struct addrinfo *hints,
struct addrinfo *hints,
struct addrinfo **res)
{
again:
int err = getaddrinfo(node, service, hints, res);
if (err) {
const char *errstr = getxinfo_strerr(err);
const char *errstr;
/* glibc starts to support MPTCP since v2.42.
* For older versions, use IPPROTO_TCP to resolve,
* and use TCP/MPTCP to create socket.
* Link: https://sourceware.org/git/?p=glibc.git;a=commit;h=a8e9022e0f82
*/
if (err == EAI_SOCKTYPE) {
hints->ai_protocol = IPPROTO_TCP;
goto again;
}
errstr = getxinfo_strerr(err);
fprintf(stderr, "Fatal: getaddrinfo(%s:%s): %s\n",
node ? node : "", service ? service : "", errstr);
@ -292,7 +305,7 @@ static int sock_listen_mptcp(const char * const listenaddr,
{
int sock = -1;
struct addrinfo hints = {
.ai_protocol = IPPROTO_TCP,
.ai_protocol = IPPROTO_MPTCP,
.ai_socktype = SOCK_STREAM,
.ai_flags = AI_PASSIVE | AI_NUMERICHOST
};
@ -356,7 +369,7 @@ static int sock_connect_mptcp(const char * const remoteaddr,
int infd, struct wstate *winfo)
{
struct addrinfo hints = {
.ai_protocol = IPPROTO_TCP,
.ai_protocol = IPPROTO_MPTCP,
.ai_socktype = SOCK_STREAM,
};
struct addrinfo *a, *addr;

View File

@ -185,9 +185,10 @@ static void parse_nlmsg(struct nlmsghdr *nlh)
}
}
static void recv_nlmsg(int fd, struct nlmsghdr *nlh)
static void recv_nlmsg(int fd)
{
char rcv_buff[8192];
struct nlmsghdr *nlh = (struct nlmsghdr *)rcv_buff;
struct sockaddr_nl rcv_nladdr = {
.nl_family = AF_NETLINK
};
@ -204,7 +205,6 @@ static void recv_nlmsg(int fd, struct nlmsghdr *nlh)
int len;
len = recvmsg(fd, &rcv_msg, 0);
nlh = (struct nlmsghdr *)rcv_buff;
while (NLMSG_OK(nlh, len)) {
if (nlh->nlmsg_type == NLMSG_DONE) {
@ -225,7 +225,6 @@ static void recv_nlmsg(int fd, struct nlmsghdr *nlh)
static void get_mptcpinfo(__u32 token)
{
struct nlmsghdr *nlh = NULL;
int fd;
fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG);
@ -233,7 +232,7 @@ static void get_mptcpinfo(__u32 token)
die_perror("Netlink socket");
send_query(fd, token);
recv_nlmsg(fd, nlh);
recv_nlmsg(fd);
close(fd);
}

View File

@ -62,6 +62,7 @@ unset sflags
unset fastclose
unset fullmesh
unset speed
unset join_syn_rej
unset join_csum_ns1
unset join_csum_ns2
unset join_fail_nr
@ -1403,6 +1404,7 @@ chk_join_nr()
local syn_nr=$1
local syn_ack_nr=$2
local ack_nr=$3
local syn_rej=${join_syn_rej:-0}
local csum_ns1=${join_csum_ns1:-0}
local csum_ns2=${join_csum_ns2:-0}
local fail_nr=${join_fail_nr:-0}
@ -1468,6 +1470,15 @@ chk_join_nr()
fail_test "got $count JOIN[s] ack HMAC failure expected 0"
fi
count=$(mptcp_lib_get_counter ${ns1} "MPTcpExtMPJoinRejected")
if [ -z "$count" ]; then
rc=${KSFT_SKIP}
elif [ "$count" != "$syn_rej" ]; then
rc=${KSFT_FAIL}
print_check "syn rejected"
fail_test "got $count JOIN[s] syn rejected expected $syn_rej"
fi
print_results "join Rx" ${rc}
join_syn_tx="${join_syn_tx:-${syn_nr}}" \
@ -1963,7 +1974,8 @@ subflows_tests()
pm_nl_set_limits $ns2 0 1
pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow
run_tests $ns1 $ns2 10.0.1.1
chk_join_nr 1 1 0
join_syn_rej=1 \
chk_join_nr 1 1 0
fi
# subflow
@ -1992,7 +2004,8 @@ subflows_tests()
pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow
pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow
run_tests $ns1 $ns2 10.0.1.1
chk_join_nr 2 2 1
join_syn_rej=1 \
chk_join_nr 2 2 1
fi
# single subflow, dev
@ -3061,7 +3074,8 @@ syncookies_tests()
pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow
pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow
run_tests $ns1 $ns2 10.0.1.1
chk_join_nr 2 1 1
join_syn_rej=1 \
chk_join_nr 2 1 1
fi
# test signal address with cookies
@ -3545,7 +3559,8 @@ userspace_tests()
pm_nl_set_limits $ns2 1 1
pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow
run_tests $ns1 $ns2 10.0.1.1
chk_join_nr 1 1 0
join_syn_rej=1 \
chk_join_nr 1 1 0
fi
# userspace pm type does not send join
@ -3568,7 +3583,8 @@ userspace_tests()
pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow
sflags=backup speed=slow \
run_tests $ns1 $ns2 10.0.1.1
chk_join_nr 1 1 0
join_syn_rej=1 \
chk_join_nr 1 1 0
chk_prio_nr 0 0 0 0
fi