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