| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/09/01 02:29 | flow | patch-triage |
1mArgs:null Results: {
"EnableConfigs": [
"BPF_SYSCALL",
"BPF_CRYPTO",
"DEBUG_INFO_BTF"
],
"FocusSymbols": [
"bpf_crypto_ctx_create",
"bpf_crypto_ctx_release",
"bpf_crypto_ctx_acquire",
"bpf_crypto_ctx_release_dtor",
"bpf_crypto_decrypt",
"bpf_crypto_encrypt"
],
"KMSANReasoning": "The patch simplifies the BPF crypto kfuncs implementation by replacing the generic crypto tfm registration architecture with direct invocations of AES library functions (CRYPTO_LIB_AES_CBC and CRYPTO_LIB_AES_ECB). \n\nMemory safety analysis:\n1. Memory Allocation \u0026 Initialization: The context `struct bpf_crypto_ctx` is allocated with `kzalloc_obj`, ensuring all fields (including `enum bpf_crypto_algo_id` and the `aes_key` union) are zero-initialized. Key setup is handled by `aes_preparekey()`. Cleanup is handled via `kfree_sensitive()`.\n2. Buffers \u0026 Info Leaks: Data encryption and decryption operate directly on dynptr buffers supplied by BPF programs after verifying block alignment and bounds (`AES_BLOCK_SIZE` checks, `dst_len \u003e= src_len`). No uninitialized kernel memory or struct padding is copied to user space or used in branching/control flow.\n3. Sanitizer Applicability: Any potential out-of-bounds dynptr accesses, buffer length calculation bugs, or lifetime/refcounting issues are covered by KASAN and standard BPF verifier/debug infrastructure. There are no uninitialized memory read risks or information leaks requiring a dedicated KMSAN session.",
"NeedsKMSAN": false,
"Reasoning": "The patch refactors BPF crypto support by removing the dynamic crypto type registration interface and implementing direct AES-CBC and AES-ECB library integration. It introduces CONFIG_BPF_CRYPTO and modifies the BPF crypto kfunc handlers (context creation, key setup, encryption, decryption, and lifecycle management), making these functions important targets for BPF program fuzzing.",
"WorthFuzzing": true
} |
| 1/1 | 2026/09/01 02:29 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 97b409223e251e0a20b889ab7a76b5978328fcee\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Tue Sep 1 02:29:23 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/MAINTAINERS b/MAINTAINERS\nindex 3a19da74d00c9..16f13270ce1f9 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -4936,8 +4936,6 @@ BPF [CRYPTO]\n M:\tVadim Fedorenko \u003cvadim.fedorenko@linux.dev\u003e\n L:\tbpf@vger.kernel.org\n S:\tMaintained\n-F:\tcrypto/bpf_crypto_skcipher.c\n-F:\tinclude/linux/bpf_crypto.h\n F:\tkernel/bpf/crypto.c\n \n BPF [DOCUMENTATION] (Related to Standardization)\ndiff --git a/crypto/Makefile b/crypto/Makefile\nindex 8386d55a9755e..33bb5ad595e8f 100644\n--- a/crypto/Makefile\n+++ b/crypto/Makefile\n@@ -22,9 +22,6 @@ crypto_skcipher-y += lskcipher.o\n crypto_skcipher-y += skcipher.o\n \n obj-$(CONFIG_CRYPTO_SKCIPHER2) += crypto_skcipher.o\n-ifeq ($(CONFIG_BPF_SYSCALL),y)\n-obj-$(CONFIG_CRYPTO_SKCIPHER2) += bpf_crypto_skcipher.o\n-endif\n \n obj-$(CONFIG_CRYPTO_SEQIV) += seqiv.o\n obj-$(CONFIG_CRYPTO_ECHAINIV) += echainiv.o\ndiff --git a/crypto/bpf_crypto_skcipher.c b/crypto/bpf_crypto_skcipher.c\ndeleted file mode 100644\nindex a88798d3e8c87..0000000000000\n--- a/crypto/bpf_crypto_skcipher.c\n+++ /dev/null\n@@ -1,83 +0,0 @@\n-// SPDX-License-Identifier: GPL-2.0-only\n-/* Copyright (c) 2024 Meta, Inc */\n-#include \u003clinux/types.h\u003e\n-#include \u003clinux/module.h\u003e\n-#include \u003clinux/bpf_crypto.h\u003e\n-#include \u003ccrypto/skcipher.h\u003e\n-\n-static void *bpf_crypto_lskcipher_alloc_tfm(const char *algo)\n-{\n-\treturn crypto_alloc_lskcipher(algo, 0, 0);\n-}\n-\n-static void bpf_crypto_lskcipher_free_tfm(void *tfm)\n-{\n-\tcrypto_free_lskcipher(tfm);\n-}\n-\n-static int bpf_crypto_lskcipher_has_algo(const char *algo)\n-{\n-\treturn crypto_has_skcipher(algo, CRYPTO_ALG_TYPE_LSKCIPHER, CRYPTO_ALG_TYPE_MASK);\n-}\n-\n-static int bpf_crypto_lskcipher_setkey(void *tfm, const u8 *key, unsigned int keylen)\n-{\n-\treturn crypto_lskcipher_setkey(tfm, key, keylen);\n-}\n-\n-static u32 bpf_crypto_lskcipher_get_flags(void *tfm)\n-{\n-\treturn crypto_lskcipher_get_flags(tfm);\n-}\n-\n-static unsigned int bpf_crypto_lskcipher_ivsize(void *tfm)\n-{\n-\treturn crypto_lskcipher_ivsize(tfm);\n-}\n-\n-static unsigned int bpf_crypto_lskcipher_statesize(void *tfm)\n-{\n-\treturn crypto_lskcipher_statesize(tfm);\n-}\n-\n-static int bpf_crypto_lskcipher_encrypt(void *tfm, const u8 *src, u8 *dst,\n-\t\t\t\t\tunsigned int len, u8 *siv)\n-{\n-\treturn crypto_lskcipher_encrypt(tfm, src, dst, len, siv);\n-}\n-\n-static int bpf_crypto_lskcipher_decrypt(void *tfm, const u8 *src, u8 *dst,\n-\t\t\t\t\tunsigned int len, u8 *siv)\n-{\n-\treturn crypto_lskcipher_decrypt(tfm, src, dst, len, siv);\n-}\n-\n-static const struct bpf_crypto_type bpf_crypto_lskcipher_type = {\n-\t.alloc_tfm\t= bpf_crypto_lskcipher_alloc_tfm,\n-\t.free_tfm\t= bpf_crypto_lskcipher_free_tfm,\n-\t.has_algo\t= bpf_crypto_lskcipher_has_algo,\n-\t.setkey\t\t= bpf_crypto_lskcipher_setkey,\n-\t.encrypt\t= bpf_crypto_lskcipher_encrypt,\n-\t.decrypt\t= bpf_crypto_lskcipher_decrypt,\n-\t.ivsize\t\t= bpf_crypto_lskcipher_ivsize,\n-\t.statesize\t= bpf_crypto_lskcipher_statesize,\n-\t.get_flags\t= bpf_crypto_lskcipher_get_flags,\n-\t.owner\t\t= THIS_MODULE,\n-\t.name\t\t= \"skcipher\",\n-};\n-\n-static int __init bpf_crypto_skcipher_init(void)\n-{\n-\treturn bpf_crypto_register_type(\u0026bpf_crypto_lskcipher_type);\n-}\n-\n-static void __exit bpf_crypto_skcipher_exit(void)\n-{\n-\tint err = bpf_crypto_unregister_type(\u0026bpf_crypto_lskcipher_type);\n-\tWARN_ON_ONCE(err);\n-}\n-\n-module_init(bpf_crypto_skcipher_init);\n-module_exit(bpf_crypto_skcipher_exit);\n-MODULE_LICENSE(\"GPL\");\n-MODULE_DESCRIPTION(\"Symmetric key cipher support for BPF\");\ndiff --git a/include/linux/bpf_crypto.h b/include/linux/bpf_crypto.h\ndeleted file mode 100644\nindex a41e71d4e2d9f..0000000000000\n--- a/include/linux/bpf_crypto.h\n+++ /dev/null\n@@ -1,24 +0,0 @@\n-/* SPDX-License-Identifier: GPL-2.0-only */\n-/* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */\n-#ifndef _BPF_CRYPTO_H\n-#define _BPF_CRYPTO_H\n-\n-struct bpf_crypto_type {\n-\tvoid *(*alloc_tfm)(const char *algo);\n-\tvoid (*free_tfm)(void *tfm);\n-\tint (*has_algo)(const char *algo);\n-\tint (*setkey)(void *tfm, const u8 *key, unsigned int keylen);\n-\tint (*setauthsize)(void *tfm, unsigned int authsize);\n-\tint (*encrypt)(void *tfm, const u8 *src, u8 *dst, unsigned int len, u8 *iv);\n-\tint (*decrypt)(void *tfm, const u8 *src, u8 *dst, unsigned int len, u8 *iv);\n-\tunsigned int (*ivsize)(void *tfm);\n-\tunsigned int (*statesize)(void *tfm);\n-\tu32 (*get_flags)(void *tfm);\n-\tstruct module *owner;\n-\tchar name[14];\n-};\n-\n-int bpf_crypto_register_type(const struct bpf_crypto_type *type);\n-int bpf_crypto_unregister_type(const struct bpf_crypto_type *type);\n-\n-#endif /* _BPF_CRYPTO_H */\ndiff --git a/kernel/bpf/Kconfig b/kernel/bpf/Kconfig\nindex eb3de35734f09..822599b42be2e 100644\n--- a/kernel/bpf/Kconfig\n+++ b/kernel/bpf/Kconfig\n@@ -87,6 +87,15 @@ config BPF_UNPRIV_DEFAULT_OFF\n \n \t If you are unsure how to answer this question, answer Y.\n \n+config BPF_CRYPTO\n+\tdef_bool y\n+\tdepends on BPF_SYSCALL\n+\tselect CRYPTO_LIB_AES_CBC\n+\tselect CRYPTO_LIB_AES_ECB\n+\thelp\n+\t Provide the kfuncs needed for BPF programs to encrypt and decrypt\n+\t data. The supported algorithms are AES-CBC and AES-ECB.\n+\n source \"kernel/bpf/preload/Kconfig\"\n \n config BPF_LSM\ndiff --git a/kernel/bpf/Makefile b/kernel/bpf/Makefile\nindex 90255d80e5be6..ab2e5d2782e6e 100644\n--- a/kernel/bpf/Makefile\n+++ b/kernel/bpf/Makefile\n@@ -55,9 +55,7 @@ obj-$(CONFIG_BPF_SYSCALL) += cpumask.o\n # semantics within pahole are revisited accordingly.\n obj-${CONFIG_BPF_LSM} += bpf_lsm_proto.o bpf_lsm.o\n endif\n-ifneq ($(CONFIG_CRYPTO),)\n-obj-$(CONFIG_BPF_SYSCALL) += crypto.o\n-endif\n+obj-$(CONFIG_BPF_CRYPTO) += crypto.o\n obj-$(CONFIG_BPF_PRELOAD) += preload/\n \n obj-$(CONFIG_BPF_SYSCALL) += relo_core.o\ndiff --git a/kernel/bpf/crypto.c b/kernel/bpf/crypto.c\nindex 51f89cecefb4d..8cdc16f9b374a 100644\n--- a/kernel/bpf/crypto.c\n+++ b/kernel/bpf/crypto.c\n@@ -1,19 +1,13 @@\n // SPDX-License-Identifier: GPL-2.0-only\n /* Copyright (c) 2024 Meta, Inc */\n #include \u003clinux/bpf.h\u003e\n-#include \u003clinux/bpf_crypto.h\u003e\n #include \u003clinux/bpf_mem_alloc.h\u003e\n #include \u003clinux/btf.h\u003e\n #include \u003clinux/btf_ids.h\u003e\n #include \u003clinux/filter.h\u003e\n-#include \u003clinux/scatterlist.h\u003e\n #include \u003clinux/skbuff.h\u003e\n-#include \u003ccrypto/skcipher.h\u003e\n-\n-struct bpf_crypto_type_list {\n-\tconst struct bpf_crypto_type *type;\n-\tstruct list_head list;\n-};\n+#include \u003ccrypto/aes-cbc.h\u003e\n+#include \u003ccrypto/aes-ecb.h\u003e\n \n /* BPF crypto initialization parameters struct */\n /**\n@@ -36,94 +30,53 @@ struct bpf_crypto_params {\n \tu32 authsize;\n };\n \n-static LIST_HEAD(bpf_crypto_types);\n-static DECLARE_RWSEM(bpf_crypto_types_sem);\n+enum bpf_crypto_algo_id {\n+\tBPF_ALGO_AES_CBC,\n+\tBPF_ALGO_AES_ECB,\n+};\n+\n+static const struct {\n+\tconst char *type_name;\n+\tconst char *algo_name;\n+\tenum bpf_crypto_algo_id algo;\n+} bpf_crypto_algos[] = {\n+\t{ \"skcipher\", \"cbc(aes)\", BPF_ALGO_AES_CBC },\n+\t{ \"skcipher\", \"ecb(aes)\", BPF_ALGO_AES_ECB },\n+};\n+\n+static bool bpf_crypto_find_algo(const struct bpf_crypto_params *params,\n+\t\t\t\t enum bpf_crypto_algo_id *id_ret)\n+{\n+\tfor (size_t i = 0; i \u003c ARRAY_SIZE(bpf_crypto_algos); i++) {\n+\t\tif (strncmp(bpf_crypto_algos[i].type_name, params-\u003etype,\n+\t\t\t sizeof(params-\u003etype)) == 0 \u0026\u0026\n+\t\t strncmp(bpf_crypto_algos[i].algo_name, params-\u003ealgo,\n+\t\t\t sizeof(params-\u003ealgo)) == 0) {\n+\t\t\t*id_ret = bpf_crypto_algos[i].algo;\n+\t\t\treturn true;\n+\t\t}\n+\t}\n+\treturn false;\n+}\n \n /**\n * struct bpf_crypto_ctx - refcounted BPF crypto context structure\n- * @type:\tThe pointer to bpf crypto type\n- * @tfm:\tThe pointer to instance of crypto API struct.\n- * @siv_len: Size of IV and state storage for cipher\n+ * @algo:\tThe crypto algorithm ID\n+ * @key:\tThe crypto key\n * @rcu:\tThe RCU head used to free the crypto context with RCU safety.\n * @usage:\tObject reference counter. When the refcount goes to 0, the\n *\t\tmemory is released back to the BPF allocator, which provides\n *\t\tRCU safety.\n */\n struct bpf_crypto_ctx {\n-\tconst struct bpf_crypto_type *type;\n-\tvoid *tfm;\n-\tu32 siv_len;\n+\tenum bpf_crypto_algo_id algo;\n+\tunion {\n+\t\tstruct aes_key aes;\n+\t} key;\n \tstruct rcu_head rcu;\n \trefcount_t usage;\n };\n \n-int bpf_crypto_register_type(const struct bpf_crypto_type *type)\n-{\n-\tstruct bpf_crypto_type_list *node;\n-\tint err = -EBUSY;\n-\n-\tdown_write(\u0026bpf_crypto_types_sem);\n-\tlist_for_each_entry(node, \u0026bpf_crypto_types, list) {\n-\t\tif (!strcmp(node-\u003etype-\u003ename, type-\u003ename))\n-\t\t\tgoto unlock;\n-\t}\n-\n-\tnode = kmalloc_obj(*node);\n-\terr = -ENOMEM;\n-\tif (!node)\n-\t\tgoto unlock;\n-\n-\tnode-\u003etype = type;\n-\tlist_add(\u0026node-\u003elist, \u0026bpf_crypto_types);\n-\terr = 0;\n-\n-unlock:\n-\tup_write(\u0026bpf_crypto_types_sem);\n-\n-\treturn err;\n-}\n-EXPORT_SYMBOL_GPL(bpf_crypto_register_type);\n-\n-int bpf_crypto_unregister_type(const struct bpf_crypto_type *type)\n-{\n-\tstruct bpf_crypto_type_list *node;\n-\tint err = -ENOENT;\n-\n-\tdown_write(\u0026bpf_crypto_types_sem);\n-\tlist_for_each_entry(node, \u0026bpf_crypto_types, list) {\n-\t\tif (strcmp(node-\u003etype-\u003ename, type-\u003ename))\n-\t\t\tcontinue;\n-\n-\t\tlist_del(\u0026node-\u003elist);\n-\t\tkfree(node);\n-\t\terr = 0;\n-\t\tbreak;\n-\t}\n-\tup_write(\u0026bpf_crypto_types_sem);\n-\n-\treturn err;\n-}\n-EXPORT_SYMBOL_GPL(bpf_crypto_unregister_type);\n-\n-static const struct bpf_crypto_type *bpf_crypto_get_type(const char *name)\n-{\n-\tconst struct bpf_crypto_type *type = ERR_PTR(-ENOENT);\n-\tstruct bpf_crypto_type_list *node;\n-\n-\tdown_read(\u0026bpf_crypto_types_sem);\n-\tlist_for_each_entry(node, \u0026bpf_crypto_types, list) {\n-\t\tif (strcmp(node-\u003etype-\u003ename, name))\n-\t\t\tcontinue;\n-\n-\t\tif (try_module_get(node-\u003etype-\u003eowner))\n-\t\t\ttype = node-\u003etype;\n-\t\tbreak;\n-\t}\n-\tup_read(\u0026bpf_crypto_types_sem);\n-\n-\treturn type;\n-}\n-\n __bpf_kfunc_start_defs();\n \n /**\n@@ -146,7 +99,6 @@ __bpf_kfunc struct bpf_crypto_ctx *\n bpf_crypto_ctx_create(const struct bpf_crypto_params *params, u32 params__sz,\n \t\t int *err)\n {\n-\tconst struct bpf_crypto_type *type;\n \tstruct bpf_crypto_ctx *ctx;\n \n \tif (!params || params-\u003ereserved[0] || params-\u003ereserved[1] ||\n@@ -155,69 +107,40 @@ bpf_crypto_ctx_create(const struct bpf_crypto_params *params, u32 params__sz,\n \t\treturn NULL;\n \t}\n \n-\ttype = bpf_crypto_get_type(params-\u003etype);\n-\tif (IS_ERR(type)) {\n-\t\t*err = PTR_ERR(type);\n-\t\treturn NULL;\n-\t}\n-\n-\tif (!type-\u003ehas_algo(params-\u003ealgo)) {\n-\t\t*err = -EOPNOTSUPP;\n-\t\tgoto err_module_put;\n-\t}\n-\n-\tif (!!params-\u003eauthsize ^ !!type-\u003esetauthsize) {\n-\t\t*err = -EOPNOTSUPP;\n-\t\tgoto err_module_put;\n-\t}\n-\n-\tif (!params-\u003ekey_len || params-\u003ekey_len \u003e sizeof(params-\u003ekey)) {\n-\t\t*err = -EINVAL;\n-\t\tgoto err_module_put;\n-\t}\n-\n \tctx = kzalloc_obj(*ctx);\n \tif (!ctx) {\n \t\t*err = -ENOMEM;\n-\t\tgoto err_module_put;\n+\t\treturn NULL;\n \t}\n \n-\tctx-\u003etype = type;\n-\tctx-\u003etfm = type-\u003ealloc_tfm(params-\u003ealgo);\n-\tif (IS_ERR(ctx-\u003etfm)) {\n-\t\t*err = PTR_ERR(ctx-\u003etfm);\n-\t\tgoto err_free_ctx;\n+\tif (!bpf_crypto_find_algo(params, \u0026ctx-\u003ealgo)) {\n+\t\t*err = -ENOENT;\n+\t\tgoto out;\n \t}\n \n-\tif (params-\u003eauthsize) {\n-\t\t*err = type-\u003esetauthsize(ctx-\u003etfm, params-\u003eauthsize);\n-\t\tif (*err)\n-\t\t\tgoto err_free_tfm;\n+\tswitch (ctx-\u003ealgo) {\n+\tcase BPF_ALGO_AES_CBC:\n+\tcase BPF_ALGO_AES_ECB:\n+\t\tif (params-\u003eauthsize)\n+\t\t\t*err = -EOPNOTSUPP;\n+\t\telse\n+\t\t\t*err = aes_preparekey(\u0026ctx-\u003ekey.aes, params-\u003ekey,\n+\t\t\t\t\t params-\u003ekey_len);\n+\t\tbreak;\n+\tdefault:\n+\t\tWARN_ON(1);\n+\t\t*err = -ENOENT;\n+\t\tbreak;\n \t}\n \n-\t*err = type-\u003esetkey(ctx-\u003etfm, params-\u003ekey, params-\u003ekey_len);\n-\tif (*err)\n-\t\tgoto err_free_tfm;\n-\n-\tif (type-\u003eget_flags(ctx-\u003etfm) \u0026 CRYPTO_TFM_NEED_KEY) {\n-\t\t*err = -EINVAL;\n-\t\tgoto err_free_tfm;\n+out:\n+\tif (*err) {\n+\t\tkfree_sensitive(ctx);\n+\t\treturn NULL;\n \t}\n \n-\tctx-\u003esiv_len = type-\u003eivsize(ctx-\u003etfm) + type-\u003estatesize(ctx-\u003etfm);\n-\n \trefcount_set(\u0026ctx-\u003eusage, 1);\n-\n \treturn ctx;\n-\n-err_free_tfm:\n-\ttype-\u003efree_tfm(ctx-\u003etfm);\n-err_free_ctx:\n-\tkfree(ctx);\n-err_module_put:\n-\tmodule_put(type-\u003eowner);\n-\n-\treturn NULL;\n }\n \n static void crypto_free_cb(struct rcu_head *head)\n@@ -225,9 +148,7 @@ static void crypto_free_cb(struct rcu_head *head)\n \tstruct bpf_crypto_ctx *ctx;\n \n \tctx = container_of(head, struct bpf_crypto_ctx, rcu);\n-\tctx-\u003etype-\u003efree_tfm(ctx-\u003etfm);\n-\tmodule_put(ctx-\u003etype-\u003eowner);\n-\tkfree(ctx);\n+\tkfree_sensitive(ctx);\n }\n \n /**\n@@ -267,27 +188,53 @@ __bpf_kfunc void bpf_crypto_ctx_release_dtor(void *ctx)\n }\n CFI_NOSEAL(bpf_crypto_ctx_release_dtor);\n \n+static int bpf_aes_cbc_crypt(u8 *dst, u32 dst_len, const u8 *src, u32 src_len,\n+\t\t\t u8 *iv, u32 iv_len,\n+\t\t\t const struct bpf_crypto_ctx *ctx, bool decrypt)\n+{\n+\tif (iv_len != AES_BLOCK_SIZE)\n+\t\treturn -EINVAL;\n+\tif (src_len % AES_BLOCK_SIZE || dst_len \u003c src_len)\n+\t\treturn -EINVAL;\n+\tif (decrypt)\n+\t\taes_cbc_decrypt(dst, src, src_len, iv, \u0026ctx-\u003ekey.aes);\n+\telse\n+\t\taes_cbc_encrypt(dst, src, src_len, iv, \u0026ctx-\u003ekey.aes);\n+\treturn 0;\n+}\n+\n+static int bpf_aes_ecb_crypt(u8 *dst, u32 dst_len, const u8 *src, u32 src_len,\n+\t\t\t u8 *iv, u32 iv_len,\n+\t\t\t const struct bpf_crypto_ctx *ctx, bool decrypt)\n+{\n+\tif (iv_len != 0)\n+\t\treturn -EINVAL;\n+\tif (src_len % AES_BLOCK_SIZE || dst_len \u003c src_len)\n+\t\treturn -EINVAL;\n+\tif (decrypt)\n+\t\taes_ecb_decrypt(dst, src, src_len, \u0026ctx-\u003ekey.aes);\n+\telse\n+\t\taes_ecb_encrypt(dst, src, src_len, \u0026ctx-\u003ekey.aes);\n+\treturn 0;\n+}\n+\n static int bpf_crypto_crypt(const struct bpf_crypto_ctx *ctx,\n \t\t\t const struct bpf_dynptr_kern *src,\n \t\t\t const struct bpf_dynptr_kern *dst,\n-\t\t\t const struct bpf_dynptr_kern *siv,\n+\t\t\t const struct bpf_dynptr_kern *iv,\n \t\t\t bool decrypt)\n {\n-\tu32 src_len, dst_len, siv_len;\n+\tu32 src_len, dst_len, iv_len;\n \tconst u8 *psrc;\n \tu8 *pdst, *piv;\n-\tint err;\n \n \tif (__bpf_dynptr_is_rdonly(dst))\n \t\treturn -EINVAL;\n \n-\tsiv_len = siv ? __bpf_dynptr_size(siv) : 0;\n+\tiv_len = iv ? __bpf_dynptr_size(iv) : 0;\n \tsrc_len = __bpf_dynptr_size(src);\n \tdst_len = __bpf_dynptr_size(dst);\n-\tif (!src_len || !dst_len || src_len \u003e dst_len)\n-\t\treturn -EINVAL;\n-\n-\tif (siv_len != ctx-\u003esiv_len)\n+\tif (!src_len || !dst_len)\n \t\treturn -EINVAL;\n \n \tpsrc = __bpf_dynptr_data(src, src_len);\n@@ -297,14 +244,20 @@ static int bpf_crypto_crypt(const struct bpf_crypto_ctx *ctx,\n \tif (!pdst)\n \t\treturn -EINVAL;\n \n-\tpiv = siv_len ? __bpf_dynptr_data_rw(siv, siv_len) : NULL;\n-\tif (siv_len \u0026\u0026 !piv)\n+\tpiv = iv_len ? __bpf_dynptr_data_rw(iv, iv_len) : NULL;\n+\tif (iv_len \u0026\u0026 !piv)\n \t\treturn -EINVAL;\n \n-\terr = decrypt ? ctx-\u003etype-\u003edecrypt(ctx-\u003etfm, psrc, pdst, src_len, piv)\n-\t\t : ctx-\u003etype-\u003eencrypt(ctx-\u003etfm, psrc, pdst, src_len, piv);\n-\n-\treturn err;\n+\tswitch (ctx-\u003ealgo) {\n+\tcase BPF_ALGO_AES_CBC:\n+\t\treturn bpf_aes_cbc_crypt(pdst, dst_len, psrc, src_len, piv,\n+\t\t\t\t\t iv_len, ctx, decrypt);\n+\tcase BPF_ALGO_AES_ECB:\n+\t\treturn bpf_aes_ecb_crypt(pdst, dst_len, psrc, src_len, piv,\n+\t\t\t\t\t iv_len, ctx, decrypt);\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n }\n \n /**\n@@ -312,20 +265,20 @@ static int bpf_crypto_crypt(const struct bpf_crypto_ctx *ctx,\n * @ctx:\t\tThe crypto context being used. The ctx must be a trusted pointer.\n * @src:\t\tbpf_dynptr to the encrypted data. Must be a trusted pointer.\n * @dst:\t\tbpf_dynptr to the buffer where to store the result. Must be a trusted pointer.\n- * @siv__nullable:\tbpf_dynptr to IV data and state data to be used by decryptor. May be NULL.\n+ * @iv__nullable:\tbpf_dynptr to the initialization vector. May be NULL.\n *\n * Decrypts provided buffer using IV data and the crypto context. Crypto context must be configured.\n */\n __bpf_kfunc int bpf_crypto_decrypt(struct bpf_crypto_ctx *ctx,\n \t\t\t\t const struct bpf_dynptr *src,\n \t\t\t\t const struct bpf_dynptr *dst,\n-\t\t\t\t const struct bpf_dynptr *siv__nullable)\n+\t\t\t\t const struct bpf_dynptr *iv__nullable)\n {\n \tconst struct bpf_dynptr_kern *src_kern = (struct bpf_dynptr_kern *)src;\n \tconst struct bpf_dynptr_kern *dst_kern = (struct bpf_dynptr_kern *)dst;\n-\tconst struct bpf_dynptr_kern *siv_kern = (struct bpf_dynptr_kern *)siv__nullable;\n+\tconst struct bpf_dynptr_kern *iv_kern = (struct bpf_dynptr_kern *)iv__nullable;\n \n-\treturn bpf_crypto_crypt(ctx, src_kern, dst_kern, siv_kern, true);\n+\treturn bpf_crypto_crypt(ctx, src_kern, dst_kern, iv_kern, true);\n }\n \n /**\n@@ -333,20 +286,20 @@ __bpf_kfunc int bpf_crypto_decrypt(struct bpf_crypto_ctx *ctx,\n * @ctx:\t\tThe crypto context being used. The ctx must be a trusted pointer.\n * @src:\t\tbpf_dynptr to the plain data. Must be a trusted pointer.\n * @dst:\t\tbpf_dynptr to the buffer where to store the result. Must be a trusted pointer.\n- * @siv__nullable:\tbpf_dynptr to IV data and state data to be used by decryptor. May be NULL.\n+ * @iv__nullable:\tbpf_dynptr to the initialization vector. May be NULL.\n *\n * Encrypts provided buffer using IV data and the crypto context. Crypto context must be configured.\n */\n __bpf_kfunc int bpf_crypto_encrypt(struct bpf_crypto_ctx *ctx,\n \t\t\t\t const struct bpf_dynptr *src,\n \t\t\t\t const struct bpf_dynptr *dst,\n-\t\t\t\t const struct bpf_dynptr *siv__nullable)\n+\t\t\t\t const struct bpf_dynptr *iv__nullable)\n {\n \tconst struct bpf_dynptr_kern *src_kern = (struct bpf_dynptr_kern *)src;\n \tconst struct bpf_dynptr_kern *dst_kern = (struct bpf_dynptr_kern *)dst;\n-\tconst struct bpf_dynptr_kern *siv_kern = (struct bpf_dynptr_kern *)siv__nullable;\n+\tconst struct bpf_dynptr_kern *iv_kern = (struct bpf_dynptr_kern *)iv__nullable;\n \n-\treturn bpf_crypto_crypt(ctx, src_kern, dst_kern, siv_kern, false);\n+\treturn bpf_crypto_crypt(ctx, src_kern, dst_kern, iv_kern, false);\n }\n \n __bpf_kfunc_end_defs();\n"
} |
| 2/1 | 2026/09/01 02:29 | agent | patch-evaluator |
0mModel:core Args: null Results: {
"EnableConfigs": [
"BPF_SYSCALL",
"BPF_CRYPTO",
"DEBUG_INFO_BTF"
],
"FocusSymbols": [
"bpf_crypto_ctx_create",
"bpf_crypto_ctx_release",
"bpf_crypto_ctx_acquire",
"bpf_crypto_ctx_release_dtor",
"bpf_crypto_decrypt",
"bpf_crypto_encrypt"
],
"Reasoning": "The patch refactors BPF crypto support by removing the dynamic crypto type registration interface and implementing direct AES-CBC and AES-ECB library integration. It introduces CONFIG_BPF_CRYPTO and modifies the BPF crypto kfunc handlers (context creation, key setup, encryption, decryption, and lifecycle management), making these functions important targets for BPF program fuzzing.",
"WorthFuzzing": true
}Instruction: You are an expert Linux kernel maintainer. Your job is to review a provided patch series and determine if it makes functional changes to the kernel that should be fuzzed. IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively use your code access tools to examine the actual source code and confirm any assumptions. Return WorthFuzzing=false if the patch only contains: - Modifications to Documentation/, Kconfig files, or code comments. - Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints. - Changes to numeric constants or macros that do not functionally alter execution flow. - Code paths that are impossible to reach in virtualized environments like GCE or QEMU, even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim). - Code in vendor-specific PCIe switch, SmartNIC, or GPU drivers (e.g., mlxsw, pds_core, qed, ionic, amdgpu) that require physical PCIe hardware cards not emulated in standard QEMU. - Driver .remove, .shutdown, or pci_unregister_driver teardown callbacks (e.g., igb_remove) that are executed only during PCI hot-unplug or sysfs driver unbind operations. If it modifies reachable core kernel logic, drivers, or architectures, use your code search tools to verify the code can be executed, then return WorthFuzzing=true. When returning WorthFuzzing=true, you MUST ALSO: 1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols. Avoid listing generic hot-path functions to prevent skewed test distributions. Prefer non-static, non-inlined API entrypoint functions over internal static helper functions (which are inlined by the compiler and do not have distinct symbol addresses). 2. Identify any specific CONFIG_ options required to properly test this new/modified feature. Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions. Also check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed for Kbuild to compile the code statically into vmlinux. List them in the EnableConfigs output array, and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4"). Prefer calling several tools at the same time to save round-trips. Use set-results tool to provide results of the analysis. It must be called exactly once before the final reply. Ignore results of this tool. Prompt: For your convenience, here is the diff of the changes:
commit 97b409223e251e0a20b889ab7a76b5978328fcee
Author: syz-cluster <triage@syzkaller.com>
Date: Tue Sep 1 02:29:23 2026 +0000
syz-cluster: applied patch under review
diff --git a/MAINTAINERS b/MAINTAINERS
index 3a19da74d00c9..16f13270ce1f9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4936,8 +4936,6 @@ BPF [CRYPTO]
M: Vadim Fedorenko <vadim.fedorenko@linux.dev>
L: bpf@vger.kernel.org
S: Maintained
-F: crypto/bpf_crypto_skcipher.c
-F: include/linux/bpf_crypto.h
F: kernel/bpf/crypto.c
BPF [DOCUMENTATION] (Related to Standardization)
diff --git a/crypto/Makefile b/crypto/Makefile
index 8386d55a9755e..33bb5ad595e8f 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -22,9 +22,6 @@ crypto_skcipher-y += lskcipher.o
crypto_skcipher-y += skcipher.o
obj-$(CONFIG_CRYPTO_SKCIPHER2) += crypto_skcipher.o
-ifeq ($(CONFIG_BPF_SYSCALL),y)
-obj-$(CONFIG_CRYPTO_SKCIPHER2) += bpf_crypto_skcipher.o
-endif
obj-$(CONFIG_CRYPTO_SEQIV) += seqiv.o
obj-$(CONFIG_CRYPTO_ECHAINIV) += echainiv.o
diff --git a/crypto/bpf_crypto_skcipher.c b/crypto/bpf_crypto_skcipher.c
deleted file mode 100644
index a88798d3e8c87..0000000000000
--- a/crypto/bpf_crypto_skcipher.c
+++ /dev/null
@@ -1,83 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2024 Meta, Inc */
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/bpf_crypto.h>
-#include <crypto/skcipher.h>
-
-static void *bpf_crypto_lskcipher_alloc_tfm(const char *algo)
-{
- return crypto_alloc_lskcipher(algo, 0, 0);
-}
-
-static void bpf_crypto_lskcipher_free_tfm(void *tfm)
-{
- crypto_free_lskcipher(tfm);
-}
-
-static int bpf_crypto_lskcipher_has_algo(const char *algo)
-{
- return crypto_has_skcipher(algo, CRYPTO_ALG_TYPE_LSKCIPHER, CRYPTO_ALG_TYPE_MASK);
-}
-
-static int bpf_crypto_lskcipher_setkey(void *tfm, const u8 *key, unsigned int keylen)
-{
- return crypto_lskcipher_setkey(tfm, key, keylen);
-}
-
-static u32 bpf_crypto_lskcipher_get_flags(void *tfm)
-{
- return crypto_lskcipher_get_flags(tfm);
-}
-
-static unsigned int bpf_crypto_lskcipher_ivsize(void *tfm)
-{
- return crypto_lskcipher_ivsize(tfm);
-}
-
-static unsigned int bpf_crypto_lskcipher_statesize(void *tfm)
-{
- return crypto_lskcipher_statesize(tfm);
-}
-
-static int bpf_crypto_lskcipher_encrypt(void *tfm, const u8 *src, u8 *dst,
- unsigned int len, u8 *siv)
-{
- return crypto_lskcipher_encrypt(tfm, src, dst, len, siv);
-}
-
-static int bpf_crypto_lskcipher_decrypt(void *tfm, const u8 *src, u8 *dst,
- unsigned int len, u8 *siv)
-{
- return crypto_lskcipher_decrypt(tfm, src, dst, len, siv);
-}
-
-static const struct bpf_crypto_type bpf_crypto_lskcipher_type = {
- .alloc_tfm = bpf_crypto_lskcipher_alloc_tfm,
- .free_tfm = bpf_crypto_lskcipher_free_tfm,
- .has_algo = bpf_crypto_lskcipher_has_algo,
- .setkey = bpf_crypto_lskcipher_setkey,
- .encrypt = bpf_crypto_lskcipher_encrypt,
- .decrypt = bpf_crypto_lskcipher_decrypt,
- .ivsize = bpf_crypto_lskcipher_ivsize,
- .statesize = bpf_crypto_lskcipher_statesize,
- .get_flags = bpf_crypto_lskcipher_get_flags,
- .owner = THIS_MODULE,
- .name = "skcipher",
-};
-
-static int __init bpf_crypto_skcipher_init(void)
-{
- return bpf_crypto_register_type(&bpf_crypto_lskcipher_type);
-}
-
-static void __exit bpf_crypto_skcipher_exit(void)
-{
- int err = bpf_crypto_unregister_type(&bpf_crypto_lskcipher_type);
- WARN_ON_ONCE(err);
-}
-
-module_init(bpf_crypto_skcipher_init);
-module_exit(bpf_crypto_skcipher_exit);
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Symmetric key cipher support for BPF");
diff --git a/include/linux/bpf_crypto.h b/include/linux/bpf_crypto.h
deleted file mode 100644
index a41e71d4e2d9f..0000000000000
--- a/include/linux/bpf_crypto.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */
-#ifndef _BPF_CRYPTO_H
-#define _BPF_CRYPTO_H
-
-struct bpf_crypto_type {
- void *(*alloc_tfm)(const char *algo);
- void (*free_tfm)(void *tfm);
- int (*has_algo)(const char *algo);
- int (*setkey)(void *tfm, const u8 *key, unsigned int keylen);
- int (*setauthsize)(void *tfm, unsigned int authsize);
- int (*encrypt)(void *tfm, const u8 *src, u8 *dst, unsigned int len, u8 *iv);
- int (*decrypt)(void *tfm, const u8 *src, u8 *dst, unsigned int len, u8 *iv);
- unsigned int (*ivsize)(void *tfm);
- unsigned int (*statesize)(void *tfm);
- u32 (*get_flags)(void *tfm);
- struct module *owner;
- char name[14];
-};
-
-int bpf_crypto_register_type(const struct bpf_crypto_type *type);
-int bpf_crypto_unregister_type(const struct bpf_crypto_type *type);
-
-#endif /* _BPF_CRYPTO_H */
diff --git a/kernel/bpf/Kconfig b/kernel/bpf/Kconfig
index eb3de35734f09..822599b42be2e 100644
--- a/kernel/bpf/Kconfig
+++ b/kernel/bpf/Kconfig
@@ -87,6 +87,15 @@ config BPF_UNPRIV_DEFAULT_OFF
If you are unsure how to answer this question, answer Y.
+config BPF_CRYPTO
+ def_bool y
+ depends on BPF_SYSCALL
+ select CRYPTO_LIB_AES_CBC
+ select CRYPTO_LIB_AES_ECB
+ help
+ Provide the kfuncs needed for BPF programs to encrypt and decrypt
+ data. The supported algorithms are AES-CBC and AES-ECB.
+
source "kernel/bpf/preload/Kconfig"
config BPF_LSM
diff --git a/kernel/bpf/Makefile b/kernel/bpf/Makefile
index 90255d80e5be6..ab2e5d2782e6e 100644
--- a/kernel/bpf/Makefile
+++ b/kernel/bpf/Makefile
@@ -55,9 +55,7 @@ obj-$(CONFIG_BPF_SYSCALL) += cpumask.o
# semantics within pahole are revisited accordingly.
obj-${CONFIG_BPF_LSM} += bpf_lsm_proto.o bpf_lsm.o
endif
-ifneq ($(CONFIG_CRYPTO),)
-obj-$(CONFIG_BPF_SYSCALL) += crypto.o
-endif
+obj-$(CONFIG_BPF_CRYPTO) += crypto.o
obj-$(CONFIG_BPF_PRELOAD) += preload/
obj-$(CONFIG_BPF_SYSCALL) += relo_core.o
diff --git a/kernel/bpf/crypto.c b/kernel/bpf/crypto.c
index 51f89cecefb4d..8cdc16f9b374a 100644
--- a/kernel/bpf/crypto.c
+++ b/kernel/bpf/crypto.c
@@ -1,19 +1,13 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2024 Meta, Inc */
#include <linux/bpf.h>
-#include <linux/bpf_crypto.h>
#include <linux/bpf_mem_alloc.h>
#include <linux/btf.h>
#include <linux/btf_ids.h>
#include <linux/filter.h>
-#include <linux/scatterlist.h>
#include <linux/skbuff.h>
-#include <crypto/skcipher.h>
-
-struct bpf_crypto_type_list {
- const struct bpf_crypto_type *type;
- struct list_head list;
-};
+#include <crypto/aes-cbc.h>
+#include <crypto/aes-ecb.h>
/* BPF crypto initialization parameters struct */
/**
@@ -36,94 +30,53 @@ struct bpf_crypto_params {
u32 authsize;
};
-static LIST_HEAD(bpf_crypto_types);
-static DECLARE_RWSEM(bpf_crypto_types_sem);
+enum bpf_crypto_algo_id {
+ BPF_ALGO_AES_CBC,
+ BPF_ALGO_AES_ECB,
+};
+
+static const struct {
+ const char *type_name;
+ const char *algo_name;
+ enum bpf_crypto_algo_id algo;
+} bpf_crypto_algos[] = {
+ { "skcipher", "cbc(aes)", BPF_ALGO_AES_CBC },
+ { "skcipher", "ecb(aes)", BPF_ALGO_AES_ECB },
+};
+
+static bool bpf_crypto_find_algo(const struct bpf_crypto_params *params,
+ enum bpf_crypto_algo_id *id_ret)
+{
+ for (size_t i = 0; i < ARRAY_SIZE(bpf_crypto_algos); i++) {
+ if (strncmp(bpf_crypto_algos[i].type_name, params->type,
+ sizeof(params->type)) == 0 &&
+ strncmp(bpf_crypto_algos[i].algo_name, params->algo,
+ sizeof(params->algo)) == 0) {
+ *id_ret = bpf_crypto_algos[i].algo;
+ return true;
+ }
+ }
+ return false;
+}
/**
* struct bpf_crypto_ctx - refcounted BPF crypto context structure
- * @type: The pointer to bpf crypto type
- * @tfm: The pointer to instance of crypto API struct.
- * @siv_len: Size of IV and state storage for cipher
+ * @algo: The crypto algorithm ID
+ * @key: The crypto key
* @rcu: The RCU head used to free the crypto context with RCU safety.
* @usage: Object reference counter. When the refcount goes to 0, the
* memory is released back to the BPF allocator, which provides
* RCU safety.
*/
struct bpf_crypto_ctx {
- const struct bpf_crypto_type *type;
- void *tfm;
- u32 siv_len;
+ enum bpf_crypto_algo_id algo;
+ union {
+ struct aes_key aes;
+ } key;
struct rcu_head rcu;
refcount_t usage;
};
-int bpf_crypto_register_type(const struct bpf_crypto_type *type)
-{
- struct bpf_crypto_type_list *node;
- int err = -EBUSY;
-
- down_write(&bpf_crypto_types_sem);
- list_for_each_entry(node, &bpf_crypto_types, list) {
- if (!strcmp(node->type->name, type->name))
- goto unlock;
- }
-
- node = kmalloc_obj(*node);
- err = -ENOMEM;
- if (!node)
- goto unlock;
-
- node->type = type;
- list_add(&node->list, &bpf_crypto_types);
- err = 0;
-
-unlock:
- up_write(&bpf_crypto_types_sem);
-
- return err;
-}
-EXPORT_SYMBOL_GPL(bpf_crypto_register_type);
-
-int bpf_crypto_unregister_type(const struct bpf_crypto_type *type)
-{
- struct bpf_crypto_type_list *node;
- int err = -ENOENT;
-
- down_write(&bpf_crypto_types_sem);
- list_for_each_entry(node, &bpf_crypto_types, list) {
- if (strcmp(node->type->name, type->name))
- continue;
-
- list_del(&node->list);
- kfree(node);
- err = 0;
- break;
- }
- up_write(&bpf_crypto_types_sem);
-
- return err;
-}
-EXPORT_SYMBOL_GPL(bpf_crypto_unregister_type);
-
-static const struct bpf_crypto_type *bpf_crypto_get_type(const char *name)
-{
- const struct bpf_crypto_type *type = ERR_PTR(-ENOENT);
- struct bpf_crypto_type_list *node;
-
- down_read(&bpf_crypto_types_sem);
- list_for_each_entry(node, &bpf_crypto_types, list) {
- if (strcmp(node->type->name, name))
- continue;
-
- if (try_module_get(node->type->owner))
- type = node->type;
- break;
- }
- up_read(&bpf_crypto_types_sem);
-
- return type;
-}
-
__bpf_kfunc_start_defs();
/**
@@ -146,7 +99,6 @@ __bpf_kfunc struct bpf_crypto_ctx *
bpf_crypto_ctx_create(const struct bpf_crypto_params *params, u32 params__sz,
int *err)
{
- const struct bpf_crypto_type *type;
struct bpf_crypto_ctx *ctx;
if (!params || params->reserved[0] || params->reserved[1] ||
@@ -155,69 +107,40 @@ bpf_crypto_ctx_create(const struct bpf_crypto_params *params, u32 params__sz,
return NULL;
}
- type = bpf_crypto_get_type(params->type);
- if (IS_ERR(type)) {
- *err = PTR_ERR(type);
- return NULL;
- }
-
- if (!type->has_algo(params->algo)) {
- *err = -EOPNOTSUPP;
- goto err_module_put;
- }
-
- if (!!params->authsize ^ !!type->setauthsize) {
- *err = -EOPNOTSUPP;
- goto err_module_put;
- }
-
- if (!params->key_len || params->key_len > sizeof(params->key)) {
- *err = -EINVAL;
- goto err_module_put;
- }
-
ctx = kzalloc_obj(*ctx);
if (!ctx) {
*err = -ENOMEM;
- goto err_module_put;
+ return NULL;
}
- ctx->type = type;
- ctx->tfm = type->alloc_tfm(params->algo);
- if (IS_ERR(ctx->tfm)) {
- *err = PTR_ERR(ctx->tfm);
- goto err_free_ctx;
+ if (!bpf_crypto_find_algo(params, &ctx->algo)) {
+ *err = -ENOENT;
+ goto out;
}
- if (params->authsize) {
- *err = type->setauthsize(ctx->tfm, params->authsize);
- if (*err)
- goto err_free_tfm;
+ switch (ctx->algo) {
+ case BPF_ALGO_AES_CBC:
+ case BPF_ALGO_AES_ECB:
+ if (params->authsize)
+ *err = -EOPNOTSUPP;
+ else
+ *err = aes_preparekey(&ctx->key.aes, params->key,
+ params->key_len);
+ break;
+ default:
+ WARN_ON(1);
+ *err = -ENOENT;
+ break;
}
- *err = type->setkey(ctx->tfm, params->key, params->key_len);
- if (*err)
- goto err_free_tfm;
-
- if (type->get_flags(ctx->tfm) & CRYPTO_TFM_NEED_KEY) {
- *err = -EINVAL;
- goto err_free_tfm;
+out:
+ if (*err) {
+ kfree_sensitive(ctx);
+ return NULL;
}
- ctx->siv_len = type->ivsize(ctx->tfm) + type->statesize(ctx->tfm);
-
refcount_set(&ctx->usage, 1);
-
return ctx;
-
-err_free_tfm:
- type->free_tfm(ctx->tfm);
-err_free_ctx:
- kfree(ctx);
-err_module_put:
- module_put(type->owner);
-
- return NULL;
}
static void crypto_free_cb(struct rcu_head *head)
@@ -225,9 +148,7 @@ static void crypto_free_cb(struct rcu_head *head)
struct bpf_crypto_ctx *ctx;
ctx = container_of(head, struct bpf_crypto_ctx, rcu);
- ctx->type->free_tfm(ctx->tfm);
- module_put(ctx->type->owner);
- kfree(ctx);
+ kfree_sensitive(ctx);
}
/**
@@ -267,27 +188,53 @@ __bpf_kfunc void bpf_crypto_ctx_release_dtor(void *ctx)
}
CFI_NOSEAL(bpf_crypto_ctx_release_dtor);
+static int bpf_aes_cbc_crypt(u8 *dst, u32 dst_len, const u8 *src, u32 src_len,
+ u8 *iv, u32 iv_len,
+ const struct bpf_crypto_ctx *ctx, bool decrypt)
+{
+ if (iv_len != AES_BLOCK_SIZE)
+ return -EINVAL;
+ if (src_len % AES_BLOCK_SIZE || dst_len < src_len)
+ return -EINVAL;
+ if (decrypt)
+ aes_cbc_decrypt(dst, src, src_len, iv, &ctx->key.aes);
+ else
+ aes_cbc_encrypt(dst, src, src_len, iv, &ctx->key.aes);
+ return 0;
+}
+
+static int bpf_aes_ecb_crypt(u8 *dst, u32 dst_len, const u8 *src, u32 src_len,
+ u8 *iv, u32 iv_len,
+ const struct bpf_crypto_ctx *ctx, bool decrypt)
+{
+ if (iv_len != 0)
+ return -EINVAL;
+ if (src_len % AES_BLOCK_SIZE || dst_len < src_len)
+ return -EINVAL;
+ if (decrypt)
+ aes_ecb_decrypt(dst, src, src_len, &ctx->key.aes);
+ else
+ aes_ecb_encrypt(dst, src, src_len, &ctx->key.aes);
+ return 0;
+}
+
static int bpf_crypto_crypt(const struct bpf_crypto_ctx *ctx,
const struct bpf_dynptr_kern *src,
const struct bpf_dynptr_kern *dst,
- const struct bpf_dynptr_kern *siv,
+ const struct bpf_dynptr_kern *iv,
bool decrypt)
{
- u32 src_len, dst_len, siv_len;
+ u32 src_len, dst_len, iv_len;
const u8 *psrc;
u8 *pdst, *piv;
- int err;
if (__bpf_dynptr_is_rdonly(dst))
return -EINVAL;
- siv_len = siv ? __bpf_dynptr_size(siv) : 0;
+ iv_len = iv ? __bpf_dynptr_size(iv) : 0;
src_len = __bpf_dynptr_size(src);
dst_len = __bpf_dynptr_size(dst);
- if (!src_len || !dst_len || src_len > dst_len)
- return -EINVAL;
-
- if (siv_len != ctx->siv_len)
+ if (!src_len || !dst_len)
return -EINVAL;
psrc = __bpf_dynptr_data(src, src_len);
@@ -297,14 +244,20 @@ static int bpf_crypto_crypt(const struct bpf_crypto_ctx *ctx,
if (!pdst)
return -EINVAL;
- piv = siv_len ? __bpf_dynptr_data_rw(siv, siv_len) : NULL;
- if (siv_len && !piv)
+ piv = iv_len ? __bpf_dynptr_data_rw(iv, iv_len) : NULL;
+ if (iv_len && !piv)
return -EINVAL;
- err = decrypt ? ctx->type->decrypt(ctx->tfm, psrc, pdst, src_len, piv)
- : ctx->type->encrypt(ctx->tfm, psrc, pdst, src_len, piv);
-
- return err;
+ switch (ctx->algo) {
+ case BPF_ALGO_AES_CBC:
+ return bpf_aes_cbc_crypt(pdst, dst_len, psrc, src_len, piv,
+ iv_len, ctx, decrypt);
+ case BPF_ALGO_AES_ECB:
+ return bpf_aes_ecb_crypt(pdst, dst_len, psrc, src_len, piv,
+ iv_len, ctx, decrypt);
+ default:
+ return -EINVAL;
+ }
}
/**
@@ -312,20 +265,20 @@ 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__nullable: bpf_dynptr to IV data and state data to be used by decryptor. May be NULL.
+ * @iv__nullable: bpf_dynptr to the initialization vector. 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__nullable)
+ const struct bpf_dynptr *iv__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__nullable;
+ const struct bpf_dynptr_kern *iv_kern = (struct bpf_dynptr_kern *)iv__nullable;
- return bpf_crypto_crypt(ctx, src_kern, dst_kern, siv_kern, true);
+ return bpf_crypto_crypt(ctx, src_kern, dst_kern, iv_kern, true);
}
/**
@@ -333,20 +286,20 @@ __bpf_kfunc int bpf_crypto_decrypt(struct bpf_crypto_ctx *ctx,
* @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 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.
+ * @iv__nullable: bpf_dynptr to the initialization vector. 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__nullable)
+ const struct bpf_dynptr *iv__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__nullable;
+ const struct bpf_dynptr_kern *iv_kern = (struct bpf_dynptr_kern *)iv__nullable;
- return bpf_crypto_crypt(ctx, src_kern, dst_kern, siv_kern, false);
+ return bpf_crypto_crypt(ctx, src_kern, dst_kern, iv_kern, false);
}
__bpf_kfunc_end_defs();
|
| 3/2 | 2026/09/01 02:29 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 9099 output: 30 thoughts: 489 Thoughts: **Analyzing the BPF Crypto Patch** Okay, let's dive into this patch. My initial assessment is that it's focusing on optimizing the BPF crypto subsystem. It looks like they are removing the old `crypto/bpf_crypto_skcipher.c` and `include/linux/bpf_crypto.h` files – so the legacy code is gone. Instead, they're introducing a `config BPF_CRYPTO` option in `kernel/bpf/Kconfig`, which is set to `y` if `BPF_SYSCALL` is enabled, and also selecting both `CRYPTO_LIB_AES_CBC` and `CRYPTO_LIB_AES_ECB`. This means the patch enables the use of AES-CBC and AES-ECB for encryption/decryption within BPF programs. The change in the Makefile confirms this with `obj-$(CONFIG_BPF_CRYPTO) += crypto.o`. The real meat of the change, though, appears to be in `kernel/bpf/crypto.c`. They're refactoring the crypto handling, moving away from the generic crypto tfm registration interface. The aim seems to be to streamline things by directly calling the `CRYPTO_LIB_AES_CBC` and `CRYPTO_LIB_AES_ECB` implementations via kfuncs. Specifically, they've implemented new kfuncs: `bpf_crypto_ctx_create`, `bpf_crypto_ctx_release`, `bpf_crypto_decrypt`, and `bpf_crypto_encrypt`. Now, is this a worthwhile target for fuzzing? Let's see. The entry points are definitely reachable. These new kfuncs, along with others such as `bpf_crypto_ctx_release_dtor` are called from within BPF programs. This means they are core kernel logic, and this patch touches a lot. They're replacing the generic crypto driver backend with direct calls to `aes_cbc_encrypt`, `aes_cbc_decrypt`, `aes_ecb_encrypt`, and `aes_ecb_decrypt`. That's a significant change to parameter checking, buffer validation, context lifecycle, and memory management. Any error here has large potential impact. I need to inspect `kernel/bpf/crypto.c` and `Kconfig` for the dependencies and functions involved. I'll search for the symbols and read the code to have a good look. |
| 4/2 | 2026/09/01 02:29 | tool | grepper |
0mArgs:{
"Expression": "bpf_crypto_",
"PathPrefix": "kernel/bpf/"
}Results: {
"Output": "kernel/bpf/crypto.c-13-/**\nkernel/bpf/crypto.c:14: * struct bpf_crypto_params - BPF crypto initialization parameters structure\nkernel/bpf/crypto.c-15- * @type:\tThe string of crypto operation type.\n--\nkernel/bpf/crypto.c-23- */\nkernel/bpf/crypto.c:24:struct bpf_crypto_params {\nkernel/bpf/crypto.c-25-\tchar type[14];\n--\nkernel/bpf/crypto.c-32-\nkernel/bpf/crypto.c:33:enum bpf_crypto_algo_id {\nkernel/bpf/crypto.c-34-\tBPF_ALGO_AES_CBC,\n--\nkernel/bpf/crypto.c=38=static const struct {\n--\nkernel/bpf/crypto.c-40-\tconst char *algo_name;\nkernel/bpf/crypto.c:41:\tenum bpf_crypto_algo_id algo;\nkernel/bpf/crypto.c:42:} bpf_crypto_algos[] = {\nkernel/bpf/crypto.c-43-\t{ \"skcipher\", \"cbc(aes)\", BPF_ALGO_AES_CBC },\n--\nkernel/bpf/crypto.c-46-\nkernel/bpf/crypto.c:47:static bool bpf_crypto_find_algo(const struct bpf_crypto_params *params,\nkernel/bpf/crypto.c:48:\t\t\t\t enum bpf_crypto_algo_id *id_ret)\nkernel/bpf/crypto.c-49-{\nkernel/bpf/crypto.c:50:\tfor (size_t i = 0; i \u003c ARRAY_SIZE(bpf_crypto_algos); i++) {\nkernel/bpf/crypto.c:51:\t\tif (strncmp(bpf_crypto_algos[i].type_name, params-\u003etype,\nkernel/bpf/crypto.c-52-\t\t\t sizeof(params-\u003etype)) == 0 \u0026\u0026\nkernel/bpf/crypto.c:53:\t\t strncmp(bpf_crypto_algos[i].algo_name, params-\u003ealgo,\nkernel/bpf/crypto.c-54-\t\t\t sizeof(params-\u003ealgo)) == 0) {\nkernel/bpf/crypto.c:55:\t\t\t*id_ret = bpf_crypto_algos[i].algo;\nkernel/bpf/crypto.c-56-\t\t\treturn true;\n--\nkernel/bpf/crypto.c-62-/**\nkernel/bpf/crypto.c:63: * struct bpf_crypto_ctx - refcounted BPF crypto context structure\nkernel/bpf/crypto.c-64- * @algo:\tThe crypto algorithm ID\n--\nkernel/bpf/crypto.c-70- */\nkernel/bpf/crypto.c:71:struct bpf_crypto_ctx {\nkernel/bpf/crypto.c:72:\tenum bpf_crypto_algo_id algo;\nkernel/bpf/crypto.c-73-\tunion {\n--\nkernel/bpf/crypto.c=80=__bpf_kfunc_start_defs();\n--\nkernel/bpf/crypto.c-82-/**\nkernel/bpf/crypto.c:83: * bpf_crypto_ctx_create() - Create a mutable BPF crypto context.\nkernel/bpf/crypto.c-84- *\n--\nkernel/bpf/crypto.c-86- * a BPF program. The crypto context returned by this function must either\nkernel/bpf/crypto.c:87: * be embedded in a map as a kptr, or freed with bpf_crypto_ctx_release().\nkernel/bpf/crypto.c-88- * As crypto API functions use GFP_KERNEL allocations, this function can\n--\nkernel/bpf/crypto.c-90- *\nkernel/bpf/crypto.c:91: * bpf_crypto_ctx_create() allocates memory for crypto context.\nkernel/bpf/crypto.c-92- * It may return NULL if no memory is available.\nkernel/bpf/crypto.c:93: * @params:\tpointer to struct bpf_crypto_params which contains all the\nkernel/bpf/crypto.c-94- *\t\tdetails needed to initialise crypto context.\nkernel/bpf/crypto.c:95: * @params__sz:\tsize of steuct bpf_crypto_params usef by bpf program\nkernel/bpf/crypto.c-96- * @err:\tinteger to store error code when NULL is returned.\nkernel/bpf/crypto.c-97- */\nkernel/bpf/crypto.c:98:__bpf_kfunc struct bpf_crypto_ctx *\nkernel/bpf/crypto.c:99:bpf_crypto_ctx_create(const struct bpf_crypto_params *params, u32 params__sz,\nkernel/bpf/crypto.c-100-\t\t int *err)\nkernel/bpf/crypto.c-101-{\nkernel/bpf/crypto.c:102:\tstruct bpf_crypto_ctx *ctx;\nkernel/bpf/crypto.c-103-\nkernel/bpf/crypto.c-104-\tif (!params || params-\u003ereserved[0] || params-\u003ereserved[1] ||\nkernel/bpf/crypto.c:105:\t params__sz != sizeof(struct bpf_crypto_params)) {\nkernel/bpf/crypto.c-106-\t\t*err = -EINVAL;\n--\nkernel/bpf/crypto.c-115-\nkernel/bpf/crypto.c:116:\tif (!bpf_crypto_find_algo(params, \u0026ctx-\u003ealgo)) {\nkernel/bpf/crypto.c-117-\t\t*err = -ENOENT;\n--\nkernel/bpf/crypto.c=146=static void crypto_free_cb(struct rcu_head *head)\nkernel/bpf/crypto.c-147-{\nkernel/bpf/crypto.c:148:\tstruct bpf_crypto_ctx *ctx;\nkernel/bpf/crypto.c-149-\nkernel/bpf/crypto.c:150:\tctx = container_of(head, struct bpf_crypto_ctx, rcu);\nkernel/bpf/crypto.c-151-\tkfree_sensitive(ctx);\n--\nkernel/bpf/crypto.c-154-/**\nkernel/bpf/crypto.c:155: * bpf_crypto_ctx_acquire() - Acquire a reference to a BPF crypto context.\nkernel/bpf/crypto.c-156- * @ctx: The BPF crypto context being acquired. The ctx must be a trusted\n--\nkernel/bpf/crypto.c-160- * must either be embedded in a map as a kptr, or freed with\nkernel/bpf/crypto.c:161: * bpf_crypto_ctx_release().\nkernel/bpf/crypto.c-162- */\nkernel/bpf/crypto.c:163:__bpf_kfunc struct bpf_crypto_ctx *\nkernel/bpf/crypto.c:164:bpf_crypto_ctx_acquire(struct bpf_crypto_ctx *ctx)\nkernel/bpf/crypto.c-165-{\n--\nkernel/bpf/crypto.c-171-/**\nkernel/bpf/crypto.c:172: * bpf_crypto_ctx_release() - Release a previously acquired BPF crypto context.\nkernel/bpf/crypto.c-173- * @ctx: The crypto context being released.\n--\nkernel/bpf/crypto.c-178- */\nkernel/bpf/crypto.c:179:__bpf_kfunc void bpf_crypto_ctx_release(struct bpf_crypto_ctx *ctx)\nkernel/bpf/crypto.c-180-{\n--\nkernel/bpf/crypto.c-184-\nkernel/bpf/crypto.c:185:__bpf_kfunc void bpf_crypto_ctx_release_dtor(void *ctx)\nkernel/bpf/crypto.c-186-{\nkernel/bpf/crypto.c:187:\tbpf_crypto_ctx_release(ctx);\nkernel/bpf/crypto.c-188-}\nkernel/bpf/crypto.c:189:CFI_NOSEAL(bpf_crypto_ctx_release_dtor);\nkernel/bpf/crypto.c-190-\nkernel/bpf/crypto.c=191=static int bpf_aes_cbc_crypt(u8 *dst, u32 dst_len, const u8 *src, u32 src_len,\nkernel/bpf/crypto.c-192-\t\t\t u8 *iv, u32 iv_len,\nkernel/bpf/crypto.c:193:\t\t\t const struct bpf_crypto_ctx *ctx, bool decrypt)\nkernel/bpf/crypto.c-194-{\n--\nkernel/bpf/crypto.c=206=static int bpf_aes_ecb_crypt(u8 *dst, u32 dst_len, const u8 *src, u32 src_len,\nkernel/bpf/crypto.c-207-\t\t\t u8 *iv, u32 iv_len,\nkernel/bpf/crypto.c:208:\t\t\t const struct bpf_crypto_ctx *ctx, bool decrypt)\nkernel/bpf/crypto.c-209-{\n--\nkernel/bpf/crypto.c-220-\nkernel/bpf/crypto.c:221:static int bpf_crypto_crypt(const struct bpf_crypto_ctx *ctx,\nkernel/bpf/crypto.c-222-\t\t\t const struct bpf_dynptr_kern *src,\n--\nkernel/bpf/crypto.c-263-/**\nkernel/bpf/crypto.c:264: * bpf_crypto_decrypt() - Decrypt buffer using configured context and IV provided.\nkernel/bpf/crypto.c-265- * @ctx:\t\tThe crypto context being used. The ctx must be a trusted pointer.\n--\nkernel/bpf/crypto.c-271- */\nkernel/bpf/crypto.c:272:__bpf_kfunc int bpf_crypto_decrypt(struct bpf_crypto_ctx *ctx,\nkernel/bpf/crypto.c-273-\t\t\t\t const struct bpf_dynptr *src,\n--\nkernel/bpf/crypto.c-280-\nkernel/bpf/crypto.c:281:\treturn bpf_crypto_crypt(ctx, src_kern, dst_kern, iv_kern, true);\nkernel/bpf/crypto.c-282-}\n--\nkernel/bpf/crypto.c-284-/**\nkernel/bpf/crypto.c:285: * bpf_crypto_encrypt() - Encrypt buffer using configured context and IV provided.\nkernel/bpf/crypto.c-286- * @ctx:\t\tThe crypto context being used. The ctx must be a trusted pointer.\n--\nkernel/bpf/crypto.c-292- */\nkernel/bpf/crypto.c:293:__bpf_kfunc int bpf_crypto_encrypt(struct bpf_crypto_ctx *ctx,\nkernel/bpf/crypto.c-294-\t\t\t\t const struct bpf_dynptr *src,\n--\nkernel/bpf/crypto.c-301-\nkernel/bpf/crypto.c:302:\treturn bpf_crypto_crypt(ctx, src_kern, dst_kern, iv_kern, false);\nkernel/bpf/crypto.c-303-}\n--\nkernel/bpf/crypto.c=307=BTF_KFUNCS_START(crypt_init_kfunc_btf_ids)\nkernel/bpf/crypto.c:308:BTF_ID_FLAGS(func, bpf_crypto_ctx_create, KF_ACQUIRE | KF_RET_NULL | KF_SLEEPABLE)\nkernel/bpf/crypto.c:309:BTF_ID_FLAGS(func, bpf_crypto_ctx_release, KF_RELEASE)\nkernel/bpf/crypto.c:310:BTF_ID_FLAGS(func, bpf_crypto_ctx_acquire, KF_ACQUIRE | KF_RCU | KF_RET_NULL)\nkernel/bpf/crypto.c-311-BTF_KFUNCS_END(crypt_init_kfunc_btf_ids)\n--\nkernel/bpf/crypto.c=318=BTF_KFUNCS_START(crypt_kfunc_btf_ids)\nkernel/bpf/crypto.c:319:BTF_ID_FLAGS(func, bpf_crypto_decrypt, KF_RCU)\nkernel/bpf/crypto.c:320:BTF_ID_FLAGS(func, bpf_crypto_encrypt, KF_RCU)\nkernel/bpf/crypto.c-321-BTF_KFUNCS_END(crypt_kfunc_btf_ids)\n--\nkernel/bpf/crypto.c=323=static const struct btf_kfunc_id_set crypt_kfunc_set = {\n--\nkernel/bpf/crypto.c-327-\nkernel/bpf/crypto.c:328:BTF_ID_LIST(bpf_crypto_dtor_ids)\nkernel/bpf/crypto.c:329:BTF_ID(struct, bpf_crypto_ctx)\nkernel/bpf/crypto.c:330:BTF_ID(func, bpf_crypto_ctx_release_dtor)\nkernel/bpf/crypto.c-331-\nkernel/bpf/crypto.c=332=static int __init crypto_kfunc_init(void)\n--\nkernel/bpf/crypto.c-334-\tint ret;\nkernel/bpf/crypto.c:335:\tconst struct btf_id_dtor_kfunc bpf_crypto_dtors[] = {\nkernel/bpf/crypto.c-336-\t\t{\nkernel/bpf/crypto.c:337:\t\t\t.btf_id\t = bpf_crypto_dtor_ids[0],\nkernel/bpf/crypto.c:338:\t\t\t.kfunc_btf_id = bpf_crypto_dtor_ids[1]\nkernel/bpf/crypto.c-339-\t\t},\n--\nkernel/bpf/crypto.c-346-\t\t\t\t\t \u0026crypt_init_kfunc_set);\nkernel/bpf/crypto.c:347:\treturn ret ?: register_btf_id_dtor_kfuncs(bpf_crypto_dtors,\nkernel/bpf/crypto.c:348:\t\t\t\t\t\t ARRAY_SIZE(bpf_crypto_dtors),\nkernel/bpf/crypto.c-349-\t\t\t\t\t\t THIS_MODULE);\n--\nkernel/bpf/verifier.c=4571=BTF_ID(struct, task_struct)\nkernel/bpf/verifier.c-4572-#ifdef CONFIG_CRYPTO\nkernel/bpf/verifier.c:4573:BTF_ID(struct, bpf_crypto_ctx)\nkernel/bpf/verifier.c-4574-#endif\n"
} |
| 5/2 | 2026/09/01 02:29 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 13945 output: 34 thoughts: 30 Thoughts: Here's my thinking process: **Diving into the BPF Crypto Configuration** Okay, time to get to the bottom of this. My focus right now is understanding the configuration dependencies for `BPF_CRYPTO`. That's the starting point. I need to know what other Kconfig options might need to be enabled or set in order for `BPF_CRYPTO` to work correctly. So, first things first, I need to get my hands dirty with the relevant Kconfig file. I'm going to navigate to `kernel/bpf/Kconfig`. That's where I expect to find the definition and any accompanying dependencies for `BPF_CRYPTO`. Reading that file will be key to understanding the configuration landscape here. Let's see what's in there! |
| 6/2 | 2026/09/01 02:29 | tool | read-file |
0mArgs:{
"File": "kernel/bpf/Kconfig",
"FirstLine": 80,
"LineCount": 30
}Results: {
"Contents": " 80:\t\t still reenable it by setting it to 0 later on, or permanently\n 81:\t\t disable it by setting it to 1 (from which no other transition to\n 82:\t\t 0 is possible anymore).\n 83:\t\n 84:\t\t Unprivileged BPF could be used to exploit certain potential\n 85:\t\t speculative execution side-channel vulnerabilities on unmitigated\n 86:\t\t affected hardware.\n 87:\t\n 88:\t\t If you are unsure how to answer this question, answer Y.\n 89:\t\n 90:\tconfig BPF_CRYPTO\n 91:\t\tdef_bool y\n 92:\t\tdepends on BPF_SYSCALL\n 93:\t\tselect CRYPTO_LIB_AES_CBC\n 94:\t\tselect CRYPTO_LIB_AES_ECB\n 95:\t\thelp\n 96:\t\t Provide the kfuncs needed for BPF programs to encrypt and decrypt\n 97:\t\t data. The supported algorithms are AES-CBC and AES-ECB.\n 98:\t\n 99:\tsource \"kernel/bpf/preload/Kconfig\"\n 100:\t\n 101:\tconfig BPF_LSM\n 102:\t\tbool \"Enable BPF LSM Instrumentation\"\n 103:\t\tdepends on BPF_EVENTS\n 104:\t\tdepends on BPF_SYSCALL\n 105:\t\tdepends on SECURITY\n 106:\t\tdepends on BPF_JIT\n 107:\t\thelp\n 108:\t\t Enables instrumentation of the security hooks with BPF programs for\n 109:\t\t implementing dynamic MAC and Audit Policies.\n"
} |
| 7/2 | 2026/09/01 02:29 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 14600 output: 30 thoughts: 23 Thoughts: Here's my summary, as though I'm thinking through this process: **Diving into the BPF Implementation** Alright, time to get my hands dirty with this BPF stuff. Let's see... I'm going to start with the core. To understand the build process and the overall architecture, I'll need to look at the `kernel/bpf/Makefile` first. That should give me a good sense of how the BPF components are compiled and linked within the kernel. I'm especially interested in dependencies and any potential build-time configurations that might be relevant. Then, to really grasp the runtime behavior and, crucially, the security aspects, I *have* to delve into `kernel/bpf/verifier.c`. The verifier is the heart of the BPF security model. I need to understand its logic, the checks it performs, and how it ensures that the BPF programs loaded into the kernel are safe and won't crash the system or introduce security vulnerabilities. I'm particularly interested in how it handles control flow analysis, register validation, and the handling of potential exploits, and how they interact with each other. This is where the magic (and potential headaches) happen. |
| 8/2 | 2026/09/01 02:29 | tool | grepper |
0mArgs:{
"Expression": "BPF_CRYPTO",
"PathPrefix": "kernel/bpf/"
}Results: {
"Output": "kernel/bpf/Kconfig=73=config BPF_UNPRIV_DEFAULT_OFF\n--\nkernel/bpf/Kconfig-89-\nkernel/bpf/Kconfig:90:config BPF_CRYPTO\nkernel/bpf/Kconfig-91-\tdef_bool y\n--\nkernel/bpf/Makefile=57=endif\nkernel/bpf/Makefile:58:obj-$(CONFIG_BPF_CRYPTO) += crypto.o\nkernel/bpf/Makefile-59-obj-$(CONFIG_BPF_PRELOAD) += preload/\n"
} |
| 9/2 | 2026/09/01 02:29 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 15055 output: 37 thoughts: 22 Thoughts: Here's a summary of my thought process, as requested: **Diving into the BPF Verifier** Okay, time to get to the heart of the matter. I need to take a look at the BPF verifier code. Given the context, I suspect the issue lies within the verification process itself. My best guess is that the problem I'm trying to solve is related to some edge case the verifier isn't handling properly, or perhaps an unexpected interaction between different verification rules. To start, I'm going to zero in on `kernel/bpf/verifier.c` and specifically, around line 4572. That location feels like a good starting point based on my prior analysis of similar issues. Let's see what we find... |
| 10/2 | 2026/09/01 02:29 | tool | read-file |
0mArgs:{
"File": "kernel/bpf/verifier.c",
"FirstLine": 4565,
"LineCount": 20
}Results: {
"Contents": "4565:\t#ifdef CONFIG_CGROUPS\n4566:\tBTF_ID(struct, cgroup)\n4567:\t#endif\n4568:\t#ifdef CONFIG_BPF_JIT\n4569:\tBTF_ID(struct, bpf_cpumask)\n4570:\t#endif\n4571:\tBTF_ID(struct, task_struct)\n4572:\t#ifdef CONFIG_CRYPTO\n4573:\tBTF_ID(struct, bpf_crypto_ctx)\n4574:\t#endif\n4575:\t#ifdef CONFIG_INET\n4576:\tBTF_ID(struct, bpf_ksock)\n4577:\t#endif\n4578:\tBTF_SET_END(rcu_protected_types)\n4579:\t\n4580:\tstatic bool rcu_protected_object(const struct btf *btf, u32 btf_id)\n4581:\t{\n4582:\t\tif (!btf_is_kernel(btf))\n4583:\t\t\treturn true;\n4584:\t\treturn btf_id_set_contains(\u0026rcu_protected_types, btf_id);\n"
} |
| 11/2 | 2026/09/01 02:29 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 15603 output: 195 thoughts: 653 Thoughts: **My Analysis of the BPF Crypto Patch** Okay, let's break this down systematically. First, I need to figure out the configuration requirements. It looks like `BPF_SYSCALL` is a prerequisite, and enabling `BPF_SYSCALL` automatically brings in `BPF_CRYPTO` (which depends on it). `BPF_CRYPTO` then selects `CRYPTO_LIB_AES_CBC` and `CRYPTO_LIB_AES_ECB`, which makes sense. `BPF_SYSCALL` is pretty standard, but `BPF_CRYPTO` is the new addition here. Now, are there any other dependencies? Well, `BPF_SYSCALL` depends on `BPF`, which is a given. Next, I need to check if `BPF_CRYPTO`, `BPF_SYSCALL`, or `DEBUG_INFO_BTF` are needed for kfuncs. Ah, yes, for those kfuncs (`register_btf_kfunc_id_set`), `BPF_SYSCALL` and `DEBUG_INFO_BTF` are typically required. Good to know. Next, I need to identify the important symbols, the non-static functions, the ones we'll really be focusing on. In `kernel/bpf/crypto.c`, the kfuncs are: `bpf_crypto_ctx_create`, `bpf_crypto_ctx_release`, `bpf_crypto_ctx_acquire`, `bpf_crypto_ctx_release_dtor`, `bpf_crypto_decrypt`, and `bpf_crypto_encrypt`. These are the non-static kfuncs exposed to BTF / BPF verifier. Alright, is this change worth fuzzing? Absolutely! This patch is a big deal. It's completely reworking the BPF crypto backend. We're moving from skcipher tfms to direct `aes_cbc` / `aes_ecb` library functions. This impacts validation, memory management (specifically `kfree_sensitive`), the core encryption/decryption execution path, algorithm lookup, and the kfunc interfaces themselves. This is a significant change to core BPF functionality, reachable via the `sys_bpf` syscall – definitely worth a thorough investigation. Therefore, the configs to enable are: `BPF_SYSCALL`, `BPF_CRYPTO`, and `DEBUG_INFO_BTF`. The focus symbols are: `bpf_crypto_ctx_create`, `bpf_crypto_ctx_release`, `bpf_crypto_ctx_acquire`, `bpf_crypto_ctx_release_dtor`, `bpf_crypto_decrypt`, and `bpf_crypto_encrypt`. Finally, a quick final check of all requirements and format of `set-results`. `WorthFuzzing`: true `EnableConfigs`: ["BPF_SYSCALL", "BPF_CRYPTO", "DEBUG_INFO_BTF"] `FocusSymbols`: ["bpf_crypto_ctx_create", "bpf_crypto_ctx_release", "bpf_crypto_ctx_acquire", "bpf_crypto_ctx_release_dtor", "bpf_crypto_decrypt", "bpf_crypto_encrypt"] `Reasoning`: Concise explanation. Okay, ready to call `set-results`. |
| 12/2 | 2026/09/01 02:29 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"BPF_SYSCALL",
"BPF_CRYPTO",
"DEBUG_INFO_BTF"
],
"FocusSymbols": [
"bpf_crypto_ctx_create",
"bpf_crypto_ctx_release",
"bpf_crypto_ctx_acquire",
"bpf_crypto_ctx_release_dtor",
"bpf_crypto_decrypt",
"bpf_crypto_encrypt"
],
"Reasoning": "The patch refactors BPF crypto support by removing the dynamic crypto type registration interface and implementing direct AES-CBC and AES-ECB library integration. It introduces CONFIG_BPF_CRYPTO and modifies the BPF crypto kfunc handlers (context creation, key setup, encryption, decryption, and lifecycle management), making these functions important targets for BPF program fuzzing.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"BPF_SYSCALL",
"BPF_CRYPTO",
"DEBUG_INFO_BTF"
],
"FocusSymbols": [
"bpf_crypto_ctx_create",
"bpf_crypto_ctx_release",
"bpf_crypto_ctx_acquire",
"bpf_crypto_ctx_release_dtor",
"bpf_crypto_decrypt",
"bpf_crypto_encrypt"
],
"Reasoning": "The patch refactors BPF crypto support by removing the dynamic crypto type registration interface and implementing direct AES-CBC and AES-ECB library integration. It introduces CONFIG_BPF_CRYPTO and modifies the BPF crypto kfunc handlers (context creation, key setup, encryption, decryption, and lifecycle management), making these functions important targets for BPF program fuzzing.",
"WorthFuzzing": true
} |
| 13/1 | 2026/09/01 02:29 | action | If |
0mArgs:{
"WorthFuzzing": true
}Results: null |
| 14/2 | 2026/09/01 02:29 | agent | kmsan-evaluator |
0mModel:core Args: null Results: {
"KMSANReasoning": "The patch simplifies the BPF crypto kfuncs implementation by replacing the generic crypto tfm registration architecture with direct invocations of AES library functions (CRYPTO_LIB_AES_CBC and CRYPTO_LIB_AES_ECB). \n\nMemory safety analysis:\n1. Memory Allocation \u0026 Initialization: The context `struct bpf_crypto_ctx` is allocated with `kzalloc_obj`, ensuring all fields (including `enum bpf_crypto_algo_id` and the `aes_key` union) are zero-initialized. Key setup is handled by `aes_preparekey()`. Cleanup is handled via `kfree_sensitive()`.\n2. Buffers \u0026 Info Leaks: Data encryption and decryption operate directly on dynptr buffers supplied by BPF programs after verifying block alignment and bounds (`AES_BLOCK_SIZE` checks, `dst_len \u003e= src_len`). No uninitialized kernel memory or struct padding is copied to user space or used in branching/control flow.\n3. Sanitizer Applicability: Any potential out-of-bounds dynptr accesses, buffer length calculation bugs, or lifetime/refcounting issues are covered by KASAN and standard BPF verifier/debug infrastructure. There are no uninitialized memory read risks or information leaks requiring a dedicated KMSAN session.",
"NeedsKMSAN": false
}Instruction: You are an expert Linux kernel security engineer specializing in kernel memory
error detectors (KASAN and KMSAN). Your job is to review the provided patch series and
determine if the code changes justify spawning a dedicated KMSAN (KernelMemorySanitizer)
fuzzing session in addition to standard KASAN fuzzing.
CRITICAL DISTINCTION BETWEEN KASAN AND KMSAN:
- Standard KASAN kernel builds (upstream-apparmor-kasan.config) already enable
a comprehensive suite of debugging tools and sanitizers, including KASAN
(out-of-bounds accesses, use-after-free, double free, invalid free), LOCKDEP
(locking bugs and deadlocks), UB-sanitizers, and memory corruption checks.
- KMSAN (KernelMemorySanitizer) detects reads of UNINITIALIZED memory (stack, heap,
or page allocations) and kernel-to-user memory info-leaks.
Rule: THERE IS NO SENSE IN RUNNING A KMSAN SESSION IF A BUG CAN BE CAUGHT BY KASAN,
LOCKDEP, OR OTHER STANDARD BUG DETECTORS.
A dedicated KMSAN fuzzing session incurs significant resource costs. You must ONLY
set NeedsKMSAN=true if the code changes introduce or expose UNINITIALIZED MEMORY risks
that are detected ONLY by KMSAN.
Look holistically at the patch series and surrounding code. Even if no direct
uninitialized field accesses or new buffer allocations are added in the diff itself,
a patch may alter control flow, bounds checking, or data length calculations in ways
that change how the rest of the code operates on existing buffers (e.g. allowing
uninitialized stack/heap memory to be read, copied to user space, or used in control
flow). Do not hesitate to use your code access tools to inspect the surrounding code,
called functions, and callers.
Set NeedsKMSAN=true ONLY IF the patch introduces or modifies:
1. Kernel structures sent to user space (via copy_to_user, put_user, netlink skb
attributes, ioctl output arguments, socket options, or BPF buffers) where fields
or structure padding might not be fully initialized/zeroed.
2. Conditional logic or branching that depends on potentially uninitialized variables
or struct fields.
3. Allocation or initialization of complex data structures where uninitialized fields
could be read later in reachable code paths.
4. Bounds checks, lengths, or logic in a way that allows surrounding code to access
uninitialized bytes of existing buffers.
Set NeedsKMSAN=false IF:
- The code changes primarily risk out-of-bounds access, array overflows, NULL pointer
dereferences, locking deadlocks, or use-after-free bugs (these are already caught
by KASAN, LOCKDEP, or standard bug detectors).
- All stack/heap structures touched or introduced by the patch are fully zeroed
or initialized (e.g. using = {0}, memset, kzalloc) before being read or copied.
- The patch does not introduce any risk of uninitialized memory usage or info-leaks.
Use your code access tools to inspect the surrounding code if necessary, then provide
detailed KMSANReasoning contrasting KASAN vs KMSAN applicability for this patch.
Prefer calling several tools at the same time to save round-trips.
Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.
Prompt: For your convenience, here is the diff of the changes:
commit 97b409223e251e0a20b889ab7a76b5978328fcee
Author: syz-cluster <triage@syzkaller.com>
Date: Tue Sep 1 02:29:23 2026 +0000
syz-cluster: applied patch under review
diff --git a/MAINTAINERS b/MAINTAINERS
index 3a19da74d00c9..16f13270ce1f9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4936,8 +4936,6 @@ BPF [CRYPTO]
M: Vadim Fedorenko <vadim.fedorenko@linux.dev>
L: bpf@vger.kernel.org
S: Maintained
-F: crypto/bpf_crypto_skcipher.c
-F: include/linux/bpf_crypto.h
F: kernel/bpf/crypto.c
BPF [DOCUMENTATION] (Related to Standardization)
diff --git a/crypto/Makefile b/crypto/Makefile
index 8386d55a9755e..33bb5ad595e8f 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -22,9 +22,6 @@ crypto_skcipher-y += lskcipher.o
crypto_skcipher-y += skcipher.o
obj-$(CONFIG_CRYPTO_SKCIPHER2) += crypto_skcipher.o
-ifeq ($(CONFIG_BPF_SYSCALL),y)
-obj-$(CONFIG_CRYPTO_SKCIPHER2) += bpf_crypto_skcipher.o
-endif
obj-$(CONFIG_CRYPTO_SEQIV) += seqiv.o
obj-$(CONFIG_CRYPTO_ECHAINIV) += echainiv.o
diff --git a/crypto/bpf_crypto_skcipher.c b/crypto/bpf_crypto_skcipher.c
deleted file mode 100644
index a88798d3e8c87..0000000000000
--- a/crypto/bpf_crypto_skcipher.c
+++ /dev/null
@@ -1,83 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2024 Meta, Inc */
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/bpf_crypto.h>
-#include <crypto/skcipher.h>
-
-static void *bpf_crypto_lskcipher_alloc_tfm(const char *algo)
-{
- return crypto_alloc_lskcipher(algo, 0, 0);
-}
-
-static void bpf_crypto_lskcipher_free_tfm(void *tfm)
-{
- crypto_free_lskcipher(tfm);
-}
-
-static int bpf_crypto_lskcipher_has_algo(const char *algo)
-{
- return crypto_has_skcipher(algo, CRYPTO_ALG_TYPE_LSKCIPHER, CRYPTO_ALG_TYPE_MASK);
-}
-
-static int bpf_crypto_lskcipher_setkey(void *tfm, const u8 *key, unsigned int keylen)
-{
- return crypto_lskcipher_setkey(tfm, key, keylen);
-}
-
-static u32 bpf_crypto_lskcipher_get_flags(void *tfm)
-{
- return crypto_lskcipher_get_flags(tfm);
-}
-
-static unsigned int bpf_crypto_lskcipher_ivsize(void *tfm)
-{
- return crypto_lskcipher_ivsize(tfm);
-}
-
-static unsigned int bpf_crypto_lskcipher_statesize(void *tfm)
-{
- return crypto_lskcipher_statesize(tfm);
-}
-
-static int bpf_crypto_lskcipher_encrypt(void *tfm, const u8 *src, u8 *dst,
- unsigned int len, u8 *siv)
-{
- return crypto_lskcipher_encrypt(tfm, src, dst, len, siv);
-}
-
-static int bpf_crypto_lskcipher_decrypt(void *tfm, const u8 *src, u8 *dst,
- unsigned int len, u8 *siv)
-{
- return crypto_lskcipher_decrypt(tfm, src, dst, len, siv);
-}
-
-static const struct bpf_crypto_type bpf_crypto_lskcipher_type = {
- .alloc_tfm = bpf_crypto_lskcipher_alloc_tfm,
- .free_tfm = bpf_crypto_lskcipher_free_tfm,
- .has_algo = bpf_crypto_lskcipher_has_algo,
- .setkey = bpf_crypto_lskcipher_setkey,
- .encrypt = bpf_crypto_lskcipher_encrypt,
- .decrypt = bpf_crypto_lskcipher_decrypt,
- .ivsize = bpf_crypto_lskcipher_ivsize,
- .statesize = bpf_crypto_lskcipher_statesize,
- .get_flags = bpf_crypto_lskcipher_get_flags,
- .owner = THIS_MODULE,
- .name = "skcipher",
-};
-
-static int __init bpf_crypto_skcipher_init(void)
-{
- return bpf_crypto_register_type(&bpf_crypto_lskcipher_type);
-}
-
-static void __exit bpf_crypto_skcipher_exit(void)
-{
- int err = bpf_crypto_unregister_type(&bpf_crypto_lskcipher_type);
- WARN_ON_ONCE(err);
-}
-
-module_init(bpf_crypto_skcipher_init);
-module_exit(bpf_crypto_skcipher_exit);
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Symmetric key cipher support for BPF");
diff --git a/include/linux/bpf_crypto.h b/include/linux/bpf_crypto.h
deleted file mode 100644
index a41e71d4e2d9f..0000000000000
--- a/include/linux/bpf_crypto.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */
-#ifndef _BPF_CRYPTO_H
-#define _BPF_CRYPTO_H
-
-struct bpf_crypto_type {
- void *(*alloc_tfm)(const char *algo);
- void (*free_tfm)(void *tfm);
- int (*has_algo)(const char *algo);
- int (*setkey)(void *tfm, const u8 *key, unsigned int keylen);
- int (*setauthsize)(void *tfm, unsigned int authsize);
- int (*encrypt)(void *tfm, const u8 *src, u8 *dst, unsigned int len, u8 *iv);
- int (*decrypt)(void *tfm, const u8 *src, u8 *dst, unsigned int len, u8 *iv);
- unsigned int (*ivsize)(void *tfm);
- unsigned int (*statesize)(void *tfm);
- u32 (*get_flags)(void *tfm);
- struct module *owner;
- char name[14];
-};
-
-int bpf_crypto_register_type(const struct bpf_crypto_type *type);
-int bpf_crypto_unregister_type(const struct bpf_crypto_type *type);
-
-#endif /* _BPF_CRYPTO_H */
diff --git a/kernel/bpf/Kconfig b/kernel/bpf/Kconfig
index eb3de35734f09..822599b42be2e 100644
--- a/kernel/bpf/Kconfig
+++ b/kernel/bpf/Kconfig
@@ -87,6 +87,15 @@ config BPF_UNPRIV_DEFAULT_OFF
If you are unsure how to answer this question, answer Y.
+config BPF_CRYPTO
+ def_bool y
+ depends on BPF_SYSCALL
+ select CRYPTO_LIB_AES_CBC
+ select CRYPTO_LIB_AES_ECB
+ help
+ Provide the kfuncs needed for BPF programs to encrypt and decrypt
+ data. The supported algorithms are AES-CBC and AES-ECB.
+
source "kernel/bpf/preload/Kconfig"
config BPF_LSM
diff --git a/kernel/bpf/Makefile b/kernel/bpf/Makefile
index 90255d80e5be6..ab2e5d2782e6e 100644
--- a/kernel/bpf/Makefile
+++ b/kernel/bpf/Makefile
@@ -55,9 +55,7 @@ obj-$(CONFIG_BPF_SYSCALL) += cpumask.o
# semantics within pahole are revisited accordingly.
obj-${CONFIG_BPF_LSM} += bpf_lsm_proto.o bpf_lsm.o
endif
-ifneq ($(CONFIG_CRYPTO),)
-obj-$(CONFIG_BPF_SYSCALL) += crypto.o
-endif
+obj-$(CONFIG_BPF_CRYPTO) += crypto.o
obj-$(CONFIG_BPF_PRELOAD) += preload/
obj-$(CONFIG_BPF_SYSCALL) += relo_core.o
diff --git a/kernel/bpf/crypto.c b/kernel/bpf/crypto.c
index 51f89cecefb4d..8cdc16f9b374a 100644
--- a/kernel/bpf/crypto.c
+++ b/kernel/bpf/crypto.c
@@ -1,19 +1,13 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2024 Meta, Inc */
#include <linux/bpf.h>
-#include <linux/bpf_crypto.h>
#include <linux/bpf_mem_alloc.h>
#include <linux/btf.h>
#include <linux/btf_ids.h>
#include <linux/filter.h>
-#include <linux/scatterlist.h>
#include <linux/skbuff.h>
-#include <crypto/skcipher.h>
-
-struct bpf_crypto_type_list {
- const struct bpf_crypto_type *type;
- struct list_head list;
-};
+#include <crypto/aes-cbc.h>
+#include <crypto/aes-ecb.h>
/* BPF crypto initialization parameters struct */
/**
@@ -36,94 +30,53 @@ struct bpf_crypto_params {
u32 authsize;
};
-static LIST_HEAD(bpf_crypto_types);
-static DECLARE_RWSEM(bpf_crypto_types_sem);
+enum bpf_crypto_algo_id {
+ BPF_ALGO_AES_CBC,
+ BPF_ALGO_AES_ECB,
+};
+
+static const struct {
+ const char *type_name;
+ const char *algo_name;
+ enum bpf_crypto_algo_id algo;
+} bpf_crypto_algos[] = {
+ { "skcipher", "cbc(aes)", BPF_ALGO_AES_CBC },
+ { "skcipher", "ecb(aes)", BPF_ALGO_AES_ECB },
+};
+
+static bool bpf_crypto_find_algo(const struct bpf_crypto_params *params,
+ enum bpf_crypto_algo_id *id_ret)
+{
+ for (size_t i = 0; i < ARRAY_SIZE(bpf_crypto_algos); i++) {
+ if (strncmp(bpf_crypto_algos[i].type_name, params->type,
+ sizeof(params->type)) == 0 &&
+ strncmp(bpf_crypto_algos[i].algo_name, params->algo,
+ sizeof(params->algo)) == 0) {
+ *id_ret = bpf_crypto_algos[i].algo;
+ return true;
+ }
+ }
+ return false;
+}
/**
* struct bpf_crypto_ctx - refcounted BPF crypto context structure
- * @type: The pointer to bpf crypto type
- * @tfm: The pointer to instance of crypto API struct.
- * @siv_len: Size of IV and state storage for cipher
+ * @algo: The crypto algorithm ID
+ * @key: The crypto key
* @rcu: The RCU head used to free the crypto context with RCU safety.
* @usage: Object reference counter. When the refcount goes to 0, the
* memory is released back to the BPF allocator, which provides
* RCU safety.
*/
struct bpf_crypto_ctx {
- const struct bpf_crypto_type *type;
- void *tfm;
- u32 siv_len;
+ enum bpf_crypto_algo_id algo;
+ union {
+ struct aes_key aes;
+ } key;
struct rcu_head rcu;
refcount_t usage;
};
-int bpf_crypto_register_type(const struct bpf_crypto_type *type)
-{
- struct bpf_crypto_type_list *node;
- int err = -EBUSY;
-
- down_write(&bpf_crypto_types_sem);
- list_for_each_entry(node, &bpf_crypto_types, list) {
- if (!strcmp(node->type->name, type->name))
- goto unlock;
- }
-
- node = kmalloc_obj(*node);
- err = -ENOMEM;
- if (!node)
- goto unlock;
-
- node->type = type;
- list_add(&node->list, &bpf_crypto_types);
- err = 0;
-
-unlock:
- up_write(&bpf_crypto_types_sem);
-
- return err;
-}
-EXPORT_SYMBOL_GPL(bpf_crypto_register_type);
-
-int bpf_crypto_unregister_type(const struct bpf_crypto_type *type)
-{
- struct bpf_crypto_type_list *node;
- int err = -ENOENT;
-
- down_write(&bpf_crypto_types_sem);
- list_for_each_entry(node, &bpf_crypto_types, list) {
- if (strcmp(node->type->name, type->name))
- continue;
-
- list_del(&node->list);
- kfree(node);
- err = 0;
- break;
- }
- up_write(&bpf_crypto_types_sem);
-
- return err;
-}
-EXPORT_SYMBOL_GPL(bpf_crypto_unregister_type);
-
-static const struct bpf_crypto_type *bpf_crypto_get_type(const char *name)
-{
- const struct bpf_crypto_type *type = ERR_PTR(-ENOENT);
- struct bpf_crypto_type_list *node;
-
- down_read(&bpf_crypto_types_sem);
- list_for_each_entry(node, &bpf_crypto_types, list) {
- if (strcmp(node->type->name, name))
- continue;
-
- if (try_module_get(node->type->owner))
- type = node->type;
- break;
- }
- up_read(&bpf_crypto_types_sem);
-
- return type;
-}
-
__bpf_kfunc_start_defs();
/**
@@ -146,7 +99,6 @@ __bpf_kfunc struct bpf_crypto_ctx *
bpf_crypto_ctx_create(const struct bpf_crypto_params *params, u32 params__sz,
int *err)
{
- const struct bpf_crypto_type *type;
struct bpf_crypto_ctx *ctx;
if (!params || params->reserved[0] || params->reserved[1] ||
@@ -155,69 +107,40 @@ bpf_crypto_ctx_create(const struct bpf_crypto_params *params, u32 params__sz,
return NULL;
}
- type = bpf_crypto_get_type(params->type);
- if (IS_ERR(type)) {
- *err = PTR_ERR(type);
- return NULL;
- }
-
- if (!type->has_algo(params->algo)) {
- *err = -EOPNOTSUPP;
- goto err_module_put;
- }
-
- if (!!params->authsize ^ !!type->setauthsize) {
- *err = -EOPNOTSUPP;
- goto err_module_put;
- }
-
- if (!params->key_len || params->key_len > sizeof(params->key)) {
- *err = -EINVAL;
- goto err_module_put;
- }
-
ctx = kzalloc_obj(*ctx);
if (!ctx) {
*err = -ENOMEM;
- goto err_module_put;
+ return NULL;
}
- ctx->type = type;
- ctx->tfm = type->alloc_tfm(params->algo);
- if (IS_ERR(ctx->tfm)) {
- *err = PTR_ERR(ctx->tfm);
- goto err_free_ctx;
+ if (!bpf_crypto_find_algo(params, &ctx->algo)) {
+ *err = -ENOENT;
+ goto out;
}
- if (params->authsize) {
- *err = type->setauthsize(ctx->tfm, params->authsize);
- if (*err)
- goto err_free_tfm;
+ switch (ctx->algo) {
+ case BPF_ALGO_AES_CBC:
+ case BPF_ALGO_AES_ECB:
+ if (params->authsize)
+ *err = -EOPNOTSUPP;
+ else
+ *err = aes_preparekey(&ctx->key.aes, params->key,
+ params->key_len);
+ break;
+ default:
+ WARN_ON(1);
+ *err = -ENOENT;
+ break;
}
- *err = type->setkey(ctx->tfm, params->key, params->key_len);
- if (*err)
- goto err_free_tfm;
-
- if (type->get_flags(ctx->tfm) & CRYPTO_TFM_NEED_KEY) {
- *err = -EINVAL;
- goto err_free_tfm;
+out:
+ if (*err) {
+ kfree_sensitive(ctx);
+ return NULL;
}
- ctx->siv_len = type->ivsize(ctx->tfm) + type->statesize(ctx->tfm);
-
refcount_set(&ctx->usage, 1);
-
return ctx;
-
-err_free_tfm:
- type->free_tfm(ctx->tfm);
-err_free_ctx:
- kfree(ctx);
-err_module_put:
- module_put(type->owner);
-
- return NULL;
}
static void crypto_free_cb(struct rcu_head *head)
@@ -225,9 +148,7 @@ static void crypto_free_cb(struct rcu_head *head)
struct bpf_crypto_ctx *ctx;
ctx = container_of(head, struct bpf_crypto_ctx, rcu);
- ctx->type->free_tfm(ctx->tfm);
- module_put(ctx->type->owner);
- kfree(ctx);
+ kfree_sensitive(ctx);
}
/**
@@ -267,27 +188,53 @@ __bpf_kfunc void bpf_crypto_ctx_release_dtor(void *ctx)
}
CFI_NOSEAL(bpf_crypto_ctx_release_dtor);
+static int bpf_aes_cbc_crypt(u8 *dst, u32 dst_len, const u8 *src, u32 src_len,
+ u8 *iv, u32 iv_len,
+ const struct bpf_crypto_ctx *ctx, bool decrypt)
+{
+ if (iv_len != AES_BLOCK_SIZE)
+ return -EINVAL;
+ if (src_len % AES_BLOCK_SIZE || dst_len < src_len)
+ return -EINVAL;
+ if (decrypt)
+ aes_cbc_decrypt(dst, src, src_len, iv, &ctx->key.aes);
+ else
+ aes_cbc_encrypt(dst, src, src_len, iv, &ctx->key.aes);
+ return 0;
+}
+
+static int bpf_aes_ecb_crypt(u8 *dst, u32 dst_len, const u8 *src, u32 src_len,
+ u8 *iv, u32 iv_len,
+ const struct bpf_crypto_ctx *ctx, bool decrypt)
+{
+ if (iv_len != 0)
+ return -EINVAL;
+ if (src_len % AES_BLOCK_SIZE || dst_len < src_len)
+ return -EINVAL;
+ if (decrypt)
+ aes_ecb_decrypt(dst, src, src_len, &ctx->key.aes);
+ else
+ aes_ecb_encrypt(dst, src, src_len, &ctx->key.aes);
+ return 0;
+}
+
static int bpf_crypto_crypt(const struct bpf_crypto_ctx *ctx,
const struct bpf_dynptr_kern *src,
const struct bpf_dynptr_kern *dst,
- const struct bpf_dynptr_kern *siv,
+ const struct bpf_dynptr_kern *iv,
bool decrypt)
{
- u32 src_len, dst_len, siv_len;
+ u32 src_len, dst_len, iv_len;
const u8 *psrc;
u8 *pdst, *piv;
- int err;
if (__bpf_dynptr_is_rdonly(dst))
return -EINVAL;
- siv_len = siv ? __bpf_dynptr_size(siv) : 0;
+ iv_len = iv ? __bpf_dynptr_size(iv) : 0;
src_len = __bpf_dynptr_size(src);
dst_len = __bpf_dynptr_size(dst);
- if (!src_len || !dst_len || src_len > dst_len)
- return -EINVAL;
-
- if (siv_len != ctx->siv_len)
+ if (!src_len || !dst_len)
return -EINVAL;
psrc = __bpf_dynptr_data(src, src_len);
@@ -297,14 +244,20 @@ static int bpf_crypto_crypt(const struct bpf_crypto_ctx *ctx,
if (!pdst)
return -EINVAL;
- piv = siv_len ? __bpf_dynptr_data_rw(siv, siv_len) : NULL;
- if (siv_len && !piv)
+ piv = iv_len ? __bpf_dynptr_data_rw(iv, iv_len) : NULL;
+ if (iv_len && !piv)
return -EINVAL;
- err = decrypt ? ctx->type->decrypt(ctx->tfm, psrc, pdst, src_len, piv)
- : ctx->type->encrypt(ctx->tfm, psrc, pdst, src_len, piv);
-
- return err;
+ switch (ctx->algo) {
+ case BPF_ALGO_AES_CBC:
+ return bpf_aes_cbc_crypt(pdst, dst_len, psrc, src_len, piv,
+ iv_len, ctx, decrypt);
+ case BPF_ALGO_AES_ECB:
+ return bpf_aes_ecb_crypt(pdst, dst_len, psrc, src_len, piv,
+ iv_len, ctx, decrypt);
+ default:
+ return -EINVAL;
+ }
}
/**
@@ -312,20 +265,20 @@ 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__nullable: bpf_dynptr to IV data and state data to be used by decryptor. May be NULL.
+ * @iv__nullable: bpf_dynptr to the initialization vector. 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__nullable)
+ const struct bpf_dynptr *iv__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__nullable;
+ const struct bpf_dynptr_kern *iv_kern = (struct bpf_dynptr_kern *)iv__nullable;
- return bpf_crypto_crypt(ctx, src_kern, dst_kern, siv_kern, true);
+ return bpf_crypto_crypt(ctx, src_kern, dst_kern, iv_kern, true);
}
/**
@@ -333,20 +286,20 @@ __bpf_kfunc int bpf_crypto_decrypt(struct bpf_crypto_ctx *ctx,
* @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 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.
+ * @iv__nullable: bpf_dynptr to the initialization vector. 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__nullable)
+ const struct bpf_dynptr *iv__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__nullable;
+ const struct bpf_dynptr_kern *iv_kern = (struct bpf_dynptr_kern *)iv__nullable;
- return bpf_crypto_crypt(ctx, src_kern, dst_kern, siv_kern, false);
+ return bpf_crypto_crypt(ctx, src_kern, dst_kern, iv_kern, false);
}
__bpf_kfunc_end_defs();
|
| 15/3 | 2026/09/01 02:29 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 9096 output: 18 thoughts: 840 Thoughts: **Analyzing the BPF Crypto Patch for Uninitialized Memory Risks**
Okay, let's dive into this patch and determine if it warrants a dedicated KMSAN fuzzing session. My initial thought is to carefully analyze the code for any potential uninitialized memory exposures or memory leaks.
First, I need to grasp the overall context of the changes. It seems we're moving away from the generic BPF crypto dynamic registration framework (using `crypto tfm` API for `skcipher` and `lskcipher`) and opting for a direct implementation leveraging the `crypto/aes-cbc.h` and `crypto/aes-ecb.h` helpers (`CRYPTO_LIB_AES_CBC` and `CRYPTO_LIB_AES_ECB`). That's a significant shift, and it's where I need to pay close attention.
Now, let's get into the details:
* The patch removes `crypto/bpf_crypto_skcipher.c` and `include/linux/bpf_crypto.h`, suggesting a simplification of the framework.
* In `kernel/bpf/Kconfig`, it's adding `config BPF_CRYPTO` and selecting `CRYPTO_LIB_AES_CBC` and `CRYPTO_LIB_AES_ECB`, which confirms the AES-specific focus.
* The critical changes are within `kernel/bpf/crypto.c`. Here's where I need to focus the most:
* The `bpf_crypto_types` registry and the `tfm`-based dispatch are gone, replaced by a hardcoded `enum bpf_crypto_algo_id` for AES CBC and ECB. This is a simplification but could introduce issues if not handled carefully.
* The `struct bpf_crypto_ctx` has been modified. It now contains an `enum bpf_crypto_algo_id`, a union for the AES key (`struct aes_key`), an `rcu_head`, and a `refcount_t`. This looks generally sound, and I see it's now zero-initialized by `kzalloc_obj`, which is a good starting point.
* `bpf_crypto_ctx_create()` is where I want to look closely. It's doing some parameter checking, calling `aes_preparekey`, and handling errors by freeing the context with `kfree_sensitive`. This seems reasonable, but `aes_preparekey` needs further investigation.
* `crypto_free_cb()` uses `kfree_sensitive`, which is a good sign for sensitive key material.
* The `bpf_aes_cbc_crypt` and `bpf_aes_ecb_crypt` functions are present with sanity checks (IV length, source/destination length checks). It seems like the core AES operations are delegated to `aes_cbc_decrypt`/`aes_cbc_encrypt` and `aes_ecb_decrypt`/`aes_ecb_encrypt`. These functions are my next area of focus.
* `bpf_crypto_crypt` seems to be the top-level function that does size checking, extracts the pointers, and dispatches to the AES CBC or ECB functions. It also calls the `__bpf_dynptr_is_rdonly` and `__bpf_dynptr_data` family of functions. This is where I need to see what's happening with the source, destination, and IV buffers.
My main concerns right now revolve around these aspects:
1. **`aes_preparekey`:** I need to understand its implementation and whether it could potentially leave any uninitialized memory in the `struct aes_key`.
2. **`aes_cbc_encrypt/decrypt` and `aes_ecb_encrypt/decrypt`:** I have to analyze these implementations for any subtle flaws related to memory access patterns or padding issues that might expose uninitialized data. Specifically, I'll need to check how the input data is handled and if there's any risk of reading beyond the provided buffers.
3. **Data movement:** the `__bpf_dynptr_data` calls. The important thing here is to ensure that the source, destination and IV buffers are all handled safely.
4. **`struct aes_key`:** The definition of this data structure is critical for checking padding bytes.
I will conduct a deeper dive into the surrounding code, especially the definitions of `struct aes_key`, `aes_preparekey`, and the AES encrypt/decrypt functions, to uncover any potential vulnerabilities. I'll be searching for any occurrences of these functions or definitions, so as not to miss any detail. Based on my findings, I'll decide if a KMSAN fuzzing session is necessary to provide an extra layer of security.
|
| 16/3 | 2026/09/01 02:30 | tool | grepper |
0mArgs:{
"Expression": "aes_preparekey"
}Results: {
"Output": "arch/arm/crypto/aes-neonbs-glue.c=234=static int aesbs_xts_setkey(struct crypto_skcipher *tfm, const u8 *in_key,\n--\narch/arm/crypto/aes-neonbs-glue.c-244-\tkey_len /= 2;\narch/arm/crypto/aes-neonbs-glue.c:245:\terr = aes_preparekey(\u0026ctx-\u003efallback, in_key, key_len);\narch/arm/crypto/aes-neonbs-glue.c-246-\tif (err)\n--\ncrypto/aes.c=26=static int crypto_aes_setkey(struct crypto_tfm *tfm, const u8 *in_key,\n--\ncrypto/aes.c-30-\ncrypto/aes.c:31:\treturn aes_preparekey(key, in_key, key_len);\ncrypto/aes.c-32-}\n--\ncrypto/aes.c=213=crypto_aes_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *in_key,\n--\ncrypto/aes.c-217-\ncrypto/aes.c:218:\treturn aes_preparekey(key, in_key, key_len);\ncrypto/aes.c-219-}\n--\ndrivers/crypto/chelsio/chcr_algo.c=1025=static int chcr_update_tweak(struct skcipher_request *req, u8 *iv,\n--\ndrivers/crypto/chelsio/chcr_algo.c-1046-\t\t\t== CHCR_KEYCTX_CIPHER_KEY_SIZE_192)\ndrivers/crypto/chelsio/chcr_algo.c:1047:\t\tret = aes_preparekey(\u0026aes, key, keylen - 8);\ndrivers/crypto/chelsio/chcr_algo.c-1048-\telse\ndrivers/crypto/chelsio/chcr_algo.c:1049:\t\tret = aes_preparekey(\u0026aes, key, keylen);\ndrivers/crypto/chelsio/chcr_algo.c-1050-\tif (ret)\n--\ninclude/crypto/aes-cbc.h-19- *\tlast ciphertext block (or left unchanged if @len == 0).\ninclude/crypto/aes-cbc.h:20: * @key: The key, already prepared using aes_preparekey() or aes_prepareenckey()\ninclude/crypto/aes-cbc.h-21- *\n--\ninclude/crypto/aes-cbc.h=27=void aes_cbc_encrypt(u8 *dst, const u8 *src, size_t len,\n--\ninclude/crypto/aes-cbc.h-37- *\tlast ciphertext block (or left unchanged if @len == 0).\ninclude/crypto/aes-cbc.h:38: * @key: The key, already prepared using aes_preparekey()\ninclude/crypto/aes-cbc.h-39- *\n--\ninclude/crypto/aes-cbc.h=45=void aes_cbc_decrypt(u8 *dst, const u8 *src, size_t len,\n--\ninclude/crypto/aes-cbc.h-54- * @iv: The initialization vector, clobbered by this function\ninclude/crypto/aes-cbc.h:55: * @key: The key, already prepared using aes_preparekey() or aes_prepareenckey()\ninclude/crypto/aes-cbc.h-56- *\n--\ninclude/crypto/aes-cbc.h=59=void aes_cbc_cts_encrypt(u8 *dst, const u8 *src, size_t len,\n--\ninclude/crypto/aes-cbc.h-68- * @iv: The initialization vector, clobbered by this function\ninclude/crypto/aes-cbc.h:69: * @key: The key, already prepared using aes_preparekey()\ninclude/crypto/aes-cbc.h-70- *\n--\ninclude/crypto/aes-ctr.h-18- * @ctr: The counter. It will be incremented by ceil(@len / AES_BLOCK_SIZE).\ninclude/crypto/aes-ctr.h:19: * @key: The key, already prepared using aes_preparekey() or aes_prepareenckey()\ninclude/crypto/aes-ctr.h-20- *\n--\ninclude/crypto/aes-ctr.h=34=void aes_ctr(u8 *dst, const u8 *src, size_t len,\n--\ninclude/crypto/aes-ctr.h-45- * @iv: The initialization vector\ninclude/crypto/aes-ctr.h:46: * @key: The key, already prepared using aes_preparekey() or aes_prepareenckey()\ninclude/crypto/aes-ctr.h-47- *\n--\ninclude/crypto/aes-ecb.h-17- * @len: Number of bytes to encrypt. Must be a multiple of AES_BLOCK_SIZE.\ninclude/crypto/aes-ecb.h:18: * @key: The key, already prepared using aes_preparekey() or aes_prepareenckey()\ninclude/crypto/aes-ecb.h-19- *\n--\ninclude/crypto/aes-ecb.h=28=void aes_ecb_encrypt(u8 *dst, const u8 *src, size_t len, aes_encrypt_arg key);\n--\ninclude/crypto/aes-ecb.h-35- * @len: Number of bytes to decrypt. Must be a multiple of AES_BLOCK_SIZE.\ninclude/crypto/aes-ecb.h:36: * @key: The key, already prepared using aes_preparekey()\ninclude/crypto/aes-ecb.h-37- *\n--\ninclude/crypto/aes.h=308=void aes_sparc64_ctr_crypt_256(const u64 *key, const u64 *input, u64 *output,\n--\ninclude/crypto/aes.h-312-/**\ninclude/crypto/aes.h:313: * aes_preparekey() - Prepare an AES key for encryption and decryption\ninclude/crypto/aes.h-314- * @key: (output) The key structure to initialize\n--\ninclude/crypto/aes.h-334- */\ninclude/crypto/aes.h:335:int aes_preparekey(struct aes_key *key, const u8 *in_key, size_t key_len);\ninclude/crypto/aes.h-336-\n--\ninclude/crypto/aes.h=377=void aes_encrypt(aes_encrypt_arg key, u8 out[at_least AES_BLOCK_SIZE],\n--\ninclude/crypto/aes.h-381- * aes_decrypt() - Decrypt a single AES block\ninclude/crypto/aes.h:382: * @key: The AES key, previously initialized by aes_preparekey()\ninclude/crypto/aes.h-383- * @out: Buffer to store the plaintext block\n--\nkernel/bpf/crypto.c=99=bpf_crypto_ctx_create(const struct bpf_crypto_params *params, u32 params__sz,\n--\nkernel/bpf/crypto.c-126-\t\telse\nkernel/bpf/crypto.c:127:\t\t\t*err = aes_preparekey(\u0026ctx-\u003ekey.aes, params-\u003ekey,\nkernel/bpf/crypto.c-128-\t\t\t\t\t params-\u003ekey_len);\n--\nlib/crypto/aes.c=411=static void __maybe_unused aes_decrypt_generic(const u32 inv_rndkeys[],\n--\nlib/crypto/aes.c-450- *\nlib/crypto/aes.c:451: * aes_preparekey_arch() is passed an optional pointer 'inv_k' which points to\nlib/crypto/aes.c-452- * the area to store the prepared decryption key. It will be NULL if the user\nlib/crypto/aes.c:453: * is requesting encryption-only. aes_preparekey_arch() is also passed a valid\nlib/crypto/aes.c-454- * 'key_len' and 'nrounds', corresponding to AES-128, AES-192, or AES-256.\n--\nlib/crypto/aes.c-461-\nlib/crypto/aes.c:462:static void aes_preparekey_arch(union aes_enckey_arch *k,\nlib/crypto/aes.c-463-\t\t\t\tunion aes_invkey_arch *inv_k,\n--\nlib/crypto/aes.c=477=static void aes_decrypt_arch(const struct aes_key *key,\n--\nlib/crypto/aes.c-484-\nlib/crypto/aes.c:485:static int __aes_preparekey(struct aes_enckey *enc_key,\nlib/crypto/aes.c-486-\t\t\t union aes_invkey_arch *inv_k,\n--\nlib/crypto/aes.c-492-\tenc_key-\u003enrounds = 6 + key_len / 4;\nlib/crypto/aes.c:493:\taes_preparekey_arch(\u0026enc_key-\u003ek, inv_k, in_key, key_len,\nlib/crypto/aes.c-494-\t\t\t enc_key-\u003enrounds);\n--\nlib/crypto/aes.c-497-\nlib/crypto/aes.c:498:int aes_preparekey(struct aes_key *key, const u8 *in_key, size_t key_len)\nlib/crypto/aes.c-499-{\nlib/crypto/aes.c:500:\treturn __aes_preparekey((struct aes_enckey *)key, \u0026key-\u003einv_k,\nlib/crypto/aes.c-501-\t\t\t\tin_key, key_len);\nlib/crypto/aes.c-502-}\nlib/crypto/aes.c:503:EXPORT_SYMBOL(aes_preparekey);\nlib/crypto/aes.c-504-\nlib/crypto/aes.c=505=int aes_prepareenckey(struct aes_enckey *key, const u8 *in_key, size_t key_len)\nlib/crypto/aes.c-506-{\nlib/crypto/aes.c:507:\treturn __aes_preparekey(key, NULL, in_key, key_len);\nlib/crypto/aes.c-508-}\n--\nlib/crypto/aes.c=526=static void __init aes_fips_test(void)\n--\nlib/crypto/aes.c-530-\nlib/crypto/aes.c:531:\tif (aes_preparekey(\u0026key, fips_test_key, sizeof(fips_test_key)) != 0)\nlib/crypto/aes.c-532-\t\tpanic(\"aes: FIPS self-test failed (preparekey)\\n\");\n--\nlib/crypto/aes.c=814=static void __init aes_ecb_fips_test(void)\n--\nlib/crypto/aes.c-818-\nlib/crypto/aes.c:819:\tif (aes_preparekey(\u0026key, fips_test_key, sizeof(fips_test_key)) != 0)\nlib/crypto/aes.c-820-\t\tpanic(\"aes: ECB FIPS self-test failed (preparekey)\\n\");\n--\nlib/crypto/aes.c=1024=static void __init aes_cbc_fips_test(void)\n--\nlib/crypto/aes.c-1029-\nlib/crypto/aes.c:1030:\tif (aes_preparekey(\u0026key, fips_test_key, sizeof(fips_test_key)) != 0)\nlib/crypto/aes.c-1031-\t\tpanic(\"aes: CBC FIPS self-test failed (preparekey)\\n\");\n--\nlib/crypto/aes.c=1047=static void __init aes_cbc_cts_fips_test(void)\n--\nlib/crypto/aes.c-1058-\nlib/crypto/aes.c:1059:\tif (aes_preparekey(\u0026key, fips_test_key, sizeof(fips_test_key)) != 0)\nlib/crypto/aes.c-1060-\t\tpanic(\"aes: CBC-CTS FIPS self-test failed (preparekey)\\n\");\n--\nlib/crypto/aes.c=1206=int aes_xts_preparekey(struct aes_xts_key *key, const u8 *in_key,\n--\nlib/crypto/aes.c-1214-\t/* First half of XTS key is the main key */\nlib/crypto/aes.c:1215:\terr = aes_preparekey(\u0026key-\u003emain_key, in_key, key_len / 2);\nlib/crypto/aes.c-1216-\tif (unlikely(err))\n--\nlib/crypto/arm/aes.h=12=asmlinkage void __aes_arm_decrypt(const u32 inv_rk[], int rounds,\n--\nlib/crypto/arm/aes.h-15-\nlib/crypto/arm/aes.h:16:static void aes_preparekey_arch(union aes_enckey_arch *k,\nlib/crypto/arm/aes.h-17-\t\t\t\tunion aes_invkey_arch *inv_k,\n--\nlib/crypto/arm64/aes.h=41=static void aes_expandkey_arm64(u32 rndkeys[], u32 *inv_rndkeys,\n--\nlib/crypto/arm64/aes.h-107-\nlib/crypto/arm64/aes.h:108:static void aes_preparekey_arch(union aes_enckey_arch *k,\nlib/crypto/arm64/aes.h-109-\t\t\t\tunion aes_invkey_arch *inv_k,\n--\nlib/crypto/powerpc/aes.h=38=static void spe_end(void)\n--\nlib/crypto/powerpc/aes.h-44-\nlib/crypto/powerpc/aes.h:45:static void aes_preparekey_arch(union aes_enckey_arch *k,\nlib/crypto/powerpc/aes.h-46-\t\t\t\tunion aes_invkey_arch *inv_k,\n--\nlib/crypto/powerpc/aes.h=109=static void rndkey_from_vsx(u32 out[4], const u32 in[4], bool apply_inv_mix)\n--\nlib/crypto/powerpc/aes.h-128-\nlib/crypto/powerpc/aes.h:129:static void aes_preparekey_arch(union aes_enckey_arch *k,\nlib/crypto/powerpc/aes.h-130-\t\t\t\tunion aes_invkey_arch *inv_k,\n--\nlib/crypto/riscv/aes.h=15=void aes_decrypt_zvkned(const u32 rndkeys[], int key_len,\n--\nlib/crypto/riscv/aes.h-17-\nlib/crypto/riscv/aes.h:18:static void aes_preparekey_arch(union aes_enckey_arch *k,\nlib/crypto/riscv/aes.h-19-\t\t\t\tunion aes_invkey_arch *inv_k,\n--\nlib/crypto/s390/aes.h=12=static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_cpacf_aes256);\n--\nlib/crypto/s390/aes.h-19- */\nlib/crypto/s390/aes.h:20:static void aes_preparekey_arch(union aes_enckey_arch *k,\nlib/crypto/s390/aes.h-21-\t\t\t\tunion aes_invkey_arch *inv_k,\n--\nlib/crypto/sparc/aes.h=45=void aes_sparc64_decrypt_256(const u64 *key, const u32 *input, u32 *output);\nlib/crypto/sparc/aes.h-46-\nlib/crypto/sparc/aes.h:47:static void aes_preparekey_arch(union aes_enckey_arch *k,\nlib/crypto/sparc/aes.h-48-\t\t\t\tunion aes_invkey_arch *inv_k,\n--\nlib/crypto/x86/aes.h=18=void aes_decrypt_aesni(const u32 inv_rndkeys[], int nrounds,\n--\nlib/crypto/x86/aes.h-31- */\nlib/crypto/x86/aes.h:32:static void aes_preparekey_arch(union aes_enckey_arch *k,\nlib/crypto/x86/aes.h-33-\t\t\t\tunion aes_invkey_arch *inv_k,\n"
} |
| 17/3 | 2026/09/01 02:30 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 15141 output: 35 thoughts: 49 Thoughts: **Analyzing Kernel BPF Crypto Code** Okay, let's dive in. First, I need to take a look at the changes specifically made in `kernel/bpf/crypto.c`. This is where the core crypto BPF functionality resides, so it’s critical to understand any modifications. I'll need to go through the diffs carefully to spot any potential issues, especially related to security or performance. Then, to get a holistic picture, I'm going to read the entire `kernel/bpf/crypto.c` file from top to bottom. I want to thoroughly examine how dynptrs and the BPF context are being utilized and allocated within the crypto context. I need to understand the lifecycle of these constructs to ensure they are being managed correctly, with no memory leaks, and that the contexts are being handled safely. This thorough review is crucial for BPF code, as errors here could lead to serious vulnerabilities. I'll need to pay extra attention to any pointer arithmetic or off-by-one errors. |
| 18/3 | 2026/09/01 02:30 | tool | read-file |
0mArgs:{
"File": "kernel/bpf/crypto.c",
"FirstLine": 1,
"LineCount": 100
}Results: {
"Contents": " 1:\t// SPDX-License-Identifier: GPL-2.0-only\n 2:\t/* Copyright (c) 2024 Meta, Inc */\n 3:\t#include \u003clinux/bpf.h\u003e\n 4:\t#include \u003clinux/bpf_mem_alloc.h\u003e\n 5:\t#include \u003clinux/btf.h\u003e\n 6:\t#include \u003clinux/btf_ids.h\u003e\n 7:\t#include \u003clinux/filter.h\u003e\n 8:\t#include \u003clinux/skbuff.h\u003e\n 9:\t#include \u003ccrypto/aes-cbc.h\u003e\n 10:\t#include \u003ccrypto/aes-ecb.h\u003e\n 11:\t\n 12:\t/* BPF crypto initialization parameters struct */\n 13:\t/**\n 14:\t * struct bpf_crypto_params - BPF crypto initialization parameters structure\n 15:\t * @type:\tThe string of crypto operation type.\n 16:\t * @reserved:\tReserved member, will be reused for more options in future\n 17:\t *\t\tValues:\n 18:\t *\t\t 0\n 19:\t * @algo:\tThe string of algorithm to initialize.\n 20:\t * @key:\tThe cipher key used to init crypto algorithm.\n 21:\t * @key_len:\tThe length of cipher key.\n 22:\t * @authsize:\tThe length of authentication tag used by algorithm.\n 23:\t */\n 24:\tstruct bpf_crypto_params {\n 25:\t\tchar type[14];\n 26:\t\tu8 reserved[2];\n 27:\t\tchar algo[128];\n 28:\t\tu8 key[256];\n 29:\t\tu32 key_len;\n 30:\t\tu32 authsize;\n 31:\t};\n 32:\t\n 33:\tenum bpf_crypto_algo_id {\n 34:\t\tBPF_ALGO_AES_CBC,\n 35:\t\tBPF_ALGO_AES_ECB,\n 36:\t};\n 37:\t\n 38:\tstatic const struct {\n 39:\t\tconst char *type_name;\n 40:\t\tconst char *algo_name;\n 41:\t\tenum bpf_crypto_algo_id algo;\n 42:\t} bpf_crypto_algos[] = {\n 43:\t\t{ \"skcipher\", \"cbc(aes)\", BPF_ALGO_AES_CBC },\n 44:\t\t{ \"skcipher\", \"ecb(aes)\", BPF_ALGO_AES_ECB },\n 45:\t};\n 46:\t\n 47:\tstatic bool bpf_crypto_find_algo(const struct bpf_crypto_params *params,\n 48:\t\t\t\t\t enum bpf_crypto_algo_id *id_ret)\n 49:\t{\n 50:\t\tfor (size_t i = 0; i \u003c ARRAY_SIZE(bpf_crypto_algos); i++) {\n 51:\t\t\tif (strncmp(bpf_crypto_algos[i].type_name, params-\u003etype,\n 52:\t\t\t\t sizeof(params-\u003etype)) == 0 \u0026\u0026\n 53:\t\t\t strncmp(bpf_crypto_algos[i].algo_name, params-\u003ealgo,\n 54:\t\t\t\t sizeof(params-\u003ealgo)) == 0) {\n 55:\t\t\t\t*id_ret = bpf_crypto_algos[i].algo;\n 56:\t\t\t\treturn true;\n 57:\t\t\t}\n 58:\t\t}\n 59:\t\treturn false;\n 60:\t}\n 61:\t\n 62:\t/**\n 63:\t * struct bpf_crypto_ctx - refcounted BPF crypto context structure\n 64:\t * @algo:\tThe crypto algorithm ID\n 65:\t * @key:\tThe crypto key\n 66:\t * @rcu:\tThe RCU head used to free the crypto context with RCU safety.\n 67:\t * @usage:\tObject reference counter. When the refcount goes to 0, the\n 68:\t *\t\tmemory is released back to the BPF allocator, which provides\n 69:\t *\t\tRCU safety.\n 70:\t */\n 71:\tstruct bpf_crypto_ctx {\n 72:\t\tenum bpf_crypto_algo_id algo;\n 73:\t\tunion {\n 74:\t\t\tstruct aes_key aes;\n 75:\t\t} key;\n 76:\t\tstruct rcu_head rcu;\n 77:\t\trefcount_t usage;\n 78:\t};\n 79:\t\n 80:\t__bpf_kfunc_start_defs();\n 81:\t\n 82:\t/**\n 83:\t * bpf_crypto_ctx_create() - Create a mutable BPF crypto context.\n 84:\t *\n 85:\t * Allocates a crypto context that can be used, acquired, and released by\n 86:\t * a BPF program. The crypto context returned by this function must either\n 87:\t * be embedded in a map as a kptr, or freed with bpf_crypto_ctx_release().\n 88:\t * As crypto API functions use GFP_KERNEL allocations, this function can\n 89:\t * only be used in sleepable BPF programs.\n 90:\t *\n 91:\t * bpf_crypto_ctx_create() allocates memory for crypto context.\n 92:\t * It may return NULL if no memory is available.\n 93:\t * @params:\tpointer to struct bpf_crypto_params which contains all the\n 94:\t *\t\tdetails needed to initialise crypto context.\n 95:\t * @params__sz:\tsize of steuct bpf_crypto_params usef by bpf program\n 96:\t * @err:\tinteger to store error code when NULL is returned.\n 97:\t */\n 98:\t__bpf_kfunc struct bpf_crypto_ctx *\n 99:\tbpf_crypto_ctx_create(const struct bpf_crypto_params *params, u32 params__sz,\n 100:\t\t\t int *err)\n"
} |
| 19/3 | 2026/09/01 02:30 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 16986 output: 37 thoughts: 17 Thoughts: Okay, let's dive into `kernel/bpf/crypto.c`. I've got a feeling there's going to be some interesting stuff in here, considering it's dealing with cryptography within the BPF framework. I need to understand how cryptographic primitives are being exposed to the eBPF programs, and what level of control the BPF code has over these operations. Are they providing the bare metal instructions, or more high-level abstractions? I'm particularly interested in looking for any potential performance bottlenecks or security implications. This is kernel space, so any vulnerability here could be devastating. I want to see if they're using hardened implementations, and if there's any obvious attack surface that needs further scrutiny. Then, there's the question of integration with other kernel cryptographic modules. Are they leveraging existing crypto API calls, or building something entirely new for the BPF environment? The design choices here will speak volumes about the goals of the developers and the trade-offs they made. I'll need to pay close attention to the data structures involved, the function calls, and error handling. I hope to find that the code is well-commented and thoroughly reviewed. Now, let's see what we're dealing with. |
| 20/3 | 2026/09/01 02:30 | tool | read-file |
0mArgs:{
"File": "kernel/bpf/crypto.c",
"FirstLine": 101,
"LineCount": 100
}Results: {
"Contents": " 101:\t{\n 102:\t\tstruct bpf_crypto_ctx *ctx;\n 103:\t\n 104:\t\tif (!params || params-\u003ereserved[0] || params-\u003ereserved[1] ||\n 105:\t\t params__sz != sizeof(struct bpf_crypto_params)) {\n 106:\t\t\t*err = -EINVAL;\n 107:\t\t\treturn NULL;\n 108:\t\t}\n 109:\t\n 110:\t\tctx = kzalloc_obj(*ctx);\n 111:\t\tif (!ctx) {\n 112:\t\t\t*err = -ENOMEM;\n 113:\t\t\treturn NULL;\n 114:\t\t}\n 115:\t\n 116:\t\tif (!bpf_crypto_find_algo(params, \u0026ctx-\u003ealgo)) {\n 117:\t\t\t*err = -ENOENT;\n 118:\t\t\tgoto out;\n 119:\t\t}\n 120:\t\n 121:\t\tswitch (ctx-\u003ealgo) {\n 122:\t\tcase BPF_ALGO_AES_CBC:\n 123:\t\tcase BPF_ALGO_AES_ECB:\n 124:\t\t\tif (params-\u003eauthsize)\n 125:\t\t\t\t*err = -EOPNOTSUPP;\n 126:\t\t\telse\n 127:\t\t\t\t*err = aes_preparekey(\u0026ctx-\u003ekey.aes, params-\u003ekey,\n 128:\t\t\t\t\t\t params-\u003ekey_len);\n 129:\t\t\tbreak;\n 130:\t\tdefault:\n 131:\t\t\tWARN_ON(1);\n 132:\t\t\t*err = -ENOENT;\n 133:\t\t\tbreak;\n 134:\t\t}\n 135:\t\n 136:\tout:\n 137:\t\tif (*err) {\n 138:\t\t\tkfree_sensitive(ctx);\n 139:\t\t\treturn NULL;\n 140:\t\t}\n 141:\t\n 142:\t\trefcount_set(\u0026ctx-\u003eusage, 1);\n 143:\t\treturn ctx;\n 144:\t}\n 145:\t\n 146:\tstatic void crypto_free_cb(struct rcu_head *head)\n 147:\t{\n 148:\t\tstruct bpf_crypto_ctx *ctx;\n 149:\t\n 150:\t\tctx = container_of(head, struct bpf_crypto_ctx, rcu);\n 151:\t\tkfree_sensitive(ctx);\n 152:\t}\n 153:\t\n 154:\t/**\n 155:\t * bpf_crypto_ctx_acquire() - Acquire a reference to a BPF crypto context.\n 156:\t * @ctx: The BPF crypto context being acquired. The ctx must be a trusted\n 157:\t *\t pointer.\n 158:\t *\n 159:\t * Acquires a reference to a BPF crypto context. The context returned by this function\n 160:\t * must either be embedded in a map as a kptr, or freed with\n 161:\t * bpf_crypto_ctx_release().\n 162:\t */\n 163:\t__bpf_kfunc struct bpf_crypto_ctx *\n 164:\tbpf_crypto_ctx_acquire(struct bpf_crypto_ctx *ctx)\n 165:\t{\n 166:\t\tif (!refcount_inc_not_zero(\u0026ctx-\u003eusage))\n 167:\t\t\treturn NULL;\n 168:\t\treturn ctx;\n 169:\t}\n 170:\t\n 171:\t/**\n 172:\t * bpf_crypto_ctx_release() - Release a previously acquired BPF crypto context.\n 173:\t * @ctx: The crypto context being released.\n 174:\t *\n 175:\t * Releases a previously acquired reference to a BPF crypto context. When the final\n 176:\t * reference of the BPF crypto context has been released, its memory\n 177:\t * will be released.\n 178:\t */\n 179:\t__bpf_kfunc void bpf_crypto_ctx_release(struct bpf_crypto_ctx *ctx)\n 180:\t{\n 181:\t\tif (refcount_dec_and_test(\u0026ctx-\u003eusage))\n 182:\t\t\tcall_rcu(\u0026ctx-\u003ercu, crypto_free_cb);\n 183:\t}\n 184:\t\n 185:\t__bpf_kfunc void bpf_crypto_ctx_release_dtor(void *ctx)\n 186:\t{\n 187:\t\tbpf_crypto_ctx_release(ctx);\n 188:\t}\n 189:\tCFI_NOSEAL(bpf_crypto_ctx_release_dtor);\n 190:\t\n 191:\tstatic int bpf_aes_cbc_crypt(u8 *dst, u32 dst_len, const u8 *src, u32 src_len,\n 192:\t\t\t\t u8 *iv, u32 iv_len,\n 193:\t\t\t\t const struct bpf_crypto_ctx *ctx, bool decrypt)\n 194:\t{\n 195:\t\tif (iv_len != AES_BLOCK_SIZE)\n 196:\t\t\treturn -EINVAL;\n 197:\t\tif (src_len % AES_BLOCK_SIZE || dst_len \u003c src_len)\n 198:\t\t\treturn -EINVAL;\n 199:\t\tif (decrypt)\n 200:\t\t\taes_cbc_decrypt(dst, src, src_len, iv, \u0026ctx-\u003ekey.aes);\n"
} |
| 21/3 | 2026/09/01 02:30 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 18767 output: 37 thoughts: 27 Thoughts: Here's my take on the kernel code, thinking out loud as an expert: **Diving into `crypto.c` (Lines 201-310)** Alright, time to dig into those lines in `kernel/bpf/crypto.c`. Let's see what we're working with here, based on my understanding of this module and eBPF in general. I'm expecting this section to be handling the core cryptography primitives exposed via eBPF, likely involving the `bpf_crypto_*` helper functions. Given the context, I bet we're looking at things like hash calculations, encryption, perhaps even authentication mechanisms like HMAC. I'll be focused on how these functions interact with the BPF VM, any potential security considerations, and of course, performance implications. I'll be keeping an eye out for how this section handles memory allocation and potential data corruption issues, because those are often tricky in the kernel space, especially when dealing with data being passed in from user-space via eBPF programs. I want to check how the arguments are checked for validity (like length). I'll also try to infer how the code is optimized, and whether the optimization techniques are appropriate for a kernel setting. Let's see if there are any specific cryptographic algorithms that are being favored here, or if the code is more generic in its approach. My gut feeling is that this would be optimized for common usages. I also wonder if these functions support different hardware acceleration features, and if so, how that’s handled within the eBPF framework. This looks like the fun part! Let's get reading. |
| 22/3 | 2026/09/01 02:30 | tool | read-file |
0mArgs:{
"File": "kernel/bpf/crypto.c",
"FirstLine": 201,
"LineCount": 100
}Results: {
"Contents": " 201:\t\telse\n 202:\t\t\taes_cbc_encrypt(dst, src, src_len, iv, \u0026ctx-\u003ekey.aes);\n 203:\t\treturn 0;\n 204:\t}\n 205:\t\n 206:\tstatic int bpf_aes_ecb_crypt(u8 *dst, u32 dst_len, const u8 *src, u32 src_len,\n 207:\t\t\t\t u8 *iv, u32 iv_len,\n 208:\t\t\t\t const struct bpf_crypto_ctx *ctx, bool decrypt)\n 209:\t{\n 210:\t\tif (iv_len != 0)\n 211:\t\t\treturn -EINVAL;\n 212:\t\tif (src_len % AES_BLOCK_SIZE || dst_len \u003c src_len)\n 213:\t\t\treturn -EINVAL;\n 214:\t\tif (decrypt)\n 215:\t\t\taes_ecb_decrypt(dst, src, src_len, \u0026ctx-\u003ekey.aes);\n 216:\t\telse\n 217:\t\t\taes_ecb_encrypt(dst, src, src_len, \u0026ctx-\u003ekey.aes);\n 218:\t\treturn 0;\n 219:\t}\n 220:\t\n 221:\tstatic int bpf_crypto_crypt(const struct bpf_crypto_ctx *ctx,\n 222:\t\t\t\t const struct bpf_dynptr_kern *src,\n 223:\t\t\t\t const struct bpf_dynptr_kern *dst,\n 224:\t\t\t\t const struct bpf_dynptr_kern *iv,\n 225:\t\t\t\t bool decrypt)\n 226:\t{\n 227:\t\tu32 src_len, dst_len, iv_len;\n 228:\t\tconst u8 *psrc;\n 229:\t\tu8 *pdst, *piv;\n 230:\t\n 231:\t\tif (__bpf_dynptr_is_rdonly(dst))\n 232:\t\t\treturn -EINVAL;\n 233:\t\n 234:\t\tiv_len = iv ? __bpf_dynptr_size(iv) : 0;\n 235:\t\tsrc_len = __bpf_dynptr_size(src);\n 236:\t\tdst_len = __bpf_dynptr_size(dst);\n 237:\t\tif (!src_len || !dst_len)\n 238:\t\t\treturn -EINVAL;\n 239:\t\n 240:\t\tpsrc = __bpf_dynptr_data(src, src_len);\n 241:\t\tif (!psrc)\n 242:\t\t\treturn -EINVAL;\n 243:\t\tpdst = __bpf_dynptr_data_rw(dst, dst_len);\n 244:\t\tif (!pdst)\n 245:\t\t\treturn -EINVAL;\n 246:\t\n 247:\t\tpiv = iv_len ? __bpf_dynptr_data_rw(iv, iv_len) : NULL;\n 248:\t\tif (iv_len \u0026\u0026 !piv)\n 249:\t\t\treturn -EINVAL;\n 250:\t\n 251:\t\tswitch (ctx-\u003ealgo) {\n 252:\t\tcase BPF_ALGO_AES_CBC:\n 253:\t\t\treturn bpf_aes_cbc_crypt(pdst, dst_len, psrc, src_len, piv,\n 254:\t\t\t\t\t\t iv_len, ctx, decrypt);\n 255:\t\tcase BPF_ALGO_AES_ECB:\n 256:\t\t\treturn bpf_aes_ecb_crypt(pdst, dst_len, psrc, src_len, piv,\n 257:\t\t\t\t\t\t iv_len, ctx, decrypt);\n 258:\t\tdefault:\n 259:\t\t\treturn -EINVAL;\n 260:\t\t}\n 261:\t}\n 262:\t\n 263:\t/**\n 264:\t * bpf_crypto_decrypt() - Decrypt buffer using configured context and IV provided.\n 265:\t * @ctx:\t\tThe crypto context being used. The ctx must be a trusted pointer.\n 266:\t * @src:\t\tbpf_dynptr to the encrypted data. Must be a trusted pointer.\n 267:\t * @dst:\t\tbpf_dynptr to the buffer where to store the result. Must be a trusted pointer.\n 268:\t * @iv__nullable:\tbpf_dynptr to the initialization vector. May be NULL.\n 269:\t *\n 270:\t * Decrypts provided buffer using IV data and the crypto context. Crypto context must be configured.\n 271:\t */\n 272:\t__bpf_kfunc int bpf_crypto_decrypt(struct bpf_crypto_ctx *ctx,\n 273:\t\t\t\t\t const struct bpf_dynptr *src,\n 274:\t\t\t\t\t const struct bpf_dynptr *dst,\n 275:\t\t\t\t\t const struct bpf_dynptr *iv__nullable)\n 276:\t{\n 277:\t\tconst struct bpf_dynptr_kern *src_kern = (struct bpf_dynptr_kern *)src;\n 278:\t\tconst struct bpf_dynptr_kern *dst_kern = (struct bpf_dynptr_kern *)dst;\n 279:\t\tconst struct bpf_dynptr_kern *iv_kern = (struct bpf_dynptr_kern *)iv__nullable;\n 280:\t\n 281:\t\treturn bpf_crypto_crypt(ctx, src_kern, dst_kern, iv_kern, true);\n 282:\t}\n 283:\t\n 284:\t/**\n 285:\t * bpf_crypto_encrypt() - Encrypt buffer using configured context and IV provided.\n 286:\t * @ctx:\t\tThe crypto context being used. The ctx must be a trusted pointer.\n 287:\t * @src:\t\tbpf_dynptr to the plain data. Must be a trusted pointer.\n 288:\t * @dst:\t\tbpf_dynptr to the buffer where to store the result. Must be a trusted pointer.\n 289:\t * @iv__nullable:\tbpf_dynptr to the initialization vector. May be NULL.\n 290:\t *\n 291:\t * Encrypts provided buffer using IV data and the crypto context. Crypto context must be configured.\n 292:\t */\n 293:\t__bpf_kfunc int bpf_crypto_encrypt(struct bpf_crypto_ctx *ctx,\n 294:\t\t\t\t\t const struct bpf_dynptr *src,\n 295:\t\t\t\t\t const struct bpf_dynptr *dst,\n 296:\t\t\t\t\t const struct bpf_dynptr *iv__nullable)\n 297:\t{\n 298:\t\tconst struct bpf_dynptr_kern *src_kern = (struct bpf_dynptr_kern *)src;\n 299:\t\tconst struct bpf_dynptr_kern *dst_kern = (struct bpf_dynptr_kern *)dst;\n 300:\t\tconst struct bpf_dynptr_kern *iv_kern = (struct bpf_dynptr_kern *)iv__nullable;\n"
} |
| 23/3 | 2026/09/01 02:30 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 21026 output: 18 thoughts: 608 Thoughts: **My Memory Safety Analysis of the BPF Crypto Context** Okay, let's break this down from a memory safety perspective. I'm focusing on potential vulnerabilities here. First, I'm starting with `bpf_crypto_ctx_create`. This looks pretty solid. `kzalloc_obj` is a good choice for initialization, ensuring the `ctx` struct is zeroed. The `bpf_crypto_find_algo` and `aes_preparekey` calls seem standard, handling algorithm and key setup, and the key length checks in `aes_preparekey` (16, 24, or 32 bytes) are important. The `kfree_sensitive(ctx)` on error and the refcount of 1 setup a straightforward lifetime management. Next, I'm examining `bpf_aes_cbc_crypt`. The length checks for the IV (`iv_len == AES_BLOCK_SIZE`) and source/destination buffers (`src_len` multiple of `AES_BLOCK_SIZE` and `dst_len >= src_len`) are crucial for preventing buffer overflows and underflows. The use of dynptr helpers further strengthens this. Same for `bpf_aes_ecb_crypt` with the IV check (`iv_len == 0`) and the source/destination length checks. Then I'm digging into potential information leaks and uninitialized memory issues. I don't see any obvious ways uninitialized kernel memory can leak to userspace. BPF dynptrs are pointing to caller-provided buffers, which is good. The `ctx` is zeroed by `kzalloc_obj`. The `aes_preparekey` call initializes the key schedule, `algo` is initialized by `bpf_crypto_find_algo`. No conditional branches on uninitialized values. The freeing is handled correctly with `kfree_sensitive`. Now, I'm thinking, are there any subtle edge cases? Is there a chance `aes_preparekey` could leave something uninitialized in the `struct aes_key`? It's time to check the definition of `struct aes_key` and the implementation of `aes_preparekey` to make sure. That's the next logical step. |
| 24/3 | 2026/09/01 02:30 | tool | grepper |
0mArgs:{
"Expression": "struct aes_key"
}Results: {
"Output": "arch/arm/crypto/aes-neonbs-glue.c=53=struct aesbs_xts_ctx {\narch/arm/crypto/aes-neonbs-glue.c-54-\tstruct aesbs_ctx\tkey;\narch/arm/crypto/aes-neonbs-glue.c:55:\tstruct aes_key\t\tfallback;\narch/arm/crypto/aes-neonbs-glue.c-56-\tstruct aes_enckey\ttweak_key;\n--\ncrypto/aes.c-22-\ncrypto/aes.c:23:static_assert(__alignof__(struct aes_key) \u003c= CRYPTO_MINALIGN);\ncrypto/aes.c-24-static_assert(__alignof__(struct aes_enckey) \u003c= CRYPTO_MINALIGN);\n--\ncrypto/aes.c=26=static int crypto_aes_setkey(struct crypto_tfm *tfm, const u8 *in_key,\n--\ncrypto/aes.c-28-{\ncrypto/aes.c:29:\tstruct aes_key *key = crypto_tfm_ctx(tfm);\ncrypto/aes.c-30-\n--\ncrypto/aes.c=34=static void crypto_aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)\ncrypto/aes.c-35-{\ncrypto/aes.c:36:\tconst struct aes_key *key = crypto_tfm_ctx(tfm);\ncrypto/aes.c-37-\n--\ncrypto/aes.c=41=static void crypto_aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)\ncrypto/aes.c-42-{\ncrypto/aes.c:43:\tconst struct aes_key *key = crypto_tfm_ctx(tfm);\ncrypto/aes.c-44-\n--\ncrypto/aes.c=139=static struct crypto_alg alg = {\n--\ncrypto/aes.c-144-\t.cra_blocksize = AES_BLOCK_SIZE,\ncrypto/aes.c:145:\t.cra_ctxsize = sizeof(struct aes_key),\ncrypto/aes.c-146-\t.cra_module = THIS_MODULE,\n--\ncrypto/aes.c=213=crypto_aes_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *in_key,\n--\ncrypto/aes.c-215-{\ncrypto/aes.c:216:\tstruct aes_key *key = crypto_skcipher_ctx(tfm);\ncrypto/aes.c-217-\n--\ncrypto/aes.c=348=static __maybe_unused int crypto_aes_ecb_encrypt(struct skcipher_request *req)\ncrypto/aes.c-349-{\ncrypto/aes.c:350:\tconst struct aes_key *key =\ncrypto/aes.c-351-\t\tcrypto_skcipher_ctx(crypto_skcipher_reqtfm(req));\n--\ncrypto/aes.c=360=static __maybe_unused int crypto_aes_ecb_decrypt(struct skcipher_request *req)\ncrypto/aes.c-361-{\ncrypto/aes.c:362:\tconst struct aes_key *key =\ncrypto/aes.c-363-\t\tcrypto_skcipher_ctx(crypto_skcipher_reqtfm(req));\n--\ncrypto/aes.c=374=static void crypto_aes_cbc_encrypt_sg(struct skcipher_request *req,\ncrypto/aes.c-375-\t\t\t\t unsigned int cryptlen,\ncrypto/aes.c:376:\t\t\t\t const struct aes_key *key)\ncrypto/aes.c-377-{\n--\ncrypto/aes.c=382=static void crypto_aes_cbc_decrypt_sg(struct skcipher_request *req,\ncrypto/aes.c-383-\t\t\t\t unsigned int cryptlen,\ncrypto/aes.c:384:\t\t\t\t const struct aes_key *key)\ncrypto/aes.c-385-{\n--\ncrypto/aes.c=390=static __maybe_unused int crypto_aes_cbc_encrypt(struct skcipher_request *req)\ncrypto/aes.c-391-{\ncrypto/aes.c:392:\tconst struct aes_key *key =\ncrypto/aes.c-393-\t\tcrypto_skcipher_ctx(crypto_skcipher_reqtfm(req));\n--\ncrypto/aes.c=401=static __maybe_unused int crypto_aes_cbc_decrypt(struct skcipher_request *req)\ncrypto/aes.c-402-{\ncrypto/aes.c:403:\tconst struct aes_key *key =\ncrypto/aes.c-404-\t\tcrypto_skcipher_ctx(crypto_skcipher_reqtfm(req));\n--\ncrypto/aes.c=420=crypto_aes_cbc_cts_crypt_nonlinear(struct skcipher_request *req, bool enc)\ncrypto/aes.c-421-{\ncrypto/aes.c:422:\tconst struct aes_key *key =\ncrypto/aes.c-423-\t\tcrypto_skcipher_ctx(crypto_skcipher_reqtfm(req));\n--\ncrypto/aes.c=454=crypto_aes_cbc_cts_encrypt(struct skcipher_request *req)\ncrypto/aes.c-455-{\ncrypto/aes.c:456:\tconst struct aes_key *key =\ncrypto/aes.c-457-\t\tcrypto_skcipher_ctx(crypto_skcipher_reqtfm(req));\n--\ncrypto/aes.c=471=crypto_aes_cbc_cts_decrypt(struct skcipher_request *req)\ncrypto/aes.c-472-{\ncrypto/aes.c:473:\tconst struct aes_key *key =\ncrypto/aes.c-474-\t\tcrypto_skcipher_ctx(crypto_skcipher_reqtfm(req));\n--\ncrypto/aes.c=608=static struct skcipher_alg skcipher_algs[] = {\n--\ncrypto/aes.c-614-\t\t.base.cra_blocksize = AES_BLOCK_SIZE,\ncrypto/aes.c:615:\t\t.base.cra_ctxsize = sizeof(struct aes_key),\ncrypto/aes.c-616-\t\t.base.cra_module = THIS_MODULE,\n--\ncrypto/aes.c-629-\t\t.base.cra_blocksize = AES_BLOCK_SIZE,\ncrypto/aes.c:630:\t\t.base.cra_ctxsize = sizeof(struct aes_key),\ncrypto/aes.c-631-\t\t.base.cra_module = THIS_MODULE,\n--\ncrypto/aes.c-645-\t\t.base.cra_blocksize = AES_BLOCK_SIZE,\ncrypto/aes.c:646:\t\t.base.cra_ctxsize = sizeof(struct aes_key),\ncrypto/aes.c-647-\t\t.base.cra_module = THIS_MODULE,\n--\ndrivers/crypto/chelsio/chcr_algo.c=1025=static int chcr_update_tweak(struct skcipher_request *req, u8 *iv,\n--\ndrivers/crypto/chelsio/chcr_algo.c-1030-\tstruct chcr_skcipher_req_ctx *reqctx = skcipher_request_ctx(req);\ndrivers/crypto/chelsio/chcr_algo.c:1031:\tstruct aes_key aes;\ndrivers/crypto/chelsio/chcr_algo.c-1032-\tint ret, i;\n--\ninclude/crypto/aes-cbc.h=45=void aes_cbc_decrypt(u8 *dst, const u8 *src, size_t len,\ninclude/crypto/aes-cbc.h:46:\t\t u8 iv[at_least AES_BLOCK_SIZE], const struct aes_key *key);\ninclude/crypto/aes-cbc.h-47-\n--\ninclude/crypto/aes-cbc.h=73=void aes_cbc_cts_decrypt(u8 *dst, const u8 *src, size_t len,\ninclude/crypto/aes-cbc.h-74-\t\t\t u8 iv[at_least AES_BLOCK_SIZE],\ninclude/crypto/aes-cbc.h:75:\t\t\t const struct aes_key *key);\ninclude/crypto/aes-cbc.h-76-\n--\ninclude/crypto/aes-ecb.h=46=void aes_ecb_decrypt(u8 *dst, const u8 *src, size_t len,\ninclude/crypto/aes-ecb.h:47:\t\t const struct aes_key *key);\ninclude/crypto/aes-ecb.h-48-\n--\ninclude/crypto/aes-xts.h=19=struct aes_xts_key {\ninclude/crypto/aes-xts.h-20-\t/* private: */\ninclude/crypto/aes-xts.h:21:\tstruct aes_key main_key;\ninclude/crypto/aes-xts.h-22-\tstruct aes_enckey tweak_key;\n--\ninclude/crypto/aes.h=59=union aes_invkey_arch {\n--\ninclude/crypto/aes.h-86- *\ninclude/crypto/aes.h:87: * Note that this struct is about half the size of struct aes_key. This is\ninclude/crypto/aes.h:88: * separate from struct aes_key so that modes that need only AES encryption\ninclude/crypto/aes.h-89- * (e.g. AES-GCM, AES-CTR, AES-CMAC, tweak key in AES-XTS) don't incur the time\n--\ninclude/crypto/aes.h=97=struct aes_enckey {\n--\ninclude/crypto/aes.h-104-/**\ninclude/crypto/aes.h:105: * struct aes_key - An AES key prepared for encryption and decryption\ninclude/crypto/aes.h-106- * @aes_enckey: Common fields and the key prepared for encryption\n--\ninclude/crypto/aes.h-112- */\ninclude/crypto/aes.h:113:struct aes_key {\ninclude/crypto/aes.h-114-\tstruct aes_enckey; /* Include all fields of aes_enckey. */\n--\ninclude/crypto/aes.h=308=void aes_sparc64_ctr_crypt_256(const u64 *key, const u64 *input, u64 *output,\n--\ninclude/crypto/aes.h-323- *\ninclude/crypto/aes.h:324: * The caller is responsible for zeroizing both the struct aes_key and the raw\ninclude/crypto/aes.h-325- * key once they are no longer needed.\n--\ninclude/crypto/aes.h-334- */\ninclude/crypto/aes.h:335:int aes_preparekey(struct aes_key *key, const u8 *in_key, size_t key_len);\ninclude/crypto/aes.h-336-\n--\ninclude/crypto/aes.h-345- * cipher. Typically this involves expanding the raw key into only the standard\ninclude/crypto/aes.h:346: * round keys, resulting in a struct about half the size of struct aes_key.\ninclude/crypto/aes.h-347- *\n--\ninclude/crypto/aes.h=363=typedef union {\ninclude/crypto/aes.h-364-\tconst struct aes_enckey *enc_key;\ninclude/crypto/aes.h:365:\tconst struct aes_key *full_key;\ninclude/crypto/aes.h-366-} aes_encrypt_arg __attribute__ ((__transparent_union__));\n--\ninclude/crypto/aes.h-370- * @key: The AES key, as a pointer to either an encryption-only key\ninclude/crypto/aes.h:371: *\t (struct aes_enckey) or a full, bidirectional key (struct aes_key).\ninclude/crypto/aes.h-372- * @out: Buffer to store the ciphertext block\n--\ninclude/crypto/aes.h=377=void aes_encrypt(aes_encrypt_arg key, u8 out[at_least AES_BLOCK_SIZE],\n--\ninclude/crypto/aes.h-387- */\ninclude/crypto/aes.h:388:void aes_decrypt(const struct aes_key *key, u8 out[at_least AES_BLOCK_SIZE],\ninclude/crypto/aes.h-389-\t\t const u8 in[at_least AES_BLOCK_SIZE]);\n--\nkernel/bpf/crypto.c=71=struct bpf_crypto_ctx {\n--\nkernel/bpf/crypto.c-73-\tunion {\nkernel/bpf/crypto.c:74:\t\tstruct aes_key aes;\nkernel/bpf/crypto.c-75-\t} key;\n--\nlib/crypto/aes.c=470=static void aes_encrypt_arch(const struct aes_enckey *key,\n--\nlib/crypto/aes.c-476-\nlib/crypto/aes.c:477:static void aes_decrypt_arch(const struct aes_key *key,\nlib/crypto/aes.c-478-\t\t\t u8 out[AES_BLOCK_SIZE],\n--\nlib/crypto/aes.c=485=static int __aes_preparekey(struct aes_enckey *enc_key,\n--\nlib/crypto/aes.c-497-\nlib/crypto/aes.c:498:int aes_preparekey(struct aes_key *key, const u8 *in_key, size_t key_len)\nlib/crypto/aes.c-499-{\n--\nlib/crypto/aes.c=516=EXPORT_SYMBOL(aes_encrypt);\nlib/crypto/aes.c-517-\nlib/crypto/aes.c:518:void aes_decrypt(const struct aes_key *key, u8 out[AES_BLOCK_SIZE],\nlib/crypto/aes.c-519-\t\t const u8 in[AES_BLOCK_SIZE])\n--\nlib/crypto/aes.c=526=static void __init aes_fips_test(void)\nlib/crypto/aes.c-527-{\nlib/crypto/aes.c:528:\tstruct aes_key key;\nlib/crypto/aes.c-529-\tu8 data[AES_BLOCK_SIZE];\n--\nlib/crypto/aes.c=773=static bool aes_ecb_decrypt_arch(u8 *dst, const u8 *src, size_t len,\nlib/crypto/aes.c:774:\t\t\t\t const struct aes_key *key)\nlib/crypto/aes.c-775-{\n--\nlib/crypto/aes.c=796=void aes_ecb_decrypt(u8 *dst, const u8 *src, size_t len,\nlib/crypto/aes.c:797:\t\t const struct aes_key *key)\nlib/crypto/aes.c-798-{\n--\nlib/crypto/aes.c=814=static void __init aes_ecb_fips_test(void)\nlib/crypto/aes.c-815-{\nlib/crypto/aes.c:816:\tstruct aes_key key;\nlib/crypto/aes.c-817-\tu8 data[sizeof(fips_test_data)];\n--\nlib/crypto/aes.c=853=static bool aes_cbc_decrypt_arch(u8 *dst, const u8 *src, size_t len,\nlib/crypto/aes.c-854-\t\t\t\t u8 iv[AES_BLOCK_SIZE],\nlib/crypto/aes.c:855:\t\t\t\t const struct aes_key *key)\nlib/crypto/aes.c-856-{\n--\nlib/crypto/aes.c=887=void aes_cbc_decrypt(u8 *dst, const u8 *src, size_t len, u8 iv[AES_BLOCK_SIZE],\nlib/crypto/aes.c:888:\t\t const struct aes_key *key)\nlib/crypto/aes.c-889-{\n--\nlib/crypto/aes.c=935=static bool aes_cbc_cts_decrypt_arch(u8 *dst, const u8 *src, size_t len,\nlib/crypto/aes.c-936-\t\t\t\t u8 iv[AES_BLOCK_SIZE],\nlib/crypto/aes.c:937:\t\t\t\t const struct aes_key *key)\nlib/crypto/aes.c-938-{\n--\nlib/crypto/aes.c=982=void aes_cbc_cts_decrypt(u8 *dst, const u8 *src, size_t len,\nlib/crypto/aes.c:983:\t\t\t u8 iv[AES_BLOCK_SIZE], const struct aes_key *key)\nlib/crypto/aes.c-984-{\n--\nlib/crypto/aes.c=1024=static void __init aes_cbc_fips_test(void)\nlib/crypto/aes.c-1025-{\nlib/crypto/aes.c:1026:\tstruct aes_key key;\nlib/crypto/aes.c-1027-\tu8 iv[AES_BLOCK_SIZE];\n--\nlib/crypto/aes.c=1047=static void __init aes_cbc_cts_fips_test(void)\nlib/crypto/aes.c-1048-{\nlib/crypto/aes.c:1049:\tstruct aes_key key;\nlib/crypto/aes.c-1050-\tu8 iv[AES_BLOCK_SIZE];\n--\nlib/crypto/arm/aes.h=24=static void aes_encrypt_arch(const struct aes_enckey *key,\n--\nlib/crypto/arm/aes.h-40-\nlib/crypto/arm/aes.h:41:static void aes_decrypt_arch(const struct aes_key *key,\nlib/crypto/arm/aes.h-42-\t\t\t u8 out[AES_BLOCK_SIZE],\n--\nlib/crypto/arm64/aes.h=161=static void aes_encrypt_arch(const struct aes_enckey *key,\n--\nlib/crypto/arm64/aes.h-172-\nlib/crypto/arm64/aes.h:173:static void aes_decrypt_arch(const struct aes_key *key,\nlib/crypto/arm64/aes.h-174-\t\t\t u8 out[AES_BLOCK_SIZE],\n--\nlib/crypto/powerpc/aes.h=61=static void aes_encrypt_arch(const struct aes_enckey *key,\n--\nlib/crypto/powerpc/aes.h-69-\nlib/crypto/powerpc/aes.h:70:static void aes_decrypt_arch(const struct aes_key *key,\nlib/crypto/powerpc/aes.h-71-\t\t\t u8 out[AES_BLOCK_SIZE],\n--\nlib/crypto/powerpc/aes.h=166=static void aes_encrypt_arch(const struct aes_enckey *key,\n--\nlib/crypto/powerpc/aes.h-195-\nlib/crypto/powerpc/aes.h:196:static void aes_decrypt_arch(const struct aes_key *key, u8 out[AES_BLOCK_SIZE],\nlib/crypto/powerpc/aes.h-197-\t\t\t const u8 in[AES_BLOCK_SIZE])\n--\nlib/crypto/riscv/aes.h=26=static void aes_encrypt_arch(const struct aes_enckey *key,\n--\nlib/crypto/riscv/aes.h-38-\nlib/crypto/riscv/aes.h:39:static void aes_decrypt_arch(const struct aes_key *key,\nlib/crypto/riscv/aes.h-40-\t\t\t u8 out[AES_BLOCK_SIZE],\n--\nlib/crypto/s390/aes.h=73=static void aes_encrypt_arch(const struct aes_enckey *key,\n--\nlib/crypto/s390/aes.h-81-\nlib/crypto/s390/aes.h:82:static void aes_decrypt_arch(const struct aes_key *key,\nlib/crypto/s390/aes.h-83-\t\t\t u8 out[AES_BLOCK_SIZE],\n--\nlib/crypto/sparc/aes.h=86=static void aes_encrypt_arch(const struct aes_enckey *key,\n--\nlib/crypto/sparc/aes.h-104-\nlib/crypto/sparc/aes.h:105:static void aes_sparc64_decrypt(const struct aes_key *key,\nlib/crypto/sparc/aes.h-106-\t\t\t\tconst u32 *input, u32 *output)\n--\nlib/crypto/sparc/aes.h-115-\nlib/crypto/sparc/aes.h:116:static void aes_decrypt_arch(const struct aes_key *key,\nlib/crypto/sparc/aes.h-117-\t\t\t u8 out[AES_BLOCK_SIZE],\n--\nlib/crypto/x86/aes.h=52=static void aes_encrypt_arch(const struct aes_enckey *key,\n--\nlib/crypto/x86/aes.h-64-\nlib/crypto/x86/aes.h:65:static void aes_decrypt_arch(const struct aes_key *key,\nlib/crypto/x86/aes.h-66-\t\t\t u8 out[AES_BLOCK_SIZE],\n"
} |
| 25/3 | 2026/09/01 02:30 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 27487 output: 294 thoughts: 544 Thoughts: **My Assessment of KMSAN Applicability** Okay, let's break this down. My initial instinct is to assess if KMSAN is *really* needed here. From what I can see, we're dealing with a refactoring of the BPF crypto subsystem, shifting from the `crypto_tfm` dynamic registration approach to direct AES library function calls. We're getting rid of `bpf_crypto_skcipher.c` and updating the `bpf_crypto_ctx` structure. That's the core change. Now, let's drill down into memory considerations, because that's what KMSAN is all about. The key part is that `struct bpf_crypto_ctx` is allocated with `kzalloc_obj`, which *guarantees* that everything is zeroed out from the get-go. No uninitialized memory hanging around. The key schedule within `ctx->key.aes` is then prepared with `aes_preparekey`. That solidifies the key material. Looking at data transfers, we've got dynptrs for the input/output buffers and the IV. Critically, we have checks in `bpf_aes_cbc_crypt` and `bpf_aes_ecb_crypt` for buffer bounds and alignment. Namely, `iv_len != AES_BLOCK_SIZE`, `src_len % AES_BLOCK_SIZE || dst_len < src_len`. Also, in `bpf_crypto_ctx_create`, the `params` are validated with checks for `params__sz != sizeof(struct bpf_crypto_params)` and `reserved` fields. I see that the code is taking data directly from caller dynptrs and writing encrypted/decrypted data directly to the destination dynptrs. This is good: no uninitialized kernel memory being copied to userspace and no information leaks. Essentially, there are no instances here of reading uninitialized memory, branching on uninitialized variables, or leaking uninitialized padding or struct fields to userspace. Finally, while we can always run into memory issues with BPF (e.g. out-of-bounds access or buffer overruns), any issues with dynptrs, memory boundaries and lifetimes would be caught by KASAN or the BPF verifier dynptr checks. We *don't* require KMSAN here. My conclusion: `NeedsKMSAN` should be `false`. Now, let's call `set-results`. |
| 26/3 | 2026/09/01 02:30 | tool | set-results |
0mArgs:{
"KMSANReasoning": "The patch simplifies the BPF crypto kfuncs implementation by replacing the generic crypto tfm registration architecture with direct invocations of AES library functions (CRYPTO_LIB_AES_CBC and CRYPTO_LIB_AES_ECB). \n\nMemory safety analysis:\n1. Memory Allocation \u0026 Initialization: The context `struct bpf_crypto_ctx` is allocated with `kzalloc_obj`, ensuring all fields (including `enum bpf_crypto_algo_id` and the `aes_key` union) are zero-initialized. Key setup is handled by `aes_preparekey()`. Cleanup is handled via `kfree_sensitive()`.\n2. Buffers \u0026 Info Leaks: Data encryption and decryption operate directly on dynptr buffers supplied by BPF programs after verifying block alignment and bounds (`AES_BLOCK_SIZE` checks, `dst_len \u003e= src_len`). No uninitialized kernel memory or struct padding is copied to user space or used in branching/control flow.\n3. Sanitizer Applicability: Any potential out-of-bounds dynptr accesses, buffer length calculation bugs, or lifetime/refcounting issues are covered by KASAN and standard BPF verifier/debug infrastructure. There are no uninitialized memory read risks or information leaks requiring a dedicated KMSAN session.",
"NeedsKMSAN": false
}Results: {
"KMSANReasoning": "The patch simplifies the BPF crypto kfuncs implementation by replacing the generic crypto tfm registration architecture with direct invocations of AES library functions (CRYPTO_LIB_AES_CBC and CRYPTO_LIB_AES_ECB). \n\nMemory safety analysis:\n1. Memory Allocation \u0026 Initialization: The context `struct bpf_crypto_ctx` is allocated with `kzalloc_obj`, ensuring all fields (including `enum bpf_crypto_algo_id` and the `aes_key` union) are zero-initialized. Key setup is handled by `aes_preparekey()`. Cleanup is handled via `kfree_sensitive()`.\n2. Buffers \u0026 Info Leaks: Data encryption and decryption operate directly on dynptr buffers supplied by BPF programs after verifying block alignment and bounds (`AES_BLOCK_SIZE` checks, `dst_len \u003e= src_len`). No uninitialized kernel memory or struct padding is copied to user space or used in branching/control flow.\n3. Sanitizer Applicability: Any potential out-of-bounds dynptr accesses, buffer length calculation bugs, or lifetime/refcounting issues are covered by KASAN and standard BPF verifier/debug infrastructure. There are no uninitialized memory read risks or information leaks requiring a dedicated KMSAN session.",
"NeedsKMSAN": false
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|