CVE-2022-33981: Use After Free (CWE-416)
value: drivers/block/floppy.c in the Linux kernel before 5.17.6 is vulnerable to a denial of service, because of a concurrency use-after-free flaw after deallocating raw_cmd in the raw_cmd_ioctl function.
CWE description: The product reuses or references memory after it has been freed. At some point afterward, the memory may be allocated again and saved in another pointer, while the original pointer references a location somewhere within the new allocation. Any operations using the original pointer are no longer valid because the memory "belongs" to the code that operates on the new pointer.
CVSS v3 base score: 3.3
Published: 2022-06-18T16:15Z
Repository: https://github.com/torvalds/linux
Language: Other
Files changed: drivers/block/Kconfig, drivers/block/floppy.c
Commit date: 2022-04-27 09:41:54 -0700
Commit message: floppy: disable FDRAWCMD by default

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>

Diff: diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 519b6d38d4df..fdb81f2794cd 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -31,10 +31,26 @@ config BLK_DEV_FD
 	  parameters of the driver at run time.
 
 	  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
 
 config ATARI_FLOPPY
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 8c647532e3ce..d5b9ff9bcbb2 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -2980,10 +2980,12 @@ static const char *drive_name(int type, int drive)
 		return floppy->name;
 	else
 		return "(null)";
 }
 
+#ifdef CONFIG_BLK_DEV_FD_RAWCMD
+
 /* raw commands */
 static void raw_cmd_done(int flag)
 {
 	if (!flag) {
 		raw_cmd->flags |= FD_RAW_FAILURE;
@@ -3179,10 +3181,39 @@ static int raw_cmd_ioctl(int cmd, void __user *param)
 		ret = ret2;
 	raw_cmd_free(&my_raw_cmd);
 	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 */
 	set_bit((long)bdev->bd_disk->private_data, &fake_change);
 	process_fd_request();
@@ -3367,11 +3398,10 @@ static bool valid_floppy_drive_params(const short autodetect[FD_AUTODETECT_SIZE]
 static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
 		    unsigned long param)
 {
 	int drive = (long)bdev->bd_disk->private_data;
 	int type = ITYPE(drive_state[drive].fd_device);
-	int i;
 	int ret;
 	int size;
 	union inparam {
 		struct floppy_struct g;	/* geometry */
 		struct format_descr f;
@@ -3518,20 +3548,11 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
 		return 0;
 	case FDWERRORGET:
 		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;
 		twaddle(current_fdc, current_drive);
 		process_fd_request();

Vulnerable code: 	int i;
		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;
Fixed code: 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.

#ifdef CONFIG_BLK_DEV_FD_RAWCMD

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

		return floppy_raw_cmd_ioctl(type, drive, cmd, (void __user *)param);