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 (at) 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 25 static char *argv_default[] = { BPF_DEFAULT_CMD, NULL }; 26 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 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 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 memset(fds, 0, sizeof(fds)); 119 memset(&aux, 0, sizeof(aux)); 120 121 ret = bpf_recv_map_fds(bpf_uds_name, fds, &aux, ARRAY_SIZE(fds)); 122 if (ret < 0) { 123 fprintf(stderr, "bpf: Could not receive fds!\n"); 124 return -1; 125 } 126 127 if (aux.num_ent == 0) { 128 envp_run = environ; 129 goto out; 130 } 131 132 env_old = bpf_num_env_entries(); 133 env_num = env_old + aux.num_ent + 2; 134 env_map = env_old + 1; 135 136 envp_run = malloc(sizeof(*envp_run) * env_num); 137 if (!envp_run) { 138 fprintf(stderr, "bpf: No memory left to allocate env!\n"); 139 goto err; 140 } 141 142 for (i = 0; i < env_old; i++) 143 envp_run[i] = environ[i]; 144 145 ret = asprintf(&tmp, "BPF_NUM_MAPS=%u", aux.num_ent); 146 if (ret < 0) 147 goto err_free; 148 149 envp_run[env_old] = tmp; 150 151 for (i = env_map; i < env_num - 1; i++) { 152 ret = asprintf(&tmp, "BPF_MAP%u=%u", 153 aux.ent[i - env_map].id, 154 fds[i - env_map]); 155 if (ret < 0) 156 goto err_free_env; 157 158 envp_run[i] = tmp; 159 } 160 161 envp_run[env_num - 1] = NULL; 162 out: 163 return execvpe(argv_run[0], argv_run, envp_run); 164 165 err_free_env: 166 for (--i; i >= env_old; i--) 167 free(envp_run[i]); 168 err_free: 169 free(envp_run); 170 err: 171 for (i = 0; i < aux.num_ent; i++) 172 close(fds[i]); 173 return -1; 174 } 175 176 struct exec_util bpf_exec_util = { 177 .id = "bpf", 178 .parse_eopt = parse_bpf, 179 }; 180