From patchwork Fri Jun 8 08:42:33 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Ananyev, Konstantin" X-Patchwork-Id: 40807 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 904251B1A2; Fri, 8 Jun 2018 10:42:53 +0200 (CEST) Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by dpdk.org (Postfix) with ESMTP id C1AD11B029 for ; Fri, 8 Jun 2018 10:42:49 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga007.jf.intel.com ([10.7.209.58]) by fmsmga101.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 08 Jun 2018 01:42:49 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.49,490,1520924400"; d="scan'208";a="47424171" Received: from sivswdev02.ir.intel.com (HELO localhost.localdomain) ([10.237.217.46]) by orsmga007.jf.intel.com with ESMTP; 08 Jun 2018 01:42:48 -0700 From: Konstantin Ananyev To: dev@dpdk.org Cc: Konstantin Ananyev Date: Fri, 8 Jun 2018 09:42:33 +0100 Message-Id: <1528447355-29411-2-git-send-email-konstantin.ananyev@intel.com> X-Mailer: git-send-email 1.7.0.7 In-Reply-To: <1528447355-29411-1-git-send-email-konstantin.ananyev@intel.com> References: <1528447355-29411-1-git-send-email-konstantin.ananyev@intel.com> To: dev@dpdk.org Subject: [dpdk-dev] [PATCH 1/3] bpf: add extra information for external symbol definitions X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Extend struct rte_bpf_xsym with new fields to provide information about: - for variables - type and size - for functions - number of arguments and type/size of each argument and return value Such information would allow validate code to perform more extensive checking on input BPF program and catch misbehaving BPF code. That change would cause ABI/API breakage for librte_bpf. Signed-off-by: Konstantin Ananyev --- app/test-pmd/bpf_cmd.c | 27 ++++++++++++++++++++++-- lib/librte_bpf/bpf_def.h | 5 +++++ lib/librte_bpf/bpf_exec.c | 2 +- lib/librte_bpf/bpf_impl.h | 14 +++++++++++++ lib/librte_bpf/bpf_jit_x86.c | 17 ++------------- lib/librte_bpf/bpf_load.c | 49 ++++++++++++++++++++++++++++++++++++++++++- lib/librte_bpf/bpf_load_elf.c | 4 ++-- lib/librte_bpf/rte_bpf.h | 21 +++++++++++++++---- test/test/test_bpf.c | 19 ++++++++++++++++- 9 files changed, 132 insertions(+), 26 deletions(-) diff --git a/app/test-pmd/bpf_cmd.c b/app/test-pmd/bpf_cmd.c index 584fad908..830bfc13a 100644 --- a/app/test-pmd/bpf_cmd.c +++ b/app/test-pmd/bpf_cmd.c @@ -19,12 +19,35 @@ static const struct rte_bpf_xsym bpf_xsym[] = { { .name = RTE_STR(stdout), .type = RTE_BPF_XTYPE_VAR, - .var = &stdout, + .var = { + .val = &stdout, + .desc = { + .type = RTE_BPF_ARG_PTR, + .size = sizeof(stdout), + }, + }, }, { .name = RTE_STR(rte_pktmbuf_dump), .type = RTE_BPF_XTYPE_FUNC, - .func = (void *)rte_pktmbuf_dump, + .func = { + .val = (void *)rte_pktmbuf_dump, + .nb_args = 3, + .args = { + [0] = { + .type = RTE_BPF_ARG_RAW, + .size = sizeof(uintptr_t), + }, + [1] = { + .type = RTE_BPF_ARG_PTR_MBUF, + .size = sizeof(struct rte_mbuf), + }, + [2] = { + .type = RTE_BPF_ARG_RAW, + .size = sizeof(uint32_t), + }, + }, + }, }, }; diff --git a/lib/librte_bpf/bpf_def.h b/lib/librte_bpf/bpf_def.h index 6b69de345..c10f3aec4 100644 --- a/lib/librte_bpf/bpf_def.h +++ b/lib/librte_bpf/bpf_def.h @@ -131,6 +131,11 @@ struct ebpf_insn { int32_t imm; }; +/* + * eBPF allows functions with R1-R5 as arguments. + */ +#define EBPF_FUNC_MAX_ARGS (EBPF_REG_6 - EBPF_REG_1) + #ifdef __cplusplus } #endif diff --git a/lib/librte_bpf/bpf_exec.c b/lib/librte_bpf/bpf_exec.c index e373b1f3d..6a79139c0 100644 --- a/lib/librte_bpf/bpf_exec.c +++ b/lib/librte_bpf/bpf_exec.c @@ -402,7 +402,7 @@ bpf_exec(const struct rte_bpf *bpf, uint64_t reg[EBPF_REG_NUM]) break; /* call instructions */ case (BPF_JMP | EBPF_CALL): - reg[EBPF_REG_0] = bpf->prm.xsym[ins->imm].func( + reg[EBPF_REG_0] = bpf->prm.xsym[ins->imm].func.val( reg[EBPF_REG_1], reg[EBPF_REG_2], reg[EBPF_REG_3], reg[EBPF_REG_4], reg[EBPF_REG_5]); diff --git a/lib/librte_bpf/bpf_impl.h b/lib/librte_bpf/bpf_impl.h index 5d7e65c31..b577e2cbe 100644 --- a/lib/librte_bpf/bpf_impl.h +++ b/lib/librte_bpf/bpf_impl.h @@ -34,6 +34,20 @@ extern int rte_bpf_logtype; #define RTE_BPF_LOG(lvl, fmt, args...) \ rte_log(RTE_LOG_## lvl, rte_bpf_logtype, fmt, ##args) +static inline size_t +bpf_size(uint32_t bpf_op_sz) +{ + if (bpf_op_sz == BPF_B) + return sizeof(uint8_t); + else if (bpf_op_sz == BPF_H) + return sizeof(uint16_t); + else if (bpf_op_sz == BPF_W) + return sizeof(uint32_t); + else if (bpf_op_sz == EBPF_DW) + return sizeof(uint64_t); + return 0; +} + #ifdef __cplusplus } #endif diff --git a/lib/librte_bpf/bpf_jit_x86.c b/lib/librte_bpf/bpf_jit_x86.c index 111e028d2..68ea389f2 100644 --- a/lib/librte_bpf/bpf_jit_x86.c +++ b/lib/librte_bpf/bpf_jit_x86.c @@ -113,20 +113,6 @@ union bpf_jit_imm { uint8_t u8[4]; }; -static size_t -bpf_size(uint32_t bpf_op_sz) -{ - if (bpf_op_sz == BPF_B) - return sizeof(uint8_t); - else if (bpf_op_sz == BPF_H) - return sizeof(uint16_t); - else if (bpf_op_sz == BPF_W) - return sizeof(uint32_t); - else if (bpf_op_sz == EBPF_DW) - return sizeof(uint64_t); - return 0; -} - /* * In many cases for imm8 we can produce shorter code. */ @@ -1294,7 +1280,8 @@ emit(struct bpf_jit_state *st, const struct rte_bpf *bpf) break; /* call instructions */ case (BPF_JMP | EBPF_CALL): - emit_call(st, (uintptr_t)bpf->prm.xsym[ins->imm].func); + emit_call(st, + (uintptr_t)bpf->prm.xsym[ins->imm].func.val); break; /* return instruction */ case (BPF_JMP | EBPF_EXIT): diff --git a/lib/librte_bpf/bpf_load.c b/lib/librte_bpf/bpf_load.c index d1c9abd7f..2b84fe724 100644 --- a/lib/librte_bpf/bpf_load.c +++ b/lib/librte_bpf/bpf_load.c @@ -51,17 +51,64 @@ bpf_load(const struct rte_bpf_prm *prm) return bpf; } +/* + * Check that user provided external symbol. + */ +static int +bpf_check_xsym(const struct rte_bpf_xsym *xsym) +{ + uint32_t i; + + if (xsym->name == NULL) + return -EINVAL; + + if (xsym->type == RTE_BPF_XTYPE_VAR) { + if (xsym->var.desc.type == RTE_BPF_ARG_UNDEF) + return -EINVAL; + } else if (xsym->type == RTE_BPF_XTYPE_FUNC) { + + if (xsym->func.nb_args > EBPF_FUNC_MAX_ARGS) + return -EINVAL; + + /* check function arguments */ + for (i = 0; i != xsym->func.nb_args; i++) { + if (xsym->func.args[i].type == RTE_BPF_ARG_UNDEF) + return -EINVAL; + } + + /* check return value info */ + if (xsym->func.ret.type != RTE_BPF_ARG_UNDEF && + xsym->func.ret.size == 0) + return -EINVAL; + } else + return -EINVAL; + + return 0; +} + __rte_experimental struct rte_bpf * rte_bpf_load(const struct rte_bpf_prm *prm) { struct rte_bpf *bpf; int32_t rc; + uint32_t i; - if (prm == NULL || prm->ins == NULL) { + if (prm == NULL || prm->ins == NULL || + (prm->nb_xsym != 0 && prm->xsym == NULL)) { rte_errno = EINVAL; return NULL; } + rc = 0; + for (i = 0; i != prm->nb_xsym && rc == 0; i++) + rc = bpf_check_xsym(prm->xsym + i); + + if (rc != 0) { + rte_errno = -rc; + RTE_BPF_LOG(ERR, "%s: %d-th xsym is invalid\n", __func__, i); + return NULL; + } + bpf = bpf_load(prm); if (bpf == NULL) { rte_errno = ENOMEM; diff --git a/lib/librte_bpf/bpf_load_elf.c b/lib/librte_bpf/bpf_load_elf.c index 6ab03d86e..96d3630fe 100644 --- a/lib/librte_bpf/bpf_load_elf.c +++ b/lib/librte_bpf/bpf_load_elf.c @@ -81,9 +81,9 @@ resolve_xsym(const char *sn, size_t ofs, struct ebpf_insn *ins, size_t ins_sz, ins[idx].imm = fidx; /* for variable we need to store its absolute address */ else { - ins[idx].imm = (uintptr_t)prm->xsym[fidx].var; + ins[idx].imm = (uintptr_t)prm->xsym[fidx].var.val; ins[idx + 1].imm = - (uint64_t)(uintptr_t)prm->xsym[fidx].var >> 32; + (uint64_t)(uintptr_t)prm->xsym[fidx].var.val >> 32; } return 0; diff --git a/lib/librte_bpf/rte_bpf.h b/lib/librte_bpf/rte_bpf.h index 1249a992c..ad62ef2c6 100644 --- a/lib/librte_bpf/rte_bpf.h +++ b/lib/librte_bpf/rte_bpf.h @@ -40,7 +40,11 @@ enum rte_bpf_arg_type { */ struct rte_bpf_arg { enum rte_bpf_arg_type type; - size_t size; /**< for pointer types, size of data it points to */ + /** + * for ptr type - max size of data buffer it points to + * for raw type - the size (in bytes) of the value + */ + size_t size; size_t buf_size; /**< for mbuf ptr type, max size of rte_mbuf data buffer */ }; @@ -66,10 +70,19 @@ struct rte_bpf_xsym { const char *name; /**< name */ enum rte_bpf_xtype type; /**< type */ union { - uint64_t (*func)(uint64_t, uint64_t, uint64_t, + struct { + uint64_t (*val)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t); - void *var; - }; /**< value */ + uint32_t nb_args; + struct rte_bpf_arg args[EBPF_FUNC_MAX_ARGS]; + /**< Function arguments descriptions. */ + struct rte_bpf_arg ret; /**< function return value. */ + } func; + struct { + void *val; /**< actual memory location */ + struct rte_bpf_arg desc; /**< type, size, etc. */ + } var; /**< external variable */ + }; }; /** diff --git a/test/test/test_bpf.c b/test/test/test_bpf.c index cbd6be63d..1e9caef95 100644 --- a/test/test/test_bpf.c +++ b/test/test/test_bpf.c @@ -1530,7 +1530,24 @@ static const struct rte_bpf_xsym test_call1_xsym[] = { { .name = RTE_STR(dummy_func1), .type = RTE_BPF_XTYPE_FUNC, - .func = (void *)dummy_func1, + .func = { + .val = (void *)dummy_func1, + .nb_args = 3, + .args = { + [0] = { + .type = RTE_BPF_ARG_PTR, + .size = sizeof(struct dummy_offset), + }, + [1] = { + .type = RTE_BPF_ARG_PTR, + .size = sizeof(uint32_t), + }, + [2] = { + .type = RTE_BPF_ARG_PTR, + .size = sizeof(uint64_t), + }, + }, + }, }, };