bpf: Add bpf_copy_from_user() helper.
authorAlexei Starovoitov <ast@kernel.org>
Thu, 27 Aug 2020 22:01:12 +0000 (15:01 -0700)
committerDaniel Borkmann <daniel@iogearbox.net>
Fri, 28 Aug 2020 19:20:33 +0000 (21:20 +0200)
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
include/linux/bpf.h
include/uapi/linux/bpf.h
kernel/bpf/helpers.c
kernel/trace/bpf_trace.c
tools/include/uapi/linux/bpf.h

index 4dd7e927621d1e956f3ca28ec37881aef4e07dcb..c6d9f2c444f40a5ccfe334a6f74f32b34da6c146 100644 (file)
@@ -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);
index 6e8b706aeb050925572021b0ef64898c0b2f9cda..a613750d55158218500a2da83c5b587f107e651b 100644 (file)
@@ -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
index be43ab3e619f973d49cceccae8369b8ec2918eaf..5cc7425ee476b3bc9adb9fa43040842f47b31d2b 100644 (file)
@@ -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;
index d973d891f2e25d8c26da60b2274da487f04b4112..b2a5380eb18713c6fe684fb6a794f34bd9717076 100644 (file)
@@ -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;
        }
index 6e8b706aeb050925572021b0ef64898c0b2f9cda..a613750d55158218500a2da83c5b587f107e651b 100644 (file)
@@ -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