This is an automated email from the ASF dual-hosted git repository.

remm pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/main by this push:
     new 714236a  Switch again to shared scope for the context
714236a is described below

commit 714236af3458f030ec598660fa5fa886cd63dbd0
Author: remm <r...@apache.org>
AuthorDate: Mon Dec 20 17:22:58 2021 +0100

    Switch again to shared scope for the context
    
    Following further feedback from Panama.
    The problem is the implicit scope isn't explicitly closed on JVM
    shutdown at the moment. OTOH, this change (once everything is done
    properly, there were simply too many places when convenient references
    could be kept, preventing GC) to a shared scope works fine both with GC
    (like the implicit scope does) and JVM shutdown (the explicit clean call
    on shutdown does the cleanup there).
    The engine should be able to keep its implicit scope for optimal safety
    (GC will likely come soon enough for engines).
---
 .../util/net/openssl/panama/OpenSSLContext.java    | 67 +++++++++++++---------
 webapps/docs/changelog.xml                         |  4 ++
 2 files changed, 43 insertions(+), 28 deletions(-)

diff --git 
a/modules/openssl-java17/src/main/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLContext.java
 
b/modules/openssl-java17/src/main/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLContext.java
index be94914..2755a0d 100644
--- 
a/modules/openssl-java17/src/main/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLContext.java
+++ 
b/modules/openssl-java17/src/main/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLContext.java
@@ -30,6 +30,8 @@ import java.io.File;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
+import java.lang.ref.Cleaner;
+import java.lang.ref.Cleaner.Cleanable;
 import java.nio.charset.StandardCharsets;
 import java.security.PrivateKey;
 import java.security.SecureRandom;
