git: d8925a5f42b5 - main - Support BTI in rtld

From: Andrew Turner <andrew_at_FreeBSD.org>
Date: Fri, 12 Apr 2024 14:31:17 UTC
The branch main has been updated by andrew:

URL: https://cgit.FreeBSD.org/src/commit/?id=d8925a5f42b517131f926d665538be95db710c4a

commit d8925a5f42b517131f926d665538be95db710c4a
Author:     Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2023-04-05 12:44:31 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2024-04-12 14:30:44 +0000

    Support BTI in rtld
    
    Read the elf note to decide when to set the guard page on arm64.
    
    Reviewed by:    kib
    Sponsored by:   Arm Ltd
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D39452
---
 libexec/rtld-elf/aarch64/reloc.c          | 47 +++++++++++++++++++++++++++++++
 libexec/rtld-elf/aarch64/rtld_machdep.h   |  2 ++
 libexec/rtld-elf/amd64/rtld_machdep.h     |  3 ++
 libexec/rtld-elf/arm/rtld_machdep.h       |  3 ++
 libexec/rtld-elf/i386/rtld_machdep.h      |  3 ++
 libexec/rtld-elf/powerpc/rtld_machdep.h   |  3 ++
 libexec/rtld-elf/powerpc64/rtld_machdep.h |  3 ++
 libexec/rtld-elf/riscv/rtld_machdep.h     |  3 ++
 libexec/rtld-elf/rtld.c                   |  3 ++
 9 files changed, 70 insertions(+)

diff --git a/libexec/rtld-elf/aarch64/reloc.c b/libexec/rtld-elf/aarch64/reloc.c
index 44d390c5e083..d73982e26b76 100644
--- a/libexec/rtld-elf/aarch64/reloc.c
+++ b/libexec/rtld-elf/aarch64/reloc.c
@@ -29,6 +29,8 @@
 
 #include <sys/types.h>
 
+#include <machine/sysarch.h>
+
 #include <stdlib.h>
 
 #include "debug.h"
@@ -52,6 +54,51 @@ void *_rtld_tlsdesc_dynamic(void *);
 
 void _exit(int);
 
+bool
+arch_digest_note(struct Struct_Obj_Entry *obj __unused, const Elf_Note *note)
+{
+	const char *note_name;
+	const uint32_t *note_data;
+
+	note_name = (const char *)(note + 1);
+	/* Only handle GNU notes */
+	if (note->n_namesz != sizeof(ELF_NOTE_GNU) ||
+	    strncmp(note_name, ELF_NOTE_GNU, sizeof(ELF_NOTE_GNU)) != 0)
+		return (false);
+
+	/* Only handle GNU property notes */
+	if (note->n_type != NT_GNU_PROPERTY_TYPE_0)
+		return (false);
+
+	/*
+	 * note_data[0] - Type
+	 * note_data[1] - Length
+	 * note_data[2] - Data
+	 * note_data[3] - Padding?
+	 */
+	note_data = (const uint32_t *)(note_name + note->n_namesz);
+
+	/* Only handle AArch64 feature notes */
+	if (note_data[0] != GNU_PROPERTY_AARCH64_FEATURE_1_AND)
+		return (false);
+
+	/* We expect at least 4 bytes of data */
+	if (note_data[1] < 4)
+		return (false);
+
+	/* TODO: Only guard if HWCAP2_BTI is set */
+	if ((note_data[2] & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) != 0) {
+		struct arm64_guard_page_args guard;
+
+		guard.addr = (uintptr_t)obj->mapbase;
+		guard.len = obj->mapsize;
+
+		sysarch(ARM64_GUARD_PAGE, &guard);
+	}
+
+	return (true);
+}
+
 void
 init_pltgot(Obj_Entry *obj)
 {
diff --git a/libexec/rtld-elf/aarch64/rtld_machdep.h b/libexec/rtld-elf/aarch64/rtld_machdep.h
index b1c5e21cb505..36e3ec3e1a4e 100644
--- a/libexec/rtld-elf/aarch64/rtld_machdep.h
+++ b/libexec/rtld-elf/aarch64/rtld_machdep.h
@@ -45,6 +45,8 @@ struct Struct_Obj_Entry;
 	(const Elf_Dyn *)_dynamic_addr;					\
 })
 
+bool arch_digest_note(struct Struct_Obj_Entry *obj, const Elf_Note *note);
+
 Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
     const struct Struct_Obj_Entry *defobj, const struct Struct_Obj_Entry *obj,
     const Elf_Rel *rel);
diff --git a/libexec/rtld-elf/amd64/rtld_machdep.h b/libexec/rtld-elf/amd64/rtld_machdep.h
index 68e51c4894f4..ab23567cb6e6 100644
--- a/libexec/rtld-elf/amd64/rtld_machdep.h
+++ b/libexec/rtld-elf/amd64/rtld_machdep.h
@@ -39,6 +39,9 @@ struct Struct_Obj_Entry;
 Elf_Dyn *rtld_dynamic_addr(void);
 #define	rtld_dynamic(obj)	rtld_dynamic_addr()
 
