mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-10-26 10:57:38 +08:00
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:
1 parent
538b529509
commit
0984ebc631
3 files changed
+11
-7
No files matched your search
@@ -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.
|
||||
|
||||
::
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in new issue
Block a user