Skip to content

Commit

Permalink
Fix read data out of boundary cause System.AccessViolationException (#…
Browse files Browse the repository at this point in the history
…470)

* Fix read data out of boundary cause System.AccessViolationException

* Add in history

* fix load error for special gcc machine type

* Update src/ReleaseHistory.md

Co-authored-by: Eddy Nakamura <eddynaka@gmail.com>
  • Loading branch information
shaopeng-gh and eddynaka authored Aug 31, 2021
1 parent c4a2a4b commit c5aeee5
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 104 deletions.
6 changes: 6 additions & 0 deletions src/BinaryParsers/ElfBinary/Dwarf/DwarfLineNumberProgram.cs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,12 @@ private static List<DwarfFileInformation> ReadData(DwarfMemoryReader debugLine,
// Read header
ulong length = debugLine.ReadLength(out bool is64bit);
int endPosition = debugLine.Position + (int)length;

if (endPosition > debugLine.Data.Length - 1)
{
endPosition = debugLine.Data.Length - 1;
}

debugLine.ReadUshort(); // version
debugLine.ReadOffset(is64bit); // headerLength
byte minimumInstructionLength = debugLine.ReadByte();
Expand Down
20 changes: 20 additions & 0 deletions src/BinaryParsers/ElfBinary/Dwarf/DwarfMemoryReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,11 @@ public byte[] ReadBlock(uint size)
/// <param name="position">The position.</param>
public byte[] ReadBlock(uint size, int position)
{
if (position >= Data.Length)
{
return Array.Empty<byte>();
}

int originalPosition = Position;
Position = position;
byte[] result = ReadBlock(size);
Expand All @@ -262,6 +267,11 @@ public byte[] ReadBlock(uint size, int position)
/// <param name="position">The position.</param>
public string ReadString(int position)
{
if (position >= Data.Length)
{
return string.Empty;
}

int originalPosition = Position;
Position = position;
string result = ReadString();
Expand All @@ -275,6 +285,11 @@ public string ReadString(int position)
/// <param name="position">The position.</param>
public uint ReadUint(int position)
{
if (position >= Data.Length)
{
return 0;
}

int originalPosition = Position;
Position = position;
uint result = ReadUint();
Expand All @@ -289,6 +304,11 @@ public uint ReadUint(int position)
/// <param name="position">The position.</param>
public T ReadStructure<T>(int position)
{
if (position >= Data.Length)
{
return default;
}

int originalPosition = Position;
Position = position;
T result = ReadStructure<T>();
Expand Down
1 change: 1 addition & 0 deletions src/ReleaseHistory.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Unreleased

* BUGFIX: Fix exception `System.AccessViolationException` caused by trying to read data out of boundary. [#470](https://github.com/microsoft/binskim/pull/470)
* BUGFIX: Fix exception handling when PDB cannot be loaded by `IDiaDataSource`. [#461](https://github.com/microsoft/binskim/pull/461)
* BREAKING: PDB exceptions will be reported once per target. [#465](https://github.com/microsoft/binskim/pull/465)

Expand Down
230 changes: 126 additions & 104 deletions src/Test.UnitTests.BinaryParsers/Elf/ElfBinaryTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,112 +29,25 @@ internal static string GetTestDirectory(string relativeDirectory)
}

[Fact]
public void ValidateDwarfV4_WithO2()
{
// Hello.c compiled using: gcc -Wall -O2 -g -gdwarf-4 hello.c -o hello4
string fileName = Path.Combine(TestData, "Dwarf/hello-dwarf4-o2");
using var binary = new ElfBinary(new Uri(fileName));
binary.DwarfVersion.Should().Be(4);
binary.CommandLineInfos.Should().OnlyContain(x => x.CommandLine.Contains("O2"));
binary.GetLanguage().Should().Be(DwarfLanguage.C99);
}

[Fact]
public void ValidateDwarfV5_WithO2()
{
// Hello.c compiled using: gcc -Wall -O2 -g -gdwarf-5 hello.c -o hello5
string fileName = Path.Combine(TestData, "Dwarf/hello-dwarf5-o2");
using var binary = new ElfBinary(new Uri(fileName));
binary.DwarfVersion.Should().Be(5);
binary.CommandLineInfos.Should().OnlyContain(x => x.CommandLine.Contains("O2"));
binary.GetLanguage().Should().Be(DwarfLanguage.C11);
}

[Fact]
public void ValidateDwarfV4_WithO2_Split_DebugFileExists()
{
// dwotest.cpp compiled using: gcc -Wall -O2 -g -gdwarf-4 dwotest.cpp -gsplit-dwarf -o dwotest.gcc.4.o
string fileName = Path.Combine(TestData, "Dwarf/DwarfSplitV4/dwotest.gcc.4.o");
using var binary = new ElfBinary(new Uri(fileName));
binary.DwarfVersion.Should().Be(4);
binary.GetLanguage().Should().Be(DwarfLanguage.CPlusPlus);
}

[Fact]
public void ValidateDwarfV5_WithO2_Split_DebugFileExists()
{
// dwotest.cpp compiled using: gcc -Wall -O2 -g -gdwarf-5 dwotest.cpp -gsplit-dwarf -o dwotest.gcc.5.o
string fileName = Path.Combine(TestData, "Dwarf/DwarfSplitV5/dwotest.gcc.5.o");
using var binary = new ElfBinary(new Uri(fileName));
binary.DwarfVersion.Should().Be(5);
binary.GetLanguage().Should().Be(DwarfLanguage.CPlusPlus14);
}

[Fact]
public void ValidateDwarfV4_WithO2_Split_DebugFileMissing()
{
// dwotest.cpp compiled using: gcc -Wall -O2 -g -gdwarf-4 dwotest.cpp -gsplit-dwarf -o dwotest.gcc.4.o
string fileName = Path.Combine(TestData, "Dwarf/DwarfSplitV4DebugFileMissing/dwotest.gcc.4.o");
using var binary = new ElfBinary(new Uri(fileName));
binary.DwarfVersion.Should().Be(4);
binary.GetLanguage().Should().Be(DwarfLanguage.Unknown); //missing dwo file should not cause exception
}

[Fact]
public void ValidateDwarfV5_WithO2_Split_DebugFileMissing()
{
// dwotest.cpp compiled using: gcc -Wall -O2 -g -gdwarf-5 dwotest.cpp -gsplit-dwarf -o dwotest.gcc.5.o
string fileName = Path.Combine(TestData, "Dwarf/DwarfSplitV5DebugFileMissing/dwotest.gcc.5.o");
using var binary = new ElfBinary(new Uri(fileName));
binary.DwarfVersion.Should().Be(5);
binary.GetLanguage().Should().Be(DwarfLanguage.Unknown); //missing dwo file should not cause exception
}

[Fact]
public void ValidateDwarfV4_WithO2_Split_DebugFileInAnotherDirectory()
{
// dwotest.cpp compiled using: gcc -Wall -O2 -g -gdwarf-4 dwotest.cpp -gsplit-dwarf -o dwotest.gcc.4.o
string fileName = Path.Combine(TestData,
"Dwarf/DwarfSplitV4DebugFileInAnotherDirectory/BinaryDirectory/dwotest.gcc.4.o");

// test for: when not pass in directories
using var binaryWithoutPathList = new ElfBinary(new Uri(fileName));
binaryWithoutPathList.GetLanguage().Should().Be(DwarfLanguage.Unknown);

// test for: when able to find in any of the pass in directories
string localSymbolDirectory1 = Path.Combine(TestData,
"Dwarf/DwarfSplitV4DebugFileInAnotherDirectory/NotExists");
string localSymbolDirectory2 = Path.Combine(TestData,
"WithoutDwoFiles");
string localSymbolDirectory3 = Path.Combine(TestData,
"Dwarf/DwarfSplitV4DebugFileInAnotherDirectory/AnotherLocalSymbolDirectory");
var pathListFound = new List<string>() { localSymbolDirectory1, localSymbolDirectory2, localSymbolDirectory3 };
using var binaryFound = new ElfBinary(new Uri(fileName), string.Join(';', pathListFound));
binaryFound.DwarfVersion.Should().Be(4);
binaryFound.GetLanguage().Should().Be(DwarfLanguage.CPlusPlus);

// test for: when not able to find in any of the pass in directories, also not able to find in same directory
var pathListNotFound = new List<string>() { localSymbolDirectory1, localSymbolDirectory2 };
using var binaryNotFound = new ElfBinary(new Uri(fileName), string.Join(';', pathListNotFound));
binaryNotFound.GetLanguage().Should().Be(DwarfLanguage.Unknown);
}

[Fact]
public void ValidateDwarfV4_WithO2_Split_DebugFileInSameDirectory()
public void Validate_MachineType()
{
// dwotest.cpp compiled using: gcc -Wall -O2 -g -gdwarf-4 dwotest.cpp -gsplit-dwarf -o dwotest.gcc.4.o
string fileName = Path.Combine(TestData,
"Dwarf/DwarfSplitV4/dwotest.gcc.4.o");
// test for: build with aarch64, should load without error
// compiled using:
// aarch64-linux-gnu-gcc-8 tls.c -c -o gcc.tls.aarch64-linux-gnu-gcc-8.o -mlittle-endian
// -mabi=lp64 -g -O2 -std=gnu11 -fgnu89-inline -feliminate-unused-debug-types
// -fmerge-all-constants -fno-stack-protector -frounding-math -fno-math-errno -ftls-model=initial-exec
string fileName = Path.Combine(TestData, "Dwarf/MachineType/gcc.tls.aarch64-linux-gnu-gcc-8.o");
using var binaryAarch64 = new ElfBinary(new Uri(fileName));
binaryAarch64.ELF.Machine.Should().Be(ELFSharp.ELF.Machine.AArch64);

// test for: when not able to find in any of the pass in directories, should try load in same directory
string localSymbolDirectory1 = Path.Combine(TestData,
"Dwarf/DwarfSplitV4DebugFileInAnotherDirectory/NotExists");
string localSymbolDirectory2 = Path.Combine(TestData,
"WithoutDwoFiles");
var pathList = new List<string>() { localSymbolDirectory1, localSymbolDirectory2 };
using var binary = new ElfBinary(new Uri(fileName), string.Join(';', pathList));
binary.DwarfVersion.Should().Be(4);
binary.GetLanguage().Should().Be(DwarfLanguage.CPlusPlus);
// test for: build with mips, should load without error
// compiled using:
// mips-linux-gnu-gcc-9 tls.c -c -o gcc.tls.mips-linux-gnu-gcc-9.o
// -mabi=64 -g -O2 -std=gnu11 -fgnu89-inline -feliminate-unused-debug-types
// -fmerge-all-constants -fno-stack-protector -frounding-math -fno-math-errno -ftls-model=initial-exec
fileName = Path.Combine(TestData, "Dwarf/MachineType/gcc.tls.mips-linux-gnu-gcc-9.o");
using var binaryMips = new ElfBinary(new Uri(fileName));
binaryMips.ELF.Machine.Should().Be(ELFSharp.ELF.Machine.MIPS);
}

[Fact]
Expand Down Expand Up @@ -248,5 +161,114 @@ public void Validate_DebugFileType()
binaryDebugOnlyFileDwo.DebugFileType.Should().Be(DebugFileType.DebugOnlyFileDwo);
binaryDebugOnlyFileDwo.DebugFileLoaded.Should().Be(false);
}

[Fact]
public void ValidateDwarfV4_WithO2()
{
// Hello.c compiled using: gcc -Wall -O2 -g -gdwarf-4 hello.c -o hello4
string fileName = Path.Combine(TestData, "Dwarf/hello-dwarf4-o2");
using var binary = new ElfBinary(new Uri(fileName));
binary.DwarfVersion.Should().Be(4);
binary.CommandLineInfos.Should().OnlyContain(x => x.CommandLine.Contains("O2"));
binary.GetLanguage().Should().Be(DwarfLanguage.C99);
}

[Fact]
public void ValidateDwarfV5_WithO2()
{
// Hello.c compiled using: gcc -Wall -O2 -g -gdwarf-5 hello.c -o hello5
string fileName = Path.Combine(TestData, "Dwarf/hello-dwarf5-o2");
using var binary = new ElfBinary(new Uri(fileName));
binary.DwarfVersion.Should().Be(5);
binary.CommandLineInfos.Should().OnlyContain(x => x.CommandLine.Contains("O2"));
binary.GetLanguage().Should().Be(DwarfLanguage.C11);
}

[Fact]
public void ValidateDwarfV4_WithO2_Split_DebugFileExists()
{
// dwotest.cpp compiled using: gcc -Wall -O2 -g -gdwarf-4 dwotest.cpp -gsplit-dwarf -o dwotest.gcc.4.o
string fileName = Path.Combine(TestData, "Dwarf/DwarfSplitV4/dwotest.gcc.4.o");
using var binary = new ElfBinary(new Uri(fileName));
binary.DwarfVersion.Should().Be(4);
binary.GetLanguage().Should().Be(DwarfLanguage.CPlusPlus);
}

[Fact]
public void ValidateDwarfV5_WithO2_Split_DebugFileExists()
{
// dwotest.cpp compiled using: gcc -Wall -O2 -g -gdwarf-5 dwotest.cpp -gsplit-dwarf -o dwotest.gcc.5.o
string fileName = Path.Combine(TestData, "Dwarf/DwarfSplitV5/dwotest.gcc.5.o");
using var binary = new ElfBinary(new Uri(fileName));
binary.DwarfVersion.Should().Be(5);
binary.GetLanguage().Should().Be(DwarfLanguage.CPlusPlus14);
}

[Fact]
public void ValidateDwarfV4_WithO2_Split_DebugFileMissing()
{
// dwotest.cpp compiled using: gcc -Wall -O2 -g -gdwarf-4 dwotest.cpp -gsplit-dwarf -o dwotest.gcc.4.o
string fileName = Path.Combine(TestData, "Dwarf/DwarfSplitV4DebugFileMissing/dwotest.gcc.4.o");
using var binary = new ElfBinary(new Uri(fileName));
binary.DwarfVersion.Should().Be(4);
binary.GetLanguage().Should().Be(DwarfLanguage.Unknown); //missing dwo file should not cause exception
}

[Fact]
public void ValidateDwarfV5_WithO2_Split_DebugFileMissing()
{
// dwotest.cpp compiled using: gcc -Wall -O2 -g -gdwarf-5 dwotest.cpp -gsplit-dwarf -o dwotest.gcc.5.o
string fileName = Path.Combine(TestData, "Dwarf/DwarfSplitV5DebugFileMissing/dwotest.gcc.5.o");
using var binary = new ElfBinary(new Uri(fileName));
binary.DwarfVersion.Should().Be(5);
binary.GetLanguage().Should().Be(DwarfLanguage.Unknown); //missing dwo file should not cause exception
}

[Fact]
public void ValidateDwarfV4_WithO2_Split_DebugFileInSameDirectory()
{
// dwotest.cpp compiled using: gcc -Wall -O2 -g -gdwarf-4 dwotest.cpp -gsplit-dwarf -o dwotest.gcc.4.o
string fileName = Path.Combine(TestData,
"Dwarf/DwarfSplitV4/dwotest.gcc.4.o");

// test for: when not able to find in any of the pass in directories, should try load in same directory
string localSymbolDirectory1 = Path.Combine(TestData,
"Dwarf/DwarfSplitV4DebugFileInAnotherDirectory/NotExists");
string localSymbolDirectory2 = Path.Combine(TestData,
"WithoutDwoFiles");
var pathList = new List<string>() { localSymbolDirectory1, localSymbolDirectory2 };
using var binary = new ElfBinary(new Uri(fileName), string.Join(';', pathList));
binary.DwarfVersion.Should().Be(4);
binary.GetLanguage().Should().Be(DwarfLanguage.CPlusPlus);
}

[Fact]
public void ValidateDwarfV4_WithO2_Split_DebugFileInAnotherDirectory()
{
// dwotest.cpp compiled using: gcc -Wall -O2 -g -gdwarf-4 dwotest.cpp -gsplit-dwarf -o dwotest.gcc.4.o
string fileName = Path.Combine(TestData,
"Dwarf/DwarfSplitV4DebugFileInAnotherDirectory/BinaryDirectory/dwotest.gcc.4.o");

// test for: when not pass in directories
using var binaryWithoutPathList = new ElfBinary(new Uri(fileName));
binaryWithoutPathList.GetLanguage().Should().Be(DwarfLanguage.Unknown);

// test for: when able to find in any of the pass in directories
string localSymbolDirectory1 = Path.Combine(TestData,
"Dwarf/DwarfSplitV4DebugFileInAnotherDirectory/NotExists");
string localSymbolDirectory2 = Path.Combine(TestData,
"WithoutDwoFiles");
string localSymbolDirectory3 = Path.Combine(TestData,
"Dwarf/DwarfSplitV4DebugFileInAnotherDirectory/AnotherLocalSymbolDirectory");
var pathListFound = new List<string>() { localSymbolDirectory1, localSymbolDirectory2, localSymbolDirectory3 };
using var binaryFound = new ElfBinary(new Uri(fileName), string.Join(';', pathListFound));
binaryFound.DwarfVersion.Should().Be(4);
binaryFound.GetLanguage().Should().Be(DwarfLanguage.CPlusPlus);

// test for: when not able to find in any of the pass in directories, also not able to find in same directory
var pathListNotFound = new List<string>() { localSymbolDirectory1, localSymbolDirectory2 };
using var binaryNotFound = new ElfBinary(new Uri(fileName), string.Join(';', pathListNotFound));
binaryNotFound.GetLanguage().Should().Be(DwarfLanguage.Unknown);
}
}
}
Binary file not shown.
Binary file not shown.

0 comments on commit c5aeee5

Please sign in to comment.