Received: by 2002:a5d:925a:0:0:0:0:0 with SMTP id e26csp1524080iol; Fri, 10 Jun 2022 09:09:57 -0700 (PDT) X-Google-Smtp-Source: ABdhPJw59CLj17kGIEzhbXG+gFdYFg0WPU4TBoYsUoze5tDfW1QaAFwBHlLLHPgAtcKGmkvcTzRx X-Received: by 2002:aa7:c9c9:0:b0:431:962f:f61e with SMTP id i9-20020aa7c9c9000000b00431962ff61emr20959761edt.189.1654877397761; Fri, 10 Jun 2022 09:09:57 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1654877397; cv=none; d=google.com; s=arc-20160816; b=mvsQJ4gWm9wyAA1dV4fxLOjJyASvXVBq2LZEWg3LGsFkuiv9xjJoRef7Ezo33hNVAK ZEm/K0qAAUKtNUSSULzG3+omX4OoR9TZpcdmMjpbAlRXjfwth0+n3ZxjoW8hjxhQ0AdY +dUii0dLhGm75nMGS/s0aQ2cnR+iCbQ1A2HC2islQavzctzEsKPfQWhlh/WiMqVdLBsC Arv/Urahmmkr0t+Rpc/RqHPtxiTaAvdkSA6swxxe/xrlfPtKAM5aidcZZE3oWyGWSyYh clt7gWN1sjkt5ASU4jc8D/xB+FOGVqErhNjQckhvfimIfdJChObs4Ys1MfkBsnm9FNpG tuNg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:content-language :in-reply-to:mime-version:user-agent:date:message-id:from:references :cc:to:subject; bh=jsLsvVjLevUDLy/lkSuioctctGpNkJISfPGjMfa+EdQ=; b=aDIClV9+IaAeztJ8C0TnkDFO5M4buqp311QJzxMrM1CGtQqRKgwg2oKcjqsH2lR/e7 XX44856/k/cVQhZWrcRKCf3o6UGL0cwHnFDunxQ9sKJMldbmuYLkUUogAJVymV0Q0Zfx z5XqQJFatpOywHPYFffNVq1J5vfHHY1mOBpacrBL8/3rlQgpxHJgwBFN7a89Yo0WmVVN 71fYaMzyO0maP7nuqWc5DIsxR8Cm0M/4J7mgr1xQUYh08MTbDEIGLO5kKZt9fE3FWKT0 WfhiZOYGmn+tb+P+Y5ZfKDONmFeLNnQ7xnpRkkWanKv3hQ0Q2bZE7JA1u1sIveYFe/KM ZHCA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id dp17-20020a170906c15100b0070ef64a5880si10591364ejc.454.2022.06.10.09.09.31; Fri, 10 Jun 2022 09:09:57 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233633AbiFJPOk (ORCPT + 99 others); Fri, 10 Jun 2022 11:14:40 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33098 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229553AbiFJPOh (ORCPT ); Fri, 10 Jun 2022 11:14:37 -0400 Received: from www62.your-server.de (www62.your-server.de [213.133.104.62]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DAC4E95A3; Fri, 10 Jun 2022 08:14:35 -0700 (PDT) Received: from sslproxy03.your-server.de ([88.198.220.132]) by www62.your-server.de with esmtpsa (TLSv1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.92.3) (envelope-from ) id 1nzgLE-0003a9-0M; Fri, 10 Jun 2022 17:14:28 +0200 Received: from [85.1.206.226] (helo=linux.home) by sslproxy03.your-server.de with esmtpsa (TLSv1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1nzgLD-000Tc0-Mu; Fri, 10 Jun 2022 17:14:27 +0200 Subject: Re: [PATCH v3 1/2] bpf: Add bpf_verify_signature() helper To: Roberto Sassu , "ast@kernel.org" , "andrii@kernel.org" , "kpsingh@kernel.org" Cc: "bpf@vger.kernel.org" , "netdev@vger.kernel.org" , "linux-kselftest@vger.kernel.org" , "linux-kernel@vger.kernel.org" , kernel test robot , "john.fastabend@gmail.com" References: <20220610135916.1285509-1-roberto.sassu@huawei.com> <20220610135916.1285509-2-roberto.sassu@huawei.com> <4b877d4877be495787cb431d0a42cbc9@huawei.com> From: Daniel Borkmann Message-ID: <1a5534e6-4d63-7c91-8dcd-41b22f1ea2ba@iogearbox.net> Date: Fri, 10 Jun 2022 17:14:27 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.7.2 MIME-Version: 1.0 In-Reply-To: <4b877d4877be495787cb431d0a42cbc9@huawei.com> Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 7bit X-Authenticated-Sender: daniel@iogearbox.net X-Virus-Scanned: Clear (ClamAV 0.103.6/26568/Fri Jun 10 10:06:23 2022) X-Spam-Status: No, score=-3.1 required=5.0 tests=BAYES_00,NICE_REPLY_A, RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 6/10/22 4:59 PM, Roberto Sassu wrote: >> From: Daniel Borkmann [mailto:daniel@iogearbox.net] >> Sent: Friday, June 10, 2022 4:49 PM >> On 6/10/22 3:59 PM, Roberto Sassu wrote: >>> Add the bpf_verify_signature() helper, to give eBPF security modules the >>> ability to check the validity of a signature against supplied data, by >>> using system-provided keys as trust anchor. >>> >>> The new helper 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 specify the identifier of the keyring containing the keys >>> for signature verification: 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); >>> 0xffff for the session keyring (for testing purposes). >>> >>> The caller should also specify the type of signature. Currently only PKCS#7 >>> is supported. >>> >>> Since the maximum number of parameters of an eBPF helper is 5, the keyring >>> and signature types share one (keyring ID: low 16 bits, signature type: >>> high 16 bits). >>> >>> Signed-off-by: Roberto Sassu >>> Reported-by: kernel test robot (cast warning) >>> --- >>> include/uapi/linux/bpf.h | 17 +++++++++++++ >>> kernel/bpf/bpf_lsm.c | 46 ++++++++++++++++++++++++++++++++++ >>> tools/include/uapi/linux/bpf.h | 17 +++++++++++++ >>> 3 files changed, 80 insertions(+) >>> >>> diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h >>> index f4009dbdf62d..97521857e44a 100644 >>> --- a/include/uapi/linux/bpf.h >>> +++ b/include/uapi/linux/bpf.h >>> @@ -5249,6 +5249,22 @@ union bpf_attr { >>> * Pointer to the underlying dynptr data, NULL if the dynptr is >>> * read-only, if the dynptr is invalid, or if the offset and length >>> * is out of bounds. >>> + * >>> + * long bpf_verify_signature(u8 *data, u32 datalen, u8 *sig, u32 siglen, u32 >> info) >>> + * Description >>> + * Verify a signature of length *siglen* against the supplied data >>> + * with length *datalen*. *info* contains the keyring identifier >>> + * (low 16 bits) and the signature type (high 16 bits). The keyring >>> + * identifier can have the following values (some defined in >>> + * 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); 0xffff for >>> + * the session keyring (for testing purposes). >>> + * Return >>> + * 0 on success, a negative value on error. >>> */ >>> #define __BPF_FUNC_MAPPER(FN) \ >>> FN(unspec), \ >>> @@ -5455,6 +5471,7 @@ union bpf_attr { >>> FN(dynptr_read), \ >>> FN(dynptr_write), \ >>> FN(dynptr_data), \ >>> + FN(verify_signature), \ >>> /* */ >>> >>> /* integer value in 'imm' field of BPF_CALL instruction selects which helper >>> diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c >>> index c1351df9f7ee..20bd850ea3ee 100644 >>> --- a/kernel/bpf/bpf_lsm.c >>> +++ b/kernel/bpf/bpf_lsm.c >>> @@ -16,6 +16,8 @@ >>> #include >>> #include >>> #include >>> +#include >>> +#include >>> >>> /* For every LSM hook that allows attachment of BPF programs, declare a >> nop >>> * function where a BPF program can be attached. >>> @@ -132,6 +134,46 @@ static const struct bpf_func_proto >> bpf_get_attach_cookie_proto = { >>> .arg1_type = ARG_PTR_TO_CTX, >>> }; >>> >>> +#ifdef CONFIG_SYSTEM_DATA_VERIFICATION >>> +BPF_CALL_5(bpf_verify_signature, u8 *, data, u32, datalen, u8 *, sig, >>> + u32, siglen, u32, info) >>> +{ >>> + unsigned long keyring_id = info & U16_MAX; >>> + enum pkey_id_type id_type = info >> 16; >>> + const struct cred *cred = current_cred(); >>> + struct key *keyring; >>> + >>> + if (keyring_id > (unsigned long)VERIFY_USE_PLATFORM_KEYRING && >>> + keyring_id != U16_MAX) >>> + return -EINVAL; >>> + >>> + keyring = (keyring_id == U16_MAX) ? >>> + cred->session_keyring : (struct key *)keyring_id; >>> + >>> + switch (id_type) { >>> + case PKEY_ID_PKCS7: >>> + return verify_pkcs7_signature(data, datalen, sig, siglen, >>> + keyring, >>> + >> VERIFYING_UNSPECIFIED_SIGNATURE, >>> + NULL, NULL); >>> + default: >>> + return -EOPNOTSUPP; >> >> Question to you & KP: >> >> > Can we keep the helper generic so that it can be extended to more types of >> > signatures and pass the signature type as an enum? >> >> How many different signature types do we expect, say, in the next 6mo, to land >> here? Just thinking out loud whether it is better to keep it simple as with the >> last iteration where we have a helper specific to pkcs7, and if needed in future >> we add others. We only have the last reg as auxillary arg where we need to >> squeeze >> all info into it now. What if for other, future signature types this won't suffice? > > I would add at least another for PGP, assuming that the code will be > upstreamed. But I agree, the number should not be that high. If realistically expected is really just two helpers, what speaks against a bpf_verify_signature_pkcs7() and bpf_verify_signature_pgp() in that case, for sake of better user experience? Maybe one other angle.. if CONFIG_SYSTEM_DATA_VERIFICATION is enabled, it may not be clear whether verify_pkcs7_signature() or a verify_pgp_signature() are both always builtin. And then, we run into the issue again of more complex probing for availability of the algs compared to simple ... #if defined(CONFIG_SYSTEM_DATA_VERIFICATION) && defined(CONFIG_XYZ) case BPF_FUNC_verify_signature_xyz: return ..._proto; #endif ... which bpftool and others easily understand. >>> + } >>> +} >>> + >>> +static const struct bpf_func_proto bpf_verify_signature_proto = { >>> + .func = bpf_verify_signature, >>> + .gpl_only = false, >>> + .ret_type = RET_INTEGER, >>> + .arg1_type = ARG_PTR_TO_MEM, >>> + .arg2_type = ARG_CONST_SIZE_OR_ZERO, >> >> Can verify_pkcs7_signature() handle null/0 len for data* args? > > Shouldn't ARG_PTR_TO_MEM require valid memory? 0 len should > not be a problem. check_helper_mem_access() has: /* Allow zero-byte read from NULL, regardless of pointer type */ if (zero_size_allowed && access_size == 0 && register_is_null(reg)) return 0; So NULL/0 pair can be passed. Maybe good to add these corner cases to the test_progs selftest additions then if it's needed. >>> + .arg3_type = ARG_PTR_TO_MEM, >>> + .arg4_type = ARG_CONST_SIZE_OR_ZERO, >> >> Ditto for sig* args? >> >>> + .arg5_type = ARG_ANYTHING, >>> + .allowed = bpf_ima_inode_hash_allowed, >>> +}; >>> +#endif >>> + >>> static const struct bpf_func_proto * >>> bpf_lsm_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) >>> { >>> @@ -158,6 +200,10 @@ bpf_lsm_func_proto(enum bpf_func_id func_id, >> const struct bpf_prog *prog) >>> return prog->aux->sleepable ? &bpf_ima_file_hash_proto : >> NULL; >>> case BPF_FUNC_get_attach_cookie: >>> return bpf_prog_has_trampoline(prog) ? >> &bpf_get_attach_cookie_proto : NULL; >>> +#ifdef CONFIG_SYSTEM_DATA_VERIFICATION >>> + case BPF_FUNC_verify_signature: >>> + return prog->aux->sleepable ? &bpf_verify_signature_proto : >> NULL; >>> +#endif >>> default: >>> return tracing_prog_func_proto(func_id, prog); >>> }