Re: disfunctional floppy driver in kernels 4.5, 4.6 and 4.7

Jiri Kosina
2016-06-15T14:13:57Z

On Wed, 15 Jun 2016, Al Viro wrote:

> ioctl-only open. It's an old weird part of /dev/fd0 ABI

Ah, right you are, I completely forgot about this gem.

> and if you are playing with that driver,

I am merely trying to keep it in a state that doesn't crash the system.

> you'd better bother to check the actual userland talking to it.

Sure, this needs to be fixed.

Wim, could you please test whether the patch below, applied on top of
vanilla kernel (i.e. drop the revert), everything you are using still
works as expected?

From: Jiri Kosina <jkosina@suse.cz>
Subject: [PATCH] floppy: fix open(O_ACCMODE) for ioctl-only open

Commit 09954bad4 ("floppy: refactor open() flags handling"), as a side-effect,
causes open(/dev/fdX, O_ACCMODE) to fail. It turns out that this is being used
setfdprm userspace for ioctl-only open().

Reintroduce back the original behavior wrt !(FMODE_READ|FMODE_WRITE)
modes, while still keeping the original O_NDELAY bug fixed.

Reported-by: Al Viro <viro@ZenIV.linux.org.uk>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
---
drivers/block/floppy.c | 21 +++++++++------------
1 file changed, 9 insertions(+), 12 deletions(-)

diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 84708a5..a1dcf12 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -3663,11 +3663,6 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)

opened_bdev[drive] = bdev;

- if (!(mode & (FMODE_READ|FMODE_WRITE))) {
- res = -EINVAL;
- goto out;
- }
-
res = -ENXIO;

if (!floppy_track_buffer) {
@@ -3711,13 +3706,15 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
if (UFDCS->rawcmd == 1)
UFDCS->rawcmd = 2;

- UDRS->last_checked = 0;
- clear_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags);
- check_disk_change(bdev);
- if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
- goto out;
- if (test_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags))
- goto out;
+ if (mode & (FMODE_READ|FMODE_WRITE)) {
+ UDRS->last_checked = 0;
+ clear_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags);
+ check_disk_change(bdev);
+ if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
+ goto out;
+ if (test_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags))
+ goto out;
+ }

res = -EROFS;

--
Jiri Kosina
SUSE Labs