summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-10-22 09:36:46 -1000
committerLinus Torvalds <torvalds@linux-foundation.org>2026-10-22 09:36:46 -1000
commitbf2325084583daaea91084b25069f121d5d8832b (patch)
tree92934f2b651890d36f1a2177c31a246b25b412c0 /lib
parent2a08195e4db5aba84600db6518089a1dbe2d04c7 (diff)
parent178aff4cf425b3fc51ff09c571fa1bfbc1eb8ea4 (diff)
Merge tag 'v7.4-p1' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
Pull crypto updates from Herbert Xu: "API: - Fix algif_skcipher source SG overrun - Allow hmac(sha512) for non-root users Algorithms: - Add wrapper for zeroing AES key context - Avoid redundant stream initialisations in zstd Drivers: - Remove hisilicon/sec. - Handle digest-only authenc requests in atmel - Handle zero-length skcipher requests in mxs-dcp - Lower the default priority of caam/qi2 Others: - Optimise key comparison in rhashtable lookup that uses constant parameters" * tag 'v7.4-p1' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6: (146 commits) crypto: atmel-tdes - consolidate error paths in atmel_tdes_dma_init() crypto: atmel-tdes - reuse fast in atmel_tdes_crypt_start() crypto: atmel-tdes - use separate DMA scatterlists MAINTAINERS: delete entry for John Allen hwrng: amd - use PMBASE_OFFSET consistently hwrng: cctrng - simplify cctrng_probe() hwrng: intel - simplify intel_rng_mod_init() crypto: qat - fix use of destroyed vf2pf_lock on VF restart crypto: qat - initialise state_lock on every path in adf_devmgr_add_dev() hwrng: imx-rngc - Use optional clock crypto: talitos - init tasklets before requesting IRQs crypto: algif_skcipher - rewind rounded output bytes crypto: algif_hash - Allow hmac(sha512) for unpriviledged users crypto: sa2ul - Remove unused fields hwrng: stm32 - use devm_platform_ioremap_resource() in stm32_rng_probe() hwrng: stm32 - drop redundant initializations hwrng: amd - simplify control flow in amd_rng_mod_init() hwrng: stm32 - reuse clock rate in stm32_rng_clock_freq_restrain() hwrng: stm32 - use swap() in stm32_rng_probe() hwrng: cctrng - drop redundant initializations ...
Diffstat (limited to 'lib')
-rw-r--r--lib/842/842_decompress.c7
-rw-r--r--lib/Kconfig.debug15
-rw-r--r--lib/rhashtable.c75
-rw-r--r--lib/tests/842_decompress_kunit.c144
-rw-r--r--lib/tests/Makefile1
5 files changed, 181 insertions, 61 deletions
diff --git a/lib/842/842_decompress.c b/lib/842/842_decompress.c
index 582085ef8b49..45a9815abd63 100644
--- a/lib/842/842_decompress.c
+++ b/lib/842/842_decompress.c
@@ -165,6 +165,9 @@ static int __do_index(struct sw842_param *p, u8 size, u8 bits, u64 fsize)
u64 index, offset, total = round_down(p->out - p->ostart, 8);
int ret;
+ if (size > p->olen)
+ return -ENOSPC;
+
ret = next_bits(p, &index, bits);
if (ret)
return ret;
@@ -306,7 +309,7 @@ int sw842_decompress(const u8 *in, unsigned int ilen,
if (ret)
return ret;
- if (p.out == out) /* no previous bytes */
+ if (p.out - p.ostart < 8) /* no complete previous block */
return -EINVAL;
/* copy rep + 1 */
@@ -344,6 +347,8 @@ int sw842_decompress(const u8 *in, unsigned int ilen,
if (!bytes || bytes > SHORT_DATA_BITS_MAX)
return -EINVAL;
+ if (bytes > p.olen)
+ return -ENOSPC;
while (bytes-- > 0) {
ret = next_bits(&p, &tmp, 8);
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 4b9b337df256..004188ac0d52 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2239,6 +2239,21 @@ menuconfig RUNTIME_TESTING_MENU
if RUNTIME_TESTING_MENU
+config 842_DECOMPRESS_KUNIT_TEST
+ tristate "KUnit tests for the 842 decompressor" if !KUNIT_ALL_TESTS
+ depends on KUNIT
+ depends on 842_DECOMPRESS
+ default KUNIT_ALL_TESTS
+ help
+ Enable stream-validation and boundary tests for the software 842
+ decompressor. The tests exercise indexed copies, short data and
+ repeat operations at valid and invalid output or history boundaries.
+
+ For more information on KUnit and unit tests in general, refer to
+ Documentation/dev-tools/kunit/.
+
+ If unsure, say N.
+
config TEST_DHRY
tristate "Dhrystone benchmark test"
help
diff --git a/lib/rhashtable.c b/lib/rhashtable.c
index 6362896e4f09..500c45cd1304 100644
--- a/lib/rhashtable.c
+++ b/lib/rhashtable.c
@@ -191,7 +191,6 @@ static struct bucket_table *bucket_table_alloc(struct rhashtable *ht,
struct bucket_table *tbl = NULL;
size_t size;
int i;
- static struct lock_class_key __key;
tbl = alloc_hooks_tag(ht->alloc_tag,
kvmalloc_node_align_noprof(struct_size(tbl, buckets, nbuckets),
@@ -207,7 +206,9 @@ static struct bucket_table *bucket_table_alloc(struct rhashtable *ht,
if (tbl == NULL)
return NULL;
- lockdep_init_map(&tbl->dep_map, "rhashtable_bucket", &__key, 0);
+#ifdef CONFIG_LOCKDEP
+ lockdep_init_map(&tbl->dep_map, "rhashtable_bucket", ht->lockdep_key, 0);
+#endif
tbl->size = size;
@@ -548,7 +549,7 @@ static void *rhashtable_lookup_one(struct rhashtable *ht,
if (!key ||
(ht->p.obj_cmpfn ?
ht->p.obj_cmpfn(&arg, rht_obj(ht, head)) :
- rhashtable_compare(&arg, rht_obj(ht, head)))) {
+ rhashtable_compare(&arg, rht_obj(ht, head), ht->p))) {
pprev = &head->next;
continue;
}
@@ -710,7 +711,8 @@ static struct rhash_head *__rhashtable_next_in_table(
rht_for_each_rcu(he, tbl, b) {
bool match = params.obj_cmpfn
? !params.obj_cmpfn(&arg, rht_obj(ht, he))
- : !rhashtable_compare(&arg, rht_obj(ht, he));
+ : !rhashtable_compare(&arg, rht_obj(ht, he),
+ params);
if (found) {
if (match)
continue;
@@ -1120,51 +1122,9 @@ static u32 rhashtable_jhash2(const void *key, u32 length, u32 seed)
return jhash2(key, length, seed);
}
-/**
- * rhashtable_init - initialize a new hash table
- * @ht: hash table to be initialized
- * @params: configuration parameters
- *
- * Initializes a new hash table based on the provided configuration
- * parameters. A table can be configured either with a variable or
- * fixed length key:
- *
- * Configuration Example 1: Fixed length keys
- * struct test_obj {
- * int key;
- * void * my_member;
- * struct rhash_head node;
- * };
- *
- * struct rhashtable_params params = {
- * .head_offset = offsetof(struct test_obj, node),
- * .key_offset = offsetof(struct test_obj, key),
- * .key_len = sizeof(int),
- * .hashfn = jhash,
- * };
- *
- * Configuration Example 2: Variable length keys
- * struct test_obj {
- * [...]
- * struct rhash_head node;
- * };
- *
- * u32 my_hash_fn(const void *data, u32 len, u32 seed)
- * {
- * struct test_obj *obj = data;
- *
- * return [... hash ...];
- * }
- *
- * struct rhashtable_params params = {
- * .head_offset = offsetof(struct test_obj, node),
- * .hashfn = jhash,
- * .obj_hashfn = my_hash_fn,
- * };
- */
int __rhashtable_init_noprof(struct rhashtable *ht,
- const struct rhashtable_params *params,
- struct lock_class_key *key)
+ const struct rhashtable_params *params,
+ struct rhashtable_lockdep_keys *keys)
{
struct bucket_table *tbl;
size_t size;
@@ -1174,8 +1134,12 @@ int __rhashtable_init_noprof(struct rhashtable *ht,
return -EINVAL;
memset(ht, 0, sizeof(*ht));
- mutex_init_with_key(&ht->mutex, key);
+ mutex_init_with_key(&ht->mutex, &keys->mutex_key);
spin_lock_init(&ht->lock);
+ lockdep_set_class(&ht->lock, &keys->lock_key);
+#ifdef CONFIG_LOCKDEP
+ ht->lockdep_key = &keys->bucket_key;
+#endif
memcpy(&ht->p, params, sizeof(*params));
alloc_tag_record(ht->alloc_tag);
@@ -1228,22 +1192,13 @@ int __rhashtable_init_noprof(struct rhashtable *ht,
}
EXPORT_SYMBOL_GPL(__rhashtable_init_noprof);
-/**
- * rhltable_init - initialize a new hash list table
- * @hlt: hash list table to be initialized
- * @params: configuration parameters
- *
- * Initializes a new hash list table.
- *
- * See documentation for rhashtable_init.
- */
int __rhltable_init_noprof(struct rhltable *hlt,
const struct rhashtable_params *params,
- struct lock_class_key *key)
+ struct rhashtable_lockdep_keys *keys)
{
int err;
- err = __rhashtable_init_noprof(&hlt->ht, params, key);
+ err = __rhashtable_init_noprof(&hlt->ht, params, keys);
hlt->ht.rhlist = true;
return err;
}
diff --git a/lib/tests/842_decompress_kunit.c b/lib/tests/842_decompress_kunit.c
new file mode 100644
index 000000000000..11202ba9539b
--- /dev/null
+++ b/lib/tests/842_decompress_kunit.c
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <kunit/test.h>
+#include <linux/sw842.h>
+
+#define SW842_GUARD_SIZE 8
+#define SW842_MAX_OUTPUT 16
+#define SW842_GUARD_BYTE 0x42
+#define SW842_OUTPUT_POISON 0x5a
+
+/* ZEROS, I8(0), END, CRC32. */
+static const u8 sw842_index_exact_fit[] = {
+ 0xe6, 0x40, 0x3c, 0x00, 0x00, 0x00, 0x00,
+};
+
+/* D8(eight zero bytes), I8(0), END, CRC32. */
+static const u8 sw842_index_output_overflow[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x06, 0x40, 0x3c, 0x00, 0x00, 0x00, 0x00,
+};
+
+/* ZEROS, SHORT_DATA(01 02 03 04 05), END, CRC32. */
+static const u8 sw842_short_data_exact_fit[] = {
+ 0xe7, 0x68, 0x08, 0x10, 0x18, 0x20,
+ 0x2f, 0xa9, 0x67, 0xfc, 0x07, 0xc0,
+};
+
+/* ZEROS, SHORT_DATA(five zero bytes), END, CRC32. */
+static const u8 sw842_short_data_output_overflow[] = {
+ 0xe7, 0x48, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00,
+};
+
+/* ZEROS, REPEAT(one block), END, CRC32. */
+static const u8 sw842_repeat_exact_history[] = {
+ 0xe6, 0xc0, 0xf0, 0x00, 0x00, 0x00, 0x00,
+};
+
+/*
+ * SHORT_DATA(seven zero bytes), REPEAT(one block), END, CRC32.
+ * CRC32 includes SW842_GUARD_BYTE copied from before output into byte 7.
+ */
+static const u8 sw842_repeat_without_full_history[] = {
+ 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xd8, 0x1e, 0x09, 0xa3, 0x1d, 0xd6,
+};
+
+static const u8 sw842_zero_output[SW842_MAX_OUTPUT];
+static const u8 sw842_short_data_output[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x03, 0x04, 0x05,
+};
+
+struct sw842_decompress_test_case {
+ const char *name;
+ const u8 *compressed;
+ unsigned int compressed_len;
+ const u8 *expected_output;
+ unsigned int output_capacity;
+ int expected_ret;
+};
+
+#define SW842_DECOMPRESS_CASE(_name, _compressed, _compressed_len, _expected, \
+ _capacity, _ret) \
+ { \
+ .name = _name, \
+ .compressed = _compressed, \
+ .compressed_len = _compressed_len, \
+ .expected_output = _expected, \
+ .output_capacity = _capacity, \
+ .expected_ret = _ret, \
+ }
+
+static const struct sw842_decompress_test_case sw842_decompress_cases[] = {
+ SW842_DECOMPRESS_CASE("index_exact_fit", sw842_index_exact_fit,
+ ARRAY_SIZE(sw842_index_exact_fit),
+ sw842_zero_output, 16, 0),
+ SW842_DECOMPRESS_CASE("index_output_overflow",
+ sw842_index_output_overflow,
+ ARRAY_SIZE(sw842_index_output_overflow),
+ sw842_zero_output, 8, -ENOSPC),
+ SW842_DECOMPRESS_CASE("short_data_exact_fit",
+ sw842_short_data_exact_fit,
+ ARRAY_SIZE(sw842_short_data_exact_fit),
+ sw842_short_data_output,
+ sizeof(sw842_short_data_output), 0),
+ SW842_DECOMPRESS_CASE("short_data_output_overflow",
+ sw842_short_data_output_overflow,
+ ARRAY_SIZE(sw842_short_data_output_overflow),
+ sw842_zero_output, 8, -ENOSPC),
+ SW842_DECOMPRESS_CASE("repeat_exact_history",
+ sw842_repeat_exact_history,
+ ARRAY_SIZE(sw842_repeat_exact_history),
+ sw842_zero_output, 16, 0),
+ SW842_DECOMPRESS_CASE("repeat_without_full_history",
+ sw842_repeat_without_full_history,
+ ARRAY_SIZE(sw842_repeat_without_full_history),
+ sw842_zero_output, 15, -EINVAL),
+};
+
+KUNIT_ARRAY_PARAM_DESC(sw842_decompress, sw842_decompress_cases, name);
+
+static void sw842_decompress_test(struct kunit *test)
+{
+ const struct sw842_decompress_test_case *test_case = test->param_value;
+ u8 storage[SW842_GUARD_SIZE + SW842_MAX_OUTPUT + SW842_GUARD_SIZE];
+ u8 expected_guard[SW842_GUARD_SIZE];
+ u8 *output = storage + SW842_GUARD_SIZE;
+ unsigned int output_len = test_case->output_capacity;
+ int ret;
+
+ KUNIT_ASSERT_LE(test, test_case->output_capacity, SW842_MAX_OUTPUT);
+ memset(storage, SW842_GUARD_BYTE, sizeof(storage));
+ memset(expected_guard, SW842_GUARD_BYTE, sizeof(expected_guard));
+ memset(output, SW842_OUTPUT_POISON, test_case->output_capacity);
+
+ ret = sw842_decompress(test_case->compressed,
+ test_case->compressed_len, output, &output_len);
+
+ KUNIT_EXPECT_EQ(test, ret, test_case->expected_ret);
+ /* Every successful case is an exact-fit boundary test. */
+ KUNIT_EXPECT_EQ(test, output_len,
+ test_case->expected_ret ? 0U : test_case->output_capacity);
+ if (!test_case->expected_ret)
+ KUNIT_EXPECT_MEMEQ(test, output, test_case->expected_output,
+ test_case->output_capacity);
+ KUNIT_EXPECT_MEMEQ(test, storage, expected_guard, SW842_GUARD_SIZE);
+ KUNIT_EXPECT_MEMEQ(test, output + test_case->output_capacity,
+ expected_guard, SW842_GUARD_SIZE);
+}
+
+static struct kunit_case sw842_decompress_test_cases[] = {
+ KUNIT_CASE_PARAM(sw842_decompress_test, sw842_decompress_gen_params),
+ {}
+};
+
+static struct kunit_suite sw842_decompress_test_suite = {
+ .name = "842-decompress",
+ .test_cases = sw842_decompress_test_cases,
+};
+
+kunit_test_suite(sw842_decompress_test_suite);
+
+MODULE_DESCRIPTION("Software 842 decompressor KUnit tests");
+MODULE_LICENSE("GPL");
diff --git a/lib/tests/Makefile b/lib/tests/Makefile
index 1a3d39db268f..5f6cf654a128 100644
--- a/lib/tests/Makefile
+++ b/lib/tests/Makefile
@@ -4,6 +4,7 @@
# KUnit tests
CFLAGS_bitfield_kunit.o := $(DISABLE_STRUCTLEAK_PLUGIN)
+obj-$(CONFIG_842_DECOMPRESS_KUNIT_TEST) += 842_decompress_kunit.o
obj-$(CONFIG_BASE64_KUNIT) += base64_kunit.o
obj-$(CONFIG_BITOPS_KUNIT) += bitops_kunit.o
obj-$(CONFIG_BITFIELD_KUNIT) += bitfield_kunit.o