]> Zhao Yanbai Git Server - minix.git/commitdiff
VFS: deny copying sockets to owning socket driver 21/3421/1
authorDavid van Moolenbroek <david@minix3.org>
Wed, 20 Jul 2016 12:47:34 +0000 (12:47 +0000)
committerDavid van Moolenbroek <david@minix3.org>
Thu, 9 Mar 2017 23:39:51 +0000 (23:39 +0000)
This patch stops a socket driver from using copyfd(2) to copy in a
file descriptor that is a reference to a socket owned by that socket
driver, returning EDEADLK instead.  In effect, this will stop deadlock
and resource exhaustion issues with UDS once it has been converted to
a socket driver.  See the comment in the patch for details.

Change-Id: I5728a405eabda207725618231a6ff7be2d517146

minix/servers/vfs/filedes.c

index 4ba4faf8a6e1a711636eefc173de4249c3f020b3..ea7ee4a4e17d1d8ac7ab19e48fbde9c49ce48d09 100644 (file)
@@ -529,6 +529,8 @@ int do_copyfd(void)
  */
   struct fproc *rfp;
   struct filp *rfilp;
+  struct vnode *vp;
+  struct smap *sp;
   endpoint_t endpt;
   int r, fd, what, slot;
 
@@ -571,6 +573,40 @@ int do_copyfd(void)
 
   switch (what) {
   case COPYFD_FROM:
+       /*
+        * If the caller is a socket driver (namely, UDS) and the file
+        * descriptor being copied in is a socket for that socket driver, then
+        * deny the call, because of at least two known issues.  Both issues
+        * are related to UDS having an in-flight file descriptor that is the
+        * last reference to a UDS socket:
+        *
+        * 1) if UDS tries to close the file descriptor, this will prompt VFS
+        *    to close the underlying object, which is a UDS socket.  As a
+        *    result, while UDS is blocked in the close(2), VFS will try to
+        *    send a request to UDS to close the socket.  This results in a
+        *    deadlock of the UDS service.
+        *
+        * 2) if a file descriptor for a UDS socket is sent across that same
+        *    UDS socket, the socket will remain referenced by UDS, thus open
+        *    in VFS, and therefore also open in UDS.  The socket and file
+        *    descriptor will both remain in use for the rest of UDS' lifetime.
+        *    This can easily result in denial-of-service in the UDS service.
+        *    The same problem can be triggered using multiple sockets that
+        *    have in-flight file descriptors referencing each other.
+        *
+        * A proper solution for these problems may consist of some form of
+        * "soft reference counting" where VFS does not count UDS having a
+        * filp open as a real reference.  That is tricky business, so for now
+        * we prevent any such problems with the check here.
+        */
+       if ((vp = rfilp->filp_vno) != NULL && S_ISSOCK(vp->v_mode) &&
+           (sp = get_smap_by_dev(vp->v_sdev, NULL)) != NULL &&
+           sp->smap_endpt == who_e) {
+               r = EDEADLK;
+
+               break;
+       }
+
        rfp = fp;
 
        /* FALLTHROUGH */