diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-10-22 09:36:46 -1000 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-10-22 09:36:46 -1000 |
| commit | bf2325084583daaea91084b25069f121d5d8832b (patch) | |
| tree | 92934f2b651890d36f1a2177c31a246b25b412c0 /lib | |
| parent | 2a08195e4db5aba84600db6518089a1dbe2d04c7 (diff) | |
| parent | 178aff4cf425b3fc51ff09c571fa1bfbc1eb8ea4 (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.c | 7 | ||||
| -rw-r--r-- | lib/Kconfig.debug | 15 | ||||
| -rw-r--r-- | lib/rhashtable.c | 75 | ||||
| -rw-r--r-- | lib/tests/842_decompress_kunit.c | 144 | ||||
| -rw-r--r-- | lib/tests/Makefile | 1 |
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 |
