tc_bpf.c revision 11c39b5e98a163889fe5e1840e1b2a105bc33680
11d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko/* 21d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko * tc_bpf.c BPF common code 31d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko * 41d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko * This program is free software; you can distribute it and/or 51d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko * modify it under the terms of the GNU General Public License 61d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko * as published by the Free Software Foundation; either version 71d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko * 2 of the License, or (at your option) any later version. 81d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko * 91d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko * Authors: Daniel Borkmann <dborkman@redhat.com> 101d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko * Jiri Pirko <jiri@resnulli.us> 1111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann * Alexei Starovoitov <ast@plumgrid.com> 121d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko */ 131d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 141d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko#include <stdio.h> 151d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko#include <stdlib.h> 161d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko#include <unistd.h> 171d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko#include <string.h> 181d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko#include <stdbool.h> 191d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko#include <errno.h> 2011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann#include <fcntl.h> 2111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann#include <stdarg.h> 2211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann#include <sys/types.h> 2311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann#include <sys/stat.h> 241d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko#include <linux/filter.h> 251d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko#include <linux/netlink.h> 261d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko#include <linux/rtnetlink.h> 271d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 2811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann#ifdef HAVE_ELF 2911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann#include <libelf.h> 3011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann#include <gelf.h> 3111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann#endif 3211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 331d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko#include "utils.h" 341d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko#include "tc_util.h" 351d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko#include "tc_bpf.h" 361d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 371d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirkoint bpf_parse_string(char *arg, bool from_file, __u16 *bpf_len, 381d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko char **bpf_string, bool *need_release, 391d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko const char separator) 401d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko{ 411d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko char sp; 421d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 431d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko if (from_file) { 441d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko size_t tmp_len, op_len = sizeof("65535 255 255 4294967295,"); 451d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko char *tmp_string; 461d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko FILE *fp; 471d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 481d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko tmp_len = sizeof("4096,") + BPF_MAXINSNS * op_len; 491d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko tmp_string = malloc(tmp_len); 501d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko if (tmp_string == NULL) 511d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko return -ENOMEM; 521d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 531d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko memset(tmp_string, 0, tmp_len); 541d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 551d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko fp = fopen(arg, "r"); 561d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko if (fp == NULL) { 571d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko perror("Cannot fopen"); 581d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko free(tmp_string); 591d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko return -ENOENT; 601d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko } 611d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 621d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko if (!fgets(tmp_string, tmp_len, fp)) { 631d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko free(tmp_string); 641d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko fclose(fp); 651d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko return -EIO; 661d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko } 671d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 681d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko fclose(fp); 691d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 701d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko *need_release = true; 711d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko *bpf_string = tmp_string; 721d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko } else { 731d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko *need_release = false; 741d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko *bpf_string = arg; 751d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko } 761d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 771d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko if (sscanf(*bpf_string, "%hu%c", bpf_len, &sp) != 2 || 781d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko sp != separator) { 791d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko if (*need_release) 801d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko free(*bpf_string); 811d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko return -EINVAL; 821d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko } 831d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 841d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko return 0; 851d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko} 861d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 871d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirkoint bpf_parse_ops(int argc, char **argv, struct sock_filter *bpf_ops, 881d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko bool from_file) 891d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko{ 901d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko char *bpf_string, *token, separator = ','; 911d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko int ret = 0, i = 0; 921d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko bool need_release; 931d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko __u16 bpf_len = 0; 941d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 951d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko if (argc < 1) 961d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko return -EINVAL; 971d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko if (bpf_parse_string(argv[0], from_file, &bpf_len, &bpf_string, 981d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko &need_release, separator)) 991d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko return -EINVAL; 1001d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko if (bpf_len == 0 || bpf_len > BPF_MAXINSNS) { 1011d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko ret = -EINVAL; 1021d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko goto out; 1031d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko } 1041d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 1051d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko token = bpf_string; 1061d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko while ((token = strchr(token, separator)) && (++token)[0]) { 1071d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko if (i >= bpf_len) { 1081d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko fprintf(stderr, "Real program length exceeds encoded " 1091d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko "length parameter!\n"); 1101d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko ret = -EINVAL; 1111d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko goto out; 1121d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko } 1131d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 1141d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko if (sscanf(token, "%hu %hhu %hhu %u,", 1151d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko &bpf_ops[i].code, &bpf_ops[i].jt, 1161d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko &bpf_ops[i].jf, &bpf_ops[i].k) != 4) { 1171d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko fprintf(stderr, "Error at instruction %d!\n", i); 1181d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko ret = -EINVAL; 1191d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko goto out; 1201d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko } 1211d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 1221d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko i++; 1231d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko } 1241d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 1251d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko if (i != bpf_len) { 1261d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko fprintf(stderr, "Parsed program length is less than encoded" 1271d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko "length parameter!\n"); 1281d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko ret = -EINVAL; 1291d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko goto out; 1301d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko } 1311d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko ret = bpf_len; 1321d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 1331d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirkoout: 1341d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko if (need_release) 1351d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko free(bpf_string); 1361d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 1371d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko return ret; 1381d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko} 1391d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 1401d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirkovoid bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len) 1411d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko{ 1421d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko struct sock_filter *ops = (struct sock_filter *) RTA_DATA(bpf_ops); 1431d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko int i; 1441d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 1451d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko if (len == 0) 1461d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko return; 1471d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 1481d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko fprintf(f, "bytecode \'%u,", len); 1491d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 1501d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko for (i = 0; i < len - 1; i++) 1511d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko fprintf(f, "%hu %hhu %hhu %u,", ops[i].code, ops[i].jt, 1521d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko ops[i].jf, ops[i].k); 1531d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 1541d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko fprintf(f, "%hu %hhu %hhu %u\'\n", ops[i].code, ops[i].jt, 1551d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko ops[i].jf, ops[i].k); 1561d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko} 15711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 15811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann#ifdef HAVE_ELF 15911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannstruct bpf_elf_sec_data { 16011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann GElf_Shdr sec_hdr; 16111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann char *sec_name; 16211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann Elf_Data *sec_data; 16311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann}; 16411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 16511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannstatic char bpf_log_buf[8192]; 16611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 16711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannstatic const char *prog_type_section(enum bpf_prog_type type) 16811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 16911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann switch (type) { 17011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann case BPF_PROG_TYPE_SCHED_CLS: 17111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return ELF_SECTION_CLASSIFIER; 17211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann /* case BPF_PROG_TYPE_SCHED_ACT: */ 17311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann /* return ELF_SECTION_ACTION; */ 17411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann default: 17511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return NULL; 17611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann } 17711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 17811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 17911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannstatic void bpf_dump_error(const char *format, ...) __check_format_string(1, 2); 18011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannstatic void bpf_dump_error(const char *format, ...) 18111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 18211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann va_list vl; 18311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 18411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann va_start(vl, format); 18511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann vfprintf(stderr, format, vl); 18611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann va_end(vl); 18711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 18811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann fprintf(stderr, "%s", bpf_log_buf); 18911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann memset(bpf_log_buf, 0, sizeof(bpf_log_buf)); 19011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 19111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 19211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannstatic int bpf_create_map(enum bpf_map_type type, unsigned int size_key, 19311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann unsigned int size_value, unsigned int max_elem) 19411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 19511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann union bpf_attr attr = { 19611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann .map_type = type, 19711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann .key_size = size_key, 19811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann .value_size = size_value, 19911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann .max_entries = max_elem, 20011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann }; 20111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 20211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); 20311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 20411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 20511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannstatic int bpf_prog_load(enum bpf_prog_type type, const struct bpf_insn *insns, 20611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann unsigned int len, const char *license) 20711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 20811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann union bpf_attr attr = { 20911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann .prog_type = type, 21011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann .insns = bpf_ptr_to_u64(insns), 21111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann .insn_cnt = len / sizeof(struct bpf_insn), 21211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann .license = bpf_ptr_to_u64(license), 21311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann .log_buf = bpf_ptr_to_u64(bpf_log_buf), 21411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann .log_size = sizeof(bpf_log_buf), 21511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann .log_level = 1, 21611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann }; 21711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 21811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); 21911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 22011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 22111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannstatic int bpf_prog_attach(enum bpf_prog_type type, const struct bpf_insn *insns, 22211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann unsigned int size, const char *license) 22311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 22411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann int prog_fd = bpf_prog_load(type, insns, size, license); 22511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 22611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (prog_fd < 0) 22711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann bpf_dump_error("BPF program rejected: %s\n", strerror(errno)); 22811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 22911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return prog_fd; 23011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 23111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 23211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannstatic int bpf_map_attach(enum bpf_map_type type, unsigned int size_key, 23311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann unsigned int size_value, unsigned int max_elem) 23411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 23511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann int map_fd = bpf_create_map(type, size_key, size_value, max_elem); 23611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 23711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (map_fd < 0) 23811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann bpf_dump_error("BPF map rejected: %s\n", strerror(errno)); 23911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 24011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return map_fd; 24111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 24211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 24311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannstatic void bpf_maps_init(int *map_fds, unsigned int max_fds) 24411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 24511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann int i; 24611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 24711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann for (i = 0; i < max_fds; i++) 24811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann map_fds[i] = -1; 24911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 25011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 25111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannstatic void bpf_maps_destroy(const int *map_fds, unsigned int max_fds) 25211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 25311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann int i; 25411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 25511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann for (i = 0; i < max_fds; i++) { 25611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (map_fds[i] >= 0) 25711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann close(map_fds[i]); 25811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann } 25911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 26011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 26111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannstatic int bpf_maps_attach(struct bpf_elf_map *maps, unsigned int num_maps, 26211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann int *map_fds, unsigned int max_fds) 26311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 26411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann int i, ret; 26511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 26611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann for (i = 0; i < num_maps && num_maps <= max_fds; i++) { 26711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann struct bpf_elf_map *map = &maps[i]; 26811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 26911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann ret = bpf_map_attach(map->type, map->size_key, 27011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann map->size_value, map->max_elem); 27111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (ret < 0) 27211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann goto err_unwind; 27311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 27411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann map_fds[i] = ret; 27511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann } 27611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 27711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return 0; 27811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 27911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannerr_unwind: 28011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann bpf_maps_destroy(map_fds, i); 28111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return ret; 28211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 28311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 28411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannstatic int bpf_fill_section_data(Elf *elf_fd, GElf_Ehdr *elf_hdr, int sec_index, 28511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann struct bpf_elf_sec_data *sec_data) 28611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 28711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann GElf_Shdr sec_hdr; 28811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann Elf_Scn *sec_fd; 28911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann Elf_Data *sec_edata; 29011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann char *sec_name; 29111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 29211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann memset(sec_data, 0, sizeof(*sec_data)); 29311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 29411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann sec_fd = elf_getscn(elf_fd, sec_index); 29511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (!sec_fd) 29611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return -EINVAL; 29711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 29811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (gelf_getshdr(sec_fd, &sec_hdr) != &sec_hdr) 29911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return -EIO; 30011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 30111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann sec_name = elf_strptr(elf_fd, elf_hdr->e_shstrndx, 30211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann sec_hdr.sh_name); 30311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (!sec_name || !sec_hdr.sh_size) 30411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return -ENOENT; 30511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 30611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann sec_edata = elf_getdata(sec_fd, NULL); 30711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (!sec_edata || elf_getdata(sec_fd, sec_edata)) 30811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return -EIO; 30911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 31011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann memcpy(&sec_data->sec_hdr, &sec_hdr, sizeof(sec_hdr)); 31111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann sec_data->sec_name = sec_name; 31211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann sec_data->sec_data = sec_edata; 31311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 31411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return 0; 31511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 31611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 31711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannstatic int bpf_apply_relo_data(struct bpf_elf_sec_data *data_relo, 31811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann struct bpf_elf_sec_data *data_insn, 31911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann Elf_Data *sym_tab, int *map_fds, int max_fds) 32011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 32111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann Elf_Data *idata = data_insn->sec_data; 32211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann GElf_Shdr *rhdr = &data_relo->sec_hdr; 32311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann int relo_ent, relo_num = rhdr->sh_size / rhdr->sh_entsize; 32411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann struct bpf_insn *insns = idata->d_buf; 32511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann unsigned int num_insns = idata->d_size / sizeof(*insns); 32611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 32711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann for (relo_ent = 0; relo_ent < relo_num; relo_ent++) { 32811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann unsigned int ioff, fnum; 32911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann GElf_Rel relo; 33011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann GElf_Sym sym; 33111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 33211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (gelf_getrel(data_relo->sec_data, relo_ent, &relo) != &relo) 33311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return -EIO; 33411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 33511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann ioff = relo.r_offset / sizeof(struct bpf_insn); 33611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (ioff >= num_insns) 33711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return -EINVAL; 33811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (insns[ioff].code != (BPF_LD | BPF_IMM | BPF_DW)) 33911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return -EINVAL; 34011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 34111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (gelf_getsym(sym_tab, GELF_R_SYM(relo.r_info), &sym) != &sym) 34211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return -EIO; 34311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 34411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann fnum = sym.st_value / sizeof(struct bpf_elf_map); 34511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (fnum >= max_fds) 34611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return -EINVAL; 34711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 34811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann insns[ioff].src_reg = BPF_PSEUDO_MAP_FD; 34911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann insns[ioff].imm = map_fds[fnum]; 35011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann } 35111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 35211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return 0; 35311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 35411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 35511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannstatic int bpf_fetch_ancillary(Elf *elf_fd, GElf_Ehdr *elf_hdr, bool *sec_seen, 35611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann int *map_fds, unsigned int max_fds, 35711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann char *license, unsigned int lic_len, 35811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann Elf_Data **sym_tab) 35911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 36011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann int sec_index, ret = -1; 36111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 36211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann for (sec_index = 1; sec_index < elf_hdr->e_shnum; sec_index++) { 36311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann struct bpf_elf_sec_data data_anc; 36411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 36511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann ret = bpf_fill_section_data(elf_fd, elf_hdr, sec_index, 36611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann &data_anc); 36711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (ret < 0) 36811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann continue; 36911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 37011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann /* Extract and load eBPF map fds. */ 37111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (!strcmp(data_anc.sec_name, ELF_SECTION_MAPS)) { 37211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann struct bpf_elf_map *maps = data_anc.sec_data->d_buf; 37311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann unsigned int maps_num = data_anc.sec_data->d_size / 37411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann sizeof(*maps); 37511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 37611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann sec_seen[sec_index] = true; 37711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann ret = bpf_maps_attach(maps, maps_num, map_fds, 37811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann max_fds); 37911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (ret < 0) 38011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return ret; 38111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann } 38211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann /* Extract eBPF license. */ 38311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann else if (!strcmp(data_anc.sec_name, ELF_SECTION_LICENSE)) { 38411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (data_anc.sec_data->d_size > lic_len) 38511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return -ENOMEM; 38611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 38711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann sec_seen[sec_index] = true; 38811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann memcpy(license, data_anc.sec_data->d_buf, 38911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann data_anc.sec_data->d_size); 39011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann } 39111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann /* Extract symbol table for relocations (map fd fixups). */ 39211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann else if (data_anc.sec_hdr.sh_type == SHT_SYMTAB) { 39311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann sec_seen[sec_index] = true; 39411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann *sym_tab = data_anc.sec_data; 39511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann } 39611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann } 39711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 39811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return ret; 39911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 40011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 40111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannstatic int bpf_fetch_prog_relo(Elf *elf_fd, GElf_Ehdr *elf_hdr, bool *sec_seen, 40211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann enum bpf_prog_type type, char *license, 40311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann Elf_Data *sym_tab, int *map_fds, unsigned int max_fds) 40411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 40511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann int sec_index, prog_fd = -1; 40611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 40711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann for (sec_index = 1; sec_index < elf_hdr->e_shnum; sec_index++) { 40811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann struct bpf_elf_sec_data data_relo, data_insn; 40911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann int ins_index, ret; 41011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 41111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann /* Attach eBPF programs with relocation data (maps). */ 41211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann ret = bpf_fill_section_data(elf_fd, elf_hdr, sec_index, 41311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann &data_relo); 41411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (ret < 0 || data_relo.sec_hdr.sh_type != SHT_REL) 41511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann continue; 41611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 41711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann ins_index = data_relo.sec_hdr.sh_info; 41811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 41911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann ret = bpf_fill_section_data(elf_fd, elf_hdr, ins_index, 42011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann &data_insn); 42111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (ret < 0) 42211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann continue; 42311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (strcmp(data_insn.sec_name, prog_type_section(type))) 42411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann continue; 42511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 42611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann sec_seen[sec_index] = true; 42711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann sec_seen[ins_index] = true; 42811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 42911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann ret = bpf_apply_relo_data(&data_relo, &data_insn, sym_tab, 43011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann map_fds, max_fds); 43111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (ret < 0) 43211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann continue; 43311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 43411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann prog_fd = bpf_prog_attach(type, data_insn.sec_data->d_buf, 43511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann data_insn.sec_data->d_size, license); 43611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (prog_fd < 0) 43711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann continue; 43811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 43911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann break; 44011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann } 44111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 44211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return prog_fd; 44311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 44411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 44511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannstatic int bpf_fetch_prog(Elf *elf_fd, GElf_Ehdr *elf_hdr, bool *sec_seen, 44611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann enum bpf_prog_type type, char *license) 44711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 44811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann int sec_index, prog_fd = -1; 44911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 45011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann for (sec_index = 1; sec_index < elf_hdr->e_shnum; sec_index++) { 45111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann struct bpf_elf_sec_data data_insn; 45211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann int ret; 45311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 45411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann /* Attach eBPF programs without relocation data. */ 45511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (sec_seen[sec_index]) 45611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann continue; 45711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 45811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann ret = bpf_fill_section_data(elf_fd, elf_hdr, sec_index, 45911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann &data_insn); 46011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (ret < 0) 46111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann continue; 46211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (strcmp(data_insn.sec_name, prog_type_section(type))) 46311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann continue; 46411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 46511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann prog_fd = bpf_prog_attach(type, data_insn.sec_data->d_buf, 46611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann data_insn.sec_data->d_size, license); 46711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (prog_fd < 0) 46811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann continue; 46911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 47011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann break; 47111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann } 47211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 47311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return prog_fd; 47411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 47511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 47611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannint bpf_open_object(const char *path, enum bpf_prog_type type) 47711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 47811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann int map_fds[ELF_MAX_MAPS], max_fds = ARRAY_SIZE(map_fds); 47911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann char license[ELF_MAX_LICENSE_LEN]; 48011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann int file_fd, prog_fd = -1, ret; 48111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann Elf_Data *sym_tab = NULL; 48211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann GElf_Ehdr elf_hdr; 48311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann bool *sec_seen; 48411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann Elf *elf_fd; 48511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 48611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (elf_version(EV_CURRENT) == EV_NONE) 48711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return -EINVAL; 48811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 48911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann file_fd = open(path, O_RDONLY, 0); 49011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (file_fd < 0) 49111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return -errno; 49211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 49311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann elf_fd = elf_begin(file_fd, ELF_C_READ, NULL); 49411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (!elf_fd) { 49511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann ret = -EINVAL; 49611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann goto out; 49711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann } 49811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 49911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (gelf_getehdr(elf_fd, &elf_hdr) != &elf_hdr) { 50011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann ret = -EIO; 50111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann goto out_elf; 50211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann } 50311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 50411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann sec_seen = calloc(elf_hdr.e_shnum, sizeof(*sec_seen)); 50511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (!sec_seen) { 50611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann ret = -ENOMEM; 50711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann goto out_elf; 50811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann } 50911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 51011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann memset(license, 0, sizeof(license)); 51111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann bpf_maps_init(map_fds, max_fds); 51211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 51311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann ret = bpf_fetch_ancillary(elf_fd, &elf_hdr, sec_seen, map_fds, max_fds, 51411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann license, sizeof(license), &sym_tab); 51511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (ret < 0) 51611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann goto out_maps; 51711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (sym_tab) 51811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann prog_fd = bpf_fetch_prog_relo(elf_fd, &elf_hdr, sec_seen, type, 51911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann license, sym_tab, map_fds, max_fds); 52011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (prog_fd < 0) 52111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann prog_fd = bpf_fetch_prog(elf_fd, &elf_hdr, sec_seen, type, 52211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann license); 52311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (prog_fd < 0) 52411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann goto out_maps; 52511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannout_sec: 52611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann free(sec_seen); 52711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannout_elf: 52811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann elf_end(elf_fd); 52911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannout: 53011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann close(file_fd); 53111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return prog_fd; 53211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 53311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannout_maps: 53411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann bpf_maps_destroy(map_fds, max_fds); 53511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann goto out_sec; 53611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 53711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 53811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann#endif /* HAVE_ELF */ 539