RFR: 8362268: NPE thrown from SASL GSSAPI impl when TLS is used with QOP auth-int against Active Directory [v2]
Jaikiran Pai
jpai at openjdk.org
Tue Feb 10 07:22:24 UTC 2026
On Tue, 10 Feb 2026 07:18:29 GMT, Jaikiran Pai <jpai at openjdk.org> wrote:
>> Can I please get a review of this change which proposes to fix the issue reported in https://bugs.openjdk.org/browse/JDK-8362268?
>>
>> The underlying issue here is simple - A `javax.naming.Context` for LDAP is backed by a JDK internal `com.sun.jndi.ldap.LdapCtx` instance. Each `LdapCtx` uses a `com.sun.jndi.ldap.LdapClient` instance to do the LDAP operations. Each `LdapClient` further uses a `com.sun.jndi.ldap.Connection` instance. Each `Connection` instance uses a `Socket` and the socket's `InputStream` and `OutputStream` to read/write LDAP messages from/to a LDAP server. Each `Connection` instance spawns a `Thread` to read (over the InputStream) and queue incoming messages from the LDAP server.
>>
>> When a LDAP backed `javax.naming.Context` initiates an operation, for example a `Context.lookup()`, then internally the LdapCtx initiates a LDAP request over the Connection's `OutputStream` and then waits for a LDAP response to arrive. In the issue reported here, it so happens that while reading over the `Connection`'s `InputStream`, the `InputStream.read()` raises an `IOException` (for whatever reason). That `IOException` rightly initiates the close of the `Connection` instance. Closing a `Connection` instance involves queuing a marker response for all waiting thread(s) to notice and raise an IOException, which they can ulimately propagate as a `NamingException` to the application. Additionally, the closing of the `Connection` also closes the `InputStream` and `OutputStream` of that `Connection`.
>>
>> When a thread that was waiting for a LDAP response, in LdapCtx, wakes up due to an IOException, it attempts to send a "abandon request" LDAP message over the `Connection`, so that the server knows that the client has abandoned the request. Since the Connection and its Input/OutputStream(s) are already closed, trying to write a message over the OutputStream can/will lead to an exception. The implementation of `Connection.abandonRequest(LdapRequest ldr, Control[] reqCtls)` which is where this code resides, guards against such exceptions by catching and ignoring an `IOException` from an `OutputStream.write(...)/flush()` call.
>>
>> Although `OutputStream.write(...)` is specified to throw an IOException if that stream is already closed, not all implementations adhere to that specification. For example, `java.io.BufferedOutputStream` does not throw any exception when `write(...)` is invoked on a closed `OutputStream`. Incidentally, the `Connection` instance's `Outp...
>
> Jaikiran Pai has updated the pull request incrementally with one additional commit since the last revision:
>
> add comment
Thank you Weibing for running your test and thank you Daniel and Michael for the inputs. I've updated this PR to not rely on `useable` field and instead rely on the `com.sun.jndi.ldap.LdapRequest` itself to decide whether or not to send an "abandon request" message over the connection. The `LdapRequest` has the necessary detail whether a connection is closed or not and if the connection is closed then we skip the BER message creation and sending of that message over the stream.
> The BER stream is dumped to tracefile although not request is being sent, that is wrong.
As a separate activity, I will check other places where this might be happening. With the current proposed update to the PR, this no longer happens for the abandon request.
With the changes in this PR, tier1, tier2 and tier3 tests passed and test repeat of 50 for `test/jdk/com/sun/jndi/ldap/` too completed without issues.
-------------
PR Comment: https://git.openjdk.org/jdk/pull/29638#issuecomment-3875796425
More information about the core-libs-dev
mailing list