ARM: PIE: Add position independent executable embedding to ARM
authorRuss Dill <Russ.Dill@ti.com>
Tue, 17 Sep 2013 09:55:15 +0000 (02:55 -0700)
committer黄涛 <huangtao@rock-chips.com>
Thu, 21 Nov 2013 05:39:21 +0000 (13:39 +0800)
Add support to ARM for embedding PIEs into the kernel, loading them into
genalloc pools (such as SRAM) and executing them. Support for ARM means
performing R_ARM_RELATIVE fixups within the .rel.dyn section.

Signed-off-by: Russ Dill <Russ.Dill@ti.com>
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/include/asm/elf.h
arch/arm/kernel/.gitignore
arch/arm/kernel/Makefile
arch/arm/kernel/pie.c [new file with mode: 0644]
arch/arm/kernel/pie.lds.S [new file with mode: 0644]
arch/arm/kernel/vmlinux.lds.S
arch/arm/libpie/.gitignore [new file with mode: 0644]
arch/arm/libpie/Makefile [new file with mode: 0644]
arch/arm/libpie/empty.S [new file with mode: 0644]

index 02b9bf9268dd95f1d712dff4285a3998c5f009df..2092322106d0731422cb089e8031d65046b39cf7 100644 (file)
@@ -47,6 +47,7 @@ config ARM
        select HAVE_MEMBLOCK
        select HAVE_OPROFILE if (HAVE_PERF_EVENTS)
        select HAVE_PERF_EVENTS
+       select HAVE_PIE
        select HAVE_REGS_AND_STACK_ACCESS_API
        select HAVE_SYSCALL_TRACEPOINTS
        select HAVE_UID16
index 883e4bec807fe3614a767de19b21783e93b11cfd..4b5ff1e590ddc08011fe6402ab2a76e0f3d98bed 100644 (file)
@@ -121,6 +121,8 @@ KBUILD_AFLAGS       +=$(CFLAGS_ABI) $(AFLAGS_ISA) $(arch-y) $(tune-y) -include asm/uni
 
 CHECKFLAGS     += -D__arm__
 
+OBJCOPY_OUTPUT_FORMAT := elf32-littlearm
+
 #Default value
 head-y         := arch/arm/kernel/head$(MMUEXT).o
 textofs-y      := 0x00008000
@@ -261,6 +263,9 @@ drivers-$(CONFIG_OPROFILE)      += arch/arm/oprofile/
 
 libs-y                         := arch/arm/lib/ $(libs-y)
 
+PIE_LDS                                := arch/arm/kernel/pie.lds
+libpie-$(CONFIG_PIE)           += arch/arm/libpie/
+
 # Default target when executing plain make
 ifeq ($(CONFIG_XIP_KERNEL),y)
 KBUILD_IMAGE := xipImage
index 56211f2084ef871841215a0c4adfec6f778689d3..a8d036b482de5699a9f4e23593bf221a6510dfa6 100644 (file)
@@ -50,6 +50,7 @@ typedef struct user_fp elf_fpregset_t;
 #define R_ARM_NONE             0
 #define R_ARM_PC24             1
 #define R_ARM_ABS32            2
+#define R_ARM_RELATIVE         23
 #define R_ARM_CALL             28
 #define R_ARM_JUMP24           29
 #define R_ARM_V4BX             40
index c5f676c3c224b67afb51c50589e82fbf6d333c46..a055a4811aa801f3a0ee086e032aed37af143199 100644 (file)
@@ -1 +1,2 @@
 vmlinux.lds
+pie.lds
index dd9d90ab65d0cd7975031c0d67bf2cb8d1aefbb7..609536d9426632c9d1a610184fe598cad388445f 100644 (file)
@@ -87,4 +87,6 @@ obj-y                         += psci.o
 obj-$(CONFIG_SMP)              += psci_smp.o
 endif
 
