CVE-2021-4213 (published 2022-08-24T16:15Z)

A flaw was found in JSS, where it did not properly free up all memory. Over time, the wasted memory builds up in the server memory, saturating the server’s RAM. This flaw allows an attacker to force the invocation of an out-of-memory process, causing a denial of service.

CVSS v3 base score: 7.5, HIGH (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H)

Weakness information:
cwe_id: CWE-401
cwe_name: Missing Release of Memory after Effective Lifetime
description: The product does not sufficiently track and release allocated memory after it has been used, which slowly consumes remaining memory.
extended_description: This is often triggered by improper handling of malformed data or unexpectedly interrupted sessions.  In some languages, developers are responsible for tracking memory allocation and releasing the memory.  If there are no more pointers or references to the memory, then it can no longer be tracked and identified for release.
         

Fix information:
repo_url: https://github.com/dogtagpki/jss
commit_details: repo_url: https://github.com/dogtagpki/jss
author: Matthew McClain
author_date: 2022-01-26 06:38:55+00:00
msg: Fix memory leak on each TLS connection

Each TLS connection is leaking a bunch of data that isn't in the heap
and so after 25k requests Tomcat uses about 2.5GB resident memory.

There are large number of relationships that point at each other and we
need to break the cycle so JSSEngineReferenceImpl's finalizer can run
and clear all the native resources these point at.

The lowest impact place to break the cycle was at SSLAlertEvent.engine.
This relationship doesn't seem to be used anywhere.  Once the cycle is
broken, JSSEngineReferenceImpl can be garbage collected and the
finalizer can run.

Signed-off-by: Chris Kelley <ckelley@redhat.com>
repository: repo_url: https://github.com/dogtagpki/jss
repo_name: dogtagpki/jss
description:   Network Security Services for Java is a Java interface to NSS
repo_language: Java
owner: dogtagpki
file_changes: filename: SSLFDProxy.java
change_type: ModificationType.MODIFY
diff: @@ -1,6 +1,5 @@
 package org.mozilla.jss.nss;
 
-import java.lang.IllegalArgumentException;
 import java.util.ArrayList;
 
 import org.mozilla.jss.crypto.X509Certificate;
