Uploaded image for project: 'Core ReactOS'
  1. Core ReactOS
  2. CORE-15384

Corruption when writing to FAT16 volumes

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Open
    • Priority: Major
    • Resolution: Unresolved
    • Fix Version/s: 0.4.13
    • Component/s: NTCore
    • Labels:

      Description

      Since 0.4.11-dev-210-g2a80ae2, write operations to FAT16 volumes are corrupted.

      This problem can be reproduced in many ways (two are listed below):

      1. During 1st-stage install on a blank disk, create two partitions: the first one of 300MB size (will be formatted in FAT16) and the second one taking the remaining of space (and formatted in FAT32). Install ReactOS on the 2nd partition; the 1st partition will be used as the "system partition" where freeldr will be installed. If then this disk is mounted on e.g. Windows, it will be detected that the FAT16 partition is corrupted, see below. Booting on it will fail.

      2. Use a separate disk with a FAT16 partition inside. From ReactOS, copy some random files in it. When being mounted on e.g. Windows that partition will also be detected as corrupted.

      The following is a stack trace obtained while diagnosing the problem using method 1. , where I have added the attached patch to Cc code (in addition to irrelevant fastfat DPRINTs).

      (base\setup\lib\bootsup.c:1346) Install FAT16 bootcode: \Device\CdRom0\loader\fat.bin ==> \Device\Harddisk0\Partition1\
      (ntoskrnl\cc\copy.c:101) CcReadVirtualAddress(): Vacb size 2048 has been page-rounded up to 4096
      (ntoskrnl\cc\copy.c:147) CcReadVirtualAddress(): Zero-colmating 258048 bytes at the end of the VACB
      (drivers\filesystems\fastfat\cleanup.c:34) VfatCleanupFile(DeviceExt B127C0D0, FileObject B10E2F80)
      (drivers\filesystems\fastfat\close.c:178) VfatCloseFile(DeviceExt B127C0D0, FileObject B10E2F80)
      (drivers\filesystems\fastfat\close.c:28) Ignoring $$Volume$$ in VfatCommonCloseFile()
      (drivers\filesystems\fastfat\misc.c:426) VfatCheckForDismount(B127C0D0, 0)
      (drivers\storage\scsiport\scsiport.c:2894)   unknown ioctl code: 0x24054
      (drivers\storage\scsiport\scsiport.c:2894)   unknown ioctl code: 0x24000
      (drivers\storage\scsiport\scsiport.c:2894)   unknown ioctl code: 0x24038
      (base\setup\lib\bootsup.c:705) Save MBR: \Device\Harddisk0\Partition0 ==> \Device\Harddisk0\Partition1\mbr.old
      (drivers\storage\scsiport\scsiport.c:2894)   unknown ioctl code: 0x24054
      (drivers\storage\scsiport\scsiport.c:2894)   unknown ioctl code: 0x24000
      (drivers\storage\scsiport\scsiport.c:2894)   unknown ioctl code: 0x24038
      (drivers\filesystems\fastfat\dirwr.c:141) updEntry dirIndex 4, PathName '\mbr.old'
      (ntoskrnl\cc\copy.c:147) CcReadVirtualAddress(): Zero-colmating 253952 bytes at the end of the VACB
      (drivers\filesystems\fastfat\cleanup.c:34) VfatCleanupFile(DeviceExt B127C0D0, FileObject B10E2F80)
      (drivers\filesystems\fastfat\dirwr.c:141) updEntry dirIndex 4, PathName '\mbr.old'
      (drivers\filesystems\fastfat\cleanup.c:132) CcUninitializeCacheMap truncating file to 512 bytes
      (drivers\filesystems\fastfat\close.c:178) VfatCloseFile(DeviceExt B127C0D0, FileObject B10E2F80)
      (base\setup\lib\bootsup.c:715) Install MBR bootcode: \Device\CdRom0\loader\dosmbr.bin ==> \Device\Harddisk0\Partition0
      (drivers\storage\scsiport\scsiport.c:2894)   unknown ioctl code: 0x24054
      (drivers\storage\scsiport\scsiport.c:2894)   unknown ioctl code: 0x24000
      (drivers\storage\scsiport\scsiport.c:2894)   unknown ioctl code: 0x24038
      (ntoskrnl\cc\copy.c:101) CcReadVirtualAddress(): Vacb size 2048 has been page-rounded up to 4096
      (ntoskrnl\cc\copy.c:147) CcReadVirtualAddress(): Zero-colmating 258048 bytes at the end of the VACB
      (ntoskrnl\cc\copy.c:178) CcWriteVirtualAddress(): Vacb size 76800 has been page-rounded up to 77824
       
      >---> Here, Vacb->SharedCacheMap->SectionSize.QuadPart - Vacb->FileOffset.QuadPart == LargeSize.QuadPart == 0x12C00 is rounded up to 0x13000 <---<
      >---> This VACB points to the FAT16 FAT table. Writing more than needed is going to erase/corrupt the data that is following...              <---<
       
      Break instruction exception - code 80000003 (first chance)
      nt!DbgUserBreakPoint:
      80548492 cc              int     3
      kd> .reload
      Connected to Windows Server 2003 3790 x86 compatible target at (Mon Nov 26 01:16:22.609 2018 (UTC + 1:00)), ptr64 FALSE
      Loading Kernel Symbols
      ................................
      Loading User Symbols
      ..
      kd> kp
      ChildEBP RetAddr  
      f87e7a44 80404f2e nt!DbgUserBreakPoint
      f87e7ac4 804093a1 nt!CcWriteVirtualAddress(struct _ROS_VACB * Vacb = 0xb1296008)+0x10e [h:\trunk\reactos_setup\ntoskrnl\cc\copy.c @ 181]
      f87e7ad4 80409562 nt!CcRosFlushVacb(struct _ROS_VACB * Vacb = 0xb1296008)+0x21 [h:\trunk\reactos_setup\ntoskrnl\cc\view.c @ 173]
      f87e7b18 80500795 nt!CcRosFlushDirtyPages(unsigned long Target = 0xffffffff, unsigned long * Count = 0xf87e7b3c, unsigned char Wait = 0x00 '', unsigned char CalledFromLazy = 0x00 '')+0x192 [h:\trunk\reactos_setup\ntoskrnl\cc\view.c @ 237]
      f87e7b94 80533e0b nt!NtSetSystemPowerState(POWER_ACTION SystemAction = PowerActionShutdownReset (5), _SYSTEM_POWER_STATE MinSystemState = PowerSystemSleeping3 (4), unsigned long Flags = 0xc0000004)+0x275 [h:\trunk\reactos_setup\ntoskrnl\po\power.c @ 963]
      f87e7bb0 805333fb nt!KiSystemCallTrampoline(void * Handler = 0x80500520, void * Arguments = 0xf87e7c78, unsigned long StackBytes = 0xc)+0x1b [h:\trunk\reactos_setup\ntoskrnl\include\internal\i386\ke.h @ 748]
      f87e7bf8 80403d96 nt!KiSystemServiceHandler(struct _KTRAP_FRAME * TrapFrame = 0xf87e7c00, void * Arguments = 0xf87e7c78)+0x24b [h:\trunk\reactos_setup\ntoskrnl\ke\i386\traphdlr.c @ 1813]
      f87e7bf8 804023a5 nt!KiInterruptTemplateDispatch+0x60
      f87e7c70 805006e1 nt!ZwSetSystemPowerState+0x11
      f87e7ce8 8043fc71 nt!NtSetSystemPowerState(POWER_ACTION SystemAction = PowerActionShutdownReset (5), _SYSTEM_POWER_STATE MinSystemState = PowerSystemSleeping3 (4), unsigned long Flags = 0xc0000004)+0x1c1 [h:\trunk\reactos_setup\ntoskrnl\po\power.c @ 902]
      f87e7d00 80533e0b nt!NtShutdownSystem(_SHUTDOWN_ACTION Action = ShutdownReboot (1))+0x51 [h:\trunk\reactos_setup\ntoskrnl\ex\shutdown.c @ 72]
      f87e7d14 805333fb nt!KiSystemCallTrampoline(void * Handler = 0x8043fc20, void * Arguments = 0x0021ff94, unsigned long StackBytes = 4)+0x1b [h:\trunk\reactos_setup\ntoskrnl\include\internal\i386\ke.h @ 748]
      f87e7d5c 80403e23 nt!KiSystemServiceHandler(struct _KTRAP_FRAME * TrapFrame = 0xf87e7d64, void * Arguments = 0x0021ff94)+0x24b [h:\trunk\reactos_setup\ntoskrnl\ke\i386\traphdlr.c @ 1813]
      f87e7d5c 7c931d1e nt!KiFastCallEntry+0x8c
      0021ff88 7c95fde6 ntdll!KiFastSystemCallRet
      0021ff8c 0040f2b6 ntdll!ZwShutdownSystem+0xc
      0021ffd4 00415fc6 smss!RunUSetup(void)+0x416 [h:\trunk\reactos_setup\base\setup\usetup\usetup.c @ 4699]
      0021fff4 00000000 smss!NtProcessStartup(struct _PEB * Peb = 0x7ffd6000)+0x56 [h:\trunk\reactos_setup\base\setup\usetup\usetup.c @ 4718]
      

      As observed, while flushing we get a cached write of originally 0x12C00 bytes in size, that gets rounded up to 0x13000. I have checked to which data this VACB was pointing to (looking at Vacb->BaseAddress) and it happened it pointed to the contents of the volume's FAT. Obviously, writing more data than needed has the effect of corrupting what is following up on the disk.
      If I manually fix the size back to its original value, no FAT corruption happens.

      Here is an example of CHKDSK output under Windows showing the corruption:

      Volume BOOT a créé 26/11/2018 01:13
      Le numéro de série du volume est 30E4-7F24
      Windows vérifie les fichiers et les dossiers...
      La taille de l'entrée \freeldr.sys est incorrecte.
      \freeldr.ini  La première unité d'allocation n'est pas valide. L'entrée sera tronquée.
      \BOOTSECT.OLD  La première unité d'allocation n'est pas valide. L'entrée sera tronquée.
      \mbr.old  La première unité d'allocation n'est pas valide. L'entrée sera tronquée.
      \$RECYCLE.BIN a une référence croisée dans l'unité d'allocation 2
      Dossier tronqué.
      Vérification des fichiers et des dossiers terminée.
      8192 octets dans 1 fichiers récupérés.
      Windows a effectué des corrections sur le système de fichiers.
       
        314 384 384 octets d'espace disque total.
              8 192 octets dans 1 dossiers.
             16 384 octets dans 2 fichiers.
        314 359 808 octets disponibles sur le disque.
       
              8 192 octets dans chaque unité d'allocation.
             38 377 unités d'allocation au total sur le disque.
             38 374 unités d'allocation disponibles sur le disque.
      

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                Heis Spiter Pierre Schweitzer
                Reporter:
                hbelusca hbelusca
              • Votes:
                3 Vote for this issue
                Watchers:
                6 Start watching this issue

                Dates

                • Created:
                  Updated: