mbox series

[v2,0/8] add support for relative references in jump tables

Message ID 20180702181145.4799-1-ard.biesheuvel@linaro.org
Headers show
Series add support for relative references in jump tables | expand

Message

Ard Biesheuvel July 2, 2018, 6:11 p.m. UTC
This series implements support for emitting the data structures associated
with jump tables as 32-bit relative references instead of absolute
references, which take up more space on builds that target 64-bit
architectures, or implement self relocation [or both].

This series enables it for arm64 and x86, although other architectures
might benefit as well.

Patch #1 does some preparatory refactoring before patch #2 introduces the
generic pieces required for using relative references.

Patch #3 wires everything up for arm64.

Patch #4 introduces support for handling 64-bit place relative relocations
on x86_64 (see 'Changes since v1' below)

For x86, patch #5 applies some preparatory changes for the arch specific
jump label C code, which is a lot more involved than on arm64, which is
why it is split off in this case. Patch #6 wires it up for x86 as well.

Patch #7 and #8 implement the changes so that the jump_entry arrays reside
in ro_after_init memory rather than remain fully writable all of the time.

Changes since v1:
- change the relative reference to the static key to a 64-bit wide one on 64
  bit architectures; this is necessary on arm64, which allows modules to
  reside anywhere within a 4 GB window covering the core kernel text, which
  means a 32-bit signed quantity with its +/- 2 GB range is insufficient.
  Note that x86_64 changes are in preparation that widen the relocation
  range as well (using the PIE linker), so I assumed that the same change
  is appropriate for x86 as well.
- add patch #4 to handle the relocations emitted by the compiler as a result
  of the change above
- added patches to move the jump_entry arrays to ro_after_init memory, so
  that they are not as easily corrupted or manipulated.
- add Will's ack to patch #3

Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Ingo Molnar <mingo@redhat.com> 
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Jessica Yu <jeyu@kernel.org> 
Cc: Peter Zijlstra <peterz@infradead.org>

Ard Biesheuvel (8):
  kernel/jump_label: abstract jump_entry member accessors
  kernel/jump_label: implement generic support for relative references
  arm64/kernel: jump_label: switch to relative references
  x86: add support for 64-bit place relative relocations
  x86: jump_label: switch to jump_entry accessors
  x86/kernel: jump_table: use relative references
  jump_label: annotate entries that operate on __init code earlier
  jump_table: move entries into ro_after_init region

 arch/Kconfig                        |   3 +
 arch/arm/kernel/vmlinux-xip.lds.S   |   1 +
 arch/arm64/Kconfig                  |   1 +
 arch/arm64/include/asm/jump_label.h |  36 ++++---
 arch/arm64/kernel/jump_label.c      |   6 +-
 arch/s390/kernel/vmlinux.lds.S      |   1 +
 arch/x86/Kconfig                    |   1 +
 arch/x86/include/asm/elf.h          |   1 +
 arch/x86/include/asm/jump_label.h   |  24 ++---
 arch/x86/kernel/jump_label.c        |  62 +++++-------
 arch/x86/kernel/machine_kexec_64.c  |   4 +
 arch/x86/kernel/module.c            |   6 ++
 arch/x86/tools/relocs.c             |  10 ++
 include/asm-generic/vmlinux.lds.h   |  11 ++-
 include/linux/jump_label.h          |  65 ++++++++++++-
 init/main.c                         |   1 -
 kernel/jump_label.c                 | 100 +++++++++-----------
 kernel/module.c                     |   9 ++
 tools/objtool/special.c             |   4 +-
 19 files changed, 205 insertions(+), 141 deletions(-)

-- 
2.17.1

Comments

Heiko Carstens July 4, 2018, 7:59 a.m. UTC | #1
On Mon, Jul 02, 2018 at 08:11:37PM +0200, Ard Biesheuvel wrote:
> This series implements support for emitting the data structures associated

> with jump tables as 32-bit relative references instead of absolute

> references, which take up more space on builds that target 64-bit

> architectures, or implement self relocation [or both].

> 

> This series enables it for arm64 and x86, although other architectures

> might benefit as well.


Hello Ard,

feel free to add the patch below which adds support for s390 to your series.

> Changes since v1:

> - change the relative reference to the static key to a 64-bit wide one on 64

>   bit architectures; this is necessary on arm64, which allows modules to

>   reside anywhere within a 4 GB window covering the core kernel text, which

>   means a 32-bit signed quantity with its +/- 2 GB range is insufficient.

>   Note that x86_64 changes are in preparation that widen the relocation

>   range as well (using the PIE linker), so I assumed that the same change

>   is appropriate for x86 as well.


FWIW, kernel modules on s390 are since ages more than 2GB away from the
core kernel text. So this is required for s390 as well.

