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
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 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