diff options
| author | Jason Baron <[email protected]> | 2018-08-03 21:24:53 +0000 |
|---|---|---|
| committer | David S. Miller <[email protected]> | 2018-08-03 23:44:19 +0000 |
| commit | 51f7e95187f127d5eadf50541943813ff57f12ba (patch) | |
| tree | bc23c743b9cf6bed86cd611cdc16e31b4bb4fb70 /net/core/utils.c | |
| parent | ppp: mppe: Remove VLA usage (diff) | |
| download | kernel-51f7e95187f127d5eadf50541943813ff57f12ba.tar.gz kernel-51f7e95187f127d5eadf50541943813ff57f12ba.zip | |
af_unix: ensure POLLOUT on remote close() for connected dgram socket
Applications use -ECONNREFUSED as returned from write() in order to
determine that a socket should be closed. However, when using connected
dgram unix sockets in a poll/write loop, a final POLLOUT event can be
missed when the remote end closes. Thus, the poll is stuck forever:
thread 1 (client) thread 2 (server)
connect() to server
write() returns -EAGAIN
unix_dgram_poll()
-> unix_recvq_full() is true
close()
->unix_release_sock()
->wake_up_interruptible_all()
unix_dgram_poll() (due to the
wake_up_interruptible_all)
-> unix_recvq_full() still is true
->free all skbs
Now thread 1 is stuck and will not receive anymore wakeups. In this
case, when thread 1 gets the -EAGAIN, it has not queued any skbs
otherwise the 'free all skbs' step would in fact cause a wakeup and
a POLLOUT return. So the race here is probably fairly rare because
it means there are no skbs that thread 1 queued and that thread 1
schedules before the 'free all skbs' step.
This issue was reported as a hang when /dev/log is closed.
The fix is to signal POLLOUT if the socket is marked as SOCK_DEAD, which
means a subsequent write() will get -ECONNREFUSED.
Reported-by: Ian Lance Taylor <[email protected]>
Cc: David Rientjes <[email protected]>
Cc: Rainer Weikusat <[email protected]>
Cc: Eric Dumazet <[email protected]>
Signed-off-by: Jason Baron <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
Diffstat (limited to 'net/core/utils.c')
0 files changed, 0 insertions, 0 deletions