@@ -72,6 +74,8 @@ public class OpenSSLContext implements 
org.apache.tomcat.util.net.SSLContext {
     private static final StringManager netSm = 
StringManager.getManager(AbstractEndpoint.class);
     private static final StringManager sm = 
StringManager.getManager(OpenSSLContext.class);
 
+    private static final Cleaner cleaner = Cleaner.create();
+
     private static final String defaultProtocol = "TLS";
 
     private static final int SSL_AIDX_RSA     = 0;
@@ -167,7 +171,7 @@ public class OpenSSLContext implements 
org.apache.tomcat.util.net.SSLContext {
     }
 
     private final ContextState state;
-    private final ResourceScope contextScope;
+    private final Cleanable cleanable;
 
     private static String[] getCiphers(MemoryAddress sslCtx) {
         MemoryAddress sk = SSL_CTX_get_ciphers(sslCtx);
@@ -198,7 +202,7 @@ public class OpenSSLContext implements 
org.apache.tomcat.util.net.SSLContext {
 
         this.sslHostConfig = certificate.getSSLHostConfig();
         this.certificate = certificate;
-        contextScope = ResourceScope.newImplicitScope();
+        ResourceScope contextScope = ResourceScope.newSharedScope();
 
         MemoryAddress sslCtx = MemoryAddress.NULL;
         MemoryAddress confCtx = MemoryAddress.NULL;
@@ -335,7 +339,7 @@ public class OpenSSLContext implements 
org.apache.tomcat.util.net.SSLContext {
         } catch(Exception e) {
             throw new SSLException(sm.getString("openssl.errorSSLCtxInit"), e);
         } finally {
-            state = new ContextState(sslCtx, confCtx, 
negotiableProtocolsBytes);
+            state = new ContextState(contextScope, sslCtx, confCtx, 
negotiableProtocolsBytes);
             /*
              * When an SSLHostConfig is replaced at runtime, it is not 
possible to
              * call destroy() on the associated OpenSSLContext since it is 
likely
@@ -347,7 +351,7 @@ public class OpenSSLContext implements 
org.apache.tomcat.util.net.SSLContext {
              * and the implicit scope will ensure that the associated native
              * resources are cleaned up.
              */
-            contextScope.addCloseAction(state);
+            cleanable = cleaner.register(this, state);
 
             if (!success) {
                 destroy();
@@ -368,6 +372,7 @@ public class OpenSSLContext implements 
org.apache.tomcat.util.net.SSLContext {
 
     @Override
     public void destroy() {
+        cleanable.clean();
     }
 
 
@@ -554,7 +559,7 @@ public class OpenSSLContext implements 
org.apache.tomcat.util.net.SSLContext {
             }
 
             // List the ciphers that the client is permitted to negotiate
-            if (SSL_CTX_set_cipher_list(state.sslCtx, 
CLinker.toCString(sslHostConfig.getCiphers(), contextScope)) <= 0) {
+            if (SSL_CTX_set_cipher_list(state.sslCtx, 
CLinker.toCString(sslHostConfig.getCiphers(), state.contextScope)) <= 0) {
                 log.warn(sm.getString("engine.failedCipherSuite", 
sslHostConfig.getCiphers()));
             }
 
@@ -590,18 +595,18 @@ public class OpenSSLContext implements 
org.apache.tomcat.util.net.SSLContext {
             // Set int verify_callback(int preverify_ok, X509_STORE_CTX 
*x509_ctx) callback
             MemoryAddress openSSLCallbackVerify =
                     
CLinker.getInstance().upcallStub(openSSLCallbackVerifyHandle,
-                    openSSLCallbackVerifyFunctionDescriptor, contextScope);
+                    openSSLCallbackVerifyFunctionDescriptor, 
state.contextScope);
             // Leave this just in case but in Tomcat this is always set again 
by the engine
             SSL_CTX_set_verify(state.sslCtx, value, openSSLCallbackVerify);
 
             // Trust and certificate verification
-            var allocator = SegmentAllocator.ofScope(contextScope);
+            var allocator = SegmentAllocator.ofScope(state.contextScope);
             if (tms != null) {
                 // Client certificate verification based on custom trust 
managers
                 state.x509TrustManager = chooseTrustManager(tms);
                 MemoryAddress openSSLCallbackCertVerify =
                         
CLinker.getInstance().upcallStub(openSSLCallbackCertVerifyHandle,
-                                openSSLCallbackCertVerifyFunctionDescriptor, 
contextScope);
+                                openSSLCallbackCertVerifyFunctionDescriptor, 
state.contextScope);
                 SSL_CTX_set_cert_verify_callback(state.sslCtx, 
openSSLCallbackCertVerify, state.sslCtx);
 
                 // Pass along the DER encoded certificates of the accepted 
client
@@ -627,9 +632,9 @@ public class OpenSSLContext implements 
org.apache.tomcat.util.net.SSLContext {
                 //        
SSLHostConfig.adjustRelativePath(sslHostConfig.getCaCertificateFile()),
                 //        
SSLHostConfig.adjustRelativePath(sslHostConfig.getCaCertificatePath()));
                 MemorySegment caCertificateFileNative = 
sslHostConfig.getCaCertificateFile() != null
-                        ? 
CLinker.toCString(SSLHostConfig.adjustRelativePath(sslHostConfig.getCaCertificateFile()),
 contextScope) : null;
+                        ? 
CLinker.toCString(SSLHostConfig.adjustRelativePath(sslHostConfig.getCaCertificateFile()),
 state.contextScope) : null;
                 MemorySegment caCertificatePathNative = 
sslHostConfig.getCaCertificatePath() != null
-                        ? 
CLinker.toCString(SSLHostConfig.adjustRelativePath(sslHostConfig.getCaCertificatePath()),
 contextScope) : null;
+                        ? 
CLinker.toCString(SSLHostConfig.adjustRelativePath(sslHostConfig.getCaCertificatePath()),
 state.contextScope) : null;
                 if (SSL_CTX_load_verify_locations(state.sslCtx,
                         caCertificateFileNative == null ? MemoryAddress.NULL : 
caCertificateFileNative,
                                 caCertificatePathNative == null ? 
MemoryAddress.NULL : caCertificatePathNative) <= 0) {
@@ -654,7 +659,7 @@ public class OpenSSLContext implements 
org.apache.tomcat.util.net.SSLContext {
                 // No CA certificates configured. Reject all client 
certificates.
                 MemoryAddress openSSLCallbackCertVerify =
                         
CLinker.getInstance().upcallStub(openSSLCallbackCertVerifyHandle,
-                                openSSLCallbackCertVerifyFunctionDescriptor, 
contextScope);
+                                openSSLCallbackCertVerifyFunctionDescriptor, 
state.contextScope);
                 SSL_CTX_set_cert_verify_callback(state.sslCtx, 
openSSLCallbackCertVerify, MemoryAddress.NULL);
             }
 
@@ -663,7 +668,7 @@ public class OpenSSLContext implements 
org.apache.tomcat.util.net.SSLContext {
                 //        MemoryAddress in, int inlen, MemoryAddress arg
                 MemoryAddress openSSLCallbackAlpnSelectProto =
                         
CLinker.getInstance().upcallStub(openSSLCallbackAlpnSelectProtoHandle,
-                        openSSLCallbackAlpnSelectProtoFunctionDescriptor, 
contextScope);
+                        openSSLCallbackAlpnSelectProtoFunctionDescriptor, 
state.contextScope);
                 SSL_CTX_set_alpn_select_cb(state.sslCtx, 
openSSLCallbackAlpnSelectProto, state.sslCtx);
                 // Skip NPN (annoying and likely not useful anymore)
                 //SSLContext.setNpnProtos(state.ctx, protocolsArray, 
SSL.SSL_SELECTOR_FAILURE_NO_ADVERTISE);
@@ -965,7 +970,7 @@ public class OpenSSLContext implements 
org.apache.tomcat.util.net.SSLContext {
 
 
     private void addCertificate(SSLHostConfigCertificate certificate) throws 
Exception {
-        var allocator = SegmentAllocator.ofScope(contextScope);
+        var allocator = SegmentAllocator.ofScope(state.contextScope);
         int index = getCertificateIndex(certificate);
         // Load Server key and certificate
         if (certificate.getCertificateFile() != null) {
@@ -974,9 +979,9 @@ public class OpenSSLContext implements 
org.apache.tomcat.util.net.SSLContext {
             //        
SSLHostConfig.adjustRelativePath(certificate.getCertificateFile()),
             //        
SSLHostConfig.adjustRelativePath(certificate.getCertificateKeyFile()),
             //        certificate.getCertificateKeyPassword(), 
getCertificateIndex(certificate));
-            var certificateFileNative = 
CLinker.toCString(SSLHostConfig.adjustRelativePath(certificate.getCertificateFile()),
 contextScope);
+            var certificateFileNative = 
CLinker.toCString(SSLHostConfig.adjustRelativePath(certificate.getCertificateFile()),
 state.contextScope);
             var certificateKeyFileNative = 
(certificate.getCertificateKeyFile() == null) ? certificateFileNative
-                    : 
CLinker.toCString(SSLHostConfig.adjustRelativePath(certificate.getCertificateKeyFile()),
 contextScope);
+                    : 
CLinker.toCString(SSLHostConfig.adjustRelativePath(certificate.getCertificateKeyFile()),
 state.contextScope);
             MemoryAddress bio;
             MemoryAddress cert = MemoryAddress.NULL;
             MemoryAddress key = MemoryAddress.NULL;
@@ -1000,7 +1005,7 @@ public class OpenSSLContext implements 
org.apache.tomcat.util.net.SSLContext {
                 int passwordLength = 0;
                 String callbackPassword = 
certificate.getCertificateKeyPassword();
                 if (callbackPassword != null && callbackPassword.length() > 0) 
{
-                    MemorySegment password = 
CLinker.toCString(callbackPassword, contextScope);
+                    MemorySegment password = 
CLinker.toCString(callbackPassword, state.contextScope);
                     passwordAddress = password.address();
                     passwordLength = (int) (password.byteSize() - 1);
                 }
@@ -1104,7 +1109,7 @@ public class OpenSSLContext implements 
org.apache.tomcat.util.net.SSLContext {
             }
             // Try to read DH parameters from the (first) SSLCertificateFile
             if (index == SSL_AIDX_RSA) {
-                bio = BIO_new_file(certificateFileNative, 
CLinker.toCString("r", contextScope));
+                bio = BIO_new_file(certificateFileNative, 
CLinker.toCString("r", state.contextScope));
                 var dh = PEM_read_bio_DHparams(bio, MemoryAddress.NULL, 
MemoryAddress.NULL, MemoryAddress.NULL);
                 BIO_free(bio);
                 // #  define SSL_CTX_set_tmp_dh(sslCtx,dh) \
@@ -1115,7 +1120,7 @@ public class OpenSSLContext implements 
org.apache.tomcat.util.net.SSLContext {
                 }
             }
             // Similarly, try to read the ECDH curve name from 
SSLCertificateFile...
-            bio = BIO_new_file(certificateFileNative, CLinker.toCString("r", 
contextScope));
+            bio = BIO_new_file(certificateFileNative, CLinker.toCString("r", 
state.contextScope));
             var ecparams = PEM_read_bio_ECPKParameters(bio, 
MemoryAddress.NULL, MemoryAddress.NULL, MemoryAddress.NULL);
             BIO_free(bio);
             if (!MemoryAddress.NULL.equals(ecparams)) {
@@ -1129,12 +1134,12 @@ public class OpenSSLContext implements 
org.apache.tomcat.util.net.SSLContext {
             }
             // Set callback for DH parameters
             MemoryAddress openSSLCallbackTmpDH = 
CLinker.getInstance().upcallStub(openSSLCallbackTmpDHHandle,
-                    openSSLCallbackTmpDHFunctionDescriptor, contextScope);
+                    openSSLCallbackTmpDHFunctionDescriptor, 
state.contextScope);
             SSL_CTX_set_tmp_dh_callback(state.sslCtx, openSSLCallbackTmpDH);
             // Set certificate chain file
             if (certificate.getCertificateChainFile() != null) {
                 var certificateChainFileNative =
-                        
CLinker.toCString(SSLHostConfig.adjustRelativePath(certificate.getCertificateChainFile()),
 contextScope);
+                        
CLinker.toCString(SSLHostConfig.adjustRelativePath(certificate.getCertificateChainFile()),
 state.contextScope);
                 // SSLContext.setCertificateChainFile(state.ctx,
                 //        
SSLHostConfig.adjustRelativePath(certificate.getCertificateChainFile()), false);
                 if (SSL_CTX_use_certificate_chain_file(state.sslCtx, 
certificateChainFileNative) <= 0) {
@@ -1151,7 +1156,7 @@ public class OpenSSLContext implements 
org.apache.tomcat.util.net.SSLContext {
             if (sslHostConfig.getCertificateRevocationListFile() != null) {
                 MemoryAddress x509Lookup = 
X509_STORE_add_lookup(certificateStore, X509_LOOKUP_file());
                 var certificateRevocationListFileNative =
-                        
CLinker.toCString(SSLHostConfig.adjustRelativePath(sslHostConfig.getCertificateRevocationListFile()),
 contextScope);
+                        
CLinker.toCString(SSLHostConfig.adjustRelativePath(sslHostConfig.getCertificateRevocationListFile()),
 state.contextScope);
                 //X509_LOOKUP_ctrl(lookup,X509_L_FILE_LOAD,file,type,NULL)
                 if (X509_LOOKUP_ctrl(x509Lookup, X509_L_FILE_LOAD(), 
certificateRevocationListFileNative,
                         X509_FILETYPE_PEM(), MemoryAddress.NULL) <= 0) {
@@ -1161,7 +1166,7 @@ public class OpenSSLContext implements 
org.apache.tomcat.util.net.SSLContext {
             if (sslHostConfig.getCertificateRevocationListPath() != null) {
                 MemoryAddress x509Lookup = 
X509_STORE_add_lookup(certificateStore, X509_LOOKUP_hash_dir());
                 var certificateRevocationListPathNative =
-                        
CLinker.toCString(SSLHostConfig.adjustRelativePath(sslHostConfig.getCertificateRevocationListPath()),
 contextScope);
+                        
CLinker.toCString(SSLHostConfig.adjustRelativePath(sslHostConfig.getCertificateRevocationListPath()),
 state.contextScope);
                 //X509_LOOKUP_ctrl(lookup,X509_L_ADD_DIR,path,type,NULL)
                 if (X509_LOOKUP_ctrl(x509Lookup, X509_L_ADD_DIR(), 
certificateRevocationListPathNative,
                         X509_FILETYPE_PEM(), MemoryAddress.NULL) <= 0) {
@@ -1217,7 +1222,7 @@ public class OpenSSLContext implements 
org.apache.tomcat.util.net.SSLContext {
             }
             // Set callback for DH parameters
             MemoryAddress openSSLCallbackTmpDH = 
CLinker.getInstance().upcallStub(openSSLCallbackTmpDHHandle,
-                    openSSLCallbackTmpDHFunctionDescriptor, contextScope);
+                    openSSLCallbackTmpDHFunctionDescriptor, 
state.contextScope);
             SSL_CTX_set_tmp_dh_callback(state.sslCtx, openSSLCallbackTmpDH);
             for (int i = 1; i < chain.length; i++) {
                 //SSLContext.addChainCertificateRaw(state.ctx, 
chain[i].getEncoded());
@@ -1362,14 +1367,16 @@ public class OpenSSLContext implements 
org.apache.tomcat.util.net.SSLContext {
 
     private static class ContextState implements Runnable {
 
+        private final ResourceScope contextScope;
         private final MemoryAddress sslCtx;
         private final MemoryAddress confCtx;
         private final List<byte[]> negotiableProtocols;
 
         private X509TrustManager x509TrustManager = null;
 
-        private ContextState(MemoryAddress sslCtx, MemoryAddress confCtx, 
List<byte[]> negotiableProtocols) {
+        private ContextState(ResourceScope contextScope, MemoryAddress sslCtx, 
MemoryAddress confCtx, List<byte[]> negotiableProtocols) {
             states.put(Long.valueOf(sslCtx.toRawLongValue()), this);
+            this.contextScope = contextScope;
             this.sslCtx = sslCtx;
             this.confCtx = confCtx;
             this.negotiableProtocols = negotiableProtocols;
@@ -1377,10 +1384,14 @@ public class OpenSSLContext implements 
org.apache.tomcat.util.net.SSLContext {
 
         @Override
         public void run() {
-            states.remove(Long.valueOf(sslCtx.toRawLongValue()));
-            SSL_CTX_free(sslCtx);
-            if (!MemoryAddress.NULL.equals(confCtx)) {
-                SSL_CONF_CTX_free(confCtx);
+            try {
+                states.remove(Long.valueOf(sslCtx.toRawLongValue()));
+                SSL_CTX_free(sslCtx);
+                if (!MemoryAddress.NULL.equals(confCtx)) {
+                    SSL_CONF_CTX_free(confCtx);
+                }
+            } finally {
+                contextScope.close();
             }
         }
     }
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 9e3f380..4153ffd 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -129,6 +129,10 @@
         Revert the previous fix for <bug>65714</bug> and implement a more
         comprehensive fix. (markt)
       </fix>
+      <fix>
+        Allow freeing up context on JVM shutdown in the OpenSSL Panama module
+        by properly using a shared scope. (remm)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Jasper">

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to