aboutsummaryrefslogtreecommitdiff
path: root/linker/linker_phdr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linker/linker_phdr.cpp')
-rw-r--r--linker/linker_phdr.cpp53
1 files changed, 43 insertions, 10 deletions
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 1e8909457..9b1b99ffd 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -169,8 +169,16 @@ bool ElfReader::Load(address_space_params* address_space) {
if (did_load_) {
return true;
}
- if (ReserveAddressSpace(address_space) && LoadSegments() && FindPhdr()) {
+ if (ReserveAddressSpace(address_space) && LoadSegments() && FindPhdr() &&
+ FindGnuPropertySection()) {
did_load_ = true;
+#if defined(__aarch64__)
+ // For Armv8.5-A loaded executable segments may require PROT_BTI.
+ if (note_gnu_property_.IsBTICompatible()) {
+ did_load_ = (phdr_table_protect_segments(phdr_table_, phdr_num_, load_bias_,
+ &note_gnu_property_) == 0);
+ }
+#endif
}
return did_load_;
@@ -748,15 +756,21 @@ static int _phdr_table_set_load_prot(const ElfW(Phdr)* phdr_table, size_t phdr_c
ElfW(Addr) seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
ElfW(Addr) seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
- int prot = PFLAGS_TO_PROT(phdr->p_flags);
- if ((extra_prot_flags & PROT_WRITE) != 0) {
+ int prot = PFLAGS_TO_PROT(phdr->p_flags) | extra_prot_flags;
+ if ((prot & PROT_WRITE) != 0) {
// make sure we're never simultaneously writable / executable
prot &= ~PROT_EXEC;
}
+#if defined(__aarch64__)
+ if ((prot & PROT_EXEC) == 0) {
+ // Though it is not specified don't add PROT_BTI if segment is not
+ // executable.
+ prot &= ~PROT_BTI;
+ }
+#endif
- int ret = mprotect(reinterpret_cast<void*>(seg_page_start),
- seg_page_end - seg_page_start,
- prot | extra_prot_flags);
+ int ret =
+ mprotect(reinterpret_cast<void*>(seg_page_start), seg_page_end - seg_page_start, prot);
if (ret < 0) {
return -1;
}
@@ -768,16 +782,26 @@ static int _phdr_table_set_load_prot(const ElfW(Phdr)* phdr_table, size_t phdr_c
* You should only call this after phdr_table_unprotect_segments and
* applying all relocations.
*
+ * AArch64: also called from linker_main and ElfReader::Load to apply
+ * PROT_BTI for loaded main so and other so-s.
+ *
* Input:
* phdr_table -> program header table
* phdr_count -> number of entries in tables
* load_bias -> load bias
+ * prop -> GnuPropertySection or nullptr
* Return:
* 0 on error, -1 on failure (error code in errno).
*/
-int phdr_table_protect_segments(const ElfW(Phdr)* phdr_table,
- size_t phdr_count, ElfW(Addr) load_bias) {
- return _phdr_table_set_load_prot(phdr_table, phdr_count, load_bias, 0);
+int phdr_table_protect_segments(const ElfW(Phdr)* phdr_table, size_t phdr_count,
+ ElfW(Addr) load_bias, const GnuPropertySection* prop __unused) {
+ int prot = 0;
+#if defined(__aarch64__)
+ if ((prop != nullptr) && prop->IsBTICompatible()) {
+ prot |= PROT_BTI;
+ }
+#endif
+ return _phdr_table_set_load_prot(phdr_table, phdr_count, load_bias, prot);
}
/* Change the protection of all loaded segments in memory to writable.
@@ -1081,7 +1105,7 @@ void phdr_table_get_dynamic_section(const ElfW(Phdr)* phdr_table, size_t phdr_co
* Return:
* pointer to the program interpreter string.
*/
-const char* phdr_table_get_interpreter_name(const ElfW(Phdr) * phdr_table, size_t phdr_count,
+const char* phdr_table_get_interpreter_name(const ElfW(Phdr)* phdr_table, size_t phdr_count,
ElfW(Addr) load_bias) {
for (size_t i = 0; i<phdr_count; ++i) {
const ElfW(Phdr)& phdr = phdr_table[i];
@@ -1124,6 +1148,15 @@ bool ElfReader::FindPhdr() {
return false;
}
+// Tries to find .note.gnu.property section.
+// It is not considered an error if such section is missing.
+bool ElfReader::FindGnuPropertySection() {
+#if defined(__aarch64__)
+ note_gnu_property_ = GnuPropertySection(phdr_table_, phdr_num_, load_start(), name_.c_str());
+#endif
+ return true;
+}
+
// Ensures that our program header is actually within a loadable
// segment. This should help catch badly-formed ELF files that
// would cause the linker to crash later when trying to access it.