@@ -42,13 +41,14 @@ public class SSLFDProxy extends PRFDProxy {
 
     @Override
     protected synchronized void releaseNativeResources() throws Exception {
-        synchronized (globalRef) {
-            if (globalRef != null) {
-                try {
-                    globalRef.close();
-                } finally {
-                    globalRef = null;
-                }
+
+        super.releaseNativeResources();
+
+        if (globalRef != null) {
+            try {
+                globalRef.close();
+            } finally {
+                globalRef = null;
             }
         }
     }

programming_language: Java
filename: JSSEngineReferenceImpl.java
change_type: ModificationType.MODIFY
diff: @@ -4,17 +4,39 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.ServerSocket;
 import java.net.Socket;
-import java.nio.channels.WritableByteChannel;
+import java.nio.ByteBuffer;
 import java.nio.channels.Channels;
+import java.nio.channels.WritableByteChannel;
 import java.security.PublicKey;
-import java.nio.ByteBuffer;
-
-import javax.net.ssl.*;
 
-import org.mozilla.jss.nss.*;
-import org.mozilla.jss.pkcs11.*;
-import org.mozilla.jss.provider.javax.crypto.*;
-import org.mozilla.jss.ssl.*;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.X509ExtendedTrustManager;
+import javax.net.ssl.X509TrustManager;
+
+import org.mozilla.jss.nss.BadCertHandler;
+import org.mozilla.jss.nss.Buffer;
+import org.mozilla.jss.nss.BufferProxy;
+import org.mozilla.jss.nss.Cert;
+import org.mozilla.jss.nss.CertAuthHandler;
+import org.mozilla.jss.nss.PR;
+import org.mozilla.jss.nss.PRErrors;
+import org.mozilla.jss.nss.PRFDProxy;
+import org.mozilla.jss.nss.SSL;
+import org.mozilla.jss.nss.SSLErrors;
+import org.mozilla.jss.nss.SSLFDProxy;
+import org.mozilla.jss.nss.SSLPreliminaryChannelInfo;
+import org.mozilla.jss.nss.SecurityStatusResult;
+import org.mozilla.jss.pkcs11.PK11Cert;
+import org.mozilla.jss.provider.javax.crypto.JSSNativeTrustManager;
+import org.mozilla.jss.ssl.SSLAlertDescription;
+import org.mozilla.jss.ssl.SSLAlertEvent;
+import org.mozilla.jss.ssl.SSLAlertLevel;
+import org.mozilla.jss.ssl.SSLCipher;
+import org.mozilla.jss.ssl.SSLHandshakeCompletedEvent;
+import org.mozilla.jss.ssl.SSLVersion;
+import org.mozilla.jss.ssl.SSLVersionRange;
 
 /**
  * The reference JSSEngine implementation.
@@ -1651,10 +1673,10 @@ public class JSSEngineReferenceImpl extends JSSEngine {
         if (!closed_fd && ssl_fd != null) {
             try {
                 SSL.RemoveCallbacks(ssl_fd);
-                PR.Close(ssl_fd);
                 ssl_fd.close();
+                ssl_fd = null;
             } catch (Exception e) {
-                debug("Got exception trying to cleanup SSLFD: " + e.getMessage());
+                logger.error("Got exception trying to cleanup SSLFD", e);
             } finally {
                 closed_fd = true;
             }
@@ -1671,6 +1693,15 @@ public class JSSEngineReferenceImpl extends JSSEngine {
         }
     }
 
+    // During testing with Tomcat 8.5, most instances did not call
+    // cleanup, so all the JNI resources end up getting leaked: ssl_fd
+    // (and its global ref), read_buf, and write_buf.
+    @Override
+    protected void finalize() {
+        cleanup();
+    }
+
+
     private class CertValidationTask extends CertAuthHandler {
         public CertValidationTask(SSLFDProxy fd) {
             super(fd);

programming_language: Java
filename: GlobalRefProxy.java
change_type: ModificationType.MODIFY
diff: @@ -12,7 +12,5 @@ public class GlobalRefProxy extends NativeProxy {
     private static native byte[] refOf(Object target);
 
     @Override
-    protected synchronized void releaseNativeResources() {
-        clear();
-    }
+    protected native void releaseNativeResources();
 }

programming_language: Java
repo_url: https://github.com/dogtagpki/jss
commit_details: repo_url: https://github.com/dogtagpki/jss
author: Chris Kelley
author_date: 2022-02-14 10:49:08+00:00
msg: Additional fix for TLS connection I missed from original patch
repository: repo_url: https://github.com/dogtagpki/jss
repo_name: dogtagpki/jss
description:   Network Security Services for Java is a Java interface to NSS
repo_language: Java
owner: dogtagpki
file_changes: filename: JSSEngineReferenceImpl.java
change_type: ModificationType.MODIFY
diff: @@ -961,7 +961,6 @@ public class JSSEngineReferenceImpl extends JSSEngine {
         while (ssl_fd.inboundOffset < ssl_fd.inboundAlerts.size()) {
             SSLAlertEvent event = ssl_fd.inboundAlerts.get(ssl_fd.inboundOffset);
             ssl_fd.inboundOffset += 1;
-	    event.setEngine(this);
 
             if (event.getLevelEnum() == SSLAlertLevel.WARNING && event.getDescriptionEnum() == SSLAlertDescription.CLOSE_NOTIFY) {
                 debug("Got inbound CLOSE_NOTIFY alert");
@@ -985,7 +984,6 @@ public class JSSEngineReferenceImpl extends JSSEngine {
         while (ssl_fd.outboundOffset < ssl_fd.outboundAlerts.size()) {
             SSLAlertEvent event = ssl_fd.outboundAlerts.get(ssl_fd.outboundOffset);
             ssl_fd.outboundOffset += 1;
-            event.setEngine(this);
 
             if (event.getLevelEnum() == SSLAlertLevel.WARNING && event.getDescriptionEnum() == SSLAlertDescription.CLOSE_NOTIFY) {
                 debug("Sent outbound CLOSE_NOTIFY alert.");

programming_language: Java