floppy: fix out-of-bounds read in next_valid_format [Linux 3.16.72]

This Linux kernel change "floppy: fix out-of-bounds read in next_valid_format" is included in the Linux 3.16.72 release. This change is authored by Denis Efremov <efremov [at] ispras.ru> on Fri Jul 12 21:55:21 2019 +0300. The commit for this change in Linux stable tree is 59fbdf8 (patch) which is from upstream commit 5635f89. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream 5635f89.

floppy: fix out-of-bounds read in next_valid_format

commit 5635f897ed83fd539df78e98ba69ee91592f9bb8 upstream.

This fixes a global out-of-bounds read access in the next_valid_format
function of the floppy driver.

The values from autodetect field of the struct floppy_drive_params are
used as indices for the floppy_type array in the next_valid_format
function 'floppy_type[DP->autodetect[probed_format]].sect'.

To trigger the bug, one could use a value out of range and set the drive
parameters with the FDSETDRVPRM ioctl.  A floppy disk is not required to
be inserted.

CAP_SYS_ADMIN is required to call FDSETDRVPRM.

The patch adds the check for values of the autodetect field to be in the
'0 <= x < ARRAY_SIZE(floppy_type)' range of the floppy_type array indices.

The bug was found by syzkaller.

Signed-off-by: Denis Efremov <[email protected]>
Tested-by: Willy Tarreau <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
[bwh: Backported to 3.16: Drop changes in compat_setdrvprm(), as compat
 ioctls go via fd_ioctl_locked() after translation in compat_ioctl.c.]
Signed-off-by: Ben Hutchings <[email protected]>

There are 16 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 drivers/block/floppy.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 5dd5f49..7345154 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -3383,6 +3383,20 @@ static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
    return 0;
 }

+static bool valid_floppy_drive_params(const short autodetect[8])
+{
+   size_t floppy_type_size = ARRAY_SIZE(floppy_type);
+   size_t i = 0;
+
+   for (i = 0; i < 8; ++i) {
+       if (autodetect[i] < 0 ||
+           autodetect[i] >= floppy_type_size)
+           return false;
+   }
+
+   return true;
+}
+
 static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
            unsigned long param)
 {
@@ -3509,6 +3523,8 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
        SUPBOUND(size, strlen((const char *)outparam) + 1);
        break;
    case FDSETDRVPRM:
+       if (!valid_floppy_drive_params(inparam.dp.autodetect))
+           return -EINVAL;
        *UDP = inparam.dp;
        break;
    case FDGETDRVPRM:

Leave a Reply

Your email address will not be published. Required fields are marked *