Commit 6d4a0fbd authored by Adrian Barnaś's avatar Adrian Barnaś Committed by Will Deacon
Browse files

arm64: Fail module loading if dynamic SCS patching fails



Disallow a module to load if SCS dynamic patching fails for its code. For
module loading, instead of running a dry-run to check for patching errors,
try to run patching in the first run and propagate any errors so module
loading will fail.

Signed-off-by: default avatarAdrian Barnaś <abarnas@google.com>
Reviewed-by: default avatarArd Biesheuvel <ardb@kernel.org>
Signed-off-by: default avatarWill Deacon <will@kernel.org>
parent 7f163573
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -53,7 +53,7 @@ enum {
	EDYNSCS_INVALID_CFA_OPCODE		= 4,
};

int __pi_scs_patch(const u8 eh_frame[], int size);
int __pi_scs_patch(const u8 eh_frame[], int size, bool skip_dry_run);

#endif /* __ASSEMBLY __ */

+10 −2
Original line number Diff line number Diff line
@@ -495,10 +495,18 @@ int module_finalize(const Elf_Ehdr *hdr,
	if (scs_is_dynamic()) {
		s = find_section(hdr, sechdrs, ".init.eh_frame");
		if (s) {
			ret = __pi_scs_patch((void *)s->sh_addr, s->sh_size);
			if (ret)
			/*
			 * Because we can reject modules that are malformed
			 * so SCS patching fails, skip dry run and try to patch
			 * it in place. If patching fails, the module would not
			 * be loaded anyway.
			 */
			ret = __pi_scs_patch((void *)s->sh_addr, s->sh_size, true);
			if (ret) {
				pr_err("module %s: error occurred during dynamic SCS patching (%d)\n",
				       me->name, ret);
				return -ENOEXEC;
			}
		}
	}

+1 −1
Original line number Diff line number Diff line
@@ -104,7 +104,7 @@ static void __init map_kernel(u64 kaslr_offset, u64 va_offset, int root_level)

		if (enable_scs) {
			scs_patch(__eh_frame_start + va_offset,
				  __eh_frame_end - __eh_frame_start);
				  __eh_frame_end - __eh_frame_start, false);
			asm("ic ialluis");

			dynamic_scs_is_enabled = true;
+6 −4
Original line number Diff line number Diff line
@@ -225,7 +225,7 @@ static int scs_handle_fde_frame(const struct eh_frame *frame,
	return 0;
}

int scs_patch(const u8 eh_frame[], int size)
int scs_patch(const u8 eh_frame[], int size, bool skip_dry_run)
{
	int code_alignment_factor = 1;
	bool fde_use_sdata8 = false;
@@ -277,9 +277,11 @@ int scs_patch(const u8 eh_frame[], int size)
			}
		} else {
			ret = scs_handle_fde_frame(frame, code_alignment_factor,
						   fde_use_sdata8, true);
						   fde_use_sdata8, !skip_dry_run);
			if (ret)
				return ret;

			if (!skip_dry_run)
				scs_handle_fde_frame(frame, code_alignment_factor,
						     fde_use_sdata8, false);
		}
+1 −1
Original line number Diff line number Diff line
@@ -27,7 +27,7 @@ extern pgd_t init_pg_dir[], init_pg_end[];
void init_feature_override(u64 boot_status, const void *fdt, int chosen);
u64 kaslr_early_init(void *fdt, int chosen);
void relocate_kernel(u64 offset);
int scs_patch(const u8 eh_frame[], int size);
int scs_patch(const u8 eh_frame[], int size, bool skip_dry_run);

void map_range(phys_addr_t *pte, u64 start, u64 end, phys_addr_t pa,
	       pgprot_t prot, int level, pte_t *tbl, bool may_use_cont,