Package: freeradius
Version: 3.0.12+dfsg-5
Severity: important
Tags: patch
freeRADIUS v3 does have implementation bug. It isn't able to read more
than one packet from incoming TLS (RadSec) connection. The bug shows
more likely on large deployments and is able to make server completely
useless. That is why I'm setting Severity to important.
More detailed technical info is available here:
https://github.com/FreeRADIUS/freeradius-server/pull/2106
https://github.com/FreeRADIUS/freeradius-server/pull/2107
The attached patch is tested against official freeRAIDUS releases
3.0.12, 3.0.14, 3.0.15 and against Debian package
freeradius_3.0.12+dfsg-5 it fixes the problem and causes no harm.
Please is it possible to propagate this into Debian/Stretch?
Thanks
--
-----------------------
Jan Tomasek aka Semik
http://www.tomasek.cz/
--- freeradius-server-3.0.15/src/main/tls_listen.c 2017-07-17 14:43:00.000000000 +0200
+++ freeradius-server/src/main/tls_listen.c 2017-11-05 08:39:50.681941501 +0100
@@ -188,6 +188,18 @@
RDEBUG3("Reading from socket %d", request->packet->sockfd);
PTHREAD_MUTEX_LOCK(&sock->mutex);
+
+ /*
+ * If there is pending application data, as set up by
+ * SSL_peek(), read that before reading more data from
+ * the socket.
+ */
+ if (SSL_pending(sock->ssn->ssl)) {
+ RDEBUG3("Reading pending buffered data");
+ sock->ssn->dirty_in.used = 0;
+ goto get_application_data;
+ }
+
rcode = read(request->packet->sockfd,
sock->ssn->dirty_in.data,
sizeof(sock->ssn->dirty_in.data));
@@ -249,6 +261,7 @@
/*
* Try to get application data.
*/
+get_application_data:
status = tls_application_data(sock->ssn, request);
RDEBUG("Application data status %d", status);
@@ -332,9 +345,13 @@
RAD_REQUEST_FUNP fun = NULL;
listen_socket_t *sock = listener->data;
RADCLIENT *client = sock->client;
+ BIO *rbio;
+ int pending;
if (listener->status != RAD_LISTEN_STATUS_KNOWN) return 0;
+
+redo:
if (!tls_socket_recv(listener)) {
return 0;
}
@@ -402,6 +419,27 @@
return 0;
}
+ /*
+ * Check for more application data.
+ *
+ * If there is pending SSL data, "peek" at the
+ * application data. If we get at least one byte of
+ * application data, go back to tls_socket_recv().
+ * SSL_peek() will set SSL_pending(), and
+ * tls_socket_recv() will read another packet.
+ */
+ rbio = SSL_get_rbio(sock->ssn->ssl);
+ pending = BIO_ctrl_pending(rbio);
+ if (pending) {
+ char buf[1];
+ int peek = SSL_peek(sock->ssn->ssl, buf, 1);
+
+ if (peek > 0) {
+ DEBUG("more TLS records after dual_tls_recv");
+ goto redo;
+ }
+ }
+
return 1;
}