mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +00:00
fix: add TLS handshake timeout and fix accept loop deadlock
Two issues in TlsListener::poll_accept: 1. No timeout on TLS handshakes: LazyConfigAcceptor waits indefinitely for ClientHello. Attackers that complete TCP handshake but never send TLS data create zombie futures in `in_progress` that never complete. Fix: wrap the entire handshake in tokio::time::timeout(15s). 2. Missing waker on new-connection pending path: when a TCP connection is accepted and the TLS handshake is pending, poll_accept returned Pending without calling wake_by_ref(). Since the TcpListener returned Ready (not Pending), no waker was registered for it. With edge- triggered epoll and no other wakeup source, the task sleeps forever and remaining connections in the kernel accept queue are never drained. Fix: add cx.waker().wake_by_ref() so the task immediately re-polls and continues draining the accept queue.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
use std::sync::Arc;
|
||||
use std::task::{Poll, ready};
|
||||
use std::time::Duration;
|
||||
|
||||
use futures::future::BoxFuture;
|
||||
use futures::stream::FuturesUnordered;
|
||||
@@ -170,14 +171,20 @@ where
|
||||
let (metadata, stream) = ready!(self.accept.poll_accept(cx)?);
|
||||
let mut tls_handler = self.tls_handler.clone();
|
||||
let mut fut = async move {
|
||||
let res = async {
|
||||
let mut acceptor =
|
||||
LazyConfigAcceptor::new(Acceptor::default(), BackTrackingIO::new(stream));
|
||||
let mut mid: tokio_rustls::StartHandshake<BackTrackingIO<AcceptStream>> =
|
||||
match (&mut acceptor).await {
|
||||
let res = match tokio::time::timeout(
|
||||
Duration::from_secs(15),
|
||||
async {
|
||||
let mut acceptor = LazyConfigAcceptor::new(
|
||||
Acceptor::default(),
|
||||
BackTrackingIO::new(stream),
|
||||
);
|
||||
let mut mid: tokio_rustls::StartHandshake<
|
||||
BackTrackingIO<AcceptStream>,
|
||||
> = match (&mut acceptor).await {
|
||||
Ok(a) => a,
|
||||
Err(e) => {
|
||||
let mut stream = acceptor.take_io().or_not_found("acceptor io")?;
|
||||
let mut stream =
|
||||
acceptor.take_io().or_not_found("acceptor io")?;
|
||||
let (_, buf) = stream.rewind();
|
||||
if std::str::from_utf8(buf)
|
||||
.ok()
|
||||
@@ -201,46 +208,57 @@ where
|
||||
}
|
||||
}
|
||||
};
|
||||
let hello = mid.client_hello();
|
||||
if let Some(cfg) = tls_handler.get_config(&hello, &metadata).await {
|
||||
let buffered = mid.io.stop_buffering();
|
||||
mid.io
|
||||
.write_all(&buffered)
|
||||
.await
|
||||
.with_kind(ErrorKind::Network)?;
|
||||
return Ok(match mid.into_stream(Arc::new(cfg)).await {
|
||||
Ok(stream) => {
|
||||
let s = stream.get_ref().1;
|
||||
Some((
|
||||
TlsMetadata {
|
||||
inner: metadata,
|
||||
tls_info: TlsHandshakeInfo {
|
||||
sni: s.server_name().map(InternedString::intern),
|
||||
alpn: s
|
||||
.alpn_protocol()
|
||||
.map(|a| MaybeUtf8String(a.to_vec())),
|
||||
let hello = mid.client_hello();
|
||||
if let Some(cfg) = tls_handler.get_config(&hello, &metadata).await {
|
||||
let buffered = mid.io.stop_buffering();
|
||||
mid.io
|
||||
.write_all(&buffered)
|
||||
.await
|
||||
.with_kind(ErrorKind::Network)?;
|
||||
return Ok(match mid.into_stream(Arc::new(cfg)).await {
|
||||
Ok(stream) => {
|
||||
let s = stream.get_ref().1;
|
||||
Some((
|
||||
TlsMetadata {
|
||||
inner: metadata,
|
||||
tls_info: TlsHandshakeInfo {
|
||||
sni: s
|
||||
.server_name()
|
||||
.map(InternedString::intern),
|
||||
alpn: s
|
||||
.alpn_protocol()
|
||||
.map(|a| MaybeUtf8String(a.to_vec())),
|
||||
},
|
||||
},
|
||||
},
|
||||
Box::pin(stream) as AcceptStream,
|
||||
))
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::trace!("Error completing TLS handshake: {e}");
|
||||
tracing::trace!("{e:?}");
|
||||
None
|
||||
}
|
||||
});
|
||||
}
|
||||
Box::pin(stream) as AcceptStream,
|
||||
))
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::trace!("Error completing TLS handshake: {e}");
|
||||
tracing::trace!("{e:?}");
|
||||
None
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
.await;
|
||||
Ok(None)
|
||||
},
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(res) => res,
|
||||
Err(_) => {
|
||||
tracing::trace!("TLS handshake timed out");
|
||||
Ok(None)
|
||||
}
|
||||
};
|
||||
(tls_handler, res)
|
||||
}
|
||||
.boxed();
|
||||
match fut.poll_unpin(cx) {
|
||||
Poll::Pending => {
|
||||
in_progress.push(fut);
|
||||
cx.waker().wake_by_ref();
|
||||
Poll::Pending
|
||||
}
|
||||
Poll::Ready((handler, res)) => {
|
||||
|
||||
Reference in New Issue
Block a user