aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2016-02-06 17:00:22 -0500
committerJiri Kosina <jkosina@suse.cz>2016-02-06 17:00:22 -0500
commit09954bad448791ef01202351d437abdd9497a804 (patch)
treee44a5262e04f1a19a4bfbfc5ba82d9bc440b4f5d
parentbf64318564c43385ffc3d3dfedab5287bdf3dfdd (diff)
floppy: refactor open() flags handling
In case /dev/fdX is open with O_NDELAY / O_NONBLOCK, floppy_open() immediately succeeds, without performing any further media / controller preparations. That's "correct" wrt. the NODELAY flag, but is hardly correct wrt. the rest of the floppy driver, that is not really O_NONBLOCK ready, at all. Therefore it's not too surprising, that subsequent attempts to work with the filedescriptor produce bad results. Namely, syzkaller tool has been able to livelock mmap() on the returned fd to keep waiting on the page unlock bit forever. Quite frankly, I have trouble defining what non-blocking behavior would be for floppies. Is waiting ages for the driver to actually succeed reading a sector blocking operation? Is waiting for drive motor to start blocking operation? How about in case of virtualized floppies? One option would be returning EWOULDBLOCK in case O_NDLEAY / O_NONBLOCK is being passed to open(). That has a theoretical potential of breaking some arcane and archaic userspace though. Let's take a more conservative aproach, and accept the O_NDLEAY flag, and let the driver behave as usual. While at it, clean up a bit handling of !(mode & (FMODE_READ|FMODE_WRITE)) case and return EINVAL instead of succeeding as well. Spotted by syzkaller tool. Reported-by: Dmitry Vyukov <dvyukov@google.com> Tested-by: Dmitry Vyukov <dvyukov@google.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r--drivers/block/floppy.c34
1 files changed, 19 insertions, 15 deletions
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index b206115d761c..84708a5f8c52 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -3663,6 +3663,11 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
3663 3663
3664 opened_bdev[drive] = bdev; 3664 opened_bdev[drive] = bdev;
3665 3665
3666 if (!(mode & (FMODE_READ|FMODE_WRITE))) {
3667 res = -EINVAL;
3668 goto out;
3669 }
3670
3666 res = -ENXIO; 3671 res = -ENXIO;
3667 3672
3668 if (!floppy_track_buffer) { 3673 if (!floppy_track_buffer) {
@@ -3706,21 +3711,20 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
3706 if (UFDCS->rawcmd == 1) 3711 if (UFDCS->rawcmd == 1)
3707 UFDCS->rawcmd = 2; 3712 UFDCS->rawcmd = 2;
3708 3713
3709 if (!(mode & FMODE_NDELAY)) { 3714 UDRS->last_checked = 0;
3710 if (mode & (FMODE_READ|FMODE_WRITE)) { 3715 clear_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags);
3711 UDRS->last_checked = 0; 3716 check_disk_change(bdev);
3712 clear_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags); 3717 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
3713 check_disk_change(bdev); 3718 goto out;
3714 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags)) 3719 if (test_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags))
3715 goto out; 3720 goto out;
3716 if (test_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags)) 3721
3717 goto out; 3722 res = -EROFS;
3718 } 3723
3719 res = -EROFS; 3724 if ((mode & FMODE_WRITE) &&
3720 if ((mode & FMODE_WRITE) && 3725 !test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
3721 !test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags)) 3726 goto out;
3722 goto out; 3727
3723 }
3724 mutex_unlock(&open_lock); 3728 mutex_unlock(&open_lock);
3725 mutex_unlock(&floppy_mutex); 3729 mutex_unlock(&floppy_mutex);
3726 return 0; 3730 return 0;