VFS: better dupfrom(2) deadlock detection
Change-Id: I29f00075698888c7c8ca60b47ab82fba8c606f4e
This commit is contained in:
parent
9e3e032c26
commit
50685cbec3
4 changed files with 19 additions and 16 deletions
|
@ -560,9 +560,13 @@ int do_ioctl(message *UNUSED(m_out))
|
|||
if (r == OK) {
|
||||
dev = (dev_t) vp->v_sdev;
|
||||
|
||||
if (S_ISBLK(vp->v_mode))
|
||||
if (S_ISBLK(vp->v_mode)) {
|
||||
f->filp_ioctl_fp = fp;
|
||||
|
||||
r = bdev_ioctl(dev, who_e, ioctlrequest, argx);
|
||||
else
|
||||
|
||||
f->filp_ioctl_fp = NULL;
|
||||
} else
|
||||
r = cdev_io(CDEV_IOCTL, dev, who_e, argx, 0, ioctlrequest,
|
||||
f->filp_flags);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,9 @@ EXTERN struct filp {
|
|||
struct fproc *filp_softlock; /* if not NULL; this filp didn't lock the
|
||||
* vnode. Another filp already holds a lock
|
||||
* for this thread */
|
||||
struct fproc *filp_ioctl_fp; /* if not NULL, this filp is locked by the
|
||||
* process for a currently ongoing IOCTL call
|
||||
*/
|
||||
|
||||
/* the following fields are for select() and are owned by the generic
|
||||
* select() code (i.e., fd-type-specific select() code can't touch these).
|
||||
|
|
|
@ -131,6 +131,7 @@ int get_fd(struct fproc *rfp, int start, mode_t bits, int *k, struct filp **fpt)
|
|||
f->filp_flags = 0;
|
||||
f->filp_select_flags = 0;
|
||||
f->filp_softlock = NULL;
|
||||
f->filp_ioctl_fp = NULL;
|
||||
*fpt = f;
|
||||
return(OK);
|
||||
}
|
||||
|
@ -628,7 +629,6 @@ int do_dupfrom(message *UNUSED(m_out))
|
|||
*/
|
||||
struct fproc *rfp;
|
||||
struct filp *rfilp;
|
||||
struct vnode *vp;
|
||||
endpoint_t endpt;
|
||||
int r, fd, slot;
|
||||
|
||||
|
@ -647,19 +647,15 @@ int do_dupfrom(message *UNUSED(m_out))
|
|||
if ((rfilp = get_filp2(rfp, fd, VNODE_NONE)) == NULL)
|
||||
return(err_code);
|
||||
|
||||
/* For now, we do not allow remote duplication of device nodes. In practice,
|
||||
* only a block-special file can cause a deadlock for the caller (currently
|
||||
* only the VND driver). This would happen if a user process passes in the
|
||||
* file descriptor to the device node on which it is performing the IOCTL.
|
||||
* This would cause two VFS threads to deadlock on the same filp. Since the
|
||||
* VND driver does not allow device nodes to be used anyway, this somewhat
|
||||
* rudimentary check eliminates such deadlocks. A better solution would be
|
||||
* to check if the given endpoint holds a lock to the target filp, but we
|
||||
* currently do not have this information within VFS.
|
||||
/* If the filp is involved in an IOCTL by the user process, locking the filp
|
||||
* here would result in a deadlock. This would happen if a user process
|
||||
* passes in the file descriptor to the device node on which it is performing
|
||||
* the IOCTL. We do not allow manipulation of such device nodes. In
|
||||
* practice, this only applies to block-special files (and thus VND), because
|
||||
* character-special files (as used by UDS) are unlocked during the IOCTL.
|
||||
*/
|
||||
vp = rfilp->filp_vno;
|
||||
if (S_ISCHR(vp->v_mode) || S_ISBLK(vp->v_mode))
|
||||
return(EINVAL);
|
||||
if (rfilp->filp_ioctl_fp == rfp)
|
||||
return(EBADF);
|
||||
|
||||
/* Now we can safely lock the filp, copy it, and unlock it again. */
|
||||
lock_filp(rfilp, VNODE_READ);
|
||||
|
|
|
@ -42,7 +42,7 @@ main(int argc, char **argv)
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (errno != EINVAL) {
|
||||
if (errno != EBADF) {
|
||||
perror("ioctl(VNDIOCSET)");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue