Skip to content

Commit

Permalink
selftests/bpf: verify lsm_cgroup struct sock access
Browse files Browse the repository at this point in the history
sk_priority & sk_mark are writable, the rest is readonly.

Add new ldx_offset fixups to lookup the offset of struct field.
Allow using test.kfunc regardless of prog_type.

One interesting thing here is that the verifier doesn't
really force me to add NULL checks anywhere :-/

Signed-off-by: Stanislav Fomichev <[email protected]>
  • Loading branch information
fomichev authored and Nobody committed Apr 6, 2022
1 parent dc1dce5 commit 6fa78aa
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 1 deletion.
54 changes: 53 additions & 1 deletion tools/testing/selftests/bpf/test_verifier.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ struct kfunc_btf_id_pair {
int insn_idx;
};

struct ldx_offset {
const char *strct;
const char *field;
int insn_idx;
};

struct bpf_test {
const char *descr;
struct bpf_insn insns[MAX_INSNS];
Expand Down Expand Up @@ -102,6 +108,7 @@ struct bpf_test {
int fixup_map_ringbuf[MAX_FIXUPS];
int fixup_map_timer[MAX_FIXUPS];
struct kfunc_btf_id_pair fixup_kfunc_btf_id[MAX_FIXUPS];
struct ldx_offset fixup_ldx[MAX_FIXUPS];
/* Expected verifier log output for result REJECT or VERBOSE_ACCEPT.
* Can be a tab-separated sequence of expected strings. An empty string
* means no log verification.
Expand Down Expand Up @@ -755,6 +762,7 @@ static void do_test_fixup(struct bpf_test *test, enum bpf_prog_type prog_type,
int *fixup_map_ringbuf = test->fixup_map_ringbuf;
int *fixup_map_timer = test->fixup_map_timer;
struct kfunc_btf_id_pair *fixup_kfunc_btf_id = test->fixup_kfunc_btf_id;
struct ldx_offset *fixup_ldx = test->fixup_ldx;

if (test->fill_helper) {
test->fill_insns = calloc(MAX_TEST_INSNS, sizeof(struct bpf_insn));
Expand Down Expand Up @@ -967,6 +975,50 @@ static void do_test_fixup(struct bpf_test *test, enum bpf_prog_type prog_type,
fixup_kfunc_btf_id++;
} while (fixup_kfunc_btf_id->kfunc);
}

if (fixup_ldx->strct) {
const struct btf_member *memb;
const struct btf_type *tp;
const char *name;
struct btf *btf;
int btf_id;
int off;
int i;

btf = btf__load_vmlinux_btf();

do {
off = -1;
if (!btf)
goto next_ldx;

btf_id = btf__find_by_name_kind(btf,
fixup_ldx->strct,
BTF_KIND_STRUCT);
if (btf_id < 0)
goto next_ldx;

tp = btf__type_by_id(btf, btf_id);
memb = btf_members(tp);

for (i = 0; i < btf_vlen(tp); i++) {
name = btf__name_by_offset(btf,
memb->name_off);
if (strcmp(fixup_ldx->field, name) == 0) {
off = memb->offset / 8;
break;
}
memb++;
}

next_ldx:
prog[fixup_ldx->insn_idx].off = off;
fixup_ldx++;

} while (fixup_ldx->strct);

btf__free(btf);
}
}

struct libcap {
Expand Down Expand Up @@ -1131,7 +1183,7 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
opts.log_level = 4;
opts.prog_flags = pflags;

if (prog_type == BPF_PROG_TYPE_TRACING && test->kfunc) {
if (test->kfunc) {
int attach_btf_id;

attach_btf_id = libbpf_find_vmlinux_btf_id(test->kfunc,
Expand Down
34 changes: 34 additions & 0 deletions tools/testing/selftests/bpf/verifier/lsm_cgroup.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#define SK_WRITABLE_FIELD(tp, field, size, res) \
{ \
.descr = field, \
.insns = { \
/* r1 = *(u64 *)(r1 + 0) */ \
BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_1, 0), \
/* r1 = *(u64 *)(r1 + offsetof(struct socket, sk)) */ \
BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_1, 0), \
/* r2 = *(u64 *)(r1 + offsetof(struct sock, <field>)) */ \
BPF_LDX_MEM(size, BPF_REG_2, BPF_REG_1, 0), \
/* *(u64 *)(r1 + offsetof(struct sock, <field>)) = r2 */ \
BPF_STX_MEM(size, BPF_REG_1, BPF_REG_2, 0), \
BPF_MOV64_IMM(BPF_REG_0, 1), \
BPF_EXIT_INSN(), \
}, \
.result = res, \
.errstr = res ? "no write support to 'struct sock' at off" : "", \
.prog_type = BPF_PROG_TYPE_LSM, \
.expected_attach_type = BPF_LSM_CGROUP, \
.kfunc = "socket_post_create", \
.fixup_ldx = { \
{ "socket", "sk", 1 }, \
{ tp, field, 2 }, \
{ tp, field, 3 }, \
}, \
}

SK_WRITABLE_FIELD("sock_common", "skc_family", BPF_H, REJECT),
SK_WRITABLE_FIELD("sock", "sk_sndtimeo", BPF_DW, REJECT),
SK_WRITABLE_FIELD("sock", "sk_priority", BPF_W, ACCEPT),
SK_WRITABLE_FIELD("sock", "sk_mark", BPF_W, ACCEPT),
SK_WRITABLE_FIELD("sock", "sk_pacing_rate", BPF_DW, REJECT),

#undef SK_WRITABLE_FIELD

0 comments on commit 6fa78aa

Please sign in to comment.