Commit 8b08807d authored by Dmitrii Banshchikov's avatar Dmitrii Banshchikov Committed by Alexei Starovoitov
Browse files

selftests/bpf: Add unit tests for pointers in global functions



test_global_func9  - check valid pointer's scenarios
test_global_func10 - check that a smaller type cannot be passed as a
                     larger one
test_global_func11 - check that CTX pointer cannot be passed
test_global_func12 - check access to a null pointer
test_global_func13 - check access to an arbitrary pointer value
test_global_func14 - check that an opaque pointer cannot be passed
test_global_func15 - check that a variable has an unknown value after
		     it was passed to a global function by pointer
test_global_func16 - check access to uninitialized stack memory

test_global_func_args - check read and write operations through a pointer

Signed-off-by: default avatarDmitrii Banshchikov <me@ubique.spb.ru>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
Acked-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20210212205642.620788-5-me@ubique.spb.ru
parent e5069b9c
Loading
Loading
Loading
Loading
+60 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
#include "test_progs.h"
#include "network_helpers.h"

static __u32 duration;

static void test_global_func_args0(struct bpf_object *obj)
{
	int err, i, map_fd, actual_value;
	const char *map_name = "values";

	map_fd = bpf_find_map(__func__, obj, map_name);
	if (CHECK(map_fd < 0, "bpf_find_map", "cannot find BPF map %s: %s\n",
		map_name, strerror(errno)))
		return;

	struct {
		const char *descr;
		int expected_value;
	} tests[] = {
		{"passing NULL pointer", 0},
		{"returning value", 1},
		{"reading local variable", 100 },
		{"writing local variable", 101 },
		{"reading global variable", 42 },
		{"writing global variable", 43 },
		{"writing to pointer-to-pointer", 1 },
	};

	for (i = 0; i < ARRAY_SIZE(tests); ++i) {
		const int expected_value = tests[i].expected_value;

		err = bpf_map_lookup_elem(map_fd, &i, &actual_value);

		CHECK(err || actual_value != expected_value, tests[i].descr,
			 "err %d result %d expected %d\n", err, actual_value, expected_value);
	}
}

void test_global_func_args(void)
{
	const char *file = "./test_global_func_args.o";
	__u32 retval;
	struct bpf_object *obj;
	int err, prog_fd;

	err = bpf_prog_load(file, BPF_PROG_TYPE_CGROUP_SKB, &obj, &prog_fd);
	if (CHECK(err, "load program", "error %d loading %s\n", err, file))
		return;

	err = bpf_prog_test_run(prog_fd, 1, &pkt_v4, sizeof(pkt_v4),
				NULL, NULL, &retval, &duration);
	CHECK(err || retval, "pass global func args run",
	      "err %d errno %d retval %d duration %d\n",
	      err, errno, retval, duration);

	test_global_func_args0(obj);

	bpf_object__close(obj);
}
+8 −0
Original line number Diff line number Diff line
@@ -61,6 +61,14 @@ void test_test_global_funcs(void)
		{ "test_global_func6.o" , "modified ctx ptr R2" },
		{ "test_global_func7.o" , "foo() doesn't return scalar" },
		{ "test_global_func8.o" },
		{ "test_global_func9.o" },
		{ "test_global_func10.o", "invalid indirect read from stack" },
		{ "test_global_func11.o", "Caller passes invalid args into func#1" },
		{ "test_global_func12.o", "invalid mem access 'mem_or_null'" },
		{ "test_global_func13.o", "Caller passes invalid args into func#1" },
		{ "test_global_func14.o", "reference type('FWD S') size cannot be determined" },
		{ "test_global_func15.o", "At program exit the register R0 has value" },
		{ "test_global_func16.o", "invalid indirect read from stack" },
	};
	libbpf_print_fn_t old_print_fn = NULL;
	int err, i, duration = 0;
+29 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
#include <stddef.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>

struct Small {
	int x;
};

struct Big {
	int x;
	int y;
};

__noinline int foo(const struct Big *big)
{
	if (big == 0)
		return 0;

	return bpf_get_prandom_u32() < big->y;
}

SEC("cgroup_skb/ingress")
int test_cls(struct __sk_buff *skb)
{
	const struct Small small = {.x = skb->len };

	return foo((struct Big *)&small) ? 1 : 0;
}
+19 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
#include <stddef.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>

struct S {
	int x;
};

__noinline int foo(const struct S *s)
{
	return s ? bpf_get_prandom_u32() < s->x : 0;
}

SEC("cgroup_skb/ingress")
int test_cls(struct __sk_buff *skb)
{
	return foo(skb);
}
+21 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
#include <stddef.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>

struct S {
	int x;
};

__noinline int foo(const struct S *s)
{
	return bpf_get_prandom_u32() < s->x;
}

SEC("cgroup_skb/ingress")
int test_cls(struct __sk_buff *skb)
{
	const struct S s = {.x = skb->len };

	return foo(&s);
}
Loading