]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
elf: Allow arch to tweak initial mmap prot flags
authorDave Martin <Dave.Martin@arm.com>
Mon, 16 Mar 2020 16:50:46 +0000 (16:50 +0000)
committerCatalin Marinas <catalin.marinas@arm.com>
Mon, 16 Mar 2020 17:19:48 +0000 (17:19 +0000)
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: Mark Brown <broonie@kernel.org>
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
fs/Kconfig.binfmt
fs/binfmt_elf.c
include/linux/elf.h

index d2cfe0729a73fe77eb6870a764d7cacf16e10f8c..2358368319b8a0e10e805b6b80e94fc311e3df36 100644 (file)
@@ -36,6 +36,9 @@ config COMPAT_BINFMT_ELF
 config ARCH_BINFMT_ELF_STATE
        bool
 
+config ARCH_HAVE_ELF_PROT
+       bool
+
 config ARCH_USE_GNU_PROPERTY
        bool
 
index 1fb67e506b68b90ec80d53c69af8381aed933689..cceb29d6ef1d9ff14c0f4eab0b811fee1c0db786 100644 (file)
@@ -544,7 +544,8 @@ static inline int arch_check_elf(struct elfhdr *ehdr, bool has_interp,
 
 #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;
 
@@ -554,7 +555,8 @@ static inline int make_prot(u32 p_flags)
                prot |= PROT_WRITE;
        if (p_flags & PF_X)
                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,
@@ -564,7 +566,8 @@ static inline int make_prot(u32 p_flags)
 
 static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
                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;
        unsigned long load_addr = 0;
@@ -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++) {
                if (eppnt->p_type == PT_LOAD) {
                        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 k, map_addr;
 
@@ -1041,7 +1045,8 @@ out_free_interp:
                        }
                }
 
-               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;
 
@@ -1184,7 +1189,8 @@ out_free_interp:
        if (interpreter) {
                elf_entry = load_elf_interp(&loc->interp_elf_ex,
                                            interpreter,
-                                           load_bias, interp_elf_phdata);
+                                           load_bias, interp_elf_phdata,
+                                           &arch_state);
                if (!IS_ERR((void *)elf_entry)) {
                        /*
                         * load_elf_interp() returns relocation
index db5113479f5e9398bce2f1b135d765509c17fc20..5d5b0321da0bd81db3afa2bbe802252ca7e58a94 100644 (file)
@@ -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);
 #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 */