Skip to content

Commit

Permalink
Merge pull request #87 from jerkerolofsson/master
Browse files Browse the repository at this point in the history
Support multiple NoteData within a NoteSegment
  • Loading branch information
konrad-kruczynski authored Apr 11, 2022
2 parents 1cc2331 + b61c3cb commit 1a227f7
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 11 deletions.
48 changes: 41 additions & 7 deletions ELFSharp/ELF/Sections/NoteData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,38 @@
using ELFSharp;
using System.Text;
using ELFSharp.Utilities;
using ELFSharp.ELF.Segments;
using System.Collections.ObjectModel;

namespace ELFSharp.ELF.Sections
{
internal class NoteData
public class NoteData : INoteData
{
internal string Name { get; private set; }
public const ulong NoteDataHeaderSize = 12; // name size + description size + field

internal byte[] Description { get; private set; }
public string Name { get; private set; }

public ReadOnlyCollection<byte> Description
{
get
{
return new ReadOnlyCollection<byte>(DescriptionBytes);
}
}

internal byte[] DescriptionBytes { get; private set; }

public ulong Type { get; private set; }

internal ulong NoteOffset { get; private set; }
internal ulong NoteFileSize { get; private set; }
internal ulong NoteFileEnd { get { return NoteOffset + NoteFileSize; } }

public override string ToString()
{
return $"Name={Name} DataSize=0x{DescriptionBytes.Length.ToString("x8")}";
}

internal ulong Type { get; private set; }

internal NoteData(ulong sectionOffset, ulong sectionSize, SimpleEndianessAwareReader reader)
{
this.reader = reader;
Expand All @@ -26,6 +47,9 @@ internal NoteData(ulong sectionOffset, ulong sectionSize, SimpleEndianessAwareRe
var fields = Math.DivRem(nameSize, FieldSize, out remainder);
var alignedNameSize = FieldSize * (remainder > 0 ? fields + 1 : fields);

fields = Math.DivRem(descriptionSize, FieldSize, out remainder);
var alignedDescriptionSize = FieldSize * (remainder > 0 ? fields + 1 : fields);

// We encountered binaries where nameSize and descriptionSize are
// invalid (i.e. significantly larger than the size of the binary itself).
// To avoid throwing on such binaries, we only read in name and description
Expand All @@ -39,11 +63,21 @@ internal NoteData(ulong sectionOffset, ulong sectionSize, SimpleEndianessAwareRe
}
if (reader.BaseStream.Position + descriptionSize <= sectionEnd)
{
Description = descriptionSize > 0 ? reader.ReadBytes(descriptionSize) : new byte[0];
DescriptionBytes = descriptionSize > 0 ? reader.ReadBytes(descriptionSize) : new byte[0];
}
}

// If there are multiple notes inside one segment, keep track of the end position so we can read them
// all when parsing the segment
NoteOffset = sectionOffset;
NoteFileSize = (ulong)alignedNameSize + (ulong)alignedDescriptionSize + NoteDataHeaderSize;
}


public Stream ToStream()
{
return new MemoryStream(DescriptionBytes);
}

private int ReadSize()
{
/*
Expand Down
2 changes: 1 addition & 1 deletion ELFSharp/ELF/Sections/NoteSection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public byte[] Description
{
get
{
return data.Description;
return data.DescriptionBytes;
}
}

Expand Down
32 changes: 32 additions & 0 deletions ELFSharp/ELF/Segments/INoteData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System.Collections.ObjectModel;
using System.IO;

namespace ELFSharp.ELF.Segments
{
public interface INoteData
{
/// <summary>
/// Owner of the note.
/// </summary>
string Name { get; }

/// <summary>
/// Data contents of the note. The format of this depends on the combination of the Name and Type properties and often
/// corresponds to a struct.
///
/// For example, see elf.h in the Linux kernel source tree.
/// </summary>
ReadOnlyCollection<byte> Description { get; }

/// <summary>
/// Data type
/// </summary>
ulong Type { get; }

/// <summary>
/// Returns the Description byte[] as a Stream
/// </summary>
/// <returns></returns>
Stream ToStream();
}
}
7 changes: 7 additions & 0 deletions ELFSharp/ELF/Segments/INoteSegment.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
using System;
using System.Collections.Generic;

namespace ELFSharp.ELF.Segments
{
public interface INoteSegment : ISegment
{
string NoteName { get; }
ulong NoteType { get; }
byte[] NoteDescription { get; }

/// <summary>
/// Returns all notes within the segment
/// </summary>
IReadOnlyList<INoteData> Notes { get; }
}
}
40 changes: 38 additions & 2 deletions ELFSharp/ELF/Segments/NoteSegment.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,58 @@
using System;
using System.Collections.Generic;
using ELFSharp.ELF.Sections;
using ELFSharp.Utilities;

namespace ELFSharp.ELF.Segments
{
public sealed class NoteSegment<T> : Segment<T>, INoteSegment
{

internal NoteSegment(long headerOffset, Class elfClass, SimpleEndianessAwareReader reader)
: base(headerOffset, elfClass, reader)
{
data = new NoteData((ulong)base.Offset, (ulong)base.FileSize, reader);
ulong offset = (ulong)base.Offset;
ulong fileSize = (ulong)base.FileSize;
ulong remainingSize = fileSize;

// Keep the first NoteData as a property for backwards compatibility
data = new NoteData(offset, remainingSize, reader);
notes.Add(data);

offset += data.NoteFileSize;

// Read all additional notes within the segment
// Multiple notes are common in ELF core files
if (data.NoteFileSize < remainingSize)
{
remainingSize -= data.NoteFileSize;

while (remainingSize > NoteData.NoteDataHeaderSize)
{
var note = new NoteData(offset, remainingSize, reader);
notes.Add(note);
offset += note.NoteFileSize;
if (note.NoteFileSize <= remainingSize)
{
remainingSize -= note.NoteFileSize;
}
else
{
// File is damaged
throw new IndexOutOfRangeException("NoteSegment internal note-data is out of bounds");
}
}
}
}

public string NoteName => data.Name;

public ulong NoteType => data.Type;

public byte[] NoteDescription => data.Description;
public byte[] NoteDescription => data.DescriptionBytes;
public IReadOnlyList<INoteData> Notes { get => notes.AsReadOnly(); }

private List<NoteData> notes = new List<NoteData>();

private readonly NoteData data;
}
Expand Down
2 changes: 1 addition & 1 deletion Tests/Binaries
28 changes: 28 additions & 0 deletions Tests/ELF/NoteSectionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using ELFSharp.ELF.Sections;
using ELFSharp.ELF;
using System.Linq;
using ELFSharp.ELF.Segments;

namespace Tests.ELF
{
Expand Down Expand Up @@ -52,6 +53,33 @@ public void ShouldNotThrowOnCustomNote()
var noteSection = (NoteSection<uint>)elf.GetSection(sectionName);
Assert.AreEqual(sectionName, noteSection.Name);
}


[Test]
public void ShouldReadMultipleNotesWithinNoteSection()
{
using var elf = ELFReader.Load(Utilities.GetBinaryStream("elf32-core-adbd_3124"), true);
var noteSegment = elf.Segments.Where(x => x.Type == SegmentType.Note).First() as INoteSegment;
Assert.AreEqual(22, noteSegment.Notes.Count);
}

[Test]
public void ShouldReadMultipleNoteDataName()
{
using var elf = ELFReader.Load(Utilities.GetBinaryStream("elf32-core-adbd_3124"), true);
var noteSegment = elf.Segments.Where(x => x.Type == SegmentType.Note).First() as INoteSegment;
Assert.AreEqual("CORE", noteSegment.Notes[0].Name);
Assert.AreEqual("LINUX", noteSegment.Notes[6].Name);
}

[Test]
public void ShouldReadMultipleNoteDataType()
{
using var elf = ELFReader.Load(Utilities.GetBinaryStream("elf32-core-adbd_3124"), true);
var noteSegment = elf.Segments.Where(x => x.Type == SegmentType.Note).First() as INoteSegment;
Assert.AreEqual(1ul, noteSegment.Notes[0].Type);
Assert.AreEqual(1024ul, noteSegment.Notes[6].Type);
}
}
}

0 comments on commit 1a227f7

Please sign in to comment.