tc_bpf.c revision d937a74b6d7818d67b12f2439320bfddcdd35e58
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> 246256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann#include <sys/un.h> 251d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko#include <linux/filter.h> 261d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko#include <linux/netlink.h> 271d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko#include <linux/rtnetlink.h> 281d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 2911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann#ifdef HAVE_ELF 3011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann#include <libelf.h> 3111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann#include <gelf.h> 3211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann#endif 3311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 341d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko#include "utils.h" 356256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 366256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann#include "bpf_elf.h" 376256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann#include "bpf_scm.h" 386256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 391d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko#include "tc_util.h" 401d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko#include "tc_bpf.h" 411d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 421d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirkoint bpf_parse_string(char *arg, bool from_file, __u16 *bpf_len, 431d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko char **bpf_string, bool *need_release, 441d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko const char separator) 451d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko{ 461d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko char sp; 471d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 481d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko if (from_file) { 491d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko size_t tmp_len, op_len = sizeof("65535 255 255 4294967295,"); 501d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko char *tmp_string; 511d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko FILE *fp; 521d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 531d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko tmp_len = sizeof("4096,") + BPF_MAXINSNS * op_len; 541d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko tmp_string = malloc(tmp_len); 551d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko if (tmp_string == NULL) 561d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko return -ENOMEM; 571d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 581d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko memset(tmp_string, 0, tmp_len); 591d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 601d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko fp = fopen(arg, "r"); 611d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko if (fp == NULL) { 621d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko perror("Cannot fopen"); 631d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko free(tmp_string); 641d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko return -ENOENT; 651d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko } 661d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 671d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko if (!fgets(tmp_string, tmp_len, fp)) { 681d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko free(tmp_string); 691d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko fclose(fp); 701d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko return -EIO; 711d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko } 721d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 731d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko fclose(fp); 741d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 751d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko *need_release = true; 761d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko *bpf_string = tmp_string; 771d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko } else { 781d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko *need_release = false; 791d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko *bpf_string = arg; 801d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko } 811d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 821d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko if (sscanf(*bpf_string, "%hu%c", bpf_len, &sp) != 2 || 831d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko sp != separator) { 841d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko if (*need_release) 851d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko free(*bpf_string); 861d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko return -EINVAL; 871d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko } 881d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 891d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko return 0; 901d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko} 911d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 921d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirkoint bpf_parse_ops(int argc, char **argv, struct sock_filter *bpf_ops, 931d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko bool from_file) 941d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko{ 951d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko char *bpf_string, *token, separator = ','; 961d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko int ret = 0, i = 0; 971d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko bool need_release; 981d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko __u16 bpf_len = 0; 991d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 1001d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko if (argc < 1) 1011d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko return -EINVAL; 1021d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko if (bpf_parse_string(argv[0], from_file, &bpf_len, &bpf_string, 1031d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko &need_release, separator)) 1041d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko return -EINVAL; 1051d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko if (bpf_len == 0 || bpf_len > BPF_MAXINSNS) { 1061d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko ret = -EINVAL; 1071d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko goto out; 1081d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko } 1091d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 1101d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko token = bpf_string; 1111d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko while ((token = strchr(token, separator)) && (++token)[0]) { 1121d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko if (i >= bpf_len) { 1131d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko fprintf(stderr, "Real program length exceeds encoded " 1141d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko "length parameter!\n"); 1151d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko ret = -EINVAL; 1161d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko goto out; 1171d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko } 1181d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 1191d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko if (sscanf(token, "%hu %hhu %hhu %u,", 1201d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko &bpf_ops[i].code, &bpf_ops[i].jt, 1211d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko &bpf_ops[i].jf, &bpf_ops[i].k) != 4) { 1221d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko fprintf(stderr, "Error at instruction %d!\n", i); 1231d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko ret = -EINVAL; 1241d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko goto out; 1251d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko } 1261d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 1271d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko i++; 1281d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko } 1291d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 1301d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko if (i != bpf_len) { 1311d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko fprintf(stderr, "Parsed program length is less than encoded" 1321d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko "length parameter!\n"); 1331d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko ret = -EINVAL; 1341d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko goto out; 1351d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko } 1361d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko ret = bpf_len; 1371d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 1381d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirkoout: 1391d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko if (need_release) 1401d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko free(bpf_string); 1411d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 1421d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko return ret; 1431d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko} 1441d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 1451d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirkovoid bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len) 1461d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko{ 1471d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko struct sock_filter *ops = (struct sock_filter *) RTA_DATA(bpf_ops); 1481d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko int i; 1491d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 1501d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko if (len == 0) 1511d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko return; 1521d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 1531d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko fprintf(f, "bytecode \'%u,", len); 1541d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 1551d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko for (i = 0; i < len - 1; i++) 1561d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko fprintf(f, "%hu %hhu %hhu %u,", ops[i].code, ops[i].jt, 1571d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko ops[i].jf, ops[i].k); 1581d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko 1596256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann fprintf(f, "%hu %hhu %hhu %u\'", ops[i].code, ops[i].jt, 1601d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko ops[i].jf, ops[i].k); 1611d129d191a3a632e05cf440c15aaffe23e0fa798Jiri Pirko} 16211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 1636256f8c9e45f01187b297a576e148534a393c990Daniel Borkmannconst char *bpf_default_section(const enum bpf_prog_type type) 16411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 16511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann switch (type) { 16611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann case BPF_PROG_TYPE_SCHED_CLS: 16711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return ELF_SECTION_CLASSIFIER; 1686256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann case BPF_PROG_TYPE_SCHED_ACT: 1696256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann return ELF_SECTION_ACTION; 17011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann default: 17111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return NULL; 17211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann } 17311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 17411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 1756256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann#ifdef HAVE_ELF 1766256f8c9e45f01187b297a576e148534a393c990Daniel Borkmannstruct bpf_elf_sec_data { 1776256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann GElf_Shdr sec_hdr; 1786256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann char *sec_name; 1796256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann Elf_Data *sec_data; 1806256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann}; 1816256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 1826256f8c9e45f01187b297a576e148534a393c990Daniel Borkmannstruct bpf_map_data { 1836256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann int *fds; 1846256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann const char *obj; 1856256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann struct bpf_elf_st *st; 1866256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann struct bpf_elf_map *ent; 1876256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann}; 1886256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 1896256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann/* If we provide a small buffer with log level enabled, the kernel 1906256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann * could fail program load as no buffer space is available for the 1916256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann * log and thus verifier fails. In case something doesn't pass the 1926256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann * verifier we still want to hand something descriptive to the user. 1936256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann */ 1946256f8c9e45f01187b297a576e148534a393c990Daniel Borkmannstatic char bpf_log_buf[65536]; 195d937a74b6d7818d67b12f2439320bfddcdd35e58Daniel Borkmannstatic bool bpf_verbose; 1966256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 1976256f8c9e45f01187b297a576e148534a393c990Daniel Borkmannstatic struct bpf_elf_st bpf_st; 1986256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 1996256f8c9e45f01187b297a576e148534a393c990Daniel Borkmannstatic int map_fds[ELF_MAX_MAPS]; 2006256f8c9e45f01187b297a576e148534a393c990Daniel Borkmannstatic struct bpf_elf_map map_ent[ELF_MAX_MAPS]; 2016256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 20211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannstatic void bpf_dump_error(const char *format, ...) __check_format_string(1, 2); 20311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannstatic void bpf_dump_error(const char *format, ...) 20411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 20511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann va_list vl; 20611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 20711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann va_start(vl, format); 20811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann vfprintf(stderr, format, vl); 20911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann va_end(vl); 21011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 211d937a74b6d7818d67b12f2439320bfddcdd35e58Daniel Borkmann if (bpf_log_buf[0]) { 212d937a74b6d7818d67b12f2439320bfddcdd35e58Daniel Borkmann fprintf(stderr, "%s\n", bpf_log_buf); 213d937a74b6d7818d67b12f2439320bfddcdd35e58Daniel Borkmann memset(bpf_log_buf, 0, sizeof(bpf_log_buf)); 214d937a74b6d7818d67b12f2439320bfddcdd35e58Daniel Borkmann } 21511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 21611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 2176256f8c9e45f01187b297a576e148534a393c990Daniel Borkmannstatic void bpf_save_finfo(int file_fd) 2186256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann{ 2196256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann struct stat st; 2206256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann int ret; 2216256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 2226256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann memset(&bpf_st, 0, sizeof(bpf_st)); 2236256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 2246256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann ret = fstat(file_fd, &st); 2256256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann if (ret < 0) { 2266256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann fprintf(stderr, "Stat of elf file failed: %s\n", 2276256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann strerror(errno)); 2286256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann return; 2296256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann } 2306256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 2316256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann bpf_st.st_dev = st.st_dev; 2326256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann bpf_st.st_ino = st.st_ino; 2336256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann} 2346256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 2356256f8c9e45f01187b297a576e148534a393c990Daniel Borkmannstatic void bpf_clear_finfo(void) 2366256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann{ 2376256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann memset(&bpf_st, 0, sizeof(bpf_st)); 2386256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann} 2396256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 2406256f8c9e45f01187b297a576e148534a393c990Daniel Borkmannstatic bool bpf_may_skip_map_creation(int file_fd) 2416256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann{ 2426256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann struct stat st; 2436256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann int ret; 2446256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 2456256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann ret = fstat(file_fd, &st); 2466256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann if (ret < 0) { 2476256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann fprintf(stderr, "Stat of elf file failed: %s\n", 2486256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann strerror(errno)); 2496256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann return false; 2506256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann } 2516256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 2526256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann return (bpf_st.st_dev == st.st_dev) && 2536256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann (bpf_st.st_ino == st.st_ino); 2546256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann} 2556256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 25611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannstatic int bpf_create_map(enum bpf_map_type type, unsigned int size_key, 25711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann unsigned int size_value, unsigned int max_elem) 25811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 25911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann union bpf_attr attr = { 26011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann .map_type = type, 26111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann .key_size = size_key, 26211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann .value_size = size_value, 26311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann .max_entries = max_elem, 26411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann }; 26511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 26611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); 26711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 26811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 26911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannstatic int bpf_prog_load(enum bpf_prog_type type, const struct bpf_insn *insns, 27011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann unsigned int len, const char *license) 27111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 27211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann union bpf_attr attr = { 27311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann .prog_type = type, 27411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann .insns = bpf_ptr_to_u64(insns), 27511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann .insn_cnt = len / sizeof(struct bpf_insn), 27611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann .license = bpf_ptr_to_u64(license), 27711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann .log_buf = bpf_ptr_to_u64(bpf_log_buf), 27811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann .log_size = sizeof(bpf_log_buf), 27911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann .log_level = 1, 28011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann }; 28111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 28211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); 28311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 28411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 28511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannstatic int bpf_prog_attach(enum bpf_prog_type type, const struct bpf_insn *insns, 28611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann unsigned int size, const char *license) 28711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 28811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann int prog_fd = bpf_prog_load(type, insns, size, license); 28911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 290d937a74b6d7818d67b12f2439320bfddcdd35e58Daniel Borkmann if (prog_fd < 0 || bpf_verbose) { 291d937a74b6d7818d67b12f2439320bfddcdd35e58Daniel Borkmann bpf_dump_error("%s: %s\n", prog_fd < 0 ? 292d937a74b6d7818d67b12f2439320bfddcdd35e58Daniel Borkmann "BPF program rejected" : 293d937a74b6d7818d67b12f2439320bfddcdd35e58Daniel Borkmann "BPF program verification", strerror(errno)); 294d937a74b6d7818d67b12f2439320bfddcdd35e58Daniel Borkmann } 29511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 29611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return prog_fd; 29711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 29811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 29911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannstatic int bpf_map_attach(enum bpf_map_type type, unsigned int size_key, 30011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann unsigned int size_value, unsigned int max_elem) 30111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 30211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann int map_fd = bpf_create_map(type, size_key, size_value, max_elem); 30311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 30411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (map_fd < 0) 30511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann bpf_dump_error("BPF map rejected: %s\n", strerror(errno)); 30611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 30711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return map_fd; 30811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 30911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 3106256f8c9e45f01187b297a576e148534a393c990Daniel Borkmannstatic void bpf_maps_init(void) 31111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 31211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann int i; 31311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 3146256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann memset(map_ent, 0, sizeof(map_ent)); 3156256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann for (i = 0; i < ARRAY_SIZE(map_fds); i++) 31611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann map_fds[i] = -1; 31711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 31811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 3196256f8c9e45f01187b297a576e148534a393c990Daniel Borkmannstatic int bpf_maps_count(void) 3206256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann{ 3216256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann int i, count = 0; 3226256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 3236256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann for (i = 0; i < ARRAY_SIZE(map_fds); i++) { 3246256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann if (map_fds[i] < 0) 3256256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann break; 3266256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann count++; 3276256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann } 3286256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 3296256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann return count; 3306256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann} 3316256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 3326256f8c9e45f01187b297a576e148534a393c990Daniel Borkmannstatic void bpf_maps_destroy(void) 33311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 33411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann int i; 33511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 3366256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann memset(map_ent, 0, sizeof(map_ent)); 3376256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann for (i = 0; i < ARRAY_SIZE(map_fds); i++) { 33811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (map_fds[i] >= 0) 33911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann close(map_fds[i]); 34011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann } 34111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 34211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 3436256f8c9e45f01187b297a576e148534a393c990Daniel Borkmannstatic int bpf_maps_attach(struct bpf_elf_map *maps, unsigned int num_maps) 34411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 34511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann int i, ret; 34611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 3476256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann for (i = 0; (i < num_maps) && (num_maps <= ARRAY_SIZE(map_fds)); i++) { 34811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann struct bpf_elf_map *map = &maps[i]; 34911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 35011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann ret = bpf_map_attach(map->type, map->size_key, 35111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann map->size_value, map->max_elem); 35211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (ret < 0) 35311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann goto err_unwind; 35411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 35511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann map_fds[i] = ret; 35611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann } 35711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 35811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return 0; 35911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 36011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannerr_unwind: 3616256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann bpf_maps_destroy(); 36211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return ret; 36311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 36411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 36511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannstatic int bpf_fill_section_data(Elf *elf_fd, GElf_Ehdr *elf_hdr, int sec_index, 36611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann struct bpf_elf_sec_data *sec_data) 36711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 36811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann GElf_Shdr sec_hdr; 36911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann Elf_Scn *sec_fd; 37011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann Elf_Data *sec_edata; 37111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann char *sec_name; 37211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 37311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann memset(sec_data, 0, sizeof(*sec_data)); 37411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 37511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann sec_fd = elf_getscn(elf_fd, sec_index); 37611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (!sec_fd) 37711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return -EINVAL; 37811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 37911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (gelf_getshdr(sec_fd, &sec_hdr) != &sec_hdr) 38011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return -EIO; 38111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 38211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann sec_name = elf_strptr(elf_fd, elf_hdr->e_shstrndx, 38311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann sec_hdr.sh_name); 38411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (!sec_name || !sec_hdr.sh_size) 38511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return -ENOENT; 38611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 38711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann sec_edata = elf_getdata(sec_fd, NULL); 38811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (!sec_edata || elf_getdata(sec_fd, sec_edata)) 38911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return -EIO; 39011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 39111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann memcpy(&sec_data->sec_hdr, &sec_hdr, sizeof(sec_hdr)); 39211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann sec_data->sec_name = sec_name; 39311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann sec_data->sec_data = sec_edata; 39411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 39511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return 0; 39611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 39711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 39811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannstatic int bpf_apply_relo_data(struct bpf_elf_sec_data *data_relo, 39911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann struct bpf_elf_sec_data *data_insn, 4006256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann Elf_Data *sym_tab) 40111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 40211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann Elf_Data *idata = data_insn->sec_data; 40311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann GElf_Shdr *rhdr = &data_relo->sec_hdr; 40411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann int relo_ent, relo_num = rhdr->sh_size / rhdr->sh_entsize; 40511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann struct bpf_insn *insns = idata->d_buf; 40611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann unsigned int num_insns = idata->d_size / sizeof(*insns); 40711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 40811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann for (relo_ent = 0; relo_ent < relo_num; relo_ent++) { 40911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann unsigned int ioff, fnum; 41011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann GElf_Rel relo; 41111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann GElf_Sym sym; 41211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 41311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (gelf_getrel(data_relo->sec_data, relo_ent, &relo) != &relo) 41411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return -EIO; 41511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 41611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann ioff = relo.r_offset / sizeof(struct bpf_insn); 41711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (ioff >= num_insns) 41811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return -EINVAL; 41911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (insns[ioff].code != (BPF_LD | BPF_IMM | BPF_DW)) 42011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return -EINVAL; 42111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 42211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (gelf_getsym(sym_tab, GELF_R_SYM(relo.r_info), &sym) != &sym) 42311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return -EIO; 42411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 42511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann fnum = sym.st_value / sizeof(struct bpf_elf_map); 4266256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann if (fnum >= ARRAY_SIZE(map_fds)) 4276256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann return -EINVAL; 4286256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann if (map_fds[fnum] < 0) 42911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return -EINVAL; 43011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 43111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann insns[ioff].src_reg = BPF_PSEUDO_MAP_FD; 43211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann insns[ioff].imm = map_fds[fnum]; 43311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann } 43411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 43511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return 0; 43611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 43711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 4386256f8c9e45f01187b297a576e148534a393c990Daniel Borkmannstatic int bpf_fetch_ancillary(int file_fd, Elf *elf_fd, GElf_Ehdr *elf_hdr, 4396256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann bool *sec_seen, char *license, unsigned int lic_len, 44011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann Elf_Data **sym_tab) 44111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 44211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann int sec_index, ret = -1; 44311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 44411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann for (sec_index = 1; sec_index < elf_hdr->e_shnum; sec_index++) { 44511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann struct bpf_elf_sec_data data_anc; 44611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 44711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann ret = bpf_fill_section_data(elf_fd, elf_hdr, sec_index, 44811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann &data_anc); 44911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (ret < 0) 45011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann continue; 45111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 45211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann /* Extract and load eBPF map fds. */ 4536256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann if (!strcmp(data_anc.sec_name, ELF_SECTION_MAPS) && 4546256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann !bpf_may_skip_map_creation(file_fd)) { 4556256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann struct bpf_elf_map *maps; 4566256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann unsigned int maps_num; 4576256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 4586256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann if (data_anc.sec_data->d_size % sizeof(*maps) != 0) 4596256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann return -EINVAL; 4606256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 4616256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann maps = data_anc.sec_data->d_buf; 4626256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann maps_num = data_anc.sec_data->d_size / sizeof(*maps); 4636256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann memcpy(map_ent, maps, data_anc.sec_data->d_size); 46411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 46511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann sec_seen[sec_index] = true; 4666256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann ret = bpf_maps_attach(maps, maps_num); 46711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (ret < 0) 46811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return ret; 46911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann } 47011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann /* Extract eBPF license. */ 47111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann else if (!strcmp(data_anc.sec_name, ELF_SECTION_LICENSE)) { 47211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (data_anc.sec_data->d_size > lic_len) 47311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return -ENOMEM; 47411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 47511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann sec_seen[sec_index] = true; 47611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann memcpy(license, data_anc.sec_data->d_buf, 47711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann data_anc.sec_data->d_size); 47811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann } 47911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann /* Extract symbol table for relocations (map fd fixups). */ 48011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann else if (data_anc.sec_hdr.sh_type == SHT_SYMTAB) { 48111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann sec_seen[sec_index] = true; 48211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann *sym_tab = data_anc.sec_data; 48311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann } 48411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann } 48511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 48611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return ret; 48711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 48811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 48911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannstatic int bpf_fetch_prog_relo(Elf *elf_fd, GElf_Ehdr *elf_hdr, bool *sec_seen, 4906256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann enum bpf_prog_type type, const char *sec, 4916256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann const char *license, Elf_Data *sym_tab) 49211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 49311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann int sec_index, prog_fd = -1; 49411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 49511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann for (sec_index = 1; sec_index < elf_hdr->e_shnum; sec_index++) { 49611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann struct bpf_elf_sec_data data_relo, data_insn; 49711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann int ins_index, ret; 49811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 49911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann /* Attach eBPF programs with relocation data (maps). */ 50011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann ret = bpf_fill_section_data(elf_fd, elf_hdr, sec_index, 50111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann &data_relo); 50211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (ret < 0 || data_relo.sec_hdr.sh_type != SHT_REL) 50311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann continue; 50411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 50511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann ins_index = data_relo.sec_hdr.sh_info; 50611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 50711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann ret = bpf_fill_section_data(elf_fd, elf_hdr, ins_index, 50811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann &data_insn); 50911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (ret < 0) 51011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann continue; 5116256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann if (strcmp(data_insn.sec_name, sec)) 51211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann continue; 51311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 51411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann sec_seen[sec_index] = true; 51511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann sec_seen[ins_index] = true; 51611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 5176256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann ret = bpf_apply_relo_data(&data_relo, &data_insn, sym_tab); 51811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (ret < 0) 51911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann continue; 52011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 52111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann prog_fd = bpf_prog_attach(type, data_insn.sec_data->d_buf, 52211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann data_insn.sec_data->d_size, license); 52311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (prog_fd < 0) 52411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann continue; 52511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 52611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann break; 52711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann } 52811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 52911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return prog_fd; 53011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 53111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 53211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannstatic int bpf_fetch_prog(Elf *elf_fd, GElf_Ehdr *elf_hdr, bool *sec_seen, 5336256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann enum bpf_prog_type type, const char *sec, 5346256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann const char *license) 53511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 53611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann int sec_index, prog_fd = -1; 53711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 53811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann for (sec_index = 1; sec_index < elf_hdr->e_shnum; sec_index++) { 53911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann struct bpf_elf_sec_data data_insn; 54011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann int ret; 54111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 54211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann /* Attach eBPF programs without relocation data. */ 54311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (sec_seen[sec_index]) 54411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann continue; 54511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 54611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann ret = bpf_fill_section_data(elf_fd, elf_hdr, sec_index, 54711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann &data_insn); 54811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (ret < 0) 54911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann continue; 5506256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann if (strcmp(data_insn.sec_name, sec)) 55111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann continue; 55211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 55311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann prog_fd = bpf_prog_attach(type, data_insn.sec_data->d_buf, 55411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann data_insn.sec_data->d_size, license); 55511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (prog_fd < 0) 55611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann continue; 55711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 55811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann break; 55911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann } 56011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 56111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return prog_fd; 56211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 56311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 564d937a74b6d7818d67b12f2439320bfddcdd35e58Daniel Borkmannint bpf_open_object(const char *path, enum bpf_prog_type type, 565d937a74b6d7818d67b12f2439320bfddcdd35e58Daniel Borkmann const char *sec, bool verbose) 56611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann{ 56711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann char license[ELF_MAX_LICENSE_LEN]; 56811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann int file_fd, prog_fd = -1, ret; 56911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann Elf_Data *sym_tab = NULL; 57011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann GElf_Ehdr elf_hdr; 57111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann bool *sec_seen; 57211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann Elf *elf_fd; 57311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 57411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (elf_version(EV_CURRENT) == EV_NONE) 57511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return -EINVAL; 57611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 57711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann file_fd = open(path, O_RDONLY, 0); 57811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (file_fd < 0) 57911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return -errno; 58011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 58111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann elf_fd = elf_begin(file_fd, ELF_C_READ, NULL); 58211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (!elf_fd) { 58311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann ret = -EINVAL; 58411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann goto out; 58511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann } 58611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 58711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (gelf_getehdr(elf_fd, &elf_hdr) != &elf_hdr) { 58811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann ret = -EIO; 58911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann goto out_elf; 59011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann } 59111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 59211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann sec_seen = calloc(elf_hdr.e_shnum, sizeof(*sec_seen)); 59311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (!sec_seen) { 59411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann ret = -ENOMEM; 59511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann goto out_elf; 59611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann } 59711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 59811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann memset(license, 0, sizeof(license)); 599d937a74b6d7818d67b12f2439320bfddcdd35e58Daniel Borkmann bpf_verbose = verbose; 600d937a74b6d7818d67b12f2439320bfddcdd35e58Daniel Borkmann 6016256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann if (!bpf_may_skip_map_creation(file_fd)) 6026256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann bpf_maps_init(); 60311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 6046256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann ret = bpf_fetch_ancillary(file_fd, elf_fd, &elf_hdr, sec_seen, 60511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann license, sizeof(license), &sym_tab); 60611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (ret < 0) 60711c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann goto out_maps; 60811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (sym_tab) 60911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann prog_fd = bpf_fetch_prog_relo(elf_fd, &elf_hdr, sec_seen, type, 6106256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann sec, license, sym_tab); 61111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (prog_fd < 0) 6126256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann prog_fd = bpf_fetch_prog(elf_fd, &elf_hdr, sec_seen, type, sec, 61311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann license); 61411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann if (prog_fd < 0) 61511c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann goto out_maps; 6166256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 6176256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann bpf_save_finfo(file_fd); 6186256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 6196256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann free(sec_seen); 6206256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 6216256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann elf_end(elf_fd); 6226256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann close(file_fd); 6236256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 6246256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann return prog_fd; 6256256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 6266256f8c9e45f01187b297a576e148534a393c990Daniel Borkmannout_maps: 6276256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann bpf_maps_destroy(); 62811c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann free(sec_seen); 62911c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannout_elf: 63011c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann elf_end(elf_fd); 63111c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmannout: 63211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann close(file_fd); 6336256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann bpf_clear_finfo(); 63411c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann return prog_fd; 6356256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann} 63611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 6376256f8c9e45f01187b297a576e148534a393c990Daniel Borkmannstatic int 6384bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmannbpf_map_set_send(int fd, struct sockaddr_un *addr, unsigned int addr_len, 6394bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann const struct bpf_map_data *aux, unsigned int entries) 6406256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann{ 6416256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann struct bpf_map_set_msg msg; 6426256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann int *cmsg_buf, min_fd; 6436256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann char *amsg_buf; 6446256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann int i; 6456256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 6466256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann memset(&msg, 0, sizeof(msg)); 6476256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 6486256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann msg.aux.uds_ver = BPF_SCM_AUX_VER; 6494bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann msg.aux.num_ent = entries; 6506256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 6516256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann strncpy(msg.aux.obj_name, aux->obj, sizeof(msg.aux.obj_name)); 6526256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann memcpy(&msg.aux.obj_st, aux->st, sizeof(msg.aux.obj_st)); 6536256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 6546256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann cmsg_buf = bpf_map_set_init(&msg, addr, addr_len); 6556256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann amsg_buf = (char *)msg.aux.ent; 6566256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 6574bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann for (i = 0; i < entries; i += min_fd) { 6586256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann int ret; 6596256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 6604bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann min_fd = min(BPF_SCM_MAX_FDS * 1U, entries - i); 6616256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann bpf_map_set_init_single(&msg, min_fd); 6626256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 6636256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann memcpy(cmsg_buf, &aux->fds[i], sizeof(aux->fds[0]) * min_fd); 6646256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann memcpy(amsg_buf, &aux->ent[i], sizeof(aux->ent[0]) * min_fd); 6656256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 6666256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann ret = sendmsg(fd, &msg.hdr, 0); 6676256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann if (ret <= 0) 6686256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann return ret ? : -1; 6696256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann } 6706256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 6716256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann return 0; 67211c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann} 67311c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann 6744bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmannstatic int 6754bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmannbpf_map_set_recv(int fd, int *fds, struct bpf_map_aux *aux, 6764bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann unsigned int entries) 6774bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann{ 6784bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann struct bpf_map_set_msg msg; 6794bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann int *cmsg_buf, min_fd; 6804bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann char *amsg_buf, *mmsg_buf; 6814bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann unsigned int needed = 1; 6824bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann int i; 6834bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann 6844bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann cmsg_buf = bpf_map_set_init(&msg, NULL, 0); 6854bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann amsg_buf = (char *)msg.aux.ent; 6864bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann mmsg_buf = (char *)&msg.aux; 6874bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann 6884bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann for (i = 0; i < min(entries, needed); i += min_fd) { 6894bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann struct cmsghdr *cmsg; 6904bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann int ret; 6914bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann 6924bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann min_fd = min(entries, entries - i); 6934bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann bpf_map_set_init_single(&msg, min_fd); 6944bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann 6954bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann ret = recvmsg(fd, &msg.hdr, 0); 6964bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann if (ret <= 0) 6974bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann return ret ? : -1; 6984bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann 6994bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann cmsg = CMSG_FIRSTHDR(&msg.hdr); 7004bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann if (!cmsg || cmsg->cmsg_type != SCM_RIGHTS) 7014bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann return -EINVAL; 7024bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann if (msg.hdr.msg_flags & MSG_CTRUNC) 7034bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann return -EIO; 7044bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann if (msg.aux.uds_ver != BPF_SCM_AUX_VER) 7054bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann return -ENOSYS; 7064bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann 7074bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann min_fd = (cmsg->cmsg_len - sizeof(*cmsg)) / sizeof(fd); 7084bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann if (min_fd > entries || min_fd <= 0) 7094bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann return -EINVAL; 7104bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann 7114bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann memcpy(&fds[i], cmsg_buf, sizeof(fds[0]) * min_fd); 7124bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann memcpy(&aux->ent[i], amsg_buf, sizeof(aux->ent[0]) * min_fd); 7134bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann memcpy(aux, mmsg_buf, offsetof(struct bpf_map_aux, ent)); 7144bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann 7154bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann needed = aux->num_ent; 7164bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann } 7174bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann 7184bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann return 0; 7194bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann} 7204bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann 7214bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmannint bpf_send_map_fds(const char *path, const char *obj) 7226256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann{ 7236256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann struct sockaddr_un addr; 7246256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann struct bpf_map_data bpf_aux; 7256256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann int fd, ret; 7266256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 7276256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann fd = socket(AF_UNIX, SOCK_DGRAM, 0); 7286256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann if (fd < 0) { 7296256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann fprintf(stderr, "Cannot open socket: %s\n", 7306256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann strerror(errno)); 7316256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann return -1; 7326256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann } 7336256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 7346256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann memset(&addr, 0, sizeof(addr)); 7356256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann addr.sun_family = AF_UNIX; 7366256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann strncpy(addr.sun_path, path, sizeof(addr.sun_path)); 7376256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 7386256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr)); 7396256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann if (ret < 0) { 7406256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann fprintf(stderr, "Cannot connect to %s: %s\n", 7416256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann path, strerror(errno)); 7426256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann return -1; 7436256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann } 7446256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 7456256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann memset(&bpf_aux, 0, sizeof(bpf_aux)); 7466256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 7476256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann bpf_aux.fds = map_fds; 7486256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann bpf_aux.ent = map_ent; 7496256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 7506256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann bpf_aux.obj = obj; 7516256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann bpf_aux.st = &bpf_st; 7526256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 7534bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann ret = bpf_map_set_send(fd, &addr, sizeof(addr), &bpf_aux, 7546256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann bpf_maps_count()); 7556256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann if (ret < 0) 7564bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann fprintf(stderr, "Cannot send fds to %s: %s\n", 7574bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann path, strerror(errno)); 7584bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann 7594bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann close(fd); 7604bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann return ret; 7614bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann} 7624bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann 7634bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmannint bpf_recv_map_fds(const char *path, int *fds, struct bpf_map_aux *aux, 7644bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann unsigned int entries) 7654bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann{ 7664bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann struct sockaddr_un addr; 7674bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann int fd, ret; 7684bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann 7694bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann fd = socket(AF_UNIX, SOCK_DGRAM, 0); 7704bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann if (fd < 0) { 7714bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann fprintf(stderr, "Cannot open socket: %s\n", 7724bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann strerror(errno)); 7734bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann return -1; 7744bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann } 7754bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann 7764bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann memset(&addr, 0, sizeof(addr)); 7774bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann addr.sun_family = AF_UNIX; 7784bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann strncpy(addr.sun_path, path, sizeof(addr.sun_path)); 7794bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann 7804bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); 7814bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann if (ret < 0) { 7824bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann fprintf(stderr, "Cannot bind to socket: %s\n", 7834bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann strerror(errno)); 7844bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann return -1; 7854bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann } 7864bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann 7874bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann ret = bpf_map_set_recv(fd, fds, aux, entries); 7884bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann if (ret < 0) 7894bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann fprintf(stderr, "Cannot recv fds from %s: %s\n", 7906256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann path, strerror(errno)); 7916256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann 7924bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70Daniel Borkmann unlink(addr.sun_path); 7936256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann close(fd); 7946256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann return ret; 7956256f8c9e45f01187b297a576e148534a393c990Daniel Borkmann} 79611c39b5e98a163889fe5e1840e1b2a105bc33680Daniel Borkmann#endif /* HAVE_ELF */ 797