Add bpf_crypto_shash module that registers a hash type with the BPF
crypto infrastructure, enabling BPF programs to access kernel hash
algorithms through a unified interface.
Update the bpf_crypto_type interface with hash-specific callbacks:
- alloc_tfm: Allocates crypto_shash context with proper descriptor size
- free_tfm: Releases hash transform and context memory
- has_algo: Checks algorithm availability via crypto_has_shash()
- hash: Performs single-shot hashing via crypto_shash_digest()
- digestsize: Returns the output size for the hash algorithm
- get_flags: Exposes transform flags to BPF programs
Update bpf_shash_ctx to contain crypto_shash transform and shash_desc
descriptor to accommodate algorithm-specific descriptor requirements.
Signed-off-by: Daniel Hodges <git@danielhodges.dev>
---
MAINTAINERS | 1 +
crypto/Makefile | 3 ++
crypto/bpf_crypto_shash.c | 96 ++++++++++++++++++++++++++++++++++++++
include/linux/bpf_crypto.h | 7 +++
4 files changed, 107 insertions(+)
create mode 100644 crypto/bpf_crypto_shash.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 491d567f7dc8..4e9b369acd1c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4713,6 +4713,7 @@ BPF [CRYPTO]
M: Vadim Fedorenko <vadim.fedorenko@linux.dev>
L: bpf@vger.kernel.org
S: Maintained
+F: crypto/bpf_crypto_shash.c
F: crypto/bpf_crypto_skcipher.c
F: include/linux/bpf_crypto.h
F: kernel/bpf/crypto.c
diff --git a/crypto/Makefile b/crypto/Makefile
index 16a35649dd91..853dff375906 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -30,6 +30,9 @@ obj-$(CONFIG_CRYPTO_ECHAINIV) += echainiv.o
crypto_hash-y += ahash.o
crypto_hash-y += shash.o
obj-$(CONFIG_CRYPTO_HASH2) += crypto_hash.o
+ifeq ($(CONFIG_BPF_SYSCALL),y)
+obj-$(CONFIG_CRYPTO_HASH2) += bpf_crypto_shash.o
+endif
obj-$(CONFIG_CRYPTO_AKCIPHER2) += akcipher.o
obj-$(CONFIG_CRYPTO_SIG2) += sig.o
diff --git a/crypto/bpf_crypto_shash.c b/crypto/bpf_crypto_shash.c
new file mode 100644
index 000000000000..6e9b0d757ec9
--- /dev/null
+++ b/crypto/bpf_crypto_shash.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/bpf_crypto.h>
+#include <crypto/hash.h>
+
+struct bpf_shash_ctx {
+ struct crypto_shash *tfm;
+ struct shash_desc desc;
+};
+
+static void *bpf_crypto_shash_alloc_tfm(const char *algo)
+{
+ struct bpf_shash_ctx *ctx;
+ struct crypto_shash *tfm;
+
+ tfm = crypto_alloc_shash(algo, 0, 0);
+ if (IS_ERR(tfm))
+ return tfm;
+
+ ctx = kzalloc(sizeof(*ctx) + crypto_shash_descsize(tfm), GFP_KERNEL);
+ if (!ctx) {
+ crypto_free_shash(tfm);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ ctx->tfm = tfm;
+ ctx->desc.tfm = tfm;
+
+ return ctx;
+}
+
+static void bpf_crypto_shash_free_tfm(void *tfm)
+{
+ struct bpf_shash_ctx *ctx = tfm;
+
+ crypto_free_shash(ctx->tfm);
+ kfree(ctx);
+}
+
+static int bpf_crypto_shash_has_algo(const char *algo)
+{
+ return crypto_has_shash(algo, 0, 0);
+}
+
+static int bpf_crypto_shash_hash(void *tfm, const u8 *data, u8 *out,
+ unsigned int len)
+{
+ struct bpf_shash_ctx *ctx = tfm;
+
+ return crypto_shash_digest(&ctx->desc, data, len, out);
+}
+
+static unsigned int bpf_crypto_shash_digestsize(void *tfm)
+{
+ struct bpf_shash_ctx *ctx = tfm;
+
+ return crypto_shash_digestsize(ctx->tfm);
+}
+
+static u32 bpf_crypto_shash_get_flags(void *tfm)
+{
+ struct bpf_shash_ctx *ctx = tfm;
+
+ return crypto_shash_get_flags(ctx->tfm);
+}
+
+static const struct bpf_crypto_type bpf_crypto_shash_type = {
+ .alloc_tfm = bpf_crypto_shash_alloc_tfm,
+ .free_tfm = bpf_crypto_shash_free_tfm,
+ .has_algo = bpf_crypto_shash_has_algo,
+ .hash = bpf_crypto_shash_hash,
+ .digestsize = bpf_crypto_shash_digestsize,
+ .get_flags = bpf_crypto_shash_get_flags,
+ .owner = THIS_MODULE,
+ .type_id = BPF_CRYPTO_TYPE_HASH,
+ .name = "hash",
+};
+
+static int __init bpf_crypto_shash_init(void)
+{
+ return bpf_crypto_register_type(&bpf_crypto_shash_type);
+}
+
+static void __exit bpf_crypto_shash_exit(void)
+{
+ int err = bpf_crypto_unregister_type(&bpf_crypto_shash_type);
+
+ WARN_ON_ONCE(err);
+}
+
+module_init(bpf_crypto_shash_init);
+module_exit(bpf_crypto_shash_exit);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Hash algorithm support for BPF");
diff --git a/include/linux/bpf_crypto.h b/include/linux/bpf_crypto.h
index c84371cc4e47..cf2c66f9782b 100644
--- a/include/linux/bpf_crypto.h
+++ b/include/linux/bpf_crypto.h
@@ -3,6 +3,12 @@
#ifndef _BPF_CRYPTO_H
#define _BPF_CRYPTO_H
+enum bpf_crypto_type_id {
+ BPF_CRYPTO_TYPE_SKCIPHER = 1,
+ BPF_CRYPTO_TYPE_HASH,
+ BPF_CRYPTO_TYPE_SIG,
+};
+
struct bpf_crypto_type {
void *(*alloc_tfm)(const char *algo);
void (*free_tfm)(void *tfm);
@@ -17,6 +23,7 @@ struct bpf_crypto_type {
unsigned int (*digestsize)(void *tfm);
u32 (*get_flags)(void *tfm);
struct module *owner;
+ enum bpf_crypto_type_id type_id;
char name[14];
};
--
2.52.0
> diff --git a/crypto/bpf_crypto_shash.c b/crypto/bpf_crypto_shash.c
> new file mode 100644
> index 000000000000..6e9b0d757ec9
> --- /dev/null
> +++ b/crypto/bpf_crypto_shash.c
[ ... ]
> +static const struct bpf_crypto_type bpf_crypto_shash_type = {
> + .alloc_tfm = bpf_crypto_shash_alloc_tfm,
> + .free_tfm = bpf_crypto_shash_free_tfm,
> + .has_algo = bpf_crypto_shash_has_algo,
> + .hash = bpf_crypto_shash_hash,
> + .digestsize = bpf_crypto_shash_digestsize,
> + .get_flags = bpf_crypto_shash_get_flags,
> + .owner = THIS_MODULE,
> + .type_id = BPF_CRYPTO_TYPE_HASH,
> + .name = "hash",
> +};
Can this cause a NULL pointer dereference when a BPF program calls
bpf_crypto_ctx_create() with type="hash"?
The bpf_crypto_ctx_create() function in kernel/bpf/crypto.c unconditionally
calls type->setkey(), type->ivsize(), and type->statesize():
*err = type->setkey(ctx->tfm, params->key, params->key_len);
...
ctx->siv_len = type->ivsize(ctx->tfm) + type->statesize(ctx->tfm);
But bpf_crypto_shash_type does not implement these callbacks, leaving them
as NULL.
Note: This appears to be fixed later in the series by commit 76d771a64b50
("bpf: Add hash kfunc for cryptographic hashing") which adds NULL checks
before calling these function pointers. Should this commit be squashed
with 76d771a64b50 to ensure each patch in the series is bisectable without
introducing crashes?
> +module_init(bpf_crypto_shash_init);
> +module_exit(bpf_crypto_shash_exit);
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Hash algorithm support for BPF");
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/21183820118
© 2016 - 2026 Red Hat, Inc.