Commit ae4a3160 authored by Menglong Dong's avatar Menglong Dong Committed by Alexei Starovoitov
Browse files

bpf: specify the old and new poke_type for bpf_arch_text_poke



In the origin logic, the bpf_arch_text_poke() assume that the old and new
instructions have the same opcode. However, they can have different opcode
if we want to replace a "call" insn with a "jmp" insn.

Therefore, add the new function parameter "old_t" along with the "new_t",
which are used to indicate the old and new poke type. Meanwhile, adjust
the implement of bpf_arch_text_poke() for all the archs.

"BPF_MOD_NOP" is added to make the code more readable. In
bpf_arch_text_poke(), we still check if the new and old address is NULL to
determine if nop insn should be used, which I think is more safe.

Signed-off-by: default avatarMenglong Dong <dongml2@chinatelecom.cn>
Link: https://lore.kernel.org/r/20251118123639.688444-6-dongml2@chinatelecom.cn


Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 373f2f44
Loading
Loading
Loading
Loading
+7 −7
Original line number Diff line number Diff line
@@ -2934,8 +2934,9 @@ static int gen_branch_or_nop(enum aarch64_insn_branch_type type, void *ip,
 * The dummy_tramp is used to prevent another CPU from jumping to unknown
 * locations during the patching process, making the patching process easier.
 */
int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type,
		       void *old_addr, void *new_addr)
int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type old_t,
		       enum bpf_text_poke_type new_t, void *old_addr,
		       void *new_addr)
{
	int ret;
	u32 old_insn;
@@ -2979,14 +2980,13 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type,
		    !poking_bpf_entry))
		return -EINVAL;

	if (poke_type == BPF_MOD_CALL)
		branch_type = AARCH64_INSN_BRANCH_LINK;
	else
		branch_type = AARCH64_INSN_BRANCH_NOLINK;

	branch_type = old_t == BPF_MOD_CALL ? AARCH64_INSN_BRANCH_LINK :
					      AARCH64_INSN_BRANCH_NOLINK;
	if (gen_branch_or_nop(branch_type, ip, old_addr, plt, &old_insn) < 0)
		return -EFAULT;

	branch_type = new_t == BPF_MOD_CALL ? AARCH64_INSN_BRANCH_LINK :
					      AARCH64_INSN_BRANCH_NOLINK;
	if (gen_branch_or_nop(branch_type, ip, new_addr, plt, &new_insn) < 0)
		return -EFAULT;

+6 −3
Original line number Diff line number Diff line
@@ -1284,11 +1284,12 @@ void *bpf_arch_text_copy(void *dst, void *src, size_t len)
	return ret ? ERR_PTR(-EINVAL) : dst;
}

int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type,
		       void *old_addr, void *new_addr)
int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type old_t,
		       enum bpf_text_poke_type new_t, void *old_addr,
		       void *new_addr)
{
	int ret;
	bool is_call = (poke_type == BPF_MOD_CALL);
	bool is_call;
	u32 old_insns[LOONGARCH_LONG_JUMP_NINSNS] = {[0 ... 4] = INSN_NOP};
	u32 new_insns[LOONGARCH_LONG_JUMP_NINSNS] = {[0 ... 4] = INSN_NOP};

@@ -1298,6 +1299,7 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type,
	if (!is_bpf_text_address((unsigned long)ip))
		return -ENOTSUPP;

	is_call = old_t == BPF_MOD_CALL;
	ret = emit_jump_or_nops(old_addr, ip, old_insns, is_call);
	if (ret)
		return ret;
@@ -1305,6 +1307,7 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type,
	if (memcmp(ip, old_insns, LOONGARCH_LONG_JUMP_NBYTES))
		return -EFAULT;

	is_call = new_t == BPF_MOD_CALL;
	ret = emit_jump_or_nops(new_addr, ip, new_insns, is_call);
	if (ret)
		return ret;
+6 −4
Original line number Diff line number Diff line
@@ -1107,8 +1107,9 @@ static void do_isync(void *info __maybe_unused)
 * execute isync (or some CSI) so that they don't go back into the
 * trampoline again.
 */
int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type,
		       void *old_addr, void *new_addr)
