Commit fe0f6766 authored by Dave Martin's avatar Dave Martin Committed by Catalin Marinas

elf: Allow arch to tweak initial mmap prot flags

An arch may want to tweak the mmap prot flags for an
ELFexecutable's initial mappings.  For example, arm64 is going to
need to add PROT_BTI for executable pages in an ELF process whose
executable is marked as using Branch Target Identification (an
ARMv8.5-A control flow integrity feature).

So that this can be done in a generic way, add a hook
arch_elf_adjust_prot() to modify the prot flags as desired: arches
can select CONFIG_HAVE_ELF_PROT and implement their own backend
where necessary.

By default, leave the prot flags unchanged.
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
Signed-off-by: default avatarDave Martin <Dave.Martin@arm.com>
Reviewed-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
Reviewed-by: default avatarKees Cook <keescook@chromium.org>
Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
parent 8ef8f360
...@@ -36,6 +36,9 @@ config COMPAT_BINFMT_ELF ...@@ -36,6 +36,9 @@ config COMPAT_BINFMT_ELF
config ARCH_BINFMT_ELF_STATE config ARCH_BINFMT_ELF_STATE
bool bool
config ARCH_HAVE_ELF_PROT
bool
config ARCH_USE_GNU_PROPERTY config ARCH_USE_GNU_PROPERTY
bool bool
......
...@@ -544,7 +544,8 @@ static inline int arch_check_elf(struct elfhdr *ehdr, bool has_interp, ...@@ -544,7 +544,8 @@ static inline int arch_check_elf(struct elfhdr *ehdr, bool has_interp,
#endif /* !CONFIG_ARCH_BINFMT_ELF_STATE */ #endif /* !CONFIG_ARCH_BINFMT_ELF_STATE */
static inline int make_prot(u32 p_flags) static inline int make_prot(u32 p_flags, struct arch_elf_state *arch_state,
bool has_interp, bool is_interp)
{ {
int prot = 0; int prot = 0;
...@@ -554,7 +555,8 @@ static inline int make_prot(u32 p_flags) ...@@ -554,7 +555,8 @@ static inline int make_prot(u32 p_flags)
prot |= PROT_WRITE; prot |= PROT_WRITE;
if (p_flags & PF_X) if (p_flags & PF_X)
prot |= PROT_EXEC; prot |= PROT_EXEC;
return prot;
return arch_elf_adjust_prot(prot, arch_state, has_interp, is_interp);
} }
/* This is much more generalized than the library routine read function, /* This is much more generalized than the library routine read function,
...@@ -564,7 +566,8 @@ static inline int make_prot(u32 p_flags) ...@@ -564,7 +566,8 @@ static inline int make_prot(u32 p_flags)
static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
struct file *interpreter, struct file *interpreter,
unsigned long no_base, struct elf_phdr *interp_elf_phdata) unsigned long no_base, struct elf_phdr *interp_elf_phdata,
struct arch_elf_state *arch_state)
{ {
struct elf_phdr *eppnt; struct elf_phdr *eppnt;
unsigned long load_addr = 0; unsigned long load_addr = 0;
...@@ -596,7 +599,8 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, ...@@ -596,7 +599,8 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) { for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) {
if (eppnt->p_type == PT_LOAD) { if (eppnt->p_type == PT_LOAD) {
int elf_type = MAP_PRIVATE | MAP_DENYWRITE; int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
int elf_prot = make_prot(eppnt->p_flags); int elf_prot = make_prot(eppnt->p_flags, arch_state,
true, true);
unsigned long vaddr = 0; unsigned long vaddr = 0;
unsigned long k, map_addr; unsigned long k, map_addr;
...@@ -1041,7 +1045,8 @@ static int load_elf_binary(struct linux_binprm *bprm) ...@@ -1041,7 +1045,8 @@ static int load_elf_binary(struct linux_binprm *bprm)
} }
} }
elf_prot = make_prot(elf_ppnt->p_flags); elf_prot = make_prot(elf_ppnt->p_flags, &arch_state,
!!interpreter, false);
elf_flags = MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE; elf_flags = MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE;
...@@ -1184,7 +1189,8 @@ static int load_elf_binary(struct linux_binprm *bprm) ...@@ -1184,7 +1189,8 @@ static int load_elf_binary(struct linux_binprm *bprm)
if (interpreter) { if (interpreter) {
elf_entry = load_elf_interp(&loc->interp_elf_ex, elf_entry = load_elf_interp(&loc->interp_elf_ex,
interpreter, interpreter,
load_bias, interp_elf_phdata); load_bias, interp_elf_phdata,
&arch_state);
if (!IS_ERR((void *)elf_entry)) { if (!IS_ERR((void *)elf_entry)) {
/* /*
* load_elf_interp() returns relocation * load_elf_interp() returns relocation
......
...@@ -87,4 +87,16 @@ extern int arch_parse_elf_property(u32 type, const void *data, size_t datasz, ...@@ -87,4 +87,16 @@ extern int arch_parse_elf_property(u32 type, const void *data, size_t datasz,
bool compat, struct arch_elf_state *arch); bool compat, struct arch_elf_state *arch);
#endif #endif
#ifdef CONFIG_ARCH_HAVE_ELF_PROT
int arch_elf_adjust_prot(int prot, const struct arch_elf_state *state,
bool has_interp, bool is_interp);
#else
static inline int arch_elf_adjust_prot(int prot,
const struct arch_elf_state *state,
bool has_interp, bool is_interp)
{
return prot;
}
#endif
#endif /* _LINUX_ELF_H */ #endif /* _LINUX_ELF_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment