Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
b8a5ece
Add compression detection for TAR files with helpful error messages
iremyux Sep 23, 2025
2135e0e
Merge branch 'main' into 89056-tar-magic-numbers
iremyux Sep 23, 2025
ed092f0
Fox comment
iremyux Sep 23, 2025
3ff4e89
Merge branch '89056-tar-magic-numbers' of https://github.com/iremyux/…
iremyux Sep 23, 2025
904da9d
Check the buffer lenght in local functions
iremyux Oct 6, 2025
ba0501f
Change checks to switch-case
iremyux Oct 6, 2025
4837fe8
Change where we check the magic numbers + do not differentiate betwee…
iremyux Oct 15, 2025
56bfc98
Merge branch 'dotnet:main' into 89056-tar-magic-numbers
iremyux Oct 21, 2025
4703aa2
Remove the check from TryGetNextHeaderAsync method
iremyux Oct 21, 2025
ac4aa8b
Merge branch 'main' into 89056-tar-magic-numbers
iremyux Oct 27, 2025
9b4a528
Change the function's name and remove unreachable throw
iremyux Oct 27, 2025
56b541e
Merge branch '89056-tar-magic-numbers' of https://github.com/iremyux/…
iremyux Oct 27, 2025
26bf6b4
Fix build error
iremyux Oct 27, 2025
28a536e
Use string resources
iremyux Oct 27, 2025
c7b0380
Add compression detection for TAR files with helpful error messages
iremyux Sep 23, 2025
eeaa2cd
Fox comment
iremyux Sep 23, 2025
dd33737
Check the buffer lenght in local functions
iremyux Oct 6, 2025
614de69
Change checks to switch-case
iremyux Oct 6, 2025
26ffa48
Change where we check the magic numbers + do not differentiate betwee…
iremyux Oct 15, 2025
a62bca0
Remove the check from TryGetNextHeaderAsync method
iremyux Oct 21, 2025
5d1de04
Change the function's name and remove unreachable throw
iremyux Oct 27, 2025
2672306
Fix build error
iremyux Oct 27, 2025
c973705
Use string resources
iremyux Oct 27, 2025
6a70987
Merge branch '89056-tar-magic-numbers' of https://github.com/iremyux/…
iremyux Nov 4, 2025
e1ca749
Add compression detection for TAR files with helpful error messages
iremyux Sep 23, 2025
07f5478
Change where we check the magic numbers + do not differentiate betwee…
iremyux Oct 15, 2025
f3eb72c
Remove the check from TryGetNextHeaderAsync method
iremyux Oct 21, 2025
987e5b2
Merge branch '89056-tar-magic-numbers' of https://github.com/iremyux/…
iremyux Nov 4, 2025
25618b0
Change the test assert since we changed the error message
iremyux Nov 10, 2025
e342175
Change the function name + only throw inside the function if we can m…
iremyux Nov 10, 2025
73af2b9
Merge branch 'main' into 89056-tar-magic-numbers
iremyux Nov 10, 2025
87ad6f2
Trailing whitespaces
iremyux Nov 10, 2025
08bb9e8
Wrap documentation comment in <summary> tag
iremyux Nov 10, 2025
dfd5ceb
Remove TarInvalidArchiveFormat from strings
iremyux Nov 10, 2025
9527212
Update src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHea…
iremyux Nov 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/libraries/System.Formats.Tar/src/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@
<value>An attempt was made to move the position before the beginning of the stream.</value>
</data>
<data name="TarInvalidNumber" xml:space="preserve">
<value>Unable to parse number.</value>
<value>The TAR archive is corrupted or invalid.</value>
</data>
<data name="TarInvalidChecksum" xml:space="preserve">
<value>Checksum validation failed. The archive might be corrupted.</value>
Expand All @@ -211,4 +211,7 @@
<data name="ExtHeaderInvalidRecords" xml:space="preserve">
<value>The extended header contains invalid records.</value>
</data>
<data name="TarCompressionArchiveDetected" xml:space="preserve">
<value>The file appears to be a {0} archive. TAR format expected.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,20 @@ private async Task ProcessDataBlockAsync(Stream archiveStream, bool copyData, Ca
{
return null;
}
int checksum = (int)TarHelpers.ParseOctal<uint>(spanChecksum);

int checksum;
try
{
checksum = (int)TarHelpers.ParseOctal<uint>(spanChecksum);
}
catch (InvalidDataException)
{
// Check if this might be a compressed file by looking at the buffer for compression magic numbers
ThrowIfCompressedArchive(buffer);
// If not a compressed file, re-throw the original parsing exception
throw;
}

// Zero checksum means the whole header is empty
if (checksum == 0)
{
Expand Down Expand Up @@ -789,5 +802,83 @@ private static bool TryGetNextExtendedAttribute(
buffer = buffer.Slice(newlinePos + 1);
return true;
}

/// <summary>
/// Analyzes the buffer for known compression format magic numbers and throws an InvalidDataException
/// with a specific error message if a compression format is detected.
/// If no compression format is detected, the method returns without throwing.
/// </summary>
/// <exception cref="InvalidDataException">Thrown if a compression format is detected.</exception>
private static void ThrowIfCompressedArchive(ReadOnlySpan<byte> buffer)
{
if (buffer.Length < 2)
{
return;
}

byte firstByte = buffer[0];
switch (firstByte)
{
case 0x28: // Zstandard
if (buffer.Length >= 4 &&
buffer[1] == 0xB5 && buffer[2] == 0x2F && buffer[3] == 0xFD)
{
throw new InvalidDataException(SR.Format(SR.TarCompressionArchiveDetected, "Zstandard"));
}
break;

case 0x37: // 7-Zip
if (buffer.Length >= 6 &&
buffer[1] == 0x7A && buffer[2] == 0xBC &&
buffer[3] == 0xAF && buffer[4] == 0x27 && buffer[5] == 0x1C)
{
throw new InvalidDataException(SR.Format(SR.TarCompressionArchiveDetected, "7-Zip"));
}
break;

case 0x50: // ZIP files start with "PK"
if (buffer.Length >= 2 && buffer[1] == 0x4B)
{
throw new InvalidDataException(SR.Format(SR.TarCompressionArchiveDetected, "ZIP"));
}
break;

case 0x1F: // GZIP
if (buffer.Length >= 2 && buffer[1] == 0x8B)
{
throw new InvalidDataException(SR.Format(SR.TarCompressionArchiveDetected, "GZIP"));
}
break;

case 0x42: // BZIP2 - "BZh"
if (buffer.Length >= 3 && buffer[1] == 0x5A && buffer[2] == 0x68)
{
throw new InvalidDataException(SR.Format(SR.TarCompressionArchiveDetected, "BZIP2"));
}
break;

case 0xFD: // XZ
if (buffer.Length >= 6 &&
buffer[1] == 0x37 && buffer[2] == 0x7A &&
buffer[3] == 0x58 && buffer[4] == 0x5A && buffer[5] == 0x00)
{
throw new InvalidDataException(SR.Format(SR.TarCompressionArchiveDetected, "XZ"));
}
break;

case 0x78: // ZLIB (deflate compression)
if (buffer.Length >= 2)
{
byte secondByte = buffer[1];
if (secondByte == 0x01 || secondByte == 0x5E || secondByte == 0x9C ||
secondByte == 0xDA || secondByte == 0x20 || secondByte == 0x7D ||
secondByte == 0xBB || secondByte == 0xF9)
{
throw new InvalidDataException(SR.Format(SR.TarCompressionArchiveDetected, "ZLIB"));
}
}
break;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ public void TarReader_InvalidChecksum_ThrowsException(bool corrupted)

if (corrupted)
{
Assert.Contains("parse", exception.Message);
Assert.Contains("corrupted", exception.Message);
}
else
{
Expand Down
Loading