mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 04:34:03 +02:00
Merge branch 'mptcp-misc-fixes-for-v7-2-rc6'
Matthieu Baerts says: ==================== mptcp: misc fixes for v7.2-rc6 Here are various unrelated fixes: - Patches 1-3: harden incoming MPTCP suboptions parsing by rejecting non-combinable ones. Patch 3 removes unreachable code after patch 2 added here for consistency, and to reduce comments from AI reviews. Fixes for v5.6. - Patch 4: fix a data race in the ADD_ADDR timer callback. A fix for v5.13. - Patch 5: correctly catch data corruption during the MPTCP join selftest by marking tests as failed, instead of only printing a warning. A fix for v5.18. - Patch 6: fix a leak with the userspace ADD_ADDR list in case of race condition during teardown. A fix for v5.19. - Patch 7: deal with MPTFO with a valid token, but no data in the SYN. A fix for v6.2. - Patch 8: reclaim forward-allocated memory in case of error on the receive side. A fix for v6.19. ==================== Link: https://patch.msgid.link/20260803-net-mptcp-misc-fixes-7-2-rc6-v2-0-b8f496d71664@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
c53900b3f1
|
|
@ -24,12 +24,13 @@ void mptcp_fastopen_subflow_synack_set_params(struct mptcp_subflow_context *subf
|
|||
sk = subflow->conn;
|
||||
tp = tcp_sk(ssk);
|
||||
|
||||
subflow->is_mptfo = 1;
|
||||
|
||||
/* A valid TFO cookie does not guarantee SYN data. */
|
||||
skb = skb_peek(&ssk->sk_receive_queue);
|
||||
if (WARN_ON_ONCE(!skb))
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
subflow->is_mptfo = 1;
|
||||
|
||||
/* dequeue the skb from sk receive queue */
|
||||
__skb_unlink(skb, &ssk->sk_receive_queue);
|
||||
skb_ext_reset(skb);
|
||||
|
|
|
|||
|
|
@ -50,6 +50,14 @@ static void mptcp_parse_option(const struct sk_buff *skb,
|
|||
}
|
||||
}
|
||||
|
||||
/* Only the MPC + ACK can be used with a RM_ADDR */
|
||||
if (subopt == OPTION_MPTCP_MPC_ACK) {
|
||||
if ((mp_opt->suboptions & ~OPTION_MPTCP_RM_ADDR) != 0)
|
||||
break;
|
||||
} else if (mp_opt->suboptions != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Cfr RFC 8684 Section 3.3.0:
|
||||
* If a checksum is present but its use had
|
||||
* not been negotiated in the MP_CAPABLE handshake, the receiver MUST
|
||||
|
|
@ -122,6 +130,11 @@ static void mptcp_parse_option(const struct sk_buff *skb,
|
|||
break;
|
||||
|
||||
case MPTCPOPT_MP_JOIN:
|
||||
/* Can be used with a restricted number of other options */
|
||||
if ((mp_opt->suboptions & ~(OPTION_MPTCP_RM_ADDR |
|
||||
OPTION_MPTCP_PRIO)) != 0)
|
||||
break;
|
||||
|
||||
if (opsize == TCPOLEN_MPTCP_MPJ_SYN) {
|
||||
mp_opt->suboptions |= OPTION_MPTCP_MPJ_SYN;
|
||||
mp_opt->backup = *ptr++ & MPTCPOPT_BACKUP;
|
||||
|
|
@ -153,6 +166,14 @@ static void mptcp_parse_option(const struct sk_buff *skb,
|
|||
break;
|
||||
|
||||
case MPTCPOPT_DSS:
|
||||
/* Can be used with a restricted number of other options */
|
||||
if ((mp_opt->suboptions & ~(OPTION_MPTCP_ADD_ADDR |
|
||||
OPTION_MPTCP_RM_ADDR |
|
||||
OPTION_MPTCP_PRIO |
|
||||
OPTION_MPTCP_FASTCLOSE |
|
||||
OPTION_MPTCP_FAIL)) != 0)
|
||||
break;
|
||||
|
||||
pr_debug("DSS\n");
|
||||
ptr++;
|
||||
|
||||
|
|
@ -188,8 +209,14 @@ static void mptcp_parse_option(const struct sk_buff *skb,
|
|||
* RFC 8684 Section 3.3.0 checks later in subflow_data_ready
|
||||
*/
|
||||
if (opsize != expected_opsize &&
|
||||
opsize != expected_opsize + TCPOLEN_MPTCP_DSS_CHECKSUM)
|
||||
opsize != expected_opsize + TCPOLEN_MPTCP_DSS_CHECKSUM) {
|
||||
mp_opt->dsn64 = 0;
|
||||
mp_opt->use_map = 0;
|
||||
mp_opt->ack64 = 0;
|
||||
mp_opt->use_ack = 0;
|
||||
mp_opt->data_fin = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
mp_opt->suboptions |= OPTION_MPTCP_DSS;
|
||||
if (mp_opt->use_ack) {
|
||||
|
|
@ -234,6 +261,12 @@ static void mptcp_parse_option(const struct sk_buff *skb,
|
|||
break;
|
||||
|
||||
case MPTCPOPT_ADD_ADDR:
|
||||
/* Can be used with a restricted number of other options */
|
||||
if ((mp_opt->suboptions & ~(OPTIONS_MPTCP_DSS |
|
||||
OPTION_MPTCP_RM_ADDR |
|
||||
OPTION_MPTCP_PRIO)) != 0)
|
||||
break;
|
||||
|
||||
mp_opt->echo = (*ptr++) & MPTCP_ADDR_ECHO;
|
||||
if (!mp_opt->echo) {
|
||||
if (opsize == TCPOLEN_MPTCP_ADD_ADDR ||
|
||||
|
|
@ -293,6 +326,14 @@ static void mptcp_parse_option(const struct sk_buff *skb,
|
|||
break;
|
||||
|
||||
case MPTCPOPT_RM_ADDR:
|
||||
/* Can be used with a restricted number of other options */
|
||||
if ((mp_opt->suboptions & ~(OPTION_MPTCP_MPC_ACK |
|
||||
OPTIONS_MPTCP_MPJ |
|
||||
OPTIONS_MPTCP_DSS |
|
||||
OPTION_MPTCP_ADD_ADDR |
|
||||
OPTION_MPTCP_PRIO)) != 0)
|
||||
break;
|
||||
|
||||
if (opsize < TCPOLEN_MPTCP_RM_ADDR_BASE + 1 ||
|
||||
opsize > TCPOLEN_MPTCP_RM_ADDR_BASE + MPTCP_RM_IDS_MAX)
|
||||
break;
|
||||
|
|
@ -307,6 +348,13 @@ static void mptcp_parse_option(const struct sk_buff *skb,
|
|||
break;
|
||||
|
||||
case MPTCPOPT_MP_PRIO:
|
||||
/* Can be used with a restricted number of other options */
|
||||
if ((mp_opt->suboptions & ~(OPTIONS_MPTCP_MPJ |
|
||||
OPTIONS_MPTCP_DSS |
|
||||
OPTION_MPTCP_ADD_ADDR |
|
||||
OPTION_MPTCP_RM_ADDR)) != 0)
|
||||
break;
|
||||
|
||||
if (opsize != TCPOLEN_MPTCP_PRIO)
|
||||
break;
|
||||
|
||||
|
|
@ -316,6 +364,11 @@ static void mptcp_parse_option(const struct sk_buff *skb,
|
|||
break;
|
||||
|
||||
case MPTCPOPT_MP_FASTCLOSE:
|
||||
/* Can be used with a restricted number of other options */
|
||||
if ((mp_opt->suboptions & ~(OPTIONS_MPTCP_DSS |
|
||||
OPTION_MPTCP_RST)) != 0)
|
||||
break;
|
||||
|
||||
if (opsize != TCPOLEN_MPTCP_FASTCLOSE)
|
||||
break;
|
||||
|
||||
|
|
@ -327,6 +380,11 @@ static void mptcp_parse_option(const struct sk_buff *skb,
|
|||
break;
|
||||
|
||||
case MPTCPOPT_RST:
|
||||
/* Can be used with a restricted number of other options */
|
||||
if ((mp_opt->suboptions & ~(OPTION_MPTCP_FAIL |
|
||||
OPTION_MPTCP_FASTCLOSE)) != 0)
|
||||
break;
|
||||
|
||||
if (opsize != TCPOLEN_MPTCP_RST)
|
||||
break;
|
||||
|
||||
|
|
@ -342,6 +400,11 @@ static void mptcp_parse_option(const struct sk_buff *skb,
|
|||
break;
|
||||
|
||||
case MPTCPOPT_MP_FAIL:
|
||||
/* Can be used with a restricted number of other options */
|
||||
if ((mp_opt->suboptions & ~(OPTIONS_MPTCP_DSS |
|
||||
OPTION_MPTCP_RST)) != 0)
|
||||
break;
|
||||
|
||||
if (opsize != TCPOLEN_MPTCP_FAIL)
|
||||
break;
|
||||
|
||||
|
|
@ -1400,7 +1463,7 @@ void mptcp_write_options(struct tcphdr *th, __be32 *ptr, struct tcp_sock *tp,
|
|||
* RM | C | C | C | P |------|------|------|------|
|
||||
* PRIO | X | C | C | C | C |------|------|------|
|
||||
* FAIL | X | X | C | X | X | X |------|------|
|
||||
* FC | X | X | X | X | X | X | X |------|
|
||||
* FC | X | X | P | X | X | X | X |------|
|
||||
* RST | X | X | X | X | X | X | O | O |
|
||||
* ------|------|------|------|------|------|------|------|------|
|
||||
*
|
||||
|
|
|
|||
|
|
@ -380,6 +380,7 @@ static void mptcp_pm_add_addr_timer(struct timer_list *timer)
|
|||
struct mptcp_sock *msk = entry->sock;
|
||||
struct sock *sk = (struct sock *)msk;
|
||||
unsigned int timeout = 0;
|
||||
bool retransmit;
|
||||
|
||||
pr_debug("msk=%p\n", msk);
|
||||
|
||||
|
|
@ -412,14 +413,15 @@ static void mptcp_pm_add_addr_timer(struct timer_list *timer)
|
|||
entry->retrans_times++;
|
||||
}
|
||||
|
||||
if (entry->retrans_times < ADD_ADDR_RETRANS_MAX)
|
||||
retransmit = entry->retrans_times < ADD_ADDR_RETRANS_MAX;
|
||||
if (retransmit)
|
||||
timeout <<= entry->retrans_times;
|
||||
else
|
||||
timeout = 0;
|
||||
|
||||
spin_unlock_bh(&msk->pm.lock);
|
||||
|
||||
if (entry->retrans_times == ADD_ADDR_RETRANS_MAX)
|
||||
if (!retransmit)
|
||||
mptcp_pm_subflow_established(msk);
|
||||
|
||||
out:
|
||||
|
|
@ -441,6 +443,9 @@ bool mptcp_pm_announced_alloc(struct mptcp_sock *msk,
|
|||
|
||||
lockdep_assert_held(&msk->pm.lock);
|
||||
|
||||
if (msk->pm.status & BIT(MPTCP_PM_DESTROYING))
|
||||
return false;
|
||||
|
||||
add_entry = mptcp_pm_announced_lookup(msk, addr);
|
||||
if (add_entry) {
|
||||
if (WARN_ON_ONCE(mptcp_pm_is_kernel(msk)))
|
||||
|
|
@ -1143,10 +1148,16 @@ void mptcp_pm_worker(struct mptcp_sock *msk)
|
|||
|
||||
void mptcp_pm_destroy(struct mptcp_sock *msk)
|
||||
{
|
||||
spin_lock_bh(&msk->pm.lock);
|
||||
msk->pm.status |= BIT(MPTCP_PM_DESTROYING);
|
||||
spin_unlock_bh(&msk->pm.lock);
|
||||
|
||||
mptcp_pm_free_announced_list(msk);
|
||||
|
||||
if (mptcp_pm_is_userspace(msk))
|
||||
mptcp_userspace_pm_free_local_addr_list(msk);
|
||||
/* Free the userspace local address list unconditionally: the socket
|
||||
* can be reused (mptcp_disconnect()) and re-selected to a different PM
|
||||
*/
|
||||
mptcp_userspace_pm_free_local_addr_list(msk);
|
||||
}
|
||||
|
||||
void mptcp_pm_data_reset(struct mptcp_sock *msk)
|
||||
|
|
|
|||
|
|
@ -54,6 +54,10 @@ static int mptcp_userspace_pm_append_new_local_addr(struct mptcp_sock *msk,
|
|||
bitmap_zero(id_bitmap, MPTCP_PM_MAX_ADDR_ID + 1);
|
||||
|
||||
spin_lock_bh(&msk->pm.lock);
|
||||
if (msk->pm.status & BIT(MPTCP_PM_DESTROYING)) {
|
||||
ret = -EINVAL;
|
||||
goto append_err;
|
||||
}
|
||||
mptcp_for_each_userspace_pm_addr(msk, e) {
|
||||
addr_match = mptcp_addresses_equal(&e->addr, &entry->addr, true);
|
||||
if (addr_match && entry->addr.id == 0 && needs_id)
|
||||
|
|
|
|||
|
|
@ -149,6 +149,12 @@ struct sock *__mptcp_nmpc_sk(struct mptcp_sock *msk)
|
|||
|
||||
static void mptcp_drop(struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
/* The skb forward memory was already transferred to sk by
|
||||
* mptcp_borrow_fwdmem(), even before setting the destructor.
|
||||
*/
|
||||
if (!skb->destructor)
|
||||
sk_mem_reclaim(sk);
|
||||
|
||||
sk_drops_skbadd(sk, skb);
|
||||
__kfree_skb(skb);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
OPTION_MPTCP_MPC_ACK)
|
||||
#define OPTIONS_MPTCP_MPJ (OPTION_MPTCP_MPJ_SYN | OPTION_MPTCP_MPJ_SYNACK | \
|
||||
OPTION_MPTCP_MPJ_ACK)
|
||||
#define OPTIONS_MPTCP_DSS (OPTION_MPTCP_DSS | OPTION_MPTCP_CSUMREQD)
|
||||
|
||||
/* MPTCP option subtypes */
|
||||
#define MPTCPOPT_MP_CAPABLE 0
|
||||
|
|
@ -189,9 +190,10 @@ enum mptcp_pm_status {
|
|||
MPTCP_PM_ESTABLISHED,
|
||||
MPTCP_PM_SUBFLOW_ESTABLISHED,
|
||||
MPTCP_PM_ALREADY_ESTABLISHED, /* persistent status, set after ESTABLISHED event */
|
||||
MPTCP_PM_MPC_ENDPOINT_ACCOUNTED /* persistent status, set after MPC local address is
|
||||
* accounted int id_avail_bitmap
|
||||
*/
|
||||
MPTCP_PM_MPC_ENDPOINT_ACCOUNTED, /* persistent status, set after MPC local address is
|
||||
* accounted int id_avail_bitmap
|
||||
*/
|
||||
MPTCP_PM_DESTROYING, /* To fence out PM list allocs */
|
||||
};
|
||||
|
||||
enum mptcp_pm_type {
|
||||
|
|
|
|||
|
|
@ -174,8 +174,6 @@ static int subflow_check_req(struct request_sock *req,
|
|||
|
||||
if (unlikely(listener->pm_listener))
|
||||
return subflow_reset_req_endp(req, skb);
|
||||
if (opt_mp_join)
|
||||
return 0;
|
||||
} else if (opt_mp_join) {
|
||||
SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINSYNRX);
|
||||
|
||||
|
|
@ -277,9 +275,6 @@ int mptcp_subflow_init_cookie_req(struct request_sock *req,
|
|||
|
||||
opt_mp_capable = !!(mp_opt.suboptions & OPTION_MPTCP_MPC_ACK);
|
||||
opt_mp_join = !!(mp_opt.suboptions & OPTION_MPTCP_MPJ_ACK);
|
||||
if (opt_mp_capable && opt_mp_join)
|
||||
return -EINVAL;
|
||||
|
||||
if (opt_mp_capable && listener->request_mptcp) {
|
||||
if (mp_opt.sndr_key == 0)
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -584,7 +584,7 @@ check_transfer()
|
|||
mv "$tmpfile" "$out"
|
||||
tmpfile=""
|
||||
fi
|
||||
cmp -l "$in" "$out" | while read -r i a b; do
|
||||
while read -r i a b; do
|
||||
local sum=$((0${a} + 0${b}))
|
||||
if [ $check_invert -eq 0 ] || [ $sum -ne $((0xff)) ]; then
|
||||
fail_test "$what does not match (in, out):"
|
||||
|
|
@ -595,7 +595,7 @@ check_transfer()
|
|||
else
|
||||
print_info "$what has inverted byte at ${i}"
|
||||
fi
|
||||
done
|
||||
done < <(cmp -l "$in" "$out")
|
||||
|
||||
return 0
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user