floppy: fix invalid pointer dereference in drive_name [Linux 4.9.187]

This Linux kernel change "floppy: fix invalid pointer dereference in drive_name" is included in the Linux 4.9.187 release. This change is authored by Denis Efremov <efremov [at] ispras.ru> on Fri Jul 12 21:55:22 2019 +0300. The commit for this change in Linux stable tree is 5d6d639 (patch) which is from upstream commit 9b04609. 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 9b04609.

floppy: fix invalid pointer dereference in drive_name

[ Upstream commit 9b04609b784027968348796a18f601aed9db3789 ]

This fixes the invalid pointer dereference in the drive_name function of
the floppy driver.

The native_format field of the struct floppy_drive_params is used as
floppy_type array index in the drive_name function.  Thus, the field
should be checked the same way as the autodetect field.

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

CAP_SYS_ADMIN is required to call FDSETDRVPRM.

The patch adds the check for a value of the native_format 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 <efremov@ispras.ru>
Tested-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

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

 drivers/block/floppy.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 945f93d..d651e43 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -3384,7 +3384,8 @@ static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
    return 0;
 }

-static bool valid_floppy_drive_params(const short autodetect[8])
+static bool valid_floppy_drive_params(const short autodetect[8],
+       int native_format)
 {
    size_t floppy_type_size = ARRAY_SIZE(floppy_type);
    size_t i = 0;
@@ -3395,6 +3396,9 @@ static bool valid_floppy_drive_params(const short autodetect[8])
            return false;
    }

+   if (native_format < 0 || native_format >= floppy_type_size)
+       return false;
+
    return true;
 }

@@ -3524,7 +3528,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))
+       if (!valid_floppy_drive_params(inparam.dp.autodetect,
+               inparam.dp.native_format))
            return -EINVAL;
        *UDP = inparam.dp;
        break;
@@ -3723,7 +3728,7 @@ static int compat_setdrvprm(int drive,
        return -EPERM;
    if (copy_from_user(&v, arg, sizeof(struct compat_floppy_drive_params)))
        return -EFAULT;
-   if (!valid_floppy_drive_params(v.autodetect))
+   if (!valid_floppy_drive_params(v.autodetect, v.native_format))
        return -EINVAL;
    mutex_lock(&floppy_mutex);
    UDP->cmos = v.cmos;

Leave a Reply

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