floppy: disable FDRAWCMD by default
authorWilly Tarreau <w@1wt.eu>
Tue, 26 Apr 2022 20:41:05 +0000 (23:41 +0300)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 27 Apr 2022 16:41:54 +0000 (09:41 -0700)
Minh Yuan reported a concurrency use-after-free issue in the floppy code
between raw_cmd_ioctl and seek_interrupt.

[ It turns out this has been around, and that others have reported the
  KASAN splats over the years, but Minh Yuan had a reproducer for it and
  so gets primary credit for reporting it for this fix   - Linus ]

The problem is, this driver tends to break very easily and nowadays,
nobody is expected to use FDRAWCMD anyway since it was used to
manipulate non-standard formats.  The risk of breaking the driver is
higher than the risk presented by this race, and accessing the device
requires privileges anyway.

Let's just add a config option to completely disable this ioctl and
leave it disabled by default.  Distros shouldn't use it, and only those
running on antique hardware might need to enable it.

Link: https://lore.kernel.org/all/000000000000b71cdd05d703f6bf@google.com/
Link: https://lore.kernel.org/lkml/CAKcFiNC=MfYVW-Jt9A3=FPJpTwCD2PL_ULNCpsCVE5s8ZeBQgQ@mail.gmail.com
Link: https://lore.kernel.org/all/CAEAjamu1FRhz6StCe_55XY5s389ZP_xmCF69k987En+1z53=eg@mail.gmail.com
Reported-by: Minh Yuan <yuanmingbuaa@gmail.com>
Reported-by: syzbot+8e8958586909d62b6840@syzkaller.appspotmail.com
Reported-by: cruise k <cruise4k@gmail.com>
Reported-by: Kyungtae Kim <kt0755@gmail.com>
Suggested-by: Linus Torvalds <torvalds@linuxfoundation.org>
Tested-by: Denis Efremov <efremov@linux.com>
Signed-off-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
drivers/block/Kconfig
drivers/block/floppy.c

index 519b6d3..fdb81f2 100644 (file)
@@ -33,6 +33,22 @@ config BLK_DEV_FD
          To compile this driver as a module, choose M here: the
          module will be called floppy.
 
+config BLK_DEV_FD_RAWCMD
+       bool "Support for raw floppy disk commands (DEPRECATED)"
+       depends on BLK_DEV_FD
+       help
+         If you want to use actual physical floppies and expect to do
+         special low-level hardware accesses to them (access and use
+         non-standard formats, for example), then enable this.
+
+         Note that the code enabled by this option is rarely used and
+         might be unstable or insecure, and distros should not enable it.
+
+         Note: FDRAWCMD is deprecated and will be removed from the kernel
+         in the near future.
+
+         If unsure, say N.
+
 config AMIGA_FLOPPY
        tristate "Amiga floppy support"
        depends on AMIGA
index 8c64753..d5b9ff9 100644 (file)
@@ -2982,6 +2982,8 @@ static const char *drive_name(int type, int drive)
                return "(null)";
 }
 
+#ifdef CONFIG_BLK_DEV_FD_RAWCMD
+
 /* raw commands */
 static void raw_cmd_done(int flag)
 {
@@ -3181,6 +3183,35 @@ static int raw_cmd_ioctl(int cmd, void __user *param)
        return ret;
 }
 
+static int floppy_raw_cmd_ioctl(int type, int drive, int cmd,
+                               void __user *param)
+{
+       int ret;
+
+       pr_warn_once("Note: FDRAWCMD is deprecated and will be removed from the kernel in the near future.\n");
+
+       if (type)
+               return -EINVAL;
+       if (lock_fdc(drive))
+               return -EINTR;
+       set_floppy(drive);
+       ret = raw_cmd_ioctl(cmd, param);
+       if (ret == -EINTR)
+               return -EINTR;
+       process_fd_request();
+       return ret;
+}
+
+#else /* CONFIG_BLK_DEV_FD_RAWCMD */
+
+static int floppy_raw_cmd_ioctl(int type, int drive, int cmd,
+                               void __user *param)
+{
+       return -EOPNOTSUPP;
+}
+
+#endif
+
 static int invalidate_drive(struct block_device *bdev)
 {
        /* invalidate the buffer track to force a reread */
@@ -3369,7 +3400,6 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
 {
        int drive = (long)bdev->bd_disk->private_data;
        int type = ITYPE(drive_state[drive].fd_device);
-       int i;
        int ret;
        int size;
        union inparam {
@@ -3520,16 +3550,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
                outparam = &write_errors[drive];
                break;
        case FDRAWCMD:
-               if (type)
-                       return -EINVAL;
-               if (lock_fdc(drive))
-                       return -EINTR;
-               set_floppy(drive);
-               i = raw_cmd_ioctl(cmd, (void __user *)param);
-               if (i == -EINTR)
-                       return -EINTR;
-               process_fd_request();
-               return i;
+               return floppy_raw_cmd_ioctl(type, drive, cmd, (void __user *)param);
        case FDTWADDLE:
                if (lock_fdc(drive))
                        return -EINTR;