1
0
mirror of https://github.com/nmap/nmap.git synced 2026-01-21 05:39:14 +00:00

Handle SSL_read()/SSL_write() returning 0 when not EOF.

OpenSSL docs say, "Old documentation indicated a difference between 0
and -1, and that -1 was retryable. You should instead call
SSL_get_error() to find out if it's retryable."
This commit is contained in:
dmiller
2024-11-21 20:11:38 +00:00
parent ff1df7a80c
commit 38823b5cd1

View File

@@ -537,43 +537,50 @@ void handle_write_result(struct npool *ms, struct nevent *nse, enum nse_status s
if (nse->writeinfo.written_so_far > 0)
assert(bytesleft > 0);
#if HAVE_OPENSSL
if (iod->ssl)
if (iod->ssl) {
res = SSL_write(iod->ssl, str, bytesleft);
if (res == bytesleft) {
nse->event_done = 1;
nse->status = NSE_STATUS_SUCCESS;
} else if (res > 0) {
// This should never happen unless we set SSL_MODE_ENABLE_PARTIAL_WRITE
nse->writeinfo.written_so_far += res;
} else { // res <= 0
int evclr, evset;
err = SSL_get_error(iod->ssl, res);
switch(err) {
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
evclr = socket_count_dec_ssl_desire(nse);
evset = (err == SSL_ERROR_WANT_READ) ?
socket_count_read_inc(iod) :
socket_count_write_inc(iod);
update_events(iod, ms, nse, evset, evclr);
nse->sslinfo.ssl_desire = err;
break;
default:
assert(err != SSL_ERROR_NONE);
/* Unexpected error */
nse->event_done = 1;
nse->status = NSE_STATUS_ERROR;
nse->errnum = EIO;
nsock_log_info("SSL_write() failed for reason %s on NSI %li",
ERR_error_string(err, NULL), iod->id);
break;
}
}
}
else
#endif
{
res = ms->engine->io_operations->iod_write(ms, nse->iod->sd, str, bytesleft, 0, (struct sockaddr *)&nse->writeinfo.dest, (int)nse->writeinfo.destlen);
if (res == bytesleft) {
nse->event_done = 1;
nse->status = NSE_STATUS_SUCCESS;
} else if (res >= 0) {
nse->writeinfo.written_so_far += res;
} else {
assert(res == -1);
if (iod->ssl) {
#if HAVE_OPENSSL
err = SSL_get_error(iod->ssl, res);
if (err == SSL_ERROR_WANT_READ) {
int evclr;
evclr = socket_count_dec_ssl_desire(nse);
socket_count_read_inc(iod);
update_events(iod, ms, nse, EV_READ, evclr);
nse->sslinfo.ssl_desire = err;
} else if (err == SSL_ERROR_WANT_WRITE) {
int evclr;
evclr = socket_count_dec_ssl_desire(nse);
socket_count_write_inc(iod);
update_events(iod, ms, nse, EV_WRITE, evclr);
nse->sslinfo.ssl_desire = err;
} else {
/* Unexpected error */
nse->event_done = 1;
nse->status = NSE_STATUS_ERROR;
nse->errnum = EIO;
}
#endif
if (res == bytesleft) {
nse->event_done = 1;
nse->status = NSE_STATUS_SUCCESS;
} else if (res >= 0) {
nse->writeinfo.written_so_far += res;
} else {
assert(res == -1);
err = socket_errno();
if (errcode_is_failure(err)) {
nse->event_done = 1;
@@ -714,30 +721,34 @@ static int do_actual_read(struct npool *ms, struct nevent *nse) {
return fs_length(&nse->iobuf) - startlen;
}
if (buflen == -1) {
if (buflen <= 0) {
int evclr, evset;
err = SSL_get_error(iod->ssl, buflen);
if (err == SSL_ERROR_WANT_READ) {
int evclr;
evclr = socket_count_dec_ssl_desire(nse);
socket_count_read_inc(iod);
update_events(iod, ms, nse, EV_READ, evclr);
nse->sslinfo.ssl_desire = err;
} else if (err == SSL_ERROR_WANT_WRITE) {
int evclr;
evclr = socket_count_dec_ssl_desire(nse);
socket_count_write_inc(iod);
update_events(iod, ms, nse, EV_WRITE, evclr);
nse->sslinfo.ssl_desire = err;
} else {
/* Unexpected error */
nse->event_done = 1;
nse->status = NSE_STATUS_ERROR;
nse->errnum = EIO;
nsock_log_info("SSL_read() failed for reason %s on NSI %li",
ERR_error_string(err, NULL), iod->id);
return -1;
switch (err) {
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
evclr = socket_count_dec_ssl_desire(nse);
evset = (err == SSL_ERROR_WANT_READ) ?
socket_count_read_inc(iod) :
socket_count_write_inc(iod);
update_events(iod, ms, nse, evset, evclr);
nse->sslinfo.ssl_desire = err;
/* Not EOF! */
buflen = 1;
break;
case SSL_ERROR_ZERO_RETURN:
/* EOF because of close_notify */
buflen = 0;
break;
default:
assert(err != SSL_ERROR_NONE);
/* Unexpected error */
nse->event_done = 1;
nse->status = NSE_STATUS_ERROR;
nse->errnum = EIO;
nsock_log_info("SSL_read() failed for reason %s on NSI %li",
ERR_error_string(err, NULL), iod->id);
return -1;
}
}
#endif /* HAVE_OPENSSL */