Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932870AbbHHIVj (ORCPT ); Sat, 8 Aug 2015 04:21:39 -0400 Received: from terminus.zytor.com ([198.137.202.10]:53645 "EHLO terminus.zytor.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932463AbbHHIK6 (ORCPT ); Sat, 8 Aug 2015 04:10:58 -0400 Date: Sat, 8 Aug 2015 01:10:15 -0700 From: tip-bot for Wang Nan Message-ID: Cc: hekuang@huawei.com, brendan.d.gregg@gmail.com, namhyung@kernel.org, ast@plumgrid.com, hpa@zytor.com, xiakaixu@huawei.com, daniel@iogearbox.net, linux-kernel@vger.kernel.org, wangnan0@huawei.com, lizefan@huawei.com, tglx@linutronix.de, dsahern@gmail.com, mingo@kernel.org, a.p.zijlstra@chello.nl, masami.hiramatsu.pt@hitachi.com, acme@redhat.com, jolsa@kernel.org Reply-To: jolsa@kernel.org, acme@redhat.com, a.p.zijlstra@chello.nl, masami.hiramatsu.pt@hitachi.com, tglx@linutronix.de, mingo@kernel.org, dsahern@gmail.com, wangnan0@huawei.com, lizefan@huawei.com, linux-kernel@vger.kernel.org, daniel@iogearbox.net, ast@plumgrid.com, hpa@zytor.com, xiakaixu@huawei.com, hekuang@huawei.com, brendan.d.gregg@gmail.com, namhyung@kernel.org In-Reply-To: <1435716878-189507-6-git-send-email-wangnan0@huawei.com> References: <1435716878-189507-6-git-send-email-wangnan0@huawei.com> To: linux-tip-commits@vger.kernel.org Subject: [tip:perf/core] bpf tools: Open eBPF object file and do basic validation Git-Commit-ID: 1a5e3fb1e9a4a3e3695cd57c33c169a90d16fd3b X-Mailer: tip-git-log-daemon Robot-ID: Robot-Unsubscribe: Contact to get blacklisted from these emails MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset=UTF-8 Content-Disposition: inline Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 6283 Lines: 248 Commit-ID: 1a5e3fb1e9a4a3e3695cd57c33c169a90d16fd3b Gitweb: http://git.kernel.org/tip/1a5e3fb1e9a4a3e3695cd57c33c169a90d16fd3b Author: Wang Nan AuthorDate: Wed, 1 Jul 2015 02:13:53 +0000 Committer: Arnaldo Carvalho de Melo CommitDate: Fri, 7 Aug 2015 10:16:56 -0300 bpf tools: Open eBPF object file and do basic validation This patch defines basic interface of libbpf. 'struct bpf_object' will be the handler of each object file. Its internal structure is hide to user. eBPF object files are compiled by LLVM as ELF format. In this patch, libelf is used to open those files, read EHDR and do basic validation according to e_type and e_machine. All elf related staffs are grouped together and reside in efile field of 'struct bpf_object'. bpf_object__elf_finish() is introduced to clear it. After all eBPF programs in an object file are loaded, related ELF information is useless. Close the object file and free those memory. The zfree() and zclose() functions are introduced to ensure setting NULL pointers and negative file descriptors after resources are released. Signed-off-by: Wang Nan Acked-by: Alexei Starovoitov Cc: Brendan Gregg Cc: Daniel Borkmann Cc: David Ahern Cc: He Kuang Cc: Jiri Olsa Cc: Kaixu Xia Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1435716878-189507-6-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/bpf/libbpf.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++++ tools/lib/bpf/libbpf.h | 8 +++ 2 files changed, 166 insertions(+) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 6f0c13a..9e44608 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -11,8 +11,12 @@ #include #include #include +#include +#include #include #include +#include +#include #include "libbpf.h" @@ -52,3 +56,157 @@ void libbpf_set_print(libbpf_print_fn_t warn, __pr_info = info; __pr_debug = debug; } + +/* Copied from tools/perf/util/util.h */ +#ifndef zfree +# define zfree(ptr) ({ free(*ptr); *ptr = NULL; }) +#endif + +#ifndef zclose +# define zclose(fd) ({ \ + int ___err = 0; \ + if ((fd) >= 0) \ + ___err = close((fd)); \ + fd = -1; \ + ___err; }) +#endif + +#ifdef HAVE_LIBELF_MMAP_SUPPORT +# define LIBBPF_ELF_C_READ_MMAP ELF_C_READ_MMAP +#else +# define LIBBPF_ELF_C_READ_MMAP ELF_C_READ +#endif + +struct bpf_object { + /* + * Information when doing elf related work. Only valid if fd + * is valid. + */ + struct { + int fd; + Elf *elf; + GElf_Ehdr ehdr; + } efile; + char path[]; +}; +#define obj_elf_valid(o) ((o)->efile.elf) + +static struct bpf_object *bpf_object__new(const char *path) +{ + struct bpf_object *obj; + + obj = calloc(1, sizeof(struct bpf_object) + strlen(path) + 1); + if (!obj) { + pr_warning("alloc memory failed for %s\n", path); + return NULL; + } + + strcpy(obj->path, path); + obj->efile.fd = -1; + return obj; +} + +static void bpf_object__elf_finish(struct bpf_object *obj) +{ + if (!obj_elf_valid(obj)) + return; + + if (obj->efile.elf) { + elf_end(obj->efile.elf); + obj->efile.elf = NULL; + } + zclose(obj->efile.fd); +} + +static int bpf_object__elf_init(struct bpf_object *obj) +{ + int err = 0; + GElf_Ehdr *ep; + + if (obj_elf_valid(obj)) { + pr_warning("elf init: internal error\n"); + return -EEXIST; + } + + obj->efile.fd = open(obj->path, O_RDONLY); + if (obj->efile.fd < 0) { + pr_warning("failed to open %s: %s\n", obj->path, + strerror(errno)); + return -errno; + } + + obj->efile.elf = elf_begin(obj->efile.fd, + LIBBPF_ELF_C_READ_MMAP, + NULL); + if (!obj->efile.elf) { + pr_warning("failed to open %s as ELF file\n", + obj->path); + err = -EINVAL; + goto errout; + } + + if (!gelf_getehdr(obj->efile.elf, &obj->efile.ehdr)) { + pr_warning("failed to get EHDR from %s\n", + obj->path); + err = -EINVAL; + goto errout; + } + ep = &obj->efile.ehdr; + + if ((ep->e_type != ET_REL) || (ep->e_machine != 0)) { + pr_warning("%s is not an eBPF object file\n", + obj->path); + err = -EINVAL; + goto errout; + } + + return 0; +errout: + bpf_object__elf_finish(obj); + return err; +} + +static struct bpf_object * +__bpf_object__open(const char *path) +{ + struct bpf_object *obj; + + if (elf_version(EV_CURRENT) == EV_NONE) { + pr_warning("failed to init libelf for %s\n", path); + return NULL; + } + + obj = bpf_object__new(path); + if (!obj) + return NULL; + + if (bpf_object__elf_init(obj)) + goto out; + + bpf_object__elf_finish(obj); + return obj; +out: + bpf_object__close(obj); + return NULL; +} + +struct bpf_object *bpf_object__open(const char *path) +{ + /* param validation */ + if (!path) + return NULL; + + pr_debug("loading %s\n", path); + + return __bpf_object__open(path); +} + +void bpf_object__close(struct bpf_object *obj) +{ + if (!obj) + return; + + bpf_object__elf_finish(obj); + + free(obj); +} diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 8d1eeba..ec3301c 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -8,6 +8,8 @@ #ifndef __BPF_LIBBPF_H #define __BPF_LIBBPF_H +#include + /* * In include/linux/compiler-gcc.h, __printf is defined. However * it should be better if libbpf.h doesn't depend on Linux header file. @@ -20,4 +22,10 @@ void libbpf_set_print(libbpf_print_fn_t warn, libbpf_print_fn_t info, libbpf_print_fn_t debug); +/* Hide internal to user */ +struct bpf_object; + +struct bpf_object *bpf_object__open(const char *path); +void bpf_object__close(struct bpf_object *object); + #endif -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/