Merge tag 'riscv-for-linus-5.17-rc8' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 11 Mar 2022 20:28:21 +0000 (12:28 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 11 Mar 2022 20:28:21 +0000 (12:28 -0800)
Pull RISC-V fixes from Palmer Dabbelt:

 - prevent users from enabling the alternatives framework (and thus
   errata handling) on XIP kernels, where runtime code patching does not
   function correctly.

 - properly detect offset overflow for AUIPC-based relocations in
   modules. This may manifest as modules calling arbitrary invalid
   addresses, depending on the address allocated when a module is
   loaded.

* tag 'riscv-for-linus-5.17-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux:
  riscv: Fix auipc+jalr relocation range checks
  riscv: alternative only works on !XIP_KERNEL

arch/riscv/Kconfig.erratas
arch/riscv/Kconfig.socs
arch/riscv/kernel/module.c

index b44d6ec..0aacd70 100644 (file)
@@ -2,6 +2,7 @@ menu "CPU errata selection"
 
 config RISCV_ERRATA_ALTERNATIVE
        bool "RISC-V alternative scheme"
+       depends on !XIP_KERNEL
        default y
        help
          This Kconfig allows the kernel to automatically patch the
index 6ec44a2..c112ab2 100644 (file)
@@ -14,8 +14,8 @@ config SOC_SIFIVE
        select CLK_SIFIVE
        select CLK_SIFIVE_PRCI
        select SIFIVE_PLIC
-       select RISCV_ERRATA_ALTERNATIVE
-       select ERRATA_SIFIVE
+       select RISCV_ERRATA_ALTERNATIVE if !XIP_KERNEL
+       select ERRATA_SIFIVE if !XIP_KERNEL
        help
          This enables support for SiFive SoC platform hardware.
 
index 68a9e3d..4a48287 100644 (file)
 #include <linux/pgtable.h>
 #include <asm/sections.h>
 
+/*
+ * The auipc+jalr instruction pair can reach any PC-relative offset
+ * in the range [-2^31 - 2^11, 2^31 - 2^11)
+ */
+static bool riscv_insn_valid_32bit_offset(ptrdiff_t val)
+{
+#ifdef CONFIG_32BIT
+       return true;
+#else
+       return (-(1L << 31) - (1L << 11)) <= val && val < ((1L << 31) - (1L << 11));
+#endif
+}
+
 static int apply_r_riscv_32_rela(struct module *me, u32 *location, Elf_Addr v)
 {
        if (v != (u32)v) {
@@ -95,7 +108,7 @@ static int apply_r_riscv_pcrel_hi20_rela(struct module *me, u32 *location,
        ptrdiff_t offset = (void *)v - (void *)location;
        s32 hi20;
 
-       if (offset != (s32)offset) {
+       if (!riscv_insn_valid_32bit_offset(offset)) {
                pr_err(
                  "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n",
                  me->name, (long long)v, location);
@@ -197,10 +210,9 @@ static int apply_r_riscv_call_plt_rela(struct module *me, u32 *location,
                                       Elf_Addr v)
 {
        ptrdiff_t offset = (void *)v - (void *)location;
-       s32 fill_v = offset;
        u32 hi20, lo12;
 
-       if (offset != fill_v) {
+       if (!riscv_insn_valid_32bit_offset(offset)) {
                /* Only emit the plt entry if offset over 32-bit range */
                if (IS_ENABLED(CONFIG_MODULE_SECTIONS)) {
                        offset = module_emit_plt_entry(me, v);
@@ -224,10 +236,9 @@ static int apply_r_riscv_call_rela(struct module *me, u32 *location,
                                   Elf_Addr v)
 {
        ptrdiff_t offset = (void *)v - (void *)location;
-       s32 fill_v = offset;
        u32 hi20, lo12;
 
-       if (offset != fill_v) {
+       if (!riscv_insn_valid_32bit_offset(offset)) {
                pr_err(
                  "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n",
                  me->name, (long long)v, location);