Skip to content

Commit 48e50dc

Browse files
matttbekuba-moo
authored andcommitted
mptcp: pm: avoid possible UaF when selecting endp
select_local_address() and select_signal_address() both select an endpoint entry from the list inside an RCU protected section, but return a reference to it, to be read later on. If the entry is dereferenced after the RCU unlock, reading info could cause a Use-after-Free. A simple solution is to copy the required info while inside the RCU protected section to avoid any risk of UaF later. The address ID might need to be modified later to handle the ID0 case later, so a copy seems OK to deal with. Reported-by: Paolo Abeni <[email protected]> Closes: https://lore.kernel.org/[email protected] Fixes: 01cacb0 ("mptcp: add netlink-based PM") Cc: [email protected] Reviewed-by: Mat Martineau <[email protected]> Signed-off-by: Matthieu Baerts (NGI0) <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 4878f9f commit 48e50dc

File tree

1 file changed

+34
-30
lines changed

1 file changed

+34
-30
lines changed

net/mptcp/pm_netlink.c

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,13 @@ static bool lookup_subflow_by_daddr(const struct list_head *list,
143143
return false;
144144
}
145145

146-
static struct mptcp_pm_addr_entry *
146+
static bool
147147
select_local_address(const struct pm_nl_pernet *pernet,
148-
const struct mptcp_sock *msk)
148+
const struct mptcp_sock *msk,
149+
struct mptcp_pm_addr_entry *new_entry)
149150
{
150-
struct mptcp_pm_addr_entry *entry, *ret = NULL;
151+
struct mptcp_pm_addr_entry *entry;
152+
bool found = false;
151153

152154
msk_owned_by_me(msk);
153155

@@ -159,17 +161,21 @@ select_local_address(const struct pm_nl_pernet *pernet,
159161
if (!test_bit(entry->addr.id, msk->pm.id_avail_bitmap))
160162
continue;
161163

162-
ret = entry;
164+
*new_entry = *entry;
165+
found = true;
163166
break;
164167
}
165168
rcu_read_unlock();
166-
return ret;
169+
170+
return found;
167171
}
168172

169-
static struct mptcp_pm_addr_entry *
170-
select_signal_address(struct pm_nl_pernet *pernet, const struct mptcp_sock *msk)
173+
static bool
174+
select_signal_address(struct pm_nl_pernet *pernet, const struct mptcp_sock *msk,
175+
struct mptcp_pm_addr_entry *new_entry)
171176
{
172-
struct mptcp_pm_addr_entry *entry, *ret = NULL;
177+
struct mptcp_pm_addr_entry *entry;
178+
bool found = false;
173179

174180
rcu_read_lock();
175181
/* do not keep any additional per socket state, just signal
@@ -184,11 +190,13 @@ select_signal_address(struct pm_nl_pernet *pernet, const struct mptcp_sock *msk)
184190
if (!(entry->flags & MPTCP_PM_ADDR_FLAG_SIGNAL))
185191
continue;
186192

187-
ret = entry;
193+
*new_entry = *entry;
194+
found = true;
188195
break;
189196
}
190197
rcu_read_unlock();
191-
return ret;
198+
199+
return found;
192200
}
193201

194202
unsigned int mptcp_pm_get_add_addr_signal_max(const struct mptcp_sock *msk)
@@ -512,9 +520,10 @@ __lookup_addr(struct pm_nl_pernet *pernet, const struct mptcp_addr_info *info)
512520

513521
static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk)
514522
{
515-
struct mptcp_pm_addr_entry *local, *signal_and_subflow = NULL;
516523
struct sock *sk = (struct sock *)msk;
524+
struct mptcp_pm_addr_entry local;
517525
unsigned int add_addr_signal_max;
526+
bool signal_and_subflow = false;
518527
unsigned int local_addr_max;
519528
struct pm_nl_pernet *pernet;
520529
unsigned int subflows_max;
@@ -565,23 +574,22 @@ static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk)
565574
if (msk->pm.addr_signal & BIT(MPTCP_ADD_ADDR_SIGNAL))
566575
return;
567576

568-
local = select_signal_address(pernet, msk);
569-
if (!local)
577+
if (!select_signal_address(pernet, msk, &local))
570578
goto subflow;
571579

572580
/* If the alloc fails, we are on memory pressure, not worth
573581
* continuing, and trying to create subflows.
574582
*/
575-
if (!mptcp_pm_alloc_anno_list(msk, &local->addr))
583+
if (!mptcp_pm_alloc_anno_list(msk, &local.addr))
576584
return;
577585

578-
__clear_bit(local->addr.id, msk->pm.id_avail_bitmap);
586+
__clear_bit(local.addr.id, msk->pm.id_avail_bitmap);
579587
msk->pm.add_addr_signaled++;
580-
mptcp_pm_announce_addr(msk, &local->addr, false);
588+
mptcp_pm_announce_addr(msk, &local.addr, false);
581589
mptcp_pm_nl_addr_send_ack(msk);
582590

583-
if (local->flags & MPTCP_PM_ADDR_FLAG_SUBFLOW)
584-
signal_and_subflow = local;
591+
if (local.flags & MPTCP_PM_ADDR_FLAG_SUBFLOW)
592+
signal_and_subflow = true;
585593
}
586594

587595
subflow:
@@ -592,26 +600,22 @@ static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk)
592600
bool fullmesh;
593601
int i, nr;
594602

595-
if (signal_and_subflow) {
596-
local = signal_and_subflow;
597-
signal_and_subflow = NULL;
598-
} else {
599-
local = select_local_address(pernet, msk);
600-
if (!local)
601-
break;
602-
}
603+
if (signal_and_subflow)
604+
signal_and_subflow = false;
605+
else if (!select_local_address(pernet, msk, &local))
606+
break;
603607

604-
fullmesh = !!(local->flags & MPTCP_PM_ADDR_FLAG_FULLMESH);
608+
fullmesh = !!(local.flags & MPTCP_PM_ADDR_FLAG_FULLMESH);
605609

606610
msk->pm.local_addr_used++;
607-
__clear_bit(local->addr.id, msk->pm.id_avail_bitmap);
608-
nr = fill_remote_addresses_vec(msk, &local->addr, fullmesh, addrs);
611+
__clear_bit(local.addr.id, msk->pm.id_avail_bitmap);
612+
nr = fill_remote_addresses_vec(msk, &local.addr, fullmesh, addrs);
609613
if (nr == 0)
610614
continue;
611615

612616
spin_unlock_bh(&msk->pm.lock);
613617
for (i = 0; i < nr; i++)
614-
__mptcp_subflow_connect(sk, &local->addr, &addrs[i]);
618+
__mptcp_subflow_connect(sk, &local.addr, &addrs[i]);
615619
spin_lock_bh(&msk->pm.lock);
616620
}
617621
mptcp_pm_nl_check_work_pending(msk);

0 commit comments

Comments
 (0)