github.com/datadog/cilium@v1.6.12/bpf/probes/raw_main.c (about) 1 /* 2 * Copyright (C) 2017 Authors of Cilium 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19 #include <unistd.h> 20 #include <stdio.h> 21 #include <stdint.h> 22 #include <string.h> 23 #include <errno.h> 24 25 #include <sys/resource.h> 26 27 #include "raw_insn.h" 28 29 #include "iproute2/bpf_elf.h" 30 31 #define BPF_MAX_FIXUPS 64 32 #define BPF_MAX_INSNS (2 * BPF_MAXINSNS) 33 34 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 35 36 struct bpf_map_fixup { 37 int off; 38 enum bpf_map_type type; 39 uint32_t size_key; 40 uint32_t size_val; 41 uint32_t flags; 42 }; 43 44 struct bpf_test { 45 const char *emits; 46 enum bpf_prog_type type; 47 enum bpf_attach_type attach_type; 48 struct bpf_insn insns[BPF_MAX_INSNS]; 49 struct bpf_map_fixup fixup_map[BPF_MAX_FIXUPS]; 50 const char *warn; 51 }; 52 53 static struct bpf_test tests[] = { 54 #include "raw_probe.t" 55 }; 56 57 static uint64_t bpf_ptr_to_u64(const void *ptr) 58 { 59 return (uint64_t)(unsigned long)ptr; 60 } 61 62 #ifndef __NR_bpf 63 # if defined(__i386__) 64 # define __NR_bpf 357 65 # elif defined(__x86_64__) 66 # define __NR_bpf 321 67 # elif defined(__aarch64__) 68 # define __NR_bpf 280 69 # else 70 # warning __NR_bpf not defined. 71 # endif 72 #endif 73 74 static int bpf(int cmd, union bpf_attr *attr, unsigned int size) 75 { 76 #ifdef __NR_bpf 77 return syscall(__NR_bpf, cmd, attr, size); 78 #else 79 errno = ENOSYS; 80 return -1; 81 #endif 82 } 83 84 int bpf_prog_load(enum bpf_prog_type type, enum bpf_attach_type attach_type, 85 const struct bpf_insn *insns, size_t num_insns, 86 const char *license, char *log, size_t size_log) 87 { 88 union bpf_attr attr; 89 90 memset(&attr, 0, sizeof(attr)); 91 attr.prog_type = type; 92 attr.insns = bpf_ptr_to_u64(insns); 93 attr.insn_cnt = num_insns; 94 attr.license = bpf_ptr_to_u64(license); 95 attr.expected_attach_type = attach_type; 96 97 if (size_log > 0) { 98 attr.log_buf = bpf_ptr_to_u64(log); 99 attr.log_size = size_log; 100 attr.log_level = 1; 101 } 102 103 return bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); 104 } 105 106 static int bpf_map_create(enum bpf_map_type type, uint32_t size_key, 107 uint32_t size_value, uint32_t max_elem, 108 uint32_t flags) 109 { 110 union bpf_attr attr; 111 112 memset(&attr, 0, sizeof(attr)); 113 attr.map_type = type; 114 attr.key_size = size_key; 115 attr.value_size = size_value; 116 attr.max_entries = max_elem; 117 attr.map_flags = flags; 118 119 return bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); 120 } 121 122 static int bpf_test_length(const struct bpf_insn *insn, size_t max) 123 { 124 int len; 125 126 for (len = max - 1; len > 0; --len) 127 if (insn[len].code != 0 || insn[len].imm != 0) 128 break; 129 130 return len + 1; 131 } 132 133 /* From iproute2/lib/bpf.c */ 134 static void bpf_map_pin_report(const struct bpf_elf_map *pin, 135 const struct bpf_elf_map *obj) 136 { 137 fprintf(stderr, "Map specification differs from pinned file!\n"); 138 139 if (obj->type != pin->type) 140 fprintf(stderr, " - Type: %u (obj) != %u (pin)\n", 141 obj->type, pin->type); 142 if (obj->size_key != pin->size_key) 143 fprintf(stderr, " - Size key: %u (obj) != %u (pin)\n", 144 obj->size_key, pin->size_key); 145 if (obj->size_value != pin->size_value) 146 fprintf(stderr, " - Size value: %u (obj) != %u (pin)\n", 147 obj->size_value, pin->size_value); 148 if (obj->max_elem != pin->max_elem) 149 fprintf(stderr, " - Max elems: %u (obj) != %u (pin)\n", 150 obj->max_elem, pin->max_elem); 151 if (obj->flags != pin->flags) 152 fprintf(stderr, " - Flags: %#x (obj) != %#x (pin)\n", 153 obj->flags, pin->flags); 154 if (obj->pinning != pin->pinning) 155 fprintf(stderr, " - Pinning: %#x (obj) != %#x (pin)\n", 156 obj->pinning, pin->pinning); 157 158 fprintf(stderr, "\n"); 159 } 160 161 #ifndef PATH_MAX 162 #define PATH_MAX 4096 163 #endif 164 165 /* From iproute2/lib/bpf.c */ 166 static int bpf_map_selfcheck_pinned(int fd, const struct bpf_elf_map *map, 167 int length, enum bpf_prog_type type) 168 { 169 char file[PATH_MAX], buff[4096]; 170 struct bpf_elf_map tmp = {}, zero = {}; 171 unsigned int val, owner_type = 0; 172 FILE *fp; 173 174 snprintf(file, sizeof(file), "/proc/%d/fdinfo/%d", getpid(), fd); 175 176 fp = fopen(file, "r"); 177 if (!fp) { 178 fprintf(stderr, "No procfs support?!\n"); 179 return -EIO; 180 } 181 182 while (fgets(buff, sizeof(buff), fp)) { 183 if (sscanf(buff, "map_type:\t%u", &val) == 1) 184 tmp.type = val; 185 else if (sscanf(buff, "key_size:\t%u", &val) == 1) 186 tmp.size_key = val; 187 else if (sscanf(buff, "value_size:\t%u", &val) == 1) 188 tmp.size_value = val; 189 else if (sscanf(buff, "max_entries:\t%u", &val) == 1) 190 tmp.max_elem = val; 191 else if (sscanf(buff, "map_flags:\t%i", &val) == 1) 192 tmp.flags = val; 193 else if (sscanf(buff, "owner_prog_type:\t%i", &val) == 1) 194 owner_type = val; 195 } 196 197 fclose(fp); 198 199 /* The decision to reject this is on kernel side eventually, but 200 * at least give the user a chance to know what's wrong. 201 */ 202 if (owner_type && owner_type != type) 203 fprintf(stderr, "Program array map owner types differ: %u (obj) != %u (pin)\n", 204 type, owner_type); 205 206 if (!memcmp(&tmp, map, length)) { 207 return 0; 208 } else { 209 /* If kernel doesn't have eBPF-related fdinfo, we cannot do much, 210 * so just accept it. We know we do have an eBPF fd and in this 211 * case, everything is 0. It is guaranteed that no such map exists 212 * since map type of 0 is unloadable BPF_MAP_TYPE_UNSPEC. 213 */ 214 if (!memcmp(&tmp, &zero, length)) 215 return 0; 216 217 bpf_map_pin_report(&tmp, map); 218 return -EINVAL; 219 } 220 } 221 222 static void bpf_report(const struct bpf_test *test, int success, 223 int debug_mode) 224 { 225 static char bpf_vlog[1U << 17]; 226 int fd; 227 228 printf("%s#define %s\n\n", success ? "" : "// ", test->emits); 229 230 if (!success || debug_mode) { 231 printf("#if 0\n"); 232 printf("%s %s: ", test->emits, success ? 233 "debug output" : "failed due to load error"); 234 235 memset(bpf_vlog, 0, sizeof(bpf_vlog)); 236 fd = bpf_prog_load(test->type, test->attach_type, test->insns, 237 bpf_test_length(test->insns, ARRAY_SIZE(test->insns)), 238 "GPL", bpf_vlog, sizeof(bpf_vlog)); 239 printf("%s\n%s", strerror(errno), bpf_vlog); 240 printf("#endif\n\n"); 241 if (fd > 0) 242 close(fd); 243 } 244 245 if (!success && test->warn) 246 fprintf(stderr, "%s: %s\n", test->emits, test->warn); 247 } 248 249 static void bpf_run_test(struct bpf_test *test, int debug_mode) 250 { 251 struct bpf_map_fixup *map = test->fixup_map; 252 int fd; 253 254 /* We can use off here as it's never first insns. */ 255 while (map->off) { 256 struct bpf_elf_map elf_map = { 257 .type = map->type, 258 .size_key = map->size_key, 259 .size_value = map->size_val, 260 .pinning = 0, 261 .max_elem = 1, 262 .flags = map->flags, 263 }; 264 265 fd = bpf_map_create(map->type, map->size_key, 266 map->size_val, 1, map->flags); 267 if (fd < 0) { 268 if (debug_mode) { 269 printf("#if 0\n"); 270 printf("%s: bpf_map_create(): %s\n", 271 test->emits, strerror(errno)); 272 printf("#endif\n\n"); 273 } 274 /* We fail in verifier eventually. */ 275 break; 276 } 277 278 if (bpf_map_selfcheck_pinned(fd, &elf_map, sizeof elf_map, test->type) != 0) 279 break; 280 281 test->insns[map->off].imm = fd; 282 map++; 283 } 284 285 fd = bpf_prog_load(test->type, test->attach_type, test->insns, 286 bpf_test_length(test->insns, ARRAY_SIZE(test->insns)), 287 "GPL", NULL, 0); 288 bpf_report(test, fd > 0, debug_mode); 289 if (fd > 0) 290 close(fd); 291 } 292 293 int main(int argc, char **argv) 294 { 295 struct rlimit rold, rinf = { RLIM_INFINITY, RLIM_INFINITY }; 296 int debug_mode = 0; 297 int i; 298 299 if (argc > 1 && !strncmp(argv[argc - 1], "debug", sizeof("debug"))) 300 debug_mode = 1; 301 302 getrlimit(RLIMIT_MEMLOCK, &rold); 303 setrlimit(RLIMIT_MEMLOCK, &rinf); 304 305 for (i = 0; i < ARRAY_SIZE(tests); i++) 306 bpf_run_test(&tests[i], debug_mode); 307 308 setrlimit(RLIMIT_MEMLOCK, &rold); 309 return 0; 310 }