JDK-8215102 (Follow-up)

Jaikiran Pai jai.forums2013 at gmail.com
Fri Jan 25 04:17:47 UTC 2019


Hello Severin,

Thank you for spending time on this. Although that JIRA was raised for
in context of MySQL driver, having watched this discussion and looked a
bit into the exception stacktrace, I think it's not really specific to
MySQL.

So I decided to reproduce this with just plain Java SSLSocket APIs and
was able to reproduce this. I have attached a very simple jtreg test
case which fails against the latest upstream jdk source repo. The test
case has details about what it does, but in short, the test creates a
SSLServerSocket (server) and a SSLSocket (client) and the client sends
some random data to the server and then calls SSLSocket.shutdownInput().
That call triggers the exception that's being discussed here. Reading
the javadoc of SSLSocket.shutdownInput() I don't think the usage of this
API is incorrect (this is of course based on my limited knowledge of
that API).

-Jaikiran

On 24/01/19 10:31 PM, Severin Gehwolf wrote:
> Hi,
>
> Thanks for your feedback!
>
> I've tried to reproduce this on my end too, but failed. At least with
> MariaDB 10.2.21 and their recent jdbc driver and JDK 11.
>
> This looks like a JDBC driver issue on newer JDKs. Hence, I've noted
> that in the bug and closed it:
> https://bugs.openjdk.java.net/browse/JDK-8215102
>
> If somebody manages to reproduce this with recent JDBC drivers I'd be
> happy to re-open it. mysql-connector-java-5.1.43.jar seems rather old.
> Current is 8.0.14.
>
> Thanks,
> Severin
>
> On Tue, 2019-01-22 at 18:14 +0530, Jaikiran Pai wrote:
>> FWIW - I don't think this is related to WildFly server. So I decided
>> to try and reproduce this in a trivial standalone program and I was
>> able to reproduce this. Here's the code to reproduce this issue:
>>
>> import java.sql.*;
>>
>> public class ConnectionCloseTest {
>>
>>     public static void main(final String[] args) throws Exception {
>>         final String url = "jdbc:mysql://localhost/?requireSSL=true";
>>         final String user = "youruser"; // set the right user
>>         final String pass = "yourpassword"; // set the right password
>>         Class.forName("com.mysql.jdbc.Driver");
>>         final Connection conn = DriverManager.getConnection(url,
>> user, pass);
>>         System.out.println("Got connection");
>>         conn.close();
>>         System.out.println("Closed connection");
>>     }
>>
>> }
>> It's important to start the MySQL server with ssl enabled. For that I
>> just had to set:
>> [mysqld]
>> ssl=1
>> in my MySQL server configuration. On the client side you will need
>> the mysql JDBC driver jar in the classpath. The one I used for this
>> test was mysql-connector-java-5.1.43.jar.
>> Running this with Java 8 doesn't throw any exceptions or WARN logs.
>> However, running it against Java 11 and even Java 12 latest EA build,
>> throws an exception, which gets logged as a WARN by the driver (and
>> things move on) on connection close:
>>
>> WARN: Caught while disconnecting...
>>
>> EXCEPTION STACK TRACE:
>>
>>
>>
>> ** BEGIN NESTED EXCEPTION ** 
>>
>> javax.net.ssl.SSLException
>> MESSAGE: closing inbound before receiving peer's close_notify
>>
>> STACKTRACE:
>>
>> javax.net.ssl.SSLException: closing inbound before receiving peer's
>> close_notify
>>     at
>> java.base/sun.security.ssl.Alert.createSSLException(Alert.java:133)
>>     at
>> java.base/sun.security.ssl.Alert.createSSLException(Alert.java:117)
>>     at
>> java.base/sun.security.ssl.TransportContext.fatal(TransportContext.ja
>> va:307)
>>     at
>> java.base/sun.security.ssl.TransportContext.fatal(TransportContext.ja
>> va:263)
>>     at
>> java.base/sun.security.ssl.TransportContext.fatal(TransportContext.ja
>> va:254)
>>     at
>> java.base/sun.security.ssl.SSLSocketImpl.shutdownInput(SSLSocketImpl.
>> java:650)
>>     at
>> java.base/sun.security.ssl.SSLSocketImpl.shutdownInput(SSLSocketImpl.
>> java:629)
>>     at com.mysql.jdbc.MysqlIO.quit(MysqlIO.java:2246)
>>     at
>> com.mysql.jdbc.ConnectionImpl.realClose(ConnectionImpl.java:4234)
>>     at com.mysql.jdbc.ConnectionImpl.close(ConnectionImpl.java:1472)
>>     at ConnectionCloseTest.main(ConnectionCloseTest.java:13)
>>     at
>> java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Nativ
>> e Method)
>>     at
>> java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Native
>> MethodAccessorImpl.java:62)
>>     at
>> java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(De
>> legatingMethodAccessorImpl.java:43)
>>     at java.base/java.lang.reflect.Method.invoke(Method.java:567)
>>     at
>> jdk.compiler/com.sun.tools.javac.launcher.Main.execute(Main.java:415)
>>     at
>> jdk.compiler/com.sun.tools.javac.launcher.Main.run(Main.java:192)
>>     at
>> jdk.compiler/com.sun.tools.javac.launcher.Main.main(Main.java:132)
>>
>>
>> ** END NESTED EXCEPTION **
>> -Jaikiran
>>
>> On 22/01/19 7:43 AM, Dennis Gesker wrote:
>>> Hi Severing:
>>>
>>> I'll post the generic error when I get to the office. It seems to
>>> throw the complaints when it closes a connection.
>>>
>>> Here is the thing...
>>>
>>> 1. I'm glad this found its way to you (being Red Hat guy) as we
>>> first noticed it in WildFly 15.0.1.  (But, wasn't looking for it
>>> before as we only need it for a few XA migration transactions.)
>>>
>>> 2. It MIGHT be the driver as we use PostgreSQL driver mostly -- in
>>> the same container -- and no errors there on WildFly 15.0.1 and JDK
>>> 11.
>>>
>>> 3. I will also try to fall back to JDK 8 and see if it continues in
>>> WildFly 15.0.1.
>>>
>>> 4. The error occurs -- it would seem -- as the pool closes idle
>>> connections.
>>>
>>> 5.  I'll post the pool/data source config in WildFly as well -- it
>>> seems correct and seems to work OK in my application.
>>>
>>> Oh, yeah...
>>>
>>> And, I found the form to be a contributor (not comitter) and will
>>> fill that out tomorrow as well and submit it to you directly.
>>>
>>> --drg
>>>
>>> On Mon, Jan 21, 2019, 09:23 Severin Gehwolf <sgehwolf at redhat.com
>>> wrote:
>>>> On Mon, 2019-01-21 at 07:57 -0700, Dennis Gesker wrote:
>>>>> Pasted:
>>>>>
>>>>> https://paste.fedoraproject.org/paste/vEvp9RwN2rVvIKGiC0IvEQ
>>>> Is this the full trace? I don't see any exceptions happening in
>>>> the
>>>> log. Am I missing something?
>>>>
>>>> Thanks,
>>>> Severin
>>>>
>>>>> On Mon, Jan 21, 2019 at 2:10 AM Severin Gehwolf <
>>>> sgehwolf at redhat.com>
>>>>> wrote:
>>>>>> Hi Dennis,
>>>>>>
>>>>>> On Sat, 2019-01-19 at 12:08 -0700, Dennis Gesker wrote:
>>>>>>> Hi Severin:
>>>>>>>
>>>>>>> A link to the txt file via Google Drive his here.
>>>>>> "Sorry, the file you have requested does not exist."
>>>>>>
>>>>>> Could you please upload it somewhere less restricted? Maybe 
>>>>>> https://paste.fedoraproject.org/ or something similar?
>>>>>>
>>>>>> I guess if you include me directly, a file attachment would
>>>> work
>>>>>> too...
>>>>>> It's the mailing lists which strip attachments.
>>>>>>
>>>>>>> I appreciate you and Alan taking a look. Especially,
>>>> information
>>>>>>> submitted from someone who is not a part of openjdk
>>>> project.
>>>>>>> I do hope the debug info helps. Let me know anything else
>>>> you
>>>>>> need
>>>>>>> and I will do my best to provide it.
>>>>>> Sure. I'll be mostly doing the intermediary work: getting the
>>>> info
>>>>>> added to the bug, though.
>>>>>>
>>>>>>> And, should your team decide to open a new ticket or reopen
>>>> this
>>>>>>> original ticket in the JIRA could you add me to the ticket?
>>>>>> You'd have to become OpenJDK author for this[1]. It's not
>>>> terribly
>>>>>> difficult, but it's somewhat of an entry barrier I
>>>> understand.
>>>>>>> BTW, (off topic), would your recommend submitting a
>>>> contributor
>>>>>>> application to the openjdk project so bug reports can be
>>>>>> submitted
>>>>>>> directly? 
>>>>>> If you intend to submit the occasional bug report and fix
>>>> it's
>>>>>> easier
>>>>>> for you long-term to attempt to become OpenJDK author (which
>>>>>> requires
>>>>>> signing the OCA[2]).
>>>>>>
>>>>>>> The dev group at my company is VERY small (and this message
>>>> to
>>>>>> your
>>>>>>> group at the project is from my personal email) but I'd be
>>>> glad
>>>>>> to
>>>>>>> submit bug reports as we come across them in our day to day
>>>> use
>>>>>> of
>>>>>>> Java.
>>>>>> If there are good reproducers for bugs this would be very
>>>> welcome.
>>>>>> Thanks for investing some time in this!
>>>>>>
>>>>>> Cheers,
>>>>>> Severin
>>>>>>
>>>>>> [1] http://openjdk.java.net/bylaws#author
>>>>>>     http://openjdk.java.net/projects/#project-author
>>>>>> [2] http://oss.oracle.com/oca.pdf
>>>>>>
>>>>>>> Cordially,
>>>>>>> Dennis
>>>>>>> dennis at gesker.com
>>>>>>>
>>>>>>> On Fri, Jan 18, 2019 at 10:07 AM Severin Gehwolf <
>>>>>> sgehwolf at redhat.com
>>>>>>>> wrote:
>>>>>>>> On Thu, 2019-01-17 at 10:00 -0700, Dennis Gesker wrote:
>>>>>>>> [...]
>>>>>>>>> Added the  -Djavax.net.debug=all option to my Wildfly
>>>> startup
>>>>>> and
>>>>>>>>> waited for the pool to close a connection to MySql at
>>>> AWS.
>>>>>>>>> TXT file attached.
>>>>>>>>>
>>>>>>>>> javac 11.0.1
>>>>>>>>> mysql jdbc driver 8.0.13
>>>>>>>>> wildfly 15.0.1
>>>>>>>>>
>>>>>>>>> --drg
>>>>>>>> Unfortunately the txt file got stripped by the mailing
>>>> list.
>>>>>> Would
>>>>>>>> you
>>>>>>>> be able to upload it somewhere and post a link?
>>>>>>>>
>>>>>>>> Thanks,
>>>>>>>> Severin
>>>>>>>>
>>>>>>>
>>>>>
>>>>
-------------- next part --------------
# HG changeset patch
# User Jaikiran Pai <jaikiran.pai at gmail.com>
# Date 1548389397 -19800
#      Fri Jan 25 09:39:57 2019 +0530
# Node ID 8b421716e12337a1f669cbb5c06ad4737f715c6f
# Parent  d02f1f4ff3a637a99885563fcee0fee5d70b9b50
JDK-8215102 Testcase to reproduce the SSLSocket.shutdownInput exception