From 77d87236f3d5474f33c25534d8ba2c7c54c88c55 Mon Sep 17 00:00:00 2001
From: Heiko Carstens <heiko.carstens@de.ibm.com>

Date: Wed, 4 Jul 2018 09:13:37 +0200
Subject: [PATCH] s390/jump_label: switch to relative references

Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>

---
 arch/s390/Kconfig                  |  1 +
 arch/s390/include/asm/jump_label.h | 40 +++++++++++++++-----------------------
 arch/s390/kernel/jump_label.c      | 11 ++++++-----
 3 files changed, 23 insertions(+), 29 deletions(-)

diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index baed39772c84..0349fb06a2ec 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -121,6 +121,7 @@ config S390
 	select HAVE_ALIGNED_STRUCT_PAGE if SLUB
 	select HAVE_ARCH_AUDITSYSCALL
 	select HAVE_ARCH_JUMP_LABEL
+	select HAVE_ARCH_JUMP_LABEL_RELATIVE
 	select CPU_NO_EFFICIENT_FFS if !HAVE_MARCH_Z9_109_FEATURES
 	select HAVE_ARCH_SECCOMP_FILTER
 	select HAVE_ARCH_SOFT_DIRTY
diff --git a/arch/s390/include/asm/jump_label.h b/arch/s390/include/asm/jump_label.h
index 40f651292aa7..e2d3e6c43395 100644
--- a/arch/s390/include/asm/jump_label.h
+++ b/arch/s390/include/asm/jump_label.h
@@ -14,41 +14,33 @@
  * We use a brcl 0,2 instruction for jump labels at compile time so it
  * can be easily distinguished from a hotpatch generated instruction.
  */
-static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
+static inline bool arch_static_branch(struct static_key *key, bool branch)
 {
-	asm_volatile_goto("0:	brcl 0,"__stringify(JUMP_LABEL_NOP_OFFSET)"\n"
-		".pushsection __jump_table, \"aw\"\n"
-		".balign 8\n"
-		".quad 0b, %l[label], %0\n"
-		".popsection\n"
-		: : "X" (&((char *)key)[branch]) : : label);
-
+	asm_volatile_goto("0:	brcl	0,"__stringify(JUMP_LABEL_NOP_OFFSET)"\n"
+			  ".pushsection __jump_table,\"aw\"\n"
+			  ".balign	8\n"
+			  ".long	0b-.,%l[label]-.\n"
+			  ".quad	%0-.\n"
+			  ".popsection\n"
+			  : : "X" (&((char *)key)[branch]) : : label);
 	return false;
 label:
 	return true;
 }
 
-static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
+static inline bool arch_static_branch_jump(struct static_key *key, bool branch)
 {
-	asm_volatile_goto("0:	brcl 15, %l[label]\n"
-		".pushsection __jump_table, \"aw\"\n"
-		".balign 8\n"
-		".quad 0b, %l[label], %0\n"
-		".popsection\n"
-		: : "X" (&((char *)key)[branch]) : : label);
-
+	asm_volatile_goto("0:	brcl 15,%l[label]\n"
+			  ".pushsection __jump_table,\"aw\"\n"
+			  ".balign	8\n"
+			  ".long	0b-.,%l[label]-.\n"
+			  ".quad	%0-.\n"
+			  ".popsection\n"
+			  : : "X" (&((char *)key)[branch]) : : label);
 	return false;
 label:
 	return true;
 }
 
-typedef unsigned long jump_label_t;
-
-struct jump_entry {
-	jump_label_t code;
-	jump_label_t target;
-	jump_label_t key;
-};
-
 #endif  /* __ASSEMBLY__ */
 #endif
