Daniel Borkmann | 4bd6244 | 2015-04-16 21:20:06 +0200 | [diff] [blame] | 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" |
Daniel Borkmann | 4bd6244 | 2015-04-16 21:20:06 +0200 | [diff] [blame] | 18 | |
Daniel Borkmann | e422566 | 2016-11-10 01:20:59 +0100 | [diff] [blame] | 19 | #include "bpf_util.h" |
Daniel Borkmann | 4bd6244 | 2015-04-16 21:20:06 +0200 | [diff] [blame] | 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 | { |
Daniel Borkmann | 91d88ee | 2015-11-26 15:38:45 +0100 | [diff] [blame] | 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"); |
Daniel Borkmann | 4bd6244 | 2015-04-16 21:20:06 +0200 | [diff] [blame] | 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); |
Daniel Borkmann | 91d88ee | 2015-11-26 15:38:45 +0100 | [diff] [blame] | 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"); |
Daniel Borkmann | 4bd6244 | 2015-04-16 21:20:06 +0200 | [diff] [blame] | 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; |
Phil Sutter | d17b136 | 2016-07-18 16:48:42 +0200 | [diff] [blame] | 59 | int fds[BPF_SCM_MAX_FDS] = {}; |
| 60 | struct bpf_map_aux aux = {}; |
Daniel Borkmann | 4bd6244 | 2015-04-16 21:20:06 +0200 | [diff] [blame] | 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; |
Daniel Borkmann | 32e93fb | 2015-11-13 00:39:29 +0100 | [diff] [blame] | 70 | } else if (matches(*argv, "import") == 0) { |
Daniel Borkmann | 4bd6244 | 2015-04-16 21:20:06 +0200 | [diff] [blame] | 71 | NEXT_ARG(); |
| 72 | bpf_uds_name = *argv; |
Daniel Borkmann | 32e93fb | 2015-11-13 00:39:29 +0100 | [diff] [blame] | 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; |
Daniel Borkmann | 91d88ee | 2015-11-26 15:38:45 +0100 | [diff] [blame] | 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); |
Daniel Borkmann | 4bd6244 | 2015-04-16 21:20:06 +0200 | [diff] [blame] | 98 | } else { |
| 99 | explain(); |
| 100 | return -1; |
| 101 | } |
| 102 | |
Daniel Borkmann | 32e93fb | 2015-11-13 00:39:29 +0100 | [diff] [blame] | 103 | NEXT_ARG_FWD(); |
Daniel Borkmann | 4bd6244 | 2015-04-16 21:20:06 +0200 | [diff] [blame] | 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 | |
Daniel Borkmann | 4bd6244 | 2015-04-16 21:20:06 +0200 | [diff] [blame] | 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 = { |
Daniel Borkmann | 32e93fb | 2015-11-13 00:39:29 +0100 | [diff] [blame] | 174 | .id = "bpf", |
| 175 | .parse_eopt = parse_bpf, |
Daniel Borkmann | 4bd6244 | 2015-04-16 21:20:06 +0200 | [diff] [blame] | 176 | }; |