diff --git a/test/jdk/javax/net/ssl/SSLSocket/SSLSocketShutdownInput.java b/test/jdk/javax/net/ssl/SSLSocket/SSLSocketShutdownInput.java
new file mode 100644
--- /dev/null
+++ b/test/jdk/javax/net/ssl/SSLSocket/SSLSocketShutdownInput.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8215102
+ * @summary Test that SSLSocket.shutdownInput() doesn't throw unexpected SSLException
+ * @library /javax/net/ssl/templates
+ */
+
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.net.InetAddress;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+public class SSLSocketShutdownInput implements SSLContextTemplate {
+
+    public static void main(String[] args) throws Exception {
+        new SSLSocketShutdownInput().test();
+    }
+
+    /**
+     * - Starts a server listening on a SSLServerSocket
+     * - Creates a (client) SSLSocket to communicate with that server
+     * - Client sends data to the server
+     * - Client then initiates a SSLSocket.shutdownInput()
+     * (Note: Server just receives data and doesn't write back or respond back
+     * to the client, so this is essentially a one-way communication)
+     *
+     * @throws Exception
+     */
+    private void test() throws Exception {
+        final String data = "hello world";
+        final Future<String> serverTaskResult;
+        final SSLServerSocketFactory serversocketfactory = createServerSSLContext().getServerSocketFactory();
+        try (final SSLServerSocket serverSocket = (SSLServerSocket) serversocketfactory.createServerSocket(0)) {
+            serverSocket.setNeedClientAuth(false);
+            serverSocket.setUseClientMode(false);
+            // start a thread which waits for client connection
+            serverTaskResult = Executors.newSingleThreadExecutor().submit(new Server(serverSocket));
+            // create a client socket and communicate with the server
+            final String serverHost = InetAddress.getLocalHost().getHostName();
+            final int serverPort = serverSocket.getLocalPort();
+            try (final SSLSocket clientSocket = (SSLSocket) createClientSSLContext().getSocketFactory().createSocket(
+                    serverHost, serverPort)) {
+                // send data to server
+                final BufferedWriter os = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
+                os.write(data);
+                os.newLine();
+                os.flush();
+
+                // shutdown the input
+                clientSocket.shutdownInput();
+
+            }
+        }
+        // verify that the server did receive the (right) data
+        final String dataReceivedByServer = serverTaskResult.get(1, TimeUnit.SECONDS);
+        if (!dataReceivedByServer.equals(data)) {
+            throw new Exception("Server did not receive the expected data");
+        }
+    }
+
+    private static final class Server implements Callable<String> {
+        private final SSLServerSocket listenSocket;
+
+        private Server(final SSLServerSocket listenSocket) {
+            this.listenSocket = listenSocket;
+        }
+
+        @Override
+        public String call() throws Exception {
+            // wait for connection
+            try (final SSLSocket socket = (SSLSocket) listenSocket.accept()) {
+                // read any data from client
+                final BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+                return reader.readLine();
+            }
+        }
+
+    }
+
+}
+


More information about the security-dev mailing list