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, §ion, 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, §ion, 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