int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type old_t,
		       enum bpf_text_poke_type new_t, void *old_addr,
		       void *new_addr)
{
	unsigned long bpf_func, bpf_func_end, size, offset;
	ppc_inst_t old_inst, new_inst;
@@ -1119,7 +1120,6 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type,
		return -EOPNOTSUPP;

	bpf_func = (unsigned long)ip;
	branch_flags = poke_type == BPF_MOD_CALL ? BRANCH_SET_LINK : 0;

	/* We currently only support poking bpf programs */
	if (!__bpf_address_lookup(bpf_func, &size, &offset, name)) {
@@ -1132,7 +1132,7 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type,
	 * an unconditional branch instruction at im->ip_after_call
	 */
	if (offset) {
		if (poke_type != BPF_MOD_JUMP) {
		if (old_t == BPF_MOD_CALL || new_t == BPF_MOD_CALL) {
			pr_err("%s (0x%lx): calls are not supported in bpf prog body\n", __func__,
			       bpf_func);
			return -EOPNOTSUPP;
@@ -1166,6 +1166,7 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type,
	}

	old_inst = ppc_inst(PPC_RAW_NOP());
	branch_flags = old_t == BPF_MOD_CALL ? BRANCH_SET_LINK : 0;
	if (old_addr) {
		if (is_offset_in_branch_range(ip - old_addr))
			create_branch(&old_inst, ip, (unsigned long)old_addr, branch_flags);
@@ -1174,6 +1175,7 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type,
				      branch_flags);
	}
	new_inst = ppc_inst(PPC_RAW_NOP());
	branch_flags = new_t == BPF_MOD_CALL ? BRANCH_SET_LINK : 0;
	if (new_addr) {
		if (is_offset_in_branch_range(ip - new_addr))
			create_branch(&new_inst, ip, (unsigned long)new_addr, branch_flags);
+6 −3
Original line number Diff line number Diff line
@@ -852,17 +852,19 @@ static int gen_jump_or_nops(void *target, void *ip, u32 *insns, bool is_call)
	return emit_jump_and_link(is_call ? RV_REG_T0 : RV_REG_ZERO, rvoff, false, &ctx);
}

int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type,
		       void *old_addr, void *new_addr)
int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type old_t,
		       enum bpf_text_poke_type new_t, void *old_addr,
		       void *new_addr)
{
	u32 old_insns[RV_FENTRY_NINSNS], new_insns[RV_FENTRY_NINSNS];
	bool is_call = poke_type == BPF_MOD_CALL;
	bool is_call;
	int ret;

	if (!is_kernel_text((unsigned long)ip) &&
	    !is_bpf_text_address((unsigned long)ip))
		return -ENOTSUPP;

	is_call = old_t == BPF_MOD_CALL;
	ret = gen_jump_or_nops(old_addr, ip, old_insns, is_call);
	if (ret)
		return ret;
@@ -870,6 +872,7 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type,
	if (memcmp(ip, old_insns, RV_FENTRY_NBYTES))
		return -EFAULT;

	is_call = new_t == BPF_MOD_CALL;
	ret = gen_jump_or_nops(new_addr, ip, new_insns, is_call);
	if (ret)
		return ret;
+4 −3
Original line number Diff line number Diff line
@@ -2413,8 +2413,9 @@ bool bpf_jit_supports_far_kfunc_call(void)
	return true;
}

int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t,
		       void *old_addr, void *new_addr)
int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type old_t,
		       enum bpf_text_poke_type new_t, void *old_addr,
		       void *new_addr)
{
	struct bpf_plt expected_plt, current_plt, new_plt, *plt;
	struct {
@@ -2431,7 +2432,7 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t,
	if (insn.opc != (0xc004 | (old_addr ? 0xf0 : 0)))
		return -EINVAL;

	if (t == BPF_MOD_JUMP &&
	if ((new_t == BPF_MOD_JUMP || old_t == BPF_MOD_JUMP) &&
	    insn.disp == ((char *)new_addr - (char *)ip) >> 1) {
		/*
		 * The branch already points to the destination,
Loading