disk: fix sectors count truncation for CHS [fixes #10]

LBA_to_CHS() uses geometry taken from BIOS, but LBA_Transfer()
was using the geometry from VBR. This caused "count" variable
to underflow over unsigned long, then corrupting the entire
DOS memory with the large read.

This patch makes LBA_to_CHS() to return the geometry to caller,
so that the calculus do always match.

Thanks to @ecm-pushbx and @andrewbird for helping to
nail this down.
This commit is contained in:
Stas Sergeev 2017-09-22 20:25:04 +03:00 committed by Kenneth J Davis
parent 5fb0c4482d
commit 8187fd8153

View File

@ -901,7 +901,8 @@ STATIC WORD dskerr(COUNT code)
translate LBA sectors into CHS addressing
*/
STATIC int LBA_to_CHS(ULONG LBA_address, struct CHS *chs, const ddt * pddt)
STATIC int LBA_to_CHS(ULONG LBA_address, struct CHS *chs, const ddt * pddt,
const bpb ** ppbpb)
{
/* we need the defbpb values since those are taken from the
BIOS, not from some random boot sector, except when
@ -926,6 +927,7 @@ STATIC int LBA_to_CHS(ULONG LBA_address, struct CHS *chs, const ddt * pddt)
chs->Cylinder = (UWORD)LBA_address;
chs->Head = hsrem / pbpb->bpb_nsecs;
chs->Sector = hsrem % pbpb->bpb_nsecs + 1;
*ppbpb = pbpb;
return 0;
}
@ -1069,15 +1071,15 @@ STATIC int LBA_Transfer(ddt * pddt, UWORD mode, VOID FAR * buffer,
}
else
{ /* transfer data, using old bios functions */
if (LBA_to_CHS(LBA_address, &chs, pddt))
const bpb *pbpb;
if (LBA_to_CHS(LBA_address, &chs, pddt, &pbpb))
return 1;
/* avoid overflow at end of track */
if (chs.Sector + count > (unsigned)pddt->ddt_bpb.bpb_nsecs + 1)
if (chs.Sector + count > (unsigned)pbpb->bpb_nsecs + 1)
{
count = pddt->ddt_bpb.bpb_nsecs + 1 - chs.Sector;
count = pbpb->bpb_nsecs + 1 - chs.Sector;
}
error_code = (mode == LBA_READ ? fl_read :