Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 30b9da0e authored by Will Deacon's avatar Will Deacon Committed by Greg Kroah-Hartman
Browse files

arm64: ftrace: Ensure module ftrace trampoline is coherent with I-side



commit b6143d10d23ebb4a77af311e8b8b7f019d0163e6 upstream.

The initial support for dynamic ftrace trampolines in modules made use
of an indirect branch which loaded its target from the beginning of
a special section (e71a4e1b ("arm64: ftrace: add support for far
branches to dynamic ftrace")). Since no instructions were being patched,
no cache maintenance was needed. However, later in be0f272b ("arm64:
ftrace: emit ftrace-mod.o contents through code") this code was reworked
to output the trampoline instructions directly into the PLT entry but,
unfortunately, the necessary cache maintenance was overlooked.

Add a call to __flush_icache_range() after writing the new trampoline
instructions but before patching in the branch to the trampoline.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: James Morse <james.morse@arm.com>
Cc: <stable@vger.kernel.org>
Fixes: be0f272b ("arm64: ftrace: emit ftrace-mod.o contents through code")
Signed-off-by: default avatarWill Deacon <will@kernel.org>
Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent a1cd2f70
Loading
Loading
Loading
Loading
+12 −9
Original line number Diff line number Diff line
@@ -76,7 +76,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)

	if (offset < -SZ_128M || offset >= SZ_128M) {
#ifdef CONFIG_ARM64_MODULE_PLTS
		struct plt_entry trampoline;
		struct plt_entry trampoline, *dst;
		struct module *mod;

		/*
@@ -104,24 +104,27 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
		 * is added in the future, but for now, the pr_err() below
		 * deals with a theoretical issue only.
		 */
		dst = mod->arch.ftrace_trampoline;
		trampoline = get_plt_entry(addr);
		if (!plt_entries_equal(mod->arch.ftrace_trampoline,
				       &trampoline)) {
			if (!plt_entries_equal(mod->arch.ftrace_trampoline,
					       &(struct plt_entry){})) {
		if (!plt_entries_equal(dst, &trampoline)) {
			if (!plt_entries_equal(dst, &(struct plt_entry){})) {
				pr_err("ftrace: far branches to multiple entry points unsupported inside a single module\n");
				return -EINVAL;
			}

			/* point the trampoline to our ftrace entry point */
			module_disable_ro(mod);
			*mod->arch.ftrace_trampoline = trampoline;
			*dst = trampoline;
			module_enable_ro(mod, true);

			/* update trampoline before patching in the branch */
			smp_wmb();
			/*
			 * Ensure updated trampoline is visible to instruction
			 * fetch before we patch in the branch.
			 */
			__flush_icache_range((unsigned long)&dst[0],
					     (unsigned long)&dst[1]);
		}
		addr = (unsigned long)(void *)mod->arch.ftrace_trampoline;
		addr = (unsigned long)dst;
#else /* CONFIG_ARM64_MODULE_PLTS */
		return -EINVAL;
#endif /* CONFIG_ARM64_MODULE_PLTS */