1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3 * Copyright (c) 2019-2020 Linux Test Project
4 */
5
6 #define TST_NO_DEFAULT_MAIN
7 #include "tst_test.h"
8 #include "bpf_common.h"
9
rlimit_bump_memlock(void)10 void rlimit_bump_memlock(void)
11 {
12 struct rlimit memlock_r;
13
14 SAFE_GETRLIMIT(RLIMIT_MEMLOCK, &memlock_r);
15 memlock_r.rlim_cur += BPF_MEMLOCK_ADD;
16 tst_res(TINFO, "Raising RLIMIT_MEMLOCK to %ld",
17 (long)memlock_r.rlim_cur);
18
19 if (memlock_r.rlim_cur <= memlock_r.rlim_max) {
20 SAFE_SETRLIMIT(RLIMIT_MEMLOCK, &memlock_r);
21 } else if ((geteuid() == 0)) {
22 memlock_r.rlim_max += BPF_MEMLOCK_ADD;
23 SAFE_SETRLIMIT(RLIMIT_MEMLOCK, &memlock_r);
24 } else {
25 tst_res(TINFO, "Can't raise RLIMIT_MEMLOCK, test may fail "
26 "due to lack of max locked memory");
27 }
28 }
29
bpf_map_create(union bpf_attr * const attr)30 int bpf_map_create(union bpf_attr *const attr)
31 {
32 int ret;
33
34 ret = TST_RETRY_FUNC(bpf(BPF_MAP_CREATE, attr, sizeof(*attr)),
35 TST_RETVAL_GE0);
36
37 if (ret == -1) {
38 if (errno == EPERM) {
39 tst_res(TCONF, "Hint: check also /proc/sys/kernel/unprivileged_bpf_disabled");
40 tst_brk(TCONF | TERRNO,
41 "bpf() requires CAP_SYS_ADMIN or CAP_BPF on this system");
42 } else {
43 tst_brk(TBROK | TERRNO, "Failed to create array map");
44 }
45 }
46
47 return ret;
48 }
49
bpf_map_array_create(const uint32_t max_entries)50 int bpf_map_array_create(const uint32_t max_entries)
51 {
52 union bpf_attr map_attr = {
53 .map_type = BPF_MAP_TYPE_ARRAY,
54 .key_size = 4,
55 .value_size = 8,
56 .max_entries = max_entries,
57 .map_flags = 0
58 };
59
60 return bpf_map_create(&map_attr);
61 }
62
bpf_map_array_get(const int map_fd,const uint32_t * const array_indx,uint64_t * const array_val)63 void bpf_map_array_get(const int map_fd,
64 const uint32_t *const array_indx,
65 uint64_t *const array_val)
66 {
67 union bpf_attr elem_attr = {
68 .map_fd = map_fd,
69 .key = ptr_to_u64(array_indx),
70 .value = ptr_to_u64(array_val),
71 .flags = 0
72 };
73 const int ret = bpf(BPF_MAP_LOOKUP_ELEM, &elem_attr, sizeof(elem_attr));
74
75 if (ret) {
76 tst_brk(TBROK | TTERRNO,
77 "Failed array map lookup: fd=%i [%"PRIu32"]",
78 map_fd, *array_indx);
79 }
80 }
81
bpf_init_prog_attr(union bpf_attr * const attr,const struct bpf_insn * const prog,const size_t prog_size,char * const log_buf,const size_t log_size)82 void bpf_init_prog_attr(union bpf_attr *const attr,
83 const struct bpf_insn *const prog,
84 const size_t prog_size, char *const log_buf,
85 const size_t log_size)
86 {
87 static struct bpf_insn *buf;
88 static size_t buf_size;
89 const size_t prog_len = prog_size / sizeof(*prog);
90
91 /* all guarded buffers will be free()d automatically by LTP library */
92 if (!buf || prog_size > buf_size) {
93 buf = tst_alloc(prog_size);
94 buf_size = prog_size;
95 }
96
97 memcpy(buf, prog, prog_size);
98 memset(attr, 0, sizeof(*attr));
99 attr->prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
100 attr->insns = ptr_to_u64(buf);
101 attr->insn_cnt = prog_len;
102 attr->license = ptr_to_u64("GPL");
103 attr->log_buf = ptr_to_u64(log_buf);
104 attr->log_size = log_size;
105 attr->log_level = 1;
106 }
107
bpf_load_prog(union bpf_attr * const attr,const char * const log)108 int bpf_load_prog(union bpf_attr *const attr, const char *const log)
109 {
110 const int ret = TST_RETRY_FUNC(bpf(BPF_PROG_LOAD, attr, sizeof(*attr)),
111 TST_RETVAL_GE0);
112
113 if (ret >= 0) {
114 tst_res(TPASS, "Loaded program");
115 return ret;
116 }
117
118 if (ret != -1)
119 tst_brk(TBROK, "Invalid bpf() return value: %d", ret);
120
121 if (log[0] != 0) {
122 tst_printf("%s\n", log);
123 tst_brk(TBROK | TERRNO, "Failed verification");
124 }
125
126 tst_brk(TBROK | TERRNO, "Failed to load program");
127 return ret;
128 }
129
bpf_run_prog(const int prog_fd,const char * const msg,const size_t msg_len)130 void bpf_run_prog(const int prog_fd,
131 const char *const msg, const size_t msg_len)
132 {
133 int sk[2];
134
135 SAFE_SOCKETPAIR(AF_UNIX, SOCK_DGRAM, 0, sk);
136 SAFE_SETSOCKOPT(sk[1], SOL_SOCKET, SO_ATTACH_BPF,
137 &prog_fd, sizeof(prog_fd));
138
139 SAFE_WRITE(1, sk[0], msg, msg_len);
140
141 SAFE_CLOSE(sk[0]);
142 SAFE_CLOSE(sk[1]);
143 }
144