diff --git a/elf/dl-load.c b/elf/dl-load.c
index 06f2ba7264..36c7b8d2bc 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -1146,6 +1146,8 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
l->l_relro_size = ph->p_memsz;
break;
+ case PT_GNU_PROPERTY:
+ /* Fall through. PT_GNU_PROPERTY holds property notes. */
case PT_NOTE:
if (_dl_process_pt_note (l, ph, fd, fbp))
{
diff --git a/elf/rtld.c b/elf/rtld.c
index 5ccc3c2dbb..623b46b226 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -1506,6 +1506,8 @@ of this helper program; chances are you did not intend to run this program.\n\
main_map->l_relro_size = ph->p_memsz;
break;
+ case PT_GNU_PROPERTY:
+ /* Fall through. PT_GNU_PROPERTY holds property notes. */
case PT_NOTE:
if (_rtld_process_pt_note (main_map, ph))
_dl_error_printf ("\
diff --git a/sysdeps/aarch64/Makefile b/sysdeps/aarch64/Makefile
index 9cb141004d..5ae8b082b0 100644
--- a/sysdeps/aarch64/Makefile
+++ b/sysdeps/aarch64/Makefile
@@ -1,5 +1,9 @@
long-double-fcts = yes
+ifeq ($(subdir),elf)
+sysdep-dl-routines += dl-bti
+endif
+
ifeq ($(subdir),elf)
sysdep-dl-routines += tlsdesc dl-tlsdesc
gen-as-const-headers += dl-link.sym
diff --git a/sysdeps/aarch64/dl-bti.c b/sysdeps/aarch64/dl-bti.c
new file mode 100644
index 0000000000..adb7ea9bcd
--- /dev/null
+++ b/sysdeps/aarch64/dl-bti.c
@@ -0,0 +1,54 @@
+/* AArch64 BTI functions.
+ Copyright (C) 2020 Free Software Foundation, Inc.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#include
+#include
+#include
+#include
+
+static int
+enable_bti (struct link_map *map, const char *program)
+{
+ const ElfW(Phdr) *phdr;
+ unsigned prot = PROT_READ | PROT_EXEC | PROT_BTI;
+
+ for (phdr = map->l_phdr; phdr < &map->l_phdr[map->l_phnum]; ++phdr)
+ if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_X))
+ {
+ ElfW(Addr) start = phdr->p_vaddr + map->l_addr;
+ ElfW(Addr) len = phdr->p_memsz;
+ if (__mprotect ((void *) start, len, prot) < 0)
+ {
+ if (program)
+ _dl_fatal_printf ("%s: mprotect failed to turn on BTI\n",
+ map->l_name);
+ else
+ _dl_signal_error (EINVAL, map->l_name, "dlopen",
+ N_("mprotect failed to turn on BTI"));
+ }
+ }
+ return 0;
+}
+
+/* Enable BTI for L if required. */
+
+void
+_dl_bti_check (struct link_map *l, const char *program)
+{
+ if (GLRO(dl_aarch64_cpu_features).bti && l->l_mach.bti_guarded)
+ enable_bti (l, program);
+}
diff --git a/sysdeps/aarch64/dl-prop.h b/sysdeps/aarch64/dl-prop.h
new file mode 100644
index 0000000000..ee10882440
--- /dev/null
+++ b/sysdeps/aarch64/dl-prop.h
@@ -0,0 +1,170 @@
+/* Support for GNU properties. AArch64 version.
+ Copyright (C) 2018-2020 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#ifndef _DL_PROP_H
+#define _DL_PROP_H
+
+#include
+
+extern void _dl_bti_check (struct link_map *, const char *)
+ attribute_hidden;
+
+static inline void __attribute__ ((always_inline))
+_rtld_main_check (struct link_map *m, const char *program)
+{
+ _dl_bti_check (m, program);
+}
+
+static inline void __attribute__ ((always_inline))
+_dl_open_check (struct link_map *m)
+{
+ _dl_bti_check (m, NULL);
+}
+
+static inline void __attribute__ ((unused))
+_dl_process_aarch64_property (struct link_map *l,
+ const ElfW(Nhdr) *note,
+ const ElfW(Addr) size,
+ const ElfW(Addr) align)
+{
+ /* The NT_GNU_PROPERTY_TYPE_0 note must be aligned to 4 bytes in
+ 32-bit objects and to 8 bytes in 64-bit objects. Skip notes
+ with incorrect alignment. */
+ if (align != (__ELF_NATIVE_CLASS / 8))
+ return;
+
+ const ElfW(Addr) start = (ElfW(Addr)) note;
+
+ unsigned int feature_1 = 0;
+ unsigned int last_type = 0;
+
+ while ((ElfW(Addr)) (note + 1) - start < size)
+ {
+ /* Find the NT_GNU_PROPERTY_TYPE_0 note. */
+ if (note->n_namesz == 4
+ && note->n_type == NT_GNU_PROPERTY_TYPE_0
+ && memcmp (note + 1, "GNU", 4) == 0)
+ {
+ /* Check for invalid property. */
+ if (note->n_descsz < 8
+ || (note->n_descsz % sizeof (ElfW(Addr))) != 0)
+ return;
+
+ /* Start and end of property array. */
+ unsigned char *ptr = (unsigned char *) (note + 1) + 4;
+ unsigned char *ptr_end = ptr + note->n_descsz;
+
+ do
+ {
+ unsigned int type = *(unsigned int *) ptr;
+ unsigned int datasz = *(unsigned int *) (ptr + 4);
+
+ /* Property type must be in ascending order. */
+ if (type < last_type)
+ return;
+
+ ptr += 8;
+ if ((ptr + datasz) > ptr_end)
+ return;
+
+ last_type = type;
+
+ if (type == GNU_PROPERTY_AARCH64_FEATURE_1_AND)
+ {
+ /* The size of GNU_PROPERTY_AARCH64_FEATURE_1_AND is 4
+ bytes. When seeing GNU_PROPERTY_AARCH64_FEATURE_1_AND,
+ we stop the search regardless if its size is correct
+ or not. There is no point to continue if this note
+ is ill-formed. */
+ if (datasz != 4)
+ return;
+
+ feature_1 = *(unsigned int *) ptr;
+ if ((feature_1 & GNU_PROPERTY_AARCH64_FEATURE_1_BTI))
+ l->l_mach.bti_guarded = true;
+
+ /* Stop if we found the property note. */
+ return;
+ }
+ else if (type > GNU_PROPERTY_AARCH64_FEATURE_1_AND)
+ {
+ /* Stop since property type is in ascending order. */
+ return;
+ }
+
+ /* Check the next property item. */
+ ptr += ALIGN_UP (datasz, sizeof (ElfW(Addr)));
+ }
+ while ((ptr_end - ptr) >= 8);
+ }
+
+ /* NB: Note sections like .note.ABI-tag and .note.gnu.build-id are
+ aligned to 4 bytes in 64-bit ELF objects. */
+ note = ((const void *) note
+ + ELF_NOTE_NEXT_OFFSET (note->n_namesz, note->n_descsz,
+ align));
+ }
+}
+
+#ifdef FILEBUF_SIZE
+static inline int __attribute__ ((unused))
+_dl_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph,
+ int fd, struct filebuf *fbp)
+{
+ if (ph->p_type != PT_GNU_PROPERTY)
+ return 0;
+
+ const ElfW(Nhdr) *note;
+ ElfW(Nhdr) *note_malloced = NULL;
+ ElfW(Addr) size = ph->p_filesz;
+
+ if (ph->p_offset + size <= (size_t) fbp->len)
+ note = (const void *) (fbp->buf + ph->p_offset);
+ else
+ {
+ if (size < __MAX_ALLOCA_CUTOFF)
+ note = alloca (size);
+ else
+ note = note_malloced = malloc (size);
+ if (note == NULL)
+ return -1;
+ if (__pread64_nocancel (fd, (void *) note, size, ph->p_offset) != size)
+ {
+ if (note_malloced)
+ free (note_malloced);
+ return -1;
+ }
+ }
+ _dl_process_aarch64_property (l, note, ph->p_filesz, ph->p_align);
+ if (note_malloced)
+ free (note_malloced);
+ return 0;
+}
+#endif
+
+static inline int __attribute__ ((unused))
+_rtld_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph)
+{
+ if (ph->p_type != PT_GNU_PROPERTY)
+ return 0;
+ const ElfW(Nhdr) *note = (const void *) (ph->p_vaddr + l->l_addr);
+ _dl_process_aarch64_property (l, note, ph->p_memsz, ph->p_align);
+ return 0;
+}
+
+#endif /* _DL_PROP_H */
diff --git a/sysdeps/aarch64/linkmap.h b/sysdeps/aarch64/linkmap.h
index 943a9ee9e4..4b9be4202f 100644
--- a/sysdeps/aarch64/linkmap.h
+++ b/sysdeps/aarch64/linkmap.h
@@ -16,8 +16,11 @@
License along with the GNU C Library; if not, see
. */
+#include
+
struct link_map_machine
{
ElfW(Addr) plt; /* Address of .plt */
void *tlsdesc_table; /* Address of TLS descriptor hash table. */
+ bool bti_guarded; /* Branch Target Identification mechanism enabled. */
};
diff --git a/sysdeps/unix/sysv/linux/aarch64/bits/hwcap.h b/sysdeps/unix/sysv/linux/aarch64/bits/hwcap.h
index 4ee14b4208..af90d8a626 100644
--- a/sysdeps/unix/sysv/linux/aarch64/bits/hwcap.h
+++ b/sysdeps/unix/sysv/linux/aarch64/bits/hwcap.h
@@ -72,3 +72,4 @@
#define HWCAP2_BF16 (1 << 14)
#define HWCAP2_DGH (1 << 15)
#define HWCAP2_RNG (1 << 16)
+#define HWCAP2_BTI (1 << 17)
diff --git a/sysdeps/unix/sysv/linux/aarch64/bits/mman.h b/sysdeps/unix/sysv/linux/aarch64/bits/mman.h
new file mode 100644
index 0000000000..ecae046344
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/aarch64/bits/mman.h
@@ -0,0 +1,31 @@
+/* Definitions for POSIX memory map interface. Linux/AArch64 version.
+ Copyright (C) 2020 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#ifndef _SYS_MMAN_H
+# error "Never use directly; include instead."
+#endif
+
+/* AArch64 specific definitions, should be in sync with
+ arch/arm64/include/uapi/asm/mman.h. */
+
+#define PROT_BTI 0x10
+
+#include
+
+/* Include generic Linux declarations. */
+#include
diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
index 896c588fee..0fc507058b 100644
--- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
+++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
@@ -83,4 +83,7 @@ init_cpu_features (struct cpu_features *cpu_features)
if ((dczid & DCZID_DZP_MASK) == 0)
cpu_features->zva_size = 4 << (dczid & DCZID_BS_MASK);
+
+ /* Check if BTI is enabled. */
+ cpu_features->bti = GLRO (dl_hwcap2) & HWCAP2_BTI;
}
diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.h b/sysdeps/unix/sysv/linux/aarch64/cpu-features.h
index 1389cea1b3..a81f186ec2 100644
--- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.h
+++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.h
@@ -20,6 +20,7 @@
#define _CPU_FEATURES_AARCH64_H
#include
+#include
#define MIDR_PARTNUM_SHIFT 4
#define MIDR_PARTNUM_MASK (0xfff << MIDR_PARTNUM_SHIFT)
@@ -64,6 +65,7 @@ struct cpu_features
{
uint64_t midr_el1;
unsigned zva_size;
+ bool bti;
};
#endif /* _CPU_FEATURES_AARCH64_H */