1 // SPDX-License-Identifier: GPL-2.0 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 26 static struct bpf_insn prog[BPF_MAXINSNS]; 27 28 static 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 38 static 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 54 static 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 69 static 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 79 static 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 92 static 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 115 static 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 145 static 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 155 static 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 166 static 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 186 int 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