at v3.19-rc1 203 lines 4.4 kB view raw
1#include <stdio.h> 2#include <sys/types.h> 3#include <sys/stat.h> 4#include <fcntl.h> 5#include <libelf.h> 6#include <gelf.h> 7#include <errno.h> 8#include <unistd.h> 9#include <string.h> 10#include <stdbool.h> 11#include <linux/bpf.h> 12#include <linux/filter.h> 13#include "libbpf.h" 14#include "bpf_helpers.h" 15#include "bpf_load.h" 16 17static char license[128]; 18static bool processed_sec[128]; 19int map_fd[MAX_MAPS]; 20int prog_fd[MAX_PROGS]; 21int prog_cnt; 22 23static int load_and_attach(const char *event, struct bpf_insn *prog, int size) 24{ 25 int fd; 26 bool is_socket = strncmp(event, "socket", 6) == 0; 27 28 if (!is_socket) 29 /* tracing events tbd */ 30 return -1; 31 32 fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, 33 prog, size, license); 34 35 if (fd < 0) { 36 printf("bpf_prog_load() err=%d\n%s", errno, bpf_log_buf); 37 return -1; 38 } 39 40 prog_fd[prog_cnt++] = fd; 41 42 return 0; 43} 44 45static int load_maps(struct bpf_map_def *maps, int len) 46{ 47 int i; 48 49 for (i = 0; i < len / sizeof(struct bpf_map_def); i++) { 50 51 map_fd[i] = bpf_create_map(maps[i].type, 52 maps[i].key_size, 53 maps[i].value_size, 54 maps[i].max_entries); 55 if (map_fd[i] < 0) 56 return 1; 57 } 58 return 0; 59} 60 61static int get_sec(Elf *elf, int i, GElf_Ehdr *ehdr, char **shname, 62 GElf_Shdr *shdr, Elf_Data **data) 63{ 64 Elf_Scn *scn; 65 66 scn = elf_getscn(elf, i); 67 if (!scn) 68 return 1; 69 70 if (gelf_getshdr(scn, shdr) != shdr) 71 return 2; 72 73 *shname = elf_strptr(elf, ehdr->e_shstrndx, shdr->sh_name); 74 if (!*shname || !shdr->sh_size) 75 return 3; 76 77 *data = elf_getdata(scn, 0); 78 if (!*data || elf_getdata(scn, *data) != NULL) 79 return 4; 80 81 return 0; 82} 83 84static int parse_relo_and_apply(Elf_Data *data, Elf_Data *symbols, 85 GElf_Shdr *shdr, struct bpf_insn *insn) 86{ 87 int i, nrels; 88 89 nrels = shdr->sh_size / shdr->sh_entsize; 90 91 for (i = 0; i < nrels; i++) { 92 GElf_Sym sym; 93 GElf_Rel rel; 94 unsigned int insn_idx; 95 96 gelf_getrel(data, i, &rel); 97 98 insn_idx = rel.r_offset / sizeof(struct bpf_insn); 99 100 gelf_getsym(symbols, GELF_R_SYM(rel.r_info), &sym); 101 102 if (insn[insn_idx].code != (BPF_LD | BPF_IMM | BPF_DW)) { 103 printf("invalid relo for insn[%d].code 0x%x\n", 104 insn_idx, insn[insn_idx].code); 105 return 1; 106 } 107 insn[insn_idx].src_reg = BPF_PSEUDO_MAP_FD; 108 insn[insn_idx].imm = map_fd[sym.st_value / sizeof(struct bpf_map_def)]; 109 } 110 111 return 0; 112} 113 114int load_bpf_file(char *path) 115{ 116 int fd, i; 117 Elf *elf; 118 GElf_Ehdr ehdr; 119 GElf_Shdr shdr, shdr_prog; 120 Elf_Data *data, *data_prog, *symbols = NULL; 121 char *shname, *shname_prog; 122 123 if (elf_version(EV_CURRENT) == EV_NONE) 124 return 1; 125 126 fd = open(path, O_RDONLY, 0); 127 if (fd < 0) 128 return 1; 129 130 elf = elf_begin(fd, ELF_C_READ, NULL); 131 132 if (!elf) 133 return 1; 134 135 if (gelf_getehdr(elf, &ehdr) != &ehdr) 136 return 1; 137 138 /* scan over all elf sections to get license and map info */ 139 for (i = 1; i < ehdr.e_shnum; i++) { 140 141 if (get_sec(elf, i, &ehdr, &shname, &shdr, &data)) 142 continue; 143 144 if (0) /* helpful for llvm debugging */ 145 printf("section %d:%s data %p size %zd link %d flags %d\n", 146 i, shname, data->d_buf, data->d_size, 147 shdr.sh_link, (int) shdr.sh_flags); 148 149 if (strcmp(shname, "license") == 0) { 150 processed_sec[i] = true; 151 memcpy(license, data->d_buf, data->d_size); 152 } else if (strcmp(shname, "maps") == 0) { 153 processed_sec[i] = true; 154 if (load_maps(data->d_buf, data->d_size)) 155 return 1; 156 } else if (shdr.sh_type == SHT_SYMTAB) { 157 symbols = data; 158 } 159 } 160 161 /* load programs that need map fixup (relocations) */ 162 for (i = 1; i < ehdr.e_shnum; i++) { 163 164 if (get_sec(elf, i, &ehdr, &shname, &shdr, &data)) 165 continue; 166 if (shdr.sh_type == SHT_REL) { 167 struct bpf_insn *insns; 168 169 if (get_sec(elf, shdr.sh_info, &ehdr, &shname_prog, 170 &shdr_prog, &data_prog)) 171 continue; 172 173 insns = (struct bpf_insn *) data_prog->d_buf; 174 175 processed_sec[shdr.sh_info] = true; 176 processed_sec[i] = true; 177 178 if (parse_relo_and_apply(data, symbols, &shdr, insns)) 179 continue; 180 181 if (memcmp(shname_prog, "events/", 7) == 0 || 182 memcmp(shname_prog, "socket", 6) == 0) 183 load_and_attach(shname_prog, insns, data_prog->d_size); 184 } 185 } 186 187 /* load programs that don't use maps */ 188 for (i = 1; i < ehdr.e_shnum; i++) { 189 190 if (processed_sec[i]) 191 continue; 192 193 if (get_sec(elf, i, &ehdr, &shname, &shdr, &data)) 194 continue; 195 196 if (memcmp(shname, "events/", 7) == 0 || 197 memcmp(shname, "socket", 6) == 0) 198 load_and_attach(shname, data->d_buf, data->d_size); 199 } 200 201 close(fd); 202 return 0; 203}