1
2#include <stdint.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <ctype.h>
6#include <time.h>
7#include <errno.h>
8#include <unistd.h>
9#include <string.h>
10#include <sched.h>
11#include <limits.h>
12#include <assert.h>
13
14#include <sys/socket.h>
15
16#include <linux/filter.h>
17#include <linux/bpf.h>
18#include <linux/if_alg.h>
19
20#include <bpf/bpf.h>
21
22#include "../../../include/linux/filter.h"
23#include "bpf_rlimit.h"
24#include "testing_helpers.h"
25
26static struct bpf_insn prog[BPF_MAXINSNS];
27
28static void bpf_gen_imm_prog(unsigned int insns, int fd_map)
29{
30 int i;
31
32 srand(time(NULL));
33 for (i = 0; i < insns; i++)
34 prog[i] = BPF_ALU64_IMM(BPF_MOV, i % BPF_REG_10, rand());
35 prog[i - 1] = BPF_EXIT_INSN();
36}
37
38static void bpf_gen_map_prog(unsigned int insns, int fd_map)
39{
40 int i, j = 0;
41
42 for (i = 0; i + 1 < insns; i += 2) {
43 struct bpf_insn tmp[] = {
44 BPF_LD_MAP_FD(j++ % BPF_REG_10, fd_map)
45 };
46
47 memcpy(&prog[i], tmp, sizeof(tmp));
48 }
49 if (insns % 2 == 0)
50 prog[insns - 2] = BPF_ALU64_IMM(BPF_MOV, i % BPF_REG_10, 42);
51 prog[insns - 1] = BPF_EXIT_INSN();
52}
53
54static int bpf_try_load_prog(int insns, int fd_map,
55 void (*bpf_filler)(unsigned int insns,
56 int fd_map))
57{
58 int fd_prog;
59
60 bpf_filler(insns, fd_map);
61 fd_prog = bpf_test_load_program(BPF_PROG_TYPE_SCHED_CLS, prog, insns, "", 0,
62 NULL, 0);
63 assert(fd_prog > 0);
64 if (fd_map > 0)
65 bpf_filler(insns, 0);
66 return fd_prog;
67}
68
69static int __hex2bin(char ch)
70{
71 if ((ch >= '0') && (ch <= '9'))
72 return ch - '0';
73 ch = tolower(ch);
74 if ((ch >= 'a') && (ch <= 'f'))
75 return ch - 'a' + 10;
76 return -1;
77}
78
79static int hex2bin(uint8_t *dst, const char *src, size_t count)
80{
81 while (count--) {
82 int hi = __hex2bin(*src++);
83 int lo = __hex2bin(*src++);
84
85 if ((hi < 0) || (lo < 0))
86 return -1;
87 *dst++ = (hi << 4) | lo;
88 }
89 return 0;
90}
91
92static void tag_from_fdinfo(int fd_prog, uint8_t *tag, uint32_t len)
93{
94 const int prefix_len = sizeof("prog_tag:\t") - 1;
95 char buff[256];
96 int ret = -1;
97 FILE *fp;
98
99 snprintf(buff, sizeof(buff), "/proc/%d/fdinfo/%d", getpid(),
100 fd_prog);
101 fp = fopen(buff, "r");
102 assert(fp);
103
104 while (fgets(buff, sizeof(buff), fp)) {
105 if (strncmp(buff, "prog_tag:\t", prefix_len))
106 continue;
107 ret = hex2bin(tag, buff + prefix_len, len);
108 break;
109 }
110
111 fclose(fp);
112 assert(!ret);
113}
114
115static void tag_from_alg(int insns, uint8_t *tag, uint32_t len)
116{
117 static const struct sockaddr_alg alg = {
118 .salg_family = AF_ALG,
119 .salg_type = "hash",
120 .salg_name = "sha1",
121 };
122 int fd_base, fd_alg, ret;
123 ssize_t size;
124
125 fd_base = socket(AF_ALG, SOCK_SEQPACKET, 0);
126 assert(fd_base > 0);
127
128 ret = bind(fd_base, (struct sockaddr *)&alg, sizeof(alg));
129 assert(!ret);
130
131 fd_alg = accept(fd_base, NULL, 0);
132 assert(fd_alg > 0);
133
134 insns *= sizeof(struct bpf_insn);
135 size = write(fd_alg, prog, insns);
136 assert(size == insns);
137
138 size = read(fd_alg, tag, len);
139 assert(size == len);
140
141 close(fd_alg);
142 close(fd_base);
143}
144
145static void tag_dump(const char *prefix, uint8_t *tag, uint32_t len)
146{
147 int i;
148
149 printf("%s", prefix);
150 for (i = 0; i < len; i++)
151 printf("%02x", tag[i]);
152 printf("\n");
153}
154
155static void tag_exit_report(int insns, int fd_map, uint8_t *ftag,
156 uint8_t *atag, uint32_t len)
157{
158 printf("Program tag mismatch for %d insns%s!\n", insns,
159 fd_map < 0 ? "" : " with map");
160
161 tag_dump(" fdinfo result: ", ftag, len);
162 tag_dump(" af_alg result: ", atag, len);
163 exit(1);
164}
165
166static void do_test(uint32_t *tests, int start_insns, int fd_map,
167 void (*bpf_filler)(unsigned int insns, int fd))
168{
169 int i, fd_prog;
170
171 for (i = start_insns; i <= BPF_MAXINSNS; i++) {
172 uint8_t ftag[8], atag[sizeof(ftag)];
173
174 fd_prog = bpf_try_load_prog(i, fd_map, bpf_filler);
175 tag_from_fdinfo(fd_prog, ftag, sizeof(ftag));
176 tag_from_alg(i, atag, sizeof(atag));
177 if (memcmp(ftag, atag, sizeof(ftag)))
178 tag_exit_report(i, fd_map, ftag, atag, sizeof(ftag));
179
180 close(fd_prog);
181 sched_yield();
182 (*tests)++;
183 }
184}
185
186int main(void)
187{
188 LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = BPF_F_NO_PREALLOC);
189 uint32_t tests = 0;
190 int i, fd_map;
191
192 fd_map = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(int),
193 sizeof(int), 1, &opts);
194 assert(fd_map > 0);
195
196 for (i = 0; i < 5; i++) {
197 do_test(&tests, 2, -1, bpf_gen_imm_prog);
198 do_test(&tests, 3, fd_map, bpf_gen_map_prog);
199 }
200
201 printf("test_tag: OK (%u tests)\n", tests);
202 close(fd_map);
203 return 0;
204}
205