cstp_send: fix worker hang and buffer overread on TLS send

A worker could get permanently stuck when a client disappeared silently
(e.g. iOS roaming between WiFi and cellular): the TLS send loop retried
indefinitely on GNUTLS_E_AGAIN with no deadline, requiring SIGKILL to
recover.

A separate bug caused a buffer overread on partial sends: the retry used
the original data_size instead of the remaining byte count, so the send
pointer advanced past the end of the caller's buffer.

Resolves: #638

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
This commit is contained in:
Nikos Mavrogiannopoulos
2026-05-23 07:39:51 +02:00
parent bb9bcd7461
commit 35e3d15a11
+9 -9
View File
@@ -31,6 +31,7 @@
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <poll.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
@@ -102,18 +103,17 @@ ssize_t cstp_send(worker_st *ws, const void *data, size_t data_size)
if (ws->session != NULL) {
while (left > 0) {
ret = gnutls_record_send(ws->session, p, data_size);
ret = gnutls_record_send(ws->session, p, left);
if (ret < 0) {
struct pollfd pfd = { ws->conn_fd, POLLOUT, 0 };
if (ret != GNUTLS_E_AGAIN &&
ret != GNUTLS_E_INTERRUPTED) {
ret != GNUTLS_E_INTERRUPTED)
return ret;
} else {
/* do not cause mayhem */
ms_sleep(20);
}
}
if (ret > 0) {
/* wait for writability; peer gone if timeout */
if (poll(&pfd, 1,
DEFAULT_SOCKET_TIMEOUT * 1000) <= 0)
return GNUTLS_E_PUSH_ERROR;
} else if (ret > 0) {
left -= ret;
p += ret;
}