Commit 2e90ca68 authored by Linus Torvalds's avatar Linus Torvalds

floppy: check FDC index for errors before assigning it

Jordy Zomer reported a KASAN out-of-bounds read in the floppy driver in
wait_til_ready().

Which on the face of it can't happen, since as Willy Tarreau points out,
the function does no particular memory access.  Except through the FDCS
macro, which just indexes a static allocation through teh current fdc,
which is always checked against N_FDC.

Except the checking happens after we've already assigned the value.

The floppy driver is a disgrace (a lot of it going back to my original
horrd "design"), and has no real maintainer.  Nobody has the hardware,
and nobody really cares.  But it still gets used in virtual environment
because it's one of those things that everybody supports.

The whole thing should be re-written, or at least parts of it should be
seriously cleaned up.  The 'current fdc' index, which is used by the
FDCS macro, and which is often shadowed by a local 'fdc' variable, is a
prime example of how not to write code.

But because nobody has the hardware or the motivation, let's just fix up
the immediate problem with a nasty band-aid: test the fdc index before
actually assigning it to the static 'fdc' variable.
Reported-by: default avatarJordy Zomer <jordy@simplyhacker.com>
Cc: Willy Tarreau <w@1wt.eu>
Cc: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent f8788d86
...@@ -853,14 +853,17 @@ static void reset_fdc_info(int mode) ...@@ -853,14 +853,17 @@ static void reset_fdc_info(int mode)
/* selects the fdc and drive, and enables the fdc's input/dma. */ /* selects the fdc and drive, and enables the fdc's input/dma. */
static void set_fdc(int drive) static void set_fdc(int drive)
{ {
unsigned int new_fdc = fdc;
if (drive >= 0 && drive < N_DRIVE) { if (drive >= 0 && drive < N_DRIVE) {
fdc = FDC(drive); new_fdc = FDC(drive);
current_drive = drive; current_drive = drive;
} }
if (fdc != 1 && fdc != 0) { if (new_fdc >= N_FDC) {
pr_info("bad fdc value\n"); pr_info("bad fdc value\n");
return; return;
} }
fdc = new_fdc;
set_dor(fdc, ~0, 8); set_dor(fdc, ~0, 8);
#if N_FDC > 1 #if N_FDC > 1
set_dor(1 - fdc, ~8, 0); set_dor(1 - fdc, ~8, 0);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment