Guard against possible segfault when OpenSslContext is gc'ed and user still hold reference to OpenSslSessionContext / OpenSslSessionStats
Motivation: When the OpenSslContext is gc'ed and the user still hold a reference to OpenSslSessionContext / OpenSslSessionStats it is possible to produce a segfault when calling a method on any of these that tries to pass down the ctx pointer to the native methods. This is because the OpenSslContext finalizer will free the native pointer. Modifications: Change OpenSslSessionContext / OpenSslSessionContext to store a reference to OpenSslContext and so prevent the GC to collect it as long as the user has a reference to OpenSslSessionContext / OpenSslSessionContext. Result: No more sefault possible.
This commit is contained in:
parent
4a1e0ceb4d
commit
65d1fb474d
@ -264,7 +264,7 @@ public final class OpenSslClientContext extends OpenSslContext {
|
|||||||
throw new SSLException("unable to setup trustmanager", e);
|
throw new SSLException("unable to setup trustmanager", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sessionContext = new OpenSslClientSessionContext(ctx);
|
sessionContext = new OpenSslClientSessionContext(this);
|
||||||
success = true;
|
success = true;
|
||||||
} finally {
|
} finally {
|
||||||
if (!success) {
|
if (!success) {
|
||||||
@ -280,7 +280,7 @@ public final class OpenSslClientContext extends OpenSslContext {
|
|||||||
|
|
||||||
// No cache is currently supported for client side mode.
|
// No cache is currently supported for client side mode.
|
||||||
private static final class OpenSslClientSessionContext extends OpenSslSessionContext {
|
private static final class OpenSslClientSessionContext extends OpenSslSessionContext {
|
||||||
private OpenSslClientSessionContext(long context) {
|
private OpenSslClientSessionContext(OpenSslContext context) {
|
||||||
super(context);
|
super(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,7 +365,10 @@ public abstract class OpenSslContext extends SslContext {
|
|||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final void destroy() {
|
// IMPORTANT: This method must only be called from either the constructor or the finalizer as a user MUST never
|
||||||
|
// get access to an OpenSslSessionContext after this method was called to prevent the user from
|
||||||
|
// producing a segfault.
|
||||||
|
final void destroy() {
|
||||||
synchronized (OpenSslContext.class) {
|
synchronized (OpenSslContext.class) {
|
||||||
if (ctx != 0) {
|
if (ctx != 0) {
|
||||||
SSLContext.free(ctx);
|
SSLContext.free(ctx);
|
||||||
|
@ -433,7 +433,7 @@ public final class OpenSslServerContext extends OpenSslContext {
|
|||||||
throw new SSLException("unable to setup trustmanager", e);
|
throw new SSLException("unable to setup trustmanager", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sessionContext = new OpenSslServerSessionContext(ctx);
|
sessionContext = new OpenSslServerSessionContext(this);
|
||||||
sessionContext.setSessionIdContext(ID);
|
sessionContext.setSessionIdContext(ID);
|
||||||
success = true;
|
success = true;
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -23,7 +23,7 @@ import org.apache.tomcat.jni.SSLContext;
|
|||||||
* {@link OpenSslSessionContext} implementation which offers extra methods which are only useful for the server-side.
|
* {@link OpenSslSessionContext} implementation which offers extra methods which are only useful for the server-side.
|
||||||
*/
|
*/
|
||||||
public final class OpenSslServerSessionContext extends OpenSslSessionContext {
|
public final class OpenSslServerSessionContext extends OpenSslSessionContext {
|
||||||
OpenSslServerSessionContext(long context) {
|
OpenSslServerSessionContext(OpenSslContext context) {
|
||||||
super(context);
|
super(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,12 +32,12 @@ public final class OpenSslServerSessionContext extends OpenSslSessionContext {
|
|||||||
if (seconds < 0) {
|
if (seconds < 0) {
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
SSLContext.setSessionCacheTimeout(context, seconds);
|
SSLContext.setSessionCacheTimeout(context.ctx, seconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSessionTimeout() {
|
public int getSessionTimeout() {
|
||||||
return (int) SSLContext.getSessionCacheTimeout(context);
|
return (int) SSLContext.getSessionCacheTimeout(context.ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -45,23 +45,23 @@ public final class OpenSslServerSessionContext extends OpenSslSessionContext {
|
|||||||
if (size < 0) {
|
if (size < 0) {
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
SSLContext.setSessionCacheSize(context, size);
|
SSLContext.setSessionCacheSize(context.ctx, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSessionCacheSize() {
|
public int getSessionCacheSize() {
|
||||||
return (int) SSLContext.getSessionCacheSize(context);
|
return (int) SSLContext.getSessionCacheSize(context.ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSessionCacheEnabled(boolean enabled) {
|
public void setSessionCacheEnabled(boolean enabled) {
|
||||||
long mode = enabled ? SSL.SSL_SESS_CACHE_SERVER : SSL.SSL_SESS_CACHE_OFF;
|
long mode = enabled ? SSL.SSL_SESS_CACHE_SERVER : SSL.SSL_SESS_CACHE_OFF;
|
||||||
SSLContext.setSessionCacheMode(context, mode);
|
SSLContext.setSessionCacheMode(context.ctx, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSessionCacheEnabled() {
|
public boolean isSessionCacheEnabled() {
|
||||||
return SSLContext.getSessionCacheMode(context) == SSL.SSL_SESS_CACHE_SERVER;
|
return SSLContext.getSessionCacheMode(context.ctx) == SSL.SSL_SESS_CACHE_SERVER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -74,6 +74,6 @@ public final class OpenSslServerSessionContext extends OpenSslSessionContext {
|
|||||||
* @return {@code true} if success, {@code false} otherwise.
|
* @return {@code true} if success, {@code false} otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean setSessionIdContext(byte[] sidCtx) {
|
public boolean setSessionIdContext(byte[] sidCtx) {
|
||||||
return SSLContext.setSessionIdContext(context, sidCtx);
|
return SSLContext.setSessionIdContext(context.ctx, sidCtx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,9 +30,13 @@ public abstract class OpenSslSessionContext implements SSLSessionContext {
|
|||||||
private static final Enumeration<byte[]> EMPTY = new EmptyEnumeration();
|
private static final Enumeration<byte[]> EMPTY = new EmptyEnumeration();
|
||||||
|
|
||||||
private final OpenSslSessionStats stats;
|
private final OpenSslSessionStats stats;
|
||||||
final long context;
|
final OpenSslContext context;
|
||||||
|
|
||||||
OpenSslSessionContext(long context) {
|
// IMPORTANT: We take the OpenSslContext and not just the long (which points the native instance) to prevent
|
||||||
|
// the GC to collect OpenSslContext as this would also free the pointer and so could result in a
|
||||||
|
// segfault when the user calls any of the methods here that try to pass the pointer down to the native
|
||||||
|
// level.
|
||||||
|
OpenSslSessionContext(OpenSslContext context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
stats = new OpenSslSessionStats(context);
|
stats = new OpenSslSessionStats(context);
|
||||||
}
|
}
|
||||||
@ -59,7 +63,7 @@ public abstract class OpenSslSessionContext implements SSLSessionContext {
|
|||||||
if (keys == null) {
|
if (keys == null) {
|
||||||
throw new NullPointerException("keys");
|
throw new NullPointerException("keys");
|
||||||
}
|
}
|
||||||
SSLContext.setSessionTicketKeys(context, keys);
|
SSLContext.setSessionTicketKeys(context.ctx, keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -73,7 +77,7 @@ public abstract class OpenSslSessionContext implements SSLSessionContext {
|
|||||||
for (int i = 0; i < ticketKeys.length; i++) {
|
for (int i = 0; i < ticketKeys.length; i++) {
|
||||||
ticketKeys[i] = keys[i].key;
|
ticketKeys[i] = keys[i].key;
|
||||||
}
|
}
|
||||||
SSLContext.setSessionTicketKeys(context, ticketKeys);
|
SSLContext.setSessionTicketKeys(context.ctx, ticketKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -25,9 +25,13 @@ import org.apache.tomcat.jni.SSLContext;
|
|||||||
*/
|
*/
|
||||||
public final class OpenSslSessionStats {
|
public final class OpenSslSessionStats {
|
||||||
|
|
||||||
private final long context;
|
private final OpenSslContext context;
|
||||||
|
|
||||||
OpenSslSessionStats(long context) {
|
// IMPORTANT: We take the OpenSslContext and not just the long (which points the native instance) to prevent
|
||||||
|
// the GC to collect OpenSslContext as this would also free the pointer and so could result in a
|
||||||
|
// segfault when the user calls any of the methods here that try to pass the pointer down to the native
|
||||||
|
// level.
|
||||||
|
OpenSslSessionStats(OpenSslContext context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,49 +39,49 @@ public final class OpenSslSessionStats {
|
|||||||
* Returns the current number of sessions in the internal session cache.
|
* Returns the current number of sessions in the internal session cache.
|
||||||
*/
|
*/
|
||||||
public long number() {
|
public long number() {
|
||||||
return SSLContext.sessionNumber(context);
|
return SSLContext.sessionNumber(context.ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of started SSL/TLS handshakes in client mode.
|
* Returns the number of started SSL/TLS handshakes in client mode.
|
||||||
*/
|
*/
|
||||||
public long connect() {
|
public long connect() {
|
||||||
return SSLContext.sessionConnect(context);
|
return SSLContext.sessionConnect(context.ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of successfully established SSL/TLS sessions in client mode.
|
* Returns the number of successfully established SSL/TLS sessions in client mode.
|
||||||
*/
|
*/
|
||||||
public long connectGood() {
|
public long connectGood() {
|
||||||
return SSLContext.sessionConnectGood(context);
|
return SSLContext.sessionConnectGood(context.ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of start renegotiations in client mode.
|
* Returns the number of start renegotiations in client mode.
|
||||||
*/
|
*/
|
||||||
public long connectRenegotiate() {
|
public long connectRenegotiate() {
|
||||||
return SSLContext.sessionConnectRenegotiate(context);
|
return SSLContext.sessionConnectRenegotiate(context.ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of started SSL/TLS handshakes in server mode.
|
* Returns the number of started SSL/TLS handshakes in server mode.
|
||||||
*/
|
*/
|
||||||
public long accept() {
|
public long accept() {
|
||||||
return SSLContext.sessionAccept(context);
|
return SSLContext.sessionAccept(context.ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of successfully established SSL/TLS sessions in server mode.
|
* Returns the number of successfully established SSL/TLS sessions in server mode.
|
||||||
*/
|
*/
|
||||||
public long acceptGood() {
|
public long acceptGood() {
|
||||||
return SSLContext.sessionAcceptGood(context);
|
return SSLContext.sessionAcceptGood(context.ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of start renegotiations in server mode.
|
* Returns the number of start renegotiations in server mode.
|
||||||
*/
|
*/
|
||||||
public long acceptRenegotiate() {
|
public long acceptRenegotiate() {
|
||||||
return SSLContext.sessionAcceptRenegotiate(context);
|
return SSLContext.sessionAcceptRenegotiate(context.ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -86,14 +90,14 @@ public final class OpenSslSessionStats {
|
|||||||
* external cache is counted as a hit.
|
* external cache is counted as a hit.
|
||||||
*/
|
*/
|
||||||
public long hits() {
|
public long hits() {
|
||||||
return SSLContext.sessionHits(context);
|
return SSLContext.sessionHits(context.ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of successfully retrieved sessions from the external session cache in server mode.
|
* Returns the number of successfully retrieved sessions from the external session cache in server mode.
|
||||||
*/
|
*/
|
||||||
public long cbHits() {
|
public long cbHits() {
|
||||||
return SSLContext.sessionCbHits(context);
|
return SSLContext.sessionCbHits(context.ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -101,7 +105,7 @@ public final class OpenSslSessionStats {
|
|||||||
* in server mode.
|
* in server mode.
|
||||||
*/
|
*/
|
||||||
public long misses() {
|
public long misses() {
|
||||||
return SSLContext.sessionMisses(context);
|
return SSLContext.sessionMisses(context.ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -110,13 +114,13 @@ public final class OpenSslSessionStats {
|
|||||||
* count.
|
* count.
|
||||||
*/
|
*/
|
||||||
public long timeouts() {
|
public long timeouts() {
|
||||||
return SSLContext.sessionTimeouts(context);
|
return SSLContext.sessionTimeouts(context.ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of sessions that were removed because the maximum session cache size was exceeded.
|
* Returns the number of sessions that were removed because the maximum session cache size was exceeded.
|
||||||
*/
|
*/
|
||||||
public long cacheFull() {
|
public long cacheFull() {
|
||||||
return SSLContext.sessionCacheFull(context);
|
return SSLContext.sessionCacheFull(context.ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user