summaryrefslogtreecommitdiff
path: root/tools/testing/selftests/bpf/prog_tests/blinding_log.c
blob: 658a8494dae5b0ff9a0fbb99051d3aff7faa1b8c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// SPDX-License-Identifier: GPL-2.0
/* The verifier log of a prog whose constants are blinded */

#include <test_progs.h>
#include <linux/filter.h>
#include "sysctl_helpers.h"

#define NR_CONSTS 11000
#define LOG_SIZE 65536

/*
 * A prog of one function gets its constants blinded when its runtime is
 * selected. Each 'r0 += 1' becomes 3 insns, which pushes the jump over them
 * out of its 16-bit range. Serial, because it sets bpf_jit_harden.
 */
void serial_test_blinding_log(void)
{
	const char *harden = "/proc/sys/net/core/bpf_jit_harden";
	LIBBPF_OPTS(bpf_prog_load_opts, opts);
	struct bpf_insn *insns;
	char old[16] = {}, *log;
	int i, cnt = 0, fd;

	if (!is_jit_enabled()) {
		printf("%s:SKIP:JIT is disabled\n", __func__);
		test__skip();
		return;
	}

	insns = calloc(NR_CONSTS + 3, sizeof(*insns));
	log = calloc(1, LOG_SIZE);
	if (!ASSERT_OK_PTR(insns, "insns") || !ASSERT_OK_PTR(log, "log"))
		goto out;

	insns[cnt++] = BPF_EMIT_CALL(BPF_FUNC_get_prandom_u32);
	insns[cnt++] = BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, NR_CONSTS);
	for (i = 0; i < NR_CONSTS; i++)
		insns[cnt++] = BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 1);
	insns[cnt++] = BPF_EXIT_INSN();

	opts.log_buf = log;
	opts.log_size = LOG_SIZE;
	/* log stats only: level 1 logs each insn, which wraps the buffer */
	opts.log_level = 4;
	if (sysctl_set_or_fail(harden, old, "2"))
		goto out;
	fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns, cnt, &opts);
	sysctl_set_or_fail(harden, NULL, old);
	/* don't mind whether the interpreter takes the prog or the load fails */
	if (fd >= 0)
		close(fd);

	/* expect the message about the jump in the log and in log_true_size */
	ASSERT_HAS_SUBSTR(log, "cannot be patched due to 16-bit range", "log");
	ASSERT_EQ(opts.log_true_size, strlen(log) + 1, "log_true_size");
out:
	free(insns);
	free(log);
}