bpf: add bpf_skb_load_bytes helper
[cascardo/linux.git] / net / core / filter.c
index 672eefb..34bf6fc 100644 (file)
@@ -1245,6 +1245,7 @@ int sk_attach_bpf(u32 ufd, struct sock *sk)
 }
 
 #define BPF_RECOMPUTE_CSUM(flags)      ((flags) & 1)
+#define BPF_LDST_LEN                   16U
 
 static u64 bpf_skb_store_bytes(u64 r1, u64 r2, u64 r3, u64 r4, u64 flags)
 {
@@ -1252,7 +1253,7 @@ static u64 bpf_skb_store_bytes(u64 r1, u64 r2, u64 r3, u64 r4, u64 flags)
        int offset = (int) r2;
        void *from = (void *) (long) r3;
        unsigned int len = (unsigned int) r4;
-       char buf[16];
+       char buf[BPF_LDST_LEN];
        void *ptr;
 
        /* bpf verifier guarantees that:
@@ -1299,6 +1300,36 @@ const struct bpf_func_proto bpf_skb_store_bytes_proto = {
        .arg5_type      = ARG_ANYTHING,
 };
 
+static u64 bpf_skb_load_bytes(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5)
+{
+       const struct sk_buff *skb = (const struct sk_buff *)(unsigned long) r1;
+       int offset = (int) r2;
+       void *to = (void *)(unsigned long) r3;
+       unsigned int len = (unsigned int) r4;
+       void *ptr;
+
+       if (unlikely((u32) offset > 0xffff || len > BPF_LDST_LEN))
+               return -EFAULT;
+
+       ptr = skb_header_pointer(skb, offset, len, to);
+       if (unlikely(!ptr))
+               return -EFAULT;
+       if (ptr != to)
+               memcpy(to, ptr, len);
+
+       return 0;
+}
+
+const struct bpf_func_proto bpf_skb_load_bytes_proto = {
+       .func           = bpf_skb_load_bytes,
+       .gpl_only       = false,
+       .ret_type       = RET_INTEGER,
+       .arg1_type      = ARG_PTR_TO_CTX,
+       .arg2_type      = ARG_ANYTHING,
+       .arg3_type      = ARG_PTR_TO_STACK,
+       .arg4_type      = ARG_CONST_STACK_SIZE,
+};
+
 #define BPF_HEADER_FIELD_SIZE(flags)   ((flags) & 0x0f)
 #define BPF_IS_PSEUDO_HEADER(flags)    ((flags) & 0x10)
 
@@ -1654,6 +1685,8 @@ tc_cls_act_func_proto(enum bpf_func_id func_id)
        switch (func_id) {
        case BPF_FUNC_skb_store_bytes:
                return &bpf_skb_store_bytes_proto;
+       case BPF_FUNC_skb_load_bytes:
+               return &bpf_skb_load_bytes_proto;
        case BPF_FUNC_l3_csum_replace:
                return &bpf_l3_csum_replace_proto;
        case BPF_FUNC_l4_csum_replace: