“3cea21b7f3fa8731b6d3c23f181f20f848d2e98e”上不存在“src/share/classes/java/io/UncheckedIOException.java”
未验证 提交 ea43b636 编写于 作者: O openeuler-ci-bot 提交者: Gitee

!178 bpf: add a bpf_override_reg helper

Merge Pull Request from: @JqyangCode 
 
[2022开源之夏] - 为ebpf添加新的辅助函数-bpf_override_reg ,功能是修改目标函数的寄存器,包括入参,返回值等
--------------------------------------
Error injection is a very important method for testing system stability. But for now,
it is still lacking in this regard, but BPF can fill this gap perfectly with its kprobe
function.

We can use some validation methods to ensure that it only fires on calls we restrict.
Although there are bpf_override_funciton that can complete some related operations
before, this is a function that bypasses the initial detection and only modifies the
return value to the specified value.This does not meet some of our practical scenarios:

1. For example, other registers (such as input registers) need to be modified: when we
receive a network packet, we will convert it into a structure and pass it to the corresponding
function for processing.For the fault tolerance of network data, we need to modify the
members of this structure, which it cannot do.

2. The function cannot be mounted or what needs to be modified is not the function but the
instruction: when the sensor reads the IO data, we need to simulate the IO data error.
At this time, the reading of the IO data may not be a function, but a few simple instructions

In summary, it is necessary to extend an interface that can modify any register, which can
provide us with a simple way to achieve system error injection

bugzilla: #I55FLX 
 
