floppy: fix div-by-zero in setup_format_params [Linux 3.16.72]

This Linux kernel change "floppy: fix div-by-zero in setup_format_params" 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:20 2019 +0300. The commit for this change in Linux stable tree is a36b645 (patch) which is from upstream commit f3554ae. 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 f3554ae.

floppy: fix div-by-zero in setup_format_params

commit f3554aeb991214cbfafd17d55e2bfddb50282e32 upstream.

This fixes a divide by zero error in the setup_format_params function of
the floppy driver.

Two consecutive ioctls can trigger the bug: The first one should set the
drive geometry with such .sect and .rate values for the F_SECT_PER_TRACK
to become zero.  Next, the floppy format operation should be called.

A floppy disk is not required to be inserted.  An unprivileged user
could trigger the bug if the device is accessible.

The patch checks F_SECT_PER_TRACK for a non-zero value in the
set_geometry function.  The proper check should involve a reasonable
upper limit for the .sect and .rate fields, but it could change the
UAPI.

The patch also checks F_SECT_PER_TRACK in the setup_format_params, and
cancels the formatting operation in case of zero.

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

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

diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index df51673..5dd5f49 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -2113,6 +2113,9 @@ static void setup_format_params(int track)
    raw_cmd->kernel_data = floppy_track_buffer;
    raw_cmd->length = 4 * F_SECT_PER_TRACK;

+   if (!F_SECT_PER_TRACK)
+       return;
+
    /* allow for about 30ms for data transport per track */
    head_shift = (F_SECT_PER_TRACK + 5) / 6;

@@ -3235,6 +3238,8 @@ static int set_geometry(unsigned int cmd, struct floppy_struct *g,
    /* sanity checking for parameters. */
    if (g->sect <= 0 ||
        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) ||
        /* check if reserved bits are set */
        (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)

Leave a Reply

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