-extra-y := $(head-y) vmlinux.lds
+obj-$(CONFIG_PIE)              += pie.o
+
+extra-y := $(head-y) vmlinux.lds pie.lds
diff --git a/arch/arm/kernel/pie.c b/arch/arm/kernel/pie.c
new file mode 100644 (file)
index 0000000..5dff5d6
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2013 Texas Instruments, Inc.
+ *     Russ Dill <russ.dill@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pie.h>
+#include <linux/elf.h>
+
+#include <asm/elf.h>
+
+extern char __pie_rel_dyn_start[];
+extern char __pie_rel_dyn_end[];
+extern char __pie_tail_offset[];
+
+struct arm_pie_tail {
+       int count;
+       uintptr_t offset[0];
+};
+
+int pie_arch_fill_tail(void *tail, void *common_start, void *common_end,
+                       void *overlay_start, void *code_start, void *code_end)
+{
+       Elf32_Rel *rel;
+       int records;
+       int i;
+       struct arm_pie_tail *pie_tail = tail;
+       int count;
+
+       rel = (Elf32_Rel *) __pie_rel_dyn_start;
+       records = (__pie_rel_dyn_end - __pie_rel_dyn_start) /
+                                               sizeof(*rel);
+
+       count = 0;
+       for (i = 0; i < records; i++, rel++) {
+               void *kern_off;
+               if (ELF32_R_TYPE(rel->r_info) != R_ARM_RELATIVE)
+                       return -ENOEXEC;
+
+               /* Adjust offset to match area in kernel */
+               kern_off = common_start + rel->r_offset;
+
+               if (kern_off >= common_start && kern_off < code_end) {
+                       if (tail)
+                               pie_tail->offset[count] = rel->r_offset;
+                       count++;
+               } else if (kern_off >= code_start && kern_off < code_end) {
+                       if (tail)
+                               pie_tail->offset[count] = rel->r_offset -
+                                               (code_start - overlay_start);
+                       count++;
+               }
+       }
+
+       if (tail)
+               pie_tail->count = count;
+
+       return count * sizeof(uintptr_t) + sizeof(*pie_tail);
+}
+EXPORT_SYMBOL_GPL(pie_arch_fill_tail);
+
+/*
+ * R_ARM_RELATIVE: B(S) + A
+ * B(S) - Addressing origin of the output segment defining the symbol S.
+ * A - Addend for the relocation.
+ */
+int pie_arch_fixup(struct pie_chunk *chunk, void *base, void *tail,
+                                               unsigned long offset)
+{
+       struct arm_pie_tail *pie_tail = tail;
+       int i;
+
+       /* Perform relocation fixups for given offset */
+       for (i = 0; i < pie_tail->count; i++)
+               *((uintptr_t *) (pie_tail->offset[i] + base)) += offset;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pie_arch_fixup);
diff --git a/arch/arm/kernel/pie.lds.S b/arch/arm/kernel/pie.lds.S
new file mode 100644 (file)
index 0000000..4fd5ac5
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * ld script to make ARM PIEs
+ * taken from the ARM vmlinux.lds.S version by Russ Dill <russ.dill@ti.com.
+ */
+
+#include <asm-generic/pie.lds.h>
+
+OUTPUT_ARCH(arm)
+
+SECTIONS
+{
+       . = 0x0;
+
+       PIE_COMMON_START
+       .got.plt : {
+               *(.got)
+               *(.got.plt)
+       }
+       .text : {
+               PIE_TEXT_TEXT
+       }
+       PIE_COMMON_END
+
+       PIE_OVERLAY_START
+       OVERLAY : NOCROSSREFS {
+       }
+       PIE_OVERLAY_SEND
+
+       __pie_rel_dyn_start : {
+               VMLINUX_SYMBOL(__pie_rel_dyn_start) = .;
+       }
+       .rel.dyn : {
+               KEEP(*(.rel*))
+       }
+       __pie_rel_dyn_end : {
+               VMLINUX_SYMBOL(__pie_rel_dyn_end) = .;
+       }
+
+       PIE_DISCARDS
+}
index 33f2ea32f5a03602d5fc3c52d1b4d4e108a84ed6..fb1e0d78c285be0c948656b225effb4e376bbf83 100644 (file)
@@ -81,6 +81,8 @@ SECTIONS
 #ifndef CONFIG_SMP_ON_UP
                *(.alt.smp.init)
 #endif
+               *(.pie.*)
+               *(.ARM.exidx.pie.*.text)
                *(.discard)
                *(.discard.*)
        }
diff --git a/arch/arm/libpie/.gitignore b/arch/arm/libpie/.gitignore
new file mode 100644 (file)
index 0000000..02e3cd5
--- /dev/null
@@ -0,0 +1,3 @@
+lib1funcs.S
+ashldi3.S
+string.c
diff --git a/arch/arm/libpie/Makefile b/arch/arm/libpie/Makefile
new file mode 100644 (file)
index 0000000..5662e99
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# linux/arch/arm/libpie/Makefile
+#
+ccflags-y      := -fpic -mno-single-pic-base -fno-builtin
+
+obj-y          := empty.o
+obj-y          += lib1funcs.o ashldi3.o string.o
+
+# string library code (-Os is enforced to keep it much smaller)
+string = $(obj)/string.o
+CFLAGS_string.o := -Os
+
+$(obj)/string.c: $(srctree)/arch/$(SRCARCH)/boot/compressed/string.c
+       $(call cmd,shipped)
+
+# For __aeabi_uidivmod
+lib1funcs = $(obj)/lib1funcs.o
+
+$(obj)/lib1funcs.S: $(srctree)/arch/$(SRCARCH)/lib/lib1funcs.S
+       $(call cmd,shipped)
+
+# For __aeabi_llsl
+ashldi3 = $(obj)/ashldi3.o
+
+$(obj)/ashldi3.S: $(srctree)/arch/$(SRCARCH)/lib/ashldi3.S
+       $(call cmd,shipped)
+
+$(obj)/libpie.o: $(string) $(lib1funcs) $(ashldi3) $(addprefix $(obj)/,$(OBJS))
+       $(call if_changed,ld)
+
+# Make sure files are removed during clean
+extra-y                += string.c lib1funcs.S ashldi3.S
diff --git a/arch/arm/libpie/empty.S b/arch/arm/libpie/empty.S
new file mode 100644 (file)
index 0000000..2416862
--- /dev/null
@@ -0,0 +1,12 @@
+#include <linux/linkage.h>
+
+ENTRY(__div0)
+ENTRY(__aeabi_unwind_cpp_pr0)
+ENTRY(__aeabi_unwind_cpp_pr1)
+ENTRY(__aeabi_unwind_cpp_pr2)
+       mov     pc, lr
+ENDPROC(__div0)
+ENDPROC(__aeabi_unwind_cpp_pr0)
+ENDPROC(__aeabi_unwind_cpp_pr1)
+ENDPROC(__aeabi_unwind_cpp_pr2)
+