Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8149450

LdapCtx.processReturnCode() throwing Null Pointer Exception

    Details

    • Subcomponent:
    • Resolved In Build:
      b114
    • CPU:
      x86_64
    • OS:
      solaris_10

      Backports

        Description

        FULL PRODUCT VERSION :
        java version "1.7.0_72"
        Java(TM) SE Runtime Environment (build 1.7.0_72-b14)
        Java HotSpot(TM) Server VM (build 24.72-b04, mixed mode)


        ADDITIONAL OS VERSION INFORMATION :
        SunOS n3 5.10 Generic_150401-18 i86pc i386 i86pc


        A DESCRIPTION OF THE PROBLEM :
        When an LDAP response is received with status of LdapClient.LDAP_REFERRAL but no referrals are present (and handleReferrals is set to LDAP_REF_THROW), the following exception is received:

        java.lang.NullPointerException
                at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2930)
                at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2840)
                at com.sun.jndi.ldap.LdapNamingEnumeration.getNextBatch(LdapNamingEnumeration.java:147)
                at com.sun.jndi.ldap.LdapNamingEnumeration.hasMoreImpl(LdapNamingEnumeration.java:216)
                at com.sun.jndi.ldap.LdapNamingEnumeration.hasMore(LdapNamingEnumeration.java:189)

        Looking at the source for LdapCtx, res.referrals.elementAt(0) is invoked without first testing that res.referrals is not null. Yes, this is technically an invalid LDAP message, but invalid messages should not result in null pointer exceptions in the stack.

        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        Here is our code snippet that calls into search():

                NamingEnumeration<SearchResult> enumeration = null;

                try
                {
                    setInterruptible(true);
                    scheduleInterruptTimerTask(timer, interruptTimerTask, interruptTimeLimit);

                    enumeration = ldapContext.search(ldapSearchArguments.getDn(), ldapSearchArguments.getFilter(),
                            searchControls);

                    SearchResult searchResult;

                    while (enumeration.hasMore())
                    {
                        searchResult = enumeration.next();
                        returnedAttributes.add(searchResult.getAttributes());
                    }
                }
                finally
                {
                    cancelInterruptTimerTaskAndSetUnInterruptible(interruptTimerTask);
                    closeEnumeration(enumeration);
                }

        As mentioned in the Description, the LDAP response has a status of LdapClient.LDAP_REFERRAL but no referrals are present in the message.

        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        The stack should be throwing some kind of NamingException rather than a null pointer exception.
        ACTUAL -
        See stack trace in Description.

        ERROR MESSAGES/STACK TRACES THAT OCCUR :
        See stack trace in Description.

        REPRODUCIBILITY :
        This bug can be reproduced always.

        CUSTOMER SUBMITTED WORKAROUND :
        We currently have to ignore referrals until this bug is fixed (i.e. handleReferrals is set to LDAP_REF_IGNORE).

          Issue Links

            Activity

            Hide
            psonal Pallavi Sonal added a comment -
            Checked the source code for LdapCtx.java in jdk 7u-dev, 8u-dev and 9-dev. There has been no changes in the expression res.referrals.elementAt(0) which is causing the NPE.
            So, the issue should be there in JDK 8u and JDK 9a versions also.
            Show
            psonal Pallavi Sonal added a comment - Checked the source code for LdapCtx.java in jdk 7u-dev, 8u-dev and 9-dev. There has been no changes in the expression res.referrals.elementAt(0) which is causing the NPE. So, the issue should be there in JDK 8u and JDK 9a versions also.
            Hide
            coffeys Sean Coffey added a comment -
            Looks like an issue sitting in ldap code for a long time. Should be fixed in JDK 9. Can consider a backport then.
            Show
            coffeys Sean Coffey added a comment - Looks like an issue sitting in ldap code for a long time. Should be fixed in JDK 9. Can consider a backport then.
            Hide
            coffeys Sean Coffey added a comment -
            Here's the problem code in a reduced format :

            LdapCtx.processReturnCode

            protected void processReturnCode(LdapResult res, Name resolvedName,
                    Object resolvedObj, Name remainName, Hashtable<?,?> envprops, String fullDN)
                    throws NamingException {

                        if (res.referrals != null) {

                            msg = "Unprocessed Continuation Reference(s)";
                            if (handleReferrals == LdapClient.LDAP_REF_IGNORE) {
                                e = new PartialResultException(msg);
                                break;
                            }
                            ...
                            
                            msg = "Continuation Reference";
                            // make a chain of LdapReferralExceptions
                            for (int i = 0; i < contRefCount; i++) {

                                r = new LdapReferralException(resolvedName, resolvedObj,
                                    remainName, msg, envprops, fullDN, handleReferrals,
                                    reqCtls);
                                r.setReferralInfo(res.referrals.elementAt(i), true); // NPE seen here

                                if (hopCount > 1) {
                                    r.setHopCount(hopCount);
                                }

                                if (head == null) {
                                    head = ptr = r;
                                } else {
                                    ptr.nextReferralEx = r; // append ex. to end of chain
                                    ptr = r;
                                }
                            }
                            res.referrals = null; // reset
                            ...
                        }
            ==

            we do make a check that res.referrals is non-null before referencing it later. Looks like some call has accessed the referral value and set it to null while above code is running. It's not obvious to me what code is doing that.

            If LdapCtx.processReturnCode(..) was called multiple times on the same LdapResult Object, then we would have a recondition (see the res.referrals = null call) - According to another group seeing this issue :

            "The problem starts when AD loses one Domain Controller and OUD fails to fetch the data it needs. OUD is handling this error gracefully and it is still returning data to OAM but with error code 10 (partial results)"

            Application code higher up the stack could handle the NPE but the best place to handle that is in the LdapCtx code. Establishing root cause of who sets referrrals to null would be useful to know. Should JDK catch the NPE and discard any extra processing of LdapReferralException generation it was involved in?
            Show
            coffeys Sean Coffey added a comment - Here's the problem code in a reduced format : LdapCtx.processReturnCode protected void processReturnCode(LdapResult res, Name resolvedName,         Object resolvedObj, Name remainName, Hashtable<?,?> envprops, String fullDN)         throws NamingException {             if (res.referrals != null) {                 msg = "Unprocessed Continuation Reference(s)";                 if (handleReferrals == LdapClient.LDAP_REF_IGNORE) {                     e = new PartialResultException(msg);                     break;                 }                 ...                                  msg = "Continuation Reference";                 // make a chain of LdapReferralExceptions                 for (int i = 0; i < contRefCount; i++) {                     r = new LdapReferralException(resolvedName, resolvedObj,                         remainName, msg, envprops, fullDN, handleReferrals,                         reqCtls);                     r.setReferralInfo(res.referrals.elementAt(i), true); // NPE seen here                     if (hopCount > 1) {                         r.setHopCount(hopCount);                     }                     if (head == null) {                         head = ptr = r;                     } else {                         ptr.nextReferralEx = r; // append ex. to end of chain                         ptr = r;                     }                 }                 res.referrals = null; // reset                 ...             } == we do make a check that res.referrals is non-null before referencing it later. Looks like some call has accessed the referral value and set it to null while above code is running. It's not obvious to me what code is doing that. If LdapCtx.processReturnCode(..) was called multiple times on the same LdapResult Object, then we would have a recondition (see the res.referrals = null call) - According to another group seeing this issue : "The problem starts when AD loses one Domain Controller and OUD fails to fetch the data it needs. OUD is handling this error gracefully and it is still returning data to OAM but with error code 10 (partial results)" Application code higher up the stack could handle the NPE but the best place to handle that is in the LdapCtx code. Establishing root cause of who sets referrrals to null would be useful to know. Should JDK catch the NPE and discard any extra processing of LdapReferralException generation it was involved in?
            Hide
            coffeys Sean Coffey added a comment -
            I was looking at the wrong res.referrals.elementAt call (the lines numbers lined up well with jdk8u code and wrongly assumed I had the right call site)

            ok - so the error occurs when Ldap result is LDAP_REFERRAL.

                    case LdapClient.LDAP_REFERRAL:

                        if (handleReferrals == LdapClient.LDAP_REF_IGNORE) {
                            e = new PartialResultException(msg);
                            break;
                        }

                        r = new LdapReferralException(resolvedName, resolvedObj, remainName,
                            msg, envprops, fullDN, handleReferrals, reqCtls);
                        // only one set of URLs is present
                        r.setReferralInfo(res.referrals.elementAt(0), false);

            ====

            No null check above and it explains why the issue would occur. I've patched the code and am running tests. Will submit RFR shortly.
            Show
            coffeys Sean Coffey added a comment - I was looking at the wrong res.referrals.elementAt call (the lines numbers lined up well with jdk8u code and wrongly assumed I had the right call site) ok - so the error occurs when Ldap result is LDAP_REFERRAL.         case LdapClient.LDAP_REFERRAL:             if (handleReferrals == LdapClient.LDAP_REF_IGNORE) {                 e = new PartialResultException(msg);                 break;             }             r = new LdapReferralException(resolvedName, resolvedObj, remainName,                 msg, envprops, fullDN, handleReferrals, reqCtls);             // only one set of URLs is present             r.setReferralInfo(res.referrals.elementAt(0), false); ==== No null check above and it explains why the issue would occur. I've patched the code and am running tests. Will submit RFR shortly.
            Hide
            coffeys Sean Coffey added a comment -
            The JDK was involved in processing an LDAPResult when a null pointer was encountered for the referral field. The LDAP reply BER signaled that the LDAP operation was a result code of LDAP_REFERRAL (value 10) - For a valid referral result, a list of URIs should be provided in the result to indicate what servers might contain the necessary results. See RFC section 4.1.10 :

            https://tools.ietf.org/html/rfc4511#section-4.1.10
            > The referral field is present in an LDAPResult if the resultCode is
            > set to referral, and it is absent with all other result codes. It
            > contains one or more references to one or more servers or services
            > that may be accessed via LDAP or other protocols. Referrals can be
            > returned in response to any operation request (except Unbind and
            > Abandon, which do not have responses). At least one URI MUST be
            > present in the Referral.

            For some reason, the LDAP server in this scenario has given this field as null. Is it non-compliant ?The JDK is now set up to return a LdapReferralException and application can decide how best to handle it.
            Show
            coffeys Sean Coffey added a comment - The JDK was involved in processing an LDAPResult when a null pointer was encountered for the referral field. The LDAP reply BER signaled that the LDAP operation was a result code of LDAP_REFERRAL (value 10) - For a valid referral result, a list of URIs should be provided in the result to indicate what servers might contain the necessary results. See RFC section 4.1.10 : https://tools.ietf.org/html/rfc4511#section-4.1.10 > The referral field is present in an LDAPResult if the resultCode is > set to referral, and it is absent with all other result codes. It > contains one or more references to one or more servers or services > that may be accessed via LDAP or other protocols. Referrals can be > returned in response to any operation request (except Unbind and > Abandon, which do not have responses). At least one URI MUST be > present in the Referral. For some reason, the LDAP server in this scenario has given this field as null. Is it non-compliant ?The JDK is now set up to return a LdapReferralException and application can decide how best to handle it.
            Hide
            hgupdate HG Updates added a comment -
            URL: http://hg.openjdk.java.net/jdk9/dev/jdk/rev/2c25eb79766e
            User: coffeys
            Date: 2016-04-11 07:00:46 +0000
            Show
            hgupdate HG Updates added a comment - URL: http://hg.openjdk.java.net/jdk9/dev/jdk/rev/2c25eb79766e User: coffeys Date: 2016-04-11 07:00:46 +0000
            Hide
            hgupdate HG Updates added a comment -
            URL: http://hg.openjdk.java.net/jdk9/jdk9/jdk/rev/2c25eb79766e
            User: lana
            Date: 2016-04-13 17:56:05 +0000
            Show
            hgupdate HG Updates added a comment - URL: http://hg.openjdk.java.net/jdk9/jdk9/jdk/rev/2c25eb79766e User: lana Date: 2016-04-13 17:56:05 +0000

              People

              • Assignee:
                coffeys Sean Coffey
                Reporter:
                webbuggrp Webbug Group
              • Votes:
                0 Vote for this issue
                Watchers:
                7 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: