Hello,
I believe I found a bug in FreeRTOS+FAT, in ff_file.c.
As I understand the logic, FF_Write() writes full sectors using FF_BlockWrite(), and then writes the remaining tail bytes using FF_WritePartial().
However, if FF_BlockWrite() returns an error inside this loop:
while( ulBytesLeft >= ( uint32_t ) pxIOManager->usSectorSize )
the code breaks out of the loop without reducing ulBytesLeft. As a result, execution can continue to the “remaining bytes” path with ulBytesLeft still greater than or equal to the sector size.
That leads to this call:
FF_WritePartial( pxFile, ulItemLBA, 0, ulBytesLeft, pucBuffer, &xError );
In this case, ulBytesLeft may be larger than one sector. Then, inside FF_WritePartial(), the following memcpy() can overflow the sector buffer and cause memory corruption:
memcpy( pxFile->pucBuffer + ulRelBlockPos, pucBuffer, ulCount );
So the issue seems to be that FF_WritePartial() is reached with ulCount >= usSectorSize when FF_BlockWrite() fails.
My expectation is that after a FF_BlockWrite() error, FF_Write() should either:
- return immediately with the error, or
- ensure that FF_WritePartial() is only called when ulBytesLeft is strictly less than one sector.
Relevant code path:
while( ulBytesLeft >= ( uint32_t ) pxIOManager->usSectorSize )
{
ulSectors = ulBytesLeft / pxIOManager->usSectorSize;
{
FF_Partition_t *pPart = &( pxIOManager->xPartition );
uint32_t ulOffset = ( pxFile->ulFilePointer / pxIOManager->usSectorSize ) % pPart->ulSectorsPerCluster;
uint32_t ulRemain = pPart->ulSectorsPerCluster - ulOffset;
if( ulSectors > ulRemain )
{
ulSectors = ulRemain;
}
}
ulItemLBA = FF_SetCluster( pxFile, &xError );
if( FF_isERR( xError ) )
{
break;
}
xError = FF_BlockWrite( pxIOManager, ulItemLBA, ulSectors, pucBuffer, pdFALSE );
if( FF_isERR( xError ) )
{
break;
}
nBytesToWrite = ulSectors * pxIOManager->usSectorSize;
ulBytesLeft -= nBytesToWrite;
pucBuffer += nBytesToWrite;
nBytesWritten += nBytesToWrite;
pxFile->ulFilePointer += nBytesToWrite;
if( pxFile->ulFilePointer > pxFile->ulFileSize )
{
pxFile->ulFileSize = pxFile->ulFilePointer;
}
}
/*---------- Write (memcpy) Remaining Bytes */
if( ulBytesLeft == 0 )
{
break;
}
ulItemLBA = FF_SetCluster( pxFile, &xError );
if( FF_isERR( xError ) )
{
break;
}
FF_WritePartial( pxFile, ulItemLBA, 0, ulBytesLeft, pucBuffer, &xError );
nBytesWritten += ulBytesLeft;
Could you please confirm whether this is a valid bug?
Thank you.