• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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