Skip to content

Commit

Permalink
Resolve #1026
Browse files Browse the repository at this point in the history
  • Loading branch information
romainthomas committed Jul 20, 2024
1 parent 3d44a66 commit 27d406b
Show file tree
Hide file tree
Showing 14 changed files with 130 additions and 39 deletions.
6 changes: 3 additions & 3 deletions api/python/lief/ELF.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -1404,13 +1404,13 @@ class Note(lief.Object):
def copy(self) -> Optional[lief.ELF.Note]: ...
@overload
@staticmethod
def create(name: str, original_type: int, description: list[int], file_type: lief.ELF.Header.FILE_TYPE = ..., arch: lief.ELF.ARCH = ..., cls: lief.ELF.Header.CLASS = ...) -> Optional[lief.ELF.Note]: ...
def create(name: str, original_type: int, description: list[int], section_name: str, file_type: lief.ELF.Header.FILE_TYPE = ..., arch: lief.ELF.ARCH = ..., cls: lief.ELF.Header.CLASS = ...) -> Optional[lief.ELF.Note]: ...
@overload
@staticmethod
def create(raw: bytes, file_type: lief.ELF.Header.FILE_TYPE = ..., arch: lief.ELF.ARCH = ..., cls: lief.ELF.Header.CLASS = ...) -> Optional[lief.ELF.Note]: ...
def create(raw: bytes, section_name: str = ..., file_type: lief.ELF.Header.FILE_TYPE = ..., arch: lief.ELF.ARCH = ..., cls: lief.ELF.Header.CLASS = ...) -> Optional[lief.ELF.Note]: ...
@overload
@staticmethod
def create(name: str, type: lief.ELF.Note.TYPE, description: list[int], arch: lief.ELF.ARCH = ..., cls: lief.ELF.Header.CLASS = ...) -> Optional[lief.ELF.Note]: ...
def create(name: str, type: lief.ELF.Note.TYPE, description: list[int], section_name: str, arch: lief.ELF.ARCH = ..., cls: lief.ELF.Header.CLASS = ...) -> Optional[lief.ELF.Note]: ...
@property
def original_type(self) -> int: ...
@property
Expand Down
14 changes: 7 additions & 7 deletions api/python/src/ELF/objects/pyNote.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ void create<Note>(nb::module_& m) {
;
#undef ENTRY

const auto create_overload_0 = nb::overload_cast<const std::string&, uint32_t, Note::description_t, Header::FILE_TYPE, ARCH, Header::CLASS>(&Note::create);
const auto create_overload_1 = nb::overload_cast<const std::string&, Note::TYPE, Note::description_t, ARCH, Header::CLASS>(&Note::create);
const auto create_overload_0 = nb::overload_cast<const std::string&, uint32_t, Note::description_t, std::string, Header::FILE_TYPE, ARCH, Header::CLASS>(&Note::create);
const auto create_overload_1 = nb::overload_cast<const std::string&, Note::TYPE, Note::description_t, std::string, ARCH, Header::CLASS>(&Note::create);
note
.def_static("create", create_overload_0,
R"doc(
Expand All @@ -98,24 +98,24 @@ void create<Note>(nb::module_& m) {
Depending on the note, the filetype, the architecture and the ELF class might be needed.
)doc"_doc,
"name"_a, "original_type"_a, "description"_a,
"name"_a, "original_type"_a, "description"_a, "section_name"_a,
"file_type"_a = Header::FILE_TYPE::NONE, "arch"_a = ARCH::NONE, "cls"_a = Header::CLASS::NONE)

.def_static("create",
[] (nb::bytes bytes, Header::FILE_TYPE ftype, ARCH arch, Header::CLASS cls) -> std::unique_ptr<Note> {
[] (nb::bytes bytes, std::string section, Header::FILE_TYPE ftype, ARCH arch, Header::CLASS cls) -> std::unique_ptr<Note> {
std::unique_ptr<LIEF::SpanStream> stream = to_stream(bytes);
if (!stream) {
return nullptr;
}
return Note::create(*stream, ftype, arch, cls);
return Note::create(*stream, std::move(section), ftype, arch, cls);
},
R"doc(
Create a note from the given `bytes` buffer.
Depending on the note, the filetype, the architecture and the ELF class might
be needed.
)doc"_doc,
"raw"_a,
"raw"_a, "section_name"_a = "",
"file_type"_a = Header::FILE_TYPE::NONE, "arch"_a = ARCH::NONE,
"cls"_a = Header::CLASS::NONE)

Expand All @@ -126,7 +126,7 @@ void create<Note>(nb::module_& m) {
Depending on the note, the filetype, the architecture and the ELF class might
be needed.
)doc"_doc,
"name"_a, "type"_a, "description"_a,
"name"_a, "type"_a, "description"_a, "section_name"_a,
"arch"_a = ARCH::NONE, "cls"_a = Header::CLASS::NONE)

