bpf: allow b/h/w/dw access for bpf's cb in ctx
When structs are used to store temporary state in cb[] buffer that is used with programs and among tail calls, then the generated code will not always access the buffer in bpf_w chunks. We can ease programming of it and let this act more natural by allowing for aligned b/h/w/dw sized access for cb[] ctx member. Various test cases are attached as well for the selftest suite. Potentially, this can also be reused for other program types to pass data around. Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:

committed by
David S. Miller

parent
6b8cc1d11e
commit
62c7989b24
@@ -2776,11 +2776,33 @@ static bool __is_valid_access(int off, int size)
|
||||
{
|
||||
if (off < 0 || off >= sizeof(struct __sk_buff))
|
||||
return false;
|
||||
|
||||
/* The verifier guarantees that size > 0. */
|
||||
if (off % size != 0)
|
||||
return false;
|
||||
if (size != sizeof(__u32))
|
||||
return false;
|
||||
|
||||
switch (off) {
|
||||
case offsetof(struct __sk_buff, cb[0]) ...
|
||||
offsetof(struct __sk_buff, cb[4]) + sizeof(__u32) - 1:
|
||||
if (size == sizeof(__u16) &&
|
||||
off > offsetof(struct __sk_buff, cb[4]) + sizeof(__u16))
|
||||
return false;
|
||||
if (size == sizeof(__u32) &&
|
||||
off > offsetof(struct __sk_buff, cb[4]))
|
||||
return false;
|
||||
if (size == sizeof(__u64) &&
|
||||
off > offsetof(struct __sk_buff, cb[2]))
|
||||
return false;
|
||||
if (size != sizeof(__u8) &&
|
||||
size != sizeof(__u16) &&
|
||||
size != sizeof(__u32) &&
|
||||
size != sizeof(__u64))
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
if (size != sizeof(__u32))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -2799,7 +2821,7 @@ static bool sk_filter_is_valid_access(int off, int size,
|
||||
if (type == BPF_WRITE) {
|
||||
switch (off) {
|
||||
case offsetof(struct __sk_buff, cb[0]) ...
|
||||
offsetof(struct __sk_buff, cb[4]):
|
||||
offsetof(struct __sk_buff, cb[4]) + sizeof(__u32) - 1:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
@@ -2823,7 +2845,7 @@ static bool lwt_is_valid_access(int off, int size,
|
||||
case offsetof(struct __sk_buff, mark):
|
||||
case offsetof(struct __sk_buff, priority):
|
||||
case offsetof(struct __sk_buff, cb[0]) ...
|
||||
offsetof(struct __sk_buff, cb[4]):
|
||||
offsetof(struct __sk_buff, cb[4]) + sizeof(__u32) - 1:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
@@ -2915,7 +2937,7 @@ static bool tc_cls_act_is_valid_access(int off, int size,
|
||||
case offsetof(struct __sk_buff, tc_index):
|
||||
case offsetof(struct __sk_buff, priority):
|
||||
case offsetof(struct __sk_buff, cb[0]) ...
|
||||
offsetof(struct __sk_buff, cb[4]):
|
||||
offsetof(struct __sk_buff, cb[4]) + sizeof(__u32) - 1:
|
||||
case offsetof(struct __sk_buff, tc_classid):
|
||||
break;
|
||||
default:
|
||||
@@ -3066,8 +3088,11 @@ static u32 sk_filter_convert_ctx_access(enum bpf_access_type type,
|
||||
si->dst_reg, si->src_reg, insn);
|
||||
|
||||
case offsetof(struct __sk_buff, cb[0]) ...
|
||||
offsetof(struct __sk_buff, cb[4]):
|
||||
offsetof(struct __sk_buff, cb[4]) + sizeof(__u32) - 1:
|
||||
BUILD_BUG_ON(FIELD_SIZEOF(struct qdisc_skb_cb, data) < 20);
|
||||
BUILD_BUG_ON((offsetof(struct sk_buff, cb) +
|
||||
offsetof(struct qdisc_skb_cb, data)) %
|
||||
sizeof(__u64));
|
||||
|
||||
prog->cb_access = 1;
|
||||
off = si->off;
|
||||
@@ -3075,10 +3100,10 @@ static u32 sk_filter_convert_ctx_access(enum bpf_access_type type,
|
||||
off += offsetof(struct sk_buff, cb);
|
||||
off += offsetof(struct qdisc_skb_cb, data);
|
||||
if (type == BPF_WRITE)
|
||||
*insn++ = BPF_STX_MEM(BPF_W, si->dst_reg,
|
||||
*insn++ = BPF_STX_MEM(BPF_SIZE(si->code), si->dst_reg,
|
||||
si->src_reg, off);
|
||||
else
|
||||
*insn++ = BPF_LDX_MEM(BPF_W, si->dst_reg,
|
||||
*insn++ = BPF_LDX_MEM(BPF_SIZE(si->code), si->dst_reg,
|
||||
si->src_reg, off);
|
||||
break;
|
||||
|
||||
|
Reference in New Issue
Block a user