tc_bpf.c revision 91d88eeb10cd4f51e3b5c675c7aee4ae1e41ff16
1b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/*
2b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * tc_bpf.c	BPF common code
3b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru *
450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho *		This program is free software; you can distribute it and/or
5b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru *		modify it under the terms of the GNU General Public License
6b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru *		as published by the Free Software Foundation; either version
7b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru *		2 of the License, or (at your option) any later version.
8b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru *
9b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * Authors:	Daniel Borkmann <dborkman@redhat.com>
10b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru *		Jiri Pirko <jiri@resnulli.us>
11b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru *		Alexei Starovoitov <ast@plumgrid.com>
12b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */
13b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
14b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include <stdio.h>
15b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include <stdlib.h>
16b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include <unistd.h>
17b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include <string.h>
18b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include <stdbool.h>
19b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include <stdint.h>
20b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include <errno.h>
21b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include <fcntl.h>
22b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include <stdarg.h>
23b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
24b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#ifdef HAVE_ELF
25b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include <libelf.h>
26b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include <gelf.h>
27b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#endif
28b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
29b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include <sys/types.h>
30b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include <sys/stat.h>
31b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include <sys/un.h>
32b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include <sys/vfs.h>
33b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include <sys/mount.h>
34b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include <sys/syscall.h>
35b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include <sys/sendfile.h>
36b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include <sys/resource.h>
37b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
38b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include <linux/bpf.h>
39b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include <linux/filter.h>
40b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include <linux/if_alg.h>
41b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
42b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include "utils.h"
43b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
44b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include "bpf_elf.h"
45b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include "bpf_scm.h"
46b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
47b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include "tc_util.h"
48b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include "tc_bpf.h"
49b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
50b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#ifdef HAVE_ELF
51b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int bpf_obj_open(const char *path, enum bpf_prog_type type,
52b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			const char *sec, bool verbose);
53b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#else
54b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int bpf_obj_open(const char *path, enum bpf_prog_type type,
55b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			const char *sec, bool verbose)
56b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru{
57b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	fprintf(stderr, "No ELF library support compiled in.\n");
58b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	errno = ENOSYS;
59b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	return -1;
60b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
61b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#endif
62b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
63b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic inline __u64 bpf_ptr_to_u64(const void *ptr)
64b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru{
65b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	return (__u64)(unsigned long)ptr;
66b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
67b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
68b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int bpf(int cmd, union bpf_attr *attr, unsigned int size)
69b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru{
70b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#ifdef __NR_bpf
71b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	return syscall(__NR_bpf, cmd, attr, size);
72b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#else
73b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	fprintf(stderr, "No bpf syscall, kernel headers too old?\n");
74b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	errno = ENOSYS;
75b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	return -1;
76b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#endif
77b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
78b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
79b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int bpf_map_update(int fd, const void *key, const void *value,
80b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			  uint64_t flags)
81b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru{
82b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	union bpf_attr attr = {
83b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		.map_fd		= fd,
84b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		.key		= bpf_ptr_to_u64(key),
85b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		.value		= bpf_ptr_to_u64(value),
86b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		.flags		= flags,
87b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	};
88b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
89b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	return bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
90b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
91b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
92b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int bpf_parse_string(char *arg, bool from_file, __u16 *bpf_len,
93b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			    char **bpf_string, bool *need_release,
94b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			    const char separator)
95b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru{
96b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	char sp;
97b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
98b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (from_file) {
99b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		size_t tmp_len, op_len = sizeof("65535 255 255 4294967295,");
100b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		char *tmp_string;
101b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		FILE *fp;
102b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
103b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		tmp_len = sizeof("4096,") + BPF_MAXINSNS * op_len;
104b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		tmp_string = malloc(tmp_len);
105b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		if (tmp_string == NULL)
106b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			return -ENOMEM;
107b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
108b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		memset(tmp_string, 0, tmp_len);
109b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
110b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		fp = fopen(arg, "r");
111b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		if (fp == NULL) {
112b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			perror("Cannot fopen");
113b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			free(tmp_string);
114b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			return -ENOENT;
115b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		}
116b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
117b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		if (!fgets(tmp_string, tmp_len, fp)) {
118b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			free(tmp_string);
119b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			fclose(fp);
120b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			return -EIO;
121b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		}
122b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
123b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		fclose(fp);
124b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
125b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		*need_release = true;
126b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		*bpf_string = tmp_string;
127b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	} else {
128b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		*need_release = false;
129b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		*bpf_string = arg;
130b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	}
131b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
132b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (sscanf(*bpf_string, "%hu%c", bpf_len, &sp) != 2 ||
133b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	    sp != separator) {
134b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		if (*need_release)
135b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			free(*bpf_string);
136b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		return -EINVAL;
137b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	}
138b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
139b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	return 0;
140b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
141b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
142b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int bpf_ops_parse(int argc, char **argv, struct sock_filter *bpf_ops,
143b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			 bool from_file)
144b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru{
145b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	char *bpf_string, *token, separator = ',';
146b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	int ret = 0, i = 0;
147b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	bool need_release;
148b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	__u16 bpf_len = 0;
149b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
150b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (argc < 1)
151b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		return -EINVAL;
152b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (bpf_parse_string(argv[0], from_file, &bpf_len, &bpf_string,
153b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			     &need_release, separator))
154b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		return -EINVAL;
155b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (bpf_len == 0 || bpf_len > BPF_MAXINSNS) {
156b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		ret = -EINVAL;
157b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		goto out;
158b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	}
159b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
16050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	token = bpf_string;
16150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	while ((token = strchr(token, separator)) && (++token)[0]) {
16250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		if (i >= bpf_len) {
163b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			fprintf(stderr, "Real program length exceeds encoded "
164b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru				"length parameter!\n");
165b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			ret = -EINVAL;
16650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho			goto out;
167b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		}
168b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
169b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		if (sscanf(token, "%hu %hhu %hhu %u,",
170b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			   &bpf_ops[i].code, &bpf_ops[i].jt,
171b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			   &bpf_ops[i].jf, &bpf_ops[i].k) != 4) {
172b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			fprintf(stderr, "Error at instruction %d!\n", i);
173b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			ret = -EINVAL;
174b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			goto out;
175b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		}
176b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
177b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		i++;
178b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	}
179b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
180b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (i != bpf_len) {
181b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		fprintf(stderr, "Parsed program length is less than encoded"
182b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			"length parameter!\n");
183b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		ret = -EINVAL;
184b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		goto out;
18550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	}
186b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	ret = bpf_len;
187b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruout:
188b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (need_release)
189b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		free(bpf_string);
190b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
191b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	return ret;
192b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
193b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
194b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruvoid bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len)
195b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru{
196b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	struct sock_filter *ops = (struct sock_filter *) RTA_DATA(bpf_ops);
197b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	int i;
198b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
199b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (len == 0)
200b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		return;
201b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
202b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	fprintf(f, "bytecode \'%u,", len);
203b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
204b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	for (i = 0; i < len - 1; i++)
205b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		fprintf(f, "%hu %hhu %hhu %u,", ops[i].code, ops[i].jt,
206b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			ops[i].jf, ops[i].k);
207b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
208b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	fprintf(f, "%hu %hhu %hhu %u\'", ops[i].code, ops[i].jt,
209b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		ops[i].jf, ops[i].k);
210b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
211b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
212b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int bpf_map_selfcheck_pinned(int fd, const struct bpf_elf_map *map,
21350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho				    int length)
214b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru{
215b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	char file[PATH_MAX], buff[4096];
216b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	struct bpf_elf_map tmp, zero;
217b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	unsigned int val;
218b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	FILE *fp;
219b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
22050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	snprintf(file, sizeof(file), "/proc/%d/fdinfo/%d", getpid(), fd);
221b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
222b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	fp = fopen(file, "r");
223b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (!fp) {
224b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		fprintf(stderr, "No procfs support?!\n");
225b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		return -EIO;
226b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	}
227b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
228b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	memset(&tmp, 0, sizeof(tmp));
229b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	while (fgets(buff, sizeof(buff), fp)) {
230b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		if (sscanf(buff, "map_type:\t%u", &val) == 1)
231b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			tmp.type = val;
232b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		else if (sscanf(buff, "key_size:\t%u", &val) == 1)
233b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			tmp.size_key = val;
234b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		else if (sscanf(buff, "value_size:\t%u", &val) == 1)
235b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			tmp.size_value = val;
236b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		else if (sscanf(buff, "max_entries:\t%u", &val) == 1)
237b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			tmp.max_elem = val;
238b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	}
239b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
240b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	fclose(fp);
241b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
242b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (!memcmp(&tmp, map, length)) {
243b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		return 0;
244b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	} else {
245b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		memset(&zero, 0, sizeof(zero));
246b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		/* If kernel doesn't have eBPF-related fdinfo, we cannot do much,
247b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		 * so just accept it. We know we do have an eBPF fd and in this
248b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		 * case, everything is 0. It is guaranteed that no such map exists
249b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		 * since map type of 0 is unloadable BPF_MAP_TYPE_UNSPEC.
250b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		 */
251b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		if (!memcmp(&tmp, &zero, length))
252b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			return 0;
253b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
254b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		fprintf(stderr, "Map specs from pinned file differ!\n");
255b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		return -EINVAL;
256b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	}
257b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
258b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
259b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int bpf_mnt_fs(const char *target)
260b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru{
261b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	bool bind_done = false;
262b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
263b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	while (mount("", target, "none", MS_PRIVATE | MS_REC, NULL)) {
264b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		if (errno != EINVAL || bind_done) {
265b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			fprintf(stderr, "mount --make-private %s failed: %s\n",
266b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru				target,	strerror(errno));
267b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			return -1;
268b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		}
269b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
270b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		if (mount(target, target, "none", MS_BIND, NULL)) {
271b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			fprintf(stderr, "mount --bind %s %s failed: %s\n",
272b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru				target,	target, strerror(errno));
273b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			return -1;
274b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		}
275b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
276b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		bind_done = true;
277b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	}
278b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
279b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (mount("bpf", target, "bpf", 0, NULL)) {
280b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		fprintf(stderr, "mount -t bpf bpf %s failed: %s\n",
281b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			target,	strerror(errno));
282b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		return -1;
283b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	}
284b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
285b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	return 0;
286b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
287b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
288b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int bpf_valid_mntpt(const char *mnt, unsigned long magic)
289b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru{
290b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	struct statfs st_fs;
291b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
292b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (statfs(mnt, &st_fs) < 0)
293b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		return -ENOENT;
294b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if ((unsigned long)st_fs.f_type != magic)
295b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		return -ENOENT;
296b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
297b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	return 0;
298b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
299b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
300b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char *bpf_find_mntpt(const char *fstype, unsigned long magic,
301b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru				  char *mnt, int len,
302b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru				  const char * const *known_mnts)
303b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru{
304b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	const char * const *ptr;
305b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	char type[100];
306b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	FILE *fp;
307b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
308b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (known_mnts) {
309b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		ptr = known_mnts;
310b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		while (*ptr) {
311b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			if (bpf_valid_mntpt(*ptr, magic) == 0) {
312b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru				strncpy(mnt, *ptr, len - 1);
313b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru				mnt[len - 1] = 0;
314b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru				return mnt;
315b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			}
316b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			ptr++;
317b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		}
318b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	}
319b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
320b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	fp = fopen("/proc/mounts", "r");
321b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (fp == NULL || len != PATH_MAX)
322b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		return NULL;
323b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
324b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	while (fscanf(fp, "%*s %" textify(PATH_MAX) "s %99s %*s %*d %*d\n",
325b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		      mnt, type) == 2) {
326b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		if (strcmp(type, fstype) == 0)
327b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			break;
328b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	}
329b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
330b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	fclose(fp);
331b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (strcmp(type, fstype) != 0)
332b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		return NULL;
333b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
334b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	return mnt;
335b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
336b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
337b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruint bpf_trace_pipe(void)
338b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru{
339b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	char tracefs_mnt[PATH_MAX] = TRACE_DIR_MNT;
340b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	static const char * const tracefs_known_mnts[] = {
341b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		TRACE_DIR_MNT,
342b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		"/sys/kernel/debug/tracing",
343b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		"/tracing",
344b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		"/trace",
345b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		0,
346b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	};
347b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	char tpipe[PATH_MAX];
348b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	const char *mnt;
349b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	int fd;
350b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
351b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	mnt = bpf_find_mntpt("tracefs", TRACEFS_MAGIC, tracefs_mnt,
352b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			     sizeof(tracefs_mnt), tracefs_known_mnts);
353b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (!mnt) {
354b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		fprintf(stderr, "tracefs not mounted?\n");
355b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		return -1;
356b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	}
357b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
358b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	snprintf(tpipe, sizeof(tpipe), "%s/trace_pipe", mnt);
359b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
360b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	fd = open(tpipe, O_RDONLY);
361b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (fd < 0)
362b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		return -1;
363b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
364b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	fprintf(stderr, "Running! Hang up with ^C!\n\n");
365b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	while (1) {
366b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		static char buff[4096];
367b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		ssize_t ret;
368b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
369b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		ret = read(fd, buff, sizeof(buff) - 1);
370b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		if (ret > 0) {
371b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			write(2, buff, ret);
372b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			fflush(stderr);
373b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		}
374b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	}
375b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
376b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	return 0;
377b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
378b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
379b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char *bpf_get_tc_dir(void)
380b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru{
381b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	static bool bpf_mnt_cached = false;
382b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	static char bpf_tc_dir[PATH_MAX];
383b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	static const char *mnt;
384b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	static const char * const bpf_known_mnts[] = {
385b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		BPF_DIR_MNT,
386b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		0,
387b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	};
388b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	char bpf_mnt[PATH_MAX] = BPF_DIR_MNT;
389b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	char bpf_glo_dir[PATH_MAX];
390b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	int ret;
391b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
392b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (bpf_mnt_cached)
393b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		goto done;
394b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
395b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	mnt = bpf_find_mntpt("bpf", BPF_FS_MAGIC, bpf_mnt, sizeof(bpf_mnt),
396b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			     bpf_known_mnts);
397b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (!mnt) {
398b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		mnt = getenv(BPF_ENV_MNT);
399b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		if (!mnt)
400b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			mnt = BPF_DIR_MNT;
401b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		ret = bpf_mnt_fs(mnt);
402b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		if (ret) {
403b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			mnt = NULL;
404b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			goto out;
405b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		}
406b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	}
407b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
408b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	snprintf(bpf_tc_dir, sizeof(bpf_tc_dir), "%s/%s", mnt, BPF_DIR_TC);
409b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	ret = mkdir(bpf_tc_dir, S_IRWXU);
410b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (ret && errno != EEXIST) {
411b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		fprintf(stderr, "mkdir %s failed: %s\n", bpf_tc_dir,
412b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			strerror(errno));
413b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		mnt = NULL;
414b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		goto out;
415b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	}
416b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
417b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	snprintf(bpf_glo_dir, sizeof(bpf_glo_dir), "%s/%s",
418b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		 bpf_tc_dir, BPF_DIR_GLOBALS);
419b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	ret = mkdir(bpf_glo_dir, S_IRWXU);
420b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (ret && errno != EEXIST) {
421b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		fprintf(stderr, "mkdir %s failed: %s\n", bpf_glo_dir,
422b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			strerror(errno));
423b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		mnt = NULL;
424b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		goto out;
425b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	}
426b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
427b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	mnt = bpf_tc_dir;
428b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruout:
429b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	bpf_mnt_cached = true;
430b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querudone:
431b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	return mnt;
432b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
433b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
434b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int bpf_obj_get(const char *pathname)
435b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru{
436b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	union bpf_attr attr;
437b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	char tmp[PATH_MAX];
438b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
439b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (strlen(pathname) > 2 && pathname[0] == 'm' &&
440b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	    pathname[1] == ':' && bpf_get_tc_dir()) {
441b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		snprintf(tmp, sizeof(tmp), "%s/%s",
442b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			 bpf_get_tc_dir(), pathname + 2);
443b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		pathname = tmp;
444b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	}
445b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
446b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	memset(&attr, 0, sizeof(attr));
447b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	attr.pathname = bpf_ptr_to_u64(pathname);
448b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
449b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	return bpf(BPF_OBJ_GET, &attr, sizeof(attr));
450b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
451b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
452b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruconst char *bpf_default_section(const enum bpf_prog_type type)
453b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru{
454b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	switch (type) {
455b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	case BPF_PROG_TYPE_SCHED_CLS:
456b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		return ELF_SECTION_CLASSIFIER;
457b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	case BPF_PROG_TYPE_SCHED_ACT:
458b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		return ELF_SECTION_ACTION;
459b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	default:
460b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		return NULL;
461b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	}
462b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
463b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
464b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruenum bpf_mode {
465b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	CBPF_BYTECODE = 0,
466b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	CBPF_FILE,
467b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	EBPF_OBJECT,
468b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	EBPF_PINNED,
469b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	__BPF_MODE_MAX,
470b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define BPF_MODE_MAX	__BPF_MODE_MAX
471b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru};
472b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
473b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int bpf_parse(int *ptr_argc, char ***ptr_argv, const bool *opt_tbl,
474b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		     enum bpf_prog_type *type, enum bpf_mode *mode,
475b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		     const char **ptr_object, const char **ptr_section,
476b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		     const char **ptr_uds_name, struct sock_filter *opcodes)
477b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru{
478b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	const char *file, *section, *uds_name;
479b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	bool verbose = false;
480b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	int ret, argc;
481b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	char **argv;
482b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
483b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	argv = *ptr_argv;
484b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	argc = *ptr_argc;
485b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
486b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (opt_tbl[CBPF_BYTECODE] &&
487b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	    (matches(*argv, "bytecode") == 0 ||
488b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	     strcmp(*argv, "bc") == 0)) {
489b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		*mode = CBPF_BYTECODE;
490b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	} else if (opt_tbl[CBPF_FILE] &&
491b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		   (matches(*argv, "bytecode-file") == 0 ||
492b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		    strcmp(*argv, "bcf") == 0)) {
493b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		*mode = CBPF_FILE;
494b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	} else if (opt_tbl[EBPF_OBJECT] &&
495b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		   (matches(*argv, "object-file") == 0 ||
496b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		    strcmp(*argv, "obj") == 0)) {
497b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		*mode = EBPF_OBJECT;
498b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	} else if (opt_tbl[EBPF_PINNED] &&
499b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		   (matches(*argv, "object-pinned") == 0 ||
500b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		    matches(*argv, "pinned") == 0 ||
501b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		    matches(*argv, "fd") == 0)) {
502b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		*mode = EBPF_PINNED;
503b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	} else {
504b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		fprintf(stderr, "What mode is \"%s\"?\n", *argv);
505b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		return -1;
506b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	}
507b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
508b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	NEXT_ARG();
509b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	file = section = uds_name = NULL;
510b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (*mode == EBPF_OBJECT || *mode == EBPF_PINNED) {
511b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		file = *argv;
512b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		NEXT_ARG_FWD();
513b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
514b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		if (*type == BPF_PROG_TYPE_UNSPEC) {
515b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			if (argc > 0 && matches(*argv, "type") == 0) {
516b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru				NEXT_ARG();
517b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru				if (matches(*argv, "cls") == 0) {
518b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru					*type = BPF_PROG_TYPE_SCHED_CLS;
519b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru				} else if (matches(*argv, "act") == 0) {
520b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru					*type = BPF_PROG_TYPE_SCHED_ACT;
521b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru				} else {
522b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru					fprintf(stderr, "What type is \"%s\"?\n",
523b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru						*argv);
524b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru					return -1;
525b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru				}
526b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru				NEXT_ARG_FWD();
527b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			} else {
528b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru				*type = BPF_PROG_TYPE_SCHED_CLS;
529b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			}
530b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		}
531b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
532b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		section = bpf_default_section(*type);
533b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		if (argc > 0 && matches(*argv, "section") == 0) {
534b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			NEXT_ARG();
535b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			section = *argv;
536b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			NEXT_ARG_FWD();
537b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		}
538b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
539b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		uds_name = getenv(BPF_ENV_UDS);
540b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		if (argc > 0 && !uds_name &&
541b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		    matches(*argv, "export") == 0) {
542b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			NEXT_ARG();
543b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			uds_name = *argv;
544b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			NEXT_ARG_FWD();
545b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		}
546b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
547b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		if (argc > 0 && matches(*argv, "verbose") == 0) {
548b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			verbose = true;
549b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			NEXT_ARG_FWD();
550b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		}
551b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
552b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		PREV_ARG();
553b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	}
554b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
555b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (*mode == CBPF_BYTECODE || *mode == CBPF_FILE)
556b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		ret = bpf_ops_parse(argc, argv, opcodes, *mode == CBPF_FILE);
557b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	else if (*mode == EBPF_OBJECT)
558b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		ret = bpf_obj_open(file, *type, section, verbose);
559b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	else if (*mode == EBPF_PINNED)
560b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		ret = bpf_obj_get(file);
561b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	else
562b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		return -1;
563b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
564b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (ptr_object)
565b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		*ptr_object = file;
566b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (ptr_section)
567b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		*ptr_section = section;
568b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (ptr_uds_name)
569b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		*ptr_uds_name = uds_name;
570b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
571b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	*ptr_argc = argc;
572b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	*ptr_argv = argv;
573b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
574b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	return ret;
575b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
576b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
577b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruint bpf_parse_common(int *ptr_argc, char ***ptr_argv, const int *nla_tbl,
578b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		     enum bpf_prog_type type, const char **ptr_object,
579b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		     const char **ptr_uds_name, struct nlmsghdr *n)
580b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru{
581b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	struct sock_filter opcodes[BPF_MAXINSNS];
582b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	const bool opt_tbl[BPF_MODE_MAX] = {
583b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		[CBPF_BYTECODE]	= true,
584b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		[CBPF_FILE]	= true,
585b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		[EBPF_OBJECT]	= true,
586b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		[EBPF_PINNED]	= true,
587b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	};
588b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	char annotation[256];
589b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	const char *section;
590b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	enum bpf_mode mode;
591b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	int ret;
592b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
593b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	ret = bpf_parse(ptr_argc, ptr_argv, opt_tbl, &type, &mode,
594b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			ptr_object, &section, ptr_uds_name, opcodes);
595b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (ret < 0)
596b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		return ret;
597b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
598b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (mode == CBPF_BYTECODE || mode == CBPF_FILE) {
599b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		addattr16(n, MAX_MSG, nla_tbl[BPF_NLA_OPS_LEN], ret);
600b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		addattr_l(n, MAX_MSG, nla_tbl[BPF_NLA_OPS], opcodes,
601b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			  ret * sizeof(struct sock_filter));
602b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	}
603b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
604b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (mode == EBPF_OBJECT || mode == EBPF_PINNED) {
605b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		snprintf(annotation, sizeof(annotation), "%s:[%s]",
606b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			 basename(*ptr_object), mode == EBPF_PINNED ?
607b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			 "*fsobj" : section);
608b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
609b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		addattr32(n, MAX_MSG, nla_tbl[BPF_NLA_FD], ret);
610b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		addattrstrz(n, MAX_MSG, nla_tbl[BPF_NLA_NAME], annotation);
611b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	}
612b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
613b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	return 0;
614b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
615b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
616b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruint bpf_graft_map(const char *map_path, uint32_t *key, int argc, char **argv)
617b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru{
618b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	enum bpf_prog_type type = BPF_PROG_TYPE_UNSPEC;
619b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	const bool opt_tbl[BPF_MODE_MAX] = {
620b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		[CBPF_BYTECODE]	= false,
621b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		[CBPF_FILE]	= false,
622b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		[EBPF_OBJECT]	= true,
623b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		[EBPF_PINNED]	= true,
624b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	};
625b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	const struct bpf_elf_map test = {
626b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		.type		= BPF_MAP_TYPE_PROG_ARRAY,
627b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		.size_key	= sizeof(int),
628b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		.size_value	= sizeof(int),
629b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	};
630b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	int ret, prog_fd, map_fd;
631b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	const char *section;
632b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	enum bpf_mode mode;
63350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	uint32_t map_key;
634b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
635b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	prog_fd = bpf_parse(&argc, &argv, opt_tbl, &type, &mode,
636b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			    NULL, &section, NULL, NULL);
637b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (prog_fd < 0)
638b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		return prog_fd;
639b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (key) {
640b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		map_key = *key;
641b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	} else {
642b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		ret = sscanf(section, "%*i/%i", &map_key);
643b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		if (ret != 1) {
644b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			fprintf(stderr, "Couldn\'t infer map key from section "
645b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru				"name! Please provide \'key\' argument!\n");
646b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			ret = -EINVAL;
647b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			goto out_prog;
648b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		}
649b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	}
650b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
651b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	map_fd = bpf_obj_get(map_path);
652b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (map_fd < 0) {
653b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		fprintf(stderr, "Couldn\'t retrieve pinned map \'%s\': %s\n",
654b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			map_path, strerror(errno));
655b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		ret = map_fd;
656b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		goto out_prog;
657b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	}
658b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
659b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	ret = bpf_map_selfcheck_pinned(map_fd, &test,
660b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru				       offsetof(struct bpf_elf_map, max_elem));
661b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (ret < 0) {
662b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		fprintf(stderr, "Map \'%s\' self-check failed!\n", map_path);
66350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		goto out_map;
664b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	}
665b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
666b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	ret = bpf_map_update(map_fd, &map_key, &prog_fd, BPF_ANY);
667b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (ret < 0)
668b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		fprintf(stderr, "Map update failed: %s\n", strerror(errno));
669b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruout_map:
670b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	close(map_fd);
671b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruout_prog:
672b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	close(prog_fd);
673b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	return ret;
67450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho}
675b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
676b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#ifdef HAVE_ELF
677b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustruct bpf_elf_prog {
678b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	enum bpf_prog_type	type;
679b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	const struct bpf_insn	*insns;
680b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	size_t			size;
681b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	const char		*license;
682b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru};
683b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
684b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustruct bpf_hash_entry {
685b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	unsigned int		pinning;
686b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	const char		*subpath;
687b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	struct bpf_hash_entry	*next;
688b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru};
689b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
690b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustruct bpf_elf_ctx {
691b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	Elf			*elf_fd;
692b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	GElf_Ehdr		elf_hdr;
693b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	Elf_Data		*sym_tab;
694b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	Elf_Data		*str_tab;
695b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	int			obj_fd;
696b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	int			map_fds[ELF_MAX_MAPS];
697b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	struct bpf_elf_map	maps[ELF_MAX_MAPS];
698b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	int			sym_num;
699b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	int			map_num;
700b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	bool			*sec_done;
701b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	int			sec_maps;
702b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	char			license[ELF_MAX_LICENSE_LEN];
703b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	enum bpf_prog_type	type;
704b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	bool			verbose;
705b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	struct bpf_elf_st	stat;
706b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	struct bpf_hash_entry	*ht[256];
707b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru};
708b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
709b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustruct bpf_elf_sec_data {
710b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	GElf_Shdr		sec_hdr;
711b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	Elf_Data		*sec_data;
712b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	const char		*sec_name;
713b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru};
714b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
715b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustruct bpf_map_data {
716b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	int			*fds;
717b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	const char		*obj;
718b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	struct bpf_elf_st	*st;
719b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	struct bpf_elf_map	*ent;
720b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru};
721b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
722b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/* If we provide a small buffer with log level enabled, the kernel
723b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * could fail program load as no buffer space is available for the
724b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * log and thus verifier fails. In case something doesn't pass the
725b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * verifier we still want to hand something descriptive to the user.
726b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */
727b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic char bpf_log_buf[65536];
728b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
729b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic __check_format_string(1, 2) void bpf_dump_error(const char *format, ...)
730b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru{
731b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	va_list vl;
732b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
733b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	va_start(vl, format);
734b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	vfprintf(stderr, format, vl);
735b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	va_end(vl);
736b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
737b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (bpf_log_buf[0]) {
738b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		fprintf(stderr, "%s\n", bpf_log_buf);
739b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		memset(bpf_log_buf, 0, sizeof(bpf_log_buf));
740b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	}
741b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
742b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
743b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int bpf_map_create(enum bpf_map_type type, unsigned int size_key,
744b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			  unsigned int size_value, unsigned int max_elem)
745b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru{
746b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	union bpf_attr attr = {
747b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		.map_type	= type,
748b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		.key_size	= size_key,
749b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		.value_size	= size_value,
750b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		.max_entries	= max_elem,
751b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	};
752b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
753b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	return bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
754b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
755b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
756b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int bpf_prog_load(enum bpf_prog_type type, const struct bpf_insn *insns,
757b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			 size_t size, const char *license)
758b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru{
759b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	union bpf_attr attr = {
760b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		.prog_type	= type,
761b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		.insns		= bpf_ptr_to_u64(insns),
762b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		.insn_cnt	= size / sizeof(struct bpf_insn),
763b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		.license	= bpf_ptr_to_u64(license),
764b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		.log_buf	= bpf_ptr_to_u64(bpf_log_buf),
765b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		.log_size	= sizeof(bpf_log_buf),
766b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		.log_level	= 1,
767b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	};
768b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
769b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (getenv(BPF_ENV_NOLOG)) {
770b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		attr.log_buf	= 0;
771b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		attr.log_size	= 0;
772b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		attr.log_level	= 0;
773b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	}
774b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
775b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	return bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
776b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
777b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
778b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int bpf_obj_pin(int fd, const char *pathname)
779b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru{
780b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	union bpf_attr attr = {
781b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		.pathname	= bpf_ptr_to_u64(pathname),
782b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		.bpf_fd		= fd,
783b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	};
784b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
785b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	return bpf(BPF_OBJ_PIN, &attr, sizeof(attr));
786b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
787b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
788b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int bpf_obj_hash(const char *object, uint8_t *out, size_t len)
789b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru{
790b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	struct sockaddr_alg alg = {
791b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		.salg_family	= AF_ALG,
792b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		.salg_type	= "hash",
793b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		.salg_name	= "sha1",
794b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	};
795b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	int ret, cfd, ofd, ffd;
796b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	struct stat stbuff;
797b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	ssize_t size;
798b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
79950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	if (!object || len != 20)
800b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		return -EINVAL;
801b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
802b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	cfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
803b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (cfd < 0) {
804b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		fprintf(stderr, "Cannot get AF_ALG socket: %s\n",
805b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			strerror(errno));
806b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		return cfd;
807b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	}
808b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
809b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	ret = bind(cfd, (struct sockaddr *)&alg, sizeof(alg));
810b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	if (ret < 0) {
811b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		fprintf(stderr, "Error binding socket: %s\n", strerror(errno));
812		goto out_cfd;
813	}
814
815	ofd = accept(cfd, NULL, 0);
816	if (ofd < 0) {
817		fprintf(stderr, "Error accepting socket: %s\n",
818			strerror(errno));
819		ret = ofd;
820		goto out_cfd;
821	}
822
823	ffd = open(object, O_RDONLY);
824	if (ffd < 0) {
825		fprintf(stderr, "Error opening object %s: %s\n",
826			object, strerror(errno));
827		ret = ffd;
828		goto out_ofd;
829	}
830
831        ret = fstat(ffd, &stbuff);
832	if (ret < 0) {
833		fprintf(stderr, "Error doing fstat: %s\n",
834			strerror(errno));
835		goto out_ffd;
836	}
837
838	size = sendfile(ofd, ffd, NULL, stbuff.st_size);
839	if (size != stbuff.st_size) {
840		fprintf(stderr, "Error from sendfile (%zd vs %zu bytes): %s\n",
841			size, stbuff.st_size, strerror(errno));
842		ret = -1;
843		goto out_ffd;
844	}
845
846	size = read(ofd, out, len);
847	if (size != len) {
848		fprintf(stderr, "Error from read (%zd vs %zu bytes): %s\n",
849			size, len, strerror(errno));
850		ret = -1;
851	} else {
852		ret = 0;
853	}
854out_ffd:
855	close(ffd);
856out_ofd:
857	close(ofd);
858out_cfd:
859	close(cfd);
860	return ret;
861}
862
863static const char *bpf_get_obj_uid(const char *pathname)
864{
865	static bool bpf_uid_cached = false;
866	static char bpf_uid[64];
867	uint8_t tmp[20];
868	int ret;
869
870	if (bpf_uid_cached)
871		goto done;
872
873	ret = bpf_obj_hash(pathname, tmp, sizeof(tmp));
874	if (ret) {
875		fprintf(stderr, "Object hashing failed!\n");
876		return NULL;
877	}
878
879	hexstring_n2a(tmp, sizeof(tmp), bpf_uid, sizeof(bpf_uid));
880	bpf_uid_cached = true;
881done:
882	return bpf_uid;
883}
884
885static int bpf_init_env(const char *pathname)
886{
887	struct rlimit limit = {
888		.rlim_cur = RLIM_INFINITY,
889		.rlim_max = RLIM_INFINITY,
890	};
891
892	/* Don't bother in case we fail! */
893	setrlimit(RLIMIT_MEMLOCK, &limit);
894
895	if (!bpf_get_tc_dir()) {
896		fprintf(stderr, "Continuing without mounted eBPF fs. "
897			"Too old kernel?\n");
898		return 0;
899	}
900
901	if (!bpf_get_obj_uid(pathname))
902		return -1;
903
904	return 0;
905}
906
907static const char *bpf_custom_pinning(const struct bpf_elf_ctx *ctx,
908				      uint32_t pinning)
909{
910	struct bpf_hash_entry *entry;
911
912	entry = ctx->ht[pinning & (ARRAY_SIZE(ctx->ht) - 1)];
913	while (entry && entry->pinning != pinning)
914		entry = entry->next;
915
916	return entry ? entry->subpath : NULL;
917}
918
919static bool bpf_no_pinning(const struct bpf_elf_ctx *ctx,
920			   uint32_t pinning)
921{
922	switch (pinning) {
923	case PIN_OBJECT_NS:
924	case PIN_GLOBAL_NS:
925		return false;
926	case PIN_NONE:
927		return true;
928	default:
929		return !bpf_custom_pinning(ctx, pinning);
930	}
931}
932
933static void bpf_make_pathname(char *pathname, size_t len, const char *name,
934			      const struct bpf_elf_ctx *ctx, uint32_t pinning)
935{
936	switch (pinning) {
937	case PIN_OBJECT_NS:
938		snprintf(pathname, len, "%s/%s/%s", bpf_get_tc_dir(),
939			 bpf_get_obj_uid(NULL), name);
940		break;
941	case PIN_GLOBAL_NS:
942		snprintf(pathname, len, "%s/%s/%s", bpf_get_tc_dir(),
943			 BPF_DIR_GLOBALS, name);
944		break;
945	default:
946		snprintf(pathname, len, "%s/../%s/%s", bpf_get_tc_dir(),
947			 bpf_custom_pinning(ctx, pinning), name);
948		break;
949	}
950}
951
952static int bpf_probe_pinned(const char *name, const struct bpf_elf_ctx *ctx,
953			    uint32_t pinning)
954{
955	char pathname[PATH_MAX];
956
957	if (bpf_no_pinning(ctx, pinning) || !bpf_get_tc_dir())
958		return 0;
959
960	bpf_make_pathname(pathname, sizeof(pathname), name, ctx, pinning);
961	return bpf_obj_get(pathname);
962}
963
964static int bpf_make_obj_path(void)
965{
966	char tmp[PATH_MAX];
967	int ret;
968
969	snprintf(tmp, sizeof(tmp), "%s/%s", bpf_get_tc_dir(),
970		 bpf_get_obj_uid(NULL));
971
972	ret = mkdir(tmp, S_IRWXU);
973	if (ret && errno != EEXIST) {
974		fprintf(stderr, "mkdir %s failed: %s\n", tmp, strerror(errno));
975		return ret;
976	}
977
978	return 0;
979}
980
981static int bpf_make_custom_path(const char *todo)
982{
983	char tmp[PATH_MAX], rem[PATH_MAX], *sub;
984	int ret;
985
986	snprintf(tmp, sizeof(tmp), "%s/../", bpf_get_tc_dir());
987	snprintf(rem, sizeof(rem), "%s/", todo);
988	sub = strtok(rem, "/");
989
990	while (sub) {
991		if (strlen(tmp) + strlen(sub) + 2 > PATH_MAX)
992			return -EINVAL;
993
994		strcat(tmp, sub);
995		strcat(tmp, "/");
996
997		ret = mkdir(tmp, S_IRWXU);
998		if (ret && errno != EEXIST) {
999			fprintf(stderr, "mkdir %s failed: %s\n", tmp,
1000				strerror(errno));
1001			return ret;
1002		}
1003
1004		sub = strtok(NULL, "/");
1005	}
1006
1007	return 0;
1008}
1009
1010static int bpf_place_pinned(int fd, const char *name,
1011			    const struct bpf_elf_ctx *ctx, uint32_t pinning)
1012{
1013	char pathname[PATH_MAX];
1014	const char *tmp;
1015	int ret = 0;
1016
1017	if (bpf_no_pinning(ctx, pinning) || !bpf_get_tc_dir())
1018		return 0;
1019
1020	if (pinning == PIN_OBJECT_NS)
1021		ret = bpf_make_obj_path();
1022	else if ((tmp = bpf_custom_pinning(ctx, pinning)))
1023		ret = bpf_make_custom_path(tmp);
1024	if (ret < 0)
1025		return ret;
1026
1027	bpf_make_pathname(pathname, sizeof(pathname), name, ctx, pinning);
1028	return bpf_obj_pin(fd, pathname);
1029}
1030
1031static int bpf_prog_attach(const char *section,
1032			   const struct bpf_elf_prog *prog, bool verbose)
1033{
1034	int fd;
1035
1036	/* We can add pinning here later as well, same as bpf_map_attach(). */
1037	errno = 0;
1038	fd = bpf_prog_load(prog->type, prog->insns, prog->size,
1039			   prog->license);
1040	if (fd < 0 || verbose) {
1041		bpf_dump_error("Prog section \'%s\' (type:%u insns:%zu "
1042			       "license:\'%s\') %s%s (%d)!\n\n",
1043			       section, prog->type,
1044			       prog->size / sizeof(struct bpf_insn),
1045			       prog->license, fd < 0 ? "rejected :" :
1046			       "loaded", fd < 0 ? strerror(errno) : "",
1047			       fd < 0 ? errno : fd);
1048	}
1049
1050	return fd;
1051}
1052
1053static int bpf_map_attach(const char *name, const struct bpf_elf_map *map,
1054			  const struct bpf_elf_ctx *ctx, bool verbose)
1055{
1056	int fd, ret;
1057
1058	fd = bpf_probe_pinned(name, ctx, map->pinning);
1059	if (fd > 0) {
1060		ret = bpf_map_selfcheck_pinned(fd, map,
1061					       offsetof(struct bpf_elf_map,
1062							id));
1063		if (ret < 0) {
1064			close(fd);
1065			fprintf(stderr, "Map \'%s\' self-check failed!\n",
1066				name);
1067			return ret;
1068		}
1069		if (verbose)
1070			fprintf(stderr, "Map \'%s\' loaded as pinned!\n",
1071				name);
1072		return fd;
1073	}
1074
1075	errno = 0;
1076	fd = bpf_map_create(map->type, map->size_key, map->size_value,
1077			    map->max_elem);
1078	if (fd < 0 || verbose) {
1079		bpf_dump_error("Map \'%s\' (type:%u id:%u pinning:%u "
1080			       "ksize:%u vsize:%u max-elems:%u) %s%s (%d)!\n",
1081			       name, map->type, map->id, map->pinning,
1082			       map->size_key, map->size_value, map->max_elem,
1083			       fd < 0 ? "rejected: " : "loaded", fd < 0 ?
1084			       strerror(errno) : "", fd < 0 ? errno : fd);
1085		if (fd < 0)
1086			return fd;
1087	}
1088
1089	ret = bpf_place_pinned(fd, name, ctx, map->pinning);
1090	if (ret < 0 && errno != EEXIST) {
1091		fprintf(stderr, "Could not pin %s map: %s\n", name,
1092			strerror(errno));
1093		close(fd);
1094		return ret;
1095	}
1096
1097	return fd;
1098}
1099
1100#define __ELF_ST_BIND(x)	((x) >> 4)
1101#define __ELF_ST_TYPE(x)	(((unsigned int) x) & 0xf)
1102
1103static const char *bpf_str_tab_name(const struct bpf_elf_ctx *ctx,
1104				    const GElf_Sym *sym)
1105{
1106	return ctx->str_tab->d_buf + sym->st_name;
1107}
1108
1109static const char *bpf_map_fetch_name(struct bpf_elf_ctx *ctx, int which)
1110{
1111	GElf_Sym sym;
1112	int i;
1113
1114	for (i = 0; i < ctx->sym_num; i++) {
1115		if (gelf_getsym(ctx->sym_tab, i, &sym) != &sym)
1116			continue;
1117
1118		if (__ELF_ST_BIND(sym.st_info) != STB_GLOBAL ||
1119		    __ELF_ST_TYPE(sym.st_info) != STT_NOTYPE ||
1120		    sym.st_shndx != ctx->sec_maps ||
1121		    sym.st_value / sizeof(struct bpf_elf_map) != which)
1122			continue;
1123
1124		return bpf_str_tab_name(ctx, &sym);
1125	}
1126
1127	return NULL;
1128}
1129
1130static int bpf_maps_attach_all(struct bpf_elf_ctx *ctx)
1131{
1132	const char *map_name;
1133	int i, fd;
1134
1135	for (i = 0; i < ctx->map_num; i++) {
1136		map_name = bpf_map_fetch_name(ctx, i);
1137		if (!map_name)
1138			return -EIO;
1139
1140		fd = bpf_map_attach(map_name, &ctx->maps[i], ctx,
1141				    ctx->verbose);
1142		if (fd < 0)
1143			return fd;
1144
1145		ctx->map_fds[i] = fd;
1146	}
1147
1148	return 0;
1149}
1150
1151static int bpf_fill_section_data(struct bpf_elf_ctx *ctx, int section,
1152				 struct bpf_elf_sec_data *data)
1153{
1154	Elf_Data *sec_edata;
1155	GElf_Shdr sec_hdr;
1156	Elf_Scn *sec_fd;
1157	char *sec_name;
1158
1159	memset(data, 0, sizeof(*data));
1160
1161	sec_fd = elf_getscn(ctx->elf_fd, section);
1162	if (!sec_fd)
1163		return -EINVAL;
1164	if (gelf_getshdr(sec_fd, &sec_hdr) != &sec_hdr)
1165		return -EIO;
1166
1167	sec_name = elf_strptr(ctx->elf_fd, ctx->elf_hdr.e_shstrndx,
1168			      sec_hdr.sh_name);
1169	if (!sec_name || !sec_hdr.sh_size)
1170		return -ENOENT;
1171
1172	sec_edata = elf_getdata(sec_fd, NULL);
1173	if (!sec_edata || elf_getdata(sec_fd, sec_edata))
1174		return -EIO;
1175
1176	memcpy(&data->sec_hdr, &sec_hdr, sizeof(sec_hdr));
1177
1178	data->sec_name = sec_name;
1179	data->sec_data = sec_edata;
1180	return 0;
1181}
1182
1183static int bpf_fetch_maps(struct bpf_elf_ctx *ctx, int section,
1184			  struct bpf_elf_sec_data *data)
1185{
1186	if (data->sec_data->d_size % sizeof(struct bpf_elf_map) != 0)
1187		return -EINVAL;
1188
1189	ctx->map_num = data->sec_data->d_size / sizeof(struct bpf_elf_map);
1190	ctx->sec_maps = section;
1191	ctx->sec_done[section] = true;
1192
1193	if (ctx->map_num > ARRAY_SIZE(ctx->map_fds)) {
1194		fprintf(stderr, "Too many BPF maps in ELF section!\n");
1195		return -ENOMEM;
1196	}
1197
1198	memcpy(ctx->maps, data->sec_data->d_buf, data->sec_data->d_size);
1199	return 0;
1200}
1201
1202static int bpf_fetch_license(struct bpf_elf_ctx *ctx, int section,
1203			     struct bpf_elf_sec_data *data)
1204{
1205	if (data->sec_data->d_size > sizeof(ctx->license))
1206		return -ENOMEM;
1207
1208	memcpy(ctx->license, data->sec_data->d_buf, data->sec_data->d_size);
1209	ctx->sec_done[section] = true;
1210	return 0;
1211}
1212
1213static int bpf_fetch_symtab(struct bpf_elf_ctx *ctx, int section,
1214			    struct bpf_elf_sec_data *data)
1215{
1216	ctx->sym_tab = data->sec_data;
1217	ctx->sym_num = data->sec_hdr.sh_size / data->sec_hdr.sh_entsize;
1218	ctx->sec_done[section] = true;
1219	return 0;
1220}
1221
1222static int bpf_fetch_strtab(struct bpf_elf_ctx *ctx, int section,
1223			    struct bpf_elf_sec_data *data)
1224{
1225	ctx->str_tab = data->sec_data;
1226	ctx->sec_done[section] = true;
1227	return 0;
1228}
1229
1230static int bpf_fetch_ancillary(struct bpf_elf_ctx *ctx)
1231{
1232	struct bpf_elf_sec_data data;
1233	int i, ret = -1;
1234
1235	for (i = 1; i < ctx->elf_hdr.e_shnum; i++) {
1236		ret = bpf_fill_section_data(ctx, i, &data);
1237		if (ret < 0)
1238			continue;
1239
1240		if (!strcmp(data.sec_name, ELF_SECTION_MAPS))
1241			ret = bpf_fetch_maps(ctx, i, &data);
1242		else if (!strcmp(data.sec_name, ELF_SECTION_LICENSE))
1243			ret = bpf_fetch_license(ctx, i, &data);
1244		else if (data.sec_hdr.sh_type == SHT_SYMTAB)
1245			ret = bpf_fetch_symtab(ctx, i, &data);
1246		else if (data.sec_hdr.sh_type == SHT_STRTAB &&
1247			 i != ctx->elf_hdr.e_shstrndx)
1248			ret = bpf_fetch_strtab(ctx, i, &data);
1249		if (ret < 0) {
1250			fprintf(stderr, "Error parsing section %d! Perhaps"
1251				"check with readelf -a?\n", i);
1252			break;
1253		}
1254	}
1255
1256	if (ctx->sym_tab && ctx->str_tab && ctx->sec_maps) {
1257		ret = bpf_maps_attach_all(ctx);
1258		if (ret < 0) {
1259			fprintf(stderr, "Error loading maps into kernel!\n");
1260			return ret;
1261		}
1262	}
1263
1264	return ret;
1265}
1266
1267static int bpf_fetch_prog(struct bpf_elf_ctx *ctx, const char *section)
1268{
1269	struct bpf_elf_sec_data data;
1270	struct bpf_elf_prog prog;
1271	int ret, i, fd = -1;
1272
1273	for (i = 1; i < ctx->elf_hdr.e_shnum; i++) {
1274		if (ctx->sec_done[i])
1275			continue;
1276
1277		ret = bpf_fill_section_data(ctx, i, &data);
1278		if (ret < 0 || strcmp(data.sec_name, section))
1279			continue;
1280
1281		memset(&prog, 0, sizeof(prog));
1282		prog.type    = ctx->type;
1283		prog.insns   = data.sec_data->d_buf;
1284		prog.size    = data.sec_data->d_size;
1285		prog.license = ctx->license;
1286
1287		fd = bpf_prog_attach(section, &prog, ctx->verbose);
1288		if (fd < 0)
1289			continue;
1290
1291		ctx->sec_done[i] = true;
1292		break;
1293	}
1294
1295	return fd;
1296}
1297
1298static int bpf_apply_relo_data(struct bpf_elf_ctx *ctx,
1299			       struct bpf_elf_sec_data *data_relo,
1300			       struct bpf_elf_sec_data *data_insn)
1301{
1302	Elf_Data *idata = data_insn->sec_data;
1303	GElf_Shdr *rhdr = &data_relo->sec_hdr;
1304	int relo_ent, relo_num = rhdr->sh_size / rhdr->sh_entsize;
1305	struct bpf_insn *insns = idata->d_buf;
1306	unsigned int num_insns = idata->d_size / sizeof(*insns);
1307
1308	for (relo_ent = 0; relo_ent < relo_num; relo_ent++) {
1309		unsigned int ioff, rmap;
1310		GElf_Rel relo;
1311		GElf_Sym sym;
1312
1313		if (gelf_getrel(data_relo->sec_data, relo_ent, &relo) != &relo)
1314			return -EIO;
1315
1316		ioff = relo.r_offset / sizeof(struct bpf_insn);
1317		if (ioff >= num_insns ||
1318		    insns[ioff].code != (BPF_LD | BPF_IMM | BPF_DW))
1319			return -EINVAL;
1320
1321		if (gelf_getsym(ctx->sym_tab, GELF_R_SYM(relo.r_info), &sym) != &sym)
1322			return -EIO;
1323
1324		rmap = sym.st_value / sizeof(struct bpf_elf_map);
1325		if (rmap >= ARRAY_SIZE(ctx->map_fds))
1326			return -EINVAL;
1327		if (!ctx->map_fds[rmap])
1328			return -EINVAL;
1329
1330		if (ctx->verbose)
1331			fprintf(stderr, "Map \'%s\' (%d) injected into prog "
1332				"section \'%s\' at offset %u!\n",
1333				bpf_str_tab_name(ctx, &sym), ctx->map_fds[rmap],
1334				data_insn->sec_name, ioff);
1335
1336		insns[ioff].src_reg = BPF_PSEUDO_MAP_FD;
1337		insns[ioff].imm     = ctx->map_fds[rmap];
1338	}
1339
1340	return 0;
1341}
1342
1343static int bpf_fetch_prog_relo(struct bpf_elf_ctx *ctx, const char *section)
1344{
1345	struct bpf_elf_sec_data data_relo, data_insn;
1346	struct bpf_elf_prog prog;
1347	int ret, idx, i, fd = -1;
1348
1349	for (i = 1; i < ctx->elf_hdr.e_shnum; i++) {
1350		ret = bpf_fill_section_data(ctx, i, &data_relo);
1351		if (ret < 0 || data_relo.sec_hdr.sh_type != SHT_REL)
1352			continue;
1353
1354		idx = data_relo.sec_hdr.sh_info;
1355		ret = bpf_fill_section_data(ctx, idx, &data_insn);
1356		if (ret < 0 || strcmp(data_insn.sec_name, section))
1357			continue;
1358
1359		ret = bpf_apply_relo_data(ctx, &data_relo, &data_insn);
1360		if (ret < 0)
1361			continue;
1362
1363		memset(&prog, 0, sizeof(prog));
1364		prog.type    = ctx->type;
1365		prog.insns   = data_insn.sec_data->d_buf;
1366		prog.size    = data_insn.sec_data->d_size;
1367		prog.license = ctx->license;
1368
1369		fd = bpf_prog_attach(section, &prog, ctx->verbose);
1370		if (fd < 0)
1371			continue;
1372
1373		ctx->sec_done[i]   = true;
1374		ctx->sec_done[idx] = true;
1375		break;
1376	}
1377
1378	return fd;
1379}
1380
1381static int bpf_fetch_prog_sec(struct bpf_elf_ctx *ctx, const char *section)
1382{
1383	int ret = -1;
1384
1385	if (ctx->sym_tab)
1386		ret = bpf_fetch_prog_relo(ctx, section);
1387	if (ret < 0)
1388		ret = bpf_fetch_prog(ctx, section);
1389
1390	return ret;
1391}
1392
1393static int bpf_find_map_by_id(struct bpf_elf_ctx *ctx, uint32_t id)
1394{
1395	int i;
1396
1397	for (i = 0; i < ARRAY_SIZE(ctx->map_fds); i++)
1398		if (ctx->map_fds[i] && ctx->maps[i].id == id &&
1399		    ctx->maps[i].type == BPF_MAP_TYPE_PROG_ARRAY)
1400			return i;
1401	return -1;
1402}
1403
1404static int bpf_fill_prog_arrays(struct bpf_elf_ctx *ctx)
1405{
1406	struct bpf_elf_sec_data data;
1407	uint32_t map_id, key_id;
1408	int fd, i, ret, idx;
1409
1410	for (i = 1; i < ctx->elf_hdr.e_shnum; i++) {
1411		if (ctx->sec_done[i])
1412			continue;
1413
1414		ret = bpf_fill_section_data(ctx, i, &data);
1415		if (ret < 0)
1416			continue;
1417
1418		ret = sscanf(data.sec_name, "%i/%i", &map_id, &key_id);
1419		if (ret != 2)
1420			continue;
1421
1422		idx = bpf_find_map_by_id(ctx, map_id);
1423		if (idx < 0)
1424			continue;
1425
1426		fd = bpf_fetch_prog_sec(ctx, data.sec_name);
1427		if (fd < 0)
1428			return -EIO;
1429
1430		ret = bpf_map_update(ctx->map_fds[idx], &key_id,
1431				     &fd, BPF_ANY);
1432		if (ret < 0)
1433			return -ENOENT;
1434
1435		ctx->sec_done[i] = true;
1436	}
1437
1438	return 0;
1439}
1440
1441static void bpf_save_finfo(struct bpf_elf_ctx *ctx)
1442{
1443	struct stat st;
1444	int ret;
1445
1446	memset(&ctx->stat, 0, sizeof(ctx->stat));
1447
1448	ret = fstat(ctx->obj_fd, &st);
1449	if (ret < 0) {
1450		fprintf(stderr, "Stat of elf file failed: %s\n",
1451			strerror(errno));
1452		return;
1453	}
1454
1455	ctx->stat.st_dev = st.st_dev;
1456	ctx->stat.st_ino = st.st_ino;
1457}
1458
1459static int bpf_read_pin_mapping(FILE *fp, uint32_t *id, char *path)
1460{
1461	char buff[PATH_MAX];
1462
1463	while (fgets(buff, sizeof(buff), fp)) {
1464		char *ptr = buff;
1465
1466		while (*ptr == ' ' || *ptr == '\t')
1467			ptr++;
1468
1469		if (*ptr == '#' || *ptr == '\n' || *ptr == 0)
1470			continue;
1471
1472		if (sscanf(ptr, "%i %s\n", id, path) != 2 &&
1473		    sscanf(ptr, "%i %s #", id, path) != 2) {
1474			strcpy(path, ptr);
1475			return -1;
1476		}
1477
1478		return 1;
1479	}
1480
1481	return 0;
1482}
1483
1484static bool bpf_pinning_reserved(uint32_t pinning)
1485{
1486	switch (pinning) {
1487	case PIN_NONE:
1488	case PIN_OBJECT_NS:
1489	case PIN_GLOBAL_NS:
1490		return true;
1491	default:
1492		return false;
1493	}
1494}
1495
1496static void bpf_hash_init(struct bpf_elf_ctx *ctx, const char *db_file)
1497{
1498	struct bpf_hash_entry *entry;
1499	char subpath[PATH_MAX];
1500	uint32_t pinning;
1501	FILE *fp;
1502	int ret;
1503
1504	fp = fopen(db_file, "r");
1505	if (!fp)
1506		return;
1507
1508	memset(subpath, 0, sizeof(subpath));
1509	while ((ret = bpf_read_pin_mapping(fp, &pinning, subpath))) {
1510		if (ret == -1) {
1511			fprintf(stderr, "Database %s is corrupted at: %s\n",
1512				db_file, subpath);
1513			fclose(fp);
1514			return;
1515		}
1516
1517		if (bpf_pinning_reserved(pinning)) {
1518			fprintf(stderr, "Database %s, id %u is reserved - "
1519				"ignoring!\n", db_file, pinning);
1520			continue;
1521		}
1522
1523		entry = malloc(sizeof(*entry));
1524		if (!entry) {
1525			fprintf(stderr, "No memory left for db entry!\n");
1526			continue;
1527		}
1528
1529		entry->pinning = pinning;
1530		entry->subpath = strdup(subpath);
1531		if (!entry->subpath) {
1532			fprintf(stderr, "No memory left for db entry!\n");
1533			free(entry);
1534			continue;
1535		}
1536
1537		entry->next = ctx->ht[pinning & (ARRAY_SIZE(ctx->ht) - 1)];
1538		ctx->ht[pinning & (ARRAY_SIZE(ctx->ht) - 1)] = entry;
1539	}
1540
1541	fclose(fp);
1542}
1543
1544static void bpf_hash_destroy(struct bpf_elf_ctx *ctx)
1545{
1546	struct bpf_hash_entry *entry;
1547	int i;
1548
1549	for (i = 0; i < ARRAY_SIZE(ctx->ht); i++) {
1550		while ((entry = ctx->ht[i]) != NULL) {
1551			ctx->ht[i] = entry->next;
1552			free((char *)entry->subpath);
1553			free(entry);
1554		}
1555	}
1556}
1557
1558static int bpf_elf_ctx_init(struct bpf_elf_ctx *ctx, const char *pathname,
1559			    enum bpf_prog_type type, bool verbose)
1560{
1561	int ret = -EINVAL;
1562
1563	if (elf_version(EV_CURRENT) == EV_NONE ||
1564	    bpf_init_env(pathname))
1565		return ret;
1566
1567	memset(ctx, 0, sizeof(*ctx));
1568	ctx->verbose = verbose;
1569	ctx->type    = type;
1570
1571	ctx->obj_fd = open(pathname, O_RDONLY);
1572	if (ctx->obj_fd < 0)
1573		return ctx->obj_fd;
1574
1575	ctx->elf_fd = elf_begin(ctx->obj_fd, ELF_C_READ, NULL);
1576	if (!ctx->elf_fd) {
1577		ret = -EINVAL;
1578		goto out_fd;
1579	}
1580
1581	if (gelf_getehdr(ctx->elf_fd, &ctx->elf_hdr) !=
1582	    &ctx->elf_hdr) {
1583		ret = -EIO;
1584		goto out_elf;
1585	}
1586
1587	ctx->sec_done = calloc(ctx->elf_hdr.e_shnum,
1588			       sizeof(*(ctx->sec_done)));
1589	if (!ctx->sec_done) {
1590		ret = -ENOMEM;
1591		goto out_elf;
1592	}
1593
1594	bpf_save_finfo(ctx);
1595	bpf_hash_init(ctx, CONFDIR "/bpf_pinning");
1596
1597	return 0;
1598out_elf:
1599	elf_end(ctx->elf_fd);
1600out_fd:
1601	close(ctx->obj_fd);
1602	return ret;
1603}
1604
1605static int bpf_maps_count(struct bpf_elf_ctx *ctx)
1606{
1607	int i, count = 0;
1608
1609	for (i = 0; i < ARRAY_SIZE(ctx->map_fds); i++) {
1610		if (!ctx->map_fds[i])
1611			break;
1612		count++;
1613	}
1614
1615	return count;
1616}
1617
1618static void bpf_maps_teardown(struct bpf_elf_ctx *ctx)
1619{
1620	int i;
1621
1622	for (i = 0; i < ARRAY_SIZE(ctx->map_fds); i++) {
1623		if (ctx->map_fds[i])
1624			close(ctx->map_fds[i]);
1625	}
1626}
1627
1628static void bpf_elf_ctx_destroy(struct bpf_elf_ctx *ctx, bool failure)
1629{
1630	if (failure)
1631		bpf_maps_teardown(ctx);
1632
1633	bpf_hash_destroy(ctx);
1634	free(ctx->sec_done);
1635	elf_end(ctx->elf_fd);
1636	close(ctx->obj_fd);
1637}
1638
1639static struct bpf_elf_ctx __ctx;
1640
1641static int bpf_obj_open(const char *pathname, enum bpf_prog_type type,
1642			const char *section, bool verbose)
1643{
1644	struct bpf_elf_ctx *ctx = &__ctx;
1645	int fd = 0, ret;
1646
1647	ret = bpf_elf_ctx_init(ctx, pathname, type, verbose);
1648	if (ret < 0) {
1649		fprintf(stderr, "Cannot initialize ELF context!\n");
1650		return ret;
1651	}
1652
1653	ret = bpf_fetch_ancillary(ctx);
1654	if (ret < 0) {
1655		fprintf(stderr, "Error fetching ELF ancillary data!\n");
1656		goto out;
1657	}
1658
1659	fd = bpf_fetch_prog_sec(ctx, section);
1660	if (fd < 0) {
1661		fprintf(stderr, "Error fetching program/map!\n");
1662		ret = fd;
1663		goto out;
1664	}
1665
1666	ret = bpf_fill_prog_arrays(ctx);
1667	if (ret < 0)
1668		fprintf(stderr, "Error filling program arrays!\n");
1669out:
1670	bpf_elf_ctx_destroy(ctx, ret < 0);
1671	if (ret < 0) {
1672		if (fd)
1673			close(fd);
1674		return ret;
1675	}
1676
1677	return fd;
1678}
1679
1680static int
1681bpf_map_set_send(int fd, struct sockaddr_un *addr, unsigned int addr_len,
1682		 const struct bpf_map_data *aux, unsigned int entries)
1683{
1684	struct bpf_map_set_msg msg;
1685	int *cmsg_buf, min_fd;
1686	char *amsg_buf;
1687	int i;
1688
1689	memset(&msg, 0, sizeof(msg));
1690
1691	msg.aux.uds_ver = BPF_SCM_AUX_VER;
1692	msg.aux.num_ent = entries;
1693
1694	strncpy(msg.aux.obj_name, aux->obj, sizeof(msg.aux.obj_name));
1695	memcpy(&msg.aux.obj_st, aux->st, sizeof(msg.aux.obj_st));
1696
1697	cmsg_buf = bpf_map_set_init(&msg, addr, addr_len);
1698	amsg_buf = (char *)msg.aux.ent;
1699
1700	for (i = 0; i < entries; i += min_fd) {
1701		int ret;
1702
1703		min_fd = min(BPF_SCM_MAX_FDS * 1U, entries - i);
1704		bpf_map_set_init_single(&msg, min_fd);
1705
1706		memcpy(cmsg_buf, &aux->fds[i], sizeof(aux->fds[0]) * min_fd);
1707		memcpy(amsg_buf, &aux->ent[i], sizeof(aux->ent[0]) * min_fd);
1708
1709		ret = sendmsg(fd, &msg.hdr, 0);
1710		if (ret <= 0)
1711			return ret ? : -1;
1712	}
1713
1714	return 0;
1715}
1716
1717static int
1718bpf_map_set_recv(int fd, int *fds,  struct bpf_map_aux *aux,
1719		 unsigned int entries)
1720{
1721	struct bpf_map_set_msg msg;
1722	int *cmsg_buf, min_fd;
1723	char *amsg_buf, *mmsg_buf;
1724	unsigned int needed = 1;
1725	int i;
1726
1727	cmsg_buf = bpf_map_set_init(&msg, NULL, 0);
1728	amsg_buf = (char *)msg.aux.ent;
1729	mmsg_buf = (char *)&msg.aux;
1730
1731	for (i = 0; i < min(entries, needed); i += min_fd) {
1732		struct cmsghdr *cmsg;
1733		int ret;
1734
1735		min_fd = min(entries, entries - i);
1736		bpf_map_set_init_single(&msg, min_fd);
1737
1738		ret = recvmsg(fd, &msg.hdr, 0);
1739		if (ret <= 0)
1740			return ret ? : -1;
1741
1742		cmsg = CMSG_FIRSTHDR(&msg.hdr);
1743		if (!cmsg || cmsg->cmsg_type != SCM_RIGHTS)
1744			return -EINVAL;
1745		if (msg.hdr.msg_flags & MSG_CTRUNC)
1746			return -EIO;
1747		if (msg.aux.uds_ver != BPF_SCM_AUX_VER)
1748			return -ENOSYS;
1749
1750		min_fd = (cmsg->cmsg_len - sizeof(*cmsg)) / sizeof(fd);
1751		if (min_fd > entries || min_fd <= 0)
1752			return -EINVAL;
1753
1754		memcpy(&fds[i], cmsg_buf, sizeof(fds[0]) * min_fd);
1755		memcpy(&aux->ent[i], amsg_buf, sizeof(aux->ent[0]) * min_fd);
1756		memcpy(aux, mmsg_buf, offsetof(struct bpf_map_aux, ent));
1757
1758		needed = aux->num_ent;
1759	}
1760
1761	return 0;
1762}
1763
1764int bpf_send_map_fds(const char *path, const char *obj)
1765{
1766	struct bpf_elf_ctx *ctx = &__ctx;
1767	struct sockaddr_un addr;
1768	struct bpf_map_data bpf_aux;
1769	int fd, ret;
1770
1771	fd = socket(AF_UNIX, SOCK_DGRAM, 0);
1772	if (fd < 0) {
1773		fprintf(stderr, "Cannot open socket: %s\n",
1774			strerror(errno));
1775		return -1;
1776	}
1777
1778	memset(&addr, 0, sizeof(addr));
1779	addr.sun_family = AF_UNIX;
1780	strncpy(addr.sun_path, path, sizeof(addr.sun_path));
1781
1782	ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
1783	if (ret < 0) {
1784		fprintf(stderr, "Cannot connect to %s: %s\n",
1785			path, strerror(errno));
1786		return -1;
1787	}
1788
1789	memset(&bpf_aux, 0, sizeof(bpf_aux));
1790
1791	bpf_aux.fds = ctx->map_fds;
1792	bpf_aux.ent = ctx->maps;
1793	bpf_aux.st  = &ctx->stat;
1794	bpf_aux.obj = obj;
1795
1796	ret = bpf_map_set_send(fd, &addr, sizeof(addr), &bpf_aux,
1797			       bpf_maps_count(ctx));
1798	if (ret < 0)
1799		fprintf(stderr, "Cannot send fds to %s: %s\n",
1800			path, strerror(errno));
1801
1802	bpf_maps_teardown(ctx);
1803	close(fd);
1804	return ret;
1805}
1806
1807int bpf_recv_map_fds(const char *path, int *fds, struct bpf_map_aux *aux,
1808		     unsigned int entries)
1809{
1810	struct sockaddr_un addr;
1811	int fd, ret;
1812
1813	fd = socket(AF_UNIX, SOCK_DGRAM, 0);
1814	if (fd < 0) {
1815		fprintf(stderr, "Cannot open socket: %s\n",
1816			strerror(errno));
1817		return -1;
1818	}
1819
1820	memset(&addr, 0, sizeof(addr));
1821	addr.sun_family = AF_UNIX;
1822	strncpy(addr.sun_path, path, sizeof(addr.sun_path));
1823
1824	ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
1825	if (ret < 0) {
1826		fprintf(stderr, "Cannot bind to socket: %s\n",
1827			strerror(errno));
1828		return -1;
1829	}
1830
1831	ret = bpf_map_set_recv(fd, fds, aux, entries);
1832	if (ret < 0)
1833		fprintf(stderr, "Cannot recv fds from %s: %s\n",
1834			path, strerror(errno));
1835
1836	unlink(addr.sun_path);
1837	close(fd);
1838	return ret;
1839}
1840#endif /* HAVE_ELF */
1841