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