diff --git a/api/python/lief/ELF.pyi b/api/python/lief/ELF.pyi index d60774fddb..2d409aacfa 100644 --- a/api/python/lief/ELF.pyi +++ b/api/python/lief/ELF.pyi @@ -52,6 +52,13 @@ class AArch64Feature(NoteGnuProperty.Property): @property def features(self) -> list[lief.ELF.AArch64Feature.FEATURE]: ... +class AArch64PAuth(NoteGnuProperty.Property): + def __init__(self, *args, **kwargs) -> None: ... + @property + def platform(self) -> int: ... + @property + def version(self) -> int: ... + class ARCH: AARCH64: ClassVar[ARCH] = ... ALPHA: ClassVar[ARCH] = ... @@ -1455,6 +1462,7 @@ class NoteGnuProperty(Note): class Property: class TYPE: AARCH64_FEATURES: ClassVar[NoteGnuProperty.Property.TYPE] = ... + AARCH64_PAUTH: ClassVar[NoteGnuProperty.Property.TYPE] = ... GENERIC: ClassVar[NoteGnuProperty.Property.TYPE] = ... NEEDED: ClassVar[NoteGnuProperty.Property.TYPE] = ... NO_COPY_ON_PROTECTED: ClassVar[NoteGnuProperty.Property.TYPE] = ... diff --git a/api/python/src/ELF/objects/NoteDetails/properties/CMakeLists.txt b/api/python/src/ELF/objects/NoteDetails/properties/CMakeLists.txt index eec5892096..a017ba9998 100644 --- a/api/python/src/ELF/objects/NoteDetails/properties/CMakeLists.txt +++ b/api/python/src/ELF/objects/NoteDetails/properties/CMakeLists.txt @@ -1,5 +1,6 @@ target_sources(pyLIEF PRIVATE pyAArch64Feature.cpp + pyAArch64PAuth.cpp pyGeneric.cpp pyNoteNoCopyOnProtected.cpp pyX86Features.cpp diff --git a/api/python/src/ELF/objects/NoteDetails/properties/pyAArch64Feature.cpp b/api/python/src/ELF/objects/NoteDetails/properties/pyAArch64Feature.cpp index 6c9fa0baf3..921072e2c3 100644 --- a/api/python/src/ELF/objects/NoteDetails/properties/pyAArch64Feature.cpp +++ b/api/python/src/ELF/objects/NoteDetails/properties/pyAArch64Feature.cpp @@ -30,7 +30,7 @@ void create(nb::module_& m) { nb::class_ Class(m, "AArch64Feature", R"doc( - This class represents the `GNU_PROPERTY_AARCH64_FEATURE_1_AND` note. + This class represents the ``GNU_PROPERTY_AARCH64_FEATURE_1_AND`` note. )doc"_doc); Class diff --git a/api/python/src/ELF/objects/NoteDetails/properties/pyAArch64PAuth.cpp b/api/python/src/ELF/objects/NoteDetails/properties/pyAArch64PAuth.cpp new file mode 100644 index 0000000000..672fbd48ff --- /dev/null +++ b/api/python/src/ELF/objects/NoteDetails/properties/pyAArch64PAuth.cpp @@ -0,0 +1,55 @@ +/* Copyright 2017 - 2024 R. Thomas + * Copyright 2017 - 2024 Quarkslab + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include + +#include "ELF/pyELF.hpp" + +#include "LIEF/ELF/NoteDetails/properties/AArch64PAuth.hpp" + +namespace LIEF::ELF::py { + +template<> +void create(nb::module_& m) { + nb::class_ + Class(m, "AArch64PAuth", + R"doc( + This class represents the ``GNU_PROPERTY_AARCH64_FEATURE_PAUTH`` note. + + .. note:: + + If both: :attr:`.AArch64PAuth.platform` and :attr:`.AArch64PAuth.version` are set to + 0, this means that the binary is incompatible with PAuth ABI extension. + )doc"_doc); + + Class + .def_prop_ro("platform", &AArch64PAuth::platform, + R"doc( + 64-bit value that specifies the platform vendor. + + A ``0`` value is associated with an *invalid* platform while the value ``1`` + is associated with a baremetal platform. + )doc"_doc) + + .def_prop_ro("version", &AArch64PAuth::version, + R"doc( + 64-bit value that identifies the signing schema used by the ELF file. + )doc"_doc) + ; + +} + +} diff --git a/api/python/src/ELF/objects/NoteDetails/properties/pyNoteNoCopyOnProtected.cpp b/api/python/src/ELF/objects/NoteDetails/properties/pyNoteNoCopyOnProtected.cpp index b7e18719c5..e1c47081f2 100644 --- a/api/python/src/ELF/objects/NoteDetails/properties/pyNoteNoCopyOnProtected.cpp +++ b/api/python/src/ELF/objects/NoteDetails/properties/pyNoteNoCopyOnProtected.cpp @@ -24,7 +24,7 @@ void create(nb::module_& m) { nb::class_ Class( m, "NoteNoCopyOnProtected", R"doc( - This class provides an interface over the `GNU_PROPERTY_NO_COPY_ON_PROTECTED` + This class provides an interface over the ``GNU_PROPERTY_NO_COPY_ON_PROTECTED`` property. This property indicates that the linker shouldn't copy relocations against protected symbols. )doc"_doc diff --git a/api/python/src/ELF/objects/NoteDetails/properties/pyStackSize.cpp b/api/python/src/ELF/objects/NoteDetails/properties/pyStackSize.cpp index 685ced7bf9..609b1b5d87 100644 --- a/api/python/src/ELF/objects/NoteDetails/properties/pyStackSize.cpp +++ b/api/python/src/ELF/objects/NoteDetails/properties/pyStackSize.cpp @@ -23,7 +23,7 @@ template<> void create(nb::module_& m) { nb::class_(m, "StackSize", R"doc( - This class provides an interface over the `GNU_PROPERTY_STACK_SIZE` property + This class provides an interface over the ``GNU_PROPERTY_STACK_SIZE`` property This property can be used by the loader to raise the stack limit. )doc") .def_prop_ro("stack_size", &StackSize::stack_size); diff --git a/api/python/src/ELF/objects/NoteDetails/pyNoteGnuProperty.cpp b/api/python/src/ELF/objects/NoteDetails/pyNoteGnuProperty.cpp index db837d6b38..441b17fa18 100644 --- a/api/python/src/ELF/objects/NoteDetails/pyNoteGnuProperty.cpp +++ b/api/python/src/ELF/objects/NoteDetails/pyNoteGnuProperty.cpp @@ -24,6 +24,7 @@ #include "LIEF/ELF/NoteDetails/NoteGnuProperty.hpp" #include "LIEF/ELF/NoteDetails/properties/AArch64Feature.hpp" +#include "LIEF/ELF/NoteDetails/properties/AArch64PAuth.hpp" #include "LIEF/ELF/NoteDetails/properties/X86Feature.hpp" #include "LIEF/ELF/NoteDetails/properties/X86ISA.hpp" #include "LIEF/ELF/NoteDetails/properties/StackSize.hpp" @@ -56,6 +57,7 @@ void create(nb::module_& m) { ENTRY(UNKNOWN) ENTRY(GENERIC) ENTRY(AARCH64_FEATURES) + ENTRY(AARCH64_PAUTH) ENTRY(STACK_SIZE) ENTRY(NO_COPY_ON_PROTECTED) ENTRY(X86_ISA) @@ -65,6 +67,7 @@ void create(nb::module_& m) { # undef ENTRY create(m); + create(m); create(m); create(m); create(m); diff --git a/doc/sphinx/_cross_api.rst b/doc/sphinx/_cross_api.rst index 18f712134f..69424b28b3 100644 --- a/doc/sphinx/_cross_api.rst +++ b/doc/sphinx/_cross_api.rst @@ -246,6 +246,11 @@ :py:meth:`lief.ELF.Binary.write` :cpp:func:`LIEF::ELF::Binary::write` +.. |lief-elf-aarch64pauth| lief-api:: lief.ELF.AArch64PAuth + + :py:class:`lief.ELF.AArch64PAuth` + :cpp:class:`LIEF::ELF::AArch64PAuth` + .. Mach-O ====================================================================== .. |lief-macho-binary| lief-api:: lief.MachO.Binary diff --git a/doc/sphinx/changelog.rst b/doc/sphinx/changelog.rst index 12196d3072..f891fb0015 100644 --- a/doc/sphinx/changelog.rst +++ b/doc/sphinx/changelog.rst @@ -6,7 +6,7 @@ 0.16.0 - Not Released Yet ------------------------- -:Abstract: +:Abstraction: * Add |get_int_from_virtual_address| to read an **integer** value at a specific virtual address @@ -35,6 +35,13 @@ elf: &lief::elf::Binary let value: i16 = elf.get_int_from_virtual_address::(0x401126).unwrap(); + * Global code cleaning (especially, |lief-header-architectures| and + |lief-header-modes| is now more meaningful) + * Re-scope ``lief.ARCHITECTURES`` into |lief-header-architectures| + * Re-scope ``lief.MODES`` into |lief-header-modes| + * Re-scope ``lief.OBJECT_TYPES`` into |lief-header-object-types| + * Re-scope ``lief.ENDIANNESS`` into |lief-header-endianness| + :MachO: @@ -67,6 +74,8 @@ :ELF: + * Add support for ``GNU_PROPERTY_AARCH64_FEATURE_PAUTH`` GNU property note: + |lief-elf-aarch64pauth|. * Add |lief-elf-binary-target-android| to check if an ELF targets Android * Fix a critical error when rewriting ELF file with ``DT_RELR`` relocations. This error leads to a crash of the modified binary. @@ -156,15 +165,6 @@ * Upgrade MbedTLS from ``3.2.1`` to ``3.6.1`` -:Abstraction: - - * Global code cleaning (especially, |lief-header-architectures| and - |lief-header-modes| is now more meaningful) - * Re-scope ``lief.ARCHITECTURES`` into |lief-header-architectures| - * Re-scope ``lief.MODES`` into |lief-header-modes| - * Re-scope ``lief.OBJECT_TYPES`` into |lief-header-object-types| - * Re-scope ``lief.ENDIANNESS`` into |lief-header-endianness| - :doc: * Global restructuring of the documentation diff --git a/doc/sphinx/formats/elf/cpp.rst b/doc/sphinx/formats/elf/cpp.rst index f895eff5e0..a929b601c0 100644 --- a/doc/sphinx/formats/elf/cpp.rst +++ b/doc/sphinx/formats/elf/cpp.rst @@ -236,6 +236,14 @@ AArch64 Feature .. doxygenclass:: LIEF::ELF::AArch64Feature +---------- + +AArch64 PAuth +*************** + +.. doxygenclass:: LIEF::ELF::AArch64PAuth + + ---------- No Copy on Protected diff --git a/doc/sphinx/formats/elf/python.rst b/doc/sphinx/formats/elf/python.rst index a6bee84274..57dffe82b4 100644 --- a/doc/sphinx/formats/elf/python.rst +++ b/doc/sphinx/formats/elf/python.rst @@ -323,6 +323,19 @@ AArch64 Feature ---------- +AArch64 PAuth +*************** + +.. lief-inheritance:: lief._lief.ELF.AArch64PAuth + :top-classes: lief._lief.ELF.NoteGnuProperty.Property + :parts: 2 + +.. autoclass:: lief.ELF.AArch64PAuth + +---------- + + + No Copy on Protected ******************** diff --git a/include/LIEF/ELF/NoteDetails/NoteGnuProperty.hpp b/include/LIEF/ELF/NoteDetails/NoteGnuProperty.hpp index 126b4fd11d..b74ae7ad6c 100644 --- a/include/LIEF/ELF/NoteDetails/NoteGnuProperty.hpp +++ b/include/LIEF/ELF/NoteDetails/NoteGnuProperty.hpp @@ -40,6 +40,7 @@ class LIEF_API NoteGnuProperty : public Note { UNKNOWN = 0, GENERIC, ///< Property that dont' have special implementation AARCH64_FEATURES, ///< Mirror of `GNU_PROPERTY_AARCH64_FEATURE_1_AND` + AARCH64_PAUTH, ///< Mirror of `GNU_PROPERTY_AARCH64_FEATURE_PAUTH` STACK_SIZE, ///< Mirror of `GNU_PROPERTY_STACK_SIZE` NO_COPY_ON_PROTECTED, ///< Mirror of `GNU_PROPERTY_NO_COPY_ON_PROTECTED` X86_ISA, ///< Mirror of `GNU_PROPERTY_X86_ISA_1_*` and `GNU_PROPERTY_X86_COMPAT_*` diff --git a/include/LIEF/ELF/NoteDetails/Properties.hpp b/include/LIEF/ELF/NoteDetails/Properties.hpp index 16560ffcfb..b0e7333e25 100644 --- a/include/LIEF/ELF/NoteDetails/Properties.hpp +++ b/include/LIEF/ELF/NoteDetails/Properties.hpp @@ -17,6 +17,7 @@ #define LIEF_ELF_NOTE_DETAILS_PROPERTIES_H #include "LIEF/ELF/NoteDetails/properties/AArch64Feature.hpp" +#include "LIEF/ELF/NoteDetails/properties/AArch64PAuth.hpp" #include "LIEF/ELF/NoteDetails/properties/Needed.hpp" #include "LIEF/ELF/NoteDetails/properties/NoteNoCopyOnProtected.hpp" #include "LIEF/ELF/NoteDetails/properties/X86ISA.hpp" diff --git a/include/LIEF/ELF/NoteDetails/properties/AArch64PAuth.hpp b/include/LIEF/ELF/NoteDetails/properties/AArch64PAuth.hpp new file mode 100644 index 0000000000..d9ff96e817 --- /dev/null +++ b/include/LIEF/ELF/NoteDetails/properties/AArch64PAuth.hpp @@ -0,0 +1,76 @@ +/* Copyright 2017 - 2024 R. Thomas + * Copyright 2017 - 2024 Quarkslab + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef LIEF_ELF_NOTE_DETAILS_PROPERTIES_AARCH64_PAUTH_H +#define LIEF_ELF_NOTE_DETAILS_PROPERTIES_AARCH64_PAUTH_H + +#include "LIEF/visibility.h" +#include "LIEF/ELF/NoteDetails/NoteGnuProperty.hpp" + +namespace LIEF { +class BinaryStream; + +namespace ELF { + + +/// This class represents the `GNU_PROPERTY_AARCH64_FEATURE_PAUTH` property. +/// +/// \note If both: AArch64PAuth::platform and AArch64PAuth::version are set to +/// 0, this means that the binary is incompatible with PAuth ABI extension. +class LIEF_API AArch64PAuth : public NoteGnuProperty::Property { + public: + /// 64-bit value that specifies the platform vendor. + /// + /// A `0` value is associated with an *invalid* platform while the value `1` + /// is associated with a baremetal platform. + uint64_t platform() const { + return platform_; + } + + /// 64-bit value that identifies the signing schema used by the ELF file. + uint64_t version() const { + return version_; + } + + static bool classof(const NoteGnuProperty::Property* prop) { + return prop->type() == NoteGnuProperty::Property::TYPE::AARCH64_PAUTH; + } + + static std::unique_ptr create(BinaryStream& stream); + + void dump(std::ostream &os) const override; + + ~AArch64PAuth() override = default; + + protected: + AArch64PAuth() : + NoteGnuProperty::Property(NoteGnuProperty::Property::TYPE::AARCH64_PAUTH) + {} + + AArch64PAuth(uint64_t platform, uint64_t version) : + NoteGnuProperty::Property(NoteGnuProperty::Property::TYPE::AARCH64_PAUTH), + platform_(platform), + version_(version) + {} + + uint64_t platform_ = 0; + uint64_t version_ = 0; +}; + +} +} + + +#endif diff --git a/src/ELF/NoteDetails/NoteGnuProperty.cpp b/src/ELF/NoteDetails/NoteGnuProperty.cpp index 0572da6f21..44a4b3c303 100644 --- a/src/ELF/NoteDetails/NoteGnuProperty.cpp +++ b/src/ELF/NoteDetails/NoteGnuProperty.cpp @@ -26,6 +26,7 @@ #include "LIEF/ELF/NoteDetails/NoteGnuProperty.hpp" #include "LIEF/ELF/NoteDetails/properties/Generic.hpp" #include "LIEF/ELF/NoteDetails/properties/AArch64Feature.hpp" +#include "LIEF/ELF/NoteDetails/properties/AArch64PAuth.hpp" #include "LIEF/ELF/NoteDetails/properties/StackSize.hpp" #include "LIEF/ELF/NoteDetails/properties/X86Feature.hpp" #include "LIEF/ELF/NoteDetails/properties/X86ISA.hpp" @@ -84,6 +85,10 @@ parse_property(ARCH arch, SpanStream& stream) { if (type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) { return AArch64Feature::create(content); } + + if (type == GNU_PROPERTY_AARCH64_FEATURE_PAUTH) { + return AArch64PAuth::create(content); + } return Generic::create(type); } } @@ -177,13 +182,13 @@ void NoteGnuProperty::accept(Visitor& visitor) const { visitor.visit(*this); } - const char* to_string(NoteGnuProperty::Property::TYPE type) { #define ENTRY(X) std::pair(NoteGnuProperty::Property::TYPE::X, #X) STRING_MAP enums2str { ENTRY(UNKNOWN), ENTRY(GENERIC), ENTRY(AARCH64_FEATURES), + ENTRY(AARCH64_PAUTH), ENTRY(STACK_SIZE), ENTRY(NO_COPY_ON_PROTECTED), ENTRY(X86_ISA), diff --git a/src/ELF/NoteDetails/properties/AArch64PAuth.cpp b/src/ELF/NoteDetails/properties/AArch64PAuth.cpp new file mode 100644 index 0000000000..a8fba9bbf2 --- /dev/null +++ b/src/ELF/NoteDetails/properties/AArch64PAuth.cpp @@ -0,0 +1,39 @@ +/* Copyright 2017 - 2024 R. Thomas + * Copyright 2017 - 2024 Quarkslab + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "LIEF/ELF/NoteDetails/properties/AArch64PAuth.hpp" +#include "LIEF/BinaryStream/BinaryStream.hpp" + +#include "frozen.hpp" +#include "fmt_formatter.hpp" + +namespace LIEF { +namespace ELF { + +std::unique_ptr AArch64PAuth::create(BinaryStream& stream) { + uint64_t platform = stream.read().value_or(0); + uint64_t version = stream.read().value_or(0); + + return std::unique_ptr(new AArch64PAuth(platform, version)); +} + +void AArch64PAuth::dump(std::ostream &os) const { + os << fmt::format("Platform: 0x{:04x}, Version: 0x{:04x}", + platform(), version()); +} + + +} +} diff --git a/src/ELF/NoteDetails/properties/CMakeLists.txt b/src/ELF/NoteDetails/properties/CMakeLists.txt index 5115b62f66..d5eb79d130 100644 --- a/src/ELF/NoteDetails/properties/CMakeLists.txt +++ b/src/ELF/NoteDetails/properties/CMakeLists.txt @@ -1,5 +1,6 @@ target_sources(LIB_LIEF PRIVATE AArch64Feature.cpp + AArch64PAuth.cpp StackSize.cpp X86Feature.cpp X86ISA.cpp diff --git a/src/ELF/NoteDetails/properties/common.hpp b/src/ELF/NoteDetails/properties/common.hpp index ee595a1bbb..e0d9599885 100644 --- a/src/ELF/NoteDetails/properties/common.hpp +++ b/src/ELF/NoteDetails/properties/common.hpp @@ -24,6 +24,7 @@ static constexpr auto GNU_PROPERTY_HIPROC = 0xdfffffff; static constexpr auto GNU_PROPERTY_LOUSER = 0xe0000000; static constexpr auto GNU_PROPERTY_HIUSER = 0xffffffff; static constexpr auto GNU_PROPERTY_AARCH64_FEATURE_1_AND = 0xc0000000; +static constexpr auto GNU_PROPERTY_AARCH64_FEATURE_PAUTH = 0xc0000001; static constexpr auto GNU_PROPERTY_STACK_SIZE = 1; static constexpr auto GNU_PROPERTY_NO_COPY_ON_PROTECTED = 2; diff --git a/tests/elf/test_notes.py b/tests/elf/test_notes.py index 71c750db32..393f6201b4 100644 --- a/tests/elf/test_notes.py +++ b/tests/elf/test_notes.py @@ -122,6 +122,25 @@ def test_note_aarch64_features(): print(note.properties[0]) print(note) +def test_note_aarch_pauth(): + GNU_PROPERTY_AARCH64_FEATURE_PAUTH = "040000001800000005000000474e5500010000c0100000002a000000000000000100000000000000" + + note: lief.ELF.NoteGnuProperty = lief.ELF.Note.create(raw=bytes.fromhex(GNU_PROPERTY_AARCH64_FEATURE_PAUTH), + file_type=lief.ELF.Header.FILE_TYPE.NONE, arch=lief.ELF.ARCH.AARCH64, + cls=lief.ELF.Header.CLASS.ELF64) + assert len(note.properties) == 1 + assert note.find(lief.ELF.NoteGnuProperty.Property.TYPE.AARCH64_PAUTH) is not None + assert note.find(lief.ELF.NoteGnuProperty.Property.TYPE.GENERIC) is None + + assert isinstance(note.properties[0], lief.ELF.AArch64PAuth) + assert note.properties[0].platform == 42 + assert note.properties[0].version == 1 + assert str(note.properties[0]) + print(note.properties[0]) + print(note) + + + def test_note_x86_isa(): GNU_PROPERTY_X86_ISA_1_NEEDED = "040000001800000005000000474e5500028000c00400000001000000020001c00400000000000000" note: lief.ELF.NoteGnuProperty = lief.ELF.Note.create(raw=bytes.fromhex(GNU_PROPERTY_X86_ISA_1_NEEDED),