add protection against using a freed quiche connection

Signed-off-by: Ludovic Orban <lorban@bitronix.be>
This commit is contained in:
Ludovic Orban 2021-03-18 15:00:49 +01:00 committed by Simone Bordet
parent 69b7fe2887
commit 90fbd977d7
1 changed files with 30 additions and 23 deletions

View File

@ -390,17 +390,17 @@ public class QuicheConnection
{ {
LibQuiche.quiche_stream_iter quiche_stream_iter; LibQuiche.quiche_stream_iter quiche_stream_iter;
if (write) if (write)
quiche_stream_iter = INSTANCE.quiche_conn_writable(quicheConn); quiche_stream_iter = libQuiche().quiche_conn_writable(quicheConn);
else else
quiche_stream_iter = INSTANCE.quiche_conn_readable(quicheConn); quiche_stream_iter = libQuiche().quiche_conn_readable(quicheConn);
List<Long> result = new ArrayList<>(); List<Long> result = new ArrayList<>();
uint64_t_pointer streamId = new uint64_t_pointer(); uint64_t_pointer streamId = new uint64_t_pointer();
while (INSTANCE.quiche_stream_iter_next(quiche_stream_iter, streamId)) while (libQuiche().quiche_stream_iter_next(quiche_stream_iter, streamId))
{ {
result.add(streamId.getValue()); result.add(streamId.getValue());
} }
INSTANCE.quiche_stream_iter_free(quiche_stream_iter); libQuiche().quiche_stream_iter_free(quiche_stream_iter);
return result; return result;
} }
@ -415,7 +415,7 @@ public class QuicheConnection
if (quicheConn == null) if (quicheConn == null)
throw new IOException("Cannot receive when not connected"); throw new IOException("Cannot receive when not connected");
int received = INSTANCE.quiche_conn_recv(quicheConn, buffer, new size_t(buffer.remaining())).intValue(); int received = libQuiche().quiche_conn_recv(quicheConn, buffer, new size_t(buffer.remaining())).intValue();
if (received < 0) if (received < 0)
throw new IOException("Quiche failed to receive packet; err=" + errToString(received)); throw new IOException("Quiche failed to receive packet; err=" + errToString(received));
buffer.position(buffer.position() + received); buffer.position(buffer.position() + received);
@ -432,7 +432,7 @@ public class QuicheConnection
{ {
if (quicheConn == null) if (quicheConn == null)
throw new IOException("Cannot send when not connected"); throw new IOException("Cannot send when not connected");
int written = INSTANCE.quiche_conn_send(quicheConn, buffer, new size_t(buffer.remaining())).intValue(); int written = libQuiche().quiche_conn_send(quicheConn, buffer, new size_t(buffer.remaining())).intValue();
if (written == QUICHE_ERR_DONE) if (written == QUICHE_ERR_DONE)
return 0; return 0;
if (written < 0L) if (written < 0L)
@ -444,41 +444,41 @@ public class QuicheConnection
public synchronized boolean isConnectionClosed() public synchronized boolean isConnectionClosed()
{ {
return INSTANCE.quiche_conn_is_closed(quicheConn); return libQuiche().quiche_conn_is_closed(quicheConn);
} }
public synchronized boolean isConnectionEstablished() public synchronized boolean isConnectionEstablished()
{ {
return INSTANCE.quiche_conn_is_established(quicheConn); return libQuiche().quiche_conn_is_established(quicheConn);
} }
public synchronized boolean isConnectionInEarlyData() public synchronized boolean isConnectionInEarlyData()
{ {
return INSTANCE.quiche_conn_is_in_early_data(quicheConn); return libQuiche().quiche_conn_is_in_early_data(quicheConn);
} }
public synchronized long nextTimeout() public synchronized long nextTimeout()
{ {
return INSTANCE.quiche_conn_timeout_as_millis(quicheConn).longValue(); return libQuiche().quiche_conn_timeout_as_millis(quicheConn).longValue();
} }
public synchronized void onTimeout() public synchronized void onTimeout()
{ {
INSTANCE.quiche_conn_on_timeout(quicheConn); libQuiche().quiche_conn_on_timeout(quicheConn);
} }
public synchronized String getNegotiatedProtocol() public synchronized String getNegotiatedProtocol()
{ {
PointerByReference out = new PointerByReference(); PointerByReference out = new PointerByReference();
size_t_pointer outLen = new size_t_pointer(); size_t_pointer outLen = new size_t_pointer();
INSTANCE.quiche_conn_application_proto(quicheConn, out, outLen); libQuiche().quiche_conn_application_proto(quicheConn, out, outLen);
return new String(out.getValue().getByteArray(0, (int)outLen.getValue()), StandardCharsets.UTF_8); return new String(out.getValue().getByteArray(0, (int)outLen.getValue()), StandardCharsets.UTF_8);
} }
public synchronized String statistics() public synchronized String statistics()
{ {
LibQuiche.quiche_stats stats = new LibQuiche.quiche_stats(); LibQuiche.quiche_stats stats = new LibQuiche.quiche_stats();
INSTANCE.quiche_conn_stats(quicheConn, stats); libQuiche().quiche_conn_stats(quicheConn, stats);
return "[recv: " + stats.recv + return "[recv: " + stats.recv +
" sent: " + stats.sent + " sent: " + stats.sent +
" lost: " + stats.lost + " lost: " + stats.lost +
@ -490,7 +490,7 @@ public class QuicheConnection
public synchronized boolean close() throws IOException public synchronized boolean close() throws IOException
{ {
int rc = INSTANCE.quiche_conn_close(quicheConn, true, new uint64_t(0), null, new size_t(0)); int rc = libQuiche().quiche_conn_close(quicheConn, true, new uint64_t(0), null, new size_t(0));
if (rc == 0) if (rc == 0)
return true; return true;
if (rc == QUICHE_ERR_DONE) if (rc == QUICHE_ERR_DONE)
@ -502,24 +502,24 @@ public class QuicheConnection
{ {
if (quicheConn != null) if (quicheConn != null)
{ {
INSTANCE.quiche_conn_free(quicheConn); libQuiche().quiche_conn_free(quicheConn);
quicheConn = null; quicheConn = null;
} }
if (quicheConfig != null) if (quicheConfig != null)
{ {
INSTANCE.quiche_config_free(quicheConfig); libQuiche().quiche_config_free(quicheConfig);
quicheConfig = null; quicheConfig = null;
} }
} }
public synchronized boolean isDraining() public synchronized boolean isDraining()
{ {
return INSTANCE.quiche_conn_is_draining(quicheConn); return libQuiche().quiche_conn_is_draining(quicheConn);
} }
public synchronized long streamCapacity(long streamId) throws IOException public synchronized long streamCapacity(long streamId) throws IOException
{ {
long value = INSTANCE.quiche_conn_stream_capacity(quicheConn, new uint64_t(streamId)).longValue(); long value = libQuiche().quiche_conn_stream_capacity(quicheConn, new uint64_t(streamId)).longValue();
if (value < 0) if (value < 0)
throw new IOException("Quiche failed to read capacity of stream " + streamId + "; err=" + errToString(value)); throw new IOException("Quiche failed to read capacity of stream " + streamId + "; err=" + errToString(value));
return value; return value;
@ -528,7 +528,7 @@ public class QuicheConnection
public synchronized void shutdownStream(long streamId, boolean writeSide) throws IOException public synchronized void shutdownStream(long streamId, boolean writeSide) throws IOException
{ {
int direction = writeSide ? LibQuiche.quiche_shutdown.QUICHE_SHUTDOWN_WRITE : LibQuiche.quiche_shutdown.QUICHE_SHUTDOWN_READ; int direction = writeSide ? LibQuiche.quiche_shutdown.QUICHE_SHUTDOWN_WRITE : LibQuiche.quiche_shutdown.QUICHE_SHUTDOWN_READ;
int rc = INSTANCE.quiche_conn_stream_shutdown(quicheConn, new uint64_t(streamId), direction, new uint64_t(0)); int rc = libQuiche().quiche_conn_stream_shutdown(quicheConn, new uint64_t(streamId), direction, new uint64_t(0));
if (rc == 0 || rc == QUICHE_ERR_DONE) if (rc == 0 || rc == QUICHE_ERR_DONE)
return; return;
throw new IOException("failed to shutdown stream " + streamId + ": " + LibQuiche.quiche_error.errToString(rc)); throw new IOException("failed to shutdown stream " + streamId + ": " + LibQuiche.quiche_error.errToString(rc));
@ -536,7 +536,7 @@ public class QuicheConnection
public synchronized void feedFinForStream(long streamId) throws IOException public synchronized void feedFinForStream(long streamId) throws IOException
{ {
int written = INSTANCE.quiche_conn_stream_send(quicheConn, new uint64_t(streamId), null, new size_t(0), true).intValue(); int written = libQuiche().quiche_conn_stream_send(quicheConn, new uint64_t(streamId), null, new size_t(0), true).intValue();
if (written == QUICHE_ERR_DONE) if (written == QUICHE_ERR_DONE)
return; return;
if (written < 0L) if (written < 0L)
@ -545,7 +545,7 @@ public class QuicheConnection
public synchronized int feedClearTextForStream(long streamId, ByteBuffer buffer) throws IOException public synchronized int feedClearTextForStream(long streamId, ByteBuffer buffer) throws IOException
{ {
int written = INSTANCE.quiche_conn_stream_send(quicheConn, new uint64_t(streamId), buffer, new size_t(buffer.remaining()), false).intValue(); int written = libQuiche().quiche_conn_stream_send(quicheConn, new uint64_t(streamId), buffer, new size_t(buffer.remaining()), false).intValue();
if (written == QUICHE_ERR_DONE) if (written == QUICHE_ERR_DONE)
return 0; return 0;
if (written < 0L) if (written < 0L)
@ -557,7 +557,7 @@ public class QuicheConnection
public synchronized int drainClearTextForStream(long streamId, ByteBuffer buffer) throws IOException public synchronized int drainClearTextForStream(long streamId, ByteBuffer buffer) throws IOException
{ {
bool_pointer fin = new bool_pointer(); bool_pointer fin = new bool_pointer();
int written = INSTANCE.quiche_conn_stream_recv(quicheConn, new uint64_t(streamId), buffer, new size_t(buffer.remaining()), fin).intValue(); int written = libQuiche().quiche_conn_stream_recv(quicheConn, new uint64_t(streamId), buffer, new size_t(buffer.remaining()), fin).intValue();
if (written == QUICHE_ERR_DONE) if (written == QUICHE_ERR_DONE)
return 0; return 0;
if (written < 0L) if (written < 0L)
@ -568,6 +568,13 @@ public class QuicheConnection
public synchronized boolean isStreamFinished(long streamId) public synchronized boolean isStreamFinished(long streamId)
{ {
return INSTANCE.quiche_conn_stream_finished(quicheConn, new uint64_t(streamId)); return libQuiche().quiche_conn_stream_finished(quicheConn, new uint64_t(streamId));
}
private LibQuiche libQuiche()
{
if (quicheConn == null)
throw new IllegalStateException("Quiche connection was released");
return INSTANCE;
} }
} }