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

This Linux kernel change "floppy: fix out-of-bounds read in copy_buffer" 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:23 2019 +0300. The commit for this change in Linux stable tree is 0542998 (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

commit da99466ac243f15fbba65bd261bfc75ffa1532b6 upstream.

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 <[email protected]>
Tested-by: Willy Tarreau <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
Signed-off-by: Ben Hutchings <[email protected]>

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 2d6087b..3999b8c 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -3236,8 +3236,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 *