Skip to content
  • Davide Libenzi's avatar
    epoll: prevent creating circular epoll structures · 22bacca4
    Davide Libenzi authored
    
    
    In several places, an epoll fd can call another file's ->f_op->poll()
    method with ep->mtx held.  This is in general unsafe, because that other
    file could itself be an epoll fd that contains the original epoll fd.
    
    The code defends against this possibility in its own ->poll() method using
    ep_call_nested, but there are several other unsafe calls to ->poll
    elsewhere that can be made to deadlock.  For example, the following simple
    program causes the call in ep_insert recursively call the original fd's
    ->poll, leading to deadlock:
    
     #include <unistd.h>
     #include <sys/epoll.h>
    
     int main(void) {
         int e1, e2, p[2];
         struct epoll_event evt = {
             .events = EPOLLIN
         };
    
         e1 = epoll_create(1);
         e2 = epoll_create(2);
         pipe(p);
    
         epoll_ctl(e2, EPOLL_CTL_ADD, e1, &evt);
         epoll_ctl(e1, EPOLL_CTL_ADD, p[0], &evt);
         write(p[1], p, sizeof p);
         epoll_ctl(e1, EPOLL_CTL_ADD, e2, &evt);
    
         return 0;
     }
    
    On insertion, check whether the inserted file is itself a struct epoll,
    and if so, do a recursive walk to detect whether inserting this file would
    create a loop of epoll structures, which could lead to deadlock.
    
    [nelhage@ksplice.com: Use epmutex to serialize concurrent inserts]
    Signed-off-by: default avatarDavide Libenzi <davidel@xmailserver.org>
    Signed-off-by: default avatarNelson Elhage <nelhage@ksplice.com>
    Reported-by: default avatarNelson Elhage <nelhage@ksplice.com>
    Tested-by: default avatarNelson Elhage <nelhage@ksplice.com>
    Cc: <stable@kernel.org>		[2.6.34+, possibly earlier]
    Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    22bacca4