[LTP] [PATCH v4 4/4] BPF: Sanity check creating a program

Clemens Famulla-Conrad cfamullaconrad@suse.de
Wed Aug 28 09:41:28 CEST 2019


Acked-by: Clemens Famulla-Conrad <cfamullaconrad@suse.de>

On Mon, 2019-08-26 at 13:10 +0200, Cyril Hrubis wrote:
> From: Richard Palethorpe <rpalethorpe@suse.com>
> 
> Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
> Reviewed-by: Cyril Hrubis <chrubis@suse.cz>
> ---
>  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 <rpalethorpe@suse.com>
> + *
> + * 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 <limits.h>
> +#include <string.h>
> +#include <stdio.h>
> +
> +#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
> 
> 


More information about the ltp mailing list