+/* No architecture specific notes */
+#define	arch_digest_note(obj, note)	false
+
 Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
     const struct Struct_Obj_Entry *obj, const struct Struct_Obj_Entry *refobj,
     const Elf_Rel *rel);
diff --git a/libexec/rtld-elf/arm/rtld_machdep.h b/libexec/rtld-elf/arm/rtld_machdep.h
index 6a08aa5eb02c..26f62547ae8e 100644
--- a/libexec/rtld-elf/arm/rtld_machdep.h
+++ b/libexec/rtld-elf/arm/rtld_machdep.h
@@ -39,6 +39,9 @@ struct Struct_Obj_Entry;
 /* Return the address of the .dynamic section in the dynamic linker. */
 #define rtld_dynamic(obj) (&_DYNAMIC)
 
+/* No architecture specific notes */
+#define	arch_digest_note(obj, note)	false
+
 Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
     const struct Struct_Obj_Entry *defobj, const struct Struct_Obj_Entry *obj,
     const Elf_Rel *rel);
diff --git a/libexec/rtld-elf/i386/rtld_machdep.h b/libexec/rtld-elf/i386/rtld_machdep.h
index 6afb5e069cb5..69078d56df4c 100644
--- a/libexec/rtld-elf/i386/rtld_machdep.h
+++ b/libexec/rtld-elf/i386/rtld_machdep.h
@@ -39,6 +39,9 @@ struct Struct_Obj_Entry;
 #define rtld_dynamic(obj) \
     ((const Elf_Dyn *)((obj)->relocbase + (Elf_Addr)&_DYNAMIC))
 
+/* No architecture specific notes */
+#define	arch_digest_note(obj, note)	false
+
 Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
     const struct Struct_Obj_Entry *obj, const struct Struct_Obj_Entry *refobj,
     const Elf_Rel *rel);
diff --git a/libexec/rtld-elf/powerpc/rtld_machdep.h b/libexec/rtld-elf/powerpc/rtld_machdep.h
index 7b106b7e38d7..2450d58490e1 100644
--- a/libexec/rtld-elf/powerpc/rtld_machdep.h
+++ b/libexec/rtld-elf/powerpc/rtld_machdep.h
@@ -38,6 +38,9 @@ struct Struct_Obj_Entry;
 /* Return the address of the .dynamic section in the dynamic linker. */
 #define rtld_dynamic(obj)    (&_DYNAMIC)
 
+/* No architecture specific notes */
+#define	arch_digest_note(obj, note)	false
+
 Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
     const struct Struct_Obj_Entry *defobj, const struct Struct_Obj_Entry *obj,
     const Elf_Rel *rel);
diff --git a/libexec/rtld-elf/powerpc64/rtld_machdep.h b/libexec/rtld-elf/powerpc64/rtld_machdep.h
index 7e6f13940daf..63939110356b 100644
--- a/libexec/rtld-elf/powerpc64/rtld_machdep.h
+++ b/libexec/rtld-elf/powerpc64/rtld_machdep.h
@@ -38,6 +38,9 @@ struct Struct_Obj_Entry;
 /* Return the address of the .dynamic section in the dynamic linker. */
 #define rtld_dynamic(obj)    (&_DYNAMIC)
 
+/* No architecture specific notes */
+#define	arch_digest_note(obj, note)	false
+
 Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
     const struct Struct_Obj_Entry *defobj, const struct Struct_Obj_Entry *obj,
     const Elf_Rel *rel);
diff --git a/libexec/rtld-elf/riscv/rtld_machdep.h b/libexec/rtld-elf/riscv/rtld_machdep.h
index 023245fbe6a4..814840790902 100644
--- a/libexec/rtld-elf/riscv/rtld_machdep.h
+++ b/libexec/rtld-elf/riscv/rtld_machdep.h
@@ -52,6 +52,9 @@ uint64_t set_gp(struct Struct_Obj_Entry *obj);
 	(const Elf_Dyn *)_dynamic_addr;                                 \
 })
 
+/* No architecture specific notes */
+#define	arch_digest_note(obj, note)	false
+
 Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
     const struct Struct_Obj_Entry *defobj, const struct Struct_Obj_Entry *obj,
     const Elf_Rel *rel);
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index ad0e426f2f0e..a46cbe4e59c8 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -1729,6 +1729,9 @@ digest_notes(Obj_Entry *obj, Elf_Addr note_start, Elf_Addr note_end)
 	    note = (const Elf_Note *)((const char *)(note + 1) +
 	      roundup2(note->n_namesz, sizeof(Elf32_Addr)) +
 	      roundup2(note->n_descsz, sizeof(Elf32_Addr)))) {
+		if (arch_digest_note(obj, note))
+			continue;
+
 		if (note->n_namesz != sizeof(NOTE_FREEBSD_VENDOR) ||
 		    note->n_descsz != sizeof(int32_t))
 			continue;