floppy: fix out-of-bounds read in copy_buffer [Linux 4.9.187]

This Linux kernel change "floppy: fix out-of-bounds read in copy_buffer" 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:23 2019 +0300. The commit for this change in Linux stable tree is 1fdefbb (patch) which is from upstream commit da99466. 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 da99466.

floppy: fix out-of-bounds read in copy_buffer

[ Upstream commit da99466ac243f15fbba65bd261bfc75ffa1532b6 ]

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

The FDDEFPRM ioctl allows one to set the geometry of a disk.  The sect
and head fields (unsigned int) of the floppy_drive structure are used to
compute the max_sector (int) in the make_raw_rw_request function.  It is
possible to overflow the max_sector.  Next, max_sector is passed to the
copy_buffer function and used in one of the memcpy calls.

An unprivileged user could trigger the bug if the device is accessible,
but requires a floppy disk to be inserted.

The patch adds the check for the .sect * .head multiplication for not
overflowing in the set_geometry function.

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 6 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 drivers/block/floppy.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index d651e43..6930abe 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -3237,8 +3237,10 @@ static int set_geometry(unsigned int cmd, struct floppy_struct *g,
    int cnt;

    /* sanity checking for parameters. */
-   if (g->sect <= 0 ||
-       g->head <= 0 ||
+   if ((int)g->sect <= 0 ||
+       (int)g->head <= 0 ||
+       /* check for overflow in max_sector */
+       (int)(g->sect * g->head) <= 0 ||
        /* check for zero in F_SECT_PER_TRACK */
        (unsigned char)((g->sect << 2) >> FD_SIZECODE(g)) == 0 ||
        g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||

Leave a Reply

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