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)