From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 94BBF126C17; Fri, 6 Jun 2025 23:29:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749252578; cv=none; b=TUE9wVb1RUatg+8YTAHANHAhF/wSG6G9ndW2qt0nCJ6BD0lvEi5TzO6NE4EYQpm274fAO3DDBYe1HibCclsHnqTIbRL5bljm9yVKPPV+luRc+kSl7+FNHDMMu60kNhrWBjBCx9C5bLimM3tZ4LVluK1XcVNkCz6F1jSk7U3+WN4= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749252578; c=relaxed/simple; bh=835MWSoe2nYoRy3aZgl+nKjMzA0rp3A9+bUlyUtQtaQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=XozYy/1Tij0+uGuWqls29NQiIfOnWLpIh3twGb2uN2sVU6KNWDrB7aHVjYsioKMn/N61iUwfEG6VQWpau44cTPM3uZ7RlhbWlCI9Jxm9L2v1d9vOUNhbzxK74gVEptgwbJ87zD8bOW15G3iP8mS+jL75gKJ1EEzO331uDcPov2Y= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=rldbgBXN; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="rldbgBXN" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 38B08C4CEEB; Fri, 6 Jun 2025 23:29:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1749252578; bh=835MWSoe2nYoRy3aZgl+nKjMzA0rp3A9+bUlyUtQtaQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=rldbgBXNncX7q4D9lvjftEhDefQpGti/7KAZQDak5t+YE98ouNcw7grTTwAivQpND S/gVoUfhzXoWdlKAUvgDlyFvH336Z1+h8NZu1T+eUPjJP0AfW6uNFGDj/cwSUpYR/K 6XjfN/LU2IwoDBYWZhCyCYstuDk1X0D9rVbgvMraxOEhI1V4Sh0clHoxc5idOXTa/M vY2GSYpEov9APi/rSY/wO92oTqrBoYHFRQTY25RJ97EKAQbgkgp0w3gWaIrt6ugBzs SfDbN+D05ZhqNiyxMe+RldB6FewNkqzgjQPsHi9FBQW5UHOxu9lnqbJtUMIVryffVs s2zxJyPouT0cA== From: KP Singh To: bpf@vger.kernel.org, linux-security-module@vger.kernel.org Cc: bboscaccy@linux.microsoft.com, paul@paul-moore.com, kys@microsoft.com, ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, KP Singh Subject: [PATCH 08/12] bpf: Implement signature verification for BPF programs Date: Sat, 7 Jun 2025 01:29:10 +0200 Message-ID: <20250606232914.317094-9-kpsingh@kernel.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250606232914.317094-1-kpsingh@kernel.org> References: <20250606232914.317094-1-kpsingh@kernel.org> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit This patch extends the BPF_PROG_LOAD command by adding three new fields to `union bpf_attr` in the user-space API: - signature: A pointer to the signature blob. - signature_size: The size of the signature blob. - keyring_id: The serial number of a loaded kernel keyring (e.g., the user or session keyring) containing the trusted public keys. When a BPF program is loaded with a signature, the kernel: 1. Retrieves the trusted keyring using the provided `keyring_id`. 2. Verifies the supplied signature against the BPF program's instruction buffer. 3. If the signature is valid and was generated by a key in the trusted keyring, the program load proceeds. 4. If no signature is provided, the load proceeds as before, allowing for backward compatibility. LSMs can chose to restrict unsigned programs and implement a security policy. 5. If signature verification fails for any reason, the program is not loaded. Signed-off-by: KP Singh --- include/linux/bpf.h | 9 +++++++- include/uapi/linux/bpf.h | 10 +++++++++ kernel/bpf/syscall.c | 39 +++++++++++++++++++++++++++++++++- kernel/trace/bpf_trace.c | 6 ++++-- tools/include/uapi/linux/bpf.h | 10 +++++++++ tools/lib/bpf/bpf.c | 2 +- 6 files changed, 71 insertions(+), 5 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 35f1a633d87a..32a41803d61c 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -2778,7 +2778,14 @@ bpf_jit_find_kfunc_model(const struct bpf_prog *prog, int bpf_get_kfunc_addr(const struct bpf_prog *prog, u32 func_id, u16 btf_fd_idx, u8 **func_addr); -struct bpf_core_ctx { +__bpf_kfunc struct bpf_key *bpf_lookup_user_key(u32 serial, u64 flags); +__bpf_kfunc struct bpf_key *bpf_lookup_system_key(u64 id); +__bpf_kfunc void bpf_key_put(struct bpf_key *bkey); +__bpf_kfunc int bpf_verify_pkcs7_signature(struct bpf_dynptr *data_p, + struct bpf_dynptr *sig_p, + struct bpf_key *trusted_keyring); + + struct bpf_core_ctx { struct bpf_verifier_log *log; const struct btf *btf; }; diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index ffd9e11befc2..5f7c82ebe10a 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -1589,6 +1589,16 @@ union bpf_attr { * continuous. */ __u32 fd_array_cnt; + /* Pointer to a buffer containing the signature of the BPF + * program. + */ + __aligned_u64 signature; + /* Size of the signature buffer in bytes. */ + __u32 signature_size; + /* ID of the kernel keyring to be used for signature + * verification. + */ + __u32 keyring_id; }; struct { /* anonymous struct used by BPF_OBJ_* commands */ diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index c81be07fa4fa..6cd5ba42d946 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -2782,8 +2782,39 @@ static bool is_perfmon_prog_type(enum bpf_prog_type prog_type) } } +static int bpf_prog_verify_signature(struct bpf_prog *prog, union bpf_attr *attr, bpfptr_t uattr) +{ + bpfptr_t usig = make_bpfptr(attr->signature, uattr.is_kernel); + struct bpf_dynptr_kern sig_ptr, insns_ptr; + struct bpf_key *key = NULL; + void *sig; + int err = 0; + + key = bpf_lookup_user_key(attr->keyring_id, 0); + if (!key) + return -ENOKEY; + + sig = kvmemdup_bpfptr(usig, attr->signature_size); + if (!sig) { + bpf_key_put(key); + return -ENOMEM; + } + + bpf_dynptr_init(&sig_ptr, sig, BPF_DYNPTR_TYPE_LOCAL, 0, + attr->signature_size); + bpf_dynptr_init(&insns_ptr, prog->insnsi, BPF_DYNPTR_TYPE_LOCAL, 0, + prog->len * sizeof(struct bpf_insn)); + + err = bpf_verify_pkcs7_signature((struct bpf_dynptr *)&insns_ptr, + (struct bpf_dynptr *)&sig_ptr, key); + + bpf_key_put(key); + kvfree(sig); + return err; +} + /* last field in 'union bpf_attr' used by this command */ -#define BPF_PROG_LOAD_LAST_FIELD fd_array_cnt +#define BPF_PROG_LOAD_LAST_FIELD keyring_id static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) { @@ -2947,6 +2978,12 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) /* eBPF programs must be GPL compatible to use GPL-ed functions */ prog->gpl_compatible = license_is_gpl_compatible(license) ? 1 : 0; + if (attr->signature) { + err = bpf_prog_verify_signature(prog, attr, uattr); + if (err) + goto free_prog; + } + prog->orig_prog = NULL; prog->jited = 0; diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 132c8be6f635..0cce39e1a9ee 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -1351,7 +1351,6 @@ __bpf_kfunc void bpf_key_put(struct bpf_key *bkey) kfree(bkey); } -#ifdef CONFIG_SYSTEM_DATA_VERIFICATION /** * bpf_verify_pkcs7_signature - verify a PKCS#7 signature * @data_p: data to verify @@ -1367,6 +1366,7 @@ __bpf_kfunc int bpf_verify_pkcs7_signature(struct bpf_dynptr *data_p, struct bpf_dynptr *sig_p, struct bpf_key *trusted_keyring) { +#ifdef CONFIG_SYSTEM_DATA_VERIFICATION struct bpf_dynptr_kern *data_ptr = (struct bpf_dynptr_kern *)data_p; struct bpf_dynptr_kern *sig_ptr = (struct bpf_dynptr_kern *)sig_p; const void *data, *sig; @@ -1396,8 +1396,10 @@ __bpf_kfunc int bpf_verify_pkcs7_signature(struct bpf_dynptr *data_p, trusted_keyring->key, VERIFYING_UNSPECIFIED_SIGNATURE, NULL, NULL); -} +#else + return -EOPNOTSUPP; #endif /* CONFIG_SYSTEM_DATA_VERIFICATION */ +} __bpf_kfunc_end_defs(); diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index ffd9e11befc2..5f7c82ebe10a 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -1589,6 +1589,16 @@ union bpf_attr { * continuous. */ __u32 fd_array_cnt; + /* Pointer to a buffer containing the signature of the BPF + * program. + */ + __aligned_u64 signature; + /* Size of the signature buffer in bytes. */ + __u32 signature_size; + /* ID of the kernel keyring to be used for signature + * verification. + */ + __u32 keyring_id; }; struct { /* anonymous struct used by BPF_OBJ_* commands */ diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 11fa2d64ccca..1a85cfa4282c 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -240,7 +240,7 @@ int bpf_prog_load(enum bpf_prog_type prog_type, const struct bpf_insn *insns, size_t insn_cnt, struct bpf_prog_load_opts *opts) { - const size_t attr_sz = offsetofend(union bpf_attr, fd_array_cnt); + const size_t attr_sz = offsetofend(union bpf_attr, keyring_id); void *finfo = NULL, *linfo = NULL; const char *func_info, *line_info; __u32 log_size, log_level, attach_prog_fd, attach_btf_obj_fd; -- 2.43.0