From mboxrd@z Thu Jan 1 00:00:00 1970 From: Clemens Famulla-Conrad Date: Wed, 28 Aug 2019 09:41:28 +0200 Subject: [LTP] [PATCH v4 4/4] BPF: Sanity check creating a program In-Reply-To: <20190826111024.19053-5-chrubis@suse.cz> References: <20190826111024.19053-1-chrubis@suse.cz> <20190826111024.19053-5-chrubis@suse.cz> Message-ID: <1566978088.6539.16.camel@suse.de> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: ltp@lists.linux.it Acked-by: Clemens Famulla-Conrad On Mon, 2019-08-26 at 13:10 +0200, Cyril Hrubis wrote: > From: Richard Palethorpe > > Signed-off-by: Richard Palethorpe > Reviewed-by: Cyril Hrubis > --- > runtest/syscalls | 1 + > testcases/kernel/syscalls/bpf/.gitignore | 1 + > testcases/kernel/syscalls/bpf/bpf_prog01.c | 162 > +++++++++++++++++++++ > 3 files changed, 164 insertions(+) > create mode 100644 testcases/kernel/syscalls/bpf/bpf_prog01.c > > diff --git a/runtest/syscalls b/runtest/syscalls > index 6ddfc2178..ec9f5ef6d 100644 > --- a/runtest/syscalls > +++ b/runtest/syscalls > @@ -33,6 +33,7 @@ bind02 bind02 > bind03 bind03 > > bpf_map01 bpf_map01 > +bpf_prog01 bpf_prog01 > > brk01 brk01 > > diff --git a/testcases/kernel/syscalls/bpf/.gitignore > b/testcases/kernel/syscalls/bpf/.gitignore > index f33532484..7eb5f7c92 100644 > --- a/testcases/kernel/syscalls/bpf/.gitignore > +++ b/testcases/kernel/syscalls/bpf/.gitignore > @@ -1 +1,2 @@ > bpf_map01 > +bpf_prog01 > diff --git a/testcases/kernel/syscalls/bpf/bpf_prog01.c > b/testcases/kernel/syscalls/bpf/bpf_prog01.c > new file mode 100644 > index 000000000..135324efb > --- /dev/null > +++ b/testcases/kernel/syscalls/bpf/bpf_prog01.c > @@ -0,0 +1,162 @@ > +// SPDX-License-Identifier: GPL-2.0-or-later > +/* > + * Copyright (c) 2019 Richard Palethorpe > + * > + * Trivial Extended Berkeley Packet Filter (eBPF) test. > + * > + * Sanity check loading and running bytecode. > + * > + * Test flow: > + * 1. Create array map > + * 2. Load eBPF program > + * 3. Attach program to socket > + * 4. Send packet on socket > + * 5. This should trigger eBPF program which writes to array map > + * 6. Verify array map was written to > + */ > + > +#include > +#include > +#include > + > +#include "config.h" > +#include "tst_test.h" > +#include "lapi/socket.h" > +#include "lapi/bpf.h" > + > +const char MSG[] = "Ahoj!"; > +static char *msg; > + > +/* > + * The following is a byte code template. We copy it to a guarded > buffer and > + * substitute the runtime value of our map file descriptor. > + * > + * r0 - r10 = registers 0 to 10 > + * r0 = return code > + * r1 - r5 = scratch registers, used for function arguments > + * r6 - r9 = registers preserved across function calls > + * fp/r10 = stack frame pointer > + */ > +const struct bpf_insn PROG[] = { > + /* Load the map FD into r1 (place holder) */ > + BPF_LD_MAP_FD(BPF_REG_1, 0), > + /* Put (key = 0) on stack and key ptr into r2 */ > + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), /* r2 = fp */ > + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), /* r2 = r2 - 8 */ > + BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), /* *r2 = 0 */ /* *(u64 * r2) = 0 */ Is it possible to can call `BPF_FUNC_map_lookup_elem` with u32, like here[1]? Maybe that hint helps to see that BPF_DW more quickly then I did :) [1] https://github.com/torvalds/linux/blob/v4.20/samples/bpf/sock_examp le.c#L52 > + /* r0 = bpf_map_lookup_elem(r1, r2) */ > + BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), > + /* if r0 == 0 goto exit */ > + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3), > + /* Set map[0] = 1 */ > + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), /* r1 = r0 */ > + BPF_ST_MEM(BPF_DW, BPF_REG_1, 0, 1), /* *r1 = 1 */ > + BPF_MOV64_IMM(BPF_REG_0, 0), /* r0 = 0 */ > + BPF_EXIT_INSN(), /* return r0 */ > +}; > + > +static struct bpf_insn *prog; > +static char *log; > +static union bpf_attr *attr; > + > +int load_prog(int fd) > +{ > + prog[0] = BPF_LD_MAP_FD(BPF_REG_1, fd); > + > + memset(attr, 0, sizeof(*attr)); > + attr->prog_type = BPF_PROG_TYPE_SOCKET_FILTER; > + attr->insns = ptr_to_u64(prog); > + attr->insn_cnt = ARRAY_SIZE(PROG); > + attr->license = ptr_to_u64("GPL"); > + attr->log_buf = ptr_to_u64(log); > + attr->log_size = BUFSIZ; > + attr->log_level = 1; > + > + TEST(bpf(BPF_PROG_LOAD, attr, sizeof(*attr))); > + if (TST_RET == -1) { > + if (log[0] != 0) { > + tst_brk(TFAIL | TTERRNO, > + "Failed verification: %s", > + log); > + } else { > + tst_brk(TFAIL | TTERRNO, "Failed to load > program"); > + } > + } else { > + tst_res(TPASS, "Loaded program"); > + } > + > + return TST_RET; > +} > + > +void setup(void) > +{ > + memcpy(prog, PROG, sizeof(PROG)); > + memcpy(msg, MSG, sizeof(MSG)); > +} > + > +void run(void) > +{ > + int map_fd, prog_fd; > + int sk[2]; > + uint32_t key = 0; > + uint64_t val; > + > + memset(attr, 0, sizeof(*attr)); > + attr->map_type = BPF_MAP_TYPE_ARRAY; > + attr->key_size = 4; > + attr->value_size = 8; > + attr->max_entries = 1; > + > + TEST(bpf(BPF_MAP_CREATE, attr, sizeof(*attr))); > + if (TST_RET == -1) { > + if (TST_ERR == EPERM) { > + tst_brk(TCONF | TTERRNO, > + "bpf() requires CAP_SYS_ADMIN on > this system"); > + } else { > + tst_brk(TBROK | TTERRNO, "Failed to create > array map"); > + } > + } > + map_fd = TST_RET; > + > + prog_fd = load_prog(map_fd); > + > + SAFE_SOCKETPAIR(AF_UNIX, SOCK_DGRAM, 0, sk); > + SAFE_SETSOCKOPT(sk[1], SOL_SOCKET, SO_ATTACH_BPF, > + &prog_fd, sizeof(prog_fd)); > + > + SAFE_WRITE(1, sk[0], msg, sizeof(MSG)); > + > + memset(attr, 0, sizeof(*attr)); > + attr->map_fd = map_fd; > + attr->key = ptr_to_u64(&key); > + attr->value = ptr_to_u64(&val); > + > + TEST(bpf(BPF_MAP_LOOKUP_ELEM, attr, sizeof(*attr))); > + if (TST_RET == -1) { > + tst_res(TFAIL | TTERRNO, "array map lookup"); > + } else if (val != 1) { > + tst_res(TFAIL, > + "val = %lu, but should be val = 1", > + val); > + } else { > + tst_res(TPASS, "val = 1"); > + } > + > + SAFE_CLOSE(prog_fd); > + SAFE_CLOSE(map_fd); > + SAFE_CLOSE(sk[0]); > + SAFE_CLOSE(sk[1]); > +} > + > +static struct tst_test test = { > + .setup = setup, > + .test_all = run, > + .min_kver = "3.18", > + .bufs = (struct tst_buffers []) { > + {&log, .size = BUFSIZ}, > + {&prog, .size = sizeof(PROG)}, > + {&attr, .size = sizeof(*attr)}, > + {&msg, .size = sizeof(MSG)}, > + {}, > + } > +}; > -- > 2.21.0 > >