postgres.git / summary / log / commit / refs

commit    c159b0383fa6412686abfb4e6de9face87d2b0cc
Author:   Thomas Munro <tmunro@postgresql.org>
Date:     Thu Jan 12 21:40:52 2023 +0000
First released in: 16.0, 11.19, 12.14, 13.10, 14.7, 15.2

    Fix WaitEventSetWait() buffer overrun.
    
    The WAIT_USE_EPOLL and WAIT_USE_KQUEUE implementations of
    WaitEventSetWaitBlock() confused the size of their internal buffer with
    the size of the caller's output buffer, and could ask the kernel for too
    many events.  In fact the set of events retrieved from the kernel needs
    to be able to fit in both buffers, so take the smaller of the two.
    
    The WAIT_USE_POLL and WAIT_USE WIN32 implementations didn't have this
    confusion.
    
    This probably didn't come up before because we always used the same
    number in both places, but commit 7389aad6 calculates a dynamic size at
    construction time, while using MAXLISTEN for its output event buffer on
    the stack.  That seems like a reasonable thing to want to do, so
    consider this to be a pre-existing bug worth fixing.
    
    As discovered by valgrind on skink.
    
    Back-patch to all supported releases for epoll, and to release 13 for
    the kqueue part, which copied the incorrect epoll code.
    
    Reviewed-by: Andres Freund <andres@anarazel.de>
    Discussion: https://postgr.es/m/901504.1673504836%40sss.pgh.pa.us


src/backend/storage/ipc/latch.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/backend/storage/ipc/latch.c b/src/backend/storage/ipc/latch.c index 4ae53c09fca..f346f832ee1 100644 --- a/src/backend/storage/ipc/latch.c +++ b/src/backend/storage/ipc/latch.c @@ -1293,7 +1293,7 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout, /* Sleep */ rc = epoll_wait(set->epoll_fd, set->epoll_ret_events, - nevents, cur_timeout); + Min(nevents, set->nevents_space), cur_timeout); /* Check return code */ if (rc < 0) @@ -1445,7 +1445,8 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout, /* Sleep */ rc = kevent(set->kqueue_fd, NULL, 0, - set->kqueue_ret_events, nevents, + set->kqueue_ret_events, + Min(nevents, set->nevents_space), timeout_p); /* Check return code */ [parent: 2ff3ac3b5f52]