.def_prop_rw("name",
Expand Down
17 changes: 17 additions & 0 deletions doc/sphinx/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,23 @@ Changelog
* First (beta) release of the bindings (c.f. :ref:`lief_rust_bindings`)

:ELF:
* Add support to create custom notes (:issue:`1026`):

.. code-block:: python
elf: lief.ELF.Binary = ...
elf += lief.ELF.Note.create(
name="my-custom-note",
original_type=lief.ELF.Note.TYPE.UNKNOWN,
description=list(b"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed"),
section_name=".lief.note.custom"
)
config = lief.ELF.Builder.config_t()
config.notes = True
elf.write("/tmp/new-binary.elf", config)
* Add :meth:`lief.ELF.Binary.get_relocated_dynamic_array` which allows
to get a **relocated** view of the of init/fini entries. This function can
handy ELF init array/fini array functions are defined through relocations.
Expand Down
22 changes: 18 additions & 4 deletions include/LIEF/ELF/Note.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,12 @@ class LIEF_API Note : public Object {
/// provided in parameter
static result<const char*> type_to_section(TYPE type);

static result<const char*> note_to_section(const Note& note) {
return type_to_section(note.type());
static result<std::string> note_to_section(const Note& note) {
const std::string& sec_name = note.section_name();
if (sec_name.empty()) {
return type_to_section(note.type());
}
return sec_name;
}

/// Try to determine the owner's name of the TYPE provided in parameter
Expand All @@ -146,6 +150,7 @@ class LIEF_API Note : public Object {
/// creating notes like Coredump notes.
static std::unique_ptr<Note> create(
const std::string& name, uint32_t type, description_t description,
std::string section_name,
Header::FILE_TYPE ftype = Header::FILE_TYPE::NONE, ARCH arch = ARCH::NONE,
Header::CLASS cls = Header::CLASS::NONE);

Expand All @@ -154,12 +159,14 @@ class LIEF_API Note : public Object {
/// creating notes like Coredump notes.
static std::unique_ptr<Note> create(
const std::string& name, TYPE type, description_t description,
std::string section_name,
ARCH arch = ARCH::NONE, Header::CLASS cls = Header::CLASS::NONE);

/// Create a new note from the given stream. Additional information
/// such as the architecture or the ELF class could be required for
/// creating notes like Coredump notes.
static std::unique_ptr<Note> create(BinaryStream& stream,
std::string section_name,
Header::FILE_TYPE ftype = Header::FILE_TYPE::NONE, ARCH arch = ARCH::NONE,
Header::CLASS cls = Header::CLASS::NONE);

Expand All @@ -178,6 +185,11 @@ class LIEF_API Note : public Object {
return name_;
}

/// Return the section name in which the note is or should be stored
const std::string& section_name() const {
return section_name_;
}

/// Return the type of the note. This type does not match the `NT_` type
/// value. For accessing the original `NT_` value, check original_type()
TYPE type() const {
Expand Down Expand Up @@ -224,11 +236,12 @@ class LIEF_API Note : public Object {
protected:
Note() = default;
Note(std::string name, TYPE type, uint32_t original_type,
description_t description) :
description_t description, std::string section) :
name_(std::move(name)),
type_(type),
original_type_(original_type),
description_(std::move(description))
description_(std::move(description)),
section_name_(std::move(section))
{}

template<class T>
Expand All @@ -246,6 +259,7 @@ class LIEF_API Note : public Object {
TYPE type_ = TYPE::UNKNOWN;
uint32_t original_type_ = 0;
description_t description_;
std::string section_name_;
};

LIEF_API const char* to_string(Note::TYPE type);
Expand Down
6 changes: 4 additions & 2 deletions include/LIEF/ELF/NoteDetails/NoteGnuProperty.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,10 @@ class LIEF_API NoteGnuProperty : public Note {
using properties_t = std::vector<std::unique_ptr<NoteGnuProperty::Property>>;

NoteGnuProperty(ARCH arch, Header::CLASS cls, std::string name,
uint32_t type, description_t description) :
Note(std::move(name), TYPE::GNU_PROPERTY_TYPE_0, type, std::move(description)),
uint32_t type, description_t description,
std::string secname) :
Note(std::move(name), TYPE::GNU_PROPERTY_TYPE_0, type, std::move(description),
std::move(secname)),
arch_(arch), class_(cls)
{}

Expand Down
2 changes: 1 addition & 1 deletion include/LIEF/ELF/NoteDetails/core/CoreAuxv.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class LIEF_API CoreAuxv : public Note {

CoreAuxv(ARCH arch, Header::CLASS cls, std::string name,
uint32_t type, description_t description) :
Note(std::move(name), Note::TYPE::CORE_AUXV, type, std::move(description)),
Note(std::move(name), Note::TYPE::CORE_AUXV, type, std::move(description), ""),
arch_(arch), class_(cls)
{}

Expand Down
2 changes: 1 addition & 1 deletion include/LIEF/ELF/NoteDetails/core/CorePrPsInfo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class LIEF_API CorePrPsInfo : public Note {
};
CorePrPsInfo(ARCH arch, Header::CLASS cls, std::string name,
uint32_t type, description_t description) :
Note(std::move(name), TYPE::CORE_PRPSINFO, type, std::move(description)),
Note(std::move(name), TYPE::CORE_PRPSINFO, type, std::move(description), ""),
arch_(arch), class_(cls)
{}

Expand Down
2 changes: 1 addition & 1 deletion include/LIEF/ELF/NoteDetails/core/CorePrStatus.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ class LIEF_API CorePrStatus : public Note {
public:
CorePrStatus(ARCH arch, Header::CLASS cls, std::string name,
uint32_t type, description_t description) :
Note(std::move(name), TYPE::CORE_PRSTATUS, type, std::move(description)),
Note(std::move(name), TYPE::CORE_PRSTATUS, type, std::move(description), ""),
arch_(arch), class_(cls)
{}

Expand Down
2 changes: 1 addition & 1 deletion src/ELF/ExeLayout.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1637,7 +1637,7 @@ class LIEF_LOCAL ExeLayout : public Layout {
continue;
}

const char* sec_name = *section_res;
std::string sec_name = *section_res;

// If the binary has the note type but does not have
// the section (likly because the user added the note manually)
Expand Down
11 changes: 11 additions & 0 deletions src/ELF/Layout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,17 @@ size_t Layout::section_shstr_size() {
}
}

for (const Note& note : binary_->notes()) {
const std::string& secname = note.section_name();
if (secname.empty()) {
continue;
}

if (const Section* sec = binary_->get_section(secname); sec == nullptr) {
sec_names.push_back(secname);
}
}

// First write section names
size_t offset_counter = raw_shstrtab.tellp();
std::vector<std::string> shstrtab_opt = optimize(sec_names, [] (const std::string& s) { return s; },
Expand Down
39 changes: 24 additions & 15 deletions src/ELF/Note.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,9 @@ result<Note::TYPE> Note::convert_type(Header::FILE_TYPE ftype, uint32_t type,
}

std::unique_ptr<Note>
Note::create(BinaryStream& stream, Header::FILE_TYPE ftype, ARCH arch, Header::CLASS cls) {
Note::create(BinaryStream& stream, std::string section_name,
Header::FILE_TYPE ftype, ARCH arch, Header::CLASS cls)
{
static constexpr uint32_t MAX_NOTE_DESCRIPTION = 1_MB;
const size_t pos = stream.pos();
auto res_namesz = stream.read_conv<uint32_t>();
Expand Down Expand Up @@ -447,11 +449,13 @@ Note::create(BinaryStream& stream, Header::FILE_TYPE ftype, ARCH arch, Header::C
start_ptr + description.size() * sizeof(uint32_t)};
}

return create(name, type, std::move(desc_bytes), ftype, arch, cls);
return create(name, type, std::move(desc_bytes), std::move(section_name),
ftype, arch, cls);
}

std::unique_ptr<Note>
Note::create(const std::string& name, Note::TYPE ntype, description_t description,
std::string section_name,
ARCH arch, Header::CLASS cls)
{
std::string owner;
Expand Down Expand Up @@ -549,7 +553,8 @@ Note::create(const std::string& name, Note::TYPE ntype, description_t descriptio
case Note::TYPE::CORE_SIGINFO:
{
return std::unique_ptr<CoreSigInfo>(new CoreSigInfo(
std::move(norm_name), ntype, *int_type, std::move(description)
std::move(norm_name), ntype, *int_type, std::move(description),
std::move(section_name)
));
}
case Note::TYPE::GNU_PROPERTY_TYPE_0:
Expand All @@ -564,25 +569,30 @@ Note::create(const std::string& name, Note::TYPE ntype, description_t descriptio
return nullptr;
}
return std::unique_ptr<NoteGnuProperty>(new NoteGnuProperty(
arch, cls, std::move(norm_name), *int_type, std::move(description)
arch, cls, std::move(norm_name), *int_type, std::move(description),
std::move(section_name)
));
}
case Note::TYPE::ANDROID_IDENT:
return std::unique_ptr<AndroidIdent>(new AndroidIdent(
std::move(norm_name), ntype, *int_type, std::move(description)
std::move(norm_name), ntype, *int_type, std::move(description),
std::move(section_name)
));
case Note::TYPE::QNX_STACK:
return std::unique_ptr<QNXStack>(new QNXStack(
std::move(norm_name), ntype, *int_type, std::move(description)
std::move(norm_name), ntype, *int_type, std::move(description),
std::move(section_name)
));
case Note::TYPE::GNU_ABI_TAG:
return std::unique_ptr<NoteAbi>(new NoteAbi(
std::move(norm_name), ntype, *int_type, std::move(description)
std::move(norm_name), ntype, *int_type, std::move(description),
std::move(section_name)
));

default:
return std::unique_ptr<Note>(new Note(
std::move(norm_name), ntype, *int_type, std::move(description)
std::move(norm_name), ntype, *int_type, std::move(description),
std::move(section_name)
));
}
return nullptr;
Expand All @@ -591,15 +601,17 @@ Note::create(const std::string& name, Note::TYPE ntype, description_t descriptio

std::unique_ptr<Note>
Note::create(const std::string& name, uint32_t type, description_t description,
std::string section_name,
Header::FILE_TYPE ftype, ARCH arch, Header::CLASS cls)
{
auto conv = Note::convert_type(ftype, type, name);
if (!conv) {
LIEF_WARN("Note type: 0x{:x} is not supported for owner: '{}'", type, name);
LIEF_DEBUG("Note type: 0x{:x} is not supported for owner: '{}'", type, name);
return std::unique_ptr<Note>(new Note(name, Note::TYPE::UNKNOWN, type,
std::move(description)));
std::move(description), std::move(section_name)));
}
return create(name, *conv, std::move(description), arch, cls);
return create(name, *conv, std::move(description),
std::move(section_name), arch, cls);
}


Expand All @@ -618,10 +630,7 @@ void Note::accept(Visitor& visitor) const {
}

void Note::dump(std::ostream& os) const {
std::string note_name = name();
if (type() == TYPE::GNU_BUILD_ATTRIBUTE_OPEN) {
note_name = printable_string(note_name);
}
std::string note_name = printable_string(name());
os << fmt::format("{}(0x{:04x}) '{}' [{}]",
to_string(type()), original_type(), note_name,
to_hex(description(), 10));
Expand Down
2 changes: 1 addition & 1 deletion src/ELF/NoteDetails/core/CoreFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ void CoreFile::write_files() {

CoreFile::CoreFile(ARCH arch, Header::CLASS cls, std::string name,
uint32_t type, Note::description_t description) :
Note(std::move(name), Note::TYPE::CORE_FILE, type, std::move(description)),
Note(std::move(name), Note::TYPE::CORE_FILE, type, std::move(description), ""),
arch_(arch), class_(cls)
{

Expand Down
5 changes: 4 additions & 1 deletion src/ELF/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -569,8 +569,11 @@ ok_error_t Parser::parse_notes(uint64_t offset, uint64_t size) {

while (*stream_ && stream_->pos() < last_offset) {
const auto current_pos = static_cast<int64_t>(stream_->pos());
const Section* sec = binary_->section_from_offset(current_pos);
std::string sec_name = sec != nullptr ? sec->name() : "";

std::unique_ptr<Note> note = Note::create(
*stream_,
*stream_, std::move(sec_name),
binary_->header().file_type(), binary_->header().machine_type(),
binary_->header().identity_class()
);
Expand Down
Loading

0 comments on commit 27d406b

Please sign in to comment.