diff --git a/changes/bug14554 b/changes/bug14554 new file mode 100644 index 000000000..ff2566f7a --- /dev/null +++ b/changes/bug14554 @@ -0,0 +1,4 @@ + o Major bugfix + - Possibility of an infinite loop if the returned value of the read/recv + was 0. A returned value of 0 means that we've reached the EOF thus the + pipe/sock is drained so return success not an error. diff --git a/src/common/compat_threads.c b/src/common/compat_threads.c index d2d929e43..15648d285 100644 --- a/src/common/compat_threads.c +++ b/src/common/compat_threads.c @@ -171,10 +171,12 @@ pipe_drain(int fd) { char buf[32]; ssize_t r; - while ((r = read_ni(fd, buf, sizeof(buf))) >= 0) - ; - if (r == 0 || errno != EAGAIN) + do { + r = read_ni(fd, buf, sizeof(buf)); + } while (r > 0); + if (r < 0 && errno != EAGAIN) return -1; + /* A value of r = 0 means EOF on the fd so successfully drained. */ return 0; } #endif @@ -193,10 +195,12 @@ sock_drain(tor_socket_t fd) { char buf[32]; ssize_t r; - while ((r = recv_ni(fd, buf, sizeof(buf), 0)) >= 0) - ; - if (r == 0 || !ERRNO_IS_EAGAIN(tor_socket_errno(fd))) + do { + r = recv_ni(fd, buf, sizeof(buf), 0); + } while (r > 0); + if (r < 0 && !ERRNO_IS_EAGAIN(tor_socket_errno(fd))) return -1; + /* A value of r = 0 means EOF on the fd so successfully drained. */ return 0; }