Blame tc/e_bpf.c

Packit Service 3880ab
/*
Packit Service 3880ab
 * e_bpf.c	BPF exec proxy
Packit Service 3880ab
 *
Packit Service 3880ab
 *		This program is free software; you can distribute it and/or
Packit Service 3880ab
 *		modify it under the terms of the GNU General Public License
Packit Service 3880ab
 *		as published by the Free Software Foundation; either version
Packit Service 3880ab
 *		2 of the License, or (at your option) any later version.
Packit Service 3880ab
 *
Packit Service 3880ab
 * Authors:	Daniel Borkmann <daniel@iogearbox.net>
Packit Service 3880ab
 */
Packit Service 3880ab
Packit Service 3880ab
#include <stdio.h>
Packit Service 3880ab
#include <unistd.h>
Packit Service 3880ab
Packit Service 3880ab
#include "utils.h"
Packit Service 3880ab
Packit Service 3880ab
#include "tc_util.h"
Packit Service 3880ab
Packit Service 3880ab
#include "bpf_util.h"
Packit Service 3880ab
#include "bpf_elf.h"
Packit Service 3880ab
#include "bpf_scm.h"
Packit Service 3880ab
Packit Service 3880ab
#define BPF_DEFAULT_CMD	"/bin/sh"
Packit Service 3880ab
Packit Service 3880ab
static char *argv_default[] = { BPF_DEFAULT_CMD, NULL };
Packit Service 3880ab
Packit Service 3880ab
static void explain(void)
Packit Service 3880ab
{
Packit Service 3880ab
	fprintf(stderr,
Packit Service 3880ab
		"Usage: ... bpf [ import UDS_FILE ] [ run CMD ]\n"
Packit Service 3880ab
		"       ... bpf [ debug ]\n"
Packit Service 3880ab
		"       ... bpf [ graft MAP_FILE ] [ key KEY ]\n"
Packit Service 3880ab
		"          `... [ object-file OBJ_FILE ] [ type TYPE ] [ section NAME ] [ verbose ]\n"
Packit Service 3880ab
		"          `... [ object-pinned PROG_FILE ]\n"
Packit Service 3880ab
		"\n"
Packit Service 3880ab
		"Where UDS_FILE provides the name of a unix domain socket file\n"
Packit Service 3880ab
		"to import eBPF maps and the optional CMD denotes the command\n"
Packit Service 3880ab
		"to be executed (default: \'%s\').\n"
Packit Service 3880ab
		"Where MAP_FILE points to a pinned map, OBJ_FILE to an object file\n"
Packit Service 3880ab
		"and PROG_FILE to a pinned program. TYPE can be {cls, act}, where\n"
Packit Service 3880ab
		"\'cls\' is default. KEY is optional and can be inferred from the\n"
Packit Service 3880ab
		"section name, otherwise it needs to be provided.\n",
Packit Service 3880ab
		BPF_DEFAULT_CMD);
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int bpf_num_env_entries(void)
Packit Service 3880ab
{
Packit Service 3880ab
	char **envp;
Packit Service 3880ab
	int num;
Packit Service 3880ab
Packit Service 3880ab
	for (num = 0, envp = environ; *envp != NULL; envp++)
Packit Service 3880ab
		num++;
Packit Service 3880ab
	return num;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
static int parse_bpf(struct exec_util *eu, int argc, char **argv)
Packit Service 3880ab
{
Packit Service 3880ab
	char **argv_run = argv_default, **envp_run, *tmp;
Packit Service 3880ab
	int ret, i, env_old, env_num, env_map;
Packit Service 3880ab
	const char *bpf_uds_name = NULL;
Packit Service 3880ab
	int fds[BPF_SCM_MAX_FDS] = {};
Packit Service 3880ab
	struct bpf_map_aux aux = {};
Packit Service 3880ab
Packit Service 3880ab
	if (argc == 0)
Packit Service 3880ab
		return 0;
Packit Service 3880ab
Packit Service 3880ab
	while (argc > 0) {
Packit Service 3880ab
		if (matches(*argv, "run") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			argv_run = argv;
Packit Service 3880ab
			break;
Packit Service 3880ab
		} else if (matches(*argv, "import") == 0) {
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			bpf_uds_name = *argv;
Packit Service 3880ab
		} else if (matches(*argv, "debug") == 0 ||
Packit Service 3880ab
			   matches(*argv, "dbg") == 0) {
Packit Service 3880ab
			if (bpf_trace_pipe())
Packit Service 3880ab
				fprintf(stderr,
Packit Service 3880ab
					"No trace pipe, tracefs not mounted?\n");
Packit Service 3880ab
			return -1;
Packit Service 3880ab
		} else if (matches(*argv, "graft") == 0) {
Packit Service 3880ab
			const char *bpf_map_path;
Packit Service 3880ab
			bool has_key = false;
Packit Service 3880ab
			uint32_t key;
Packit Service 3880ab
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			bpf_map_path = *argv;
Packit Service 3880ab
			NEXT_ARG();
Packit Service 3880ab
			if (matches(*argv, "key") == 0) {
Packit Service 3880ab
				NEXT_ARG();
Packit Service 3880ab
				if (get_unsigned(&key, *argv, 0)) {
Packit Service 3880ab
					fprintf(stderr, "Illegal \"key\"\n");
Packit Service 3880ab
					return -1;
Packit Service 3880ab
				}
Packit Service 3880ab
				has_key = true;
Packit Service 3880ab
				NEXT_ARG();
Packit Service 3880ab
			}
Packit Service 3880ab
			return bpf_graft_map(bpf_map_path, has_key ?
Packit Service 3880ab
					     &key : NULL, argc, argv);
Packit Service 3880ab
		} else {
Packit Service 3880ab
			explain();
Packit Service 3880ab
			return -1;
Packit Service 3880ab
		}
Packit Service 3880ab
Packit Service 3880ab
		NEXT_ARG_FWD();
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	if (!bpf_uds_name) {
Packit Service 3880ab
		fprintf(stderr, "bpf: No import parameter provided!\n");
Packit Service 3880ab
		explain();
Packit Service 3880ab
		return -1;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	if (argv_run != argv_default && argc == 0) {
Packit Service 3880ab
		fprintf(stderr, "bpf: No run command provided!\n");
Packit Service 3880ab
		explain();
Packit Service 3880ab
		return -1;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	ret = bpf_recv_map_fds(bpf_uds_name, fds, &aux, ARRAY_SIZE(fds));
Packit Service 3880ab
	if (ret < 0) {
Packit Service 3880ab
		fprintf(stderr, "bpf: Could not receive fds!\n");
Packit Service 3880ab
		return -1;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	if (aux.num_ent == 0) {
Packit Service 3880ab
		envp_run = environ;
Packit Service 3880ab
		goto out;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	env_old = bpf_num_env_entries();
Packit Service 3880ab
	env_num = env_old + aux.num_ent + 2;
Packit Service 3880ab
	env_map = env_old + 1;
Packit Service 3880ab
Packit Service 3880ab
	envp_run = malloc(sizeof(*envp_run) * env_num);
Packit Service 3880ab
	if (!envp_run) {
Packit Service 3880ab
		fprintf(stderr, "bpf: No memory left to allocate env!\n");
Packit Service 3880ab
		goto err;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	for (i = 0; i < env_old; i++)
Packit Service 3880ab
		envp_run[i] = environ[i];
Packit Service 3880ab
Packit Service 3880ab
	ret = asprintf(&tmp, "BPF_NUM_MAPS=%u", aux.num_ent);
Packit Service 3880ab
	if (ret < 0)
Packit Service 3880ab
		goto err_free;
Packit Service 3880ab
Packit Service 3880ab
	envp_run[env_old] = tmp;
Packit Service 3880ab
Packit Service 3880ab
	for (i = env_map; i < env_num - 1; i++) {
Packit Service 3880ab
		ret = asprintf(&tmp, "BPF_MAP%u=%u",
Packit Service 3880ab
			       aux.ent[i - env_map].id,
Packit Service 3880ab
			       fds[i - env_map]);
Packit Service 3880ab
		if (ret < 0)
Packit Service 3880ab
			goto err_free_env;
Packit Service 3880ab
Packit Service 3880ab
		envp_run[i] = tmp;
Packit Service 3880ab
	}
Packit Service 3880ab
Packit Service 3880ab
	envp_run[env_num - 1] = NULL;
Packit Service 3880ab
out:
Packit Service 3880ab
	return execvpe(argv_run[0], argv_run, envp_run);
Packit Service 3880ab
Packit Service 3880ab
err_free_env:
Packit Service 3880ab
	for (--i; i >= env_old; i--)
Packit Service 3880ab
		free(envp_run[i]);
Packit Service 3880ab
err_free:
Packit Service 3880ab
	free(envp_run);
Packit Service 3880ab
err:
Packit Service 3880ab
	for (i = 0; i < aux.num_ent; i++)
Packit Service 3880ab
		close(fds[i]);
Packit Service 3880ab
	return -1;
Packit Service 3880ab
}
Packit Service 3880ab
Packit Service 3880ab
struct exec_util bpf_exec_util = {
Packit Service 3880ab
	.id		= "bpf",
Packit Service 3880ab
	.parse_eopt	= parse_bpf,
Packit Service 3880ab
};