bpf: Add bpf_copy_from_user() helper.
Sleepable BPF programs can now use copy_from_user() to access user memory. Signed-off-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Andrii Nakryiko <andriin@fb.com> Acked-by: KP Singh <kpsingh@google.com> Link: https://lore.kernel.org/bpf/20200827220114.69225-4-alexei.starovoitov@gmail.com
This commit is contained in:
parent
1e6c62a882
commit
07be4c4a3e
|
@ -1784,6 +1784,7 @@ extern const struct bpf_func_proto bpf_skc_to_tcp_sock_proto;
|
|||
extern const struct bpf_func_proto bpf_skc_to_tcp_timewait_sock_proto;
|
||||
extern const struct bpf_func_proto bpf_skc_to_tcp_request_sock_proto;
|
||||
extern const struct bpf_func_proto bpf_skc_to_udp6_sock_proto;
|
||||
extern const struct bpf_func_proto bpf_copy_from_user_proto;
|
||||
|
||||
const struct bpf_func_proto *bpf_tracing_func_proto(
|
||||
enum bpf_func_id func_id, const struct bpf_prog *prog);
|
||||
|
|
|
@ -3569,6 +3569,13 @@ union bpf_attr {
|
|||
* On success, the strictly positive length of the string,
|
||||
* including the trailing NUL character. On error, a negative
|
||||
* value.
|
||||
*
|
||||
* long bpf_copy_from_user(void *dst, u32 size, const void *user_ptr)
|
||||
* Description
|
||||
* Read *size* bytes from user space address *user_ptr* and store
|
||||
* the data in *dst*. This is a wrapper of copy_from_user().
|
||||
* Return
|
||||
* 0 on success, or a negative error in case of failure.
|
||||
*/
|
||||
#define __BPF_FUNC_MAPPER(FN) \
|
||||
FN(unspec), \
|
||||
|
@ -3719,6 +3726,7 @@ union bpf_attr {
|
|||
FN(inode_storage_get), \
|
||||
FN(inode_storage_delete), \
|
||||
FN(d_path), \
|
||||
FN(copy_from_user), \
|
||||
/* */
|
||||
|
||||
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
|
||||
|
|
|
@ -601,6 +601,28 @@ const struct bpf_func_proto bpf_event_output_data_proto = {
|
|||
.arg5_type = ARG_CONST_SIZE_OR_ZERO,
|
||||
};
|
||||
|
||||
BPF_CALL_3(bpf_copy_from_user, void *, dst, u32, size,
|
||||
const void __user *, user_ptr)
|
||||
{
|
||||
int ret = copy_from_user(dst, user_ptr, size);
|
||||
|
||||
if (unlikely(ret)) {
|
||||
memset(dst, 0, size);
|
||||
ret = -EFAULT;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct bpf_func_proto bpf_copy_from_user_proto = {
|
||||
.func = bpf_copy_from_user,
|
||||
.gpl_only = false,
|
||||
.ret_type = RET_INTEGER,
|
||||
.arg1_type = ARG_PTR_TO_UNINIT_MEM,
|
||||
.arg2_type = ARG_CONST_SIZE_OR_ZERO,
|
||||
.arg3_type = ARG_ANYTHING,
|
||||
};
|
||||
|
||||
const struct bpf_func_proto bpf_get_current_task_proto __weak;
|
||||
const struct bpf_func_proto bpf_probe_read_user_proto __weak;
|
||||
const struct bpf_func_proto bpf_probe_read_user_str_proto __weak;
|
||||
|
|
|
@ -1228,6 +1228,8 @@ bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
|||
return &bpf_jiffies64_proto;
|
||||
case BPF_FUNC_get_task_stack:
|
||||
return &bpf_get_task_stack_proto;
|
||||
case BPF_FUNC_copy_from_user:
|
||||
return prog->aux->sleepable ? &bpf_copy_from_user_proto : NULL;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -3569,6 +3569,13 @@ union bpf_attr {
|
|||
* On success, the strictly positive length of the string,
|
||||
* including the trailing NUL character. On error, a negative
|
||||
* value.
|
||||
*
|
||||
* long bpf_copy_from_user(void *dst, u32 size, const void *user_ptr)
|
||||
* Description
|
||||
* Read *size* bytes from user space address *user_ptr* and store
|
||||
* the data in *dst*. This is a wrapper of copy_from_user().
|
||||
* Return
|
||||
* 0 on success, or a negative error in case of failure.
|
||||
*/
|
||||
#define __BPF_FUNC_MAPPER(FN) \
|
||||
FN(unspec), \
|
||||
|
@ -3719,6 +3726,7 @@ union bpf_attr {
|
|||
FN(inode_storage_get), \
|
||||
FN(inode_storage_delete), \
|
||||
FN(d_path), \
|
||||
FN(copy_from_user), \
|
||||
/* */
|
||||
|
||||
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
|
||||
|
|
Loading…
Reference in New Issue