Commit 77fe1ba9 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'riscv-for-linus-5.17-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux

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
parents 878409ec 0966d385
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+2 −2
Original line number Diff line number Diff line
@@ -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.

+16 −5
Original line number Diff line number Diff line
@@ -13,6 +13,19 @@
#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);