From patchwork Mon Oct 23 16:03:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Song Liu X-Patchwork-Id: 13433100 X-Patchwork-Delegate: bpf@iogearbox.net 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 CF0181C28A; Mon, 23 Oct 2023 16:04:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="YOcshhNB" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8B10FC433C7; Mon, 23 Oct 2023 16:03:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1698077041; bh=dZ2GcRRuvMMRyP0Qo7gMpZJYT+xU7qjYOosJK+G6G5s=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=YOcshhNBFaLxhfrYc/dYJLQzHP8/upkjFyQ32KdRahpbIc1J+yU+9n2q/bzZMdZtq 5InySebOBzHUr4XoEEKYJlccL5qxV7Kd3CPo6voxZebQmKnlCM9Cr5AJSrMdq0+f5F zRpNx66DlR1iko94f8F0vrt3bOPlDn4Nel6F40H5U68a3L/Jdhg526ouV66zpPxdZT 5Y5xdFDcaf1qdIYajK8j0U9PpuvHNGEdOMjDZRObIhw0f1T83ZQ7kaIeN2dWAOtDjk VdqzhlZdXfO3mweHkQw4s5NnVEsyGy1nosJgv08PQgGUY8dW3jr0DEfA5w1+nJlgul RL+cFieVwa3nw== From: Song Liu To: bpf@vger.kernel.org, fsverity@lists.linux.dev Cc: ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, martin.lau@kernel.org, kernel-team@meta.com, ebiggers@kernel.org, tytso@mit.edu, roberto.sassu@huaweicloud.com, Song Liu Subject: [PATCH v3 bpf-next 1/9] bpf: Expose bpf_dynptr_slice* kfuncs for in kernel use Date: Mon, 23 Oct 2023 09:03:41 -0700 Message-Id: <20231023160349.4161154-2-song@kernel.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231023160349.4161154-1-song@kernel.org> References: <20231023160349.4161154-1-song@kernel.org> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: bpf@iogearbox.net These kfuncs can be used to access the dynptr data. Expose them in bpf.h and use bpf_dynptr_slice in bpf_verify_pkcs7_signature. Signed-off-by: Song Liu --- include/linux/bpf.h | 4 ++++ kernel/trace/bpf_trace.c | 15 +++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index b4825d3cdb29..3ed3ae37cbdf 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1222,6 +1222,10 @@ enum bpf_dynptr_type { int bpf_dynptr_check_size(u32 size); u32 __bpf_dynptr_size(const struct bpf_dynptr_kern *ptr); +void *bpf_dynptr_slice(const struct bpf_dynptr_kern *ptr, u32 offset, + void *buffer__opt, u32 buffer__szk); +void *bpf_dynptr_slice_rdwr(const struct bpf_dynptr_kern *ptr, u32 offset, + void *buffer__opt, u32 buffer__szk); #ifdef CONFIG_BPF_JIT int bpf_trampoline_link_prog(struct bpf_tramp_link *link, struct bpf_trampoline *tr); diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index df697c74d519..43ed45a83ee2 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -1378,6 +1378,7 @@ __bpf_kfunc int bpf_verify_pkcs7_signature(struct bpf_dynptr_kern *data_ptr, struct bpf_dynptr_kern *sig_ptr, struct bpf_key *trusted_keyring) { + void *data, *sig; int ret; if (trusted_keyring->has_ref) { @@ -1394,10 +1395,16 @@ __bpf_kfunc int bpf_verify_pkcs7_signature(struct bpf_dynptr_kern *data_ptr, return ret; } - return verify_pkcs7_signature(data_ptr->data, - __bpf_dynptr_size(data_ptr), - sig_ptr->data, - __bpf_dynptr_size(sig_ptr), + data = bpf_dynptr_slice(data_ptr, 0, NULL, 0); + if (IS_ERR_OR_NULL(data)) + return PTR_ERR(data); + + sig = bpf_dynptr_slice(sig_ptr, 0, NULL, 0); + if (IS_ERR_OR_NULL(sig)) + return PTR_ERR(sig); + + return verify_pkcs7_signature(data, __bpf_dynptr_size(data_ptr), + sig, __bpf_dynptr_size(sig_ptr), trusted_keyring->key, VERIFYING_UNSPECIFIED_SIGNATURE, NULL, NULL); From patchwork Mon Oct 23 16:03:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Song Liu X-Patchwork-Id: 13433101 X-Patchwork-Delegate: bpf@iogearbox.net 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 059F51CA96; Mon, 23 Oct 2023 16:04:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="emogXKV6" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4836EC433C7; Mon, 23 Oct 2023 16:04:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1698077044; bh=0LBNy4jEmP3QOJLS/v9sSKJshgRUg6NsdZQVstUHGPY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=emogXKV6GbYRdSu1N+OovH3lb2oAUmm/F3dQ3CeIiorOls+O7tYeqryO0XAYDFku8 nwiJRAOljnwXYkcisOmhWwUwP7fq+asxjEacrsnVL8noshRJCTaFnjhMaoFH9OtuuI v8FbGho9/604nl67Qq+zjLaw1Kx19qRxdMMuD58S2o5VBG2QcwI41WvIhGDktca4cf PAsErxf9iXX9SAIGlDBX/iEDWzOrfjLZ3WFMQumydl/e9p+6wyk4hm6Ccg+YTw8pVx PnZnVzwhkzyza5wL7Y8Zu5fJGLwfmAuaVEbvWCnD/t0qWDwV6MhBBH9yAUfNoZCmmV D0pai9pzXukJw== From: Song Liu To: bpf@vger.kernel.org, fsverity@lists.linux.dev Cc: ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, martin.lau@kernel.org, kernel-team@meta.com, ebiggers@kernel.org, tytso@mit.edu, roberto.sassu@huaweicloud.com, Song Liu Subject: [PATCH v3 bpf-next 2/9] bpf: Factor out helper check_reg_const_str() Date: Mon, 23 Oct 2023 09:03:42 -0700 Message-Id: <20231023160349.4161154-3-song@kernel.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231023160349.4161154-1-song@kernel.org> References: <20231023160349.4161154-1-song@kernel.org> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: bpf@iogearbox.net This helper will be used to check whether a kfunc arg points to const string. Add a type check (PTR_TO_MAP_VALUE) in case the helper is misused in the future. Signed-off-by: Song Liu --- kernel/bpf/verifier.c | 85 +++++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 36 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index e9bc5d4a25a1..6ce5f0fbad84 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -8265,6 +8265,54 @@ static enum bpf_dynptr_type dynptr_get_type(struct bpf_verifier_env *env, return state->stack[spi].spilled_ptr.dynptr.type; } +static int check_reg_const_str(struct bpf_verifier_env *env, + struct bpf_reg_state *reg, u32 regno) +{ + struct bpf_map *map = reg->map_ptr; + int err; + int map_off; + u64 map_addr; + char *str_ptr; + + if (WARN_ON_ONCE(reg->type != PTR_TO_MAP_VALUE)) + return -EINVAL; + + if (!bpf_map_is_rdonly(map)) { + verbose(env, "R%d does not point to a readonly map'\n", regno); + return -EACCES; + } + + if (!tnum_is_const(reg->var_off)) { + verbose(env, "R%d is not a constant address'\n", regno); + return -EACCES; + } + + if (!map->ops->map_direct_value_addr) { + verbose(env, "no direct value access support for this map type\n"); + return -EACCES; + } + + err = check_map_access(env, regno, reg->off, + map->value_size - reg->off, false, + ACCESS_HELPER); + if (err) + return err; + + map_off = reg->off + reg->var_off.value; + err = map->ops->map_direct_value_addr(map, &map_addr, map_off); + if (err) { + verbose(env, "direct value access on string failed\n"); + return err; + } + + str_ptr = (char *)(long)(map_addr); + if (!strnchr(str_ptr + map_off, map->value_size - map_off, 0)) { + verbose(env, "string is not zero-terminated\n"); + return -EINVAL; + } + return 0; +} + static int check_func_arg(struct bpf_verifier_env *env, u32 arg, struct bpf_call_arg_meta *meta, const struct bpf_func_proto *fn, @@ -8509,44 +8557,9 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, } case ARG_PTR_TO_CONST_STR: { - struct bpf_map *map = reg->map_ptr; - int map_off; - u64 map_addr; - char *str_ptr; - - if (!bpf_map_is_rdonly(map)) { - verbose(env, "R%d does not point to a readonly map'\n", regno); - return -EACCES; - } - - if (!tnum_is_const(reg->var_off)) { - verbose(env, "R%d is not a constant address'\n", regno); - return -EACCES; - } - - if (!map->ops->map_direct_value_addr) { - verbose(env, "no direct value access support for this map type\n"); - return -EACCES; - } - - err = check_map_access(env, regno, reg->off, - map->value_size - reg->off, false, - ACCESS_HELPER); + err = check_reg_const_str(env, reg, regno); if (err) return err; - - map_off = reg->off + reg->var_off.value; - err = map->ops->map_direct_value_addr(map, &map_addr, map_off); - if (err) { - verbose(env, "direct value access on string failed\n"); - return err; - } - - str_ptr = (char *)(long)(map_addr); - if (!strnchr(str_ptr + map_off, map->value_size - map_off, 0)) { - verbose(env, "string is not zero-terminated\n"); - return -EINVAL; - } break; } case ARG_PTR_TO_KPTR: From patchwork Mon Oct 23 16:03:43 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Song Liu X-Patchwork-Id: 13433102 X-Patchwork-Delegate: bpf@iogearbox.net 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 0E4AD1CA96; Mon, 23 Oct 2023 16:04:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="MguuKg/I" Received: by smtp.kernel.org (Postfix) with ESMTPSA id EB68CC433C8; Mon, 23 Oct 2023 16:04:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1698077048; bh=JktvCz8l5F4UfdnmLbTyIiMyqaaZHAVs4MnXWzRhxlA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MguuKg/I2qwNWYXPN2LoAfbfpIh+wG6tuaLknIk7TZ/VBzlA2z7BcmyDzaZznwEaE UVmoTnNrLyrOGnbqiq1MbSRCDKutCJUqKOr/CgZ8TiSPu81iDYWG7arKNXFpsnlIrK nSKAvLikQSDBYRoZjqNM7YZnU57pbkSpkZmDLaxoo9iZoPYZvItjZz2NTdBL4UsrKx v+nVtg6lBp9ECio3bVxuMSW5RY1TOYICZDCcqHKf3gSdCZYpoWWqKVspo4TccyP9RA XR1FdVqe5iwt3CbaTwguTtS/C+lYgRnbF3dXpdyHyD6IVLNP5nd9NsuOsUJGSlYw1I T99VWis1bFNYw== From: Song Liu To: bpf@vger.kernel.org, fsverity@lists.linux.dev Cc: ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, martin.lau@kernel.org, kernel-team@meta.com, ebiggers@kernel.org, tytso@mit.edu, roberto.sassu@huaweicloud.com, Song Liu Subject: [PATCH v3 bpf-next 3/9] bpf: Introduce KF_ARG_PTR_TO_CONST_STR Date: Mon, 23 Oct 2023 09:03:43 -0700 Message-Id: <20231023160349.4161154-4-song@kernel.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231023160349.4161154-1-song@kernel.org> References: <20231023160349.4161154-1-song@kernel.org> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: bpf@iogearbox.net KF_ARG_PTR_TO_CONST_STR specifies kfunc args that point to const strings. This is similar to ARG_PTR_TO_CONST_STR for helpers. Signed-off-by: Song Liu --- Documentation/bpf/kfuncs.rst | 24 ++++++++++++++++++++++++ kernel/bpf/verifier.c | 19 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/Documentation/bpf/kfuncs.rst b/Documentation/bpf/kfuncs.rst index 0d2647fb358d..e696aca08b3a 100644 --- a/Documentation/bpf/kfuncs.rst +++ b/Documentation/bpf/kfuncs.rst @@ -137,6 +137,30 @@ Either way, the returned buffer is either NULL, or of size buffer_szk. Without t annotation, the verifier will reject the program if a null pointer is passed in with a nonzero size. +2.2.5 __const_str Annotation +---------------------------- +This annotation is used to indicate that the argument is a constant string. + +An example is given below:: + + __bpf_kfunc bpf_get_file_xattr(..., const char *name__const_str, ...) + { + ... + } + +In this case, ``bpf_get_file_xattr()`` can be called as:: + + bpf_get_file_xattr(..., "xattr_name", ...); + +Or:: + + const char name[] = "xattr_name"; /* This need to be global */ + int BPF_PROG(...) + { + ... + bpf_get_file_xattr(..., name, ...); + ... + } .. _BPF_kfunc_nodef: diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 6ce5f0fbad84..a2d992ca49c4 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -10350,6 +10350,11 @@ static bool is_kfunc_arg_nullable(const struct btf *btf, const struct btf_param return __kfunc_param_match_suffix(btf, arg, "__nullable"); } +static bool is_kfunc_arg_const_str(const struct btf *btf, const struct btf_param *arg) +{ + return __kfunc_param_match_suffix(btf, arg, "__const_str"); +} + static bool is_kfunc_arg_scalar_with_name(const struct btf *btf, const struct btf_param *arg, const char *name) @@ -10493,6 +10498,7 @@ enum kfunc_ptr_arg_type { KF_ARG_PTR_TO_RB_ROOT, KF_ARG_PTR_TO_RB_NODE, KF_ARG_PTR_TO_NULL, + KF_ARG_PTR_TO_CONST_STR, }; enum special_kfunc_type { @@ -10637,6 +10643,9 @@ get_kfunc_ptr_arg_type(struct bpf_verifier_env *env, if (is_kfunc_arg_rbtree_node(meta->btf, &args[argno])) return KF_ARG_PTR_TO_RB_NODE; + if (is_kfunc_arg_const_str(meta->btf, &args[argno])) + return KF_ARG_PTR_TO_CONST_STR; + if ((base_type(reg->type) == PTR_TO_BTF_ID || reg2btf_ids[base_type(reg->type)])) { if (!btf_type_is_struct(ref_t)) { verbose(env, "kernel function %s args#%d pointer type %s %s is not supported\n", @@ -11260,6 +11269,7 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ case KF_ARG_PTR_TO_MEM_SIZE: case KF_ARG_PTR_TO_CALLBACK: case KF_ARG_PTR_TO_REFCOUNTED_KPTR: + case KF_ARG_PTR_TO_CONST_STR: /* Trusted by default */ break; default: @@ -11531,6 +11541,15 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ meta->arg_btf = reg->btf; meta->arg_btf_id = reg->btf_id; break; + case KF_ARG_PTR_TO_CONST_STR: + if (reg->type != PTR_TO_MAP_VALUE) { + verbose(env, "arg#%d doesn't point to a const string\n", i); + return -EINVAL; + } + ret = check_reg_const_str(env, reg, regno); + if (ret) + return ret; + break; } } From patchwork Mon Oct 23 16:03:44 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Song Liu X-Patchwork-Id: 13433103 X-Patchwork-Delegate: bpf@iogearbox.net 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 B7A7F1C28A; Mon, 23 Oct 2023 16:04:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="tjk1iogi" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9A0FCC433C7; Mon, 23 Oct 2023 16:04:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1698077052; bh=KegfHtw+dipb9WMoL0tp2jttgRiQoKqpiiVcpl1j3Jg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=tjk1iogiNLEaW7wZOztpkfWU38o7Ia5y5RF3HOSi7gfjYRP8zjIt2jdNZ4rziDKnY QFmouIlGJgYgSiXhVvrZ6zYdF8kRD+HvlOwu5twiXkq1iamtbPfs2rNswJSHi2ADpq aE8Dh7WMlgO4BB1ve+ndY1In7LQ0Ux0p9dvQIDdSd76xnDssne6BPlU3KKt1YIsjTv 4RkCjm+y1D3UgH1yytvJGTrJQgZFcR+kD06NbAP6qfTM6IZaztwqHQiPbSWtLL05oB sgy8Wqai7c6hccqW8KNdBm3J0t68t73ZMBdBjAN2kMpJcDijAGO9BRqMv8Wsl9i8e+ 8N1nzxph+9L1w== From: Song Liu To: bpf@vger.kernel.org, fsverity@lists.linux.dev Cc: ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, martin.lau@kernel.org, kernel-team@meta.com, ebiggers@kernel.org, tytso@mit.edu, roberto.sassu@huaweicloud.com, Song Liu Subject: [PATCH v3 bpf-next 4/9] bpf: Add kfunc bpf_get_file_xattr Date: Mon, 23 Oct 2023 09:03:44 -0700 Message-Id: <20231023160349.4161154-5-song@kernel.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231023160349.4161154-1-song@kernel.org> References: <20231023160349.4161154-1-song@kernel.org> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: bpf@iogearbox.net This kfunc can be used to read xattr of a file. To avoid recursion, only allow calling this kfunc from LSM hooks. Signed-off-by: Song Liu --- kernel/trace/bpf_trace.c | 56 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 43ed45a83ee2..4178d0e339d3 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -1436,6 +1437,61 @@ static int __init bpf_key_sig_kfuncs_init(void) late_initcall(bpf_key_sig_kfuncs_init); #endif /* CONFIG_KEYS */ +/* filesystem kfuncs */ +__diag_push(); +__diag_ignore_all("-Wmissing-prototypes", + "kfuncs which will be used in BPF programs"); + +/** + * bpf_get_file_xattr - get xattr of a file + * @file: file to get xattr from + * @name__const_str: name of the xattr + * @value_ptr: output buffer of the xattr value + * + * Get xattr *name__const_str* of *file* and store the output in *value_ptr*. + * + * Return: 0 on success, a negative value on error. + */ +__bpf_kfunc int bpf_get_file_xattr(struct file *file, const char *name__const_str, + struct bpf_dynptr_kern *value_ptr) +{ + struct dentry *dentry; + void *value; + + value = bpf_dynptr_slice_rdwr(value_ptr, 0, NULL, 0); + if (IS_ERR_OR_NULL(value)) + return PTR_ERR(value); + + dentry = file_dentry(file); + return __vfs_getxattr(dentry, dentry->d_inode, name__const_str, + value, __bpf_dynptr_size(value_ptr)); +} + +__diag_pop(); + +static int bpf_get_file_xattr_filter(const struct bpf_prog *prog, u32 kfunc_id) +{ + /* Only allow to attach from LSM hooks, to avoid recursion */ + return prog->type != BPF_PROG_TYPE_LSM ? -EACCES : 0; +} + +BTF_SET8_START(fs_kfunc_set) +BTF_ID_FLAGS(func, bpf_get_file_xattr, KF_SLEEPABLE) +BTF_SET8_END(fs_kfunc_set) + +const struct btf_kfunc_id_set bpf_fs_kfunc_set = { + .owner = THIS_MODULE, + .set = &fs_kfunc_set, + .filter = bpf_get_file_xattr_filter, +}; + +static int __init bpf_fs_kfuncs_init(void) +{ + return register_btf_kfunc_id_set(BPF_PROG_TYPE_LSM, &bpf_fs_kfunc_set); +} + +late_initcall(bpf_fs_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 Mon Oct 23 16:03:45 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Song Liu X-Patchwork-Id: 13433104 X-Patchwork-Delegate: bpf@iogearbox.net 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 D4E0B1CA96; Mon, 23 Oct 2023 16:04:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="CjQXJYBo" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 280D2C433C9; Mon, 23 Oct 2023 16:04:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1698077058; bh=bTFqEHU7zXrJ2Y3hxNQ2CnsGr9qWfYenxKwmCpjWOMY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=CjQXJYBoZjz4gVDch/f4uw7V6GJBrrp+lMUmPeaGE8QgzoP91v1iHCP9yheSzTIcO U8tN9/hLJ7CK/+OZH1A5Bjz2CgH4Y5qIpcVei6GagJ4RrB29TMbH9oHMmlXIg77lMM O1GqubGJlLIq8+S5FL44al3kVyRQarHoOcL3LZt/QSTMhtWym07i0kxTVxxamP3FnO OYsZVKhxgF2joABkPkHKLnJKRPdSxGEu/GplsvfucrNpSIkqh9Vo/b9G7PP92IGyvc /oj10b7ww4GXtXUVFvFKvFmWhzKICamGaKSYZI1x25jhTwYTeUi0hm2Zlm9zEYx5/d 3ITRqVz+TTQFA== From: Song Liu To: bpf@vger.kernel.org, fsverity@lists.linux.dev Cc: ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, martin.lau@kernel.org, kernel-team@meta.com, ebiggers@kernel.org, tytso@mit.edu, roberto.sassu@huaweicloud.com, Song Liu Subject: [PATCH v3 bpf-next 5/9] bpf, fsverity: Add kfunc bpf_get_fsverity_digest Date: Mon, 23 Oct 2023 09:03:45 -0700 Message-Id: <20231023160349.4161154-6-song@kernel.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231023160349.4161154-1-song@kernel.org> References: <20231023160349.4161154-1-song@kernel.org> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: bpf@iogearbox.net The kfunc can be used to read fsverity_digest, so that we can verify signature in BPF LSM. This kfunc is added to fs/verity/measure.c because some data structure used in the function is private to fsverity (fs/verity/fsverity_private.h). Signed-off-by: Song Liu --- fs/verity/fsverity_private.h | 10 +++++ fs/verity/init.c | 1 + fs/verity/measure.c | 82 ++++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+) diff --git a/fs/verity/fsverity_private.h b/fs/verity/fsverity_private.h index d071a6e32581..f7124f89ab6f 100644 --- a/fs/verity/fsverity_private.h +++ b/fs/verity/fsverity_private.h @@ -145,4 +145,14 @@ static inline void fsverity_init_signature(void) void __init fsverity_init_workqueue(void); +/* measure.c */ + +#ifdef CONFIG_BPF_SYSCALL +int __init fsverity_init_bpf(void); +#else +static inline int fsverity_init_bpf(void) +{ +} +#endif + #endif /* _FSVERITY_PRIVATE_H */ diff --git a/fs/verity/init.c b/fs/verity/init.c index a29f062f6047..1e207c0f71de 100644 --- a/fs/verity/init.c +++ b/fs/verity/init.c @@ -69,6 +69,7 @@ static int __init fsverity_init(void) fsverity_init_workqueue(); fsverity_init_sysctl(); fsverity_init_signature(); + fsverity_init_bpf(); return 0; } late_initcall(fsverity_init) diff --git a/fs/verity/measure.c b/fs/verity/measure.c index eec5956141da..db8b3472a16c 100644 --- a/fs/verity/measure.c +++ b/fs/verity/measure.c @@ -8,6 +8,8 @@ #include "fsverity_private.h" #include +#include +#include /** * fsverity_ioctl_measure() - get a verity file's digest @@ -100,3 +102,83 @@ int fsverity_get_digest(struct inode *inode, return hash_alg->digest_size; } EXPORT_SYMBOL_GPL(fsverity_get_digest); + +#ifdef CONFIG_BPF_SYSCALL + +/* bpf kfuncs */ +__diag_push(); +__diag_ignore_all("-Wmissing-prototypes", + "kfuncs which will be used in BPF programs"); + +/** + * bpf_get_fsverity_digest: read fsverity digest of file + * @file: file to get digest from + * @digest_ptr: (out) dynptr for struct fsverity_digest + * + * Read fsverity_digest of *file* into *digest_ptr*. + * + * Return: 0 on success, a negative value on error. + */ +__bpf_kfunc int bpf_get_fsverity_digest(struct file *file, struct bpf_dynptr_kern *digest_ptr) +{ + const struct inode *inode = file_inode(file); + struct fsverity_digest *arg; + const struct fsverity_info *vi; + const struct fsverity_hash_alg *hash_alg; + int out_digest_sz; + + arg = bpf_dynptr_slice_rdwr(digest_ptr, 0, NULL, 0); + if (IS_ERR_OR_NULL(arg)) + return PTR_ERR(arg); + + if (!IS_ALIGNED((uintptr_t)arg, __alignof__(*arg))) + return -EINVAL; + + if (__bpf_dynptr_size(digest_ptr) < sizeof(struct fsverity_digest)) + return -EINVAL; + + vi = fsverity_get_info(inode); + if (!vi) + return -ENODATA; /* not a verity file */ + + hash_alg = vi->tree_params.hash_alg; + + arg->digest_algorithm = hash_alg - fsverity_hash_algs; + arg->digest_size = hash_alg->digest_size; + + out_digest_sz = __bpf_dynptr_size(digest_ptr) - sizeof(struct fsverity_digest); + + /* copy digest */ + memcpy(arg->digest, vi->file_digest, min_t(int, hash_alg->digest_size, out_digest_sz)); + + /* fill the extra buffer with zeros */ + if (out_digest_sz > hash_alg->digest_size) + memset(arg->digest + arg->digest_size, 0, out_digest_sz - hash_alg->digest_size); + + return 0; +} + +__diag_pop(); + +static int bpf_get_fsverity_digest_filter(const struct bpf_prog *prog, u32 kfunc_id) +{ + /* Only allow to attach from LSM hooks, to avoid recursion */ + return prog->type != BPF_PROG_TYPE_LSM ? -EACCES : 0; +} + +BTF_SET8_START(fsverity_set) +BTF_ID_FLAGS(func, bpf_get_fsverity_digest) +BTF_SET8_END(fsverity_set) + +static const struct btf_kfunc_id_set bpf_fsverity_set = { + .owner = THIS_MODULE, + .set = &fsverity_set, + .filter = bpf_get_fsverity_digest_filter, +}; + +int __init fsverity_init_bpf(void) +{ + return register_btf_kfunc_id_set(BPF_PROG_TYPE_LSM, &bpf_fsverity_set); +} + +#endif /* CONFIG_BPF_SYSCALL */ From patchwork Mon Oct 23 16:03:46 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Song Liu X-Patchwork-Id: 13433105 X-Patchwork-Delegate: bpf@iogearbox.net 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 DE70418E36; Mon, 23 Oct 2023 16:04:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="SQiQSYWs" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E0B54C433C7; Mon, 23 Oct 2023 16:04:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1698077062; bh=vI21SwsFh8BbUe3W4TDykih0dYY4CzbsnALGXjMyIZk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=SQiQSYWsrNMSnoFRrdgXaT1KA4JMzhmRSo8PXzVIPrpLgttt5AZHkb7uddoMsEs4c 99+EGf9ng6xNq6MaO6JWyK+gWmqrunUOb+m/I2sesrMEmD1Bt/vRd0h+94RWCOxmnM W5BbZFh0IK6fxUS8tzAKC7ntayJOoX/T2olrpOudncUII2Pi2JBLXDMQ2ymy93U/PL qsGZFPvLl0A9x47jOxKPGjOhNLnqz3CC49mgZ4A+4R9FKHYfeIvk2RwzQ75nxGSJhJ Jt5TJDmGNb8VBaYzI4CMqEYsjqVIo6M+EzNsX/RIDSfEUOtiIBEO38Qt7QN8KLIk/4 LUcprhEz5TtBg== From: Song Liu To: bpf@vger.kernel.org, fsverity@lists.linux.dev Cc: ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, martin.lau@kernel.org, kernel-team@meta.com, ebiggers@kernel.org, tytso@mit.edu, roberto.sassu@huaweicloud.com, Song Liu Subject: [PATCH v3 bpf-next 6/9] Documentation/bpf: Add documentation for filesystem kfuncs Date: Mon, 23 Oct 2023 09:03:46 -0700 Message-Id: <20231023160349.4161154-7-song@kernel.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231023160349.4161154-1-song@kernel.org> References: <20231023160349.4161154-1-song@kernel.org> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: bpf@iogearbox.net Add a brief introduction for file system kfuncs. Signed-off-by: Song Liu --- Documentation/bpf/fs_kfuncs.rst | 21 +++++++++++++++++++++ Documentation/bpf/index.rst | 1 + 2 files changed, 22 insertions(+) create mode 100644 Documentation/bpf/fs_kfuncs.rst diff --git a/Documentation/bpf/fs_kfuncs.rst b/Documentation/bpf/fs_kfuncs.rst new file mode 100644 index 000000000000..8762c3233a3d --- /dev/null +++ b/Documentation/bpf/fs_kfuncs.rst @@ -0,0 +1,21 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. _fs_kfuncs-header-label: + +===================== +BPF filesystem kfuncs +===================== + +BPF LSM programs need to access filesystem data from LSM hooks. The following +BPF kfuncs can be used to get these data. + + * ``bpf_get_file_xattr()`` + + * ``bpf_get_fsverity_digest()`` + +To avoid recursions, these kfuncs follow the following rules: + +1. These kfuncs are only permitted from BPF LSM function. +2. These kfuncs should not call into other LSM hooks, i.e. security_*(). For + example, ``bpf_get_file_xattr()`` does not use ``vfs_getxattr()``, because + the latter calls LSM hook ``security_inode_getxattr``. diff --git a/Documentation/bpf/index.rst b/Documentation/bpf/index.rst index aeaeb35e6d4a..0bb5cb8157f1 100644 --- a/Documentation/bpf/index.rst +++ b/Documentation/bpf/index.rst @@ -21,6 +21,7 @@ that goes into great technical depth about the BPF Architecture. helpers kfuncs cpumasks + fs_kfuncs programs maps bpf_prog_run From patchwork Mon Oct 23 16:03:47 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Song Liu X-Patchwork-Id: 13433106 X-Patchwork-Delegate: bpf@iogearbox.net 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 2B62A1CAA2; Mon, 23 Oct 2023 16:04:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="tHLAoS+0" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 10A7EC433C7; Mon, 23 Oct 2023 16:04:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1698077066; bh=OkdgsQ0WxLHiL+vWRAT85wEiCaCy0CgtTgmYQnUQPbc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=tHLAoS+0TS9MtJ8XU3pLMYFqDmmQ6W84aixIb+ANPaXUZtZxaBJFBUAwaQ8HAhBcF UeXJ1ChuRid1k2V5k70DP0yzu1dyIdvzlmhhkQq0qH3//tb0Pxw3LwTB9PAkHLfIX5 uwrGiErYb/Y4Qq4Atbf50cGCbRfAGE+CWG169OmsCMxxDn0DNR+bZXQY/WPKNvc/Ut rfYv48/Q+3RWp8tZnZxQkDAp+n2ALi0Q//dX1JSG3txGBfui8nojEFZPn7Obr+FFKV FOpPWFmi8cbtKrpAwdeosg3R3ZxoJfvktt5lkQZB5+e1dHwqobDC9Eu0kWHorK0wKS p1radZoOZKMyw== From: Song Liu To: bpf@vger.kernel.org, fsverity@lists.linux.dev Cc: ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, martin.lau@kernel.org, kernel-team@meta.com, ebiggers@kernel.org, tytso@mit.edu, roberto.sassu@huaweicloud.com, Song Liu Subject: [PATCH v3 bpf-next 7/9] selftests/bpf: Sort config in alphabetic order Date: Mon, 23 Oct 2023 09:03:47 -0700 Message-Id: <20231023160349.4161154-8-song@kernel.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231023160349.4161154-1-song@kernel.org> References: <20231023160349.4161154-1-song@kernel.org> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: bpf@iogearbox.net Move CONFIG_VSOCKETS up, so the CONFIGs are in sorted order. Signed-off-by: Song Liu --- tools/testing/selftests/bpf/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config index 02dd4409200e..09da30be8728 100644 --- a/tools/testing/selftests/bpf/config +++ b/tools/testing/selftests/bpf/config @@ -81,7 +81,7 @@ CONFIG_SECURITY=y CONFIG_SECURITYFS=y CONFIG_TEST_BPF=m CONFIG_USERFAULTFD=y +CONFIG_VSOCKETS=y CONFIG_VXLAN=y CONFIG_XDP_SOCKETS=y CONFIG_XFRM_INTERFACE=y -CONFIG_VSOCKETS=y From patchwork Mon Oct 23 16:03:48 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Song Liu X-Patchwork-Id: 13433107 X-Patchwork-Delegate: bpf@iogearbox.net 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 BFA6D1C6AA; Mon, 23 Oct 2023 16:04:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="DvgnDSck" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 12EC1C433C8; Mon, 23 Oct 2023 16:04:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1698077070; bh=DrsJx+z7CBw5gcPr17+7hi6ZrI1Tg3h7aMJn29TNzq4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=DvgnDSckYnm7ZfCRkILDusMDksEMm+FR1xd4SRavVMyDdwzbQc6/lFIg/1j7vAaI8 xrhM4Xwm6pdcSbMFrs5Fln+o0bflp1O9OVfojeYn7BJCgrQaSbgSfF0L8QEQIIMsxj a6Cpg3T4kcvOgUli6pSNfT2MgEJsNVHXIT//+xXavzORmtapMpjugFSnZ5niJqNvL6 C7NyAvSUNVulVKWcLYKAt7zuDopx6lx1sEo/APvX2v3ywR1tepuAs7ORxmlcGy+AZe CTCvWYHCHY5P87PVFe+TQPj1qW6FjBUsYcd/OC84zGhOyGBuj1pannElbraVKY0XE8 nye/7IvZTp9Cw== From: Song Liu To: bpf@vger.kernel.org, fsverity@lists.linux.dev Cc: ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, martin.lau@kernel.org, kernel-team@meta.com, ebiggers@kernel.org, tytso@mit.edu, roberto.sassu@huaweicloud.com, Song Liu Subject: [PATCH v3 bpf-next 8/9] selftests/bpf: Add tests for filesystem kfuncs Date: Mon, 23 Oct 2023 09:03:48 -0700 Message-Id: <20231023160349.4161154-9-song@kernel.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231023160349.4161154-1-song@kernel.org> References: <20231023160349.4161154-1-song@kernel.org> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: bpf@iogearbox.net Add selftests for two new filesystem kfuncs: 1. bpf_get_file_xattr 2. bpf_get_fsverity_digest These tests simply make sure the two kfuncs work. CONFIG_FS_VERITY is added to selftests config. However, this is not sufficient to guarantee bpf_get_fsverity_digest works. This is because fsverity need to be enabled at file system level (for example, with tune2fs on ext4). If local file system doesn't have this feature enabled, just skip the test. Signed-off-by: Song Liu --- tools/testing/selftests/bpf/bpf_kfuncs.h | 3 + tools/testing/selftests/bpf/config | 1 + .../selftests/bpf/prog_tests/fs_kfuncs.c | 132 ++++++++++++++++++ .../selftests/bpf/progs/test_fsverity.c | 46 ++++++ .../selftests/bpf/progs/test_get_xattr.c | 37 +++++ 5 files changed, 219 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/fs_kfuncs.c create mode 100644 tools/testing/selftests/bpf/progs/test_fsverity.c create mode 100644 tools/testing/selftests/bpf/progs/test_get_xattr.c diff --git a/tools/testing/selftests/bpf/bpf_kfuncs.h b/tools/testing/selftests/bpf/bpf_kfuncs.h index 5ca68ff0b59f..c2c084a44eae 100644 --- a/tools/testing/selftests/bpf/bpf_kfuncs.h +++ b/tools/testing/selftests/bpf/bpf_kfuncs.h @@ -55,4 +55,7 @@ void *bpf_cast_to_kern_ctx(void *) __ksym; void *bpf_rdonly_cast(void *obj, __u32 btf_id) __ksym; +extern int bpf_get_file_xattr(struct file *file, const char *name, + struct bpf_dynptr *value_ptr) __ksym; +extern int bpf_get_fsverity_digest(struct file *file, struct bpf_dynptr *digest_ptr) __ksym; #endif diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config index 09da30be8728..4534a913e46c 100644 --- a/tools/testing/selftests/bpf/config +++ b/tools/testing/selftests/bpf/config @@ -23,6 +23,7 @@ CONFIG_FPROBE=y CONFIG_FTRACE_SYSCALLS=y CONFIG_FUNCTION_ERROR_INJECTION=y CONFIG_FUNCTION_TRACER=y +CONFIG_FS_VERITY=y CONFIG_GENEVE=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y diff --git a/tools/testing/selftests/bpf/prog_tests/fs_kfuncs.c b/tools/testing/selftests/bpf/prog_tests/fs_kfuncs.c new file mode 100644 index 000000000000..3084872ad1f4 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/fs_kfuncs.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#include +#include +#include +#include +#include +#include +#include "test_get_xattr.skel.h" +#include "test_fsverity.skel.h" + +static const char testfile[] = "/tmp/test_progs_fs_kfuncs"; + +static void test_xattr(void) +{ + struct test_get_xattr *skel = NULL; + int fd = -1, err; + + fd = open(testfile, O_CREAT | O_RDONLY, 0644); + if (!ASSERT_GE(fd, 0, "create_file")) + return; + + close(fd); + fd = -1; + + err = setxattr(testfile, "user.kfuncs", "hello", sizeof("hello"), 0); + if (!ASSERT_OK(err, "setxattr")) + goto out; + + skel = test_get_xattr__open_and_load(); + if (!ASSERT_OK_PTR(skel, "test_get_xattr__open_and_load")) + goto out; + + skel->bss->monitored_pid = getpid(); + err = test_get_xattr__attach(skel); + + if (!ASSERT_OK(err, "test_get_xattr__attach")) + goto out; + + fd = open(testfile, O_RDONLY, 0644); + if (!ASSERT_GE(fd, 0, "open_file")) + goto out; + + ASSERT_EQ(skel->bss->found_xattr, 1, "found_xattr"); + +out: + close(fd); + test_get_xattr__destroy(skel); + remove(testfile); +} + +#ifndef SHA256_DIGEST_SIZE +#define SHA256_DIGEST_SIZE 32 +#endif + +static void test_fsverity(void) +{ + struct fsverity_enable_arg arg = {0}; + struct test_fsverity *skel = NULL; + struct fsverity_digest *d; + int fd, err; + char buffer[4096]; + + fd = open(testfile, O_CREAT | O_RDWR, 0644); + if (!ASSERT_GE(fd, 0, "create_file")) + return; + + /* Write random buffer, so the file is not empty */ + err = write(fd, buffer, 4096); + if (!ASSERT_EQ(err, 4096, "write_file")) + goto out; + close(fd); + + /* Reopen read-only, otherwise FS_IOC_ENABLE_VERITY will fail */ + fd = open(testfile, O_RDONLY, 0644); + if (!ASSERT_GE(fd, 0, "open_file1")) + return; + + /* Enable fsverity for the file. + * If the file system doesn't support verity, this will fail. Skip + * the test in such case. + */ + arg.version = 1; + arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; + arg.block_size = 4096; + err = ioctl(fd, FS_IOC_ENABLE_VERITY, &arg); + if (err) { + printf("%s:SKIP:local fs doesn't support fsverity (%d)\n", __func__, errno); + test__skip(); + goto out; + } + + skel = test_fsverity__open_and_load(); + if (!ASSERT_OK_PTR(skel, "test_fsverity__open_and_load")) + goto out; + + /* Get fsverity_digest from ioctl */ + d = (struct fsverity_digest *)skel->bss->expected_digest; + d->digest_algorithm = FS_VERITY_HASH_ALG_SHA256; + d->digest_size = SHA256_DIGEST_SIZE; + err = ioctl(fd, FS_IOC_MEASURE_VERITY, skel->bss->expected_digest); + if (!ASSERT_OK(err, "ioctl_FS_IOC_MEASURE_VERITY")) + goto out; + + skel->bss->monitored_pid = getpid(); + err = test_fsverity__attach(skel); + if (!ASSERT_OK(err, "test_fsverity__attach")) + goto out; + + /* Reopen the file to trigger the program */ + close(fd); + fd = open(testfile, O_RDONLY); + if (!ASSERT_GE(fd, 0, "open_file2")) + goto out; + + ASSERT_EQ(skel->bss->got_fsverity, 1, "got_fsverity"); + ASSERT_EQ(skel->bss->digest_matches, 1, "digest_matches"); +out: + close(fd); + test_fsverity__destroy(skel); + remove(testfile); +} + +void test_fs_kfuncs(void) +{ + if (test__start_subtest("xattr")) + test_xattr(); + + if (test__start_subtest("fsverity")) + test_fsverity(); +} diff --git a/tools/testing/selftests/bpf/progs/test_fsverity.c b/tools/testing/selftests/bpf/progs/test_fsverity.c new file mode 100644 index 000000000000..ddba2edc8e7a --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_fsverity.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#include "vmlinux.h" +#include +#include +#include "bpf_kfuncs.h" + +char _license[] SEC("license") = "GPL"; + +#ifndef SHA256_DIGEST_SIZE +#define SHA256_DIGEST_SIZE 32 +#endif + +__u32 monitored_pid; +char expected_digest[sizeof(struct fsverity_digest) + SHA256_DIGEST_SIZE]; +char digest[sizeof(struct fsverity_digest) + SHA256_DIGEST_SIZE]; +__u32 got_fsverity; +__u32 digest_matches; + +SEC("lsm.s/file_open") +int BPF_PROG(test_file_open, struct file *f) +{ + struct bpf_dynptr digest_ptr; + __u32 pid; + int ret; + int i; + + pid = bpf_get_current_pid_tgid() >> 32; + if (pid != monitored_pid) + return 0; + + bpf_dynptr_from_mem(digest, sizeof(digest), 0, &digest_ptr); + ret = bpf_get_fsverity_digest(f, &digest_ptr); + if (ret < 0) + return 0; + got_fsverity = 1; + + for (i = 0; i < sizeof(digest); i++) { + if (digest[i] != expected_digest[i]) + return 0; + } + + digest_matches = 1; + return 0; +} diff --git a/tools/testing/selftests/bpf/progs/test_get_xattr.c b/tools/testing/selftests/bpf/progs/test_get_xattr.c new file mode 100644 index 000000000000..7eb2a4e5a3e5 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_get_xattr.c @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#include "vmlinux.h" +#include +#include +#include "bpf_kfuncs.h" + +char _license[] SEC("license") = "GPL"; + +__u32 monitored_pid; +__u32 found_xattr; + +static const char expected_value[] = "hello"; +char value[32]; + +SEC("lsm.s/file_open") +int BPF_PROG(test_file_open, struct file *f) +{ + struct bpf_dynptr value_ptr; + __u32 pid; + int ret; + + pid = bpf_get_current_pid_tgid() >> 32; + if (pid != monitored_pid) + return 0; + + bpf_dynptr_from_mem(value, sizeof(value), 0, &value_ptr); + + ret = bpf_get_file_xattr(f, "user.kfuncs", &value_ptr); + if (ret != sizeof(expected_value)) + return 0; + if (bpf_strncmp(value, ret, expected_value)) + return 0; + found_xattr = 1; + return 0; +} From patchwork Mon Oct 23 16:03:49 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Song Liu X-Patchwork-Id: 13433108 X-Patchwork-Delegate: bpf@iogearbox.net 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 95F5F1CA96; Mon, 23 Oct 2023 16:04:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="mKCni5Sb" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D9959C433C8; Mon, 23 Oct 2023 16:04:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1698077075; bh=71USteCEiuLSb1j+/UlLRKPzkVHCq+YB1wYIkQ70C1g=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=mKCni5SbcBT+2aNxMwmHAzQdTZGUVlEziSPjdxdrf2SsUUL+guRmyfGB2BImPpPbn kPThi1r/Yb19plJGZ4h5Hy9YL4evQ6wgsOAZzhMb6hX1F0+FKTWuhOT+9f/0wlz7jN xhgWn5vUiw8S6l2rylMEfurcmtY+8Dxbw7FshoZd7Hdm7IFwsqaMbq9EsLd2YJceml +IjB4jOBTwFSklKOWP01O5l6GY6DYZgmTm5s+fLG+4XTezcPNn44F+kBRt0wcD1p3R laRgYmo30DxpLjV5EDzHDhUZHuhUmPPiqqTXaLuW3McmLgDl2b3NVqLB7BWvIDhDfM ADU6zcqQxc4ww== From: Song Liu To: bpf@vger.kernel.org, fsverity@lists.linux.dev Cc: ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, martin.lau@kernel.org, kernel-team@meta.com, ebiggers@kernel.org, tytso@mit.edu, roberto.sassu@huaweicloud.com, Song Liu Subject: [PATCH v3 bpf-next 9/9] selftests/bpf: Add test that use fsverity and xattr to sign a file Date: Mon, 23 Oct 2023 09:03:49 -0700 Message-Id: <20231023160349.4161154-10-song@kernel.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231023160349.4161154-1-song@kernel.org> References: <20231023160349.4161154-1-song@kernel.org> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: bpf@iogearbox.net This selftests shows a proof of concept method to use BPF LSM to enforce file signature. This test is added to verify_pkcs7_sig, so that some existing logic can be reused. This file signature method uses fsverity, which provides reliable and efficient hash (known as digest) of the file. The file digest is signed with asymmetic key, and the signature is stored in xattr. At the run time, BPF LSM reads file digest and the signature, and then checks them against the public key. Note that this solution does NOT require FS_VERITY_BUILTIN_SIGNATURES. fsverity is only used to provide file digest. The signature verification and access control is all implemented in BPF LSM. Signed-off-by: Song Liu --- tools/testing/selftests/bpf/bpf_kfuncs.h | 7 + .../bpf/prog_tests/verify_pkcs7_sig.c | 163 +++++++++++++++++- .../selftests/bpf/progs/test_sig_in_xattr.c | 82 +++++++++ .../bpf/progs/test_verify_pkcs7_sig.c | 8 +- .../testing/selftests/bpf/verify_sig_setup.sh | 25 +++ 5 files changed, 277 insertions(+), 8 deletions(-) create mode 100644 tools/testing/selftests/bpf/progs/test_sig_in_xattr.c diff --git a/tools/testing/selftests/bpf/bpf_kfuncs.h b/tools/testing/selftests/bpf/bpf_kfuncs.h index c2c084a44eae..b4e78c1eb37b 100644 --- a/tools/testing/selftests/bpf/bpf_kfuncs.h +++ b/tools/testing/selftests/bpf/bpf_kfuncs.h @@ -58,4 +58,11 @@ void *bpf_rdonly_cast(void *obj, __u32 btf_id) __ksym; extern int bpf_get_file_xattr(struct file *file, const char *name, struct bpf_dynptr *value_ptr) __ksym; extern int bpf_get_fsverity_digest(struct file *file, struct bpf_dynptr *digest_ptr) __ksym; + +extern struct bpf_key *bpf_lookup_user_key(__u32 serial, __u64 flags) __ksym; +extern struct bpf_key *bpf_lookup_system_key(__u64 id) __ksym; +extern void bpf_key_put(struct bpf_key *key) __ksym; +extern int bpf_verify_pkcs7_signature(struct bpf_dynptr *data_ptr, + struct bpf_dynptr *sig_ptr, + struct bpf_key *trusted_keyring) __ksym; #endif diff --git a/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c b/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c index dd7f2bc70048..682b6af8d0a4 100644 --- a/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c +++ b/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c @@ -16,9 +16,12 @@ #include #include #include +#include +#include #include #include "test_verify_pkcs7_sig.skel.h" +#include "test_sig_in_xattr.skel.h" #define MAX_DATA_SIZE (1024 * 1024) #define MAX_SIG_SIZE 1024 @@ -26,6 +29,10 @@ #define VERIFY_USE_SECONDARY_KEYRING (1UL) #define VERIFY_USE_PLATFORM_KEYRING (2UL) +#ifndef SHA256_DIGEST_SIZE +#define SHA256_DIGEST_SIZE 32 +#endif + /* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */ #define MODULE_SIG_STRING "~Module signature appended~\n" @@ -254,7 +261,7 @@ static int populate_data_item_mod(struct data *data_item) return ret; } -void test_verify_pkcs7_sig(void) +static void test_verify_pkcs7_sig_from_map(void) { libbpf_print_fn_t old_print_cb; char tmp_dir_template[] = "/tmp/verify_sigXXXXXX"; @@ -400,3 +407,157 @@ void test_verify_pkcs7_sig(void) skel->bss->monitored_pid = 0; test_verify_pkcs7_sig__destroy(skel); } + +static int get_signature_size(const char *sig_path) +{ + struct stat st; + + if (stat(sig_path, &st) == -1) + return -1; + + return st.st_size; +} + +static int add_signature_to_xattr(const char *data_path, const char *sig_path) +{ + char sig[MAX_SIG_SIZE] = {0}; + int fd, size, ret; + + if (sig_path) { + fd = open(sig_path, O_RDONLY); + if (fd < 0) + return -1; + + size = read(fd, sig, MAX_SIG_SIZE); + close(fd); + if (size <= 0) + return -1; + } else { + /* no sig_path, just write 32 bytes of zeros */ + size = 32; + } + ret = setxattr(data_path, "user.sig", sig, size, 0); + if (!ASSERT_OK(ret, "setxattr")) + return -1; + + return 0; +} + +static int test_open_file(struct test_sig_in_xattr *skel, char *data_path, + pid_t pid, bool should_success, char *name) +{ + int ret; + + skel->bss->monitored_pid = pid; + ret = open(data_path, O_RDONLY); + close(ret); + skel->bss->monitored_pid = 0; + + if (should_success) { + if (!ASSERT_GE(ret, 0, name)) + return -1; + } else { + if (!ASSERT_LT(ret, 0, name)) + return -1; + } + return 0; +} + +static void test_pkcs7_sig_fsverity(void) +{ + char data_path[PATH_MAX]; + char sig_path[PATH_MAX]; + char tmp_dir_template[] = "/tmp/verify_sigXXXXXX"; + char *tmp_dir; + struct test_sig_in_xattr *skel = NULL; + pid_t pid; + int ret; + + tmp_dir = mkdtemp(tmp_dir_template); + if (!ASSERT_OK_PTR(tmp_dir, "mkdtemp")) + return; + + snprintf(data_path, PATH_MAX, "%s/data-file", tmp_dir); + snprintf(sig_path, PATH_MAX, "%s/sig-file", tmp_dir); + + ret = _run_setup_process(tmp_dir, "setup"); + if (!ASSERT_OK(ret, "_run_setup_process")) + goto out; + + ret = _run_setup_process(tmp_dir, "fsverity-create-sign"); + + if (ret) { + printf("%s: SKIP: fsverity [sign|enable] doesn't work.\n", __func__); + test__skip(); + goto out; + } + + skel = test_sig_in_xattr__open(); + if (!ASSERT_OK_PTR(skel, "test_sig_in_xattr__open")) + goto out; + ret = get_signature_size(sig_path); + if (!ASSERT_GT(ret, 0, "get_signaure_size")) + goto out; + skel->bss->sig_size = ret; + skel->bss->user_keyring_serial = syscall(__NR_request_key, "keyring", + "ebpf_testing_keyring", NULL, + KEY_SPEC_SESSION_KEYRING); + memcpy(skel->bss->digest, "FSVerity", 8); + + ret = test_sig_in_xattr__load(skel); + if (!ASSERT_OK(ret, "test_sig_in_xattr__load")) + goto out; + + ret = test_sig_in_xattr__attach(skel); + if (!ASSERT_OK(ret, "test_sig_in_xattr__attach")) + goto out; + + pid = getpid(); + + /* Case 1: fsverity is not enabled, open should succeed */ + if (test_open_file(skel, data_path, pid, true, "open_1")) + goto out; + + /* Case 2: fsverity is enabled, xattr is missing, open should + * fail + */ + ret = _run_setup_process(tmp_dir, "fsverity-enable"); + if (!ASSERT_OK(ret, "fsverity-enable")) + goto out; + if (test_open_file(skel, data_path, pid, false, "open_2")) + goto out; + + /* Case 3: fsverity is enabled, xattr has valid signature, open + * should succeed + */ + ret = add_signature_to_xattr(data_path, sig_path); + if (!ASSERT_OK(ret, "add_signature_to_xattr_1")) + goto out; + + if (test_open_file(skel, data_path, pid, true, "open_3")) + goto out; + + /* Case 4: fsverity is enabled, xattr has invalid signature, open + * should fail + */ + ret = add_signature_to_xattr(data_path, NULL); + if (!ASSERT_OK(ret, "add_signature_to_xattr_2")) + goto out; + test_open_file(skel, data_path, pid, false, "open_4"); + +out: + _run_setup_process(tmp_dir, "cleanup"); + if (!skel) + return; + + skel->bss->monitored_pid = 0; + test_sig_in_xattr__destroy(skel); +} + +void test_verify_pkcs7_sig(void) +{ + if (test__start_subtest("pkcs7_sig_from_map")) + test_verify_pkcs7_sig_from_map(); + if (test__start_subtest("pkcs7_sig_fsverity")) + test_pkcs7_sig_fsverity(); +} diff --git a/tools/testing/selftests/bpf/progs/test_sig_in_xattr.c b/tools/testing/selftests/bpf/progs/test_sig_in_xattr.c new file mode 100644 index 000000000000..820b891171d8 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_sig_in_xattr.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#include "vmlinux.h" +#include +#include +#include +#include "bpf_kfuncs.h" + +char _license[] SEC("license") = "GPL"; + +#ifndef SHA256_DIGEST_SIZE +#define SHA256_DIGEST_SIZE 32 +#endif + +#define MAX_SIG_SIZE 1024 + +/* By default, "fsverity sign" signs a file with fsverity_formatted_digest + * of the file. fsverity_formatted_digest on the kernel side is only used + * with CONFIG_FS_VERITY_BUILTIN_SIGNATURES. However, BPF LSM doesn't not + * require CONFIG_FS_VERITY_BUILTIN_SIGNATURES, so vmlinux.h may not have + * fsverity_formatted_digest. In this test, we intentionally avoid using + * fsverity_formatted_digest. + * + * Luckily, fsverity_formatted_digest is simply 8-byte magic followed by + * fsverity_digest. We use a char array of size fsverity_formatted_digest + * plus SHA256_DIGEST_SIZE. The magic part of it is filled by user space, + * and the rest of it is filled by bpf_get_fsverity_digest. + * + * Note that, generating signatures based on fsverity_formatted_digest is + * the design choice of this selftest (and "fsverity sign"). With BPF + * LSM, we have the flexibility to generate signature based on other data + * sets, for example, fsverity_digest or only the digest[] part of it. + */ +#define MAGIC_SIZE 8 +char digest[MAGIC_SIZE + sizeof(struct fsverity_digest) + SHA256_DIGEST_SIZE]; + +__u32 monitored_pid; +char sig[MAX_SIG_SIZE]; +__u32 sig_size; +__u32 user_keyring_serial; + +SEC("lsm.s/file_open") +int BPF_PROG(test_file_open, struct file *f) +{ + struct bpf_dynptr digest_ptr, sig_ptr; + struct bpf_key *trusted_keyring; + __u32 pid; + int ret; + + pid = bpf_get_current_pid_tgid() >> 32; + if (pid != monitored_pid) + return 0; + + /* digest_ptr points to fsverity_digest */ + bpf_dynptr_from_mem(digest + MAGIC_SIZE, sizeof(digest) - MAGIC_SIZE, 0, &digest_ptr); + + ret = bpf_get_fsverity_digest(f, &digest_ptr); + /* No verity, allow access */ + if (ret < 0) + return 0; + + /* Move digest_ptr to fsverity_formatted_digest */ + bpf_dynptr_from_mem(digest, sizeof(digest), 0, &digest_ptr); + + /* Read signature from xattr */ + bpf_dynptr_from_mem(sig, sizeof(sig), 0, &sig_ptr); + ret = bpf_get_file_xattr(f, "user.sig", &sig_ptr); + /* No signature, reject access */ + if (ret < 0) + return -EPERM; + + trusted_keyring = bpf_lookup_user_key(user_keyring_serial, 0); + if (!trusted_keyring) + return -ENOENT; + + /* Verify signature */ + ret = bpf_verify_pkcs7_signature(&digest_ptr, &sig_ptr, trusted_keyring); + + bpf_key_put(trusted_keyring); + return ret; +} diff --git a/tools/testing/selftests/bpf/progs/test_verify_pkcs7_sig.c b/tools/testing/selftests/bpf/progs/test_verify_pkcs7_sig.c index 7748cc23de8a..f42e9f3831a1 100644 --- a/tools/testing/selftests/bpf/progs/test_verify_pkcs7_sig.c +++ b/tools/testing/selftests/bpf/progs/test_verify_pkcs7_sig.c @@ -10,17 +10,11 @@ #include #include #include +#include "bpf_kfuncs.h" #define MAX_DATA_SIZE (1024 * 1024) #define MAX_SIG_SIZE 1024 -extern struct bpf_key *bpf_lookup_user_key(__u32 serial, __u64 flags) __ksym; -extern struct bpf_key *bpf_lookup_system_key(__u64 id) __ksym; -extern void bpf_key_put(struct bpf_key *key) __ksym; -extern int bpf_verify_pkcs7_signature(struct bpf_dynptr *data_ptr, - struct bpf_dynptr *sig_ptr, - struct bpf_key *trusted_keyring) __ksym; - __u32 monitored_pid; __u32 user_keyring_serial; __u64 system_keyring_id; diff --git a/tools/testing/selftests/bpf/verify_sig_setup.sh b/tools/testing/selftests/bpf/verify_sig_setup.sh index ba08922b4a27..7e6caa134e1a 100755 --- a/tools/testing/selftests/bpf/verify_sig_setup.sh +++ b/tools/testing/selftests/bpf/verify_sig_setup.sh @@ -60,6 +60,27 @@ cleanup() { rm -rf ${tmp_dir} } +fsverity_create_sign_file() { + local tmp_dir="$1" + + data_file=${tmp_dir}/data-file + sig_file=${tmp_dir}/sig-file + dd if=/dev/urandom of=$data_file bs=1 count=12345 2> /dev/null + fsverity sign --key ${tmp_dir}/signing_key.pem $data_file $sig_file + + # We do not want to enable fsverity on $data_file yet. Try whether + # the file system support fsverity on a different file. + touch ${tmp_dir}/tmp-file + fsverity enable ${tmp_dir}/tmp-file +} + +fsverity_enable_file() { + local tmp_dir="$1" + + data_file=${tmp_dir}/data-file + fsverity enable $data_file +} + catch() { local exit_code="$1" @@ -86,6 +107,10 @@ main() setup "${tmp_dir}" elif [[ "${action}" == "cleanup" ]]; then cleanup "${tmp_dir}" + elif [[ "${action}" == "fsverity-create-sign" ]]; then + fsverity_create_sign_file "${tmp_dir}" + elif [[ "${action}" == "fsverity-enable" ]]; then + fsverity_enable_file "${tmp_dir}" else echo "Unknown action: ${action}" exit 1