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

com.sun.crypto.provider.SunJCE instance leak using KRB5 and LoginContext

XMLWordPrintable

    • b25
    • x86
    • windows_xp
    • Verified

        FULL PRODUCT VERSION :
        Windows:
        1.6.0 and 1.60_01

        java version "1.5.0_09"
        Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_09-b03)
        Java HotSpot(TM) Client VM (build 1.5.0_09-b03, mixed mode)

        Linux:

        java version "1.5.0_08"
        Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_08-b03)
        Java HotSpot(TM) Client VM (build 1.5.0_08-b03, mixed mode)



        ADDITIONAL OS VERSION INFORMATION :
        - Microsoft Windows XP [Version 5.1.2600]
        - Linux XXXXXXXXXXX 2.6.9-42.ELsmp #1 SMP Sat Aug 12 09:39:11 CDT 2006
        i686 i686 i386 GNU/Linux

        EXTRA RELEVANT SYSTEM CONFIGURATION :
        jaasLogin.conf:

        TestKrb5JAAS {
           com.sun.security.auth.module.Krb5LoginModule required debug=true storeKey=true;
        };

        A DESCRIPTION OF THE PROBLEM :
        I am experiencing a memory leak with com.sun.crypto.provider.SunJCE instances growing in count when using it in conjunction with LoginContext.
        Running the attached program will eventually run out of memory.

        YourKit profiler shows that com.security.crypto.provider.SunJCE is being allocated and hung onto by field "e" of javax.crypto.SunJCE_b which is an IdentityHashMap.

        For every call to LoginContext.login() in the attached code, two instances of com.sun.crypto.provider.SunJCE are created and held onto by SunJCE_b.e

        Debugging shows that SunJCE instance is allocated at the following stack:

        Thread [main] (Suspended (breakpoint at line 115 in Provider))
                    SunJCE(Provider).<init>(String, double, String) line: 115
                    SunJCE.<init>() line: not available
                    SunJCE_am.<init>(PBEKeySpec, String) line: not available
                    PBKDF2HmacSHA1Factory.engineGenerateSecret(KeySpec) line: not available
                   SecretKeyFactory.generateSecret(KeySpec) line: not available
                    AesDkCrypto.PBKDF2(char[], byte[], int, int) line: 462
                    AesDkCrypto.stringToKey(char[], byte[], byte[]) line: 111
                    AesDkCrypto.stringToKey(char[], String, byte[]) line: 90
                    Aes128.stringToKey(char[], String, byte[]) line: 29
                    EncryptionKey.stringToKey(char[], String, byte[], int) line: 253
                    EncryptionKey.acquireSecretKeys(char[], String, boolean, int, byte[]) line: 190
                    EncryptionKey.acquireSecretKeys(char[], String) line: 158
                    Krb5LoginModule.attemptAuthentication(boolean) line: 626
                    Krb5LoginModule.login() line: 512
                    NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
                    NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
                    DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
                    Method.invoke(Object, Object...) line: 585
                    LoginContext.invoke(String) line: 769
                    LoginContext.access$000(LoginContext, String) line: 186
                    LoginContext$4.run() line: 683
                    AccessController.doPrivileged(PrivilegedExceptionAction<T>) line: not available [native method]
                    LoginContext.invokePriv(String) line: 680
                    LoginContext.login() line: 579
                    TestKrbLeak.login(String, String, String) line: 52
                    TestKrbLeak.main(String[]) line: 28



        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        Run the attached code with a very low -Xmx setting on either Windows XP or Linux. Make sure you change the lines for jaasConfName and an applicable kerberos DC setup.



        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        It doesn't leak SunJCE instances or releases them during LoginContext.logout
        ACTUAL -
        Leaks com.sun.crypto.provider.SunJCE instances

        REPRODUCIBILITY :
        This bug can be reproduced always.

        ---------- BEGIN SOURCE ----------

        import java.io.IOException;
        import java.util.Set;

        import javax.security.auth.Subject;
        import javax.security.auth.callback.Callback;
        import javax.security.auth.callback.CallbackHandler;
        import javax.security.auth.callback.NameCallback;
        import javax.security.auth.callback.PasswordCallback;
        import javax.security.auth.callback.UnsupportedCallbackException;
        import javax.security.auth.kerberos.KerberosTicket;
        import javax.security.auth.login.LoginContext;
        import javax.security.auth.login.LoginException;

        public class TestKrbLeak {

            public static void main(String[] args) throws IOException {

                System.setProperty("java.security.krb5.realm", "MYREALM.AD");
                System.setProperty("java.security.krb5.kdc", "mytestdc.company.ad");
                System.setProperty("java.security.auth.login.config", "C:/temp/jaasLogin.conf");

                final String jaasConfName = "TestKrb5JAAS";
                final String username = "username1";
                final String password = "password1";

                while (true) {
                    login(jaasConfName, username, password);
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

            }

            private static void login(final String jaasConfName, final String username, final String password) {
                LoginContext loginContext = null;
                try {
                    loginContext = new LoginContext(jaasConfName, new CallbackHandler() {
                        public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
                            for (Callback cb : callbacks) {
                                if (cb instanceof NameCallback) {
                                    ((NameCallback) cb).setName(username);
                                } else if (cb instanceof PasswordCallback) {
                                    ((PasswordCallback) cb).setPassword(password.toCharArray());
                                }
                            }
                        }
                    });
                    loginContext.login();
                    
                    Subject subject = loginContext.getSubject();
                    
                    Set<KerberosTicket> tickets = subject.getPrivateCredentials(KerberosTicket.class);
                    
                    assert (tickets != null && !tickets.isEmpty());
                    
                } catch (LoginException e) {
                    e.printStackTrace();
                } finally {
                    if (loginContext != null) {
                        try {
                            loginContext.logout();
                        } catch (LoginException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }

        }

        ---------- END SOURCE ----------

        CUSTOMER SUBMITTED WORKAROUND :
        We placed our own backed ticket cache in front of LoginContext.login call to only call login occassionally. Note that this still leaks eventually..

              wetmore Bradford Wetmore
              ndcosta Nelson Dcosta (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

                Created:
                Updated:
                Resolved:
                Imported:
                Indexed: