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