diff --git a/arch/s390/kernel/jump_label.c b/arch/s390/kernel/jump_label.c
index 43f8430fb67d..50a1798604a8 100644
--- a/arch/s390/kernel/jump_label.c
+++ b/arch/s390/kernel/jump_label.c
@@ -33,13 +33,13 @@ static void jump_label_make_branch(struct jump_entry *entry, struct insn *insn)
 {
 	/* brcl 15,offset */
 	insn->opcode = 0xc0f4;
-	insn->offset = (entry->target - entry->code) >> 1;
+	insn->offset = (jump_entry_target(entry) - jump_entry_code(entry)) >> 1;
 }
 
 static void jump_label_bug(struct jump_entry *entry, struct insn *expected,
 			   struct insn *new)
 {
-	unsigned char *ipc = (unsigned char *)entry->code;
+	unsigned char *ipc = (unsigned char *)jump_entry_code(entry);
 	unsigned char *ipe = (unsigned char *)expected;
 	unsigned char *ipn = (unsigned char *)new;
 
@@ -59,6 +59,7 @@ static void __jump_label_transform(struct jump_entry *entry,
 				   enum jump_label_type type,
 				   int init)
 {
+	void *code = (void *)jump_entry_code(entry);
 	struct insn old, new;
 
 	if (type == JUMP_LABEL_JMP) {
@@ -69,13 +70,13 @@ static void __jump_label_transform(struct jump_entry *entry,
 		jump_label_make_nop(entry, &new);
 	}
 	if (init) {
-		if (memcmp((void *)entry->code, &orignop, sizeof(orignop)))
+		if (memcmp(code, &orignop, sizeof(orignop)))
 			jump_label_bug(entry, &orignop, &new);
 	} else {
-		if (memcmp((void *)entry->code, &old, sizeof(old)))
+		if (memcmp(code, &old, sizeof(old)))
 			jump_label_bug(entry, &old, &new);
 	}
-	s390_kernel_write((void *)entry->code, &new, sizeof(new));
+	s390_kernel_write(code, &new, sizeof(new));
 }
 
 static int __sm_arch_jump_label_transform(void *data)
-- 
2.16.4
Ard Biesheuvel July 4, 2018, 8:50 a.m. UTC | #2
On 4 July 2018 at 09:59, Heiko Carstens <heiko.carstens@de.ibm.com> wrote:
> On Mon, Jul 02, 2018 at 08:11:37PM +0200, Ard Biesheuvel wrote:

>> This series implements support for emitting the data structures associated

>> with jump tables as 32-bit relative references instead of absolute

>> references, which take up more space on builds that target 64-bit

>> architectures, or implement self relocation [or both].

>>

>> This series enables it for arm64 and x86, although other architectures

>> might benefit as well.

>

> Hello Ard,

>

> feel free to add the patch below which adds support for s390 to your series.

>


Thanks, I will incorporate it into v3 and beyond.

>> Changes since v1:

>> - change the relative reference to the static key to a 64-bit wide one on 64

>>   bit architectures; this is necessary on arm64, which allows modules to

>>   reside anywhere within a 4 GB window covering the core kernel text, which

>>   means a 32-bit signed quantity with its +/- 2 GB range is insufficient.

>>   Note that x86_64 changes are in preparation that widen the relocation

>>   range as well (using the PIE linker), so I assumed that the same change

>>   is appropriate for x86 as well.

>

> FWIW, kernel modules on s390 are since ages more than 2GB away from the

> core kernel text. So this is required for s390 as well.

>


OK, good to know.

-- 
Ard.


> From 77d87236f3d5474f33c25534d8ba2c7c54c88c55 Mon Sep 17 00:00:00 2001

> From: Heiko Carstens <heiko.carstens@de.ibm.com>

> Date: Wed, 4 Jul 2018 09:13:37 +0200

> Subject: [PATCH] s390/jump_label: switch to relative references

>

> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>

> ---

>  arch/s390/Kconfig                  |  1 +

>  arch/s390/include/asm/jump_label.h | 40 +++++++++++++++-----------------------

>  arch/s390/kernel/jump_label.c      | 11 ++++++-----

>  3 files changed, 23 insertions(+), 29 deletions(-)

>

> diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig

> index baed39772c84..0349fb06a2ec 100644

> --- a/arch/s390/Kconfig

> +++ b/arch/s390/Kconfig

> @@ -121,6 +121,7 @@ config S390

>         select HAVE_ALIGNED_STRUCT_PAGE if SLUB

>         select HAVE_ARCH_AUDITSYSCALL

>         select HAVE_ARCH_JUMP_LABEL

> +       select HAVE_ARCH_JUMP_LABEL_RELATIVE

>         select CPU_NO_EFFICIENT_FFS if !HAVE_MARCH_Z9_109_FEATURES

>         select HAVE_ARCH_SECCOMP_FILTER

>         select HAVE_ARCH_SOFT_DIRTY

> diff --git a/arch/s390/include/asm/jump_label.h b/arch/s390/include/asm/jump_label.h

> index 40f651292aa7..e2d3e6c43395 100644

> --- a/arch/s390/include/asm/jump_label.h

> +++ b/arch/s390/include/asm/jump_label.h

> @@ -14,41 +14,33 @@

>   * We use a brcl 0,2 instruction for jump labels at compile time so it

>   * can be easily distinguished from a hotpatch generated instruction.

>   */

> -static __always_inline bool arch_static_branch(struct static_key *key, bool branch)

> +static inline bool arch_static_branch(struct static_key *key, bool branch)

>  {

> -       asm_volatile_goto("0:   brcl 0,"__stringify(JUMP_LABEL_NOP_OFFSET)"\n"

> -               ".pushsection __jump_table, \"aw\"\n"

> -               ".balign 8\n"

> -               ".quad 0b, %l[label], %0\n"

> -               ".popsection\n"

> -               : : "X" (&((char *)key)[branch]) : : label);

> -

> +       asm_volatile_goto("0:   brcl    0,"__stringify(JUMP_LABEL_NOP_OFFSET)"\n"

> +                         ".pushsection __jump_table,\"aw\"\n"

> +                         ".balign      8\n"

> +                         ".long        0b-.,%l[label]-.\n"

> +                         ".quad        %0-.\n"

> +                         ".popsection\n"

> +                         : : "X" (&((char *)key)[branch]) : : label);

>         return false;

>  label:

>         return true;

>  }

>

> -static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)

> +static inline bool arch_static_branch_jump(struct static_key *key, bool branch)

>  {

> -       asm_volatile_goto("0:   brcl 15, %l[label]\n"

> -               ".pushsection __jump_table, \"aw\"\n"

> -               ".balign 8\n"

> -               ".quad 0b, %l[label], %0\n"

> -               ".popsection\n"

> -               : : "X" (&((char *)key)[branch]) : : label);

> -

> +       asm_volatile_goto("0:   brcl 15,%l[label]\n"

> +                         ".pushsection __jump_table,\"aw\"\n"

> +                         ".balign      8\n"

> +                         ".long        0b-.,%l[label]-.\n"

> +                         ".quad        %0-.\n"

> +                         ".popsection\n"

> +                         : : "X" (&((char *)key)[branch]) : : label);

>         return false;

>  label:

>         return true;

>  }

>

> -typedef unsigned long jump_label_t;

> -

> -struct jump_entry {

> -       jump_label_t code;

> -       jump_label_t target;

> -       jump_label_t key;

> -};

> -

>  #endif  /* __ASSEMBLY__ */

>  #endif

> diff --git a/arch/s390/kernel/jump_label.c b/arch/s390/kernel/jump_label.c

> index 43f8430fb67d..50a1798604a8 100644

> --- a/arch/s390/kernel/jump_label.c

> +++ b/arch/s390/kernel/jump_label.c

> @@ -33,13 +33,13 @@ static void jump_label_make_branch(struct jump_entry *entry, struct insn *insn)

>  {

>         /* brcl 15,offset */

>         insn->opcode = 0xc0f4;

> -       insn->offset = (entry->target - entry->code) >> 1;

> +       insn->offset = (jump_entry_target(entry) - jump_entry_code(entry)) >> 1;

>  }

>

>  static void jump_label_bug(struct jump_entry *entry, struct insn *expected,

>                            struct insn *new)

>  {

> -       unsigned char *ipc = (unsigned char *)entry->code;

> +       unsigned char *ipc = (unsigned char *)jump_entry_code(entry);

>         unsigned char *ipe = (unsigned char *)expected;

>         unsigned char *ipn = (unsigned char *)new;

>

> @@ -59,6 +59,7 @@ static void __jump_label_transform(struct jump_entry *entry,

>                                    enum jump_label_type type,

>                                    int init)

>  {

> +       void *code = (void *)jump_entry_code(entry);

>         struct insn old, new;

>

>         if (type == JUMP_LABEL_JMP) {

> @@ -69,13 +70,13 @@ static void __jump_label_transform(struct jump_entry *entry,

>                 jump_label_make_nop(entry, &new);

>         }

>         if (init) {

> -               if (memcmp((void *)entry->code, &orignop, sizeof(orignop)))

> +               if (memcmp(code, &orignop, sizeof(orignop)))

>                         jump_label_bug(entry, &orignop, &new);

>         } else {

> -               if (memcmp((void *)entry->code, &old, sizeof(old)))

> +               if (memcmp(code, &old, sizeof(old)))

>                         jump_label_bug(entry, &old, &new);

>         }

> -       s390_kernel_write((void *)entry->code, &new, sizeof(new));

> +       s390_kernel_write(code, &new, sizeof(new));

>  }

>

>  static int __sm_arch_jump_label_transform(void *data)

> --

> 2.16.4

>
Kees Cook Sept. 13, 2018, 9:40 p.m. UTC | #3
On Wed, Jul 4, 2018 at 1:50 AM, Ard Biesheuvel
<ard.biesheuvel@linaro.org> wrote:
> On 4 July 2018 at 09:59, Heiko Carstens <heiko.carstens@de.ibm.com> wrote:

>> On Mon, Jul 02, 2018 at 08:11:37PM +0200, Ard Biesheuvel wrote:

>>> This series implements support for emitting the data structures associated

>>> with jump tables as 32-bit relative references instead of absolute

>>> references, which take up more space on builds that target 64-bit

>>> architectures, or implement self relocation [or both].

>>>

>>> This series enables it for arm64 and x86, although other architectures

>>> might benefit as well.

>>

>> Hello Ard,

>>

>> feel free to add the patch below which adds support for s390 to your series.

>>

>

> Thanks, I will incorporate it into v3 and beyond.


Just a quick status check! :) What're your plans for this series? I'd
still love to see it.

-Kees

-- 
Kees Cook
Pixel Security