Link:https://gitee.com/openeuler/kernel/pulls/178 
Reviewed-by: Zheng Zengkai <zhengzengkai@huawei.com> 
Signed-off-by: Zheng Zengkai <zhengzengkai@huawei.com> 
...@@ -19,3 +19,16 @@ void override_function_with_return(struct pt_regs *regs) ...@@ -19,3 +19,16 @@ void override_function_with_return(struct pt_regs *regs)
regs->ip = (unsigned long)&just_return_func; regs->ip = (unsigned long)&just_return_func;
} }
NOKPROBE_SYMBOL(override_function_with_return); NOKPROBE_SYMBOL(override_function_with_return);
int regs_set_register(struct pt_regs *regs, const char *regs_name,
unsigned long value)
{
int offset = 0;
offset = regs_query_register_offset(regs_name) >> 3;
if (offset >= 0) {
*((unsigned long *)((unsigned long *)regs + offset)) = value;
return 0;
}
return -1;
}
NOKPROBE_SYMBOL(regs_set_register);
\ No newline at end of file
...@@ -32,6 +32,8 @@ static struct error_injection_entry __used \ ...@@ -32,6 +32,8 @@ static struct error_injection_entry __used \
}; };
void override_function_with_return(struct pt_regs *regs); void override_function_with_return(struct pt_regs *regs);
int regs_set_register(struct pt_regs *regs, const char *regs_name,
unsigned long value);
#else #else
#define ALLOW_ERROR_INJECTION(fname, _etype) #define ALLOW_ERROR_INJECTION(fname, _etype)
......
...@@ -4070,6 +4070,24 @@ union bpf_attr { ...@@ -4070,6 +4070,24 @@ union bpf_attr {
* *offset* * *offset*
* Return * Return
* 0 on success, or a negative error in case of failure. * 0 on success, or a negative error in case of failure.
*
* long bpf_override_reg(struct pt_regs *regs, const char* regs_name, u64 value)
* Description
* Also used for error injection, unlike bpf_override_return, this helper
* uses kprobes to overwrite the probed function's register and set it to
* *rc*. Instead of just modifying the return value, the first argument
* is the context *regs* where kprobe works,and the second parameter is
* the offset of the register.
*
* And the helper doesn't modify the PC (Program Counter). This means that
* the probed function will run and replace the function's register values.
*
* On the other hand, to avoid security implications, it is likewise only
* available when compiling the kernel with the **CONFIG_BPF_KPROBE_OVERRIDE**
* configuration option, and in this case it only applies to functions marked
* with **ALLOW_ERROR_INJECTION** in the kernel code.
* Return
* 0 on success, or a negative error in case of failure.
*/ */
#define __BPF_FUNC_MAPPER(FN) \ #define __BPF_FUNC_MAPPER(FN) \
FN(unspec), \ FN(unspec), \
...@@ -4258,6 +4276,7 @@ union bpf_attr { ...@@ -4258,6 +4276,7 @@ union bpf_attr {
FN(update_tcp_seq), \ FN(update_tcp_seq), \
FN(xdp_store_bytes), \ FN(xdp_store_bytes), \
FN(xdp_load_bytes), \ FN(xdp_load_bytes), \
FN(override_reg), \
/* */ /* */
/* integer value in 'imm' field of BPF_CALL instruction selects which helper /* integer value in 'imm' field of BPF_CALL instruction selects which helper
......
...@@ -12595,7 +12595,8 @@ static int do_misc_fixups(struct bpf_verifier_env *env) ...@@ -12595,7 +12595,8 @@ static int do_misc_fixups(struct bpf_verifier_env *env)
prog->dst_needed = 1; prog->dst_needed = 1;
if (insn->imm == BPF_FUNC_get_prandom_u32) if (insn->imm == BPF_FUNC_get_prandom_u32)
bpf_user_rnd_init_once(); bpf_user_rnd_init_once();
if (insn->imm == BPF_FUNC_override_return) if (insn->imm == BPF_FUNC_override_return ||
insn->imm == BPF_FUNC_override_reg)
prog->kprobe_override = 1; prog->kprobe_override = 1;
if (insn->imm == BPF_FUNC_tail_call) { if (insn->imm == BPF_FUNC_tail_call) {
/* If we tail call into other programs, we /* If we tail call into other programs, we
......
...@@ -144,6 +144,28 @@ static const struct bpf_func_proto bpf_override_return_proto = { ...@@ -144,6 +144,28 @@ static const struct bpf_func_proto bpf_override_return_proto = {
.arg1_type = ARG_PTR_TO_CTX, .arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_ANYTHING, .arg2_type = ARG_ANYTHING,
}; };
BPF_CALL_3(bpf_override_regs, struct pt_regs *, regs, const char *, regs_name,
unsigned long, value)
{
int ret = 0;
#ifdef CONFIG_X86_64
ret = regs_set_register(regs, regs_name, value);
if (unlikely(ret < 0))
return ret;
#endif
return 0;
}
static const struct bpf_func_proto bpf_override_reg_proto = {
.func = bpf_override_reg,
.gpl_only = true,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_ANYTHING,
.arg3_type = ARG_ANYTHING,
};
#endif #endif
static __always_inline int static __always_inline int
...@@ -1056,6 +1078,8 @@ kprobe_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) ...@@ -1056,6 +1078,8 @@ kprobe_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
#ifdef CONFIG_BPF_KPROBE_OVERRIDE #ifdef CONFIG_BPF_KPROBE_OVERRIDE
case BPF_FUNC_override_return: case BPF_FUNC_override_return:
return &bpf_override_return_proto; return &bpf_override_return_proto;
case BPF_FUNC_override_reg:
return &bpf_override_reg_proto;
#endif #endif
default: default:
return bpf_tracing_func_proto(func_id, prog); return bpf_tracing_func_proto(func_id, prog);
......
...@@ -4780,6 +4780,25 @@ union bpf_attr { ...@@ -4780,6 +4780,25 @@ union bpf_attr {
* *offset* * *offset*
* Return * Return
* 0 on success, or a negative error in case of failure. * 0 on success, or a negative error in case of failure.
*
* long bpf_override_reg(struct pt_regs *regs, const char* regs_name, u64 value)
* Description
* Also used for error injection, unlike bpf_override_return, this helper
* uses kprobes to overwrite the probed function's register and set it to
* *rc*. Instead of just modifying the return value, the first argument
* is the context *regs* where kprobe works,and the second parameter is
* the offset of the register.
*
* And the helper doesn't modify the PC (Program Counter). This means that
* the probed function will run and replace the function's register values.
*
* On the other hand, to avoid security implications, it is likewise only
* available when compiling the kernel with the **CONFIG_BPF_KPROBE_OVERRIDE**
* configuration option, and in this case it only applies to functions marked
* with **ALLOW_ERROR_INJECTION** in the kernel code.
*
* Return
* 0 on success, or a negative error in case of failure.
*/ */
#define __BPF_FUNC_MAPPER(FN) \ #define __BPF_FUNC_MAPPER(FN) \
FN(unspec), \ FN(unspec), \
...@@ -4968,6 +4987,7 @@ union bpf_attr { ...@@ -4968,6 +4987,7 @@ union bpf_attr {
FN(update_tcp_seq), \ FN(update_tcp_seq), \
FN(xdp_store_bytes), \ FN(xdp_store_bytes), \
FN(xdp_load_bytes), \ FN(xdp_load_bytes), \
FN(override_reg), \
/* */ /* */
/* integer value in 'imm' field of BPF_CALL instruction selects which helper /* integer value in 'imm' field of BPF_CALL instruction selects which helper
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册