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 #include <sys/resource.h> 16 17 #include <linux/filter.h> 18 #include <linux/bpf.h> 19 #include <linux/if_alg.h> 20 21 #include <bpf/bpf.h> 22 23 #include "../../../include/linux/filter.h" 24 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); 60 fd_prog = bpf_load_program(BPF_PROG_TYPE_SCHED_CLS, prog, insns, "", 0, 61 NULL, 0); 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)) { 104 if (strncmp(buff, "prog_tag:\t", prefix_len)) 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); 192 fd_map = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(int), 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 } 205