Page MenuHomeFreeBSD

kern: soclose: don't sleep on SO_LINGER w/ timeout=0
ClosedPublic

Authored by kevans on Nov 28 2020, 5:57 PM.
Tags
None
Referenced Files
Unknown Object (File)
Wed, Nov 20, 5:16 AM
Unknown Object (File)
Sep 27 2024, 3:28 PM
Unknown Object (File)
Sep 26 2024, 12:02 PM
Unknown Object (File)
Sep 22 2024, 11:30 PM
Unknown Object (File)
Sep 22 2024, 7:25 PM
Unknown Object (File)
Sep 21 2024, 8:27 PM
Unknown Object (File)
Sep 21 2024, 6:06 AM
Unknown Object (File)
Sep 18 2024, 7:38 PM
Subscribers

Details

Summary

This is a valid scenario that's handled in the various protocol layers where it makes sense (e.g., tcp_disconnect and sctp_disconnect).

This lead to panics with INVARIANTS, and on non-INVARIANTS would result in the thread hanging until a signal interrupts it.

Reported by: syzbot+e625d92c1dd74e402c81@syzkaller.appspotmail.com

Diff Detail

Repository
rS FreeBSD src repository - subversion
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

It might be worthwhile to update the setsockopt(2) man page clarifying the behaviour of so_linger == 0.

This revision is now accepted and ready to land.Nov 28 2020, 6:17 PM

It might be worthwhile to update the setsockopt(2) man page clarifying the behaviour of so_linger == 0.

Sure- I'll follow up with a manpage update... I'm looking at how we're handling the non-0 case, and I think it also needs a little re-working to handle some corner case. Right now we'll wait up until the linger interval has elapsed unless we see a wakeup on so->so_timeo, at which point we'll again wait until the entirety of the linger interval has elapsed again -- but any scenario that leaves me blocked for any significant amount over the linger interval would be surprising to me as an application developer.

My gut reaction is that we should probably be tracking how long we've slept thus far in case we've been woken up by some path other than soisdisconnected(), or we should make it clear why we would expect to get woken up early enough that the discrepancy is not a concern.

It might be worthwhile to update the setsockopt(2) man page clarifying the behaviour of so_linger == 0.

Sure- I'll follow up with a manpage update... I'm looking at how we're handling the non-0 case, and I think it also needs a little re-working to handle some corner case. Right now we'll wait up until the linger interval has elapsed unless we see a wakeup on so->so_timeo, at which point we'll again wait until the entirety of the linger interval has elapsed again -- but any scenario that leaves me blocked for any significant amount over the linger interval would be surprising to me as an application developer.

How do we get a spurious wakeup? It looks like we're specifically waiting for the transition to SS_ISDISCONNECTED. At the point where we're sleeping, a disconnect has already been initiated. I don't see anything in the TCP or SCTP code that would wake us up for any other reason.

My gut reaction is that we should probably be tracking how long we've slept thus far in case we've been woken up by some path other than soisdisconnected(), or we should make it clear why we would expect to get woken up early enough that the discrepancy is not a concern.

It might be worthwhile to update the setsockopt(2) man page clarifying the behaviour of so_linger == 0.

Sure- I'll follow up with a manpage update... I'm looking at how we're handling the non-0 case, and I think it also needs a little re-working to handle some corner case. Right now we'll wait up until the linger interval has elapsed unless we see a wakeup on so->so_timeo, at which point we'll again wait until the entirety of the linger interval has elapsed again -- but any scenario that leaves me blocked for any significant amount over the linger interval would be surprising to me as an application developer.

How do we get a spurious wakeup? It looks like we're specifically waiting for the transition to SS_ISDISCONNECTED. At the point where we're sleeping, a disconnect has already been initiated. I don't see anything in the TCP or SCTP code that would wake us up for any other reason.

This is part of my question as well... it's written as if it's possible, given the loop. Userland cannot call any of these so*() that might wake it up because the fd's already been removed, but I haven't dug into what else might call them in-kernel to determine if the state change is something that can safely be asserted on error == 0.

It might be worthwhile to update the setsockopt(2) man page clarifying the behaviour of so_linger == 0.

Sure- I'll follow up with a manpage update... I'm looking at how we're handling the non-0 case, and I think it also needs a little re-working to handle some corner case. Right now we'll wait up until the linger interval has elapsed unless we see a wakeup on so->so_timeo, at which point we'll again wait until the entirety of the linger interval has elapsed again -- but any scenario that leaves me blocked for any significant amount over the linger interval would be surprising to me as an application developer.

How do we get a spurious wakeup? It looks like we're specifically waiting for the transition to SS_ISDISCONNECTED. At the point where we're sleeping, a disconnect has already been initiated. I don't see anything in the TCP or SCTP code that would wake us up for any other reason.

This is part of my question as well... it's written as if it's possible, given the loop. Userland cannot call any of these so*() that might wake it up because the fd's already been removed, but I haven't dug into what else might call them in-kernel to determine if the state change is something that can safely be asserted on error == 0.

My guess is that it was written that way defensively: if (<cond>) sleep-on-cond(); is a common programming mistake when the condition isn't sticky.