From 4e56c5c956fbac7319592c959980a10f9109979f Mon Sep 17 00:00:00 2001 From: Jakub Jelen Date: Fri, 4 Aug 2023 21:39:46 +0200 Subject: [PATCH] poll: Avoid passing other events to callbacks when called recursively Some architectures (s390x) provide different poll events such as POLLHUP in case the remote end closed the connection (and they keep reporting this forever). This is an issue when the user provided callback registering this event as an error and tries to send some reply (for example EOF) using `ssh_channel_send_eof()` which will lead to infinite recursion and sefgaults. This was not solved by the 30b5a2e33bf260062dd31c9c0e98cf9982b08961 because the POLLHUP event is not provided by the poll in events bitfield, but only reported by the poll in revents bit field thus we need to filter these events later on when the poll is recursively. Fixes #202 Signed-off-by: Jakub Jelen Reviewed-by: Andreas Schneider --- src/poll.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/poll.c b/src/poll.c index b5d0a662..8f81c11c 100644 --- a/src/poll.c +++ b/src/poll.c @@ -722,14 +722,21 @@ int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout) used = ctx->polls_used; for (i = 0; i < used && rc > 0; ) { - if (ctx->pollfds[i].revents == 0) { + revents = ctx->pollfds[i].revents; + /* Do not pass any other events except for POLLOUT to callback when + * called recursively more than 2 times. On s390x the poll will be + * spammed with POLLHUP events causing infinite recursion when the user + * callback issues some write/flush/poll calls. */ + if (ctx->pollptrs[i]->lock_cnt > 2) { + revents &= POLLOUT; + } + if (revents == 0) { i++; } else { int ret; p = ctx->pollptrs[i]; fd = ctx->pollfds[i].fd; - revents = ctx->pollfds[i].revents; /* avoid having any event caught during callback */ ctx->pollfds[i].events = 0; p->lock_cnt++;