bpf: permits narrower load from bpf program context fields
Currently, verifier will reject a program if it contains an narrower load from the bpf context structure. For example, __u8 h = __sk_buff->hash, or __u16 p = __sk_buff->protocol __u32 sample_period = bpf_perf_event_data->sample_period which are narrower loads of 4-byte or 8-byte field. This patch solves the issue by: . Introduce a new parameter ctx_field_size to carry the field size of narrower load from prog type specific *__is_valid_access validator back to verifier. . The non-zero ctx_field_size for a memory access indicates (1). underlying prog type specific convert_ctx_accesses supporting non-whole-field access (2). the current insn is a narrower or whole field access. . In verifier, for such loads where load memory size is less than ctx_field_size, verifier transforms it to a full field load followed by proper masking. . Currently, __sk_buff and bpf_perf_event_data->sample_period are supporting narrowing loads. . Narrower stores are still not allowed as typical ctx stores are just normal stores. Because of this change, some tests in verifier will fail and these tests are removed. As a bonus, rename some out of bound __sk_buff->cb access to proper field name and remove two redundant "skb cb oob" tests. Acked-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: Yonghong Song <yhs@fb.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
a88e2676a6
commit
31fd85816d
@ -1073,44 +1073,22 @@ static struct bpf_test tests[] = {
|
||||
.result = ACCEPT,
|
||||
},
|
||||
{
|
||||
"check cb access: byte, oob 1",
|
||||
"__sk_buff->hash, offset 0, byte store not permitted",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_STX_MEM(BPF_B, BPF_REG_1, BPF_REG_0,
|
||||
offsetof(struct __sk_buff, cb[4]) + 4),
|
||||
offsetof(struct __sk_buff, hash)),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.errstr = "invalid bpf_context access",
|
||||
.result = REJECT,
|
||||
},
|
||||
{
|
||||
"check cb access: byte, oob 2",
|
||||
"__sk_buff->tc_index, offset 3, byte store not permitted",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_STX_MEM(BPF_B, BPF_REG_1, BPF_REG_0,
|
||||
offsetof(struct __sk_buff, cb[0]) - 1),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.errstr = "invalid bpf_context access",
|
||||
.result = REJECT,
|
||||
},
|
||||
{
|
||||
"check cb access: byte, oob 3",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1,
|
||||
offsetof(struct __sk_buff, cb[4]) + 4),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.errstr = "invalid bpf_context access",
|
||||
.result = REJECT,
|
||||
},
|
||||
{
|
||||
"check cb access: byte, oob 4",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1,
|
||||
offsetof(struct __sk_buff, cb[0]) - 1),
|
||||
offsetof(struct __sk_buff, tc_index) + 3),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.errstr = "invalid bpf_context access",
|
||||
@ -1188,44 +1166,22 @@ static struct bpf_test tests[] = {
|
||||
.result = REJECT,
|
||||
},
|
||||
{
|
||||
"check cb access: half, oob 1",
|
||||
"check __sk_buff->hash, offset 0, half store not permitted",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_STX_MEM(BPF_H, BPF_REG_1, BPF_REG_0,
|
||||
offsetof(struct __sk_buff, cb[4]) + 4),
|
||||
offsetof(struct __sk_buff, hash)),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.errstr = "invalid bpf_context access",
|
||||
.result = REJECT,
|
||||
},
|
||||
{
|
||||
"check cb access: half, oob 2",
|
||||
"check __sk_buff->tc_index, offset 2, half store not permitted",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_STX_MEM(BPF_H, BPF_REG_1, BPF_REG_0,
|
||||
offsetof(struct __sk_buff, cb[0]) - 2),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.errstr = "invalid bpf_context access",
|
||||
.result = REJECT,
|
||||
},
|
||||
{
|
||||
"check cb access: half, oob 3",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1,
|
||||
offsetof(struct __sk_buff, cb[4]) + 4),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.errstr = "invalid bpf_context access",
|
||||
.result = REJECT,
|
||||
},
|
||||
{
|
||||
"check cb access: half, oob 4",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1,
|
||||
offsetof(struct __sk_buff, cb[0]) - 2),
|
||||
offsetof(struct __sk_buff, tc_index) + 2),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.errstr = "invalid bpf_context access",
|
||||
@ -1366,28 +1322,6 @@ static struct bpf_test tests[] = {
|
||||
},
|
||||
{
|
||||
"check cb access: double, oob 2",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
|
||||
offsetof(struct __sk_buff, cb[4]) + 8),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.errstr = "invalid bpf_context access",
|
||||
.result = REJECT,
|
||||
},
|
||||
{
|
||||
"check cb access: double, oob 3",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
|
||||
offsetof(struct __sk_buff, cb[0]) - 8),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.errstr = "invalid bpf_context access",
|
||||
.result = REJECT,
|
||||
},
|
||||
{
|
||||
"check cb access: double, oob 4",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1,
|
||||
@ -1398,22 +1332,22 @@ static struct bpf_test tests[] = {
|
||||
.result = REJECT,
|
||||
},
|
||||
{
|
||||
"check cb access: double, oob 5",
|
||||
"check __sk_buff->ifindex dw store not permitted",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1,
|
||||
offsetof(struct __sk_buff, cb[4]) + 8),
|
||||
BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
|
||||
offsetof(struct __sk_buff, ifindex)),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.errstr = "invalid bpf_context access",
|
||||
.result = REJECT,
|
||||
},
|
||||
{
|
||||
"check cb access: double, oob 6",
|
||||
"check __sk_buff->ifindex dw load not permitted",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1,
|
||||
offsetof(struct __sk_buff, cb[0]) - 8),
|
||||
offsetof(struct __sk_buff, ifindex)),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.errstr = "invalid bpf_context access",
|
||||
|
Reference in New Issue
Block a user