Unverified Commit e3f16d63 authored by Alexandre Ghiti's avatar Alexandre Ghiti Committed by Palmer Dabbelt
Browse files

riscv: ftrace: Properly acquire text_mutex to fix a race condition



As reported by lockdep, some patching was done without acquiring
text_mutex, so there could be a race when mapping the page to patch
since we use the same fixmap entry.

Reported-by: default avatarHan Gao <rabenda.cn@gmail.com>
Reported-by: default avatarVivian Wang <wangruikang@iscas.ac.cn>
Reported-by: default avatarYao Zi <ziyao@disroot.org>
Closes: https://lore.kernel.org/linux-riscv/aGODMpq7TGINddzM@pie.lan/


Tested-by: default avatarYao Zi <ziyao@disroot.org>
Tested-by: default avatarHan Gao <rabenda.cn@gmail.com>
Reviewed-by: default avatarMasami Hiramatsu (Google) <mhiramat@kernel.org>
Signed-off-by: default avatarAlexandre Ghiti <alexghiti@rivosinc.com>
Link: https://lore.kernel.org/r/20250711-alex-fixes-v2-1-d85a5438da6c@rivosinc.com


Signed-off-by: default avatarPalmer Dabbelt <palmer@dabbelt.com>
parent 16d74360
Loading
Loading
Loading
Loading
+14 −4
Original line number Diff line number Diff line
@@ -14,6 +14,18 @@
#include <asm/text-patching.h>

#ifdef CONFIG_DYNAMIC_FTRACE
void ftrace_arch_code_modify_prepare(void)
	__acquires(&text_mutex)
{
	mutex_lock(&text_mutex);
}

void ftrace_arch_code_modify_post_process(void)
	__releases(&text_mutex)
{
	mutex_unlock(&text_mutex);
}

unsigned long ftrace_call_adjust(unsigned long addr)
{
	if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS))
@@ -29,10 +41,8 @@ unsigned long arch_ftrace_get_symaddr(unsigned long fentry_ip)

void arch_ftrace_update_code(int command)
{
	mutex_lock(&text_mutex);
	command |= FTRACE_MAY_SLEEP;
	ftrace_modify_all_code(command);
	mutex_unlock(&text_mutex);
	flush_icache_all();
}

@@ -149,6 +159,8 @@ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec)
	unsigned int nops[2], offset;
	int ret;

	guard(mutex)(&text_mutex);

	ret = ftrace_rec_set_nop_ops(rec);
	if (ret)
		return ret;
@@ -157,9 +169,7 @@ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec)
	nops[0] = to_auipc_t0(offset);
	nops[1] = RISCV_INSN_NOP4;

	mutex_lock(&text_mutex);
	ret = patch_insn_write((void *)pc, nops, 2 * MCOUNT_INSN_SIZE);
	mutex_unlock(&text_mutex);

	return ret;
}