JSSE: fix deadlock issues between SSLSocket close() and OutputStream write()

pull/230/head
Chris Conlon 2024-11-06 10:16:46 -07:00
parent 30e40424a8
commit fe40fe7575
1 changed files with 81 additions and 63 deletions

View File

@ -1937,18 +1937,16 @@ public class WolfSSLSocket extends SSLSocket {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"thread got ioLock (shutdown)"); "thread got ioLock (shutdown)");
synchronized (handshakeLock) { if ((this.getUseClientMode() == true) &&
if (this.getUseClientMode() == true && (handshakeFinished == true)) {
this.handshakeComplete == true) { WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, "saving WOLFSSL_SESSION into cache");
"saving WOLFSSL_SESSION into cache"); EngineHelper.saveSession();
EngineHelper.saveSession(); }
} else {
else { WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, "not saving WOLFSSL_SESSION into cache, " +
"not saving WOLFSSL_SESSION into cache, " + "not client or handshake not complete");
"not client or handshake not complete");
}
} }
try { try {
@ -2001,19 +1999,8 @@ public class WolfSSLSocket extends SSLSocket {
this.EngineHelper.clearObjectState(); this.EngineHelper.clearObjectState();
this.EngineHelper = null; this.EngineHelper = null;
/* Release Input/OutputStream objects. Do not WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
* close WolfSSLSocket inside stream close, "thread exiting handshakeLock (shutdown)");
* since we handle that next below and do
* differently depending on if autoClose has been
* set or not. */
if (this.inStream != null) {
this.inStream.close(false);
this.inStream = null;
}
if (this.outStream != null) {
this.outStream.close(false);
this.outStream = null;
}
} /* handshakeLock */ } /* handshakeLock */
@ -2021,6 +2008,23 @@ public class WolfSSLSocket extends SSLSocket {
"thread exiting ioLock (shutdown)"); "thread exiting ioLock (shutdown)");
} /* ioLock */ } /* ioLock */
/* Release Input/OutputStream objects. Do not close
* WolfSSLSocket inside stream close, since we handle that
* next below and do differently depending on if autoClose
* has been set or not. */
if (this.inStream != null) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"close(), closing InputStream");
this.inStream.close(false);
this.inStream = null;
}
if (this.outStream != null) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"close(), closing OutputStream");
this.outStream.close(false);
this.outStream = null;
}
} }
} }
@ -2457,27 +2461,28 @@ public class WolfSSLSocket extends SSLSocket {
if (isClosing.compareAndSet(false, true)) { if (isClosing.compareAndSet(false, true)) {
synchronized (this) { if (closeSocket) {
if (closeSocket) { if (this.socket == null || this.isClosed) {
if (this.socket == null || this.isClosed) { return;
return;
}
if (this.socket.isClosed()) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"socket (input) already closed");
}
else {
this.socket.close();
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"socket (input) closed: " + this.socket);
}
} }
this.socket = null; if (this.socket.isClosed()) {
this.ssl = null; WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
this.isClosed = true; "socket (input) already closed");
}
else {
this.socket.close();
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"socket (input) closed: " + this.socket);
}
} }
this.socket = null;
this.ssl = null;
this.isClosed = true;
/* Reset "is closing" state to false, now closed */
isClosing.set(false);
} }
else { else {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
@ -2534,6 +2539,12 @@ public class WolfSSLSocket extends SSLSocket {
throw new NullPointerException("Input array is null"); throw new NullPointerException("Input array is null");
} }
/* check if socket is closing */
if (isClosing.get()) {
throw new SocketException(
"InputStream in process of being closed");
}
/* check if socket is closed */ /* check if socket is closed */
if (this.isClosed || socket == null || socket.isClosed()) { if (this.isClosed || socket == null || socket.isClosed()) {
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
@ -2670,27 +2681,28 @@ public class WolfSSLSocket extends SSLSocket {
if (isClosing.compareAndSet(false, true)) { if (isClosing.compareAndSet(false, true)) {
synchronized (this) { if (closeSocket) {
if (closeSocket) { if (this.socket == null || this.isClosed) {
if (this.socket == null || this.isClosed) { return;
return;
}
if (this.socket.isClosed()) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"socket (output) already closed");
}
else {
this.socket.close();
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"socket (output) closed: " + this.socket);
}
} }
this.socket = null; if (this.socket.isClosed()) {
this.ssl = null; WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
this.isClosed = true; "socket (output) already closed");
}
else {
this.socket.close();
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"socket (output) closed: " + this.socket);
}
} }
this.socket = null;
this.ssl = null;
this.isClosed = true;
/* Reset "is closing" state to false, now closed */
isClosing.set(false);
} }
else { else {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
@ -2707,14 +2719,14 @@ public class WolfSSLSocket extends SSLSocket {
this.close(true); this.close(true);
} }
public synchronized void write(int b) throws IOException { public void write(int b) throws IOException {
byte[] data = new byte[1]; byte[] data = new byte[1];
data[0] = (byte)(b & 0xFF); data[0] = (byte)(b & 0xFF);
this.write(data, 0, 1); this.write(data, 0, 1);
} }
public synchronized void write(byte[] b) throws IOException { public void write(byte[] b) throws IOException {
this.write(b, 0, b.length); this.write(b, 0, b.length);
} }
@ -2727,6 +2739,12 @@ public class WolfSSLSocket extends SSLSocket {
throw new NullPointerException("Input array is null"); throw new NullPointerException("Input array is null");
} }
/* check if socket is closing */
if (isClosing.get()) {
throw new SocketException(
"OutputStream in process of being closed");
}
/* check if socket is closed */ /* check if socket is closed */
if (this.isClosed || socket == null || socket.isClosed()) { if (this.isClosed || socket == null || socket.isClosed()) {
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");