Fix dangling pointer in epoll after epoll_recalc().

This is based on patch 2790759 from Kevin Springborn.  His comments on
sourceforge:

  Problem:
  The failure case is as follows: Event is added using epoll_add (a
  direct pointer is stored in the user_data section), epoll_recalc is
  called and the fds array is moved (invalidating the user_data
  pointer stored in epoll).  epoll_dispatch is called for the added
  event and accesses evepoll based on the invalid pointer (set before
  the fds array was relocated).

  Solution:
  Dispatch has access to the epollop structure, so given the fd we can
  find the corresponding evepoll struct. Use data.fd instead of
  data.ptr and store the fd corresponding to the event. This way when
  epoll_recalc moves the fds array (and updates the fds array pointer
  in epollop), the evepoll calculation in dispatch still finds the
  valid evepoll struct.

svn:r1282
This commit is contained in:
Nick Mathewson 2009-05-12 18:27:45 +00:00
parent a276fa5155
commit 5e0563ba9a
2 changed files with 7 additions and 3 deletions

View File

@ -1,6 +1,7 @@
Changes in 1.4.11-stable:
o Fix a bug when removing a timeout from the heap. [Patch from Marko Kreen]
o Remove the limit on size of HTTP headers by removing static buffers.
o Fix a nasty dangling pointer bug in epoll.c that could occur after epoll_recalc(). [Patch from Kevin Springborn]
Changes in 1.4.10-stable:
o clean up buffered http connection data on reset; reported by Brian O'Kelley

View File

@ -224,8 +224,11 @@ epoll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
for (i = 0; i < res; i++) {
int what = events[i].events;
struct event *evread = NULL, *evwrite = NULL;
int fd = events[i].data.fd;
evep = (struct evepoll *)events[i].data.ptr;
if (fd < 0 && fd >= epollop->nfds)
continue;
evep = &epollop->fds[fd];
if (what & (EPOLLHUP|EPOLLERR)) {
evread = evep->evread;
@ -287,7 +290,7 @@ epoll_add(void *arg, struct event *ev)
if (ev->ev_events & EV_WRITE)
events |= EPOLLOUT;
epev.data.ptr = evep;
epev.data.fd = fd;
epev.events = events;
if (epoll_ctl(epollop->epfd, op, ev->ev_fd, &epev) == -1)
return (-1);
@ -339,7 +342,7 @@ epoll_del(void *arg, struct event *ev)
}
epev.events = events;
epev.data.ptr = evep;
epev.data.fd = fd;
if (needreaddelete)
evep->evread = NULL;