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 19 #include "bpf_util.h" 20 #include "bpf_elf.h" 21 #include "bpf_scm.h" 22 23 #define BPF_DEFAULT_CMD "/bin/sh" 24 25 static char *argv_default[] = { BPF_DEFAULT_CMD, NULL }; 26 explain(void)27 static void explain(void) 28 { 29 fprintf(stderr, "Usage: ... bpf [ import UDS_FILE ] [ run CMD ]\n"); 30 fprintf(stderr, " ... bpf [ debug ]\n"); 31 fprintf(stderr, " ... bpf [ graft MAP_FILE ] [ key KEY ]\n"); 32 fprintf(stderr, " `... [ object-file OBJ_FILE ] [ type TYPE ] [ section NAME ] [ verbose ]\n"); 33 fprintf(stderr, " `... [ object-pinned PROG_FILE ]\n"); 34 fprintf(stderr, "\n"); 35 fprintf(stderr, "Where UDS_FILE provides the name of a unix domain socket file\n"); 36 fprintf(stderr, "to import eBPF maps and the optional CMD denotes the command\n"); 37 fprintf(stderr, "to be executed (default: \'%s\').\n", BPF_DEFAULT_CMD); 38 fprintf(stderr, "Where MAP_FILE points to a pinned map, OBJ_FILE to an object file\n"); 39 fprintf(stderr, "and PROG_FILE to a pinned program. TYPE can be {cls, act}, where\n"); 40 fprintf(stderr, "\'cls\' is default. KEY is optional and can be inferred from the\n"); 41 fprintf(stderr, "section name, otherwise it needs to be provided.\n"); 42 } 43 bpf_num_env_entries(void)44 static int bpf_num_env_entries(void) 45 { 46 char **envp; 47 int num; 48 49 for (num = 0, envp = environ; *envp != NULL; envp++) 50 num++; 51 return num; 52 } 53 parse_bpf(struct exec_util * eu,int argc,char ** argv)54 static int parse_bpf(struct exec_util *eu, int argc, char **argv) 55 { 56 char **argv_run = argv_default, **envp_run, *tmp; 57 int ret, i, env_old, env_num, env_map; 58 const char *bpf_uds_name = NULL; 59 int fds[BPF_SCM_MAX_FDS] = {}; 60 struct bpf_map_aux aux = {}; 61 62 if (argc == 0) 63 return 0; 64 65 while (argc > 0) { 66 if (matches(*argv, "run") == 0) { 67 NEXT_ARG(); 68 argv_run = argv; 69 break; 70 } else if (matches(*argv, "import") == 0) { 71 NEXT_ARG(); 72 bpf_uds_name = *argv; 73 } else if (matches(*argv, "debug") == 0 || 74 matches(*argv, "dbg") == 0) { 75 if (bpf_trace_pipe()) 76 fprintf(stderr, 77 "No trace pipe, tracefs not mounted?\n"); 78 return -1; 79 } else if (matches(*argv, "graft") == 0) { 80 const char *bpf_map_path; 81 bool has_key = false; 82 uint32_t key; 83 84 NEXT_ARG(); 85 bpf_map_path = *argv; 86 NEXT_ARG(); 87 if (matches(*argv, "key") == 0) { 88 NEXT_ARG(); 89 if (get_unsigned(&key, *argv, 0)) { 90 fprintf(stderr, "Illegal \"key\"\n"); 91 return -1; 92 } 93 has_key = true; 94 NEXT_ARG(); 95 } 96 return bpf_graft_map(bpf_map_path, has_key ? 97 &key : NULL, argc, argv); 98 } else { 99 explain(); 100 return -1; 101 } 102 103 NEXT_ARG_FWD(); 104 } 105 106 if (!bpf_uds_name) { 107 fprintf(stderr, "bpf: No import parameter provided!\n"); 108 explain(); 109 return -1; 110 } 111 112 if (argv_run != argv_default && argc == 0) { 113 fprintf(stderr, "bpf: No run command provided!\n"); 114 explain(); 115 return -1; 116 } 117 118 ret = bpf_recv_map_fds(bpf_uds_name, fds, &aux, ARRAY_SIZE(fds)); 119 if (ret < 0) { 120 fprintf(stderr, "bpf: Could not receive fds!\n"); 121 return -1; 122 } 123 124 if (aux.num_ent == 0) { 125 envp_run = environ; 126 goto out; 127 } 128 129 env_old = bpf_num_env_entries(); 130 env_num = env_old + aux.num_ent + 2; 131 env_map = env_old + 1; 132 133 envp_run = malloc(sizeof(*envp_run) * env_num); 134 if (!envp_run) { 135 fprintf(stderr, "bpf: No memory left to allocate env!\n"); 136 goto err; 137 } 138 139 for (i = 0; i < env_old; i++) 140 envp_run[i] = environ[i]; 141 142 ret = asprintf(&tmp, "BPF_NUM_MAPS=%u", aux.num_ent); 143 if (ret < 0) 144 goto err_free; 145 146 envp_run[env_old] = tmp; 147 148 for (i = env_map; i < env_num - 1; i++) { 149 ret = asprintf(&tmp, "BPF_MAP%u=%u", 150 aux.ent[i - env_map].id, 151 fds[i - env_map]); 152 if (ret < 0) 153 goto err_free_env; 154 155 envp_run[i] = tmp; 156 } 157 158 envp_run[env_num - 1] = NULL; 159 out: 160 return execvpe(argv_run[0], argv_run, envp_run); 161 162 err_free_env: 163 for (--i; i >= env_old; i--) 164 free(envp_run[i]); 165 err_free: 166 free(envp_run); 167 err: 168 for (i = 0; i < aux.num_ent; i++) 169 close(fds[i]); 170 return -1; 171 } 172 173 struct exec_util bpf_exec_util = { 174 .id = "bpf", 175 .parse_eopt = parse_bpf, 176 }; 177