strparser: make sure __strp_recv isn't running before tearing down the parser

The comment above strp_done() claims that if strp is stopped,
strp_recv will no longer be called. That's only true if the caller has
a mechanism (eg locking) to guarantee that strp_recv() calls that
started before strp_stop() have completed by the time we call
strp_done().

This adds a dummy lock_sock/release_sock pair to guarantee that any
in-flight strp_recv() (which runs under either bh_lock_sock or
lock_sock, depending if it's called from ->sk_data_ready or strp_work)
has completed.

Only espintcp can be affected by this race condition, but this patch
makes sure no future user of strp can have the bug.

This could crash on strp->sk ("general mode" of strp), but this mode
has been here for 9 years and has never been used. It'll be gone soon,
no point worrying about it.

Switch the stopped/paused/etc bits to u8's to avoid races between
strp_stop() and strp_pause/unpause().

A reproducer has been published and turns the possible UAF into an
exploit [1].

Reported-by: Hyunwoo Kim <imv4bel@gmail.com>
Link: https://lore.kernel.org/all/aZLn2Faeg1FB7XOf@v4bel/
Link: https://lore.kernel.org/all/aZgpkyTDU3aXe_V0@v4bel/
Link: https://github.com/m0x41nos/RustyTux [1]
Fixes: e27cca96cd ("xfrm: add espintcp (RFC 8229)")
Cc: stable@vger.kernel.org
Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
Reviewed-by: Hyunwoo Kim <imv4bel@gmail.com>
Link: https://patch.msgid.link/425d9d926709b542ed5331110c19fee4aee1f28d.1791206940.git.sd@queasysnail.net
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Sabrina Dubroca authored and Jakub Kicinski committed 2026-10-06 18:29:12 -07:00
1 parent 538b529509
commit 0984ebc631
3 files changed
+11 -7

No files matched your search

+1 -1
View File
@@ -77,7 +77,7 @@ Functions
strp_done is called to release any resources held by the stream
parser instance. This must be called after the stream processor
has been stopped.
has been stopped. The socket lock must not be held.
::
+5 -5
View File
@@ -91,11 +91,11 @@ static inline struct strp_msg *strp_msg(struct sk_buff *skb)
struct strparser {
struct sock *sk;
u32 stopped : 1;
u32 paused : 1;
u32 aborted : 1;
u32 interrupted : 1;
u32 unrecov_intr : 1;
u8 stopped;
u8 paused;
u8 aborted;
u8 interrupted;
u8 unrecov_intr;
struct sk_buff **skb_nextp;
struct sk_buff *skb_head;
+5 -1
View File
@@ -505,12 +505,16 @@ void strp_unpause(struct strparser *strp)
EXPORT_SYMBOL_GPL(strp_unpause);
/* strp must already be stopped so that strp_recv will no longer be called.
* Note that strp_done is not called with the lower socket held.
* Note that strp_done must not be called with the lower socket held.
*/
void strp_done(struct strparser *strp)
{
WARN_ON(!strp->stopped);
lock_sock(strp->sk);
/* sync with pending strp_recv */
release_sock(strp->sk);
cancel_delayed_work_sync(&strp->msg_timer_work);
cancel_work_sync(&strp->work);