From 90dd75f3e48e90421505f0dc66568907c17fb24b Mon Sep 17 00:00:00 2001 From: Tobias Girstmair Date: Sat, 25 May 2024 15:11:10 +0200 Subject: [PATCH] fix segfault on D-line when connecting to irc.efnet.nl we get banned after RPL_WELCOME. the whole (looong) MOTD loads, then we get ERR_YOUREBANNEDCREEP and a fatal ERROR and the server closes the connection. this bug manifested, when setting '-j', that poll (ircpipe.c:246) returns revents == POLLHUP|POLLIN (while we expected only POLLIN). when read(2)ing from the now-closed socket, we then read 0 bytes. in irc_answer (ircpipe.c:260), strtok_r then returns NULL on the first invocation (which again we did not expect, as we did not expect an empty buffer to get passed). then we tried to look at the first character of the string, dereferencing NULL and causing a SIGSEGV. the solution is of course to check that return value of read(2) is > 0. this is equivalent to aborting on POLLHUP; the comment in irc_poll() has been adjusted to reflect this as well. --- ircpipe.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ircpipe.c b/ircpipe.c index b8b176d..ae71e50 100644 --- a/ircpipe.c +++ b/ircpipe.c @@ -229,6 +229,7 @@ int irc_setup(const sock_t sock, const int outfd, const char *nick, const char * for (;;) { if (poll(fds, 1, POLL_TIMEOUT)) { n = READ(sock, buf, BUFSIZ); buf[n] = '\0'; + if (n == 0) return -1; /* server closed connection */ write(outfd, buf, n); n = irc_answer(sock, buf, NICK); if (n & NICK) break; @@ -245,6 +246,7 @@ int irc_setup(const sock_t sock, const int outfd, const char *nick, const char * for (;;) { if (poll(fds, 1, POLL_TIMEOUT)) { n = READ(sock, buf, BUFSIZ); buf[n] = '\0'; + if (n == 0) return -1; /* server closed connection */ write(outfd, buf, n); n = irc_answer(sock, buf, JOIN); if (n & JOIN) break; @@ -281,7 +283,7 @@ int irc_poll(const sock_t sock, const int infd, const int outfd) { /* XXX: should handle EINTR, EAGAIN -> retry should handle EPIPE and others -> exit */ - /* todo: could check for fds[IRC].revents & (POLLERR|POLLHUP): tcp FIN or RST received */ + /* todo: could check for fds[IRC].revents & (POLLERR|POLLHUP): tcp FIN or RST received (should already be covered by n==0) */ if (fds[IRC].revents & POLLIN) { n = READ(sock, buf, BUFSIZ); buf[n] = '\0'; if (n == 0) return -1; /* server closed connection */ -- 2.39.3