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