From patchwork Thu Jul 14 19:14:44 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 12918446 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C1BF6CCA47B for ; Thu, 14 Jul 2022 19:21:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229458AbiGNTVi (ORCPT ); Thu, 14 Jul 2022 15:21:38 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56956 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232159AbiGNTVi (ORCPT ); Thu, 14 Jul 2022 15:21:38 -0400 X-Greylist: delayed 356 seconds by postgrey-1.37 at lindbergh.monkeyblade.net; Thu, 14 Jul 2022 12:21:37 PDT Received: from sinsgout.his.huawei.com (sinsgout.his.huawei.com [119.8.179.247]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 55FEB43332 for ; Thu, 14 Jul 2022 12:21:37 -0700 (PDT) Received: from sinmsgout01.his.huawei.com (unknown [172.28.115.139]) by sinsgout.his.huawei.com (SkyGuard) with ESMTP id 4LkPN16dzjz3h03s for ; Fri, 15 Jul 2022 03:15:45 +0800 (CST) Received: from fraeml714-chm.china.huawei.com (unknown [172.18.156.147]) by sinmsgout01.his.huawei.com (SkyGuard) with ESMTP id 4LkPGD2NQwz9xFB2; Fri, 15 Jul 2022 03:10:44 +0800 (CST) Received: from roberto-ThinkStation-P620.huawei.com (10.204.63.22) by fraeml714-chm.china.huawei.com (10.206.15.33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.24; Thu, 14 Jul 2022 21:15:32 +0200 From: Roberto Sassu To: , , , , , , , CC: , Benjamin Tissoires Subject: [RFC][PATCH v8 01/12] btf: Add a new kfunc set which allows to mark a function to be sleepable Date: Thu, 14 Jul 2022 21:14:44 +0200 Message-ID: <20220714191455.2101834-2-roberto.sassu@huawei.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220714191455.2101834-1-roberto.sassu@huawei.com> References: <20220714191455.2101834-1-roberto.sassu@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.204.63.22] X-ClientProxiedBy: lhreml754-chm.china.huawei.com (10.201.108.204) To fraeml714-chm.china.huawei.com (10.206.15.33) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net X-Patchwork-State: RFC From: Benjamin Tissoires This allows to declare a kfunc as sleepable and prevents its use in a non sleepable program. Acked-by: KP Singh Signed-off-by: Benjamin Tissoires Signed-off-by: KP Singh --- include/linux/btf.h | 2 ++ kernel/bpf/btf.c | 12 ++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/include/linux/btf.h b/include/linux/btf.h index 1bfed7fa0428..6e7517573d9e 100644 --- a/include/linux/btf.h +++ b/include/linux/btf.h @@ -18,6 +18,7 @@ enum btf_kfunc_type { BTF_KFUNC_TYPE_RELEASE, BTF_KFUNC_TYPE_RET_NULL, BTF_KFUNC_TYPE_KPTR_ACQUIRE, + BTF_KFUNC_TYPE_SLEEPABLE, BTF_KFUNC_TYPE_MAX, }; @@ -37,6 +38,7 @@ struct btf_kfunc_id_set { struct btf_id_set *release_set; struct btf_id_set *ret_null_set; struct btf_id_set *kptr_acquire_set; + struct btf_id_set *sleepable_set; }; struct btf_id_set *sets[BTF_KFUNC_TYPE_MAX]; }; diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 4423045b8ff3..2a28ead92841 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -6177,7 +6177,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, struct bpf_verifier_log *log = &env->log; u32 i, nargs, ref_id, ref_obj_id = 0; bool is_kfunc = btf_is_kernel(btf); - bool rel = false, kptr_get = false; + bool rel = false, kptr_get = false, sleepable = false; const char *func_name, *ref_tname; const struct btf_type *t, *ref_t; const struct btf_param *args; @@ -6208,9 +6208,10 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, } if (is_kfunc) { - /* Only kfunc can be release func */ rel = btf_kfunc_id_set_contains(btf, resolve_prog_type(env->prog), BTF_KFUNC_TYPE_RELEASE, func_id); + sleepable = btf_kfunc_id_set_contains(btf, resolve_prog_type(env->prog), + BTF_KFUNC_TYPE_SLEEPABLE, func_id); kptr_get = btf_kfunc_id_set_contains(btf, resolve_prog_type(env->prog), BTF_KFUNC_TYPE_KPTR_ACQUIRE, func_id); } @@ -6410,6 +6411,13 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, func_name); return -EINVAL; } + + if (sleepable && !env->prog->aux->sleepable) { + bpf_log(log, "kernel function %s is sleepable but the program is not\n", + func_name); + return -EINVAL; + } + /* returns argument register number > 0 in case of reference release kfunc */ return rel ? ref_regno : 0; } From patchwork Thu Jul 14 19:14:45 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 12918445 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B2EB0C43334 for ; Thu, 14 Jul 2022 19:21:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232429AbiGNTVi (ORCPT ); Thu, 14 Jul 2022 15:21:38 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56954 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229458AbiGNTVi (ORCPT ); Thu, 14 Jul 2022 15:21:38 -0400 Received: from sinsgout.his.huawei.com (sinsgout.his.huawei.com [119.8.179.247]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5A0AD43E45 for ; Thu, 14 Jul 2022 12:21:37 -0700 (PDT) Received: from sinmsgout01.his.huawei.com (unknown [172.28.115.139]) by sinsgout.his.huawei.com (SkyGuard) with ESMTP id 4LkPND06pwz3h057 for ; Fri, 15 Jul 2022 03:15:56 +0800 (CST) Received: from fraeml714-chm.china.huawei.com (unknown [172.18.156.147]) by sinmsgout01.his.huawei.com (SkyGuard) with ESMTP id 4LkPGG1kS9z9xFBk; Fri, 15 Jul 2022 03:10:46 +0800 (CST) Received: from roberto-ThinkStation-P620.huawei.com (10.204.63.22) by fraeml714-chm.china.huawei.com (10.206.15.33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.24; Thu, 14 Jul 2022 21:15:33 +0200 From: Roberto Sassu To: , , , , , , , CC: Subject: [RFC][PATCH v8 02/12] bpf: Allow kfuncs to be used in LSM programs Date: Thu, 14 Jul 2022 21:14:45 +0200 Message-ID: <20220714191455.2101834-3-roberto.sassu@huawei.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220714191455.2101834-1-roberto.sassu@huawei.com> References: <20220714191455.2101834-1-roberto.sassu@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.204.63.22] X-ClientProxiedBy: lhreml754-chm.china.huawei.com (10.201.108.204) To fraeml714-chm.china.huawei.com (10.206.15.33) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net X-Patchwork-State: RFC From: KP Singh In preparation for the addition of bpf_getxattr kfunc. Signed-off-by: KP Singh --- kernel/bpf/btf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 2a28ead92841..e6fc01de7e50 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -7241,6 +7241,7 @@ static int bpf_prog_type_to_kfunc_hook(enum bpf_prog_type prog_type) case BPF_PROG_TYPE_STRUCT_OPS: return BTF_KFUNC_HOOK_STRUCT_OPS; case BPF_PROG_TYPE_TRACING: + case BPF_PROG_TYPE_LSM: return BTF_KFUNC_HOOK_TRACING; case BPF_PROG_TYPE_SYSCALL: return BTF_KFUNC_HOOK_SYSCALL; From patchwork Thu Jul 14 19:14:46 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 12918449 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id CBA1FCCA47B for ; Thu, 14 Jul 2022 19:21:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240097AbiGNTVt (ORCPT ); Thu, 14 Jul 2022 15:21:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57050 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240104AbiGNTVs (ORCPT ); Thu, 14 Jul 2022 15:21:48 -0400 Received: from sinsgout.his.huawei.com (sinsgout.his.huawei.com [119.8.179.247]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 87E7543E58 for ; Thu, 14 Jul 2022 12:21:47 -0700 (PDT) Received: from sinmsgout01.his.huawei.com (unknown [172.28.115.139]) by sinsgout.his.huawei.com (SkyGuard) with ESMTP id 4LkPN10yvxz5RkBr for ; Fri, 15 Jul 2022 03:15:45 +0800 (CST) Received: from fraeml714-chm.china.huawei.com (unknown [172.18.156.147]) by sinmsgout01.his.huawei.com (SkyGuard) with ESMTP id 4LkPGH6vn7z9xFC0; Fri, 15 Jul 2022 03:10:47 +0800 (CST) Received: from roberto-ThinkStation-P620.huawei.com (10.204.63.22) by fraeml714-chm.china.huawei.com (10.206.15.33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.24; Thu, 14 Jul 2022 21:15:34 +0200 From: Roberto Sassu To: , , , , , , , CC: , Roberto Sassu , Joanne Koong Subject: [RFC][PATCH v8 03/12] btf: Handle dynamic pointer parameter in kfuncs Date: Thu, 14 Jul 2022 21:14:46 +0200 Message-ID: <20220714191455.2101834-4-roberto.sassu@huawei.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220714191455.2101834-1-roberto.sassu@huawei.com> References: <20220714191455.2101834-1-roberto.sassu@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.204.63.22] X-ClientProxiedBy: lhreml754-chm.china.huawei.com (10.201.108.204) To fraeml714-chm.china.huawei.com (10.206.15.33) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net X-Patchwork-State: RFC Allow the bpf_dynptr_kern parameter to be specified in kfuncs. Also, ensure that the dynamic pointer is valid and initialized. Cc: Joanne Koong Signed-off-by: Roberto Sassu --- include/linux/bpf_verifier.h | 3 +++ kernel/bpf/btf.c | 16 ++++++++++++++++ kernel/bpf/verifier.c | 4 ++-- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 2e3bad8640dc..55876fbdbae2 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -560,6 +560,9 @@ int check_kfunc_mem_size_reg(struct bpf_verifier_env *env, struct bpf_reg_state u32 regno); int check_mem_reg(struct bpf_verifier_env *env, struct bpf_reg_state *reg, u32 regno, u32 mem_size); +bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env, + struct bpf_reg_state *reg, + enum bpf_arg_type arg_type); /* this lives here instead of in bpf.h because it needs to dereference tgt_prog */ static inline u64 bpf_trampoline_compute_key(const struct bpf_prog *tgt_prog, diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index e6fc01de7e50..9e94571d1626 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -6353,6 +6353,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, if (is_kfunc) { bool arg_mem_size = i + 1 < nargs && is_kfunc_arg_mem_size(btf, &args[i + 1], ®s[regno + 1]); + bool arg_dynptr = !strcmp(ref_tname, "bpf_dynptr_kern"); /* Permit pointer to mem, but only when argument * type is pointer to scalar, or struct composed @@ -6362,6 +6363,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, */ if (!btf_type_is_scalar(ref_t) && !__btf_type_is_scalar_struct(log, btf, ref_t, 0) && + !arg_dynptr && (arg_mem_size ? !btf_type_is_void(ref_t) : 1)) { bpf_log(log, "arg#%d pointer type %s %s must point to %sscalar, or struct with scalar\n", @@ -6369,6 +6371,20 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, return -EINVAL; } + /* Assume initialized dynptr. */ + if (arg_dynptr) { + if (!is_dynptr_reg_valid_init(env, reg, + ARG_PTR_TO_DYNPTR)) { + bpf_log(log, + "arg#%d pointer type %s %s must be initialized\n", + i, btf_type_str(ref_t), + ref_tname); + return -EINVAL; + } + + continue; + } + /* Check for mem, len pair */ if (arg_mem_size) { if (check_kfunc_mem_size_reg(env, ®s[regno + 1], regno + 1)) { diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 328cfab3af60..d71c43ee9374 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -773,8 +773,8 @@ static bool is_dynptr_reg_valid_uninit(struct bpf_verifier_env *env, struct bpf_ return true; } -static bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env, struct bpf_reg_state *reg, - enum bpf_arg_type arg_type) +bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env, struct bpf_reg_state *reg, + enum bpf_arg_type arg_type) { struct bpf_func_state *state = func(env, reg); int spi = get_spi(reg->off); From patchwork Thu Jul 14 19:14:47 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 12918447 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 846D3C433EF for ; Thu, 14 Jul 2022 19:21:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232159AbiGNTVj (ORCPT ); Thu, 14 Jul 2022 15:21:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56960 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240097AbiGNTVi (ORCPT ); Thu, 14 Jul 2022 15:21:38 -0400 Received: from sinsgout.his.huawei.com (sinsgout.his.huawei.com [119.8.179.247]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 59FC643E42 for ; Thu, 14 Jul 2022 12:21:37 -0700 (PDT) Received: from sinmsgout01.his.huawei.com (unknown [172.28.115.139]) by sinsgout.his.huawei.com (SkyGuard) with ESMTP id 4LkPNH3Cd2z3h0ql for ; Fri, 15 Jul 2022 03:15:59 +0800 (CST) Received: from fraeml714-chm.china.huawei.com (unknown [172.18.156.147]) by sinmsgout01.his.huawei.com (SkyGuard) with ESMTP id 4LkPGK4zYQz9ttCk; Fri, 15 Jul 2022 03:10:49 +0800 (CST) Received: from roberto-ThinkStation-P620.huawei.com (10.204.63.22) by fraeml714-chm.china.huawei.com (10.206.15.33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.24; Thu, 14 Jul 2022 21:15:35 +0200 From: Roberto Sassu To: , , , , , , , CC: , Roberto Sassu , Benjamin Tissoires , Kumar Kartikeya Dwivedi Subject: [RFC][PATCH v8 04/12] btf: Introduce __maybe_null suffix for kfunc parameter declaration Date: Thu, 14 Jul 2022 21:14:47 +0200 Message-ID: <20220714191455.2101834-5-roberto.sassu@huawei.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220714191455.2101834-1-roberto.sassu@huawei.com> References: <20220714191455.2101834-1-roberto.sassu@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.204.63.22] X-ClientProxiedBy: lhreml754-chm.china.huawei.com (10.201.108.204) To fraeml714-chm.china.huawei.com (10.206.15.33) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net X-Patchwork-State: RFC Since kfuncs don't have a prototype defined, the BTF code has to infer the information in a different way. For example, naming a parameter with the __sz suffix is currently the way to declare such parameter as a memory size. Another feature not available without a prototype was flagging an argument as PTR_MAYBE_NULL, meaning that the function is trusted to correctly handle a NULL pointer. Similarly to the __sz suffix, introduce the __maybe_null suffix to have an equivalent feature of setting the PTR_MAYBE_NULL flag. Cc: Benjamin Tissoires Cc: Kumar Kartikeya Dwivedi Signed-off-by: Roberto Sassu --- kernel/bpf/btf.c | 48 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 9e94571d1626..80e3098fcb48 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -6142,18 +6142,13 @@ static bool __btf_type_is_scalar_struct(struct bpf_verifier_log *log, return true; } -static bool is_kfunc_arg_mem_size(const struct btf *btf, - const struct btf_param *arg, - const struct bpf_reg_state *reg) +static bool btf_param_match_suffix(const struct btf *btf, + const struct btf_param *arg, + const char *suffix) { - int len, sfx_len = sizeof("__sz") - 1; - const struct btf_type *t; + int len, sfx_len = strlen(suffix); const char *param_name; - t = btf_type_skip_modifiers(btf, arg->type, NULL); - if (!btf_type_is_scalar(t) || reg->type != SCALAR_VALUE) - return false; - /* In the future, this can be ported to use BTF tagging */ param_name = btf_name_by_offset(btf, arg->name_off); if (str_is_empty(param_name)) @@ -6162,12 +6157,25 @@ static bool is_kfunc_arg_mem_size(const struct btf *btf, if (len < sfx_len) return false; param_name += len - sfx_len; - if (strncmp(param_name, "__sz", sfx_len)) + if (strncmp(param_name, suffix, sfx_len)) return false; return true; } +static bool is_kfunc_arg_mem_size(const struct btf *btf, + const struct btf_param *arg, + const struct bpf_reg_state *reg) +{ + const struct btf_type *t; + + t = btf_type_skip_modifiers(btf, arg->type, NULL); + if (!btf_type_is_scalar(t) || reg->type != SCALAR_VALUE) + return false; + + return btf_param_match_suffix(btf, arg, "__sz"); +} + static int btf_check_func_arg_match(struct bpf_verifier_env *env, const struct btf *btf, u32 func_id, struct bpf_reg_state *regs, @@ -6302,8 +6310,12 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, i, btf_type_str(t)); return -EINVAL; } - } else if (is_kfunc && (reg->type == PTR_TO_BTF_ID || - (reg2btf_ids[base_type(reg->type)] && !type_flag(reg->type)))) { + } else if (is_kfunc && ((reg->type == PTR_TO_BTF_ID || + (reg2btf_ids[base_type(reg->type)] && !type_flag(reg->type))) || + (btf_param_match_suffix(btf, &args[i], "__maybe_null") && + (reg->type == PTR_TO_BTF_ID_OR_NULL || + (reg2btf_ids[base_type(reg->type)] && + type_flag(reg->type) == PTR_MAYBE_NULL))))) { const struct btf_type *reg_ref_t; const struct btf *reg_btf; const char *reg_ref_tname; @@ -6316,7 +6328,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, return -EINVAL; } - if (reg->type == PTR_TO_BTF_ID) { + if (base_type(reg->type) == PTR_TO_BTF_ID) { reg_btf = reg->btf; reg_ref_id = reg->btf_id; /* Ensure only one argument is referenced PTR_TO_BTF_ID */ @@ -6354,6 +6366,10 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, if (is_kfunc) { bool arg_mem_size = i + 1 < nargs && is_kfunc_arg_mem_size(btf, &args[i + 1], ®s[regno + 1]); bool arg_dynptr = !strcmp(ref_tname, "bpf_dynptr_kern"); + bool arg_null_ok = btf_param_match_suffix(btf, &args[i], + "__maybe_null") && + reg->type == SCALAR_VALUE && + tnum_equals_const(reg->var_off, 0); /* Permit pointer to mem, but only when argument * type is pointer to scalar, or struct composed @@ -6363,7 +6379,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, */ if (!btf_type_is_scalar(ref_t) && !__btf_type_is_scalar_struct(log, btf, ref_t, 0) && - !arg_dynptr && + !arg_dynptr && !arg_null_ok && (arg_mem_size ? !btf_type_is_void(ref_t) : 1)) { bpf_log(log, "arg#%d pointer type %s %s must point to %sscalar, or struct with scalar\n", @@ -6371,6 +6387,10 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, return -EINVAL; } + /* kfunc accepts NULL pointer. */ + if (arg_null_ok) + continue; + /* Assume initialized dynptr. */ if (arg_dynptr) { if (!is_dynptr_reg_valid_init(env, reg, From patchwork Thu Jul 14 19:14:48 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 12918436 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BCE60C433EF for ; Thu, 14 Jul 2022 19:16:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238657AbiGNTQ4 (ORCPT ); Thu, 14 Jul 2022 15:16:56 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53552 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229504AbiGNTQy (ORCPT ); Thu, 14 Jul 2022 15:16:54 -0400 X-Greylist: delayed 74 seconds by postgrey-1.37 at lindbergh.monkeyblade.net; Thu, 14 Jul 2022 12:16:53 PDT Received: from sinmsgout03.his.huawei.com (sinmsgout03.his.huawei.com [119.8.177.38]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F1E5B2DA88 for ; Thu, 14 Jul 2022 12:16:53 -0700 (PDT) Received: from fraeml714-chm.china.huawei.com (unknown [172.18.156.149]) by sinmsgout03.his.huawei.com (SkyGuard) with ESMTP id 4LkPMz3v2mz9v79Y; Fri, 15 Jul 2022 03:15:43 +0800 (CST) Received: from roberto-ThinkStation-P620.huawei.com (10.204.63.22) by fraeml714-chm.china.huawei.com (10.206.15.33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.24; Thu, 14 Jul 2022 21:16:48 +0200 From: Roberto Sassu To: , , , , , , , CC: , Roberto Sassu , Joanne Koong Subject: [RFC][PATCH v8 05/12] bpf: Export bpf_dynptr_get_size() Date: Thu, 14 Jul 2022 21:14:48 +0200 Message-ID: <20220714191455.2101834-6-roberto.sassu@huawei.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220714191455.2101834-1-roberto.sassu@huawei.com> References: <20220714191455.2101834-1-roberto.sassu@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.204.63.22] X-ClientProxiedBy: lhreml754-chm.china.huawei.com (10.201.108.204) To fraeml714-chm.china.huawei.com (10.206.15.33) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net X-Patchwork-State: RFC Export bpf_dynptr_get_size(), so that kernel code dealing with eBPF dynamic pointers can obtain the real size of data carried by this data structure. Reviewed-by: Joanne Koong Signed-off-by: Roberto Sassu --- include/linux/bpf.h | 1 + kernel/bpf/helpers.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index a5bf00649995..788800e68793 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -2544,6 +2544,7 @@ void bpf_dynptr_init(struct bpf_dynptr_kern *ptr, void *data, enum bpf_dynptr_type type, u32 offset, u32 size); void bpf_dynptr_set_null(struct bpf_dynptr_kern *ptr); int bpf_dynptr_check_size(u32 size); +u32 bpf_dynptr_get_size(struct bpf_dynptr_kern *ptr); #ifdef CONFIG_BPF_LSM void bpf_cgroup_atype_get(u32 attach_btf_id, int cgroup_atype); diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index a1c84d256f83..3f5ff8dbd3cb 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -1430,7 +1430,7 @@ static void bpf_dynptr_set_type(struct bpf_dynptr_kern *ptr, enum bpf_dynptr_typ ptr->size |= type << DYNPTR_TYPE_SHIFT; } -static u32 bpf_dynptr_get_size(struct bpf_dynptr_kern *ptr) +u32 bpf_dynptr_get_size(struct bpf_dynptr_kern *ptr) { return ptr->size & DYNPTR_SIZE_MASK; } From patchwork Thu Jul 14 19:14:49 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 12918437 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 37495C43334 for ; Thu, 14 Jul 2022 19:16:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239145AbiGNTQ5 (ORCPT ); Thu, 14 Jul 2022 15:16:57 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53568 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229504AbiGNTQ4 (ORCPT ); Thu, 14 Jul 2022 15:16:56 -0400 Received: from sinmsgout03.his.huawei.com (sinmsgout03.his.huawei.com [119.8.177.38]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0E5632DA88 for ; Thu, 14 Jul 2022 12:16:56 -0700 (PDT) Received: from fraeml714-chm.china.huawei.com (unknown [172.18.156.149]) by sinmsgout03.his.huawei.com (SkyGuard) with ESMTP id 4LkPN121Rgz9xGNy; Fri, 15 Jul 2022 03:15:45 +0800 (CST) Received: from roberto-ThinkStation-P620.huawei.com (10.204.63.22) by fraeml714-chm.china.huawei.com (10.206.15.33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.24; Thu, 14 Jul 2022 21:16:48 +0200 From: Roberto Sassu To: , , , , , , , CC: , Roberto Sassu Subject: [RFC][PATCH v8 06/12] KEYS: Move KEY_LOOKUP_ to include/linux/key.h Date: Thu, 14 Jul 2022 21:14:49 +0200 Message-ID: <20220714191455.2101834-7-roberto.sassu@huawei.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220714191455.2101834-1-roberto.sassu@huawei.com> References: <20220714191455.2101834-1-roberto.sassu@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.204.63.22] X-ClientProxiedBy: lhreml754-chm.china.huawei.com (10.201.108.204) To fraeml714-chm.china.huawei.com (10.206.15.33) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-State: RFC In preparation for the patch that introduces the bpf_lookup_user_key() eBPF kfunc, move KEY_LOOKUP_ definitions to include/linux/key.h, to be able to validate the kfunc parameters. Signed-off-by: Roberto Sassu --- include/linux/key.h | 3 +++ security/keys/internal.h | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/linux/key.h b/include/linux/key.h index 7febc4881363..a297e075038c 100644 --- a/include/linux/key.h +++ b/include/linux/key.h @@ -88,6 +88,9 @@ enum key_need_perm { KEY_DEFER_PERM_CHECK, /* Special: permission check is deferred */ }; +#define KEY_LOOKUP_CREATE 0x01 +#define KEY_LOOKUP_PARTIAL 0x02 + struct seq_file; struct user_struct; struct signal_struct; diff --git a/security/keys/internal.h b/security/keys/internal.h index 9b9cf3b6fcbb..3c1e7122076b 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -165,8 +165,6 @@ extern struct key *request_key_and_link(struct key_type *type, extern bool lookup_user_key_possessed(const struct key *key, const struct key_match_data *match_data); -#define KEY_LOOKUP_CREATE 0x01 -#define KEY_LOOKUP_PARTIAL 0x02 extern long join_session_keyring(const char *name); extern void key_change_session_keyring(struct callback_head *twork); From patchwork Thu Jul 14 19:14:50 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 12918439 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BC4AAC43334 for ; Thu, 14 Jul 2022 19:17:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239423AbiGNTRB (ORCPT ); Thu, 14 Jul 2022 15:17:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53606 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230352AbiGNTRA (ORCPT ); Thu, 14 Jul 2022 15:17:00 -0400 Received: from sinmsgout03.his.huawei.com (sinmsgout03.his.huawei.com [119.8.177.38]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D790A3D5BC for ; Thu, 14 Jul 2022 12:16:59 -0700 (PDT) Received: from fraeml714-chm.china.huawei.com (unknown [172.18.156.149]) by sinmsgout03.his.huawei.com (SkyGuard) with ESMTP id 4LkPN30Kfjz9xGP0; Fri, 15 Jul 2022 03:15:46 +0800 (CST) Received: from roberto-ThinkStation-P620.huawei.com (10.204.63.22) by fraeml714-chm.china.huawei.com (10.206.15.33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.24; Thu, 14 Jul 2022 21:16:49 +0200 From: Roberto Sassu To: , , , , , , , CC: , Roberto Sassu Subject: [RFC][PATCH v8 07/12] bpf: Add bpf_lookup_user_key() and bpf_key_put() kfuncs Date: Thu, 14 Jul 2022 21:14:50 +0200 Message-ID: <20220714191455.2101834-8-roberto.sassu@huawei.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220714191455.2101834-1-roberto.sassu@huawei.com> References: <20220714191455.2101834-1-roberto.sassu@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.204.63.22] X-ClientProxiedBy: lhreml754-chm.china.huawei.com (10.201.108.204) To fraeml714-chm.china.huawei.com (10.206.15.33) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net X-Patchwork-State: RFC Add the bpf_lookup_user_key() and bpf_key_put() kfuncs, to respectively search a key with a given serial and flags, and release the reference count of the found key. Signed-off-by: Roberto Sassu --- kernel/trace/bpf_trace.c | 106 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 68e5cdd24cef..bffca9465574 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -20,6 +20,7 @@ #include #include #include +#include #include @@ -1181,6 +1182,111 @@ static const struct bpf_func_proto bpf_get_func_arg_cnt_proto = { .arg1_type = ARG_PTR_TO_CTX, }; +#ifdef CONFIG_KEYS +__diag_push(); +__diag_ignore_all("-Wmissing-prototypes", + "kfuncs which will be used in BPF programs"); + +/** + * bpf_lookup_user_key - lookup a key by its serial + * @serial: key serial + * @flags: lookup-specific flags + * + * Search a key with a given *serial* and the provided *flags*. The + * returned key, if found, has the reference count incremented by + * one, and must be passed to bpf_key_put() when done with it. + * Permission checks are deferred to the time the key is used by + * one of the available key-specific kfunc. + * + * Set *flags* with 1 to attempt creating a requested special + * keyring (e.g. session keyring), if it doesn't yet exist. Set + * *flags* to 2 to lookup a key without waiting for the key + * construction, and to retrieve uninstantiated keys (keys without + * data attached to them). + * + * Return: a key pointer if the key is found, a NULL pointer otherwise. + */ +noinline __weak struct key *bpf_lookup_user_key(u32 serial, u64 flags) +{ + key_ref_t key_ref; + + /* Keep in sync with include/linux/key.h. */ + if (flags > (KEY_LOOKUP_PARTIAL << 1) - 1) + return NULL; + + /* Permission check is deferred until actual kfunc using the key. */ + key_ref = lookup_user_key(serial, flags, KEY_DEFER_PERM_CHECK); + if (IS_ERR(key_ref)) + return NULL; + + return key_ref_to_ptr(key_ref); +} + +/** + * bpf_key_put - release a key reference + * @key: key whose reference is released + * + * Decrement the reference count of *key* obtained with the + * bpf_lookup_user_key() kfunc. + */ +noinline __weak void bpf_key_put(struct key *key) +{ + key_put(key); +} + +__diag_pop(); + +BTF_SET_START(key_kfunc_ids) +BTF_ID(func, bpf_lookup_user_key) +BTF_ID(func, bpf_key_put) +BTF_SET_END(key_kfunc_ids) + +BTF_SET_START(key_lookup_kfunc_ids) +BTF_ID(func, bpf_lookup_user_key) +BTF_SET_END(key_lookup_kfunc_ids) + +BTF_SET_START(key_put_kfunc_ids) +BTF_ID(func, bpf_key_put) +BTF_SET_END(key_put_kfunc_ids) + +static const struct btf_kfunc_id_set bpf_key_kfunc_set = { + .owner = THIS_MODULE, + .check_set = &key_kfunc_ids, + .sleepable_set = &key_lookup_kfunc_ids, + .acquire_set = &key_lookup_kfunc_ids, + .release_set = &key_put_kfunc_ids, + .ret_null_set = &key_lookup_kfunc_ids, +}; +#endif /* CONFIG_KEYS */ + + +const struct btf_kfunc_id_set *kfunc_sets[] = { +#ifdef CONFIG_KEYS + &bpf_key_kfunc_set, +#endif /* CONFIG_KEYS */ +}; + +static int __init bpf_kfuncs_init(void) +{ + int ret, i; + + for (i = 0; i < ARRAY_SIZE(kfunc_sets); i++) { + ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, + kfunc_sets[i]); + if (!ret) + continue; + + ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_LSM, + kfunc_sets[i]); + if (ret < 0) + return ret; + } + + return 0; +} + +late_initcall(bpf_kfuncs_init); + static const struct bpf_func_proto * bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) { From patchwork Thu Jul 14 19:14:51 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 12918438 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 25FEEC433EF for ; Thu, 14 Jul 2022 19:17:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239326AbiGNTRB (ORCPT ); Thu, 14 Jul 2022 15:17:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53608 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229504AbiGNTRA (ORCPT ); Thu, 14 Jul 2022 15:17:00 -0400 Received: from sinmsgout03.his.huawei.com (sinmsgout03.his.huawei.com [119.8.177.38]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 724EF2DA88 for ; Thu, 14 Jul 2022 12:16:59 -0700 (PDT) Received: from fraeml714-chm.china.huawei.com (unknown [172.18.156.149]) by sinmsgout03.his.huawei.com (SkyGuard) with ESMTP id 4LkPN45YDmz9v7BW; Fri, 15 Jul 2022 03:15:48 +0800 (CST) Received: from roberto-ThinkStation-P620.huawei.com (10.204.63.22) by fraeml714-chm.china.huawei.com (10.206.15.33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.24; Thu, 14 Jul 2022 21:16:50 +0200 From: Roberto Sassu To: , , , , , , , CC: , Roberto Sassu Subject: [RFC][PATCH v8 08/12] bpf: Add bpf_verify_pkcs7_signature() kfunc Date: Thu, 14 Jul 2022 21:14:51 +0200 Message-ID: <20220714191455.2101834-9-roberto.sassu@huawei.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220714191455.2101834-1-roberto.sassu@huawei.com> References: <20220714191455.2101834-1-roberto.sassu@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.204.63.22] X-ClientProxiedBy: lhreml754-chm.china.huawei.com (10.201.108.204) To fraeml714-chm.china.huawei.com (10.206.15.33) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net X-Patchwork-State: RFC Add the bpf_verify_pkcs7_signature() kfunc, to give eBPF security modules the ability to check the validity of a signature against supplied data, by using user-provided or system-provided keys as trust anchor. The new kfunc makes it possible to enforce mandatory policies, as eBPF programs might be allowed to make security decisions only based on data sources the system administrator approves. The caller should provide both the data to be verified and the signature as eBPF dynamic pointers (to minimize the number of parameters) and, alternatively, a keyring obtained from bpf_lookup_user_key(), or a pre-determined keyring ID with values defined in include/linux/verification.h. The two keyring parameters have to be provided separately: the pre-determined IDs exist only in the context of verify_pkcs7_signature(). They should not be passed to the bpf_lookup_user_key() kfunc, or to a new kfunc doing type casting to a struct key (like: ((struct key *)2UL) in include/linux/verification.h), as otherwise, each kfunc accepting a struct key would have to check if it is a valid pointer or not. Finally, bpf_verify_pkcs7_signature() completes the permission check deferred by bpf_lookup_user_key(), by calling key_validate(). key_task_permission() is already called by the PKCS#7 code. Signed-off-by: Roberto Sassu --- kernel/trace/bpf_trace.c | 86 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index bffca9465574..c09ed20d7314 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -1234,6 +1235,75 @@ noinline __weak void bpf_key_put(struct key *key) key_put(key); } +#ifdef CONFIG_SYSTEM_DATA_VERIFICATION +/** + * bpf_verify_pkcs7_signature - verify a PKCS#7 signature + * @data_ptr: data to verify + * @sig_ptr: signature of the data + * @user_keyring__maybe_null: user-defined keyring for sig ver (alternative) + * @system_keyring: system-defined keyring for sig ver (alternative) + * + * Verify the PKCS#7 signature *sig_ptr* against the supplied *data_ptr* + * alternatively with keys in *user_keyring__maybe_null* or *system_keyring*. + * Either one of the two must be provided. Respectively, NULL or UINT64_MAX + * must be passed to signal to the kfunc that the parameter is not used. + * + * *user_keyring__maybe_null* is a key pointer obtained from + * bpf_lookup_user_key(), while *system_keyring* is a pre-determined ID with + * values defined in include/linux/verification.h: 0 for the primary keyring + * (immutable keyring of system keys); 1 for both the primary and secondary + * keyring (where keys can be added only if they are vouched for by existing + * keys in those keyrings); 2 for the platform keyring (primarily used by the + * integrity subsystem to verify a kexec'ed kerned image and, possibly, + * the initramfs signature). + * + * Return: 0 on success, a negative value on error. + */ +noinline __weak int bpf_verify_pkcs7_signature(struct bpf_dynptr_kern *data_ptr, + struct bpf_dynptr_kern *sig_ptr, + struct key *user_keyring__maybe_null, + u64 system_keyring) +{ + struct key *trusted_keyring; + int ret; + + /* Either user_keyring__maybe_null or system_keyring must be specified. */ + if ((user_keyring__maybe_null && system_keyring != U64_MAX) || + (!user_keyring__maybe_null && system_keyring == U64_MAX)) + return -EINVAL; + + if (user_keyring__maybe_null) { + /* + * Do the permission check deferred in bpf_lookup_user_key(). + * + * A call to key_task_permission() here would be redundant, as + * it is already done by keyring_search() called by + * find_asymmetric_key(). + */ + ret = key_validate(user_keyring__maybe_null); + if (ret < 0) + return ret; + + trusted_keyring = user_keyring__maybe_null; + goto verify; + } + + /* Keep in sync with defs in include/linux/verification.h. */ + if (system_keyring > (unsigned long)VERIFY_USE_PLATFORM_KEYRING) + return -EINVAL; + + trusted_keyring = (struct key *)(unsigned long)system_keyring; +verify: + return verify_pkcs7_signature(data_ptr->data, + bpf_dynptr_get_size(data_ptr), + sig_ptr->data, + bpf_dynptr_get_size(sig_ptr), + trusted_keyring, + VERIFYING_UNSPECIFIED_SIGNATURE, NULL, + NULL); +} +#endif /* CONFIG_SYSTEM_DATA_VERIFICATION */ + __diag_pop(); BTF_SET_START(key_kfunc_ids) @@ -1257,12 +1327,26 @@ static const struct btf_kfunc_id_set bpf_key_kfunc_set = { .release_set = &key_put_kfunc_ids, .ret_null_set = &key_lookup_kfunc_ids, }; -#endif /* CONFIG_KEYS */ +#ifdef CONFIG_SYSTEM_DATA_VERIFICATION +BTF_SET_START(verify_sig_kfunc_ids) +BTF_ID(func, bpf_verify_pkcs7_signature) +BTF_SET_END(verify_sig_kfunc_ids) + +static const struct btf_kfunc_id_set bpf_verify_sig_kfunc_set = { + .owner = THIS_MODULE, + .check_set = &verify_sig_kfunc_ids, + .sleepable_set = &verify_sig_kfunc_ids, +}; +#endif /* CONFIG_SYSTEM_DATA_VERIFICATION */ +#endif /* CONFIG_KEYS */ const struct btf_kfunc_id_set *kfunc_sets[] = { #ifdef CONFIG_KEYS &bpf_key_kfunc_set, +#ifdef CONFIG_SYSTEM_DATA_VERIFICATION + &bpf_verify_sig_kfunc_set, +#endif /* CONFIG_SYSTEM_DATA_VERIFICATION */ #endif /* CONFIG_KEYS */ }; From patchwork Thu Jul 14 19:14:52 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 12918440 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 598EDCCA47B for ; Thu, 14 Jul 2022 19:17:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239496AbiGNTRC (ORCPT ); Thu, 14 Jul 2022 15:17:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53616 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239294AbiGNTRB (ORCPT ); Thu, 14 Jul 2022 15:17:01 -0400 Received: from sinmsgout03.his.huawei.com (sinmsgout03.his.huawei.com [119.8.177.38]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 373843DBDA for ; Thu, 14 Jul 2022 12:17:00 -0700 (PDT) Received: from fraeml714-chm.china.huawei.com (unknown [172.18.156.149]) by sinmsgout03.his.huawei.com (SkyGuard) with ESMTP id 4LkPN63gVvz9xGP4; Fri, 15 Jul 2022 03:15:50 +0800 (CST) Received: from roberto-ThinkStation-P620.huawei.com (10.204.63.22) by fraeml714-chm.china.huawei.com (10.206.15.33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.24; Thu, 14 Jul 2022 21:16:50 +0200 From: Roberto Sassu To: , , , , , , , CC: , Roberto Sassu Subject: [RFC][PATCH v8 09/12] selftests/bpf: Test kfuncs with __maybe_null suffix Date: Thu, 14 Jul 2022 21:14:52 +0200 Message-ID: <20220714191455.2101834-10-roberto.sassu@huawei.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220714191455.2101834-1-roberto.sassu@huawei.com> References: <20220714191455.2101834-1-roberto.sassu@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.204.63.22] X-ClientProxiedBy: lhreml754-chm.china.huawei.com (10.201.108.204) To fraeml714-chm.china.huawei.com (10.206.15.33) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net X-Patchwork-State: RFC Extend the test in kfunc_call_test.c to call the newly defined functions bpf_kfunc_call_test4() and bpf_kfunc_call_test_mem_len_pass2(), which have a parameter with the __maybe_null suffix. Ensure that the eBPF program is executed successfully. Signed-off-by: Roberto Sassu --- net/bpf/test_run.c | 11 +++++++++++ .../selftests/bpf/prog_tests/kfunc_call.c | 4 ++++ .../selftests/bpf/progs/kfunc_call_test.c | 17 +++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c index 2ca96acbc50a..22b4efe72ce9 100644 --- a/net/bpf/test_run.c +++ b/net/bpf/test_run.c @@ -551,6 +551,11 @@ struct sock * noinline bpf_kfunc_call_test3(struct sock *sk) return sk; } +struct sock *noinline bpf_kfunc_call_test4(struct sock *sk__maybe_null) +{ + return sk__maybe_null; +} + struct prog_test_member1 { int a; }; @@ -683,6 +688,10 @@ noinline void bpf_kfunc_call_test_mem_len_pass1(void *mem, int mem__sz) { } +noinline void bpf_kfunc_call_test_mem_len_pass2(u64 *mem__maybe_null) +{ +} + noinline void bpf_kfunc_call_test_mem_len_fail1(void *mem, int len) { } @@ -699,6 +708,7 @@ BTF_SET_START(test_sk_check_kfunc_ids) BTF_ID(func, bpf_kfunc_call_test1) BTF_ID(func, bpf_kfunc_call_test2) BTF_ID(func, bpf_kfunc_call_test3) +BTF_ID(func, bpf_kfunc_call_test4) BTF_ID(func, bpf_kfunc_call_test_acquire) BTF_ID(func, bpf_kfunc_call_memb_acquire) BTF_ID(func, bpf_kfunc_call_test_release) @@ -712,6 +722,7 @@ BTF_ID(func, bpf_kfunc_call_test_fail1) BTF_ID(func, bpf_kfunc_call_test_fail2) BTF_ID(func, bpf_kfunc_call_test_fail3) BTF_ID(func, bpf_kfunc_call_test_mem_len_pass1) +BTF_ID(func, bpf_kfunc_call_test_mem_len_pass2) BTF_ID(func, bpf_kfunc_call_test_mem_len_fail1) BTF_ID(func, bpf_kfunc_call_test_mem_len_fail2) BTF_SET_END(test_sk_check_kfunc_ids) diff --git a/tools/testing/selftests/bpf/prog_tests/kfunc_call.c b/tools/testing/selftests/bpf/prog_tests/kfunc_call.c index c00eb974eb85..4b90abb950b5 100644 --- a/tools/testing/selftests/bpf/prog_tests/kfunc_call.c +++ b/tools/testing/selftests/bpf/prog_tests/kfunc_call.c @@ -30,6 +30,10 @@ static void test_main(void) ASSERT_OK(err, "bpf_prog_test_run(test2)"); ASSERT_EQ(topts.retval, 3, "test2-retval"); + prog_fd = skel->progs.kfunc_call_test4.prog_fd; + err = bpf_prog_test_run_opts(prog_fd, &topts); + ASSERT_OK(err, "bpf_prog_test_run(test4)"); + prog_fd = skel->progs.kfunc_call_test_ref_btf_id.prog_fd; err = bpf_prog_test_run_opts(prog_fd, &topts); ASSERT_OK(err, "bpf_prog_test_run(test_ref_btf_id)"); diff --git a/tools/testing/selftests/bpf/progs/kfunc_call_test.c b/tools/testing/selftests/bpf/progs/kfunc_call_test.c index 5aecbb9fdc68..258fa89f23b2 100644 --- a/tools/testing/selftests/bpf/progs/kfunc_call_test.c +++ b/tools/testing/selftests/bpf/progs/kfunc_call_test.c @@ -6,6 +6,7 @@ extern int bpf_kfunc_call_test2(struct sock *sk, __u32 a, __u32 b) __ksym; extern __u64 bpf_kfunc_call_test1(struct sock *sk, __u32 a, __u64 b, __u32 c, __u64 d) __ksym; +extern struct sock *bpf_kfunc_call_test4(struct sock *sk__maybe_null) __ksym; extern struct prog_test_ref_kfunc *bpf_kfunc_call_test_acquire(unsigned long *sp) __ksym; extern void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; @@ -13,8 +14,23 @@ extern void bpf_kfunc_call_test_pass_ctx(struct __sk_buff *skb) __ksym; extern void bpf_kfunc_call_test_pass1(struct prog_test_pass1 *p) __ksym; extern void bpf_kfunc_call_test_pass2(struct prog_test_pass2 *p) __ksym; extern void bpf_kfunc_call_test_mem_len_pass1(void *mem, int len) __ksym; +extern void bpf_kfunc_call_test_mem_len_pass2(u64 *mem__maybe_null) __ksym; extern void bpf_kfunc_call_test_mem_len_fail2(__u64 *mem, int len) __ksym; +SEC("tc") +int kfunc_call_test4(struct __sk_buff *skb) +{ + struct bpf_sock *sk = skb->sk; + + if (!sk) + return -1; + + sk = bpf_sk_fullsock(sk); + + bpf_kfunc_call_test4((struct sock *)sk); + return 0; +} + SEC("tc") int kfunc_call_test2(struct __sk_buff *skb) { @@ -87,6 +103,7 @@ int kfunc_call_test_pass(struct __sk_buff *skb) bpf_kfunc_call_test_mem_len_pass1(&c, sizeof(c)); bpf_kfunc_call_test_mem_len_pass1(&d, sizeof(d)); bpf_kfunc_call_test_mem_len_pass1(&e, sizeof(e)); + bpf_kfunc_call_test_mem_len_pass2(NULL); bpf_kfunc_call_test_mem_len_fail2(&b, -1); return 0; From patchwork Thu Jul 14 19:14:53 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 12918442 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9A797C433EF for ; Thu, 14 Jul 2022 19:18:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239750AbiGNTS2 (ORCPT ); Thu, 14 Jul 2022 15:18:28 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54456 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239738AbiGNTS0 (ORCPT ); Thu, 14 Jul 2022 15:18:26 -0400 Received: from sinmsgout01.his.huawei.com (sinmsgout01.his.huawei.com [119.8.177.36]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C5C9F43E5E for ; Thu, 14 Jul 2022 12:18:24 -0700 (PDT) Received: from fraeml714-chm.china.huawei.com (unknown [172.18.156.208]) by sinmsgout01.his.huawei.com (SkyGuard) with ESMTP id 4LkPKP4nfNz9xF8b; Fri, 15 Jul 2022 03:13:29 +0800 (CST) Received: from roberto-ThinkStation-P620.huawei.com (10.204.63.22) by fraeml714-chm.china.huawei.com (10.206.15.33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.24; Thu, 14 Jul 2022 21:18:18 +0200 From: Roberto Sassu To: , , , , , , , CC: , Roberto Sassu Subject: [RFC][PATCH v8 10/12] selftests/bpf: Add verifier tests for bpf_lookup_user_key() and bpf_key_put() Date: Thu, 14 Jul 2022 21:14:53 +0200 Message-ID: <20220714191455.2101834-11-roberto.sassu@huawei.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220714191455.2101834-1-roberto.sassu@huawei.com> References: <20220714191455.2101834-1-roberto.sassu@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.204.63.22] X-ClientProxiedBy: lhreml754-chm.china.huawei.com (10.201.108.204) To fraeml714-chm.china.huawei.com (10.206.15.33) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net X-Patchwork-State: RFC Add verifier tests for bpf_lookup_user_key() and bpf_key_put(), to ensure that acquired key references can be released, that a non-NULL pointer is passed to bpf_key_put(), and that key references are not leaked. Also, slightly modify test_verifier.c, to find the BTF ID of the attach point for the LSM program type (currently, it is done only for TRACING). Signed-off-by: Roberto Sassu --- tools/testing/selftests/bpf/test_verifier.c | 3 +- .../selftests/bpf/verifier/ref_tracking.c | 80 +++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index f9d553fbf68a..2dbcbf363c18 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -1498,7 +1498,8 @@ static void do_test_single(struct bpf_test *test, bool unpriv, opts.log_level = DEFAULT_LIBBPF_LOG_LEVEL; opts.prog_flags = pflags; - if (prog_type == BPF_PROG_TYPE_TRACING && test->kfunc) { + if ((prog_type == BPF_PROG_TYPE_TRACING || + prog_type == BPF_PROG_TYPE_LSM) && test->kfunc) { int attach_btf_id; attach_btf_id = libbpf_find_vmlinux_btf_id(test->kfunc, diff --git a/tools/testing/selftests/bpf/verifier/ref_tracking.c b/tools/testing/selftests/bpf/verifier/ref_tracking.c index 57a83d763ec1..b351dc62492f 100644 --- a/tools/testing/selftests/bpf/verifier/ref_tracking.c +++ b/tools/testing/selftests/bpf/verifier/ref_tracking.c @@ -84,6 +84,86 @@ .errstr = "Unreleased reference", .result = REJECT, }, +{ + "reference tracking: release key reference", + .insns = { + BPF_MOV64_IMM(BPF_REG_1, -3), + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, BPF_PSEUDO_KFUNC_CALL, 0, 0), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, BPF_PSEUDO_KFUNC_CALL, 0, 0), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_LSM, + .kfunc = "bpf", + .expected_attach_type = BPF_LSM_MAC, + .flags = BPF_F_SLEEPABLE, + .fixup_kfunc_btf_id = { + { "bpf_lookup_user_key", 2 }, + { "bpf_key_put", 5 }, + }, + .result = ACCEPT, +}, +{ + "reference tracking: release key reference without check", + .insns = { + BPF_MOV64_IMM(BPF_REG_1, -3), + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, BPF_PSEUDO_KFUNC_CALL, 0, 0), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, BPF_PSEUDO_KFUNC_CALL, 0, 0), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_LSM, + .kfunc = "bpf", + .expected_attach_type = BPF_LSM_MAC, + .flags = BPF_F_SLEEPABLE, + .errstr = "arg#0 pointer type STRUCT key must point to scalar, or struct with scalar", + .fixup_kfunc_btf_id = { + { "bpf_lookup_user_key", 2 }, + { "bpf_key_put", 4 }, + }, + .result = REJECT, +}, +{ + "reference tracking: release reference with NULL key pointer", + .insns = { + BPF_MOV64_IMM(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, BPF_PSEUDO_KFUNC_CALL, 0, 0), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_LSM, + .kfunc = "bpf", + .expected_attach_type = BPF_LSM_MAC, + .flags = BPF_F_SLEEPABLE, + .errstr = "arg#0 pointer type STRUCT key must point to scalar, or struct with scalar", + .fixup_kfunc_btf_id = { + { "bpf_key_put", 1 }, + }, + .result = REJECT, +}, +{ + "reference tracking: leak potential reference to key", + .insns = { + BPF_MOV64_IMM(BPF_REG_1, -3), + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, BPF_PSEUDO_KFUNC_CALL, 0, 0), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_LSM, + .kfunc = "bpf", + .expected_attach_type = BPF_LSM_MAC, + .flags = BPF_F_SLEEPABLE, + .errstr = "Unreleased reference", + .fixup_kfunc_btf_id = { + { "bpf_lookup_user_key", 2 }, + }, + .result = REJECT, +}, { "reference tracking: release reference without check", .insns = { From patchwork Thu Jul 14 19:14:54 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 12918443 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1DCC9CCA47B for ; Thu, 14 Jul 2022 19:18:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239738AbiGNTS2 (ORCPT ); Thu, 14 Jul 2022 15:18:28 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54454 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239650AbiGNTS1 (ORCPT ); Thu, 14 Jul 2022 15:18:27 -0400 Received: from sinmsgout01.his.huawei.com (sinmsgout01.his.huawei.com [119.8.177.36]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B6FCA42ADC for ; Thu, 14 Jul 2022 12:18:26 -0700 (PDT) Received: from fraeml714-chm.china.huawei.com (unknown [172.18.156.208]) by sinmsgout01.his.huawei.com (SkyGuard) with ESMTP id 4LkPKR2vXXz9ttCw; Fri, 15 Jul 2022 03:13:31 +0800 (CST) Received: from roberto-ThinkStation-P620.huawei.com (10.204.63.22) by fraeml714-chm.china.huawei.com (10.206.15.33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.24; Thu, 14 Jul 2022 21:18:19 +0200 From: Roberto Sassu To: , , , , , , , CC: , Roberto Sassu Subject: [RFC][PATCH v8 11/12] selftests/bpf: Add additional test for bpf_lookup_user_key() Date: Thu, 14 Jul 2022 21:14:54 +0200 Message-ID: <20220714191455.2101834-12-roberto.sassu@huawei.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220714191455.2101834-1-roberto.sassu@huawei.com> References: <20220714191455.2101834-1-roberto.sassu@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.204.63.22] X-ClientProxiedBy: lhreml754-chm.china.huawei.com (10.201.108.204) To fraeml714-chm.china.huawei.com (10.206.15.33) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net X-Patchwork-State: RFC Add an additional test to ensure that bpf_lookup_user_key() creates a referenced special keyring when the KEY_LOOKUP_CREATE flag is passed to this function. Also ensure that the kfunc rejects invalid flags. Signed-off-by: Roberto Sassu --- .../bpf/prog_tests/lookup_user_key.c | 98 +++++++++++++++++++ .../bpf/progs/test_lookup_user_key.c | 38 +++++++ 2 files changed, 136 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/lookup_user_key.c create mode 100644 tools/testing/selftests/bpf/progs/test_lookup_user_key.c diff --git a/tools/testing/selftests/bpf/prog_tests/lookup_user_key.c b/tools/testing/selftests/bpf/prog_tests/lookup_user_key.c new file mode 100644 index 000000000000..e53686932785 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/lookup_user_key.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (C) 2022 Huawei Technologies Duesseldorf GmbH + * + * Author: Roberto Sassu + */ + +#include +#include + +#include "test_lookup_user_key.skel.h" + +#define KEY_LOOKUP_CREATE 0x01 +#define KEY_LOOKUP_PARTIAL 0x02 + +static bool kfunc_not_supported; + +static int libbpf_print_cb(enum libbpf_print_level level, const char *fmt, + va_list args) +{ + char *func; + + if (strcmp(fmt, "libbpf: extern (func ksym) '%s': not found in kernel or module BTFs\n")) + return 0; + + func = va_arg(args, char *); + + if (strcmp(func, "bpf_lookup_user_key") && strcmp(func, "bpf_key_put")) + return 0; + + kfunc_not_supported = true; + return 0; +} + +void test_lookup_user_key(void) +{ + libbpf_print_fn_t old_print_cb; + struct test_lookup_user_key *skel = NULL; + u32 next_id; + int ret; + + skel = test_lookup_user_key__open(); + if (!ASSERT_OK_PTR(skel, "test_lookup_user_key__open")) + return; + + old_print_cb = libbpf_set_print(libbpf_print_cb); + ret = test_lookup_user_key__load(skel); + libbpf_set_print(old_print_cb); + + if (ret < 0 && kfunc_not_supported) { + printf("%s:SKIP:bpf_lookup_user_key() kfunc not supported\n", + __func__); + test__skip(); + goto close_prog; + } + + if (!ASSERT_OK(ret, "test_lookup_user_key__load")) + goto close_prog; + + ret = test_lookup_user_key__attach(skel); + if (!ASSERT_OK(ret, "test_lookup_user_key__attach")) + goto close_prog; + + skel->bss->monitored_pid = getpid(); + skel->bss->key_serial = KEY_SPEC_THREAD_KEYRING; + + /* The thread-specific keyring does not exist, this test fails. */ + skel->bss->flags = 0; + + ret = bpf_prog_get_next_id(0, &next_id); + if (!ASSERT_LT(ret, 0, "bpf_prog_get_next_id")) + goto close_prog; + + /* Force creation of the thread-specific keyring, this test succeeds. */ + skel->bss->flags = KEY_LOOKUP_CREATE; + + ret = bpf_prog_get_next_id(0, &next_id); + if (!ASSERT_OK(ret, "bpf_prog_get_next_id")) + goto close_prog; + + /* Pass both lookup flags for parameter validation. */ + skel->bss->flags = KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL; + + ret = bpf_prog_get_next_id(0, &next_id); + if (!ASSERT_OK(ret, "bpf_prog_get_next_id")) + goto close_prog; + + /* Pass invalid flags. */ + skel->bss->flags = UINT64_MAX; + + ret = bpf_prog_get_next_id(0, &next_id); + ASSERT_LT(ret, 0, "bpf_prog_get_next_id"); + +close_prog: + skel->bss->monitored_pid = 0; + test_lookup_user_key__destroy(skel); +} diff --git a/tools/testing/selftests/bpf/progs/test_lookup_user_key.c b/tools/testing/selftests/bpf/progs/test_lookup_user_key.c new file mode 100644 index 000000000000..29d963055834 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_lookup_user_key.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (C) 2022 Huawei Technologies Duesseldorf GmbH + * + * Author: Roberto Sassu + */ + +#include "vmlinux.h" +#include +#include +#include + +char _license[] SEC("license") = "GPL"; + +__u32 monitored_pid; +__u32 key_serial; +__u64 flags; + +extern struct key *bpf_lookup_user_key(__u32 serial, __u64 flags) __ksym; +extern void bpf_key_put(struct key *key) __ksym; + +SEC("lsm.s/bpf") +int BPF_PROG(bpf, int cmd, union bpf_attr *attr, unsigned int size) +{ + struct key *key; + __u32 pid; + + pid = bpf_get_current_pid_tgid() >> 32; + if (pid != monitored_pid) + return 0; + + key = bpf_lookup_user_key(key_serial, flags); + if (key) + bpf_key_put(key); + + return (key) ? 0 : -ENOENT; +} From patchwork Thu Jul 14 19:14:55 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 12918444 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0DAD7C43334 for ; Thu, 14 Jul 2022 19:18:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239839AbiGNTSd (ORCPT ); Thu, 14 Jul 2022 15:18:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54560 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239650AbiGNTSb (ORCPT ); Thu, 14 Jul 2022 15:18:31 -0400 Received: from sinmsgout01.his.huawei.com (sinmsgout01.his.huawei.com [119.8.177.36]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 657C843E5E for ; Thu, 14 Jul 2022 12:18:29 -0700 (PDT) Received: from fraeml714-chm.china.huawei.com (unknown [172.18.156.208]) by sinmsgout01.his.huawei.com (SkyGuard) with ESMTP id 4LkPKT0zpKz9v7NZ; Fri, 15 Jul 2022 03:13:32 +0800 (CST) Received: from roberto-ThinkStation-P620.huawei.com (10.204.63.22) by fraeml714-chm.china.huawei.com (10.206.15.33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.24; Thu, 14 Jul 2022 21:18:20 +0200 From: Roberto Sassu To: , , , , , , , CC: , Roberto Sassu Subject: [RFC][PATCH v8 12/12] selftests/bpf: Add test for bpf_verify_pkcs7_signature() kfunc Date: Thu, 14 Jul 2022 21:14:55 +0200 Message-ID: <20220714191455.2101834-13-roberto.sassu@huawei.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220714191455.2101834-1-roberto.sassu@huawei.com> References: <20220714191455.2101834-1-roberto.sassu@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.204.63.22] X-ClientProxiedBy: lhreml754-chm.china.huawei.com (10.201.108.204) To fraeml714-chm.china.huawei.com (10.206.15.33) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net X-Patchwork-State: RFC Perform several tests to ensure the correct implementation of the bpf_verify_pkcs7_signature() kfunc. Do the tests with data signed with a generated testing key (by using sign-file from scripts/) and with the tcp_bic.ko kernel module if it is found in the system. The test does not fail if tcp_bic.ko is not found. First, ensure that bpf_verify_pkcs7_signature() rejects invalid parameters. Then, perform a successful signature verification with the session keyring and a new one created for testing. Then, ensure that permission and validation checks are done properly on the keyring provided to bpf_verify_pkcs7_signature(), despite those checks were deferred at the time the keyring was retrieved with bpf_lookup_user_key(). The tests expect to encounter an error if the Search permission is removed from the keyring, or the keyring is expired. Finally, perform a successful and unsuccessful signature verification with the keyrings with pre-determined IDs (the last test fails because the key is not in the platform keyring). Signed-off-by: Roberto Sassu --- tools/testing/selftests/bpf/Makefile | 14 +- tools/testing/selftests/bpf/config | 2 + .../bpf/prog_tests/verify_pkcs7_sig.c | 415 ++++++++++++++++++ .../bpf/progs/test_verify_pkcs7_sig.c | 100 +++++ .../testing/selftests/bpf/verify_sig_setup.sh | 104 +++++ 5 files changed, 632 insertions(+), 3 deletions(-) create mode 100644 tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c create mode 100644 tools/testing/selftests/bpf/progs/test_verify_pkcs7_sig.c create mode 100755 tools/testing/selftests/bpf/verify_sig_setup.sh diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 8d59ec7f4c2d..5ae079e276b3 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -14,6 +14,7 @@ BPFTOOLDIR := $(TOOLSDIR)/bpf/bpftool APIDIR := $(TOOLSINCDIR)/uapi GENDIR := $(abspath ../../../../include/generated) GENHDR := $(GENDIR)/autoconf.h +HOSTPKG_CONFIG := pkg-config ifneq ($(wildcard $(GENHDR)),) GENFLAGS := -DHAVE_GENHDR @@ -75,7 +76,7 @@ TEST_PROGS := test_kmod.sh \ test_xsk.sh TEST_PROGS_EXTENDED := with_addr.sh \ - with_tunnels.sh ima_setup.sh \ + with_tunnels.sh ima_setup.sh verify_sig_setup.sh \ test_xdp_vlan.sh test_bpftool.py # Compile but not part of 'make run_tests' @@ -84,7 +85,7 @@ TEST_GEN_PROGS_EXTENDED = test_sock_addr test_skb_cgroup_id_user \ test_lirc_mode2_user xdping test_cpp runqslower bench bpf_testmod.ko \ xskxceiver xdp_redirect_multi xdp_synproxy -TEST_CUSTOM_PROGS = $(OUTPUT)/urandom_read +TEST_CUSTOM_PROGS = $(OUTPUT)/urandom_read $(OUTPUT)/sign-file # Emit succinct information message describing current building step # $1 - generic step name (e.g., CC, LINK, etc); @@ -189,6 +190,12 @@ $(OUTPUT)/urandom_read: urandom_read.c urandom_read_aux.c $(OUTPUT)/liburandom_r -fuse-ld=$(LLD) -Wl,-znoseparate-code \ -Wl,-rpath=. -Wl,--build-id=sha1 -o $@ +$(OUTPUT)/sign-file: ../../../../scripts/sign-file.c + $(call msg,SIGN-FILE,,$@) + $(Q)$(CC) $(shell $(HOSTPKG_CONFIG)--cflags libcrypto 2> /dev/null) \ + $< -o $@ \ + $(shell $(HOSTPKG_CONFIG) --libs libcrypto 2> /dev/null || echo -lcrypto) + $(OUTPUT)/bpf_testmod.ko: $(VMLINUX_BTF) $(wildcard bpf_testmod/Makefile bpf_testmod/*.[ch]) $(call msg,MOD,,$@) $(Q)$(RM) bpf_testmod/bpf_testmod.ko # force re-compilation @@ -514,7 +521,8 @@ TRUNNER_EXTRA_SOURCES := test_progs.c cgroup_helpers.c trace_helpers.c \ TRUNNER_EXTRA_FILES := $(OUTPUT)/urandom_read $(OUTPUT)/bpf_testmod.ko \ $(OUTPUT)/liburandom_read.so \ $(OUTPUT)/xdp_synproxy \ - ima_setup.sh \ + $(OUTPUT)/sign-file \ + ima_setup.sh verify_sig_setup.sh \ $(wildcard progs/btf_dump_test_case_*.c) TRUNNER_BPF_BUILD_RULE := CLANG_BPF_BUILD_RULE TRUNNER_BPF_CFLAGS := $(BPF_CFLAGS) $(CLANG_CFLAGS) -DENABLE_ATOMICS_TESTS diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config index c05904d631ec..76b65acd897e 100644 --- a/tools/testing/selftests/bpf/config +++ b/tools/testing/selftests/bpf/config @@ -63,3 +63,5 @@ CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_IP_NF_FILTER=y CONFIG_IP_NF_TARGET_SYNPROXY=y CONFIG_IP_NF_RAW=y +CONFIG_MODULE_SIG=y +CONFIG_KEYS=y diff --git a/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c b/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c new file mode 100644 index 000000000000..259dc216645c --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c @@ -0,0 +1,415 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (C) 2022 Huawei Technologies Duesseldorf GmbH + * + * Author: Roberto Sassu + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_verify_pkcs7_sig.skel.h" + +#define MAX_DATA_SIZE (1024 * 1024) +#define MAX_SIG_SIZE 1024 + +#define VERIFY_USE_SECONDARY_KEYRING (1UL) +#define VERIFY_USE_PLATFORM_KEYRING (2UL) + +/* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */ +#define MODULE_SIG_STRING "~Module signature appended~\n" + +/* + * Module signature information block. + * + * The constituents of the signature section are, in order: + * + * - Signer's name + * - Key identifier + * - Signature data + * - Information block + */ +struct module_signature { + u8 algo; /* Public-key crypto algorithm [0] */ + u8 hash; /* Digest algorithm [0] */ + u8 id_type; /* Key identifier type [PKEY_ID_PKCS7] */ + u8 signer_len; /* Length of signer's name [0] */ + u8 key_id_len; /* Length of key identifier [0] */ + u8 __pad[3]; + __be32 sig_len; /* Length of signature data */ +}; + +struct data { + u8 data[MAX_DATA_SIZE]; + u32 data_len; + u8 sig[MAX_SIG_SIZE]; + u32 sig_len; +}; + +static bool kfunc_not_supported; + +static int libbpf_print_cb(enum libbpf_print_level level, const char *fmt, + va_list args) +{ + if (strcmp(fmt, "libbpf: extern (func ksym) '%s': not found in kernel or module BTFs\n")) + return 0; + + if (strcmp(va_arg(args, char *), "bpf_verify_pkcs7_signature")) + return 0; + + kfunc_not_supported = true; + return 0; +} + +static int _run_setup_process(const char *setup_dir, const char *cmd) +{ + int child_pid, child_status; + + child_pid = fork(); + if (child_pid == 0) { + execlp("./verify_sig_setup.sh", "./verify_sig_setup.sh", cmd, + setup_dir, NULL); + exit(errno); + + } else if (child_pid > 0) { + waitpid(child_pid, &child_status, 0); + return WEXITSTATUS(child_status); + } + + return -EINVAL; +} + +static int populate_data_item_str(const char *tmp_dir, struct data *data_item) +{ + struct stat st; + char data_template[] = "/tmp/dataXXXXXX"; + char path[PATH_MAX]; + int ret, fd, child_status, child_pid; + + data_item->data_len = 4; + memcpy(data_item->data, "test", data_item->data_len); + + fd = mkstemp(data_template); + if (fd == -1) + return -errno; + + ret = write(fd, data_item->data, data_item->data_len); + + close(fd); + + if (ret != data_item->data_len) { + ret = -EIO; + goto out; + } + + child_pid = fork(); + + if (child_pid == -1) { + ret = -errno; + goto out; + } + + if (child_pid == 0) { + snprintf(path, sizeof(path), "%s/signing_key.pem", tmp_dir); + + return execlp("./sign-file", "./sign-file", "-d", "sha256", + path, path, data_template, NULL); + } + + waitpid(child_pid, &child_status, 0); + + ret = WEXITSTATUS(child_status); + if (ret) + goto out; + + snprintf(path, sizeof(path), "%s.p7s", data_template); + + ret = stat(path, &st); + if (ret == -1) { + ret = -errno; + goto out; + } + + if (st.st_size > sizeof(data_item->sig)) { + ret = -EINVAL; + goto out_sig; + } + + data_item->sig_len = st.st_size; + + fd = open(path, O_RDONLY); + if (fd == -1) { + ret = -errno; + goto out_sig; + } + + ret = read(fd, data_item->sig, data_item->sig_len); + + close(fd); + + if (ret != data_item->sig_len) { + ret = -EIO; + goto out_sig; + } + + ret = 0; +out_sig: + unlink(path); +out: + unlink(data_template); + return ret; +} + +static int populate_data_item_mod(struct data *data_item) +{ + char mod_path[PATH_MAX], *mod_path_ptr; + struct stat st; + void *mod; + FILE *fp; + struct module_signature ms; + int ret, fd, modlen, marker_len, sig_len; + + data_item->data_len = 0; + + if (stat("/lib/modules", &st) == -1) + return 0; + + /* Requires CONFIG_TCP_CONG_BIC=m. */ + fp = popen("find /lib/modules/$(uname -r) -name tcp_bic.ko", "r"); + if (!fp) + return 0; + + mod_path_ptr = fgets(mod_path, sizeof(mod_path), fp); + pclose(fp); + + if (!mod_path_ptr) + return 0; + + mod_path_ptr = strchr(mod_path, '\n'); + if (!mod_path_ptr) + return 0; + + *mod_path_ptr = '\0'; + + if (stat(mod_path, &st) == -1) + return 0; + + modlen = st.st_size; + marker_len = sizeof(MODULE_SIG_STRING) - 1; + + fd = open(mod_path, O_RDONLY); + if (fd == -1) + return -errno; + + mod = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + + close(fd); + + if (mod == MAP_FAILED) + return -errno; + + if (strncmp(mod + modlen - marker_len, MODULE_SIG_STRING, marker_len)) { + ret = -EINVAL; + goto out; + } + + modlen -= marker_len; + + memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms)); + + sig_len = __be32_to_cpu(ms.sig_len); + modlen -= sig_len + sizeof(ms); + + if (modlen > sizeof(data_item->data)) { + ret = -E2BIG; + goto out; + } + + memcpy(data_item->data, mod, modlen); + data_item->data_len = modlen; + + if (sig_len > sizeof(data_item->sig)) { + ret = -E2BIG; + goto out; + } + + memcpy(data_item->sig, mod + modlen, sig_len); + data_item->sig_len = sig_len; + ret = 0; +out: + munmap(mod, st.st_size); + return ret; +} + +void test_verify_pkcs7_sig(void) +{ + libbpf_print_fn_t old_print_cb; + char tmp_dir_template[] = "/tmp/verify_sigXXXXXX"; + char *tmp_dir; + struct test_verify_pkcs7_sig *skel = NULL; + struct bpf_map *map; + struct data data; + int ret, zero = 0; + + /* Trigger creation of session keyring. */ + syscall(__NR_request_key, "keyring", "_uid.0", NULL, + KEY_SPEC_SESSION_KEYRING); + + tmp_dir = mkdtemp(tmp_dir_template); + if (!ASSERT_OK_PTR(tmp_dir, "mkdtemp")) + return; + + ret = _run_setup_process(tmp_dir, "setup"); + if (!ASSERT_OK(ret, "_run_setup_process")) + goto close_prog; + + skel = test_verify_pkcs7_sig__open(); + if (!ASSERT_OK_PTR(skel, "test_verify_pkcs7_sig__open")) + goto close_prog; + + old_print_cb = libbpf_set_print(libbpf_print_cb); + ret = test_verify_pkcs7_sig__load(skel); + libbpf_set_print(old_print_cb); + + if (ret < 0 && kfunc_not_supported) { + printf( + "%s:SKIP:bpf_verify_pkcs7_signature() kfunc not supported\n", + __func__); + test__skip(); + goto close_prog; + } + + if (!ASSERT_OK(ret, "test_verify_pkcs7_sig__load")) + goto close_prog; + + ret = test_verify_pkcs7_sig__attach(skel); + if (!ASSERT_OK(ret, "test_verify_pkcs7_sig__attach")) + goto close_prog; + + map = bpf_object__find_map_by_name(skel->obj, "data_input"); + if (!ASSERT_OK_PTR(map, "data_input not found")) + goto close_prog; + + skel->bss->monitored_pid = getpid(); + + /* Test incorrect parameters. */ + skel->bss->user_keyring_serial = 0; + skel->bss->system_keyring = UINT64_MAX; + + ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY); + if (!ASSERT_LT(ret, 0, "bpf_map_update_elem data_input")) + goto close_prog; + + skel->bss->user_keyring_serial = KEY_SPEC_SESSION_KEYRING; + skel->bss->system_keyring = 0; + + ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY); + if (!ASSERT_LT(ret, 0, "bpf_map_update_elem data_input")) + goto close_prog; + + /* Test without data and signature. */ + skel->bss->user_keyring_serial = KEY_SPEC_SESSION_KEYRING; + skel->bss->system_keyring = UINT64_MAX; + + ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY); + if (!ASSERT_LT(ret, 0, "bpf_map_update_elem data_input")) + goto close_prog; + + /* Test successful signature verification with session keyring. */ + ret = populate_data_item_str(tmp_dir, &data); + if (!ASSERT_OK(ret, "populate_data_item_str")) + goto close_prog; + + ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY); + if (!ASSERT_OK(ret, "bpf_map_update_elem data_input")) + goto close_prog; + + /* Test successful signature verification with testing keyring. */ + skel->bss->user_keyring_serial = syscall(__NR_request_key, "keyring", + "ebpf_testing_keyring", NULL, + KEY_SPEC_SESSION_KEYRING); + + ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY); + if (!ASSERT_OK(ret, "bpf_map_update_elem data_input")) + goto close_prog; + + /* + * Ensure key_task_permission() is called and rejects the keyring + * (no Search permission). + */ + syscall(__NR_keyctl, KEYCTL_SETPERM, skel->bss->user_keyring_serial, + 0x37373737); + + ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY); + if (!ASSERT_LT(ret, 0, "bpf_map_update_elem data_input")) + goto close_prog; + + syscall(__NR_keyctl, KEYCTL_SETPERM, skel->bss->user_keyring_serial, + 0x3f3f3f3f); + + /* + * Ensure key_validate() is called and rejects the keyring (key expired) + */ + syscall(__NR_keyctl, KEYCTL_SET_TIMEOUT, + skel->bss->user_keyring_serial, 1); + sleep(1); + + ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY); + if (!ASSERT_LT(ret, 0, "bpf_map_update_elem data_input")) + goto close_prog; + + skel->bss->user_keyring_serial = KEY_SPEC_SESSION_KEYRING; + + /* Test with corrupted data (signature verification should fail). */ + data.data[0] = 'a'; + ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY); + if (!ASSERT_LT(ret, 0, "bpf_map_update_elem data_input")) + goto close_prog; + + ret = populate_data_item_mod(&data); + if (!ASSERT_OK(ret, "populate_data_item_mod")) + goto close_prog; + + /* Test signature verification with system keyrings. */ + if (data.data_len) { + skel->bss->user_keyring_serial = 0; + skel->bss->system_keyring = 0; + + ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, + BPF_ANY); + if (!ASSERT_OK(ret, "bpf_map_update_elem data_input")) + goto close_prog; + + skel->bss->system_keyring = VERIFY_USE_SECONDARY_KEYRING; + + ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, + BPF_ANY); + if (!ASSERT_OK(ret, "bpf_map_update_elem data_input")) + goto close_prog; + + skel->bss->system_keyring = VERIFY_USE_PLATFORM_KEYRING; + + ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, + BPF_ANY); + ASSERT_LT(ret, 0, "bpf_map_update_elem data_input"); + } + +close_prog: + _run_setup_process(tmp_dir, "cleanup"); + + if (!skel) + return; + + skel->bss->monitored_pid = 0; + test_verify_pkcs7_sig__destroy(skel); +} diff --git a/tools/testing/selftests/bpf/progs/test_verify_pkcs7_sig.c b/tools/testing/selftests/bpf/progs/test_verify_pkcs7_sig.c new file mode 100644 index 000000000000..670223211af0 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_verify_pkcs7_sig.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (C) 2022 Huawei Technologies Duesseldorf GmbH + * + * Author: Roberto Sassu + */ + +#include "vmlinux.h" +#include +#include +#include + +#define MAX_DATA_SIZE (1024 * 1024) +#define MAX_SIG_SIZE 1024 + +typedef __u8 u8; +typedef __u16 u16; +typedef __u32 u32; +typedef __u64 u64; + +struct bpf_dynptr { + __u64 :64; + __u64 :64; +} __attribute__((aligned(8))); + +extern struct key *bpf_lookup_user_key(__u32 serial, __u64 flags) __ksym; +extern void bpf_key_put(struct key *key) __ksym; +extern int bpf_verify_pkcs7_signature(struct bpf_dynptr *data_ptr, + struct bpf_dynptr *sig_ptr, + struct key *user_keyring__maybe_null, + u64 system_keyring) __ksym; + +u32 monitored_pid; +u32 user_keyring_serial; +u64 system_keyring; + +struct data { + u8 data[MAX_DATA_SIZE]; + u32 data_len; + u8 sig[MAX_SIG_SIZE]; + u32 sig_len; +}; + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(max_entries, 1); + __type(key, __u32); + __type(value, struct data); +} data_input SEC(".maps"); + +char _license[] SEC("license") = "GPL"; + +SEC("lsm.s/bpf") +int BPF_PROG(bpf, int cmd, union bpf_attr *attr, unsigned int size) +{ + struct bpf_dynptr data_ptr, sig_ptr; + struct data *data_val; + struct key *user_keyring = NULL; + u32 pid; + u64 value; + int ret, zero = 0; + + pid = bpf_get_current_pid_tgid() >> 32; + if (pid != monitored_pid) + return 0; + + data_val = bpf_map_lookup_elem(&data_input, &zero); + if (!data_val) + return 0; + + bpf_probe_read(&value, sizeof(value), &attr->value); + + bpf_copy_from_user(data_val, sizeof(struct data), + (void *)(unsigned long)value); + + if (data_val->data_len > sizeof(data_val->data)) + return -EINVAL; + + bpf_dynptr_from_mem(data_val->data, data_val->data_len, 0, &data_ptr); + + if (data_val->sig_len > sizeof(data_val->sig)) + return -EINVAL; + + bpf_dynptr_from_mem(data_val->sig, data_val->sig_len, 0, &sig_ptr); + + if (user_keyring_serial) { + user_keyring = bpf_lookup_user_key(user_keyring_serial, 0); + if (!user_keyring) + return -ENOENT; + } + + ret = bpf_verify_pkcs7_signature(&data_ptr, &sig_ptr, user_keyring, + system_keyring); + + if (user_keyring) + bpf_key_put(user_keyring); + + return ret; +} diff --git a/tools/testing/selftests/bpf/verify_sig_setup.sh b/tools/testing/selftests/bpf/verify_sig_setup.sh new file mode 100755 index 000000000000..ba08922b4a27 --- /dev/null +++ b/tools/testing/selftests/bpf/verify_sig_setup.sh @@ -0,0 +1,104 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +set -e +set -u +set -o pipefail + +VERBOSE="${SELFTESTS_VERBOSE:=0}" +LOG_FILE="$(mktemp /tmp/verify_sig_setup.log.XXXXXX)" + +x509_genkey_content="\ +[ req ] +default_bits = 2048 +distinguished_name = req_distinguished_name +prompt = no +string_mask = utf8only +x509_extensions = myexts + +[ req_distinguished_name ] +CN = eBPF Signature Verification Testing Key + +[ myexts ] +basicConstraints=critical,CA:FALSE +keyUsage=digitalSignature +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid +" + +usage() +{ + echo "Usage: $0 " + exit 1 +} + +setup() +{ + local tmp_dir="$1" + + echo "${x509_genkey_content}" > ${tmp_dir}/x509.genkey + + openssl req -new -nodes -utf8 -sha256 -days 36500 \ + -batch -x509 -config ${tmp_dir}/x509.genkey \ + -outform PEM -out ${tmp_dir}/signing_key.pem \ + -keyout ${tmp_dir}/signing_key.pem 2>&1 + + openssl x509 -in ${tmp_dir}/signing_key.pem -out \ + ${tmp_dir}/signing_key.der -outform der + + key_id=$(cat ${tmp_dir}/signing_key.der | keyctl padd asymmetric ebpf_testing_key @s) + + keyring_id=$(keyctl newring ebpf_testing_keyring @s) + keyctl link $key_id $keyring_id +} + +cleanup() { + local tmp_dir="$1" + + keyctl unlink $(keyctl search @s asymmetric ebpf_testing_key) @s + keyctl unlink $(keyctl search @s keyring ebpf_testing_keyring) @s + rm -rf ${tmp_dir} +} + +catch() +{ + local exit_code="$1" + local log_file="$2" + + if [[ "${exit_code}" -ne 0 ]]; then + cat "${log_file}" >&3 + fi + + rm -f "${log_file}" + exit ${exit_code} +} + +main() +{ + [[ $# -ne 2 ]] && usage + + local action="$1" + local tmp_dir="$2" + + [[ ! -d "${tmp_dir}" ]] && echo "Directory ${tmp_dir} doesn't exist" && exit 1 + + if [[ "${action}" == "setup" ]]; then + setup "${tmp_dir}" + elif [[ "${action}" == "cleanup" ]]; then + cleanup "${tmp_dir}" + else + echo "Unknown action: ${action}" + exit 1 + fi +} + +trap 'catch "$?" "${LOG_FILE}"' EXIT + +if [[ "${VERBOSE}" -eq 0 ]]; then + # Save the stderr to 3 so that we can output back to + # it incase of an error. + exec 3>&2 1>"${LOG_FILE}" 2>&1 +fi + +main "$@" +rm -f "${LOG_FILE}"