Commit cdbde084 authored by Alexei Starovoitov's avatar Alexei Starovoitov
Browse files

Merge branch 'bpf-make-trusted-args-nullable'

Vadim Fedorenko says:

====================
bpf: make trusted args nullable

Current verifier checks for the arg to be nullable after checking for
certain pointer types. It prevents programs to pass NULL to kfunc args
even if they are marked as nullable. This patchset adjusts verifier and
changes bpf crypto kfuncs to allow null for IV parameter which is
optional for some ciphers. Benchmark shows ~4% improvements when there
is no need to initialise 0-sized dynptr.

v3:
- add special selftest for nullable parameters
v2:
- adjust kdoc accordingly
====================

Link: https://lore.kernel.org/r/20240613211817.1551967-1-vadfed@meta.com


Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parents 373a4e13 2d45ab1e
Loading
Loading
Loading
Loading
+13 −13
Original line number Diff line number Diff line
@@ -275,7 +275,7 @@ static int bpf_crypto_crypt(const struct bpf_crypto_ctx *ctx,
	if (__bpf_dynptr_is_rdonly(dst))
		return -EINVAL;

	siv_len = __bpf_dynptr_size(siv);
	siv_len = siv ? __bpf_dynptr_size(siv) : 0;
	src_len = __bpf_dynptr_size(src);
	dst_len = __bpf_dynptr_size(dst);
	if (!src_len || !dst_len)
@@ -306,18 +306,18 @@ static int bpf_crypto_crypt(const struct bpf_crypto_ctx *ctx,
 * @ctx:		The crypto context being used. The ctx must be a trusted pointer.
 * @src:		bpf_dynptr to the encrypted data. Must be a trusted pointer.
 * @dst:		bpf_dynptr to the buffer where to store the result. Must be a trusted pointer.
 * @siv:	bpf_dynptr to IV data and state data to be used by decryptor.
 * @siv__nullable:	bpf_dynptr to IV data and state data to be used by decryptor. May be NULL.
 *
 * Decrypts provided buffer using IV data and the crypto context. Crypto context must be configured.
 */
__bpf_kfunc int bpf_crypto_decrypt(struct bpf_crypto_ctx *ctx,
				   const struct bpf_dynptr *src,
				   const struct bpf_dynptr *dst,
				   const struct bpf_dynptr *siv)
				   const struct bpf_dynptr *siv__nullable)
{
	const struct bpf_dynptr_kern *src_kern = (struct bpf_dynptr_kern *)src;
	const struct bpf_dynptr_kern *dst_kern = (struct bpf_dynptr_kern *)dst;
	const struct bpf_dynptr_kern *siv_kern = (struct bpf_dynptr_kern *)siv;
	const struct bpf_dynptr_kern *siv_kern = (struct bpf_dynptr_kern *)siv__nullable;

	return bpf_crypto_crypt(ctx, src_kern, dst_kern, siv_kern, true);
}
@@ -326,19 +326,19 @@ __bpf_kfunc int bpf_crypto_decrypt(struct bpf_crypto_ctx *ctx,
 * bpf_crypto_encrypt() - Encrypt buffer using configured context and IV provided.
 * @ctx:		The crypto context being used. The ctx must be a trusted pointer.
 * @src:		bpf_dynptr to the plain data. Must be a trusted pointer.
 * @dst:	bpf_dynptr to buffer where to store the result. Must be a trusted pointer.
 * @siv:	bpf_dynptr to IV data and state data to be used by decryptor.
 * @dst:		bpf_dynptr to the buffer where to store the result. Must be a trusted pointer.
 * @siv__nullable:	bpf_dynptr to IV data and state data to be used by decryptor. May be NULL.
 *
 * Encrypts provided buffer using IV data and the crypto context. Crypto context must be configured.
 */
__bpf_kfunc int bpf_crypto_encrypt(struct bpf_crypto_ctx *ctx,
				   const struct bpf_dynptr *src,
				   const struct bpf_dynptr *dst,
				   const struct bpf_dynptr *siv)
				   const struct bpf_dynptr *siv__nullable)
{
	const struct bpf_dynptr_kern *src_kern = (struct bpf_dynptr_kern *)src;
	const struct bpf_dynptr_kern *dst_kern = (struct bpf_dynptr_kern *)dst;
	const struct bpf_dynptr_kern *siv_kern = (struct bpf_dynptr_kern *)siv;
	const struct bpf_dynptr_kern *siv_kern = (struct bpf_dynptr_kern *)siv__nullable;

	return bpf_crypto_crypt(ctx, src_kern, dst_kern, siv_kern, false);
}
+3 −3
Original line number Diff line number Diff line
@@ -11187,6 +11187,9 @@ get_kfunc_ptr_arg_type(struct bpf_verifier_env *env,
	if (btf_is_prog_ctx_type(&env->log, meta->btf, t, resolve_prog_type(env->prog), argno))
		return KF_ARG_PTR_TO_CTX;
	if (is_kfunc_arg_nullable(meta->btf, &args[argno]) && register_is_null(reg))
		return KF_ARG_PTR_TO_NULL;
	if (is_kfunc_arg_alloc_obj(meta->btf, &args[argno]))
		return KF_ARG_PTR_TO_ALLOC_BTF_ID;
@@ -11232,9 +11235,6 @@ get_kfunc_ptr_arg_type(struct bpf_verifier_env *env,
	if (is_kfunc_arg_callback(env, meta->btf, &args[argno]))
		return KF_ARG_PTR_TO_CALLBACK;
	if (is_kfunc_arg_nullable(meta->btf, &args[argno]) && register_is_null(reg))
		return KF_ARG_PTR_TO_NULL;
	if (argno + 1 < nargs &&
	    (is_kfunc_arg_mem_size(meta->btf, &args[argno + 1], &regs[regno + 1]) ||
	     is_kfunc_arg_const_mem_size(meta->btf, &args[argno + 1], &regs[regno + 1])))
+6 −0
Original line number Diff line number Diff line
@@ -154,6 +154,11 @@ __bpf_kfunc void bpf_kfunc_common_test(void)
{
}

__bpf_kfunc void bpf_kfunc_dynptr_test(struct bpf_dynptr *ptr,
				       struct bpf_dynptr *ptr__nullable)
{
}

struct bpf_testmod_btf_type_tag_1 {
	int a;
};
@@ -363,6 +368,7 @@ BTF_ID_FLAGS(func, bpf_iter_testmod_seq_new, KF_ITER_NEW)
BTF_ID_FLAGS(func, bpf_iter_testmod_seq_next, KF_ITER_NEXT | KF_RET_NULL)
BTF_ID_FLAGS(func, bpf_iter_testmod_seq_destroy, KF_ITER_DESTROY)
BTF_ID_FLAGS(func, bpf_kfunc_common_test)
BTF_ID_FLAGS(func, bpf_kfunc_dynptr_test)
BTF_KFUNCS_END(bpf_testmod_common_kfunc_ids)

static const struct btf_kfunc_id_set bpf_testmod_common_kfunc_set = {
+1 −0
Original line number Diff line number Diff line
@@ -134,4 +134,5 @@ int bpf_kfunc_call_sock_sendmsg(struct sendmsg_args *args) __ksym;
int bpf_kfunc_call_kernel_getsockname(struct addr_args *args) __ksym;
int bpf_kfunc_call_kernel_getpeername(struct addr_args *args) __ksym;

void bpf_kfunc_dynptr_test(struct bpf_dynptr *ptr, struct bpf_dynptr *ptr__nullable) __ksym;
#endif /* _BPF_TESTMOD_KFUNC_H */
+11 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0

/* Copyright (c) 2024 Meta Platforms, Inc */

#include <test_progs.h>
#include "test_kfunc_param_nullable.skel.h"

void test_kfunc_param_nullable(void)
{
	RUN_TESTS(test_kfunc_param_nullable);
}
Loading