From: David van Moolenbroek Date: Wed, 20 Jul 2016 12:47:34 +0000 (+0000) Subject: VFS: deny copying sockets to owning socket driver X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/dnssec-keyfromlabel.html?a=commitdiff_plain;h=c344203e4858b24220b3cc2fe16a369b2a25bbcd;p=minix.git VFS: deny copying sockets to owning socket driver 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 --- diff --git a/minix/servers/vfs/filedes.c b/minix/servers/vfs/filedes.c index 4ba4faf8a..ea7ee4a4e 100644 --- a/minix/servers/vfs/filedes.c +++ b/minix/servers/vfs/filedes.c @@ -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 */