From fe40fe7575ec7c6cfa2f1e360119f37a875e339e Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Wed, 6 Nov 2024 10:16:46 -0700 Subject: [PATCH] JSSE: fix deadlock issues between SSLSocket close() and OutputStream write() --- .../wolfssl/provider/jsse/WolfSSLSocket.java | 144 ++++++++++-------- 1 file changed, 81 insertions(+), 63 deletions(-) diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLSocket.java b/src/java/com/wolfssl/provider/jsse/WolfSSLSocket.java index dddacfae..74d6b225 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLSocket.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLSocket.java @@ -1937,18 +1937,16 @@ public synchronized void close() throws IOException { WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, "thread got ioLock (shutdown)"); - synchronized (handshakeLock) { - if (this.getUseClientMode() == true && - this.handshakeComplete == true) { - WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, - "saving WOLFSSL_SESSION into cache"); - EngineHelper.saveSession(); - } - else { - WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, - "not saving WOLFSSL_SESSION into cache, " + - "not client or handshake not complete"); - } + if ((this.getUseClientMode() == true) && + (handshakeFinished == true)) { + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "saving WOLFSSL_SESSION into cache"); + EngineHelper.saveSession(); + } + else { + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "not saving WOLFSSL_SESSION into cache, " + + "not client or handshake not complete"); } try { @@ -2001,19 +1999,8 @@ public synchronized void close() throws IOException { this.EngineHelper.clearObjectState(); this.EngineHelper = null; - /* 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) { - this.inStream.close(false); - this.inStream = null; - } - if (this.outStream != null) { - this.outStream.close(false); - this.outStream = null; - } + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "thread exiting handshakeLock (shutdown)"); } /* handshakeLock */ @@ -2021,6 +2008,23 @@ public synchronized void close() throws IOException { "thread exiting ioLock (shutdown)"); } /* 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 @@ protected void close(boolean closeSocket) throws IOException { if (isClosing.compareAndSet(false, true)) { - synchronized (this) { - if (closeSocket) { - if (this.socket == null || this.isClosed) { - 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); - } + if (closeSocket) { + if (this.socket == null || this.isClosed) { + return; } - this.socket = null; - this.ssl = null; - this.isClosed = true; + 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; + this.ssl = null; + this.isClosed = true; + + /* Reset "is closing" state to false, now closed */ + isClosing.set(false); } else { WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, @@ -2534,6 +2539,12 @@ public synchronized int read(byte[] b, int off, int len) 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 */ if (this.isClosed || socket == null || socket.isClosed()) { throw new SocketException("Socket is closed"); @@ -2670,27 +2681,28 @@ protected void close(boolean closeSocket) throws IOException { if (isClosing.compareAndSet(false, true)) { - synchronized (this) { - if (closeSocket) { - if (this.socket == null || this.isClosed) { - 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); - } + if (closeSocket) { + if (this.socket == null || this.isClosed) { + return; } - this.socket = null; - this.ssl = null; - this.isClosed = true; + 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; + this.ssl = null; + this.isClosed = true; + + /* Reset "is closing" state to false, now closed */ + isClosing.set(false); } else { WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, @@ -2707,14 +2719,14 @@ public void close() throws IOException { this.close(true); } - public synchronized void write(int b) throws IOException { + public void write(int b) throws IOException { byte[] data = new byte[1]; data[0] = (byte)(b & 0xFF); 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); } @@ -2727,6 +2739,12 @@ public synchronized void write(byte[] b, int off, int len) 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 */ if (this.isClosed || socket == null || socket.isClosed()) { throw new SocketException("Socket is closed");