AST-2017-004: chan_skinny: Add EOF check in skinny_session

The while(1) loop in skinny_session wasn't checking for EOF so
a packet that was longer than a header but still truncated
would spin the while loop infinitely.  Not only does this
permanently tie up a thread and drive a core to 100% utilization,
the call of ast_log() in such a tight loop eats all available
process memory.

Added poll with timeout to top of read loop

ASTERISK-26940 #close
Reported-by: Sandro Gauci

Change-Id: I2ce65f3c5cb24b4943a9f75b64d545a1e2cd2898
certified/13.18
George Joseph 8 years ago committed by Matthew Fredrickson
parent 722ec0671e
commit 1cc18d4025

@ -7502,6 +7502,8 @@ static void skinny_session_cleanup(void *data)
destroy_session(s); destroy_session(s);
} }
#define PACKET_TIMEOUT 10000
static void *skinny_session(void *data) static void *skinny_session(void *data)
{ {
int res; int res;
@ -7548,7 +7550,10 @@ static void *skinny_session(void *data)
} }
} }
if (fds[0].revents) { if (!fds[0].revents) {
continue;
}
ast_debug(1, "Reading header\n");
if (!(req = ast_calloc(1, SKINNY_MAX_PACKET))) { if (!(req = ast_calloc(1, SKINNY_MAX_PACKET))) {
ast_log(LOG_WARNING, "Unable to allocated memorey for skinny_req.\n"); ast_log(LOG_WARNING, "Unable to allocated memorey for skinny_req.\n");
@ -7583,30 +7588,36 @@ static void *skinny_session(void *data)
break; break;
} }
ast_debug(1, "Read header: Message ID: 0x%04x, %d bytes in packet\n", eventmessage, dlen);
bytesread = 0; bytesread = 0;
while (1) { while (bytesread < dlen) {
if ((res = read(s->fd, ((char*)&req->data)+bytesread, dlen-bytesread)) < 0) { ast_debug(1, "Waiting %dms for %d bytes of %d\n", PACKET_TIMEOUT, dlen - bytesread, dlen);
ast_log(LOG_WARNING, "Data read() returned error: %s\n", strerror(errno)); fds[0].revents = 0;
break; res = ast_poll(fds, 1, PACKET_TIMEOUT);
} if (res <= 0) {
bytesread += res; if (res == 0) {
if (bytesread >= dlen) { ast_debug(1, "Poll timed out waiting for %d bytes\n", dlen - bytesread);
if (res < bytesread) { } else {
ast_log(LOG_WARNING, "Rest of partial data received.\n"); ast_log(LOG_WARNING, "Poll failed waiting for %d bytes: %s\n",
dlen - bytesread, strerror(errno));
} }
if (bytesread > dlen) { ast_verb(3, "Ending Skinny session from %s (bad input)\n", ast_inet_ntoa(s->sin.sin_addr));
ast_log(LOG_WARNING, "Client sent wrong amount of data (%d), expected (%d).\n", bytesread, dlen);
res = -1; res = -1;
}
break; break;
} }
if (!fds[0].revents) {
continue;
}
ast_log(LOG_WARNING, "Partial data received, waiting (%d bytes read of %d)\n", bytesread, dlen); res = read(s->fd, ((char*)&req->data)+bytesread, dlen-bytesread);
if (sched_yield() < 0) { if (res < 0) {
ast_log(LOG_WARNING, "Data yield() returned error: %s\n", strerror(errno)); ast_log(LOG_WARNING, "Data read() returned error: %s\n", strerror(errno));
res = -1;
break; break;
} }
bytesread += res;
ast_debug(1, "Read %d bytes. %d of %d now read\n", res, bytesread, dlen);
} }
s->lockstate = 0; s->lockstate = 0;
@ -7618,7 +7629,6 @@ static void *skinny_session(void *data)
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
res = handle_message(req, s); res = handle_message(req, s);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
}
if (req) { if (req) {
ast_free(req); ast_free(req);

Loading…
Cancel
Save