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 <stdlib.h> 12#include <linux/bpf.h> 13#include <linux/filter.h> 14#include <linux/perf_event.h> 15#include <sys/syscall.h> 16#include <sys/ioctl.h> 17#include <sys/mman.h> 18#include <poll.h> 19#include "libbpf.h" 20#include "bpf_helpers.h" 21#include "bpf_load.h" 22 23#define DEBUGFS "/sys/kernel/debug/tracing/" 24 25static char license[128]; 26static int kern_version; 27static bool processed_sec[128]; 28int map_fd[MAX_MAPS]; 29int prog_fd[MAX_PROGS]; 30int event_fd[MAX_PROGS]; 31int prog_cnt; 32 33static int load_and_attach(const char *event, struct bpf_insn *prog, int size) 34{ 35 bool is_socket = strncmp(event, "socket", 6) == 0; 36 bool is_kprobe = strncmp(event, "kprobe/", 7) == 0; 37 bool is_kretprobe = strncmp(event, "kretprobe/", 10) == 0; 38 enum bpf_prog_type prog_type; 39 char buf[256]; 40 int fd, efd, err, id; 41 struct perf_event_attr attr = {}; 42 43 attr.type = PERF_TYPE_TRACEPOINT; 44 attr.sample_type = PERF_SAMPLE_RAW; 45 attr.sample_period = 1; 46 attr.wakeup_events = 1; 47 48 if (is_socket) { 49 prog_type = BPF_PROG_TYPE_SOCKET_FILTER; 50 } else if (is_kprobe || is_kretprobe) { 51 prog_type = BPF_PROG_TYPE_KPROBE; 52 } else { 53 printf("Unknown event '%s'\n", event); 54 return -1; 55 } 56 57 if (is_kprobe || is_kretprobe) { 58 if (is_kprobe) 59 event += 7; 60 else 61 event += 10; 62 63 snprintf(buf, sizeof(buf), 64 "echo '%c:%s %s' >> /sys/kernel/debug/tracing/kprobe_events", 65 is_kprobe ? 'p' : 'r', event, event); 66 err = system(buf); 67 if (err < 0) { 68 printf("failed to create kprobe '%s' error '%s'\n", 69 event, strerror(errno)); 70 return -1; 71 } 72 } 73 74 fd = bpf_prog_load(prog_type, prog, size, license, kern_version); 75 76 if (fd < 0) { 77 printf("bpf_prog_load() err=%d\n%s", errno, bpf_log_buf); 78 return -1; 79 } 80 81 prog_fd[prog_cnt++] = fd; 82 83 if (is_socket) 84 return 0; 85 86 strcpy(buf, DEBUGFS); 87 strcat(buf, "events/kprobes/"); 88 strcat(buf, event); 89 strcat(buf, "/id"); 90 91 efd = open(buf, O_RDONLY, 0); 92 if (efd < 0) { 93 printf("failed to open event %s\n", event); 94 return -1; 95 } 96 97 err = read(efd, buf, sizeof(buf)); 98 if (err < 0 || err >= sizeof(buf)) { 99 printf("read from '%s' failed '%s'\n", event, strerror(errno)); 100 return -1; 101 } 102 103 close(efd); 104 105 buf[err] = 0; 106 id = atoi(buf); 107 attr.config = id; 108 109 efd = perf_event_open(&attr, -1/*pid*/, 0/*cpu*/, -1/*group_fd*/, 0); 110 if (efd < 0) { 111 printf("event %d fd %d err %s\n", id, efd, strerror(errno)); 112 return -1; 113 } 114 event_fd[prog_cnt - 1] = efd; 115 ioctl(efd, PERF_EVENT_IOC_ENABLE, 0); 116 ioctl(efd, PERF_EVENT_IOC_SET_BPF, fd); 117 118 return 0; 119} 120 121static int load_maps(struct bpf_map_def *maps, int len) 122{ 123 int i; 124 125 for (i = 0; i < len / sizeof(struct bpf_map_def); i++) { 126 127 map_fd[i] = bpf_create_map(maps[i].type, 128 maps[i].key_size, 129 maps[i].value_size, 130 maps[i].max_entries); 131 if (map_fd[i] < 0) 132 return 1; 133 } 134 return 0; 135} 136 137static int get_sec(Elf *elf, int i, GElf_Ehdr *ehdr, char **shname, 138 GElf_Shdr *shdr, Elf_Data **data) 139{ 140 Elf_Scn *scn; 141 142 scn = elf_getscn(elf, i); 143 if (!scn) 144 return 1; 145 146 if (gelf_getshdr(scn, shdr) != shdr) 147 return 2; 148 149 *shname = elf_strptr(elf, ehdr->e_shstrndx, shdr->sh_name); 150 if (!*shname || !shdr->sh_size) 151 return 3; 152 153 *data = elf_getdata(scn, 0); 154 if (!*data || elf_getdata(scn, *data) != NULL) 155 return 4; 156 157 return 0; 158} 159 160static int parse_relo_and_apply(Elf_Data *data, Elf_Data *symbols, 161 GElf_Shdr *shdr, struct bpf_insn *insn) 162{ 163 int i, nrels; 164 165 nrels = shdr->sh_size / shdr->sh_entsize; 166 167 for (i = 0; i < nrels; i++) { 168 GElf_Sym sym; 169 GElf_Rel rel; 170 unsigned int insn_idx; 171 172 gelf_getrel(data, i, &rel); 173 174 insn_idx = rel.r_offset / sizeof(struct bpf_insn); 175 176 gelf_getsym(symbols, GELF_R_SYM(rel.r_info), &sym); 177 178 if (insn[insn_idx].code != (BPF_LD | BPF_IMM | BPF_DW)) { 179 printf("invalid relo for insn[%d].code 0x%x\n", 180 insn_idx, insn[insn_idx].code); 181 return 1; 182 } 183 insn[insn_idx].src_reg = BPF_PSEUDO_MAP_FD; 184 insn[insn_idx].imm = map_fd[sym.st_value / sizeof(struct bpf_map_def)]; 185 } 186 187 return 0; 188} 189 190int load_bpf_file(char *path) 191{ 192 int fd, i; 193 Elf *elf; 194 GElf_Ehdr ehdr; 195 GElf_Shdr shdr, shdr_prog; 196 Elf_Data *data, *data_prog, *symbols = NULL; 197 char *shname, *shname_prog; 198 199 if (elf_version(EV_CURRENT) == EV_NONE) 200 return 1; 201 202 fd = open(path, O_RDONLY, 0); 203 if (fd < 0) 204 return 1; 205 206 elf = elf_begin(fd, ELF_C_READ, NULL); 207 208 if (!elf) 209 return 1; 210 211 if (gelf_getehdr(elf, &ehdr) != &ehdr) 212 return 1; 213 214 /* clear all kprobes */ 215 i = system("echo \"\" > /sys/kernel/debug/tracing/kprobe_events"); 216 217 /* scan over all elf sections to get license and map info */ 218 for (i = 1; i < ehdr.e_shnum; i++) { 219 220 if (get_sec(elf, i, &ehdr, &shname, &shdr, &data)) 221 continue; 222 223 if (0) /* helpful for llvm debugging */ 224 printf("section %d:%s data %p size %zd link %d flags %d\n", 225 i, shname, data->d_buf, data->d_size, 226 shdr.sh_link, (int) shdr.sh_flags); 227 228 if (strcmp(shname, "license") == 0) { 229 processed_sec[i] = true; 230 memcpy(license, data->d_buf, data->d_size); 231 } else if (strcmp(shname, "version") == 0) { 232 processed_sec[i] = true; 233 if (data->d_size != sizeof(int)) { 234 printf("invalid size of version section %zd\n", 235 data->d_size); 236 return 1; 237 } 238 memcpy(&kern_version, data->d_buf, sizeof(int)); 239 } else if (strcmp(shname, "maps") == 0) { 240 processed_sec[i] = true; 241 if (load_maps(data->d_buf, data->d_size)) 242 return 1; 243 } else if (shdr.sh_type == SHT_SYMTAB) { 244 symbols = data; 245 } 246 } 247 248 /* load programs that need map fixup (relocations) */ 249 for (i = 1; i < ehdr.e_shnum; i++) { 250 251 if (get_sec(elf, i, &ehdr, &shname, &shdr, &data)) 252 continue; 253 if (shdr.sh_type == SHT_REL) { 254 struct bpf_insn *insns; 255 256 if (get_sec(elf, shdr.sh_info, &ehdr, &shname_prog, 257 &shdr_prog, &data_prog)) 258 continue; 259 260 insns = (struct bpf_insn *) data_prog->d_buf; 261 262 processed_sec[shdr.sh_info] = true; 263 processed_sec[i] = true; 264 265 if (parse_relo_and_apply(data, symbols, &shdr, insns)) 266 continue; 267 268 if (memcmp(shname_prog, "kprobe/", 7) == 0 || 269 memcmp(shname_prog, "kretprobe/", 10) == 0 || 270 memcmp(shname_prog, "socket", 6) == 0) 271 load_and_attach(shname_prog, insns, data_prog->d_size); 272 } 273 } 274 275 /* load programs that don't use maps */ 276 for (i = 1; i < ehdr.e_shnum; i++) { 277 278 if (processed_sec[i]) 279 continue; 280 281 if (get_sec(elf, i, &ehdr, &shname, &shdr, &data)) 282 continue; 283 284 if (memcmp(shname, "kprobe/", 7) == 0 || 285 memcmp(shname, "kretprobe/", 10) == 0 || 286 memcmp(shname, "socket", 6) == 0) 287 load_and_attach(shname, data->d_buf, data->d_size); 288 } 289 290 close(fd); 291 return 0; 292} 293 294void read_trace_pipe(void) 295{ 296 int trace_fd; 297 298 trace_fd = open(DEBUGFS "trace_pipe", O_RDONLY, 0); 299 if (trace_fd < 0) 300 return; 301 302 while (1) { 303 static char buf[4096]; 304 ssize_t sz; 305 306 sz = read(trace_fd, buf, sizeof(buf)); 307 if (sz > 0) { 308 buf[sz] = 0; 309 puts(buf); 310 } 311 } 312} 313