Skip to content

Commit 8a31db5

Browse files
jrfastabdavem330
authored andcommitted
bpf: add access to sock fields and pkt data from sk_skb programs
Signed-off-by: John Fastabend <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 174a79f commit 8a31db5

File tree

3 files changed

+179
-0
lines changed

3 files changed

+179
-0
lines changed

include/uapi/linux/bpf.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,15 @@ struct __sk_buff {
712712
__u32 data;
713713
__u32 data_end;
714714
__u32 napi_id;
715+
716+
/* accessed by BPF_PROG_TYPE_sk_skb types */
717+
__u32 family;
718+
__u32 remote_ip4; /* Stored in network byte order */
719+
__u32 local_ip4; /* Stored in network byte order */
720+
__u32 remote_ip6[4]; /* Stored in network byte order */
721+
__u32 local_ip6[4]; /* Stored in network byte order */
722+
__u32 remote_port; /* Stored in network byte order */
723+
__u32 local_port; /* stored in host byte order */
715724
};
716725

717726
struct bpf_tunnel_key {

kernel/bpf/verifier.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,7 @@ static bool may_access_direct_pkt_data(struct bpf_verifier_env *env,
886886
case BPF_PROG_TYPE_SCHED_ACT:
887887
case BPF_PROG_TYPE_XDP:
888888
case BPF_PROG_TYPE_LWT_XMIT:
889+
case BPF_PROG_TYPE_SK_SKB:
889890
if (meta)
890891
return meta->pkt_access;
891892

net/core/filter.c

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3278,8 +3278,16 @@ static const struct bpf_func_proto *
32783278
static const struct bpf_func_proto *sk_skb_func_proto(enum bpf_func_id func_id)
32793279
{
32803280
switch (func_id) {
3281+
case BPF_FUNC_skb_store_bytes:
3282+
return &bpf_skb_store_bytes_proto;
32813283
case BPF_FUNC_skb_load_bytes:
32823284
return &bpf_skb_load_bytes_proto;
3285+
case BPF_FUNC_skb_pull_data:
3286+
return &bpf_skb_pull_data_proto;
3287+
case BPF_FUNC_skb_change_tail:
3288+
return &bpf_skb_change_tail_proto;
3289+
case BPF_FUNC_skb_change_head:
3290+
return &bpf_skb_change_head_proto;
32833291
case BPF_FUNC_get_socket_cookie:
32843292
return &bpf_get_socket_cookie_proto;
32853293
case BPF_FUNC_get_socket_uid:
@@ -3343,6 +3351,10 @@ static bool bpf_skb_is_valid_access(int off, int size, enum bpf_access_type type
33433351
if (off + size > offsetofend(struct __sk_buff, cb[4]))
33443352
return false;
33453353
break;
3354+
case bpf_ctx_range_till(struct __sk_buff, remote_ip6[0], remote_ip6[3]):
3355+
case bpf_ctx_range_till(struct __sk_buff, local_ip6[0], local_ip6[3]):
3356+
case bpf_ctx_range_till(struct __sk_buff, remote_ip4, remote_ip4):
3357+
case bpf_ctx_range_till(struct __sk_buff, local_ip4, local_ip4):
33463358
case bpf_ctx_range(struct __sk_buff, data):
33473359
case bpf_ctx_range(struct __sk_buff, data_end):
33483360
if (size != size_default)
@@ -3371,6 +3383,7 @@ static bool sk_filter_is_valid_access(int off, int size,
33713383
case bpf_ctx_range(struct __sk_buff, tc_classid):
33723384
case bpf_ctx_range(struct __sk_buff, data):
33733385
case bpf_ctx_range(struct __sk_buff, data_end):
3386+
case bpf_ctx_range_till(struct __sk_buff, family, local_port):
33743387
return false;
33753388
}
33763389

@@ -3392,6 +3405,7 @@ static bool lwt_is_valid_access(int off, int size,
33923405
{
33933406
switch (off) {
33943407
case bpf_ctx_range(struct __sk_buff, tc_classid):
3408+
case bpf_ctx_range_till(struct __sk_buff, family, local_port):
33953409
return false;
33963410
}
33973411

@@ -3505,6 +3519,8 @@ static bool tc_cls_act_is_valid_access(int off, int size,
35053519
case bpf_ctx_range(struct __sk_buff, data_end):
35063520
info->reg_type = PTR_TO_PACKET_END;
35073521
break;
3522+
case bpf_ctx_range_till(struct __sk_buff, family, local_port):
3523+
return false;
35083524
}
35093525

35103526
return bpf_skb_is_valid_access(off, size, type, info);
@@ -3582,11 +3598,63 @@ static bool sock_ops_is_valid_access(int off, int size,
35823598
return __is_valid_sock_ops_access(off, size);
35833599
}
35843600

3601+
static int sk_skb_prologue(struct bpf_insn *insn_buf, bool direct_write,
3602+
const struct bpf_prog *prog)
3603+
{
3604+
struct bpf_insn *insn = insn_buf;
3605+
3606+
if (!direct_write)
3607+
return 0;
3608+
3609+
/* if (!skb->cloned)
3610+
* goto start;
3611+
*
3612+
* (Fast-path, otherwise approximation that we might be
3613+
* a clone, do the rest in helper.)
3614+
*/
3615+
*insn++ = BPF_LDX_MEM(BPF_B, BPF_REG_6, BPF_REG_1, CLONED_OFFSET());
3616+
*insn++ = BPF_ALU32_IMM(BPF_AND, BPF_REG_6, CLONED_MASK);
3617+
*insn++ = BPF_JMP_IMM(BPF_JEQ, BPF_REG_6, 0, 7);
3618+
3619+
/* ret = bpf_skb_pull_data(skb, 0); */
3620+
*insn++ = BPF_MOV64_REG(BPF_REG_6, BPF_REG_1);
3621+
*insn++ = BPF_ALU64_REG(BPF_XOR, BPF_REG_2, BPF_REG_2);
3622+
*insn++ = BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
3623+
BPF_FUNC_skb_pull_data);
3624+
/* if (!ret)
3625+
* goto restore;
3626+
* return SK_DROP;
3627+
*/
3628+
*insn++ = BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2);
3629+
*insn++ = BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, SK_DROP);
3630+
*insn++ = BPF_EXIT_INSN();
3631+
3632+
/* restore: */
3633+
*insn++ = BPF_MOV64_REG(BPF_REG_1, BPF_REG_6);
3634+
/* start: */
3635+
*insn++ = prog->insnsi[0];
3636+
3637+
return insn - insn_buf;
3638+
}
3639+
35853640
static bool sk_skb_is_valid_access(int off, int size,
35863641
enum bpf_access_type type,
35873642
struct bpf_insn_access_aux *info)
35883643
{
3644+
if (type == BPF_WRITE) {
3645+
switch (off) {
3646+
case bpf_ctx_range(struct __sk_buff, mark):
3647+
case bpf_ctx_range(struct __sk_buff, tc_index):
3648+
case bpf_ctx_range(struct __sk_buff, priority):
3649+
break;
3650+
default:
3651+
return false;
3652+
}
3653+
}
3654+
35893655
switch (off) {
3656+
case bpf_ctx_range(struct __sk_buff, tc_classid):
3657+
return false;
35903658
case bpf_ctx_range(struct __sk_buff, data):
35913659
info->reg_type = PTR_TO_PACKET;
35923660
break;
@@ -3783,6 +3851,106 @@ static u32 bpf_convert_ctx_access(enum bpf_access_type type,
37833851
*insn++ = BPF_MOV64_IMM(si->dst_reg, 0);
37843852
#endif
37853853
break;
3854+
case offsetof(struct __sk_buff, family):
3855+
BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common, skc_family) != 2);
3856+
3857+
*insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, sk),
3858+
si->dst_reg, si->src_reg,
3859+
offsetof(struct sk_buff, sk));
3860+
*insn++ = BPF_LDX_MEM(BPF_H, si->dst_reg, si->dst_reg,
3861+
bpf_target_off(struct sock_common,
3862+
skc_family,
3863+
2, target_size));
3864+
break;
3865+
case offsetof(struct __sk_buff, remote_ip4):
3866+
BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common, skc_daddr) != 4);
3867+
3868+
*insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, sk),
3869+
si->dst_reg, si->src_reg,
3870+
offsetof(struct sk_buff, sk));
3871+
*insn++ = BPF_LDX_MEM(BPF_W, si->dst_reg, si->dst_reg,
3872+
bpf_target_off(struct sock_common,
3873+
skc_daddr,
3874+
4, target_size));
3875+
break;
3876+
case offsetof(struct __sk_buff, local_ip4):
3877+
BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common,
3878+
skc_rcv_saddr) != 4);
3879+
3880+
*insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, sk),
3881+
si->dst_reg, si->src_reg,
3882+
offsetof(struct sk_buff, sk));
3883+
*insn++ = BPF_LDX_MEM(BPF_W, si->dst_reg, si->dst_reg,
3884+
bpf_target_off(struct sock_common,
3885+
skc_rcv_saddr,
3886+
4, target_size));
3887+
break;
3888+
case offsetof(struct __sk_buff, remote_ip6[0]) ...
3889+
offsetof(struct __sk_buff, remote_ip6[3]):
3890+
#if IS_ENABLED(CONFIG_IPV6)
3891+
BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common,
3892+
skc_v6_daddr.s6_addr32[0]) != 4);
3893+
3894+
off = si->off;
3895+
off -= offsetof(struct __sk_buff, remote_ip6[0]);
3896+
3897+
*insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, sk),
3898+
si->dst_reg, si->src_reg,
3899+
offsetof(struct sk_buff, sk));
3900+
*insn++ = BPF_LDX_MEM(BPF_W, si->dst_reg, si->dst_reg,
3901+
offsetof(struct sock_common,
3902+
skc_v6_daddr.s6_addr32[0]) +
3903+
off);
3904+
#else
3905+
*insn++ = BPF_MOV32_IMM(si->dst_reg, 0);
3906+
#endif
3907+
break;
3908+
case offsetof(struct __sk_buff, local_ip6[0]) ...
3909+
offsetof(struct __sk_buff, local_ip6[3]):
3910+
#if IS_ENABLED(CONFIG_IPV6)
3911+
BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common,
3912+
skc_v6_rcv_saddr.s6_addr32[0]) != 4);
3913+
3914+
off = si->off;
3915+
off -= offsetof(struct __sk_buff, local_ip6[0]);
3916+
3917+
*insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, sk),
3918+
si->dst_reg, si->src_reg,
3919+
offsetof(struct sk_buff, sk));
3920+
*insn++ = BPF_LDX_MEM(BPF_W, si->dst_reg, si->dst_reg,
3921+
offsetof(struct sock_common,
3922+
skc_v6_rcv_saddr.s6_addr32[0]) +
3923+
off);
3924+
#else
3925+
*insn++ = BPF_MOV32_IMM(si->dst_reg, 0);
3926+
#endif
3927+
break;
3928+
3929+
case offsetof(struct __sk_buff, remote_port):
3930+
BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common, skc_dport) != 2);
3931+
3932+
*insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, sk),
3933+
si->dst_reg, si->src_reg,
3934+
offsetof(struct sk_buff, sk));
3935+
*insn++ = BPF_LDX_MEM(BPF_H, si->dst_reg, si->dst_reg,
3936+
bpf_target_off(struct sock_common,
3937+
skc_dport,
3938+
2, target_size));
3939+
#ifndef __BIG_ENDIAN_BITFIELD
3940+
*insn++ = BPF_ALU32_IMM(BPF_LSH, si->dst_reg, 16);
3941+
#endif
3942+
break;
3943+
3944+
case offsetof(struct __sk_buff, local_port):
3945+
BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common, skc_num) != 2);
3946+
3947+
*insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, sk),
3948+
si->dst_reg, si->src_reg,
3949+
offsetof(struct sk_buff, sk));
3950+
*insn++ = BPF_LDX_MEM(BPF_H, si->dst_reg, si->dst_reg,
3951+
bpf_target_off(struct sock_common,
3952+
skc_num, 2, target_size));
3953+
break;
37863954
}
37873955

37883956
return insn - insn_buf;
@@ -4071,6 +4239,7 @@ const struct bpf_verifier_ops sk_skb_prog_ops = {
40714239
.get_func_proto = sk_skb_func_proto,
40724240
.is_valid_access = sk_skb_is_valid_access,
40734241
.convert_ctx_access = bpf_convert_ctx_access,
4242+
.gen_prologue = sk_skb_prologue,
40744243
};
40754244

40764245
int sk_detach_filter(struct sock *sk)

0 commit comments

Comments
 (0)