e_bpf.c revision 4bd624467bc6f8f6e8b4c676f3dd8ae7593fbe70
1/* 2 * e_bpf.c BPF exec proxy 3 * 4 * This program is free software; you can distribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Authors: Daniel Borkmann <daniel@iogearbox.net> 10 */ 11 12#include <stdio.h> 13#include <unistd.h> 14 15#include "utils.h" 16 17#include "tc_util.h" 18#include "tc_bpf.h" 19 20#include "bpf_elf.h" 21#include "bpf_scm.h" 22 23#define BPF_DEFAULT_CMD "/bin/sh" 24 25static char *argv_default[] = { BPF_DEFAULT_CMD, NULL }; 26 27static void explain(void) 28{ 29 fprintf(stderr, "Usage: ... bpf [ import UDS_FILE ] [ run CMD ]\n\n"); 30 fprintf(stderr, "Where UDS_FILE provides the name of a unix domain socket file\n"); 31 fprintf(stderr, "to import eBPF maps and the optional CMD denotes the command\n"); 32 fprintf(stderr, "to be executed (default: \'%s\').\n", BPF_DEFAULT_CMD); 33} 34 35static int bpf_num_env_entries(void) 36{ 37 char **envp; 38 int num; 39 40 for (num = 0, envp = environ; *envp != NULL; envp++) 41 num++; 42 return num; 43} 44 45static int parse_bpf(struct exec_util *eu, int argc, char **argv) 46{ 47 char **argv_run = argv_default, **envp_run, *tmp; 48 int ret, i, env_old, env_num, env_map; 49 const char *bpf_uds_name = NULL; 50 int fds[BPF_SCM_MAX_FDS]; 51 struct bpf_map_aux aux; 52 53 if (argc == 0) 54 return 0; 55 56 while (argc > 0) { 57 if (matches(*argv, "run") == 0) { 58 NEXT_ARG(); 59 argv_run = argv; 60 break; 61 } else if (matches(*argv, "import") == 0 || 62 matches(*argv, "imp") == 0) { 63 NEXT_ARG(); 64 bpf_uds_name = *argv; 65 } else { 66 explain(); 67 return -1; 68 } 69 70 argc--; 71 argv++; 72 } 73 74 if (!bpf_uds_name) { 75 fprintf(stderr, "bpf: No import parameter provided!\n"); 76 explain(); 77 return -1; 78 } 79 80 if (argv_run != argv_default && argc == 0) { 81 fprintf(stderr, "bpf: No run command provided!\n"); 82 explain(); 83 return -1; 84 } 85 86 memset(fds, 0, sizeof(fds)); 87 memset(&aux, 0, sizeof(aux)); 88 89 ret = bpf_recv_map_fds(bpf_uds_name, fds, &aux, ARRAY_SIZE(fds)); 90 if (ret < 0) { 91 fprintf(stderr, "bpf: Could not receive fds!\n"); 92 return -1; 93 } 94 95 if (aux.num_ent == 0) { 96 envp_run = environ; 97 goto out; 98 } 99 100 env_old = bpf_num_env_entries(); 101 env_num = env_old + aux.num_ent + 2; 102 env_map = env_old + 1; 103 104 envp_run = malloc(sizeof(*envp_run) * env_num); 105 if (!envp_run) { 106 fprintf(stderr, "bpf: No memory left to allocate env!\n"); 107 goto err; 108 } 109 110 for (i = 0; i < env_old; i++) 111 envp_run[i] = environ[i]; 112 113 ret = asprintf(&tmp, "BPF_NUM_MAPS=%u", aux.num_ent); 114 if (ret < 0) 115 goto err_free; 116 117 envp_run[env_old] = tmp; 118 119 for (i = env_map; i < env_num - 1; i++) { 120 ret = asprintf(&tmp, "BPF_MAP%u=%u", 121 aux.ent[i - env_map].id, 122 fds[i - env_map]); 123 if (ret < 0) 124 goto err_free_env; 125 126 envp_run[i] = tmp; 127 } 128 129 envp_run[env_num - 1] = NULL; 130out: 131 return execvpe(argv_run[0], argv_run, envp_run); 132 133err_free_env: 134 for (--i; i >= env_old; i--) 135 free(envp_run[i]); 136err_free: 137 free(envp_run); 138err: 139 for (i = 0; i < aux.num_ent; i++) 140 close(fds[i]); 141 return -1; 142} 143 144struct exec_util bpf_exec_util = { 145 .id = "bpf", 146 .parse_eopt = parse_bpf, 147}; 148