summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Kconfig6
-rw-r--r--lib/Kconfig.debug97
-rw-r--r--lib/Makefile18
-rw-r--r--lib/alloc_tag.c9
-rw-r--r--lib/assoc_array.c3
-rw-r--r--lib/bitmap-str.c9
-rw-r--r--lib/bitmap.c30
-rw-r--r--lib/bootconfig.c162
-rw-r--r--lib/bug.c2
-rw-r--r--lib/codetag.c18
-rw-r--r--lib/crypto/.kunitconfig2
-rw-r--r--lib/crypto/Kconfig42
-rw-r--r--lib/crypto/Makefile3
-rw-r--r--lib/crypto/aes.c1413
-rw-r--r--lib/crypto/aesgcm.c721
-rw-r--r--lib/crypto/fips-aes.h78
-rw-r--r--lib/crypto/fips-sha.h (renamed from lib/crypto/fips.h)6
-rw-r--r--lib/crypto/md5.c14
-rw-r--r--lib/crypto/sha1.c2
-rw-r--r--lib/crypto/sha256.c2
-rw-r--r--lib/crypto/sha3.c2
-rw-r--r--lib/crypto/sha512.c2
-rw-r--r--lib/crypto/tests/Kconfig24
-rw-r--r--lib/crypto/tests/Makefile2
-rw-r--r--lib/crypto/tests/aead-test-template.h1039
-rw-r--r--lib/crypto/tests/aes_cbc_macs_kunit.c12
-rw-r--r--lib/crypto/tests/aes_ccm_kunit.c356
-rw-r--r--lib/crypto/tests/aes_gcm_kunit.c472
-rw-r--r--lib/crypto/tests/blake2b_kunit.c33
-rw-r--r--lib/crypto/tests/blake2s_kunit.c33
-rw-r--r--lib/crypto/tests/chacha20poly1305_kunit.c9
-rw-r--r--lib/crypto/tests/ghash_kunit.c37
-rw-r--r--lib/crypto/tests/hash-test-template.h249
-rw-r--r--lib/crypto/tests/md5_kunit.c2
-rw-r--r--lib/crypto/tests/mldsa_kunit.c19
-rw-r--r--lib/crypto/tests/nh_kunit.c5
-rw-r--r--lib/crypto/tests/poly1305_kunit.c21
-rw-r--r--lib/crypto/tests/polyval_kunit.c38
-rw-r--r--lib/crypto/tests/sha1_kunit.c2
-rw-r--r--lib/crypto/tests/sha224_kunit.c2
-rw-r--r--lib/crypto/tests/sha256_kunit.c48
-rw-r--r--lib/crypto/tests/sha384_kunit.c2
-rw-r--r--lib/crypto/tests/sha3_kunit.c30
-rw-r--r--lib/crypto/tests/sha512_kunit.c2
-rw-r--r--lib/crypto/tests/sm3_kunit.c2
-rw-r--r--lib/crypto/tests/test-utils.h111
-rw-r--r--lib/embedded-cmdline.S16
-rw-r--r--lib/find_bit_benchmark.c17
-rw-r--r--lib/fonts/fonts.c31
-rw-r--r--lib/glob.c31
-rw-r--r--lib/interval_tree_test.c4
-rw-r--r--lib/iov_iter.c32
-rw-r--r--lib/kobject.c8
-rw-r--r--lib/kstrtox.c115
-rw-r--r--lib/kstrtox.h17
-rw-r--r--lib/kunit/Makefile1
-rw-r--r--lib/kunit/debugfs.c30
-rw-r--r--lib/kunit/fwnode.c146
-rw-r--r--lib/kunit/kunit-example-test.c29
-rw-r--r--lib/kunit/string-stream.c9
-rw-r--r--lib/kunit/test.c17
-rw-r--r--lib/locking-selftest.c2
-rw-r--r--lib/lockref.c2
-rw-r--r--lib/maple_tree.c409
-rw-r--r--lib/math/div64.c15
-rw-r--r--lib/math/test_mul_u64_u64_div_u64.c1
-rw-r--r--lib/math/tests/Makefile1
-rw-r--r--lib/math/tests/polynomial_kunit.c270
-rw-r--r--lib/nmi_backtrace.c7
-rw-r--r--lib/percpu-refcount.c2
-rw-r--r--lib/raid/Kconfig12
-rw-r--r--lib/raid/raid6/Makefile2
-rw-r--r--lib/raid/raid6/algos.c102
-rw-r--r--lib/raid/raid6/riscv/recov_rvv.c1
-rw-r--r--lib/raid/raid6/riscv/rvv.c1
-rw-r--r--lib/raid/raid6/tests/raid6_kunit.c66
-rw-r--r--lib/raid/xor/Makefile2
-rw-r--r--lib/raid/xor/tests/Makefile2
-rw-r--r--lib/raid/xor/tests/xor_kunit.c64
-rw-r--r--lib/raid/xor/xor-core.c55
-rw-r--r--lib/random32.c184
-rw-r--r--lib/region_alloc_benchmark.c217
-rw-r--r--lib/rhashtable.c5
-rw-r--r--lib/scatterlist.c1
-rw-r--r--lib/seq_buf.c2
-rw-r--r--lib/string.c3
-rw-r--r--lib/test-kstrtox.c182
-rw-r--r--lib/test_bitmap.c39
-rw-r--r--lib/test_fortify/Makefile1
-rw-r--r--lib/test_hmm.c122
-rw-r--r--lib/test_hmm_uapi.h1
-rw-r--r--lib/test_sysctl.c2
-rw-r--r--lib/tests/Makefile3
-rw-r--r--lib/tests/blackhole_dev_kunit.c2
-rw-r--r--lib/tests/kunit_iov_iter.c5
-rw-r--r--lib/tests/random32_kunit.c182
-rw-r--r--lib/tests/slub_kunit.c190
-rw-r--r--lib/tests/test_ratelimit.c29
-rw-r--r--lib/ucs2_string.c38
-rw-r--r--lib/vdso/Kconfig8
-rw-r--r--lib/vdso/Makefile2
-rw-r--r--lib/vdso/datastore.c65
-rw-r--r--lib/vdso/getrandom.c6
-rw-r--r--lib/vdso/gettimeofday.c20
-rw-r--r--lib/vsprintf.c6
-rw-r--r--lib/xarray.c3
-rw-r--r--lib/xz/xz_dec_bcj.c2
-rw-r--r--lib/xz/xz_dec_lzma2.c63
-rw-r--r--lib/xz/xz_dec_stream.c4
-rw-r--r--lib/xz/xz_lzma2.h2
110 files changed, 6315 insertions, 1784 deletions
diff --git a/lib/Kconfig b/lib/Kconfig
index 55748b68714e..4e6b34c3346d 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -159,12 +159,6 @@ config AUDIT_COMPAT_GENERIC
depends on AUDIT_GENERIC && AUDIT_ARCH_COMPAT_GENERIC && COMPAT
default y
-config RANDOM32_SELFTEST
- bool "PRNG perform self test on init"
- help
- This option enables the 32 bit PRNG library functions to perform a
- self test on initialization.
-
#
# compression support is select'ed if needed
#
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 1244dcac2294..134b15a44625 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -613,21 +613,6 @@ config BUILTIN_MODULE_RANGES
It also records an anchor symbol to determine the load address of the
section.
-config DEBUG_FORCE_WEAK_PER_CPU
- bool "Force weak per-cpu definitions"
- depends on DEBUG_KERNEL
- help
- s390 and alpha require percpu variables in modules to be
- defined weak to work around addressing range issue which
- puts the following two restrictions on percpu variable
- definitions.
-
- 1. percpu symbols must be unique whether static or not
- 2. percpu variables can't be defined inside a function
-
- To ensure that generic code follows the above rules, this
- option forces all percpu variables to be defined as weak.
-
config WARN_CONTEXT_ANALYSIS
bool "Compiler context-analysis warnings"
depends on CC_IS_CLANG && CLANG_VERSION >= 230000
@@ -1048,34 +1033,6 @@ config CODE_TAGGING
bool
select KALLSYMS
-config MEM_ALLOC_PROFILING
- bool "Enable memory allocation profiling"
- default n
- depends on MMU
- depends on PROC_FS
- depends on !DEBUG_FORCE_WEAK_PER_CPU
- select CODE_TAGGING
- select PAGE_EXTENSION
- select SLAB_OBJ_EXT
- help
- Track allocation source code and record total allocation size
- initiated at that code location. The mechanism can be used to track
- memory leaks with a low performance and memory impact.
-
-config MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT
- bool "Enable memory allocation profiling by default"
- default y
- depends on MEM_ALLOC_PROFILING
-
-config MEM_ALLOC_PROFILING_DEBUG
- bool "Memory allocation profiler debugging"
- default n
- depends on MEM_ALLOC_PROFILING
- select MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT
- help
- Adds warnings with helpful error messages for memory allocation
- profiling.
-
source "lib/Kconfig.kasan"
source "lib/Kconfig.kfence"
source "lib/Kconfig.kmsan"
@@ -1320,10 +1277,10 @@ config DETECT_HUNG_TASK_BLOCKER
depends on !PREEMPT_RT
default y
help
- Say Y here to show the blocker task's stacktrace who acquires
- the mutex lock which "hung tasks" are waiting.
- This will add overhead a bit but shows suspicious tasks and
- call trace if it comes from waiting a mutex.
+ Say Y here to show a possible blocker task's stacktrace when
+ a hung task is waiting on a mutex, semaphore, or rwsem.
+ This will add a bit of overhead but shows suspicious tasks and
+ call traces for waits on one of these locks.
config WQ_WATCHDOG
bool "Detect Workqueue Stalls"
@@ -2247,10 +2204,11 @@ config KCOV_INSTRUMENT_ALL
config KCOV_IRQ_AREA_SIZE
hex "Size of interrupt coverage collection area in words"
depends on KCOV
+ range 0x80 0x1000000
default 0x40000
help
- KCOV uses preallocated per-cpu areas to collect coverage from
- soft interrupts. This specifies the size of those areas in the
+ KCOV uses preallocated areas to collect coverage from soft
+ interrupts. This specifies the size of those areas in the
number of unsigned long words.
config KCOV_SELFTEST
@@ -2683,6 +2641,19 @@ config FIND_BIT_BENCHMARK
If unsure, say N.
+config REGION_ALLOC_BENCHMARK
+ tristate "Benchmark bitmap, IDA and Maple Tree region allocation"
+ help
+ This builds a microbenchmark comparing variable-sized region
+ allocation using bitmaps, IDA and Maple Tree. The benchmark
+ runs at initialization time.
+
+ Usage:
+ insmod region_alloc_benchmark.ko
+ insmod region_alloc_benchmark.ko capacities=1024,2048,4096,65536
+
+ If unsure, say N.
+
config FIND_BIT_BENCHMARK_RUST
tristate "Test find_bit functions in Rust"
depends on RUST
@@ -2710,7 +2681,7 @@ config TEST_FIRMWARE
config TEST_SYSCTL
tristate "sysctl test driver"
- depends on PROC_SYSCTL
+ depends on SYSCTL
help
This builds the "test_sysctl" module. This driver enables to test the
proc sysctl interfaces available to drivers safely without affecting
@@ -3504,6 +3475,23 @@ config GCD_KUNIT_TEST
If unsure, say N
+config POLYNOMIAL_KUNIT_TEST
+ tristate "Polynomial calculation (polynomial_calc) test" if !KUNIT_ALL_TESTS
+ depends on KUNIT
+ select POLYNOMIAL
+ default KUNIT_ALL_TESTS
+ help
+ This option enables the KUnit test suite for the polynomial_calc()
+ function, which evaluates integer polynomials using factor
+ redistribution to avoid overflow.
+
+ The test suite verifies correctness for constant, linear, and
+ quadratic polynomials, negative coefficients, per-step dividers,
+ divider_leftover, total_divider scaling, and a real sensor
+ N-to-temperature conversion polynomial.
+
+ If unsure, say N
+
config PRIME_NUMBERS_KUNIT_TEST
tristate "Prime number generator test" if !KUNIT_ALL_TESTS
depends on KUNIT
@@ -3531,6 +3519,15 @@ config GLOB_KUNIT_TEST
If unsure, say N
+config PRANDOM_KUNIT_TEST
+ tristate "KUnit test for prandom" if !KUNIT_ALL_TESTS
+ depends on KUNIT
+ default KUNIT_ALL_TESTS
+ help
+ Enable this option to test the prandom functions at runtime.
+
+ If unsure, say N
+
endif # RUNTIME_TESTING_MENU
config ARCH_USE_MEMTEST
diff --git a/lib/Makefile b/lib/Makefile
index 7f75cc6edf94..dfab958327c5 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -64,6 +64,7 @@ obj-y += hexdump.o
obj-$(CONFIG_TEST_HEXDUMP) += test_hexdump.o
obj-y += kstrtox.o
obj-$(CONFIG_FIND_BIT_BENCHMARK) += find_bit_benchmark.o
+obj-$(CONFIG_REGION_ALLOC_BENCHMARK) += region_alloc_benchmark.o
obj-$(CONFIG_FIND_BIT_BENCHMARK_RUST) += find_bit_benchmark_rust.o
obj-$(CONFIG_TEST_BPF) += test_bpf.o
test_dhry-objs := dhry_1.o dhry_2.o dhry_run.o
@@ -196,7 +197,6 @@ obj-$(CONFIG_OF_RECONFIG_NOTIFIER_ERROR_INJECT) += \
obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
obj-$(CONFIG_CODE_TAGGING) += codetag.o
-obj-$(CONFIG_MEM_ALLOC_PROFILING) += alloc_tag.o
lib-$(CONFIG_GENERIC_BUG) += bug.o
@@ -273,6 +273,22 @@ filechk_defbconf = cat $(or $(real-prereqs), /dev/null)
$(obj)/default.bconf: $(CONFIG_BOOT_CONFIG_EMBED_FILE) FORCE
$(call filechk,defbconf)
+obj-$(CONFIG_CMDLINE_FROM_BOOTCONFIG) += embedded-cmdline.o
+$(obj)/embedded-cmdline.o: $(obj)/embedded_cmdline.bin
+
+# Render the bootconfig "kernel" subtree to a flat cmdline string using
+# the userspace tools/bootconfig parser (-C mode). The runtime prepend
+# helper enforces COMMAND_LINE_SIZE at boot, so no build-time size
+# check is performed here (COMMAND_LINE_SIZE is an arch header
+# constant, not a Kconfig value).
+quiet_cmd_render_cmdline = BCONF2C $@
+ cmd_render_cmdline = \
+ $(objtree)/tools/bootconfig/bootconfig -C $< > $@
+
+targets += embedded_cmdline.bin
+$(obj)/embedded_cmdline.bin: $(obj)/default.bconf $(objtree)/tools/bootconfig/bootconfig FORCE
+ $(call if_changed,render_cmdline)
+
obj-$(CONFIG_RBTREE_TEST) += rbtree_test.o
obj-$(CONFIG_INTERVAL_TREE_TEST) += interval_tree_test.o
diff --git a/lib/alloc_tag.c b/lib/alloc_tag.c
index d9be1cf5187d..e5b218176c5a 100644
--- a/lib/alloc_tag.c
+++ b/lib/alloc_tag.c
@@ -26,6 +26,15 @@ static bool mem_profiling_support = true;
static bool mem_profiling_support;
#endif
+/*
+ * Memory allocation profiling is permanently disabled and cannot be enabled.
+ * Must be called after setup_early_mem_profiling().
+ */
+bool mem_alloc_profiling_permanently_disabled(void)
+{
+ return !mem_profiling_support;
+}
+
static struct codetag_type *alloc_tag_cttype;
#ifdef CONFIG_ARCH_MODULE_NEEDS_WEAK_PER_CPU
diff --git a/lib/assoc_array.c b/lib/assoc_array.c
index bcc6e0a013eb..b6c9723e12ce 100644
--- a/lib/assoc_array.c
+++ b/lib/assoc_array.c
@@ -255,7 +255,8 @@ follow_shortcut:
sc_segments = shortcut->index_key[sc_level >> ASSOC_ARRAY_KEY_CHUNK_SHIFT];
dissimilarity = segments ^ sc_segments;
- if (round_up(sc_level, ASSOC_ARRAY_KEY_CHUNK_SIZE) > shortcut->skip_to_level) {
+ if (shortcut->skip_to_level < round_down(sc_level,
+ ASSOC_ARRAY_KEY_CHUNK_SIZE) + ASSOC_ARRAY_KEY_CHUNK_SIZE) {
/* Trim segments that are beyond the shortcut */
int shift = shortcut->skip_to_level & ASSOC_ARRAY_KEY_CHUNK_MASK;
dissimilarity &= ~(ULONG_MAX << shift);
diff --git a/lib/bitmap-str.c b/lib/bitmap-str.c
index 26d36c938c6a..dd9aa0635fa5 100644
--- a/lib/bitmap-str.c
+++ b/lib/bitmap-str.c
@@ -75,8 +75,7 @@ static int bitmap_print_to_buf(bool list, char *buf, const unsigned long *maskp,
* @off: in the string from which we are copying, We copy to @buf
* @count: the maximum number of bytes to print
*
- * The sprintf("%*pb[l]") is used indirectly via its cpumap wrapper
- * cpumap_print_to_pagebuf() or directly by drivers to export hexadecimal
+ * The sprintf("%*pb[l]") format is used by drivers to export hexadecimal
* bitmask and decimal list to userspace by sysfs ABI.
* Drivers might be using a normal attribute for this kind of ABIs. A
* normal attribute typically has show entry as below::
@@ -115,9 +114,9 @@ static int bitmap_print_to_buf(bool list, char *buf, const unsigned long *maskp,
* parameters such as off, count from bin_attribute show entry to this API.
*
* The role of cpumap_print_bitmask_to_buf() and cpumap_print_list_to_buf()
- * is similar with cpumap_print_to_pagebuf(), the difference is that
- * scnprintf("%*pb[l]") mainly serves sysfs attribute with the assumption
- * the destination buffer is exactly one page and won't be more than one page.
+ * is similar to direct sysfs_emit("%*pb[l]") formatting, but the latter
+ * assumes the destination buffer is exactly one page and won't be more than
+ * one page.
* cpumap_print_bitmask_to_buf() and cpumap_print_list_to_buf(), on the other
* hand, mainly serves bin_attribute which doesn't work with exact one page,
* and it can break the size limit of converted decimal list and hexadecimal
diff --git a/lib/bitmap.c b/lib/bitmap.c
index b9bfa157e095..ed685127a107 100644
--- a/lib/bitmap.c
+++ b/lib/bitmap.c
@@ -424,6 +424,9 @@ EXPORT_SYMBOL(__bitmap_clear);
* The @align_mask should be one less than a power of 2; the effect is that
* the bit offset of all zero areas this function finds plus @align_offset
* is multiple of that power of 2.
+ *
+ * Return: The bit offset of the found area or a value greater than or equal
+ * to @size if no area is found.
*/
unsigned long bitmap_find_next_zero_area_off(unsigned long *map,
unsigned long size,
@@ -432,22 +435,23 @@ unsigned long bitmap_find_next_zero_area_off(unsigned long *map,
unsigned long align_mask,
unsigned long align_offset)
{
- unsigned long index, end, i;
-again:
- index = find_next_zero_bit(map, size, start);
+ unsigned long end, i, off;
+
+ for_each_clear_bit_from(start, map, size) {
+ start = __ALIGN_MASK(start + align_offset, align_mask) - align_offset;
+ end = start + nr;
+ if (end > size)
+ break;
- /* Align allocation */
- index = __ALIGN_MASK(index + align_offset, align_mask) - align_offset;
+ off = round_down(start, BITS_PER_LONG);
+ i = find_last_bit(map + start / BITS_PER_LONG, end - off) + off;
+ if (i >= end || i < start)
+ return start;
- end = index + nr;
- if (end > size)
- return end;
- i = find_next_bit(map, end, index);
- if (i < end) {
- start = i + 1;
- goto again;
+ start = i;
}
- return index;
+
+ return size;
}
EXPORT_SYMBOL(bitmap_find_next_zero_area_off);
diff --git a/lib/bootconfig.c b/lib/bootconfig.c
index f445b7703fdd..89c88e359179 100644
--- a/lib/bootconfig.c
+++ b/lib/bootconfig.c
@@ -19,9 +19,13 @@
#include <linux/errno.h>
#include <linux/cache.h>
#include <linux/compiler.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/printk.h>
#include <linux/sprintf.h>
#include <linux/memblock.h>
#include <linux/string.h>
+#include <asm/setup.h> /* COMMAND_LINE_SIZE */
#ifdef CONFIG_BOOT_CONFIG_EMBED
/* embedded_bootconfig_data is defined in bootconfig-data.S */
@@ -34,7 +38,129 @@ const char * __init xbc_get_embedded_bootconfig(size_t *size)
return (*size) ? embedded_bootconfig_data : NULL;
}
#endif
-#endif
+
+#ifdef CONFIG_CMDLINE_FROM_BOOTCONFIG
+/* embedded_kernel_cmdline is defined in embedded-cmdline.S */
+extern __visible const char embedded_kernel_cmdline[];
+extern __visible const char embedded_kernel_cmdline_end[];
+
+/* Set once the embedded cmdline has actually been prepended. */
+static bool xbc_cmdline_applied __initdata;
+
+/*
+ * str_prepend() - Prepend @src in front of the string in @dst, in place
+ * @dst: NUL-terminated destination buffer, currently @dst_len bytes long
+ * @dst_len: length of the current @dst string (excluding its NUL)
+ * @src: bytes to prepend (not NUL-terminated)
+ * @src_len: number of bytes from @src to prepend
+ *
+ * The caller must guarantee @dst has room for src_len + dst_len + 1 bytes.
+ * Moving dst_len + 1 bytes carries @dst's NUL terminator too, so an empty
+ * @dst needs no special case.
+ */
+static void __init str_prepend(char *dst, size_t dst_len,
+ const char *src, size_t src_len)
+{
+ memmove(dst + src_len, dst, dst_len + 1);
+ memcpy(dst, src, src_len);
+}
+
+/**
+ * xbc_prepend_embedded_cmdline() - Prepend embedded bootconfig cmdline
+ * @dst: cmdline buffer to prepend into (must already contain a NUL byte)
+ * @size: total capacity of @dst in bytes
+ *
+ * Prepend the build-time-rendered "kernel" subtree of the embedded
+ * bootconfig to @dst. The rendered string already ends with a single
+ * space (the xbc_snprint_cmdline() invariant), which serves as the
+ * separator between the embedded keys and any existing content of @dst.
+ * On overflow, log an error and leave @dst untouched rather than
+ * silently truncating: booting without the embedded values is better
+ * than refusing to boot, and the error message tells the user why
+ * their embedded keys are missing.
+ *
+ * Intended to be called from setup_arch() before parse_early_param() so
+ * that early_param() handlers see the embedded values.
+ */
+void __init xbc_prepend_embedded_cmdline(char *dst, size_t size)
+{
+ size_t embed_len = embedded_kernel_cmdline_end - embedded_kernel_cmdline;
+ size_t dst_len;
+
+ if (!size || embed_len <= 1) /* trailing NUL only */
+ return;
+ embed_len--; /* exclude trailing NUL byte */
+
+ dst_len = strnlen(dst, size);
+ if (embed_len + dst_len + 1 > size) {
+ pr_err("embedded bootconfig cmdline (%zu bytes) does not fit in COMMAND_LINE_SIZE with %zu bytes already used; ignoring embedded values\n",
+ embed_len, dst_len);
+ return;
+ }
+
+ str_prepend(dst, dst_len, embedded_kernel_cmdline, embed_len);
+ xbc_cmdline_applied = true;
+}
+
+/**
+ * xbc_embedded_cmdline_applied() - Did the embedded cmdline get prepended?
+ *
+ * Return true if xbc_prepend_embedded_cmdline() actually prepended the
+ * embedded "kernel" subtree. setup_boot_config() uses this to avoid
+ * rendering the same keys a second time.
+ */
+bool __init xbc_embedded_cmdline_applied(void)
+{
+ return xbc_cmdline_applied;
+}
+#endif /* CONFIG_CMDLINE_FROM_BOOTCONFIG */
+
+/* parse_args() callback: flag when the "bootconfig" parameter is present. */
+static int __init bootconfig_optin(char *param, char *val,
+ const char *unused, void *arg)
+{
+ if (!strcmp(param, "bootconfig"))
+ *(bool *)arg = true;
+ return 0;
+}
+
+/**
+ * bootconfig_cmdline_requested() - Was "bootconfig" passed on the cmdline?
+ * @boot_cmdline: kernel command line to inspect (not modified)
+ * @end_offset: if non-NULL, set to the offset of the init arguments that
+ * follow a "--" separator, or 0 when there is none
+ *
+ * Parse a private copy of @boot_cmdline (parse_args() is destructive) and
+ * report whether "bootconfig" is present before the "--" separator.
+ * setup_arch() uses this to gate prepending the build-time embedded cmdline;
+ * setup_boot_config() uses it for the runtime opt-in and to locate the init
+ * arguments via @end_offset. Sharing one parser keeps the early and late
+ * paths agreeing on what counts as opt-in. CONFIG_BOOT_CONFIG_FORCE is not
+ * folded in here; callers apply it where they need it.
+ */
+bool __init bootconfig_cmdline_requested(const char *boot_cmdline, int *end_offset)
+{
+ static char tmp_cmdline[COMMAND_LINE_SIZE] __initdata;
+ bool found = false;
+ char *err;
+
+ if (end_offset)
+ *end_offset = 0;
+
+ strscpy(tmp_cmdline, boot_cmdline, COMMAND_LINE_SIZE);
+ err = parse_args("bootconfig", tmp_cmdline, NULL, 0, 0, 0,
+ &found, bootconfig_optin);
+ if (IS_ERR(err))
+ return false;
+
+ /* parse_args() stops at "--" and returns the address of the rest. */
+ if (end_offset && err)
+ *end_offset = err - tmp_cmdline;
+
+ return found;
+}
+
+#endif /* __KERNEL__ */
/*
* Extra Boot Config (XBC) is given as tree-structured ascii text of
@@ -427,11 +553,30 @@ static char xbc_namebuf[XBC_KEYLEN_MAX] __initdata;
int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root)
{
struct xbc_node *knode, *vnode;
- char *end = buf + size;
const char *val, *q;
+ size_t len = 0;
int ret;
+ /*
+ * Track the running written length rather than advancing @buf, so we
+ * never form "buf + size" or "buf += ret" while @buf is NULL (the
+ * size-probe call passes buf=NULL, size=0). NULL pointer arithmetic
+ * is undefined behavior and trips host UBSan / FORTIFY_SOURCE when
+ * this renderer runs at kernel build time. snprintf(NULL, 0, ...)
+ * itself is well defined and returns the would-be length.
+ */
xbc_node_for_each_key_value(root, knode, val) {
+ /*
+ * An empty or value-only @root (e.g. "kernel {}" or
+ * "kernel = x", possibly alongside "kernel.foo = bar")
+ * yields @root itself here. Skip it: composing a key for it
+ * would fail with -EINVAL, yet any real descendant keys must
+ * still be rendered. An entirely empty subtree then renders
+ * nothing and returns 0 rather than an error.
+ */
+ if (knode == root)
+ continue;
+
ret = xbc_node_compose_key_after(root, knode,
xbc_namebuf, XBC_KEYLEN_MAX);
if (ret < 0)
@@ -439,10 +584,11 @@ int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root)
vnode = xbc_node_get_child(knode);
if (!vnode) {
- ret = snprintf(buf, rest(buf, end), "%s ", xbc_namebuf);
+ ret = snprintf(buf ? buf + len : NULL, rest(len, size),
+ "%s ", xbc_namebuf);
if (ret < 0)
return ret;
- buf += ret;
+ len += ret;
continue;
}
xbc_array_for_each_value(vnode, val) {
@@ -452,15 +598,15 @@ int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root)
* whitespace.
*/
q = strpbrk(val, " \t\r\n") ? "\"" : "";
- ret = snprintf(buf, rest(buf, end), "%s=%s%s%s ",
- xbc_namebuf, q, val, q);
+ ret = snprintf(buf ? buf + len : NULL, rest(len, size),
+ "%s=%s%s%s ", xbc_namebuf, q, val, q);
if (ret < 0)
return ret;
- buf += ret;
+ len += ret;
}
}
- return buf - (end - size);
+ return len;
}
#undef rest
diff --git a/lib/bug.c b/lib/bug.c
index 292420f45811..7c1c2c27f58e 100644
--- a/lib/bug.c
+++ b/lib/bug.c
@@ -219,14 +219,12 @@ static enum bug_trap_type __report_bug(struct bug_entry *bug, unsigned long buga
no_cut = bug->flags & BUGFLAG_NO_CUT_HERE;
has_args = bug->flags & BUGFLAG_ARGS;
-#ifdef CONFIG_KUNIT
/*
* Before the once logic so suppressed warnings do not consume
* the single-fire budget of WARN_ON_ONCE().
*/
if (warning && kunit_is_suppressed_warning(true))
return BUG_TRAP_TYPE_WARN;
-#endif
disable_trace_on_warning();
diff --git a/lib/codetag.c b/lib/codetag.c
index 4001a7ea6675..a9cda4c962a3 100644
--- a/lib/codetag.c
+++ b/lib/codetag.c
@@ -19,6 +19,8 @@ struct codetag_type {
struct codetag_type_desc desc;
/* generates unique sequence number for module load */
unsigned long next_mod_seq;
+ /* bumped on every module load and unload */
+ unsigned long content_id;
};
struct codetag_range {
@@ -50,6 +52,20 @@ void codetag_unlock_module_list(struct codetag_type *cttype)
up_read(&cttype->mod_lock);
}
+unsigned long codetag_get_content_id(struct codetag_type *cttype)
+{
+ lockdep_assert_held(&cttype->mod_lock);
+
+ return cttype->content_id;
+}
+
+unsigned int codetag_get_count(struct codetag_type *cttype)
+{
+ lockdep_assert_held(&cttype->mod_lock);
+
+ return cttype->count;
+}
+
struct codetag_iterator codetag_get_ct_iter(struct codetag_type *cttype)
{
struct codetag_iterator iter = {
@@ -204,6 +220,7 @@ static int codetag_module_init(struct codetag_type *cttype, struct module *mod)
down_write(&cttype->mod_lock);
cmod->mod_seq = ++cttype->next_mod_seq;
+ ++cttype->content_id;
mod_id = idr_alloc(&cttype->mod_idr, cmod, 0, 0, GFP_KERNEL);
if (mod_id >= 0) {
if (cttype->desc.module_load) {
@@ -368,6 +385,7 @@ void codetag_unload_module(struct module *mod)
cttype->count -= range_size(cttype, &cmod->range);
idr_remove(&cttype->mod_idr, mod_id);
kfree(cmod);
+ ++cttype->content_id;
}
up_write(&cttype->mod_lock);
if (found && cttype->desc.free_section_mem)
diff --git a/lib/crypto/.kunitconfig b/lib/crypto/.kunitconfig
index 3efc854a2c08..60e0a77f9889 100644
--- a/lib/crypto/.kunitconfig
+++ b/lib/crypto/.kunitconfig
@@ -3,6 +3,8 @@ CONFIG_KUNIT=y
CONFIG_CRYPTO_LIB_ENABLE_ALL_FOR_KUNIT=y
CONFIG_CRYPTO_LIB_AES_CBC_MACS_KUNIT_TEST=y
+CONFIG_CRYPTO_LIB_AES_CCM_KUNIT_TEST=y
+CONFIG_CRYPTO_LIB_AES_GCM_KUNIT_TEST=y
CONFIG_CRYPTO_LIB_BLAKE2B_KUNIT_TEST=y
CONFIG_CRYPTO_LIB_BLAKE2S_KUNIT_TEST=y
CONFIG_CRYPTO_LIB_CHACHA20POLY1305_KUNIT_TEST=y
diff --git a/lib/crypto/Kconfig b/lib/crypto/Kconfig
index 591c1c2a7fb3..56f308dd0273 100644
--- a/lib/crypto/Kconfig
+++ b/lib/crypto/Kconfig
@@ -9,7 +9,8 @@ config CRYPTO_LIB_UTILS
config CRYPTO_LIB_AES
tristate
# Select dependencies of modes that are part of libaes.
- select CRYPTO_LIB_UTILS if CRYPTO_LIB_AES_CBC_MACS
+ select CRYPTO_LIB_GF128HASH if CRYPTO_LIB_AES_GCM != n
+ select CRYPTO_LIB_UTILS
config CRYPTO_LIB_AES_ARCH
bool
@@ -28,6 +29,12 @@ config CRYPTO_LIB_AESCFB
select CRYPTO_LIB_AES
select CRYPTO_LIB_UTILS
+config CRYPTO_LIB_AES_CBC
+ tristate
+ select CRYPTO_LIB_AES
+ help
+ The AES-CBC and AES-CBC-CTS library functions.
+
config CRYPTO_LIB_AES_CBC_MACS
tristate
select CRYPTO_LIB_AES
@@ -36,11 +43,38 @@ config CRYPTO_LIB_AES_CBC_MACS
this if your module uses any of the functions from
<crypto/aes-cbc-macs.h>.
-config CRYPTO_LIB_AESGCM
+config CRYPTO_LIB_AES_CCM
tristate
select CRYPTO_LIB_AES
- select CRYPTO_LIB_GF128HASH
- select CRYPTO_LIB_UTILS
+ select CRYPTO_LIB_AES_CBC_MACS
+ select CRYPTO_LIB_AES_CTR
+ help
+ The AES-CCM library functions.
+
+config CRYPTO_LIB_AES_CTR
+ tristate
+ select CRYPTO_LIB_AES
+ help
+ The AES-CTR and AES-XCTR library functions.
+
+config CRYPTO_LIB_AES_ECB
+ tristate
+ select CRYPTO_LIB_AES
+ help
+ The AES-ECB library functions.
+
+config CRYPTO_LIB_AES_GCM
+ tristate
+ select CRYPTO_LIB_AES
+ select CRYPTO_LIB_AES_CTR
+ help
+ The AES-GCM library functions.
+
+config CRYPTO_LIB_AES_XTS
+ tristate
+ select CRYPTO_LIB_AES
+ help
+ The AES-XTS library functions.
config CRYPTO_LIB_ARC4
tristate
diff --git a/lib/crypto/Makefile b/lib/crypto/Makefile
index f1e9bf89785f..ca068df1f71f 100644
--- a/lib/crypto/Makefile
+++ b/lib/crypto/Makefile
@@ -63,9 +63,6 @@ clean-files += powerpc/aesp8-ppc.S
obj-$(CONFIG_CRYPTO_LIB_AESCFB) += libaescfb.o
libaescfb-y := aescfb.o
-obj-$(CONFIG_CRYPTO_LIB_AESGCM) += libaesgcm.o
-libaesgcm-y := aesgcm.o
-
obj-$(CONFIG_CRYPTO_LIB_ARC4) += libarc4.o
libarc4-y := arc4.o
diff --git a/lib/crypto/aes.c b/lib/crypto/aes.c
index ca733f15b2a8..f1549839b3de 100644
--- a/lib/crypto/aes.c
+++ b/lib/crypto/aes.c
@@ -5,14 +5,21 @@
*/
#include <crypto/aes-cbc-macs.h>
+#include <crypto/aes-cbc.h>
+#include <crypto/aes-ccm.h>
+#include <crypto/aes-ctr.h>
+#include <crypto/aes-ecb.h>
+#include <crypto/aes-gcm.h>
+#include <crypto/aes-xts.h>
#include <crypto/aes.h>
+#include <crypto/gf128mul.h>
#include <crypto/utils.h>
#include <linux/cache.h>
#include <linux/crypto.h>
#include <linux/export.h>
#include <linux/module.h>
#include <linux/unaligned.h>
-#include "fips.h"
+#include "fips-aes.h"
static const u8 ____cacheline_aligned aes_sbox[] = {
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
@@ -515,6 +522,26 @@ void aes_decrypt(const struct aes_key *key, u8 out[AES_BLOCK_SIZE],
}
EXPORT_SYMBOL(aes_decrypt);
+/* FIPS cryptographic algorithm self-test for "bare" AES */
+static void __init aes_fips_test(void)
+{
+ struct aes_key key;
+ u8 data[AES_BLOCK_SIZE];
+
+ if (aes_preparekey(&key, fips_test_key, sizeof(fips_test_key)) != 0)
+ panic("aes: FIPS self-test failed (preparekey)\n");
+
+ aes_encrypt(&key, data, fips_test_data);
+ if (memcmp(fips_test_aes_ecb_ctext, data, sizeof(data)) != 0)
+ panic("aes: FIPS self-test failed (wrong ciphertext)\n");
+
+ aes_decrypt(&key, data, data);
+ if (memcmp(fips_test_data, data, sizeof(data)) != 0)
+ panic("aes: FIPS self-test failed (wrong plaintext)\n");
+
+ memzero_explicit(&key, sizeof(key));
+}
+
#if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_CBC_MACS)
#ifndef aes_cbcmac_blocks_arch
@@ -710,17 +737,10 @@ void aes_cbcmac_final(struct aes_cbcmac_ctx *ctx, u8 out[AES_BLOCK_SIZE])
}
EXPORT_SYMBOL_NS_GPL(aes_cbcmac_final, "CRYPTO_INTERNAL");
-/*
- * FIPS cryptographic algorithm self-test for AES-CMAC. As per the FIPS 140-3
- * Implementation Guidance, a cryptographic algorithm self-test for at least one
- * of AES-GCM, AES-CCM, AES-CMAC, or AES-GMAC is required if any of those modes
- * is implemented. This fulfills that requirement via AES-CMAC.
- *
- * This is just for FIPS. The full tests are in the KUnit test suite.
- */
+/* FIPS cryptographic algorithm self-test for AES-CMAC */
static void __init aes_cmac_fips_test(void)
{
- struct aes_cmac_key key;
+ struct aes_cmac_key key __cleanup(aes_cmac_zeroize_key);
u8 mac[AES_BLOCK_SIZE];
if (aes_cmac_preparekey(&key, fips_test_key, sizeof(fips_test_key)) !=
@@ -729,7 +749,6 @@ static void __init aes_cmac_fips_test(void)
aes_cmac(&key, fips_test_data, sizeof(fips_test_data), mac);
if (memcmp(fips_test_aes_cmac_value, mac, sizeof(mac)) != 0)
panic("aes: CMAC FIPS self-test failed (wrong MAC)\n");
- memzero_explicit(&key, sizeof(key));
}
#else /* CONFIG_CRYPTO_LIB_AES_CBC_MACS */
static inline void aes_cmac_fips_test(void)
@@ -737,13 +756,1383 @@ static inline void aes_cmac_fips_test(void)
}
#endif /* !CONFIG_CRYPTO_LIB_AES_CBC_MACS */
+#if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_ECB)
+/*
+ * Hooks for optimized AES-ECB implementations, overridable by the architecture.
+ * They are called with len > 0 && len % AES_BLOCK_SIZE == 0. Returning false
+ * causes the fallback implementation to be used instead.
+ */
+#ifndef aes_ecb_encrypt_arch
+static bool aes_ecb_encrypt_arch(u8 *dst, const u8 *src, size_t len,
+ const struct aes_enckey *key)
+{
+ return false;
+}
+#endif
+#ifndef aes_ecb_decrypt_arch
+static bool aes_ecb_decrypt_arch(u8 *dst, const u8 *src, size_t len,
+ const struct aes_key *key)
+{
+ return false;
+}
+#endif
+
+void aes_ecb_encrypt(u8 *dst, const u8 *src, size_t len, aes_encrypt_arg key)
+{
+ if (WARN_ON_ONCE(len % AES_BLOCK_SIZE))
+ len = round_down(len, AES_BLOCK_SIZE);
+
+ if (unlikely(len == 0))
+ return;
+
+ if (likely(aes_ecb_encrypt_arch(dst, src, len, key.enc_key)))
+ return;
+
+ for (size_t i = 0; i < len; i += AES_BLOCK_SIZE)
+ aes_encrypt(key, &dst[i], &src[i]);
+}
+EXPORT_SYMBOL_GPL(aes_ecb_encrypt);
+
+void aes_ecb_decrypt(u8 *dst, const u8 *src, size_t len,
+ const struct aes_key *key)
+{
+ if (WARN_ON_ONCE(len % AES_BLOCK_SIZE))
+ len = round_down(len, AES_BLOCK_SIZE);
+
+ if (unlikely(len == 0))
+ return;
+
+ if (likely(aes_ecb_decrypt_arch(dst, src, len, key)))
+ return;
+
+ for (size_t i = 0; i < len; i += AES_BLOCK_SIZE)
+ aes_decrypt(key, &dst[i], &src[i]);
+}
+EXPORT_SYMBOL_GPL(aes_ecb_decrypt);
+
+/* FIPS cryptographic algorithm self-test for AES-ECB */
+static void __init aes_ecb_fips_test(void)
+{
+ struct aes_key key;
+ u8 data[sizeof(fips_test_data)];
+
+ if (aes_preparekey(&key, fips_test_key, sizeof(fips_test_key)) != 0)
+ panic("aes: ECB FIPS self-test failed (preparekey)\n");
+
+ aes_ecb_encrypt(data, fips_test_data, sizeof(data), &key);
+ if (memcmp(fips_test_aes_ecb_ctext, data, sizeof(data)) != 0)
+ panic("aes: ECB FIPS self-test failed (wrong ciphertext)\n");
+
+ aes_ecb_decrypt(data, data, sizeof(data), &key);
+ if (memcmp(fips_test_data, data, sizeof(data)) != 0)
+ panic("aes: ECB FIPS self-test failed (wrong plaintext)\n");
+
+ memzero_explicit(&key, sizeof(key));
+}
+#else /* CONFIG_CRYPTO_LIB_AES_ECB */
+static inline void aes_ecb_fips_test(void)
+{
+}
+#endif /* !CONFIG_CRYPTO_LIB_AES_ECB */
+
+#if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_CBC)
+/*
+ * Hooks for optimized AES-CBC implementations, overridable by the architecture.
+ * They are called with len > 0 && len % AES_BLOCK_SIZE == 0. Returning false
+ * causes the fallback implementation to be used instead.
+ */
+#ifndef aes_cbc_encrypt_arch
+static bool aes_cbc_encrypt_arch(u8 *dst, const u8 *src, size_t len,
+ u8 iv[AES_BLOCK_SIZE],
+ const struct aes_enckey *key)
+{
+ return false;
+}
+#endif
+#ifndef aes_cbc_decrypt_arch
+static bool aes_cbc_decrypt_arch(u8 *dst, const u8 *src, size_t len,
+ u8 iv[AES_BLOCK_SIZE],
+ const struct aes_key *key)
+{
+ return false;
+}
+#endif
+
+void aes_cbc_encrypt(u8 *dst, const u8 *src, size_t len, u8 iv[AES_BLOCK_SIZE],
+ aes_encrypt_arg key)
+{
+ const u8 *prev = iv;
+
+ if (WARN_ON_ONCE(len % AES_BLOCK_SIZE))
+ len = round_down(len, AES_BLOCK_SIZE);
+
+ if (unlikely(len == 0))
+ return;
+
+ if (likely(aes_cbc_encrypt_arch(dst, src, len, iv, key.enc_key)))
+ return;
+
+ do {
+ crypto_xor_cpy(dst, src, prev, AES_BLOCK_SIZE);
+ aes_encrypt(key, dst, dst);
+ prev = dst;
+ dst += AES_BLOCK_SIZE;
+ src += AES_BLOCK_SIZE;
+ len -= AES_BLOCK_SIZE;
+ } while (len);
+ memcpy(iv, prev, AES_BLOCK_SIZE);
+}
+EXPORT_SYMBOL_GPL(aes_cbc_encrypt);
+
+void aes_cbc_decrypt(u8 *dst, const u8 *src, size_t len, u8 iv[AES_BLOCK_SIZE],
+ const struct aes_key *key)
+{
+ u8 next_iv[AES_BLOCK_SIZE];
+
+ if (WARN_ON_ONCE(len % AES_BLOCK_SIZE))
+ len = round_down(len, AES_BLOCK_SIZE);
+
+ if (unlikely(len == 0))
+ return;
+
+ if (likely(aes_cbc_decrypt_arch(dst, src, len, iv, key)))
+ return;
+
+ len -= AES_BLOCK_SIZE;
+ dst += len;
+ src += len;
+ memcpy(next_iv, src, AES_BLOCK_SIZE);
+ for (;;) {
+ aes_decrypt(key, dst, src);
+ if (len == 0)
+ break;
+ src -= AES_BLOCK_SIZE;
+ crypto_xor(dst, src, AES_BLOCK_SIZE);
+ dst -= AES_BLOCK_SIZE;
+ len -= AES_BLOCK_SIZE;
+ }
+ crypto_xor(dst, iv, AES_BLOCK_SIZE);
+ memcpy(iv, next_iv, AES_BLOCK_SIZE);
+}
+EXPORT_SYMBOL_GPL(aes_cbc_decrypt);
+
+/*
+ * Hooks for optimized AES-CBC-CTS implementations, overridable by the
+ * architecture. They are called with len > AES_BLOCK_SIZE. Returning false
+ * causes the fallback implementation to be used instead. The fallback
+ * implementation still uses the arch-optimized AES-CBC code if available, but
+ * direct implementation of AES-CBC-CTS is helpful on short messages.
+ */
+#ifndef aes_cbc_cts_encrypt_arch
+static bool aes_cbc_cts_encrypt_arch(u8 *dst, const u8 *src, size_t len,
+ u8 iv[AES_BLOCK_SIZE],
+ const struct aes_enckey *key)
+{
+ return false;
+}
+#endif
+#ifndef aes_cbc_cts_decrypt_arch
+static bool aes_cbc_cts_decrypt_arch(u8 *dst, const u8 *src, size_t len,
+ u8 iv[AES_BLOCK_SIZE],
+ const struct aes_key *key)
+{
+ return false;
+}
+#endif
+
+void aes_cbc_cts_encrypt(u8 *dst, const u8 *src, size_t len,
+ u8 iv[AES_BLOCK_SIZE], aes_encrypt_arg key)
+{
+ /* Offset to P[n] and C[n] (last plaintext and ciphertext block) */
+ size_t pn_offset = round_down(len - 1, AES_BLOCK_SIZE);
+ /* Length of P[n] and C[n], 1 <= pn_len <= AES_BLOCK_SIZE */
+ size_t pn_len = len - pn_offset;
+ u8 tmp[AES_BLOCK_SIZE] __aligned(__alignof__(long));
+ u8 *pad;
+
+ if (WARN_ON_ONCE(len < AES_BLOCK_SIZE))
+ return;
+
+ if (len == AES_BLOCK_SIZE) {
+ aes_cbc_encrypt(dst, src, len, iv, key);
+ return;
+ }
+ if (likely(aes_cbc_cts_encrypt_arch(dst, src, len, iv, key.enc_key)))
+ return;
+
+ /* CBC-encrypt all blocks except the last. */
+ aes_cbc_encrypt(dst, src, pn_offset, iv, key);
+
+ /*
+ * Compute C[n] and C[n - 1].
+ *
+ * Careful: src may equal dst (i.e., the encryption can be in-place), so
+ * src[pn_offset..] can't be read after dst[pn_offset..] is written.
+ */
+ pad = &dst[pn_offset - AES_BLOCK_SIZE];
+ memcpy(tmp, pad, AES_BLOCK_SIZE);
+ crypto_xor(tmp, &src[pn_offset], pn_len);
+ memcpy(&dst[pn_offset], pad, pn_len); /* C[n] */
+ aes_encrypt(key, pad, tmp); /* C[n - 1] */
+
+ memzero_explicit(tmp, sizeof(tmp));
+}
+EXPORT_SYMBOL_GPL(aes_cbc_cts_encrypt);
+
+void aes_cbc_cts_decrypt(u8 *dst, const u8 *src, size_t len,
+ u8 iv[AES_BLOCK_SIZE], const struct aes_key *key)
+{
+ /* Offset to P[n] and C[n] (last plaintext and ciphertext block) */
+ size_t pn_offset = round_down(len - 1, AES_BLOCK_SIZE);
+ /* Length of P[n] and C[n], 1 <= pn_len <= AES_BLOCK_SIZE */
+ size_t pn_len = len - pn_offset;
+ u8 *pad;
+
+ if (WARN_ON_ONCE(len < AES_BLOCK_SIZE))
+ return;
+
+ if (len == AES_BLOCK_SIZE) {
+ aes_cbc_decrypt(dst, src, len, iv, key);
+ return;
+ }
+ if (likely(aes_cbc_cts_decrypt_arch(dst, src, len, iv, key)))
+ return;
+
+ /* Compute P[0]..P[n - 2]. */
+ aes_cbc_decrypt(dst, src, pn_offset - AES_BLOCK_SIZE, iv, key);
+
+ /*
+ * Compute P[n] and P[n - 1].
+ *
+ * Careful: src may equal dst (i.e., the decryption can be in-place), so
+ * src[pn_offset..] can't be read after dst[pn_offset..] is written.
+ *
+ * To avoid needing a temporary buffer, do a "redundant" XOR to recover
+ * src[pn_offset..] from dst[pn_offset..] after the latter is written.
+ */
+ pad = &dst[pn_offset - AES_BLOCK_SIZE];
+ aes_decrypt(key, pad, &src[pn_offset - AES_BLOCK_SIZE]);
+ crypto_xor_cpy(&dst[pn_offset], &src[pn_offset], pad,
+ pn_len); /* P[n] */
+ crypto_xor(pad, &dst[pn_offset], pn_len);
+ aes_decrypt(key, pad, pad);
+ crypto_xor(pad, iv, AES_BLOCK_SIZE); /* P[n - 1] */
+}
+EXPORT_SYMBOL_GPL(aes_cbc_cts_decrypt);
+
+/* FIPS cryptographic algorithm self-test for AES-CBC */
+static void __init aes_cbc_fips_test(void)
+{
+ struct aes_key key;
+ u8 iv[AES_BLOCK_SIZE];
+ u8 data[sizeof(fips_test_data)];
+
+ if (aes_preparekey(&key, fips_test_key, sizeof(fips_test_key)) != 0)
+ panic("aes: CBC FIPS self-test failed (preparekey)\n");
+
+ memcpy(iv, fips_test_iv, sizeof(iv));
+ aes_cbc_encrypt(data, fips_test_data, sizeof(data), iv, &key);
+ if (memcmp(fips_test_aes_cbc_ctext, data, sizeof(data)) != 0)
+ panic("aes: CBC FIPS self-test failed (wrong ciphertext)\n");
+
+ memcpy(iv, fips_test_iv, sizeof(iv));
+ aes_cbc_decrypt(data, data, sizeof(data), iv, &key);
+ if (memcmp(fips_test_data, data, sizeof(data)) != 0)
+ panic("aes: CBC FIPS self-test failed (wrong plaintext)\n");
+
+ memzero_explicit(&key, sizeof(key));
+}
+
+/* FIPS cryptographic algorithm self-test for AES-CBC-CTS */
+static void __init aes_cbc_cts_fips_test(void)
+{
+ struct aes_key key;
+ u8 iv[AES_BLOCK_SIZE];
+ const size_t data_len = 2 * AES_BLOCK_SIZE;
+ u8 ptext[2 * AES_BLOCK_SIZE];
+ u8 data[2 * AES_BLOCK_SIZE];
+
+ /* ptext = fips_test_data || fips_test_data */
+ memcpy(ptext, fips_test_data, AES_BLOCK_SIZE);
+ memcpy(&ptext[AES_BLOCK_SIZE], ptext, AES_BLOCK_SIZE);
+
+ if (aes_preparekey(&key, fips_test_key, sizeof(fips_test_key)) != 0)
+ panic("aes: CBC-CTS FIPS self-test failed (preparekey)\n");
+
+ memcpy(iv, fips_test_iv, sizeof(iv));
+ aes_cbc_cts_encrypt(data, ptext, data_len, iv, &key);
+ if (memcmp(fips_test_aes_cbc_cts_ctext, data, data_len) != 0)
+ panic("aes: CBC-CTS FIPS self-test failed (wrong ciphertext)\n");
+
+ memcpy(iv, fips_test_iv, sizeof(iv));
+ aes_cbc_cts_decrypt(data, data, data_len, iv, &key);
+ if (memcmp(ptext, data, data_len) != 0)
+ panic("aes: CBC-CTS FIPS self-test failed (wrong plaintext)\n");
+
+ memzero_explicit(&key, sizeof(key));
+}
+#else /* CONFIG_CRYPTO_LIB_AES_CBC */
+static inline void aes_cbc_fips_test(void)
+{
+}
+static inline void aes_cbc_cts_fips_test(void)
+{
+}
+#endif /* !CONFIG_CRYPTO_LIB_AES_CBC */
+
+#if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_CTR)
+/*
+ * Hooks for optimized AES-CTR and AES-XCTR implementations, overridable by the
+ * architecture. They are called with any len >= 0. Returning false causes the
+ * fallback implementation to be used instead.
+ */
+#ifndef aes_ctr_arch
+static bool aes_ctr_arch(u8 *dst, const u8 *src, size_t len,
+ u8 ctr[AES_BLOCK_SIZE], const struct aes_enckey *key)
+{
+ return false;
+}
+#endif
+#ifndef aes_xctr_arch
+static bool aes_xctr_arch(u8 *dst, const u8 *src, size_t len, u64 *ctr,
+ const u8 iv[AES_BLOCK_SIZE],
+ const struct aes_enckey *key)
+{
+ return false;
+}
+#endif
+
+static __always_inline void inc_be128_ctr(u8 ctr[AES_BLOCK_SIZE])
+{
+ /*
+ * 255 times out of 256 the first iteration is enough, so unroll the
+ * first iteration as a micro-optimization.
+ */
+ if ((++ctr[AES_BLOCK_SIZE - 1]) != 0)
+ return;
+ for (int i = AES_BLOCK_SIZE - 2; i >= 0; i--) {
+ if (++ctr[i] != 0)
+ break;
+ }
+}
+
+void aes_ctr(u8 *dst, const u8 *src, size_t len, u8 ctr[AES_BLOCK_SIZE],
+ aes_encrypt_arg key)
+{
+ u8 keystream[AES_BLOCK_SIZE] __aligned(__alignof__(long));
+
+ if (likely(aes_ctr_arch(dst, src, len, ctr, key.enc_key)))
+ return;
+
+ /* Handle the full blocks. */
+ for (; len >= AES_BLOCK_SIZE; len -= AES_BLOCK_SIZE) {
+ aes_encrypt(key, keystream, ctr);
+ crypto_xor_cpy(dst, src, keystream, AES_BLOCK_SIZE);
+ inc_be128_ctr(ctr);
+ dst += AES_BLOCK_SIZE;
+ src += AES_BLOCK_SIZE;
+ }
+ /* Handle any partial block at the end. */
+ if (len) {
+ aes_encrypt(key, keystream, ctr);
+ crypto_xor_cpy(dst, src, keystream, len);
+ /* Counter is incremented even with just a partial block. */
+ inc_be128_ctr(ctr);
+ }
+ memzero_explicit(keystream, sizeof(keystream));
+}
+EXPORT_SYMBOL_GPL(aes_ctr);
+
+void aes_xctr(u8 *dst, const u8 *src, size_t len, u64 *ctr,
+ const u8 iv[AES_BLOCK_SIZE], aes_encrypt_arg key)
+{
+ const __le64 iv0 = get_unaligned((const __le64 *)&iv[0]);
+ __le64 aes_input[2];
+ u8 keystream[AES_BLOCK_SIZE] __aligned(__alignof__(long));
+
+ if (likely(aes_xctr_arch(dst, src, len, ctr, iv, key.enc_key)))
+ return;
+
+ aes_input[1] = get_unaligned((const __le64 *)&iv[8]);
+ /* Handle the full blocks. */
+ for (; len >= AES_BLOCK_SIZE; len -= AES_BLOCK_SIZE) {
+ aes_input[0] = iv0 ^ cpu_to_le64((*ctr)++);
+ aes_encrypt(key, keystream, (const u8 *)aes_input);
+ crypto_xor_cpy(dst, src, keystream, AES_BLOCK_SIZE);
+ dst += AES_BLOCK_SIZE;
+ src += AES_BLOCK_SIZE;
+ }
+ /* Handle any partial block at the end. */
+ if (len) {
+ /* Counter is incremented even with just a partial block. */
+ aes_input[0] = iv0 ^ cpu_to_le64((*ctr)++);
+ aes_encrypt(key, keystream, (const u8 *)aes_input);
+ crypto_xor_cpy(dst, src, keystream, len);
+ }
+ memzero_explicit(keystream, sizeof(keystream));
+ memzero_explicit(aes_input, sizeof(aes_input));
+}
+EXPORT_SYMBOL_GPL(aes_xctr);
+
+/* FIPS cryptographic algorithm self-test for AES-CTR */
+static void __init aes_ctr_fips_test(void)
+{
+ struct aes_enckey key;
+ u8 ctr[AES_BLOCK_SIZE];
+ u8 data[sizeof(fips_test_data)];
+
+ if (aes_prepareenckey(&key, fips_test_key, sizeof(fips_test_key)) != 0)
+ panic("aes: CTR FIPS self-test failed (preparekey)\n");
+
+ memcpy(ctr, fips_test_iv, sizeof(ctr));
+ aes_ctr(data, fips_test_data, sizeof(data), ctr, &key);
+ if (memcmp(fips_test_aes_ctr_ctext, data, sizeof(data)) != 0)
+ panic("aes: CTR FIPS self-test failed (wrong ciphertext)\n");
+
+ memcpy(ctr, fips_test_iv, sizeof(ctr));
+ aes_ctr(data, data, sizeof(data), ctr, &key);
+ if (memcmp(fips_test_data, data, sizeof(data)) != 0)
+ panic("aes: CTR FIPS self-test failed (wrong plaintext)\n");
+
+ memzero_explicit(&key, sizeof(key));
+}
+#else /* CONFIG_CRYPTO_LIB_AES_CTR */
+static inline void aes_ctr_fips_test(void)
+{
+}
+#endif /* !CONFIG_CRYPTO_LIB_AES_CTR */
+
+#if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_XTS)
+int aes_xts_preparekey(struct aes_xts_key *key, const u8 *in_key,
+ size_t key_len, int flags)
+{
+ int err;
+
+ err = __xts_verify_key(in_key, key_len, flags);
+ if (unlikely(err))
+ goto out_zeroize;
+ /* First half of XTS key is the main key */
+ err = aes_preparekey(&key->main_key, in_key, key_len / 2);
+ if (unlikely(err))
+ goto out_zeroize;
+ /* Second half of XTS key is the tweak key */
+ err = aes_prepareenckey(&key->tweak_key, &in_key[key_len / 2],
+ key_len / 2);
+ if (unlikely(err))
+ goto out_zeroize;
+ return 0;
+
+out_zeroize:
+ memzero_explicit(key, sizeof(*key));
+ return err;
+}
+EXPORT_SYMBOL_GPL(aes_xts_preparekey);
+
+/*
+ * Hooks for optimized AES-XTS implementations, overridable by the architecture.
+ * They are called with len > 0 && len % AES_BLOCK_SIZE == 0. In other words,
+ * they aren't expected to handle ciphertext stealing or empty inputs.
+ * Returning false causes the fallback implementation to be used instead.
+ *
+ * (Currently, all users of AES-XTS in the kernel seem to en/decrypt whole
+ * numbers of blocks anyway, with len >= 512. So there's no need to heavily
+ * optimize ciphertext stealing for short messages.)
+ */
+#ifndef aes_xts_encrypt_arch
+static bool aes_xts_encrypt_arch(u8 *dst, const u8 *src, size_t len,
+ u8 tweak[AES_BLOCK_SIZE],
+ const struct aes_xts_key *key, bool cont)
+{
+ return false;
+}
+#endif
+#ifndef aes_xts_decrypt_arch
+static bool aes_xts_decrypt_arch(u8 *dst, const u8 *src, size_t len,
+ u8 tweak[AES_BLOCK_SIZE],
+ const struct aes_xts_key *key, bool cont)
+{
+ return false;
+}
+#endif
+
+static noinline void aes_xts_crypt_nocts_blockbyblock(
+ u8 *dst, const u8 *src, size_t len, u8 tweak[AES_BLOCK_SIZE],
+ const struct aes_xts_key *key, bool cont, bool enc)
+{
+ le128 t;
+
+ if (cont)
+ memcpy(&t, tweak, sizeof(t));
+ else
+ aes_encrypt(&key->tweak_key, (u8 *)&t, tweak);
+ do {
+ crypto_xor_cpy(dst, src, (const u8 *)&t, AES_BLOCK_SIZE);
+ if (enc)
+ aes_encrypt(&key->main_key, dst, dst);
+ else
+ aes_decrypt(&key->main_key, dst, dst);
+ crypto_xor(dst, (const u8 *)&t, AES_BLOCK_SIZE);
+ gf128mul_x_ble(&t, &t);
+ dst += AES_BLOCK_SIZE;
+ src += AES_BLOCK_SIZE;
+ len -= AES_BLOCK_SIZE;
+ } while (len);
+ memcpy(tweak, &t, sizeof(t));
+ memzero_explicit(&t, sizeof(t));
+}
+
+/* Requires len > 0 && len % AES_BLOCK_SIZE == 0 */
+static __always_inline void aes_xts_encrypt_nocts(u8 *dst, const u8 *src,
+ size_t len,
+ u8 tweak[AES_BLOCK_SIZE],
+ const struct aes_xts_key *key,
+ bool cont)
+{
+ if (likely(aes_xts_encrypt_arch(dst, src, len, tweak, key, cont)))
+ return;
+
+ /*
+ * For the fallback, just go block-by-block. It could be implemented on
+ * top of AES-ECB, which could be significantly faster than this if the
+ * arch has optimized AES-ECB code but not AES-XTS. However, AES-XTS
+ * performance is important enough that it needs to be (and has been)
+ * implemented directly by every non-obsolete arch anyway.
+ */
+ aes_xts_crypt_nocts_blockbyblock(dst, src, len, tweak, key, cont,
+ /* enc= */ true);
+}
+
+/* Requires len > 0 && len % AES_BLOCK_SIZE == 0 */
+static __always_inline void aes_xts_decrypt_nocts(u8 *dst, const u8 *src,
+ size_t len,
+ u8 tweak[AES_BLOCK_SIZE],
+ const struct aes_xts_key *key,
+ bool cont)
+{
+ if (likely(aes_xts_decrypt_arch(dst, src, len, tweak, key, cont)))
+ return;
+
+ /* Just go block-by-block. See comment in aes_xts_encrypt_nocts(). */
+ aes_xts_crypt_nocts_blockbyblock(dst, src, len, tweak, key, cont,
+ /* enc= */ false);
+}
+
+static noinline void aes_xts_encrypt_cts(u8 *dst, const u8 *src, size_t len,
+ u8 tweak[AES_BLOCK_SIZE],
+ const struct aes_xts_key *key,
+ bool cont)
+{
+ size_t partial_len = len % AES_BLOCK_SIZE; /* Length of partial block */
+ size_t nocts_len = round_down(len, AES_BLOCK_SIZE);
+ u8 tmp_block[AES_BLOCK_SIZE] __aligned(__alignof__(long));
+
+ /* Encrypt all full blocks. */
+ aes_xts_encrypt_nocts(dst, src, nocts_len, tweak, key, cont);
+ dst += nocts_len - AES_BLOCK_SIZE;
+ src += nocts_len - AES_BLOCK_SIZE;
+
+ /*
+ * Swap the partial block with the first 'partial_len' bytes of the
+ * encrypted last full block. Note that a temporary buffer is needed to
+ * support in-place encryption.
+ */
+ memcpy(tmp_block, src + AES_BLOCK_SIZE, partial_len);
+ memcpy(dst + AES_BLOCK_SIZE, dst, partial_len);
+ memcpy(dst, tmp_block, partial_len);
+
+ /* Encrypt the last full block again. */
+ crypto_xor(dst, tweak, AES_BLOCK_SIZE);
+ aes_encrypt(&key->main_key, dst, dst);
+ crypto_xor(dst, tweak, AES_BLOCK_SIZE);
+ memzero_explicit(tmp_block, sizeof(tmp_block));
+}
+
+static noinline void aes_xts_decrypt_cts(u8 *dst, const u8 *src, size_t len,
+ u8 tweak[AES_BLOCK_SIZE],
+ const struct aes_xts_key *key,
+ bool cont)
+{
+ size_t partial_len = len % AES_BLOCK_SIZE; /* Length of partial block */
+ size_t nocts_len = round_down(len, AES_BLOCK_SIZE) - AES_BLOCK_SIZE;
+ union {
+ u8 block[AES_BLOCK_SIZE];
+ le128 tweak;
+ } tmp __aligned(__alignof__(long));
+
+ /*
+ * Decrypt all blocks except the last full block and the partial block.
+ * The last full block has to be handled specially because decryption
+ * ciphertext stealing uses the last two tweaks in reverse order.
+ *
+ * nocts_len == 0 is possible here, which aes_xts_decrypt_nocts()
+ * doesn't handle (so that the length doesn't get checked redundantly in
+ * the fast path). So handle that case specially as well.
+ */
+ if (nocts_len)
+ aes_xts_decrypt_nocts(dst, src, nocts_len, tweak, key, cont);
+ else if (!cont)
+ aes_encrypt(&key->tweak_key, tweak, tweak);
+ dst += nocts_len;
+ src += nocts_len;
+
+ /* Copy the tweak, advance it again, then decrypt last full block. */
+ memcpy(&tmp.tweak, tweak, AES_BLOCK_SIZE);
+ gf128mul_x_ble(&tmp.tweak, &tmp.tweak);
+ crypto_xor_cpy(dst, src, tmp.block, AES_BLOCK_SIZE);
+ aes_decrypt(&key->main_key, dst, dst);
+ crypto_xor(dst, tmp.block, AES_BLOCK_SIZE);
+
+ /*
+ * Swap the partial block with the first 'partial_len' bytes of the
+ * decrypted last full block. Note that a temporary buffer is needed to
+ * support in-place decryption.
+ */
+ memcpy(tmp.block, src + AES_BLOCK_SIZE, partial_len);
+ memcpy(dst + AES_BLOCK_SIZE, dst, partial_len);
+ memcpy(dst, tmp.block, partial_len);
+
+ /* Decrypt the last full block again. */
+ crypto_xor(dst, tweak, AES_BLOCK_SIZE);
+ aes_decrypt(&key->main_key, dst, dst);
+ crypto_xor(dst, tweak, AES_BLOCK_SIZE);
+ memzero_explicit(&tmp, sizeof(tmp));
+}
+
+void aes_xts_encrypt(u8 *dst, const u8 *src, size_t len,
+ u8 tweak[AES_BLOCK_SIZE], const struct aes_xts_key *key,
+ bool cont)
+{
+ if (WARN_ON_ONCE(len < AES_BLOCK_SIZE))
+ return;
+
+ if (unlikely(len % AES_BLOCK_SIZE)) {
+ aes_xts_encrypt_cts(dst, src, len, tweak, key, cont);
+ return;
+ }
+
+ aes_xts_encrypt_nocts(dst, src, len, tweak, key, cont);
+}
+EXPORT_SYMBOL_GPL(aes_xts_encrypt);
+
+void aes_xts_decrypt(u8 *dst, const u8 *src, size_t len,
+ u8 tweak[AES_BLOCK_SIZE], const struct aes_xts_key *key,
+ bool cont)
+{
+ if (WARN_ON_ONCE(len < AES_BLOCK_SIZE))
+ return;
+
+ if (unlikely(len % AES_BLOCK_SIZE)) {
+ aes_xts_decrypt_cts(dst, src, len, tweak, key, cont);
+ return;
+ }
+
+ aes_xts_decrypt_nocts(dst, src, len, tweak, key, cont);
+}
+EXPORT_SYMBOL_GPL(aes_xts_decrypt);
+
+/* FIPS cryptographic algorithm self-test for AES-XTS */
+static void __init aes_xts_fips_test(void)
+{
+ struct aes_xts_key *key __free(kfree_sensitive) = kmalloc_obj(*key);
+ u8 tweak[AES_BLOCK_SIZE];
+ u8 data[sizeof(fips_test_data)];
+
+ if (key == NULL)
+ panic("aes: XTS FIPS self-test failed (kmalloc)\n");
+
+ if (aes_xts_preparekey(key, fips_test_xts_key,
+ sizeof(fips_test_xts_key), 0) != 0)
+ panic("aes: XTS FIPS self-test failed (preparekey)\n");
+
+ memcpy(tweak, fips_test_iv, sizeof(tweak));
+ aes_xts_encrypt(data, fips_test_data, sizeof(data), tweak, key, false);
+ if (memcmp(fips_test_aes_xts_ctext, data, sizeof(data)) != 0)
+ panic("aes: XTS FIPS self-test failed (wrong ciphertext)\n");
+
+ memcpy(tweak, fips_test_iv, sizeof(tweak));
+ aes_xts_decrypt(data, data, sizeof(data), tweak, key, false);
+ if (memcmp(fips_test_data, data, sizeof(data)) != 0)
+ panic("aes: XTS FIPS self-test failed (wrong plaintext)\n");
+}
+#else /* CONFIG_CRYPTO_LIB_AES_XTS */
+static inline void aes_xts_fips_test(void)
+{
+}
+#endif /* !CONFIG_CRYPTO_LIB_AES_XTS */
+
+#if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_GCM)
+/*
+ * Hooks for optimized AES-GCM implementations, overridable by the architecture.
+ * They are called with len > 0 && len % AES_BLOCK_SIZE == 0. I.e. they aren't
+ * expected to handle empty inputs or partial blocks, as those cases are handled
+ * by non-arch-specific code instead.
+ *
+ * The GHASH accumulator is provided in POLYVAL format. The counter is provided
+ * in big endian format, and it's read-only, as the caller handles updating it.
+ *
+ * Returning false causes the fallback implementation to be used instead.
+ *
+ * These hooks are used only for en/decrypted data. For the associated data the
+ * GHASH functions are called instead, so those should be implemented too.
+ */
+#ifndef aes_gcm_encrypt_update_arch
+static bool aes_gcm_encrypt_update_arch(u8 *dst, const u8 *src, size_t len,
+ struct polyval_elem *ghash_acc,
+ const __be32 ctr32[4],
+ const struct aes_enckey *aes_key,
+ const struct ghash_key *ghash_key)
+{
+ return false;
+}
+#endif
+#ifndef aes_gcm_decrypt_update_arch
+static bool aes_gcm_decrypt_update_arch(u8 *dst, const u8 *src, size_t len,
+ struct polyval_elem *ghash_acc,
+ const __be32 ctr32[4],
+ const struct aes_enckey *aes_key,
+ const struct ghash_key *ghash_key)
+{
+ return false;
+}
+#endif
+
+int aes_gcm_preparekey(struct aes_gcm_key *key, const u8 *in_key,
+ size_t key_len, size_t authtag_len)
+{
+ u8 h[AES_BLOCK_SIZE] = { 0 };
+ int err;
+
+ err = crypto_gcm_check_authsize(authtag_len);
+ if (unlikely(err))
+ return err;
+
+ err = aes_prepareenckey(&key->aes, in_key, key_len);
+ if (unlikely(err))
+ return err;
+
+ aes_encrypt(&key->aes, h, h);
+ ghash_preparekey(&key->ghash, h);
+
+ key->authtag_len = authtag_len;
+
+ memzero_explicit(h, sizeof(h));
+ return 0;
+}
+EXPORT_SYMBOL_GPL(aes_gcm_preparekey);
+
+void aes_gcm_init(struct aes_gcm_ctx *ctx, const u8 nonce[12],
+ const struct aes_gcm_key *key)
+{
+ ctx->key = key;
+ ctx->ad_len = 0;
+ ctx->data_len = 0;
+ ghash_init(&ctx->ghash, &key->ghash);
+ memset(ctx->keystream, 0, sizeof(ctx->keystream));
+
+ memcpy(ctx->ctr32, nonce, 12);
+ ctx->ctr32[3] = cpu_to_be32(1);
+
+ aes_encrypt(&key->aes, ctx->j0_enc, ctx->ctr);
+ ctx->ctr32[3] = cpu_to_be32(2);
+}
+EXPORT_SYMBOL_GPL(aes_gcm_init);
+
+void aes_gcm_auth_update(struct aes_gcm_ctx *ctx, const u8 *ad, size_t len)
+{
+ WARN_ON_ONCE(ctx->data_len != 0);
+ if (len) {
+ ghash_update(&ctx->ghash, ad, len);
+ ctx->ad_len += len;
+ }
+}
+EXPORT_SYMBOL_GPL(aes_gcm_auth_update);
+
+static const u8 gcm_zeroes[AES_BLOCK_SIZE];
+
+static __always_inline void ghash_pad(struct ghash_ctx *ghash, u64 len)
+{
+ if (len % AES_BLOCK_SIZE)
+ ghash_update(ghash, gcm_zeroes, -len % AES_BLOCK_SIZE);
+}
+
+static __always_inline void aes_gcm_crypt_update(struct aes_gcm_ctx *ctx,
+ u8 *dst, const u8 *src,
+ size_t len, bool enc)
+{
+ size_t partial_len, n;
+
+ if (unlikely(len == 0))
+ return;
+
+ partial_len = ctx->data_len % AES_BLOCK_SIZE;
+ if (ctx->data_len == 0)
+ ghash_pad(&ctx->ghash, ctx->ad_len);
+ ctx->data_len += len;
+
+ if (unlikely(partial_len != 0)) {
+ /*
+ * The previous call ended on a non-block-aligned data_len, so
+ * continue using a previously-generated keystream block.
+ */
+ n = min(len, AES_BLOCK_SIZE - partial_len);
+ if (enc) {
+ crypto_xor_cpy(dst, src, &ctx->keystream[partial_len],
+ n);
+ ghash_update(&ctx->ghash, dst, n);
+ } else {
+ ghash_update(&ctx->ghash, src, n);
+ crypto_xor_cpy(dst, src, &ctx->keystream[partial_len],
+ n);
+ }
+ dst += n;
+ src += n;
+ len -= n;
+ }
+
+ if (len >= AES_BLOCK_SIZE) {
+ n = round_down(len, AES_BLOCK_SIZE);
+ if (enc) {
+ if (likely(aes_gcm_encrypt_update_arch(
+ dst, src, n, &ctx->ghash.acc, ctx->ctr32,
+ &ctx->key->aes, &ctx->key->ghash))) {
+ be32_add_cpu(&ctx->ctr32[3],
+ n / AES_BLOCK_SIZE);
+ } else {
+ aes_ctr(dst, src, n, ctx->ctr, &ctx->key->aes);
+ ghash_update(&ctx->ghash, dst, n);
+ }
+ } else {
+ if (likely(aes_gcm_decrypt_update_arch(
+ dst, src, n, &ctx->ghash.acc, ctx->ctr32,
+ &ctx->key->aes, &ctx->key->ghash))) {
+ be32_add_cpu(&ctx->ctr32[3],
+ n / AES_BLOCK_SIZE);
+ } else {
+ ghash_update(&ctx->ghash, src, n);
+ aes_ctr(dst, src, n, ctx->ctr, &ctx->key->aes);
+ }
+ }
+ dst += n;
+ src += n;
+ len -= n;
+ }
+
+ if (len != 0) {
+ /*
+ * Ending on a non-block aligned data_len. Generate the next
+ * keystream block, use the needed portion of it, and leave it
+ * cached in ctx->keystream in case this isn't the final call.
+ */
+ aes_encrypt(&ctx->key->aes, ctx->keystream, ctx->ctr);
+ be32_add_cpu(&ctx->ctr32[3], 1);
+ if (enc) {
+ crypto_xor_cpy(dst, src, ctx->keystream, len);
+ ghash_update(&ctx->ghash, dst, len);
+ } else {
+ ghash_update(&ctx->ghash, src, len);
+ crypto_xor_cpy(dst, src, ctx->keystream, len);
+ }
+ }
+}
+
+void aes_gcm_encrypt_update(struct aes_gcm_ctx *ctx, u8 *dst, const u8 *src,
+ size_t len)
+{
+ aes_gcm_crypt_update(ctx, dst, src, len, /* enc= */ true);
+}
+EXPORT_SYMBOL_GPL(aes_gcm_encrypt_update);
+
+void aes_gcm_decrypt_update(struct aes_gcm_ctx *ctx, u8 *dst, const u8 *src,
+ size_t len)
+{
+ aes_gcm_crypt_update(ctx, dst, src, len, /* enc= */ false);
+}
+EXPORT_SYMBOL_GPL(aes_gcm_decrypt_update);
+
+/* Maximum AES-GCM associated data length in bytes */
+#define AES_GCM_MAX_AD_LEN ((1ULL << 61) - 1)
+/* Maximum AES-GCM en/decrypted data length in bytes */
+#define AES_GCM_MAX_DATA_LEN ((1ULL << 36) - 32)
+
+void aes_gcm_encrypt_final(struct aes_gcm_ctx *ctx, u8 *authtag)
+{
+ __be64 tail[2];
+
+ WARN_ON_ONCE(ctx->ad_len > AES_GCM_MAX_AD_LEN);
+ WARN_ON_ONCE(ctx->data_len > AES_GCM_MAX_DATA_LEN);
+
+ ghash_pad(&ctx->ghash,
+ ctx->data_len == 0 ? ctx->ad_len : ctx->data_len);
+
+ tail[0] = cpu_to_be64(ctx->ad_len * 8);
+ tail[1] = cpu_to_be64(ctx->data_len * 8);
+ ghash_update(&ctx->ghash, (const u8 *)tail, 16);
+ ghash_final(&ctx->ghash, ctx->ctr); /* Use ctr as temp buffer */
+
+ crypto_xor_cpy(authtag, ctx->ctr, ctx->j0_enc, ctx->key->authtag_len);
+ memzero_explicit(ctx, sizeof(*ctx));
+}
+EXPORT_SYMBOL_GPL(aes_gcm_encrypt_final);
+
+int aes_gcm_decrypt_final(struct aes_gcm_ctx *ctx, const u8 *authtag)
+{
+ __be64 tail[2];
+ int err;
+
+ if (WARN_ON_ONCE(ctx->ad_len > AES_GCM_MAX_AD_LEN) ||
+ WARN_ON_ONCE(ctx->data_len > AES_GCM_MAX_DATA_LEN)) {
+ err = -EBADMSG;
+ goto out;
+ }
+
+ ghash_pad(&ctx->ghash,
+ ctx->data_len == 0 ? ctx->ad_len : ctx->data_len);
+
+ tail[0] = cpu_to_be64(ctx->ad_len * 8);
+ tail[1] = cpu_to_be64(ctx->data_len * 8);
+ ghash_update(&ctx->ghash, (const u8 *)tail, 16);
+ ghash_final(&ctx->ghash, ctx->ctr); /* Use ctr as temp buffer */
+ crypto_xor(ctx->ctr, ctx->j0_enc, ctx->key->authtag_len);
+ err = crypto_memneq(ctx->ctr, authtag, ctx->key->authtag_len) ?
+ -EBADMSG :
+ 0;
+out:
+ memzero_explicit(ctx, sizeof(*ctx));
+ return err;
+}
+EXPORT_SYMBOL_GPL(aes_gcm_decrypt_final);
+
+void aes_gcm_encrypt(u8 *dst, const u8 *src, size_t data_len, u8 *authtag,
+ const u8 *ad, size_t ad_len, const u8 nonce[12],
+ const struct aes_gcm_key *key)
+{
+ struct aes_gcm_ctx ctx;
+
+ aes_gcm_init(&ctx, nonce, key);
+ aes_gcm_auth_update(&ctx, ad, ad_len);
+ aes_gcm_encrypt_update(&ctx, dst, src, data_len);
+ aes_gcm_encrypt_final(&ctx, authtag);
+}
+EXPORT_SYMBOL_GPL(aes_gcm_encrypt);
+
+int aes_gcm_decrypt(u8 *dst, const u8 *src, size_t data_len, const u8 *authtag,
+ const u8 *ad, size_t ad_len, const u8 nonce[12],
+ const struct aes_gcm_key *key)
+{
+ struct aes_gcm_ctx ctx;
+ int err;
+
+ aes_gcm_init(&ctx, nonce, key);
+ aes_gcm_auth_update(&ctx, ad, ad_len);
+ aes_gcm_decrypt_update(&ctx, dst, src, data_len);
+ err = aes_gcm_decrypt_final(&ctx, authtag);
+ if (unlikely(err) && data_len) {
+ /*
+ * Clear the inauthentic decrypted data so that callers won't
+ * receive it even if they fail to correctly handle errors.
+ */
+ memset(dst, 0, data_len);
+ }
+ return err;
+}
+EXPORT_SYMBOL_GPL(aes_gcm_decrypt);
+
+/* FIPS cryptographic algorithm self-test for AES-GCM */
+static void __init aes_gcm_fips_test(void)
+{
+ const size_t data_len = sizeof(fips_test_data);
+ u8 buf[sizeof(fips_test_data) + AES_BLOCK_SIZE];
+ struct aes_gcm_key key;
+ int err;
+
+ if (aes_gcm_preparekey(&key, fips_test_key, sizeof(fips_test_key),
+ AES_BLOCK_SIZE) != 0)
+ panic("aes: GCM FIPS self-test failed (preparekey)\n");
+
+ aes_gcm_encrypt(buf, fips_test_data, data_len, &buf[data_len],
+ fips_test_ad, sizeof(fips_test_ad), fips_test_iv, &key);
+ if (memcmp(fips_test_aes_gcm_ctext_and_tag, buf, sizeof(buf)) != 0)
+ panic("aes: GCM FIPS self-test failed (wrong ciphertext and/or tag)\n");
+
+ err = aes_gcm_decrypt(buf, buf, data_len, &buf[data_len], fips_test_ad,
+ sizeof(fips_test_ad), fips_test_iv, &key);
+ if (err != 0)
+ panic("aes: GCM FIPS self-test failed (decryption failed)\n");
+ if (memcmp(fips_test_data, buf, data_len) != 0)
+ panic("aes: GCM FIPS self-test failed (wrong plaintext)\n");
+
+ memzero_explicit(&key, sizeof(key));
+}
+#else /* CONFIG_CRYPTO_LIB_AES_GCM */
+static inline void aes_gcm_fips_test(void)
+{
+}
+#endif /* !CONFIG_CRYPTO_LIB_AES_GCM */
+
+#if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_CCM)
+int aes_ccm_preparekey(struct aes_ccm_key *key, const u8 *in_key,
+ size_t key_len, size_t authtag_len)
+{
+ int err;
+
+ if (unlikely(authtag_len < 4 || authtag_len > 16 || authtag_len % 2))
+ return -EINVAL;
+
+ err = aes_prepareenckey(&key->aes, in_key, key_len);
+ if (unlikely(err))
+ return err;
+
+ key->authtag_len = authtag_len;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(aes_ccm_preparekey);
+
+int aes_ccm_init(struct aes_ccm_ctx *ctx, u64 data_len, u64 ad_len,
+ const u8 *nonce, size_t nonce_len,
+ const struct aes_ccm_key *key)
+{
+ /*
+ * This is the value L defined in the CCM specification. It determines
+ * the maximum allowed message length, and it is itself determined by
+ * the nonce length. They are inversely related, i.e. the longer the
+ * nonce the smaller the maximum message length is.
+ */
+ unsigned int l = 15 - nonce_len;
+
+ if (unlikely(nonce_len < 7 || nonce_len > 13))
+ return -EINVAL;
+ /* Thus 2 <= l <= 8. */
+
+ /* Check whether data_len can be represented in 'l' bytes. */
+ if (unlikely(data_len > U64_MAX >> (64 - 8 * l)))
+ return -EOVERFLOW;
+
+ ctx->key = key;
+ ctx->ad_remaining = ad_len;
+ ctx->data_remaining = data_len;
+ ctx->ad_padded = false;
+
+ /*
+ * Initialize the zero-th counter block to:
+ *
+ * L - 1 || nonce || 0
+ *
+ * ... and the zero-th CBC-MAC block to:
+ *
+ * Flags || nonce || data_len
+ */
+ *(__be64 *)&ctx->ctr[8] = 0;
+ *(__be64 *)&ctx->mac[8] = cpu_to_be64(data_len);
+ ctx->ctr[0] = l - 1;
+ ctx->mac[0] = (ad_len ? 0x40 : 0) |
+ (((key->authtag_len - 2) / 2) << 3) | (l - 1);
+ memcpy(&ctx->ctr[1], nonce, nonce_len); /* Overlapping store */
+ memcpy(&ctx->mac[1], nonce, nonce_len); /* Overlapping store */
+
+ /*
+ * Generate S_0 by encrypting the counter (this is used to encrypt the
+ * auth tag later), and encrypt the zero-th CBC-MAC block.
+ */
+ aes_encrypt(&key->aes, ctx->s0, ctx->ctr);
+ aes_encrypt(&key->aes, ctx->mac, ctx->mac);
+
+ /* Increment the counter from 0 to 1. */
+ ctx->ctr[15] = 1;
+
+ if (ad_len) {
+ /*
+ * Update CBC-MAC with the associated data length, represented
+ * using either 2, 6, or 10 bytes depending on the length.
+ */
+ if (likely(ad_len < 0xff00)) {
+ *(__be16 *)&ctx->mac[0] ^= cpu_to_be16(ad_len);
+ ctx->partial_len = 2;
+ } else if (ad_len <= U32_MAX) {
+ __be32 *p = (__be32 *)&ctx->mac[2];
+
+ *(__be16 *)&ctx->mac[0] ^= cpu_to_be16(0xfffe);
+ put_unaligned(get_unaligned(p) ^ cpu_to_be32(ad_len),
+ p);
+ ctx->partial_len = 6;
+ } else {
+ __be64 *p = (__be64 *)&ctx->mac[2];
+
+ *(__be16 *)&ctx->mac[0] ^= cpu_to_be16(0xffff);
+ put_unaligned(get_unaligned(p) ^ cpu_to_be64(ad_len),
+ p);
+ ctx->partial_len = 10;
+ }
+ } else {
+ ctx->partial_len = 0;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(aes_ccm_init);
+
+void aes_ccm_auth_update(struct aes_ccm_ctx *ctx, const u8 *ad, size_t len)
+{
+ size_t partial_len = ctx->partial_len;
+ bool enc_before = false;
+ size_t nblocks;
+
+ WARN_ON_ONCE(ctx->ad_padded);
+
+ /*
+ * We could warn on len > ad_remaining here, but underflow will be
+ * caught by the != 0 check at the end anyway. (It's a u64, so it isn't
+ * going to underflow all the way back to 0.)
+ */
+ ctx->ad_remaining -= len;
+
+ if (partial_len) {
+ size_t n = min(len, AES_BLOCK_SIZE - partial_len);
+
+ crypto_xor(&ctx->mac[partial_len], ad, n);
+ ad += n;
+ len -= n;
+ partial_len += n;
+ if (partial_len < AES_BLOCK_SIZE) {
+ ctx->partial_len = partial_len;
+ return;
+ }
+ enc_before = true;
+ }
+
+ nblocks = len / AES_BLOCK_SIZE;
+ len %= AES_BLOCK_SIZE;
+ if (nblocks == 0) {
+ if (enc_before)
+ aes_encrypt(&ctx->key->aes, ctx->mac, ctx->mac);
+ } else {
+ aes_cbcmac_blocks(ctx->mac, &ctx->key->aes, ad, nblocks,
+ enc_before, /* enc_after= */ true);
+ ad += nblocks * AES_BLOCK_SIZE;
+ }
+ crypto_xor(ctx->mac, ad, len);
+ ctx->partial_len = len;
+}
+EXPORT_SYMBOL_GPL(aes_ccm_auth_update);
+
+static __always_inline void aes_ccm_crypt_update(struct aes_ccm_ctx *ctx,
+ u8 *dst, const u8 *src,
+ size_t len, bool enc)
+{
+ size_t partial_len = ctx->partial_len;
+ size_t n, nblocks;
+
+ if (unlikely(len == 0))
+ return;
+
+ WARN_ON_ONCE(ctx->ad_remaining != 0);
+
+ /*
+ * We could warn on len > data_remaining here, but underflow will be
+ * caught by the != 0 check at the end anyway. (It's a u64, so it isn't
+ * going to underflow all the way back to 0.)
+ */
+ ctx->data_remaining -= len;
+
+ if (!ctx->ad_padded) {
+ ctx->ad_padded = true;
+ if (partial_len)
+ aes_encrypt(&ctx->key->aes, ctx->mac, ctx->mac);
+ } else if (partial_len) {
+ /*
+ * The previous call ended on a non-block-aligned data_len, so
+ * continue using a previously-generated keystream block.
+ */
+ n = min(len, AES_BLOCK_SIZE - partial_len);
+ if (enc)
+ crypto_xor(&ctx->mac[partial_len], src, n);
+ crypto_xor_cpy(dst, src, &ctx->keystream[partial_len], n);
+ if (!enc)
+ crypto_xor(&ctx->mac[partial_len], dst, n);
+ dst += n;
+ src += n;
+ len -= n;
+ partial_len += n;
+ if (partial_len < AES_BLOCK_SIZE) {
+ ctx->partial_len = partial_len;
+ return;
+ }
+ aes_encrypt(&ctx->key->aes, ctx->mac, ctx->mac);
+ }
+
+ if (len >= AES_BLOCK_SIZE) {
+ n = round_down(len, AES_BLOCK_SIZE);
+ nblocks = len / AES_BLOCK_SIZE;
+ if (enc)
+ aes_cbcmac_blocks(ctx->mac, &ctx->key->aes, src,
+ nblocks, /* enc_before= */ false,
+ /* enc_after= */ true);
+ aes_ctr(dst, src, n, ctx->ctr, &ctx->key->aes);
+ if (!enc)
+ aes_cbcmac_blocks(ctx->mac, &ctx->key->aes, dst,
+ nblocks, /* enc_before= */ false,
+ /* enc_after= */ true);
+ dst += n;
+ src += n;
+ len -= n;
+ }
+
+ if (len) {
+ /*
+ * Ending on a non-block aligned data_len. Generate the next
+ * keystream block, use the needed portion of it, and leave it
+ * cached in ctx->keystream in case this isn't the final call.
+ */
+ aes_encrypt(&ctx->key->aes, ctx->keystream, ctx->ctr);
+ inc_be128_ctr(ctx->ctr);
+ if (enc)
+ crypto_xor(ctx->mac, src, len);
+ crypto_xor_cpy(dst, src, ctx->keystream, len);
+ if (!enc)
+ crypto_xor(ctx->mac, dst, len);
+ }
+ ctx->partial_len = len;
+}
+
+void aes_ccm_encrypt_update(struct aes_ccm_ctx *ctx, u8 *dst, const u8 *src,
+ size_t len)
+{
+ aes_ccm_crypt_update(ctx, dst, src, len, /* enc= */ true);
+}
+EXPORT_SYMBOL_GPL(aes_ccm_encrypt_update);
+
+void aes_ccm_decrypt_update(struct aes_ccm_ctx *ctx, u8 *dst, const u8 *src,
+ size_t len)
+{
+ aes_ccm_crypt_update(ctx, dst, src, len, /* enc= */ false);
+}
+EXPORT_SYMBOL_GPL(aes_ccm_decrypt_update);
+
+void aes_ccm_encrypt_final(struct aes_ccm_ctx *ctx, u8 *authtag)
+{
+ WARN_ON_ONCE(ctx->ad_remaining != 0);
+ WARN_ON_ONCE(ctx->data_remaining != 0);
+ if (ctx->partial_len)
+ aes_encrypt(&ctx->key->aes, ctx->mac, ctx->mac);
+ crypto_xor_cpy(authtag, ctx->mac, ctx->s0, ctx->key->authtag_len);
+ memzero_explicit(ctx, sizeof(*ctx));
+}
+EXPORT_SYMBOL_GPL(aes_ccm_encrypt_final);
+
+int aes_ccm_decrypt_final(struct aes_ccm_ctx *ctx, const u8 *authtag)
+{
+ int err;
+
+ if (WARN_ON_ONCE(ctx->ad_remaining != 0) ||
+ WARN_ON_ONCE(ctx->data_remaining != 0)) {
+ err = -EBADMSG;
+ goto out;
+ }
+
+ if (ctx->partial_len)
+ aes_encrypt(&ctx->key->aes, ctx->mac, ctx->mac);
+ crypto_xor(ctx->mac, ctx->s0, ctx->key->authtag_len);
+ err = crypto_memneq(ctx->mac, authtag, ctx->key->authtag_len) ?
+ -EBADMSG :
+ 0;
+out:
+ memzero_explicit(ctx, sizeof(*ctx));
+ return err;
+}
+EXPORT_SYMBOL_GPL(aes_ccm_decrypt_final);
+
+int aes_ccm_encrypt(u8 *dst, const u8 *src, size_t data_len, u8 *authtag,
+ const u8 *ad, size_t ad_len, const u8 *nonce,
+ size_t nonce_len, const struct aes_ccm_key *key)
+{
+ struct aes_ccm_ctx ctx;
+ int err;
+
+ err = aes_ccm_init(&ctx, data_len, ad_len, nonce, nonce_len, key);
+ if (unlikely(err))
+ return err;
+ aes_ccm_auth_update(&ctx, ad, ad_len);
+ aes_ccm_encrypt_update(&ctx, dst, src, data_len);
+ aes_ccm_encrypt_final(&ctx, authtag);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(aes_ccm_encrypt);
+
+int aes_ccm_decrypt(u8 *dst, const u8 *src, size_t data_len, const u8 *authtag,
+ const u8 *ad, size_t ad_len, const u8 *nonce,
+ size_t nonce_len, const struct aes_ccm_key *key)
+{
+ struct aes_ccm_ctx ctx;
+ int err;
+
+ err = aes_ccm_init(&ctx, data_len, ad_len, nonce, nonce_len, key);
+ if (unlikely(err))
+ return err;
+ aes_ccm_auth_update(&ctx, ad, ad_len);
+ aes_ccm_decrypt_update(&ctx, dst, src, data_len);
+ err = aes_ccm_decrypt_final(&ctx, authtag);
+ if (unlikely(err) && data_len) {
+ /*
+ * Clear the inauthentic decrypted data so that callers won't
+ * receive it even if they fail to correctly handle errors.
+ */
+ memset(dst, 0, data_len);
+ }
+ return err;
+}
+EXPORT_SYMBOL_GPL(aes_ccm_decrypt);
+
+/* FIPS cryptographic algorithm self-test for AES-CCM */
+static void __init aes_ccm_fips_test(void)
+{
+ const size_t data_len = sizeof(fips_test_data);
+ const size_t nonce_len = 13;
+ u8 buf[sizeof(fips_test_data) + AES_BLOCK_SIZE];
+ struct aes_ccm_key key;
+ int err;
+
+ if (aes_ccm_preparekey(&key, fips_test_key, sizeof(fips_test_key),
+ AES_BLOCK_SIZE) != 0)
+ panic("aes: CCM FIPS self-test failed (preparekey)\n");
+
+ err = aes_ccm_encrypt(buf, fips_test_data, data_len, &buf[data_len],
+ fips_test_ad, sizeof(fips_test_ad), fips_test_iv,
+ nonce_len, &key);
+ if (err != 0)
+ panic("aes: CCM FIPS self-test failed (encryption failed)\n");
+ if (memcmp(fips_test_aes_ccm_ctext_and_tag, buf, sizeof(buf)) != 0)
+ panic("aes: CCM FIPS self-test failed (wrong ciphertext and/or tag)\n");
+
+ err = aes_ccm_decrypt(buf, buf, data_len, &buf[data_len], fips_test_ad,
+ sizeof(fips_test_ad), fips_test_iv, nonce_len,
+ &key);
+ if (err != 0)
+ panic("aes: CCM FIPS self-test failed (decryption failed)\n");
+ if (memcmp(fips_test_data, buf, data_len) != 0)
+ panic("aes: CCM FIPS self-test failed (wrong plaintext)\n");
+
+ memzero_explicit(&key, sizeof(key));
+}
+#else /* CONFIG_CRYPTO_LIB_AES_CCM */
+static inline void aes_ccm_fips_test(void)
+{
+}
+#endif /* !CONFIG_CRYPTO_LIB_AES_CCM */
+
static int __init aes_mod_init(void)
{
#ifdef aes_mod_init_arch
aes_mod_init_arch();
#endif
- if (fips_enabled)
+ if (fips_enabled) {
+ aes_fips_test();
aes_cmac_fips_test();
+ aes_ecb_fips_test();
+ aes_cbc_fips_test();
+ aes_cbc_cts_fips_test();
+ aes_ctr_fips_test();
+ aes_xts_fips_test();
+ aes_gcm_fips_test();
+ aes_ccm_fips_test();
+ }
return 0;
}
subsys_initcall(aes_mod_init);
diff --git a/lib/crypto/aesgcm.c b/lib/crypto/aesgcm.c
deleted file mode 100644
index 1da31e1f747d..000000000000
--- a/lib/crypto/aesgcm.c
+++ /dev/null
@@ -1,721 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Minimal library implementation of GCM
- *
- * Copyright 2022 Google LLC
- */
-
-#include <crypto/gcm.h>
-#include <crypto/utils.h>
-#include <linux/export.h>
-#include <linux/module.h>
-
-/**
- * aesgcm_expandkey - Expands the AES and GHASH keys for the AES-GCM key
- * schedule
- *
- * @ctx: The data structure that will hold the AES-GCM key schedule
- * @key: The AES encryption input key
- * @keysize: The length in bytes of the input key
- * @authsize: The size in bytes of the GCM authentication tag
- *
- * Returns: 0 on success, or -EINVAL if @keysize or @authsize contain values
- * that are not permitted by the GCM specification.
- */
-int aesgcm_expandkey(struct aesgcm_ctx *ctx, const u8 *key,
- unsigned int keysize, unsigned int authsize)
-{
- u8 h[AES_BLOCK_SIZE] = {};
- int ret;
-
- ret = crypto_gcm_check_authsize(authsize) ?:
- aes_prepareenckey(&ctx->aes_key, key, keysize);
- if (ret)
- return ret;
-
- ctx->authsize = authsize;
- aes_encrypt(&ctx->aes_key, h, h);
- ghash_preparekey(&ctx->ghash_key, h);
- memzero_explicit(h, sizeof(h));
- return 0;
-}
-EXPORT_SYMBOL(aesgcm_expandkey);
-
-/**
- * aesgcm_mac - Generates the authentication tag using AES-GCM algorithm.
- * @ctx: The data structure that will hold the AES-GCM key schedule
- * @src: The input source data.
- * @src_len: Length of the source data.
- * @assoc: Points to the associated data.
- * @assoc_len: Length of the associated data values.
- * @ctr: Points to the counter value.
- * @authtag: The output buffer for the authentication tag.
- *
- * It takes in the AES-GCM context, source data, associated data, counter value,
- * and an output buffer for the authentication tag.
- */
-static void aesgcm_mac(const struct aesgcm_ctx *ctx, const u8 *src, int src_len,
- const u8 *assoc, int assoc_len, __be32 *ctr, u8 *authtag)
-{
- static const u8 zeroes[GHASH_BLOCK_SIZE];
- __be64 tail[2] = {
- cpu_to_be64((u64)assoc_len * 8),
- cpu_to_be64((u64)src_len * 8),
- };
- struct ghash_ctx ghash;
- u8 ghash_out[AES_BLOCK_SIZE];
- u8 enc_ctr[AES_BLOCK_SIZE];
-
- ghash_init(&ghash, &ctx->ghash_key);
-
- ghash_update(&ghash, assoc, assoc_len);
- ghash_update(&ghash, zeroes, -assoc_len & (GHASH_BLOCK_SIZE - 1));
-
- ghash_update(&ghash, src, src_len);
- ghash_update(&ghash, zeroes, -src_len & (GHASH_BLOCK_SIZE - 1));
-
- ghash_update(&ghash, (const u8 *)&tail, sizeof(tail));
-
- ghash_final(&ghash, ghash_out);
-
- ctr[3] = cpu_to_be32(1);
- aes_encrypt(&ctx->aes_key, enc_ctr, (const u8 *)ctr);
- crypto_xor_cpy(authtag, ghash_out, enc_ctr, ctx->authsize);
-
- memzero_explicit(ghash_out, sizeof(ghash_out));
- memzero_explicit(enc_ctr, sizeof(enc_ctr));
-}
-
-static void aesgcm_crypt(const struct aesgcm_ctx *ctx, u8 *dst, const u8 *src,
- int len, __be32 *ctr)
-{
- u8 buf[AES_BLOCK_SIZE];
- unsigned int n = 2;
-
- while (len > 0) {
- /*
- * The counter increment below must not result in overflow or
- * carry into the next 32-bit word, as this could result in
- * inadvertent IV reuse, which must be avoided at all cost for
- * stream ciphers such as AES-CTR. Given the range of 'int
- * len', this cannot happen, so no explicit test is necessary.
- */
- ctr[3] = cpu_to_be32(n++);
- aes_encrypt(&ctx->aes_key, buf, (const u8 *)ctr);
- crypto_xor_cpy(dst, src, buf, min(len, AES_BLOCK_SIZE));
-
- dst += AES_BLOCK_SIZE;
- src += AES_BLOCK_SIZE;
- len -= AES_BLOCK_SIZE;
- }
- memzero_explicit(buf, sizeof(buf));
-}
-
-/**
- * aesgcm_encrypt - Perform AES-GCM encryption on a block of data
- *
- * @ctx: The AES-GCM key schedule
- * @dst: Pointer to the ciphertext output buffer
- * @src: Pointer the plaintext (may equal @dst for encryption in place)
- * @crypt_len: The size in bytes of the plaintext and ciphertext.
- * @assoc: Pointer to the associated data,
- * @assoc_len: The size in bytes of the associated data
- * @iv: The initialization vector (IV) to use for this block of data
- * (must be 12 bytes in size as per the GCM spec recommendation)
- * @authtag: The address of the buffer in memory where the authentication
- * tag should be stored. The buffer is assumed to have space for
- * @ctx->authsize bytes.
- */
-void aesgcm_encrypt(const struct aesgcm_ctx *ctx, u8 *dst, const u8 *src,
- int crypt_len, const u8 *assoc, int assoc_len,
- const u8 iv[GCM_AES_IV_SIZE], u8 *authtag)
-{
- __be32 ctr[4];
-
- memcpy(ctr, iv, GCM_AES_IV_SIZE);
-
- aesgcm_crypt(ctx, dst, src, crypt_len, ctr);
- aesgcm_mac(ctx, dst, crypt_len, assoc, assoc_len, ctr, authtag);
-}
-EXPORT_SYMBOL(aesgcm_encrypt);
-
-/**
- * aesgcm_decrypt - Perform AES-GCM decryption on a block of data
- *
- * @ctx: The AES-GCM key schedule
- * @dst: Pointer to the plaintext output buffer
- * @src: Pointer the ciphertext (may equal @dst for decryption in place)
- * @crypt_len: The size in bytes of the plaintext and ciphertext.
- * @assoc: Pointer to the associated data,
- * @assoc_len: The size in bytes of the associated data
- * @iv: The initialization vector (IV) to use for this block of data
- * (must be 12 bytes in size as per the GCM spec recommendation)
- * @authtag: The address of the buffer in memory where the authentication
- * tag is stored.
- *
- * Returns: true on success, or false if the ciphertext failed authentication.
- * On failure, no plaintext will be returned.
- */
-bool __must_check aesgcm_decrypt(const struct aesgcm_ctx *ctx, u8 *dst,
- const u8 *src, int crypt_len, const u8 *assoc,
- int assoc_len, const u8 iv[GCM_AES_IV_SIZE],
- const u8 *authtag)
-{
- u8 tagbuf[AES_BLOCK_SIZE];
- __be32 ctr[4];
-
- memcpy(ctr, iv, GCM_AES_IV_SIZE);
-
- aesgcm_mac(ctx, src, crypt_len, assoc, assoc_len, ctr, tagbuf);
- if (crypto_memneq(authtag, tagbuf, ctx->authsize)) {
- memzero_explicit(tagbuf, sizeof(tagbuf));
- return false;
- }
- aesgcm_crypt(ctx, dst, src, crypt_len, ctr);
- return true;
-}
-EXPORT_SYMBOL(aesgcm_decrypt);
-
-MODULE_DESCRIPTION("Generic AES-GCM library");
-MODULE_AUTHOR("Ard Biesheuvel <ardb@kernel.org>");
-MODULE_LICENSE("GPL");
-
-#ifdef CONFIG_CRYPTO_SELFTESTS
-
-/*
- * Test code below. Vectors taken from crypto/testmgr.h
- */
-
-static const u8 __initconst ctext0[16] __nonstring =
- "\x58\xe2\xfc\xce\xfa\x7e\x30\x61"
- "\x36\x7f\x1d\x57\xa4\xe7\x45\x5a";
-
-static const u8 __initconst ptext1[16];
-
-static const u8 __initconst ctext1[32] __nonstring =
- "\x03\x88\xda\xce\x60\xb6\xa3\x92"
- "\xf3\x28\xc2\xb9\x71\xb2\xfe\x78"
- "\xab\x6e\x47\xd4\x2c\xec\x13\xbd"
- "\xf5\x3a\x67\xb2\x12\x57\xbd\xdf";
-
-static const u8 __initconst ptext2[64] __nonstring =
- "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
- "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
- "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
- "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
- "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
- "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
- "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
- "\xba\x63\x7b\x39\x1a\xaf\xd2\x55";
-
-static const u8 __initconst ctext2[80] __nonstring =
- "\x42\x83\x1e\xc2\x21\x77\x74\x24"
- "\x4b\x72\x21\xb7\x84\xd0\xd4\x9c"
- "\xe3\xaa\x21\x2f\x2c\x02\xa4\xe0"
- "\x35\xc1\x7e\x23\x29\xac\xa1\x2e"
- "\x21\xd5\x14\xb2\x54\x66\x93\x1c"
- "\x7d\x8f\x6a\x5a\xac\x84\xaa\x05"
- "\x1b\xa3\x0b\x39\x6a\x0a\xac\x97"
- "\x3d\x58\xe0\x91\x47\x3f\x59\x85"
- "\x4d\x5c\x2a\xf3\x27\xcd\x64\xa6"
- "\x2c\xf3\x5a\xbd\x2b\xa6\xfa\xb4";
-
-static const u8 __initconst ptext3[60] __nonstring =
- "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
- "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
- "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
- "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
- "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
- "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
- "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
- "\xba\x63\x7b\x39";
-
-static const u8 __initconst ctext3[76] __nonstring =
- "\x42\x83\x1e\xc2\x21\x77\x74\x24"
- "\x4b\x72\x21\xb7\x84\xd0\xd4\x9c"
- "\xe3\xaa\x21\x2f\x2c\x02\xa4\xe0"
- "\x35\xc1\x7e\x23\x29\xac\xa1\x2e"
- "\x21\xd5\x14\xb2\x54\x66\x93\x1c"
- "\x7d\x8f\x6a\x5a\xac\x84\xaa\x05"
- "\x1b\xa3\x0b\x39\x6a\x0a\xac\x97"
- "\x3d\x58\xe0\x91"
- "\x5b\xc9\x4f\xbc\x32\x21\xa5\xdb"
- "\x94\xfa\xe9\x5a\xe7\x12\x1a\x47";
-
-static const u8 __initconst ctext4[16] __nonstring =
- "\xcd\x33\xb2\x8a\xc7\x73\xf7\x4b"
- "\xa0\x0e\xd1\xf3\x12\x57\x24\x35";
-
-static const u8 __initconst ctext5[32] __nonstring =
- "\x98\xe7\x24\x7c\x07\xf0\xfe\x41"
- "\x1c\x26\x7e\x43\x84\xb0\xf6\x00"
- "\x2f\xf5\x8d\x80\x03\x39\x27\xab"
- "\x8e\xf4\xd4\x58\x75\x14\xf0\xfb";
-
-static const u8 __initconst ptext6[64] __nonstring =
- "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
- "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
- "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
- "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
- "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
- "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
- "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
- "\xba\x63\x7b\x39\x1a\xaf\xd2\x55";
-
-static const u8 __initconst ctext6[80] __nonstring =
- "\x39\x80\xca\x0b\x3c\x00\xe8\x41"
- "\xeb\x06\xfa\xc4\x87\x2a\x27\x57"
- "\x85\x9e\x1c\xea\xa6\xef\xd9\x84"
- "\x62\x85\x93\xb4\x0c\xa1\xe1\x9c"
- "\x7d\x77\x3d\x00\xc1\x44\xc5\x25"
- "\xac\x61\x9d\x18\xc8\x4a\x3f\x47"
- "\x18\xe2\x44\x8b\x2f\xe3\x24\xd9"
- "\xcc\xda\x27\x10\xac\xad\xe2\x56"
- "\x99\x24\xa7\xc8\x58\x73\x36\xbf"
- "\xb1\x18\x02\x4d\xb8\x67\x4a\x14";
-
-static const u8 __initconst ctext7[16] __nonstring =
- "\x53\x0f\x8a\xfb\xc7\x45\x36\xb9"
- "\xa9\x63\xb4\xf1\xc4\xcb\x73\x8b";
-
-static const u8 __initconst ctext8[32] __nonstring =
- "\xce\xa7\x40\x3d\x4d\x60\x6b\x6e"
- "\x07\x4e\xc5\xd3\xba\xf3\x9d\x18"
- "\xd0\xd1\xc8\xa7\x99\x99\x6b\xf0"
- "\x26\x5b\x98\xb5\xd4\x8a\xb9\x19";
-
-static const u8 __initconst ptext9[64] __nonstring =
- "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
- "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
- "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
- "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
- "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
- "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
- "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
- "\xba\x63\x7b\x39\x1a\xaf\xd2\x55";
-
-static const u8 __initconst ctext9[80] __nonstring =
- "\x52\x2d\xc1\xf0\x99\x56\x7d\x07"
- "\xf4\x7f\x37\xa3\x2a\x84\x42\x7d"
- "\x64\x3a\x8c\xdc\xbf\xe5\xc0\xc9"
- "\x75\x98\xa2\xbd\x25\x55\xd1\xaa"
- "\x8c\xb0\x8e\x48\x59\x0d\xbb\x3d"
- "\xa7\xb0\x8b\x10\x56\x82\x88\x38"
- "\xc5\xf6\x1e\x63\x93\xba\x7a\x0a"
- "\xbc\xc9\xf6\x62\x89\x80\x15\xad"
- "\xb0\x94\xda\xc5\xd9\x34\x71\xbd"
- "\xec\x1a\x50\x22\x70\xe3\xcc\x6c";
-
-static const u8 __initconst ptext10[60] __nonstring =
- "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
- "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
- "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
- "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
- "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
- "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
- "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
- "\xba\x63\x7b\x39";
-
-static const u8 __initconst ctext10[76] __nonstring =
- "\x52\x2d\xc1\xf0\x99\x56\x7d\x07"
- "\xf4\x7f\x37\xa3\x2a\x84\x42\x7d"
- "\x64\x3a\x8c\xdc\xbf\xe5\xc0\xc9"
- "\x75\x98\xa2\xbd\x25\x55\xd1\xaa"
- "\x8c\xb0\x8e\x48\x59\x0d\xbb\x3d"
- "\xa7\xb0\x8b\x10\x56\x82\x88\x38"
- "\xc5\xf6\x1e\x63\x93\xba\x7a\x0a"
- "\xbc\xc9\xf6\x62"
- "\x76\xfc\x6e\xce\x0f\x4e\x17\x68"
- "\xcd\xdf\x88\x53\xbb\x2d\x55\x1b";
-
-static const u8 __initconst ptext11[60] __nonstring =
- "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
- "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
- "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
- "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
- "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
- "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
- "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
- "\xba\x63\x7b\x39";
-
-static const u8 __initconst ctext11[76] __nonstring =
- "\x39\x80\xca\x0b\x3c\x00\xe8\x41"
- "\xeb\x06\xfa\xc4\x87\x2a\x27\x57"
- "\x85\x9e\x1c\xea\xa6\xef\xd9\x84"
- "\x62\x85\x93\xb4\x0c\xa1\xe1\x9c"
- "\x7d\x77\x3d\x00\xc1\x44\xc5\x25"
- "\xac\x61\x9d\x18\xc8\x4a\x3f\x47"
- "\x18\xe2\x44\x8b\x2f\xe3\x24\xd9"
- "\xcc\xda\x27\x10"
- "\x25\x19\x49\x8e\x80\xf1\x47\x8f"
- "\x37\xba\x55\xbd\x6d\x27\x61\x8c";
-
-static const u8 __initconst ptext12[719] __nonstring =
- "\x42\xc1\xcc\x08\x48\x6f\x41\x3f"
- "\x2f\x11\x66\x8b\x2a\x16\xf0\xe0"
- "\x58\x83\xf0\xc3\x70\x14\xc0\x5b"
- "\x3f\xec\x1d\x25\x3c\x51\xd2\x03"
- "\xcf\x59\x74\x1f\xb2\x85\xb4\x07"
- "\xc6\x6a\x63\x39\x8a\x5b\xde\xcb"
- "\xaf\x08\x44\xbd\x6f\x91\x15\xe1"
- "\xf5\x7a\x6e\x18\xbd\xdd\x61\x50"
- "\x59\xa9\x97\xab\xbb\x0e\x74\x5c"
- "\x00\xa4\x43\x54\x04\x54\x9b\x3b"
- "\x77\xec\xfd\x5c\xa6\xe8\x7b\x08"
- "\xae\xe6\x10\x3f\x32\x65\xd1\xfc"
- "\xa4\x1d\x2c\x31\xfb\x33\x7a\xb3"
- "\x35\x23\xf4\x20\x41\xd4\xad\x82"
- "\x8b\xa4\xad\x96\x1c\x20\x53\xbe"
- "\x0e\xa6\xf4\xdc\x78\x49\x3e\x72"
- "\xb1\xa9\xb5\x83\xcb\x08\x54\xb7"
- "\xad\x49\x3a\xae\x98\xce\xa6\x66"
- "\x10\x30\x90\x8c\x55\x83\xd7\x7c"
- "\x8b\xe6\x53\xde\xd2\x6e\x18\x21"
- "\x01\x52\xd1\x9f\x9d\xbb\x9c\x73"
- "\x57\xcc\x89\x09\x75\x9b\x78\x70"
- "\xed\x26\x97\x4d\xb4\xe4\x0c\xa5"
- "\xfa\x70\x04\x70\xc6\x96\x1c\x7d"
- "\x54\x41\x77\xa8\xe3\xb0\x7e\x96"
- "\x82\xd9\xec\xa2\x87\x68\x55\xf9"
- "\x8f\x9e\x73\x43\x47\x6a\x08\x36"
- "\x93\x67\xa8\x2d\xde\xac\x41\xa9"
- "\x5c\x4d\x73\x97\x0f\x70\x68\xfa"
- "\x56\x4d\x00\xc2\x3b\x1f\xc8\xb9"
- "\x78\x1f\x51\x07\xe3\x9a\x13\x4e"
- "\xed\x2b\x2e\xa3\xf7\x44\xb2\xe7"
- "\xab\x19\x37\xd9\xba\x76\x5e\xd2"
- "\xf2\x53\x15\x17\x4c\x6b\x16\x9f"
- "\x02\x66\x49\xca\x7c\x91\x05\xf2"
- "\x45\x36\x1e\xf5\x77\xad\x1f\x46"
- "\xa8\x13\xfb\x63\xb6\x08\x99\x63"
- "\x82\xa2\xed\xb3\xac\xdf\x43\x19"
- "\x45\xea\x78\x73\xd9\xb7\x39\x11"
- "\xa3\x13\x7c\xf8\x3f\xf7\xad\x81"
- "\x48\x2f\xa9\x5c\x5f\xa0\xf0\x79"
- "\xa4\x47\x7d\x80\x20\x26\xfd\x63"
- "\x0a\xc7\x7e\x6d\x75\x47\xff\x76"
- "\x66\x2e\x8a\x6c\x81\x35\xaf\x0b"
- "\x2e\x6a\x49\x60\xc1\x10\xe1\xe1"
- "\x54\x03\xa4\x09\x0c\x37\x7a\x15"
- "\x23\x27\x5b\x8b\x4b\xa5\x64\x97"
- "\xae\x4a\x50\x73\x1f\x66\x1c\x5c"
- "\x03\x25\x3c\x8d\x48\x58\x71\x34"
- "\x0e\xec\x4e\x55\x1a\x03\x6a\xe5"
- "\xb6\x19\x2b\x84\x2a\x20\xd1\xea"
- "\x80\x6f\x96\x0e\x05\x62\xc7\x78"
- "\x87\x79\x60\x38\x46\xb4\x25\x57"
- "\x6e\x16\x63\xf8\xad\x6e\xd7\x42"
- "\x69\xe1\x88\xef\x6e\xd5\xb4\x9a"
- "\x3c\x78\x6c\x3b\xe5\xa0\x1d\x22"
- "\x86\x5c\x74\x3a\xeb\x24\x26\xc7"
- "\x09\xfc\x91\x96\x47\x87\x4f\x1a"
- "\xd6\x6b\x2c\x18\x47\xc0\xb8\x24"
- "\xa8\x5a\x4a\x9e\xcb\x03\xe7\x2a"
- "\x09\xe6\x4d\x9c\x6d\x86\x60\xf5"
- "\x2f\x48\x69\x37\x9f\xf2\xd2\xcb"
- "\x0e\x5a\xdd\x6e\x8a\xfb\x6a\xfe"
- "\x0b\x63\xde\x87\x42\x79\x8a\x68"
- "\x51\x28\x9b\x7a\xeb\xaf\xb8\x2f"
- "\x9d\xd1\xc7\x45\x90\x08\xc9\x83"
- "\xe9\x83\x84\xcb\x28\x69\x09\x69"
- "\xce\x99\x46\x00\x54\xcb\xd8\x38"
- "\xf9\x53\x4a\xbf\x31\xce\x57\x15"
- "\x33\xfa\x96\x04\x33\x42\xe3\xc0"
- "\xb7\x54\x4a\x65\x7a\x7c\x02\xe6"
- "\x19\x95\xd0\x0e\x82\x07\x63\xf9"
- "\xe1\x2b\x2a\xfc\x55\x92\x52\xc9"
- "\xb5\x9f\x23\x28\x60\xe7\x20\x51"
- "\x10\xd3\xed\x6d\x9b\xab\xb8\xe2"
- "\x5d\x9a\x34\xb3\xbe\x9c\x64\xcb"
- "\x78\xc6\x91\x22\x40\x91\x80\xbe"
- "\xd7\x78\x5c\x0e\x0a\xdc\x08\xe9"
- "\x67\x10\xa4\x83\x98\x79\x23\xe7"
- "\x92\xda\xa9\x22\x16\xb1\xe7\x78"
- "\xa3\x1c\x6c\x8f\x35\x7c\x4d\x37"
- "\x2f\x6e\x0b\x50\x5c\x34\xb9\xf9"
- "\xe6\x3d\x91\x0d\x32\x95\xaa\x3d"
- "\x48\x11\x06\xbb\x2d\xf2\x63\x88"
- "\x3f\x73\x09\xe2\x45\x56\x31\x51"
- "\xfa\x5e\x4e\x62\xf7\x90\xf9\xa9"
- "\x7d\x7b\x1b\xb1\xc8\x26\x6e\x66"
- "\xf6\x90\x9a\x7f\xf2\x57\xcc\x23"
- "\x59\xfa\xfa\xaa\x44\x04\x01\xa7"
- "\xa4\x78\xdb\x74\x3d\x8b\xb5";
-
-static const u8 __initconst ctext12[735] __nonstring =
- "\x84\x0b\xdb\xd5\xb7\xa8\xfe\x20"
- "\xbb\xb1\x12\x7f\x41\xea\xb3\xc0"
- "\xa2\xb4\x37\x19\x11\x58\xb6\x0b"
- "\x4c\x1d\x38\x05\x54\xd1\x16\x73"
- "\x8e\x1c\x20\x90\xa2\x9a\xb7\x74"
- "\x47\xe6\xd8\xfc\x18\x3a\xb4\xea"
- "\xd5\x16\x5a\x2c\x53\x01\x46\xb3"
- "\x18\x33\x74\x6c\x50\xf2\xe8\xc0"
- "\x73\xda\x60\x22\xeb\xe3\xe5\x9b"
- "\x20\x93\x6c\x4b\x37\x99\xb8\x23"
- "\x3b\x4e\xac\xe8\x5b\xe8\x0f\xb7"
- "\xc3\x8f\xfb\x4a\x37\xd9\x39\x95"
- "\x34\xf1\xdb\x8f\x71\xd9\xc7\x0b"
- "\x02\xf1\x63\xfc\x9b\xfc\xc5\xab"
- "\xb9\x14\x13\x21\xdf\xce\xaa\x88"
- "\x44\x30\x1e\xce\x26\x01\x92\xf8"
- "\x9f\x00\x4b\x0c\x4b\xf7\x5f\xe0"
- "\x89\xca\x94\x66\x11\x21\x97\xca"
- "\x3e\x83\x74\x2d\xdb\x4d\x11\xeb"
- "\x97\xc2\x14\xff\x9e\x1e\xa0\x6b"
- "\x08\xb4\x31\x2b\x85\xc6\x85\x6c"
- "\x90\xec\x39\xc0\xec\xb3\xb5\x4e"
- "\xf3\x9c\xe7\x83\x3a\x77\x0a\xf4"
- "\x56\xfe\xce\x18\x33\x6d\x0b\x2d"
- "\x33\xda\xc8\x05\x5c\xb4\x09\x2a"
- "\xde\x6b\x52\x98\x01\xef\x36\x3d"
- "\xbd\xf9\x8f\xa8\x3e\xaa\xcd\xd1"
- "\x01\x2d\x42\x49\xc3\xb6\x84\xbb"
- "\x48\x96\xe0\x90\x93\x6c\x48\x64"
- "\xd4\xfa\x7f\x93\x2c\xa6\x21\xc8"
- "\x7a\x23\x7b\xaa\x20\x56\x12\xae"
- "\x16\x9d\x94\x0f\x54\xa1\xec\xca"
- "\x51\x4e\xf2\x39\xf4\xf8\x5f\x04"
- "\x5a\x0d\xbf\xf5\x83\xa1\x15\xe1"
- "\xf5\x3c\xd8\x62\xa3\xed\x47\x89"
- "\x85\x4c\xe5\xdb\xac\x9e\x17\x1d"
- "\x0c\x09\xe3\x3e\x39\x5b\x4d\x74"
- "\x0e\xf5\x34\xee\x70\x11\x4c\xfd"
- "\xdb\x34\xb1\xb5\x10\x3f\x73\xb7"
- "\xf5\xfa\xed\xb0\x1f\xa5\xcd\x3c"
- "\x8d\x35\x83\xd4\x11\x44\x6e\x6c"
- "\x5b\xe0\x0e\x69\xa5\x39\xe5\xbb"
- "\xa9\x57\x24\x37\xe6\x1f\xdd\xcf"
- "\x16\x2a\x13\xf9\x6a\x2d\x90\xa0"
- "\x03\x60\x7a\xed\x69\xd5\x00\x8b"
- "\x7e\x4f\xcb\xb9\xfa\x91\xb9\x37"
- "\xc1\x26\xce\x90\x97\x22\x64\x64"
- "\xc1\x72\x43\x1b\xf6\xac\xc1\x54"
- "\x8a\x10\x9c\xdd\x8d\xd5\x8e\xb2"
- "\xe4\x85\xda\xe0\x20\x5f\xf4\xb4"
- "\x15\xb5\xa0\x8d\x12\x74\x49\x23"
- "\x3a\xdf\x4a\xd3\xf0\x3b\x89\xeb"
- "\xf8\xcc\x62\x7b\xfb\x93\x07\x41"
- "\x61\x26\x94\x58\x70\xa6\x3c\xe4"
- "\xff\x58\xc4\x13\x3d\xcb\x36\x6b"
- "\x32\xe5\xb2\x6d\x03\x74\x6f\x76"
- "\x93\x77\xde\x48\xc4\xfa\x30\x4a"
- "\xda\x49\x80\x77\x0f\x1c\xbe\x11"
- "\xc8\x48\xb1\xe5\xbb\xf2\x8a\xe1"
- "\x96\x2f\x9f\xd1\x8e\x8a\x5c\xe2"
- "\xf7\xd7\xd8\x54\xf3\x3f\xc4\x91"
- "\xb8\xfb\x86\xdc\x46\x24\x91\x60"
- "\x6c\x2f\xc9\x41\x37\x51\x49\x54"
- "\x09\x81\x21\xf3\x03\x9f\x2b\xe3"
- "\x1f\x39\x63\xaf\xf4\xd7\x53\x60"
- "\xa7\xc7\x54\xf9\xee\xb1\xb1\x7d"
- "\x75\x54\x65\x93\xfe\xb1\x68\x6b"
- "\x57\x02\xf9\xbb\x0e\xf9\xf8\xbf"
- "\x01\x12\x27\xb4\xfe\xe4\x79\x7a"
- "\x40\x5b\x51\x4b\xdf\x38\xec\xb1"
- "\x6a\x56\xff\x35\x4d\x42\x33\xaa"
- "\x6f\x1b\xe4\xdc\xe0\xdb\x85\x35"
- "\x62\x10\xd4\xec\xeb\xc5\x7e\x45"
- "\x1c\x6f\x17\xca\x3b\x8e\x2d\x66"
- "\x4f\x4b\x36\x56\xcd\x1b\x59\xaa"
- "\xd2\x9b\x17\xb9\x58\xdf\x7b\x64"
- "\x8a\xff\x3b\x9c\xa6\xb5\x48\x9e"
- "\xaa\xe2\x5d\x09\x71\x32\x5f\xb6"
- "\x29\xbe\xe7\xc7\x52\x7e\x91\x82"
- "\x6b\x6d\x33\xe1\x34\x06\x36\x21"
- "\x5e\xbe\x1e\x2f\x3e\xc1\xfb\xea"
- "\x49\x2c\xb5\xca\xf7\xb0\x37\xea"
- "\x1f\xed\x10\x04\xd9\x48\x0d\x1a"
- "\x1c\xfb\xe7\x84\x0e\x83\x53\x74"
- "\xc7\x65\xe2\x5c\xe5\xba\x73\x4c"
- "\x0e\xe1\xb5\x11\x45\x61\x43\x46"
- "\xaa\x25\x8f\xbd\x85\x08\xfa\x4c"
- "\x15\xc1\xc0\xd8\xf5\xdc\x16\xbb"
- "\x7b\x1d\xe3\x87\x57\xa7\x2a\x1d"
- "\x38\x58\x9e\x8a\x43\xdc\x57"
- "\xd1\x81\x7d\x2b\xe9\xff\x99\x3a"
- "\x4b\x24\x52\x58\x55\xe1\x49\x14";
-
-static struct {
- const u8 *ptext;
- const u8 *ctext;
-
- u8 key[AES_MAX_KEY_SIZE] __nonstring;
- u8 iv[GCM_AES_IV_SIZE] __nonstring;
- u8 assoc[20] __nonstring;
-
- int klen;
- int clen;
- int plen;
- int alen;
-} const aesgcm_tv[] __initconst = {
- { /* From McGrew & Viega - http://citeseer.ist.psu.edu/656989.html */
- .klen = 16,
- .ctext = ctext0,
- .clen = sizeof(ctext0),
- }, {
- .klen = 16,
- .ptext = ptext1,
- .plen = sizeof(ptext1),
- .ctext = ctext1,
- .clen = sizeof(ctext1),
- }, {
- .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
- "\x6d\x6a\x8f\x94\x67\x30\x83\x08",
- .klen = 16,
- .iv = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
- "\xde\xca\xf8\x88",
- .ptext = ptext2,
- .plen = sizeof(ptext2),
- .ctext = ctext2,
- .clen = sizeof(ctext2),
- }, {
- .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
- "\x6d\x6a\x8f\x94\x67\x30\x83\x08",
- .klen = 16,
- .iv = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
- "\xde\xca\xf8\x88",
- .ptext = ptext3,
- .plen = sizeof(ptext3),
- .assoc = "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
- "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
- "\xab\xad\xda\xd2",
- .alen = 20,
- .ctext = ctext3,
- .clen = sizeof(ctext3),
- }, {
- .klen = 24,
- .ctext = ctext4,
- .clen = sizeof(ctext4),
- }, {
- .klen = 24,
- .ptext = ptext1,
- .plen = sizeof(ptext1),
- .ctext = ctext5,
- .clen = sizeof(ctext5),
- }, {
- .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
- "\x6d\x6a\x8f\x94\x67\x30\x83\x08"
- "\xfe\xff\xe9\x92\x86\x65\x73\x1c",
- .klen = 24,
- .iv = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
- "\xde\xca\xf8\x88",
- .ptext = ptext6,
- .plen = sizeof(ptext6),
- .ctext = ctext6,
- .clen = sizeof(ctext6),
- }, {
- .klen = 32,
- .ctext = ctext7,
- .clen = sizeof(ctext7),
- }, {
- .klen = 32,
- .ptext = ptext1,
- .plen = sizeof(ptext1),
- .ctext = ctext8,
- .clen = sizeof(ctext8),
- }, {
- .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
- "\x6d\x6a\x8f\x94\x67\x30\x83\x08"
- "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
- "\x6d\x6a\x8f\x94\x67\x30\x83\x08",
- .klen = 32,
- .iv = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
- "\xde\xca\xf8\x88",
- .ptext = ptext9,
- .plen = sizeof(ptext9),
- .ctext = ctext9,
- .clen = sizeof(ctext9),
- }, {
- .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
- "\x6d\x6a\x8f\x94\x67\x30\x83\x08"
- "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
- "\x6d\x6a\x8f\x94\x67\x30\x83\x08",
- .klen = 32,
- .iv = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
- "\xde\xca\xf8\x88",
- .ptext = ptext10,
- .plen = sizeof(ptext10),
- .assoc = "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
- "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
- "\xab\xad\xda\xd2",
- .alen = 20,
- .ctext = ctext10,
- .clen = sizeof(ctext10),
- }, {
- .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
- "\x6d\x6a\x8f\x94\x67\x30\x83\x08"
- "\xfe\xff\xe9\x92\x86\x65\x73\x1c",
- .klen = 24,
- .iv = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
- "\xde\xca\xf8\x88",
- .ptext = ptext11,
- .plen = sizeof(ptext11),
- .assoc = "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
- "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
- "\xab\xad\xda\xd2",
- .alen = 20,
- .ctext = ctext11,
- .clen = sizeof(ctext11),
- }, {
- .key = "\x62\x35\xf8\x95\xfc\xa5\xeb\xf6"
- "\x0e\x92\x12\x04\xd3\xa1\x3f\x2e"
- "\x8b\x32\xcf\xe7\x44\xed\x13\x59"
- "\x04\x38\x77\xb0\xb9\xad\xb4\x38",
- .klen = 32,
- .iv = "\x00\xff\xff\xff\xff\x00\x00\xff"
- "\xff\xff\x00\xff",
- .ptext = ptext12,
- .plen = sizeof(ptext12),
- .ctext = ctext12,
- .clen = sizeof(ctext12),
- }
-};
-
-static int __init libaesgcm_init(void)
-{
- for (int i = 0; i < ARRAY_SIZE(aesgcm_tv); i++) {
- u8 tagbuf[AES_BLOCK_SIZE];
- int plen = aesgcm_tv[i].plen;
- struct aesgcm_ctx ctx;
- static u8 buf[sizeof(ptext12)];
-
- if (aesgcm_expandkey(&ctx, aesgcm_tv[i].key, aesgcm_tv[i].klen,
- aesgcm_tv[i].clen - plen)) {
- pr_err("aesgcm_expandkey() failed on vector %d\n", i);
- return -ENODEV;
- }
-
- if (!aesgcm_decrypt(&ctx, buf, aesgcm_tv[i].ctext, plen,
- aesgcm_tv[i].assoc, aesgcm_tv[i].alen,
- aesgcm_tv[i].iv, aesgcm_tv[i].ctext + plen)
- || memcmp(buf, aesgcm_tv[i].ptext, plen)) {
- pr_err("aesgcm_decrypt() #1 failed on vector %d\n", i);
- return -ENODEV;
- }
-
- /* encrypt in place */
- aesgcm_encrypt(&ctx, buf, buf, plen, aesgcm_tv[i].assoc,
- aesgcm_tv[i].alen, aesgcm_tv[i].iv, tagbuf);
- if (memcmp(buf, aesgcm_tv[i].ctext, plen)) {
- pr_err("aesgcm_encrypt() failed on vector %d\n", i);
- return -ENODEV;
- }
-
- /* decrypt in place */
- if (!aesgcm_decrypt(&ctx, buf, buf, plen, aesgcm_tv[i].assoc,
- aesgcm_tv[i].alen, aesgcm_tv[i].iv, tagbuf)
- || memcmp(buf, aesgcm_tv[i].ptext, plen)) {
- pr_err("aesgcm_decrypt() #2 failed on vector %d\n", i);
- return -ENODEV;
- }
- }
- return 0;
-}
-module_init(libaesgcm_init);
-
-static void __exit libaesgcm_exit(void)
-{
-}
-module_exit(libaesgcm_exit);
-#endif
diff --git a/lib/crypto/fips-aes.h b/lib/crypto/fips-aes.h
new file mode 100644
index 000000000000..2a1746606533
--- /dev/null
+++ b/lib/crypto/fips-aes.h
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* This file was generated by: gen-fips-testvecs.py */
+/* clang-format off */
+
+#include <linux/fips.h>
+
+static const u8 fips_test_data[] __initconst __maybe_unused = {
+ 0x66, 0x69, 0x70, 0x73, 0x20, 0x74, 0x65, 0x73,
+ 0x74, 0x20, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00,
+};
+
+static const u8 fips_test_ad[] __initconst __maybe_unused = {
+ 0x66, 0x69, 0x70, 0x73, 0x20, 0x74, 0x65, 0x73,
+ 0x74, 0x20, 0x61, 0x64, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const u8 fips_test_iv[] __initconst __maybe_unused = {
+ 0x66, 0x69, 0x70, 0x73, 0x20, 0x74, 0x65, 0x73,
+ 0x74, 0x20, 0x69, 0x76, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const u8 fips_test_key[] __initconst __maybe_unused = {
+ 0x66, 0x69, 0x70, 0x73, 0x20, 0x74, 0x65, 0x73,
+ 0x74, 0x20, 0x6b, 0x65, 0x79, 0x00, 0x00, 0x00,
+};
+
+static const u8 fips_test_xts_key[] __initconst __maybe_unused = {
+ 0x6b, 0x65, 0x79, 0x31, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x6b, 0x65, 0x79, 0x32, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const u8 fips_test_aes_cmac_value[] __initconst __maybe_unused = {
+ 0xc5, 0x88, 0x28, 0x55, 0xd7, 0x2c, 0x00, 0xb6,
+ 0x6a, 0xa7, 0xfc, 0x82, 0x90, 0x81, 0xcf, 0x18,
+};
+
+static const u8 fips_test_aes_ecb_ctext[] __initconst __maybe_unused = {
+ 0x47, 0x76, 0x48, 0xaf, 0x1b, 0xd8, 0x4c, 0xe6,
+ 0xb5, 0xa7, 0x20, 0x8d, 0x64, 0x88, 0xbc, 0x3f,
+};
+
+static const u8 fips_test_aes_cbc_ctext[] __initconst __maybe_unused = {
+ 0xc8, 0x7d, 0x7c, 0x25, 0xba, 0x15, 0xf7, 0xe1,
+ 0x08, 0xa0, 0xd0, 0x7a, 0x20, 0x37, 0xaf, 0x5e,
+};
+
+static const u8 fips_test_aes_cbc_cts_ctext[] __initconst __maybe_unused = {
+ 0x36, 0x8e, 0x37, 0xb4, 0x78, 0xe2, 0x88, 0x59,
+ 0xd5, 0xe8, 0x17, 0x65, 0x5c, 0xa1, 0x25, 0xe6,
+ 0xc8, 0x7d, 0x7c, 0x25, 0xba, 0x15, 0xf7, 0xe1,
+ 0x08, 0xa0, 0xd0, 0x7a, 0x20, 0x37, 0xaf, 0x5e,
+};
+
+static const u8 fips_test_aes_ctr_ctext[] __initconst __maybe_unused = {
+ 0x95, 0xf4, 0xf4, 0x7a, 0xc8, 0xa2, 0x53, 0x73,
+ 0x53, 0x8f, 0x95, 0xfc, 0x18, 0xfe, 0x58, 0x2f,
+};
+
+static const u8 fips_test_aes_xts_ctext[] __initconst __maybe_unused = {
+ 0xd4, 0x51, 0x7f, 0x01, 0x14, 0x91, 0x16, 0x29,
+ 0x26, 0xbe, 0xec, 0x9b, 0x90, 0xed, 0x59, 0x30,
+};
+
+static const u8 fips_test_aes_gcm_ctext_and_tag[] __initconst __maybe_unused = {
+ 0x12, 0x0c, 0x5d, 0x03, 0x32, 0x93, 0x13, 0x44,
+ 0x06, 0x35, 0x26, 0x9d, 0xe0, 0xea, 0xbc, 0xe2,
+ 0x30, 0xa9, 0xa4, 0x15, 0xc5, 0x3d, 0xb3, 0xf9,
+ 0x30, 0x82, 0xdf, 0x9c, 0xd8, 0xc4, 0x3f, 0x2f,
+};
+
+static const u8 fips_test_aes_ccm_ctext_and_tag[] __initconst __maybe_unused = {
+ 0x11, 0x8e, 0x01, 0xcb, 0xb5, 0x22, 0x6d, 0xb4,
+ 0x66, 0x98, 0x97, 0x1d, 0x35, 0x53, 0x78, 0xdd,
+ 0xd1, 0xc5, 0xff, 0xb6, 0x90, 0xcf, 0xb1, 0xf2,
+ 0x87, 0x99, 0xd6, 0x1e, 0xd5, 0xd1, 0xed, 0x63,
+};
diff --git a/lib/crypto/fips.h b/lib/crypto/fips-sha.h
index 9fc49747db64..68af7e14e09c 100644
--- a/lib/crypto/fips.h
+++ b/lib/crypto/fips-sha.h
@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* This file was generated by: gen-fips-testvecs.py */
+/* clang-format off */
#include <linux/fips.h>
@@ -43,8 +44,3 @@ static const u8 fips_test_sha3_256_value[] __initconst __maybe_unused = {
0xba, 0x9b, 0xb6, 0xaa, 0x32, 0xa7, 0x97, 0x00,
0x98, 0xdb, 0xff, 0xe7, 0xc6, 0xde, 0xb5, 0x82,
};
-
-static const u8 fips_test_aes_cmac_value[] __initconst __maybe_unused = {
- 0xc5, 0x88, 0x28, 0x55, 0xd7, 0x2c, 0x00, 0xb6,
- 0x6a, 0xa7, 0xfc, 0x82, 0x90, 0x81, 0xcf, 0x18,
-};
diff --git a/lib/crypto/md5.c b/lib/crypto/md5.c
index 6bf130cfbbf9..3d2b017a0525 100644
--- a/lib/crypto/md5.c
+++ b/lib/crypto/md5.c
@@ -298,19 +298,5 @@ void hmac_md5_usingrawkey(const u8 *raw_key, size_t raw_key_len,
}
EXPORT_SYMBOL_GPL(hmac_md5_usingrawkey);
-#ifdef md5_mod_init_arch
-static int __init md5_mod_init(void)
-{
- md5_mod_init_arch();
- return 0;
-}
-subsys_initcall(md5_mod_init);
-
-static void __exit md5_mod_exit(void)
-{
-}
-module_exit(md5_mod_exit);
-#endif
-
MODULE_DESCRIPTION("MD5 and HMAC-MD5 library functions");
MODULE_LICENSE("GPL");
diff --git a/lib/crypto/sha1.c b/lib/crypto/sha1.c
index daf18c862fdf..b687b89d97cb 100644
--- a/lib/crypto/sha1.c
+++ b/lib/crypto/sha1.c
@@ -12,7 +12,7 @@
#include <linux/string.h>
#include <linux/unaligned.h>
#include <linux/wordpart.h>
-#include "fips.h"
+#include "fips-sha.h"
static const struct sha1_block_state sha1_iv = {
.h = { SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4 },
diff --git a/lib/crypto/sha256.c b/lib/crypto/sha256.c
index 5d6b77e7e141..e8c346f563c5 100644
--- a/lib/crypto/sha256.c
+++ b/lib/crypto/sha256.c
@@ -17,7 +17,7 @@
#include <linux/string.h>
#include <linux/unaligned.h>
#include <linux/wordpart.h>
-#include "fips.h"
+#include "fips-sha.h"
static const struct sha256_block_state sha224_iv = {
.h = {
diff --git a/lib/crypto/sha3.c b/lib/crypto/sha3.c
index 32b7074de792..286a2373c156 100644
--- a/lib/crypto/sha3.c
+++ b/lib/crypto/sha3.c
@@ -17,7 +17,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/unaligned.h>
-#include "fips.h"
+#include "fips-sha.h"
/*
* On some 32-bit architectures, such as h8300, GCC ends up using over 1 KB of
diff --git a/lib/crypto/sha512.c b/lib/crypto/sha512.c
index 605eab51aabd..0dd6fb4ca15b 100644
--- a/lib/crypto/sha512.c
+++ b/lib/crypto/sha512.c
@@ -17,7 +17,7 @@
#include <linux/string.h>
#include <linux/unaligned.h>
#include <linux/wordpart.h>
-#include "fips.h"
+#include "fips-sha.h"
static const struct sha512_block_state sha384_iv = {
.h = {
diff --git a/lib/crypto/tests/Kconfig b/lib/crypto/tests/Kconfig
index 9409c1a935c3..e121114624da 100644
--- a/lib/crypto/tests/Kconfig
+++ b/lib/crypto/tests/Kconfig
@@ -9,6 +9,24 @@ config CRYPTO_LIB_AES_CBC_MACS_KUNIT_TEST
KUnit tests for the AES-CMAC, AES-XCBC-MAC, and AES-CBC-MAC message
authentication codes.
+config CRYPTO_LIB_AES_CCM_KUNIT_TEST
+ tristate "KUnit tests for AES-CCM" if !KUNIT_ALL_TESTS
+ depends on KUNIT && CRYPTO_LIB_AES_CCM
+ default KUNIT_ALL_TESTS
+ select CRYPTO_LIB_BENCHMARK_VISIBLE
+ # This test uses BLAKE2s, but that's always built-in.
+ help
+ KUnit tests for the AES-CCM authenticated encryption algorithm.
+
+config CRYPTO_LIB_AES_GCM_KUNIT_TEST
+ tristate "KUnit tests for AES-GCM" if !KUNIT_ALL_TESTS
+ depends on KUNIT && CRYPTO_LIB_AES_GCM
+ default KUNIT_ALL_TESTS
+ select CRYPTO_LIB_BENCHMARK_VISIBLE
+ # This test uses BLAKE2s, but that's always built-in.
+ help
+ KUnit tests for the AES-GCM authenticated encryption algorithm.
+
config CRYPTO_LIB_BLAKE2B_KUNIT_TEST
tristate "KUnit tests for BLAKE2b" if !KUNIT_ALL_TESTS
depends on KUNIT && CRYPTO_LIB_BLAKE2B
@@ -144,7 +162,13 @@ config CRYPTO_LIB_SM3_KUNIT_TEST
config CRYPTO_LIB_ENABLE_ALL_FOR_KUNIT
tristate "Enable all crypto library code for KUnit tests"
depends on KUNIT
+ select CRYPTO_LIB_AES_CBC
select CRYPTO_LIB_AES_CBC_MACS
+ select CRYPTO_LIB_AES_CCM
+ select CRYPTO_LIB_AES_CTR
+ select CRYPTO_LIB_AES_ECB
+ select CRYPTO_LIB_AES_GCM
+ select CRYPTO_LIB_AES_XTS
select CRYPTO_LIB_BLAKE2B
select CRYPTO_LIB_CHACHA20POLY1305
select CRYPTO_LIB_CURVE25519
diff --git a/lib/crypto/tests/Makefile b/lib/crypto/tests/Makefile
index a739413500b6..c97c1d78784a 100644
--- a/lib/crypto/tests/Makefile
+++ b/lib/crypto/tests/Makefile
@@ -1,6 +1,8 @@
# SPDX-License-Identifier: GPL-2.0-or-later
obj-$(CONFIG_CRYPTO_LIB_AES_CBC_MACS_KUNIT_TEST) += aes_cbc_macs_kunit.o
+obj-$(CONFIG_CRYPTO_LIB_AES_CCM_KUNIT_TEST) += aes_ccm_kunit.o
+obj-$(CONFIG_CRYPTO_LIB_AES_GCM_KUNIT_TEST) += aes_gcm_kunit.o
obj-$(CONFIG_CRYPTO_LIB_BLAKE2B_KUNIT_TEST) += blake2b_kunit.o
obj-$(CONFIG_CRYPTO_LIB_BLAKE2S_KUNIT_TEST) += blake2s_kunit.o
obj-$(CONFIG_CRYPTO_LIB_CHACHA20POLY1305_KUNIT_TEST) += chacha20poly1305_kunit.o
diff --git a/lib/crypto/tests/aead-test-template.h b/lib/crypto/tests/aead-test-template.h
new file mode 100644
index 000000000000..0c0138d2fa8a
--- /dev/null
+++ b/lib/crypto/tests/aead-test-template.h
@@ -0,0 +1,1039 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Shared KUnit test cases for AEAD algorithms, including a benchmark
+ *
+ * Copyright 2026 Google LLC
+ */
+
+/*
+ * This file implements KUnit test cases shared by the different KUnit test
+ * suites for Authenticated Encryption with Associated Data (AEAD) algorithms.
+ *
+ * Test suites including this file must #define the following:
+ *
+ * Data structs:
+ * - AEAD_KEY: name of key struct
+ * - AEAD_CTX: name of context for incremental computation
+ *
+ * Constants:
+ * - AEAD_VALID_KEY_LENS: array of all valid key lengths in bytes
+ * - AEAD_VALID_NONCE_LENS: array of all valid nonce lengths in bytes
+ * - AEAD_VALID_TAG_LENS: array of all valid authtag lengths in bytes
+ * - AEAD_MAX_KEY_LEN: max key length in bytes (assumed to fit on stack)
+ * - AEAD_MAX_NONCE_LEN: max nonce length in bytes (assumed to fit on stack)
+ * - AEAD_MAX_TAG_LEN: max authtag length in bytes (assumed to fit on stack)
+ * - AEAD_MONTE_CARLO_CHECKSUM: checksum of a deterministically generated series
+ * of (ciphertext, authtag) pairs (see test_aead_monte_carlo())
+ *
+ * Functions:
+ * - AEAD_PREPAREKEY: key preparation
+ * - AEAD_ENCRYPT and AEAD_DECRYPT: one-shot encryption and decryption
+ * - AEAD_INIT, AEAD_AUTH_UPDATE, AEAD_ENCRYPT_UPDATE, AEAD_ENCRYPT_FINAL,
+ * AEAD_DECRYPT_UPDATE, AEAD_DECRYPT_FINAL: functions for incremental
+ * encryption and decryption
+ *
+ * Function prototypes and their behavior must match the AES-CCM API.
+ */
+
+#include <crypto/blake2s.h>
+#include <kunit/run-in-irq-context.h>
+#include <kunit/test.h>
+#include <linux/ktime.h>
+#include <linux/preempt.h>
+#include "test-utils.h"
+
+/*
+ * Allocate a KUnit-managed struct AEAD_KEY and prepare it with a random key,
+ * using a random key length and random authentication tag length.
+ */
+static struct AEAD_KEY *aead_alloc_random_key(struct kunit *test,
+ size_t *tag_len_ret)
+{
+ size_t key_len =
+ AEAD_VALID_KEY_LENS[rand32() % ARRAY_SIZE(AEAD_VALID_KEY_LENS)];
+ size_t tag_len =
+ AEAD_VALID_TAG_LENS[rand32() % ARRAY_SIZE(AEAD_VALID_TAG_LENS)];
+ u8 raw_key[AEAD_MAX_KEY_LEN];
+ struct AEAD_KEY *key = alloc_buf(test, sizeof(*key));
+ int err;
+
+ rand_bytes(raw_key, key_len);
+ err = AEAD_PREPAREKEY(key, raw_key, key_len, tag_len);
+ KUNIT_ASSERT_EQ(test, 0, err);
+ *tag_len_ret = tag_len;
+ return key;
+}
+
+/*
+ * Allocate a KUnit-managed slab buffer of length @len bytes and initialize it
+ * with random data.
+ */
+static u8 *aead_alloc_random_data(struct kunit *test, size_t len)
+{
+ u8 *buf = alloc_buf(test, len);
+
+ rand_bytes(buf, len);
+ return buf;
+}
+
+/*
+ * Allocate a KUnit-managed guarded buffer of length @len bytes and initialize
+ * it with random data.
+ */
+static u8 *aead_alloc_random_data_guarded(struct kunit *test, size_t len)
+{
+ u8 *buf = alloc_guarded_buf(test, len);
+
+ rand_bytes(buf, len);
+ return buf;
+}
+
+/* Process the given associated data using a random incremental strategy. */
+static size_t aead_auth_incrementally(struct AEAD_CTX *ctx, const u8 *ad,
+ size_t ad_len)
+{
+ size_t num_parts = 0;
+ size_t pos = 0;
+
+ while (rand_bool()) {
+ size_t part_len = rand_length(ad_len - pos);
+
+ AEAD_AUTH_UPDATE(ctx, &ad[pos], part_len);
+ pos += part_len;
+ num_parts++;
+ }
+ if (pos < ad_len || rand_bool()) {
+ AEAD_AUTH_UPDATE(ctx, &ad[pos], ad_len - pos);
+ num_parts++;
+ }
+ return num_parts;
+}
+
+/* Process the given en/decrypted data using a random incremental strategy. */
+static size_t aead_crypt_incrementally(struct AEAD_CTX *ctx, u8 *dst,
+ const u8 *src, size_t data_len, bool enc)
+{
+ size_t num_parts = 0;
+ size_t pos = 0;
+
+ while (rand_bool()) {
+ size_t part_len = rand_length(data_len - pos);
+
+ if (enc)
+ AEAD_ENCRYPT_UPDATE(ctx, &dst[pos], &src[pos],
+ part_len);
+ else
+ AEAD_DECRYPT_UPDATE(ctx, &dst[pos], &src[pos],
+ part_len);
+ pos += part_len;
+ num_parts++;
+ }
+ if (pos < data_len || rand_bool()) {
+ if (enc)
+ AEAD_ENCRYPT_UPDATE(ctx, &dst[pos], &src[pos],
+ data_len - pos);
+ else
+ AEAD_DECRYPT_UPDATE(ctx, &dst[pos], &src[pos],
+ data_len - pos);
+ num_parts++;
+ }
+ return num_parts;
+}
+
+struct aead_incremental_info {
+ size_t num_data_parts;
+ size_t num_ad_parts;
+};
+
+static const char *aead_incr_info_str(struct kunit *test,
+ const struct aead_incremental_info *info)
+{
+ const size_t max_str_len = 64;
+ char *str = alloc_buf(test, max_str_len);
+
+ snprintf(str, max_str_len, "num_data_parts=%zu num_ad_parts=%zu",
+ info->num_data_parts, info->num_ad_parts);
+ return str;
+}
+
+/*
+ * Encrypt data using a random incremental strategy.
+ * Return information about the incremental strategy used.
+ */
+static struct aead_incremental_info
+aead_encrypt_incrementally(struct kunit *test, struct AEAD_CTX *ctx, u8 *dst,
+ const u8 *src, size_t data_len, u8 *tag,
+ const u8 *ad, size_t ad_len, const u8 *nonce,
+ size_t nonce_len, const struct AEAD_KEY *key)
+{
+ struct aead_incremental_info info;
+ int err;
+
+ err = AEAD_INIT(ctx, data_len, ad_len, nonce, nonce_len, key);
+ KUNIT_ASSERT_EQ(test, 0, err);
+ info.num_ad_parts = aead_auth_incrementally(ctx, ad, ad_len);
+ info.num_data_parts = aead_crypt_incrementally(ctx, dst, src, data_len,
+ /* enc= */ true);
+ AEAD_ENCRYPT_FINAL(ctx, tag);
+ KUNIT_ASSERT_TRUE_MSG(test, mem_is_zero(ctx, sizeof(*ctx)),
+ "encrypt_final didn't zeroize context");
+ return info;
+}
+
+/*
+ * Decrypt authentic data using a random incremental strategy.
+ * Return information about the incremental strategy used.
+ */
+static struct aead_incremental_info
+aead_decrypt_incrementally(struct kunit *test, struct AEAD_CTX *ctx, u8 *dst,
+ const u8 *src, size_t data_len, const u8 *tag,
+ const u8 *ad, size_t ad_len, const u8 *nonce,
+ size_t nonce_len, const struct AEAD_KEY *key)
+{
+ struct aead_incremental_info info;
+ int err;
+
+ err = AEAD_INIT(ctx, data_len, ad_len, nonce, nonce_len, key);
+ KUNIT_ASSERT_EQ(test, 0, err);
+ info.num_ad_parts = aead_auth_incrementally(ctx, ad, ad_len);
+ info.num_data_parts = aead_crypt_incrementally(ctx, dst, src, data_len,
+ /* enc= */ false);
+ err = AEAD_DECRYPT_FINAL(ctx, tag);
+ KUNIT_ASSERT_EQ(test, 0, err);
+ KUNIT_ASSERT_TRUE_MSG(test, mem_is_zero(ctx, sizeof(*ctx)),
+ "decrypt_final didn't zeroize context");
+ return info;
+}
+
+/* Return true if key_len is declared to be a valid key length. */
+static bool aead_is_key_len_expected_valid(size_t key_len)
+{
+ for (size_t i = 0; i < ARRAY_SIZE(AEAD_VALID_KEY_LENS); i++) {
+ if (AEAD_VALID_KEY_LENS[i] == key_len)
+ return true;
+ }
+ return false;
+}
+
+/* Return true if nonce_len is declared to be a valid nonce length. */
+static bool aead_is_nonce_len_expected_valid(size_t nonce_len)
+{
+ for (size_t i = 0; i < ARRAY_SIZE(AEAD_VALID_NONCE_LENS); i++) {
+ if (AEAD_VALID_NONCE_LENS[i] == nonce_len)
+ return true;
+ }
+ return false;
+}
+
+/* Return true if tag_len is declared to be a valid tag length. */
+static bool aead_is_tag_len_expected_valid(size_t tag_len)
+{
+ for (size_t i = 0; i < ARRAY_SIZE(AEAD_VALID_TAG_LENS); i++) {
+ if (AEAD_VALID_TAG_LENS[i] == tag_len)
+ return true;
+ }
+ return false;
+}
+
+struct aead_basic_validation_test_ctx {
+ struct AEAD_KEY key;
+ struct AEAD_CTX ctx;
+ u8 *raw_key_buf_end;
+ u8 *nonce_buf_end;
+ u8 *tag_buf_end;
+ u8 pt[64]; /* plaintext */
+ u8 ct[64]; /* ciphertext */
+ u8 decrypted[64];
+ u8 ad[16]; /* associated data */
+ u8 *unused_buf;
+ size_t data_len;
+ size_t ad_len;
+};
+
+static struct aead_basic_validation_test_ctx *
+aead_alloc_basic_validation_test_ctx(struct kunit *test)
+{
+ struct aead_basic_validation_test_ctx *ctx =
+ alloc_buf(test, sizeof(*ctx));
+
+ memset(ctx, 0, sizeof(*ctx));
+ ctx->raw_key_buf_end =
+ aead_alloc_random_data_guarded(test, AEAD_MAX_KEY_LEN) +
+ AEAD_MAX_KEY_LEN;
+ ctx->nonce_buf_end =
+ aead_alloc_random_data_guarded(test, AEAD_MAX_NONCE_LEN) +
+ AEAD_MAX_NONCE_LEN;
+ ctx->tag_buf_end =
+ aead_alloc_random_data_guarded(test, AEAD_MAX_TAG_LEN) +
+ AEAD_MAX_TAG_LEN;
+
+ /*
+ * A pointer to this buffer is passed when passing a length that is
+ * expected to be invalid. It should never actually be accessed.
+ */
+ ctx->unused_buf =
+ alloc_buf(test, max3(AEAD_MAX_KEY_LEN, AEAD_MAX_NONCE_LEN,
+ AEAD_MAX_TAG_LEN));
+
+ ctx->data_len = sizeof(ctx->pt);
+ ctx->ad_len = sizeof(ctx->ad);
+ return ctx;
+}
+
+/*
+ * Given an expected-valid key_len, nonce_len, and tag_len, verify round-trip
+ * encryption and decryption with them. Use guarded buffers for each of the raw
+ * key, nonce, and tag to detect any buffer overruns in them. Also, verify that
+ * every byte of the tag is actually checked.
+ */
+static void aead_do_basic_checks(struct kunit *test,
+ struct aead_basic_validation_test_ctx *ctx,
+ size_t key_len, size_t nonce_len,
+ size_t tag_len)
+{
+ /* Set up exact-size guarded buffers for (raw_key, nonce, tag). */
+ const u8 *raw_key = ctx->raw_key_buf_end - key_len;
+ const u8 *nonce = ctx->nonce_buf_end - nonce_len;
+ u8 *tag = ctx->tag_buf_end - tag_len;
+ int err;
+
+ /* Key preparation should succeed. */
+ err = AEAD_PREPAREKEY(&ctx->key, raw_key, key_len, tag_len);
+ KUNIT_ASSERT_EQ_MSG(test, 0, err,
+ "key_len=%zu, tag_len=%zu wasn't accepted", key_len,
+ tag_len);
+
+ /* Encryption should succeed. */
+ err = AEAD_ENCRYPT(ctx->ct, ctx->pt, ctx->data_len, tag, ctx->ad,
+ ctx->ad_len, nonce, nonce_len, &ctx->key);
+ KUNIT_ASSERT_EQ_MSG(
+ test, 0, err,
+ "Encryption failed with key_len=%zu, nonce_len=%zu, tag_len=%zu",
+ key_len, nonce_len, tag_len);
+
+ /* Decryption should succeed and give the original data. */
+ err = AEAD_DECRYPT(ctx->decrypted, ctx->ct, ctx->data_len, tag, ctx->ad,
+ ctx->ad_len, nonce, nonce_len, &ctx->key);
+ KUNIT_ASSERT_EQ_MSG(
+ test, 0, err,
+ "Decryption failed with key_len=%zu, nonce_len=%zu, tag_len=%zu",
+ key_len, nonce_len, tag_len);
+ KUNIT_ASSERT_MEMEQ_MSG(
+ test, ctx->pt, ctx->decrypted, ctx->data_len,
+ "Decryption gave wrong output with key_len=%zu, nonce_len=%zu, tag_len=%zu",
+ key_len, nonce_len, tag_len);
+
+ /*
+ * Every byte of the tag should actually be checked.
+ * And on authentication failure, the dst buffer should be cleared.
+ */
+ for (size_t i = 0; i < tag_len; i++) {
+ memset(ctx->decrypted, 0xff, ctx->data_len);
+ tag[i] ^= 1;
+ err = AEAD_DECRYPT(ctx->decrypted, ctx->ct, ctx->data_len, tag,
+ ctx->ad, ctx->ad_len, nonce, nonce_len,
+ &ctx->key);
+ KUNIT_ASSERT_EQ_MSG(
+ test, -EBADMSG, err,
+ "Decryption with bad auth tag with key_len=%zu, nonce_len=%zu, tag_len=%zu didn't fail with -EBADMSG",
+ key_len, nonce_len, tag_len);
+ KUNIT_ASSERT_TRUE_MSG(
+ test, mem_is_zero(ctx->decrypted, ctx->data_len),
+ "dst wasn't cleared on authentication failure");
+ tag[i] ^= 1;
+ }
+}
+
+/* Verify that the given expected-invalid key_len is actually rejected. */
+static void
+aead_verify_invalid_key_len(struct kunit *test,
+ struct aead_basic_validation_test_ctx *ctx,
+ size_t key_len)
+{
+ int err;
+
+ /*
+ * The preparekey function should reject the key_len. It should do so
+ * before writing to the key struct.
+ */
+ memset(&ctx->key, 0, sizeof(ctx->key));
+ err = AEAD_PREPAREKEY(&ctx->key, ctx->unused_buf, key_len,
+ AEAD_MAX_TAG_LEN);
+ KUNIT_ASSERT_EQ_MSG(test, -EINVAL, err,
+ "key_len=%zu wasn't rejected with -EINVAL",
+ key_len);
+ KUNIT_ASSERT_TRUE_MSG(
+ test, mem_is_zero(&ctx->key, sizeof(ctx->key)),
+ "Key struct was written to before length validation");
+}
+
+/*
+ * Test that every valid key length is accepted and basic checks pass with it,
+ * and test that invalid key lengths are rejected.
+ */
+static void test_aead_all_key_lens(struct kunit *test)
+{
+ struct aead_basic_validation_test_ctx *ctx =
+ aead_alloc_basic_validation_test_ctx(test);
+
+ for (size_t key_len = 0; key_len <= AEAD_MAX_KEY_LEN; key_len++) {
+ if (aead_is_key_len_expected_valid(key_len))
+ aead_do_basic_checks(test, ctx, key_len,
+ AEAD_MAX_NONCE_LEN,
+ AEAD_MAX_TAG_LEN);
+ else
+ aead_verify_invalid_key_len(test, ctx, key_len);
+ }
+ aead_verify_invalid_key_len(test, ctx, AEAD_MAX_KEY_LEN + 1);
+ aead_verify_invalid_key_len(test, ctx, AEAD_MAX_KEY_LEN * 2);
+ aead_verify_invalid_key_len(test, ctx, U32_MAX);
+ aead_verify_invalid_key_len(test, ctx, SIZE_MAX);
+}
+
+/* Verify that the given expected-invalid nonce_len is actually rejected. */
+static void
+aead_verify_invalid_nonce_len(struct kunit *test,
+ struct aead_basic_validation_test_ctx *ctx,
+ size_t nonce_len)
+{
+ static const u8 raw_key[AEAD_MAX_KEY_LEN];
+ int err;
+
+ /* Key preparation should succeed, as nonce_len isn't given yet. */
+ err = AEAD_PREPAREKEY(&ctx->key, raw_key, sizeof(raw_key),
+ AEAD_MAX_TAG_LEN);
+ KUNIT_ASSERT_EQ(test, 0, err);
+
+ /* The init function should reject the nonce_len. */
+ memset(&ctx->ctx, 0, sizeof(ctx->ctx));
+ err = AEAD_INIT(&ctx->ctx, ctx->data_len, ctx->ad_len, ctx->unused_buf,
+ nonce_len, &ctx->key);
+ KUNIT_ASSERT_EQ_MSG(test, -EINVAL, err,
+ "nonce_len=%zu wasn't rejected with -EINVAL (init)",
+ nonce_len);
+ KUNIT_ASSERT_TRUE_MSG(
+ test, mem_is_zero(&ctx->ctx, sizeof(ctx->ctx)),
+ "Context struct was written to before length validation");
+
+ /* The encrypt function should reject the nonce_len. */
+ err = AEAD_ENCRYPT(ctx->ct, ctx->pt, ctx->data_len, ctx->unused_buf,
+ ctx->ad, ctx->ad_len, ctx->unused_buf, nonce_len,
+ &ctx->key);
+ KUNIT_ASSERT_EQ_MSG(
+ test, -EINVAL, err,
+ "nonce_len=%zu wasn't rejected with -EINVAL (encrypt)",
+ nonce_len);
+
+ /* The decrypt function should reject the nonce_len. */
+ err = AEAD_DECRYPT(ctx->pt, ctx->ct, ctx->data_len, ctx->unused_buf,
+ ctx->ad, ctx->ad_len, ctx->unused_buf, nonce_len,
+ &ctx->key);
+ KUNIT_ASSERT_EQ_MSG(
+ test, -EINVAL, err,
+ "nonce_len=%zu wasn't rejected with -EINVAL (decrypt)",
+ nonce_len);
+}
+
+/*
+ * Test that every valid nonce length is accepted and basic checks pass with it,
+ * and test that invalid nonce lengths are rejected.
+ */
+static void test_aead_all_nonce_lens(struct kunit *test)
+{
+ struct aead_basic_validation_test_ctx *ctx =
+ aead_alloc_basic_validation_test_ctx(test);
+
+ for (size_t nonce_len = 0; nonce_len <= AEAD_MAX_NONCE_LEN;
+ nonce_len++) {
+ if (aead_is_nonce_len_expected_valid(nonce_len))
+ aead_do_basic_checks(test, ctx, AEAD_MAX_KEY_LEN,
+ nonce_len, AEAD_MAX_TAG_LEN);
+ else
+ aead_verify_invalid_nonce_len(test, ctx, nonce_len);
+ }
+ aead_verify_invalid_nonce_len(test, ctx, AEAD_MAX_NONCE_LEN + 1);
+ aead_verify_invalid_nonce_len(test, ctx, AEAD_MAX_NONCE_LEN * 2);
+ aead_verify_invalid_nonce_len(test, ctx, U32_MAX);
+ aead_verify_invalid_nonce_len(test, ctx, SIZE_MAX);
+}
+
+/* Verify that the given expected-invalid tag_len is actually rejected. */
+static void
+aead_verify_invalid_tag_len(struct kunit *test,
+ struct aead_basic_validation_test_ctx *ctx,
+ size_t tag_len)
+{
+ static const u8 raw_key[AEAD_MAX_KEY_LEN];
+ int err;
+
+ /*
+ * The preparekey function should reject the tag_len. It should do so
+ * before writing to the key struct.
+ */
+ memset(&ctx->key, 0, sizeof(ctx->key));
+ err = AEAD_PREPAREKEY(&ctx->key, raw_key, sizeof(raw_key), tag_len);
+ KUNIT_ASSERT_EQ_MSG(test, -EINVAL, err,
+ "tag_len=%zu wasn't rejected with -EINVAL",
+ tag_len);
+ KUNIT_ASSERT_TRUE_MSG(
+ test, mem_is_zero(&ctx->key, sizeof(ctx->key)),
+ "Key struct was written to before length validation");
+}
+
+/*
+ * Test that every valid authentication tag length is accepted and basic checks
+ * pass with it, and test that invalid authentication tag lengths are rejected.
+ */
+static void test_aead_all_tag_lens(struct kunit *test)
+{
+ struct aead_basic_validation_test_ctx *ctx =
+ aead_alloc_basic_validation_test_ctx(test);
+
+ for (size_t tag_len = 0; tag_len <= AEAD_MAX_TAG_LEN; tag_len++) {
+ if (aead_is_tag_len_expected_valid(tag_len))
+ aead_do_basic_checks(test, ctx, AEAD_MAX_KEY_LEN,
+ AEAD_MAX_NONCE_LEN, tag_len);
+ else
+ aead_verify_invalid_tag_len(test, ctx, tag_len);
+ }
+ aead_verify_invalid_tag_len(test, ctx, AEAD_MAX_TAG_LEN + 1);
+ aead_verify_invalid_tag_len(test, ctx, AEAD_MAX_TAG_LEN * 2);
+ aead_verify_invalid_tag_len(test, ctx, U32_MAX);
+ aead_verify_invalid_tag_len(test, ctx, SIZE_MAX);
+}
+
+/*
+ * Test that one-shot encryption and decryption are consistent with each other
+ * and with incremental encryption and decryption.
+ */
+static void test_aead_incremental_updates(struct kunit *test)
+{
+ const size_t max_data_len = 1024;
+ const size_t max_ad_len = 512;
+ const size_t nonce_len = AEAD_MAX_NONCE_LEN;
+ size_t tag_len;
+ struct AEAD_KEY *key = aead_alloc_random_key(test, &tag_len);
+ struct AEAD_CTX *ctx = alloc_buf(test, sizeof(*ctx));
+ u8 *pt = aead_alloc_random_data(test, max_data_len);
+ u8 *ad = aead_alloc_random_data(test, max_ad_len);
+ u8 *nonce = aead_alloc_random_data(test, nonce_len);
+ u8 *ct = alloc_buf(test, max_data_len);
+ u8 *ct2 = alloc_buf(test, max_data_len);
+ u8 *decrypted = alloc_buf(test, max_data_len);
+ u8 *tag = alloc_buf(test, tag_len);
+ u8 *tag2 = alloc_buf(test, tag_len);
+ int err;
+
+ for (int i = 0; i < 500; i++) {
+ /* Select the lengths to test. */
+ const size_t data_len = rand_length(max_data_len);
+ const size_t ad_len = rand_length(max_ad_len);
+ struct aead_incremental_info incr_info;
+
+ /* Try one-shot encryption and decryption. */
+ err = AEAD_ENCRYPT(ct, pt, data_len, tag, ad, ad_len, nonce,
+ nonce_len, key);
+ KUNIT_ASSERT_EQ(test, 0, err);
+ err = AEAD_DECRYPT(decrypted, ct, data_len, tag, ad, ad_len,
+ nonce, nonce_len, key);
+ KUNIT_ASSERT_EQ(test, 0, err);
+ KUNIT_ASSERT_MEMEQ_MSG(
+ test, pt, decrypted, data_len,
+ "Decryption didn't invert encryption; data_len=%zu, ad_len=%zu",
+ data_len, ad_len);
+
+ /* Try incremental encryption and decryption. */
+ incr_info = aead_encrypt_incrementally(test, ctx, ct2, pt,
+ data_len, tag2, ad,
+ ad_len, nonce, nonce_len,
+ key);
+ KUNIT_ASSERT_MEMEQ_MSG(
+ test, ct, ct2, data_len,
+ "One-shot and incremental encryption gave different ciphertexts; data_len=%zu ad_len=%zu %s",
+ data_len, ad_len, aead_incr_info_str(test, &incr_info));
+ KUNIT_ASSERT_MEMEQ_MSG(
+ test, tag, tag2, tag_len,
+ "One-shot and incremental encryption gave different auth tags; data_len=%zu ad_len=%zu %s",
+ data_len, ad_len, aead_incr_info_str(test, &incr_info));
+ incr_info = aead_decrypt_incrementally(test, ctx, decrypted,
+ ct2, data_len, tag2, ad,
+ ad_len, nonce, nonce_len,
+ key);
+ KUNIT_ASSERT_MEMEQ_MSG(
+ test, pt, decrypted, data_len,
+ "One-shot and incremental decryption gave different plaintexts; data_len=%zu ad_len=%zu %s",
+ data_len, ad_len, aead_incr_info_str(test, &incr_info));
+ }
+}
+
+/*
+ * Test using guarded buffers for the plaintext, ciphertext, and associated
+ * data. This detects out-of-bounds accesses, even in assembly code.
+ *
+ * Note: other test cases cover overrun of raw_key, nonce, and tag.
+ */
+static void test_aead_data_buffer_overruns(struct kunit *test)
+{
+ const size_t max_data_len = 1024;
+ const size_t max_ad_len = 512;
+ const size_t nonce_len = AEAD_MAX_NONCE_LEN;
+ size_t tag_len;
+ struct AEAD_KEY *key = aead_alloc_random_key(test, &tag_len);
+ const u8 *nonce = aead_alloc_random_data(test, nonce_len);
+ const u8 *pt_end = aead_alloc_random_data_guarded(test, max_data_len) +
+ max_data_len;
+ const u8 *ad_end =
+ aead_alloc_random_data_guarded(test, max_ad_len) + max_ad_len;
+ u8 *ct_end = alloc_guarded_buf(test, max_data_len) + max_data_len;
+ u8 *decrypted_end =
+ alloc_guarded_buf(test, max_data_len) + max_data_len;
+ u8 *tag = alloc_buf(test, tag_len);
+
+ for (int i = 0; i < 200; i++) {
+ /* Select the lengths to test. */
+ const size_t data_len = rand_length(max_data_len);
+ const size_t ad_len = rand_length(max_ad_len);
+ /* Set up exact-size guarded buffers. */
+ const u8 *pt = pt_end - data_len;
+ const u8 *ad = ad_end - ad_len;
+ u8 *ct = ct_end - data_len;
+ u8 *decrypted = decrypted_end - data_len;
+ int err;
+
+ /* Encrypt and decrypt. */
+ err = AEAD_ENCRYPT(ct, pt, data_len, tag, ad, ad_len, nonce,
+ nonce_len, key);
+ KUNIT_ASSERT_EQ(test, 0, err);
+ err = AEAD_DECRYPT(decrypted, ct, data_len, tag, ad, ad_len,
+ nonce, nonce_len, key);
+ KUNIT_ASSERT_EQ(test, 0, err);
+ KUNIT_ASSERT_MEMEQ_MSG(
+ test, pt, decrypted, data_len,
+ "Decryption didn't invert encryption; data_len=%zu, ad_len=%zu",
+ data_len, ad_len);
+ }
+}
+
+/*
+ * Test that encryption and decryption produce the same results regardless of
+ * how the buffers are aligned in memory.
+ */
+static void test_aead_alignment_consistency(struct kunit *test)
+{
+ const size_t max_data_len = 4096;
+ const size_t max_ad_len = 4096;
+ const size_t max_offset = 128;
+ const size_t nonce_len = AEAD_MAX_NONCE_LEN;
+ const size_t key_len = AEAD_MAX_KEY_LEN;
+ const size_t tag_len = AEAD_MAX_TAG_LEN;
+ u8 *raw_key1_buf = alloc_buf(test, key_len + max_offset);
+ u8 *raw_key2_buf = alloc_buf(test, key_len + max_offset);
+ u8 *nonce1_buf = alloc_buf(test, nonce_len + max_offset);
+ u8 *nonce2_buf = alloc_buf(test, nonce_len + max_offset);
+ u8 *pt1_buf = alloc_buf(test, max_data_len);
+ u8 *pt2_buf = alloc_buf(test, max_data_len);
+ u8 *ct1_buf = alloc_buf(test, max_data_len);
+ u8 *ct2_buf = alloc_buf(test, max_data_len);
+ u8 *ad1_buf = alloc_buf(test, max_ad_len);
+ u8 *ad2_buf = alloc_buf(test, max_ad_len);
+ u8 *tag1_buf = alloc_buf(test, tag_len + max_offset);
+ u8 *tag2_buf = alloc_buf(test, tag_len + max_offset);
+ struct AEAD_KEY *key = alloc_buf(test, sizeof(*key));
+ int err;
+
+ for (int i = 0; i < 100; i++) {
+ /* Generate lengths. */
+ size_t data_len = rand_length(max_data_len);
+ size_t ad_len = rand_length(max_ad_len);
+
+ /* Generate two sets of alignments. */
+ u8 *raw_key1 = raw_key1_buf + rand_offset(max_offset);
+ u8 *raw_key2 = raw_key2_buf + rand_offset(max_offset);
+ u8 *nonce1 = nonce1_buf + rand_offset(max_offset);
+ u8 *nonce2 = nonce2_buf + rand_offset(max_offset);
+ u8 *pt1 = pt1_buf + rand_offset(max_data_len - data_len);
+ u8 *pt2 = pt2_buf + rand_offset(max_data_len - data_len);
+ u8 *ct1 = ct1_buf + rand_offset(max_data_len - data_len);
+ u8 *ct2 = ct2_buf + rand_offset(max_data_len - data_len);
+ u8 *ad1 = ad1_buf + rand_offset(max_ad_len - ad_len);
+ u8 *ad2 = ad2_buf + rand_offset(max_ad_len - ad_len);
+ u8 *tag1 = tag1_buf + rand_offset(max_offset);
+ u8 *tag2 = tag2_buf + rand_offset(max_offset);
+
+ /*
+ * Generate inputs in the first set of buffers using the first
+ * set of alignments.
+ */
+ rand_bytes(raw_key1, key_len);
+ rand_bytes(nonce1, nonce_len);
+ rand_bytes(pt1, data_len);
+ rand_bytes(ad1, ad_len);
+
+ /*
+ * Copy the inputs to the second set of buffers using the second
+ * set of alignments.
+ */
+ memcpy(raw_key2, raw_key1, key_len);
+ memcpy(nonce2, nonce1, nonce_len);
+ memcpy(pt2, pt1, data_len);
+ memcpy(ad2, ad1, ad_len);
+
+ /* Verify encryption consistency. */
+
+ err = AEAD_PREPAREKEY(key, raw_key1, key_len, tag_len);
+ KUNIT_ASSERT_EQ(test, 0, err);
+ err = AEAD_ENCRYPT(ct1, pt1, data_len, tag1, ad1, ad_len,
+ nonce1, nonce_len, key);
+ KUNIT_ASSERT_EQ(test, 0, err);
+
+ err = AEAD_PREPAREKEY(key, raw_key2, key_len, tag_len);
+ KUNIT_ASSERT_EQ(test, 0, err);
+ err = AEAD_ENCRYPT(ct2, pt2, data_len, tag2, ad2, ad_len,
+ nonce2, nonce_len, key);
+ KUNIT_ASSERT_EQ(test, 0, err);
+
+ KUNIT_ASSERT_MEMEQ(test, ct1, ct2, data_len);
+ KUNIT_ASSERT_MEMEQ(test, tag1, tag2, tag_len);
+
+ /* Verify decryption consistency. */
+
+ err = AEAD_PREPAREKEY(key, raw_key1, key_len, tag_len);
+ KUNIT_ASSERT_EQ(test, 0, err);
+ err = AEAD_DECRYPT(pt1, ct1, data_len, tag1, ad1, ad_len,
+ nonce1, nonce_len, key);
+ KUNIT_ASSERT_EQ(test, 0, err);
+
+ err = AEAD_PREPAREKEY(key, raw_key2, key_len, tag_len);
+ KUNIT_ASSERT_EQ(test, 0, err);
+ err = AEAD_DECRYPT(pt2, ct2, data_len, tag2, ad2, ad_len,
+ nonce2, nonce_len, key);
+ KUNIT_ASSERT_EQ(test, 0, err);
+
+ KUNIT_ASSERT_MEMEQ(test, pt1, pt2, data_len);
+ }
+}
+
+static void test_aead_inplace(struct kunit *test)
+{
+ const size_t max_data_len = 1024;
+ const size_t max_ad_len = 512;
+ const size_t nonce_len = AEAD_MAX_NONCE_LEN;
+ size_t tag_len;
+ struct AEAD_KEY *key = aead_alloc_random_key(test, &tag_len);
+ u8 *data = aead_alloc_random_data(test, max_data_len + tag_len);
+ u8 *data2 = alloc_buf(test, max_data_len + tag_len);
+ u8 *ad = aead_alloc_random_data(test, max_ad_len);
+ const u8 *nonce = aead_alloc_random_data(test, nonce_len);
+
+ for (int i = 0; i < 100; i++) {
+ size_t data_len = rand_length(max_data_len);
+ size_t ad_len = rand_length(max_ad_len);
+ int err;
+
+ /* Encrypt out-of-place. */
+ err = AEAD_ENCRYPT(data2, data, data_len, data2 + data_len, ad,
+ ad_len, nonce, nonce_len, key);
+ KUNIT_ASSERT_EQ(test, 0, err);
+
+ /* Encrypt in-place. */
+ err = AEAD_ENCRYPT(data, data, data_len, data + data_len, ad,
+ ad_len, nonce, nonce_len, key);
+ KUNIT_ASSERT_EQ(test, 0, err);
+
+ /* Compare the results. */
+ KUNIT_ASSERT_MEMEQ(test, data2, data, data_len + tag_len);
+
+ /* Decrypt out-of-place. */
+ err = AEAD_DECRYPT(data2, data, data_len, data + data_len, ad,
+ ad_len, nonce, nonce_len, key);
+ KUNIT_ASSERT_EQ(test, 0, err);
+
+ /* Decrypt in-place. */
+ err = AEAD_DECRYPT(data, data, data_len, data + data_len, ad,
+ ad_len, nonce, nonce_len, key);
+ KUNIT_ASSERT_EQ(test, 0, err);
+
+ /* Compare the results. */
+ KUNIT_ASSERT_MEMEQ(test, data2, data, data_len);
+ }
+}
+
+/*
+ * Monte-Carlo test for AEAD algorithms. This deterministically generates
+ * random AEAD inputs, encrypts them, verifies decryption, and computes and
+ * verifies the checksum of all computed (ciphertext, tag) pairs.
+ */
+static void test_aead_monte_carlo(struct kunit *test)
+{
+ const size_t max_data_len = 1024;
+ const size_t max_ad_len = 293;
+ u8 raw_key[AEAD_MAX_KEY_LEN];
+ u8 nonce[AEAD_MAX_NONCE_LEN];
+ u8 tag[AEAD_MAX_TAG_LEN];
+ u8 *pt = alloc_buf(test, max_data_len);
+ u8 *ct = alloc_buf(test, max_data_len);
+ u8 *decrypted = alloc_buf(test, max_data_len);
+ u8 *ad = alloc_buf(test, max_ad_len);
+ struct AEAD_KEY *key = alloc_buf(test, sizeof(*key));
+ struct blake2s_ctx checksum_ctx;
+ u8 actual_checksum[BLAKE2S_HASH_SIZE];
+ int err;
+
+ blake2s_init(&checksum_ctx, BLAKE2S_HASH_SIZE);
+
+ for (size_t data_len = 0; data_len <= max_data_len; data_len++) {
+ size_t ad_len = data_len % max_ad_len;
+ size_t key_len =
+ AEAD_VALID_KEY_LENS[data_len %
+ ARRAY_SIZE(AEAD_VALID_KEY_LENS)];
+ size_t nonce_len =
+ AEAD_VALID_NONCE_LENS[data_len %
+ ARRAY_SIZE(AEAD_VALID_NONCE_LENS)];
+ size_t tag_len =
+ AEAD_VALID_TAG_LENS[data_len %
+ ARRAY_SIZE(AEAD_VALID_TAG_LENS)];
+
+ rand_bytes_seeded_from_len(pt, data_len);
+ rand_bytes_seeded_from_len(ad, ad_len);
+ rand_bytes_seeded_from_len(raw_key, key_len);
+ rand_bytes_seeded_from_len(nonce, nonce_len);
+
+ err = AEAD_PREPAREKEY(key, raw_key, key_len, tag_len);
+ KUNIT_ASSERT_EQ(test, 0, err);
+
+ err = AEAD_ENCRYPT(ct, pt, data_len, tag, ad, ad_len, nonce,
+ nonce_len, key);
+ KUNIT_ASSERT_EQ_MSG(
+ test, 0, err,
+ "Encryption failed with data_len=%zu, ad_len=%zu",
+ data_len, ad_len);
+ err = AEAD_DECRYPT(decrypted, ct, data_len, tag, ad, ad_len,
+ nonce, nonce_len, key);
+ KUNIT_ASSERT_EQ_MSG(
+ test, 0, err,
+ "Decryption failed with data_len=%zu, ad_len=%zu",
+ data_len, ad_len);
+ KUNIT_ASSERT_MEMEQ_MSG(
+ test, pt, decrypted, data_len,
+ "Decryption didn't invert encryption; data_len=%zu, ad_len=%zu",
+ data_len, ad_len);
+
+ blake2s_update(&checksum_ctx, ct, data_len);
+ blake2s_update(&checksum_ctx, tag, tag_len);
+ }
+
+ blake2s_final(&checksum_ctx, actual_checksum);
+ KUNIT_EXPECT_MEMEQ_MSG(test, actual_checksum, AEAD_MONTE_CARLO_CHECKSUM,
+ BLAKE2S_HASH_SIZE,
+ "Monte-Carlo checksum mismatch");
+}
+
+#define IRQ_TEST_DATA_LEN 256
+#define IRQ_TEST_NUM_BUFFERS 3 /* matches max concurrency level */
+
+struct aead_irq_test_slot {
+ /* Fields written only at test case initialization time */
+ u8 raw_key[AEAD_MAX_KEY_LEN];
+ u8 nonce[AEAD_MAX_NONCE_LEN];
+ u8 pt[IRQ_TEST_DATA_LEN];
+ u8 ct[IRQ_TEST_DATA_LEN + AEAD_MAX_TAG_LEN];
+ u8 ad[IRQ_TEST_DATA_LEN];
+
+ /* Fields written throughout the test case */
+ struct AEAD_KEY key;
+ u8 scratch_buf[IRQ_TEST_DATA_LEN + AEAD_MAX_TAG_LEN];
+ int phase;
+ atomic_t in_use;
+};
+
+struct aead_irq_test_state {
+ struct aead_irq_test_slot slots[IRQ_TEST_NUM_BUFFERS];
+};
+
+static bool aead_irq_test_func(void *state_)
+{
+ struct aead_irq_test_state *state = state_;
+ struct aead_irq_test_slot *slot;
+ size_t data_len;
+ bool ok = true;
+
+ /*
+ * Find a free slot. This should always succeed, since the number of
+ * slots is equal to the max concurrency level of kunit_run_irq_test().
+ */
+ for (slot = &state->slots[0];
+ slot < &state->slots[ARRAY_SIZE(state->slots)]; slot++) {
+ if (atomic_cmpxchg(&slot->in_use, 0, 1) == 0)
+ break;
+ }
+ if (WARN_ON_ONCE(slot == &state->slots[ARRAY_SIZE(state->slots)]))
+ return false;
+ /*
+ * This execution context now has exclusive access to 'slot'.
+ * Next, execute the next operation that the slot is set to perform.
+ */
+
+ data_len = sizeof(slot->pt);
+ if (slot->phase == 0) {
+ /* Phase 0: Prepare slot's key in current context. */
+ ok = ok && AEAD_PREPAREKEY(&slot->key, slot->raw_key,
+ sizeof(slot->raw_key),
+ AEAD_MAX_TAG_LEN) == 0;
+ } else if (slot->phase == 1) {
+ /*
+ * Phase 1: Encrypt plaintext using key that may have been
+ * prepared in a different context.
+ */
+ ok = ok && AEAD_ENCRYPT(slot->scratch_buf, slot->pt, data_len,
+ &slot->scratch_buf[data_len], slot->ad,
+ sizeof(slot->ad), slot->nonce,
+ sizeof(slot->nonce), &slot->key) == 0;
+ /* Verify the ciphertext (with concatenated auth tag) matches */
+ ok = ok &&
+ memcmp(slot->scratch_buf, slot->ct, sizeof(slot->ct)) == 0;
+ } else {
+ /*
+ * Phase 2: Decrypt ciphertext using key that may have been
+ * prepared in a different context.
+ */
+ ok = ok && AEAD_DECRYPT(slot->scratch_buf, slot->ct, data_len,
+ &slot->ct[data_len], slot->ad,
+ sizeof(slot->ad), slot->nonce,
+ sizeof(slot->nonce), &slot->key) == 0;
+ /* Verify the plaintext matches. */
+ ok = ok && memcmp(slot->scratch_buf, slot->pt, data_len) == 0;
+ }
+ slot->phase = (slot->phase + 1) % 3;
+ atomic_set_release(&slot->in_use, 0);
+ return ok;
+}
+
+/*
+ * Test that encryption and decryption produce the correct results in task,
+ * softirq, and hardirq contexts running concurrently -- including with keys
+ * prepared in other contexts. This is needed to cover fallback code paths that
+ * execute in contexts where FPU or vector registers cannot be used.
+ */
+static void test_aead_interrupt_context(struct kunit *test)
+{
+ struct aead_irq_test_state *state = alloc_buf(test, sizeof(*state));
+
+ memset(state, 0, sizeof(*state));
+
+ /*
+ * For each slot, generate a set of AEAD inputs: a key, a nonce, a
+ * plaintext, and some associated data. Then generate the corresponding
+ * ciphertext with concatenated auth tag.
+ */
+ for (int i = 0; i < IRQ_TEST_NUM_BUFFERS; i++) {
+ struct aead_irq_test_slot *slot = &state->slots[i];
+ int err;
+
+ rand_bytes(slot->raw_key, sizeof(slot->raw_key));
+ rand_bytes(slot->nonce, sizeof(slot->nonce));
+ rand_bytes(slot->pt, sizeof(slot->pt));
+ rand_bytes(slot->ad, sizeof(slot->ad));
+ err = AEAD_PREPAREKEY(&slot->key, slot->raw_key,
+ sizeof(slot->raw_key), AEAD_MAX_TAG_LEN);
+ KUNIT_ASSERT_EQ(test, 0, err);
+ err = AEAD_ENCRYPT(slot->ct, slot->pt, sizeof(slot->pt),
+ &slot->ct[sizeof(slot->pt)], slot->ad,
+ sizeof(slot->ad), slot->nonce,
+ sizeof(slot->nonce), &slot->key);
+ KUNIT_ASSERT_EQ(test, 0, err);
+ }
+
+ kunit_run_irq_test(test, aead_irq_test_func, 100000, state);
+}
+
+/* Benchmark AEAD encryption and decryption on various data lengths. */
+static void benchmark_aead(struct kunit *test)
+{
+ static const size_t data_lens_to_test[] = {
+ 16, 64, 128, 256, 512, 1024, 1420, 4096, 16384,
+ };
+ const size_t max_data_len = 16384;
+ const size_t ad_len = 16;
+ const size_t key_len = AEAD_MAX_KEY_LEN;
+ const size_t nonce_len = AEAD_MAX_NONCE_LEN;
+ const size_t tag_len = AEAD_MAX_TAG_LEN;
+ const u8 *raw_key, *nonce, *ad;
+ u8 *pt, *ct, *tag;
+ struct AEAD_KEY *key;
+ int err;
+
+ if (!IS_ENABLED(CONFIG_CRYPTO_LIB_BENCHMARK))
+ kunit_skip(test, "not enabled");
+
+ raw_key = aead_alloc_random_data(test, key_len);
+ nonce = aead_alloc_random_data(test, nonce_len);
+ ad = aead_alloc_random_data(test, ad_len);
+ pt = aead_alloc_random_data(test, max_data_len);
+ ct = alloc_buf(test, max_data_len);
+ tag = alloc_buf(test, tag_len);
+
+ key = alloc_buf(test, sizeof(*key));
+ err = AEAD_PREPAREKEY(key, raw_key, key_len, tag_len);
+ KUNIT_ASSERT_EQ(test, 0, err);
+
+ /* Warm-up */
+ for (size_t i = 0; i < 10000000; i += max_data_len) {
+ err = AEAD_ENCRYPT(ct, pt, max_data_len, tag, ad, ad_len, nonce,
+ nonce_len, key);
+ KUNIT_ASSERT_EQ(test, 0, err);
+ err = AEAD_DECRYPT(pt, ct, max_data_len, tag, ad, ad_len, nonce,
+ nonce_len, key);
+ KUNIT_ASSERT_EQ(test, 0, err);
+ }
+
+ for (size_t i = 0; i < ARRAY_SIZE(data_lens_to_test); i++) {
+ size_t data_len = data_lens_to_test[i];
+ size_t num_iters = 10000000 / (data_len + 128);
+ u64 t_enc, t_dec;
+ bool ok = true;
+
+ KUNIT_ASSERT_LE(test, data_len, max_data_len);
+
+ preempt_disable();
+
+ t_enc = ktime_get_ns();
+ for (size_t j = 0; j < num_iters; j++) {
+ err = AEAD_ENCRYPT(ct, pt, data_len, tag, ad, ad_len,
+ nonce, nonce_len, key);
+ ok &= (err == 0);
+ }
+ t_enc = ktime_get_ns() - t_enc;
+
+ t_dec = ktime_get_ns();
+ for (size_t j = 0; j < num_iters; j++) {
+ err = AEAD_DECRYPT(pt, ct, data_len, tag, ad, ad_len,
+ nonce, nonce_len, key);
+ ok &= (err == 0);
+ }
+ t_dec = ktime_get_ns() - t_dec;
+
+ preempt_enable();
+
+ KUNIT_ASSERT_TRUE_MSG(test, ok, "data_len=%zu", data_len);
+
+ kunit_info(test, "data_len=%zu: enc %llu MB/s, dec %llu MB/s",
+ data_len,
+ div64_u64((u64)data_len * num_iters * 1000,
+ t_enc ?: 1),
+ div64_u64((u64)data_len * num_iters * 1000,
+ t_dec ?: 1));
+ }
+}
+
+/* clang-format off */
+#define AEAD_KUNIT_CASES \
+ KUNIT_CASE(test_aead_all_key_lens), \
+ KUNIT_CASE(test_aead_all_nonce_lens), \
+ KUNIT_CASE(test_aead_all_tag_lens), \
+ KUNIT_CASE(test_aead_incremental_updates), \
+ KUNIT_CASE(test_aead_data_buffer_overruns), \
+ KUNIT_CASE(test_aead_alignment_consistency), \
+ KUNIT_CASE(test_aead_inplace), \
+ KUNIT_CASE(test_aead_monte_carlo), \
+ KUNIT_CASE(test_aead_interrupt_context), \
+ KUNIT_CASE(benchmark_aead)
diff --git a/lib/crypto/tests/aes_cbc_macs_kunit.c b/lib/crypto/tests/aes_cbc_macs_kunit.c
index ae3745212f03..6afdb3a04c17 100644
--- a/lib/crypto/tests/aes_cbc_macs_kunit.c
+++ b/lib/crypto/tests/aes_cbc_macs_kunit.c
@@ -34,18 +34,9 @@ static void aes_cmac_withtestkey(const u8 *data, size_t data_len,
static int aes_cbc_macs_suite_init(struct kunit_suite *suite)
{
u8 raw_key[AES_KEYSIZE_256];
- int err;
rand_bytes_seeded_from_len(raw_key, sizeof(raw_key));
- err = aes_cmac_preparekey(&test_key, raw_key, sizeof(raw_key));
- if (err)
- return err;
- return hash_suite_init(suite);
-}
-
-static void aes_cbc_macs_suite_exit(struct kunit_suite *suite)
-{
- hash_suite_exit(suite);
+ return aes_cmac_preparekey(&test_key, raw_key, sizeof(raw_key));
}
/* Verify compatibility of the AES-CMAC implementation with RFC 4493. */
@@ -218,7 +209,6 @@ static struct kunit_suite aes_cbc_macs_test_suite = {
.name = "aes_cbc_macs",
.test_cases = aes_cbc_macs_test_cases,
.suite_init = aes_cbc_macs_suite_init,
- .suite_exit = aes_cbc_macs_suite_exit,
};
kunit_test_suite(aes_cbc_macs_test_suite);
diff --git a/lib/crypto/tests/aes_ccm_kunit.c b/lib/crypto/tests/aes_ccm_kunit.c
new file mode 100644
index 000000000000..e8f2b3446017
--- /dev/null
+++ b/lib/crypto/tests/aes_ccm_kunit.c
@@ -0,0 +1,356 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * KUnit test suite for AES-CCM
+ *
+ * Copyright 2026 Google LLC
+ */
+#include <crypto/aes-ccm.h>
+#include <crypto/blake2s.h>
+#include "test-utils.h"
+
+/* AES-CCM test vectors from external sources */
+static const struct aes_ccm_testvec {
+ const char *name;
+ const char *key;
+ size_t key_len;
+ const char *nonce;
+ size_t nonce_len;
+ const char *ad;
+ size_t ad_len;
+ const char *ptext;
+ const char *ctext;
+ size_t data_len;
+ const char *tag;
+ size_t tag_len;
+} aes_ccm_testvecs[] = {
+ {
+ .name = "RFC 3610 Packet Vector #1",
+ .key = "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
+ .key_len = 16,
+ .nonce = "\x00\x00\x00\x03\x02\x01\x00\xa0"
+ "\xa1\xa2\xa3\xa4\xa5",
+ .nonce_len = 13,
+ .ad = "\x00\x01\x02\x03\x04\x05\x06\x07",
+ .ad_len = 8,
+ .ptext = "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e",
+ .ctext = "\x58\x8c\x97\x9a\x61\xc6\x63\xd2"
+ "\xf0\x66\xd0\xc2\xc0\xf9\x89\x80"
+ "\x6d\x5f\x6b\x61\xda\xc3\x84",
+ .data_len = 23,
+ .tag = "\x17\xe8\xd1\x2c\xfd\xf9\x26\xe0",
+ .tag_len = 8,
+ },
+ {
+ .name = "RFC 3610 Packet Vector #5",
+ .key = "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
+ .key_len = 16,
+ .nonce = "\x00\x00\x00\x07\x06\x05\x04\xa0"
+ "\xa1\xa2\xa3\xa4\xa5",
+ .nonce_len = 13,
+ .ad = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b",
+ .ad_len = 12,
+ .ptext = "\x0c\x0d\x0e\x0f\x10\x11\x12\x13"
+ "\x14\x15\x16\x17\x18\x19\x1a\x1b"
+ "\x1c\x1d\x1e\x1f",
+ .ctext = "\xdc\xf1\xfb\x7b\x5d\x9e\x23\xfb"
+ "\x9d\x4e\x13\x12\x53\x65\x8a\xd8"
+ "\x6e\xbd\xca\x3e",
+ .data_len = 20,
+ .tag = "\x51\xe8\x3f\x07\x7d\x9c\x2d\x93",
+ .tag_len = 8,
+ },
+ {
+ .name = "RFC 3610 Packet Vector #9",
+ .key = "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
+ .key_len = 16,
+ .nonce = "\x00\x00\x00\x0b\x0a\x09\x08\xa0"
+ "\xa1\xa2\xa3\xa4\xa5",
+ .nonce_len = 13,
+ .ad = "\x00\x01\x02\x03\x04\x05\x06\x07",
+ .ad_len = 8,
+ .ptext = "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20",
+ .ctext = "\x82\x53\x1a\x60\xcc\x24\x94\x5a"
+ "\x4b\x82\x79\x18\x1a\xb5\xc8\x4d"
+ "\xf2\x1c\xe7\xf9\xb7\x3f\x42\xe1"
+ "\x97",
+ .data_len = 25,
+ .tag = "\xea\x9c\x07\xe5\x6b\x5e\xb1\x7e"
+ "\x5f\x4e",
+ .tag_len = 10,
+ },
+ {
+ .name = "NIST SP 800-38C Example 1",
+ .key = "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f",
+ .key_len = 16,
+ .nonce = "\x10\x11\x12\x13\x14\x15\x16",
+ .nonce_len = 7,
+ .ad = "\x00\x01\x02\x03\x04\x05\x06\x07",
+ .ad_len = 8,
+ .ptext = "\x20\x21\x22\x23",
+ .ctext = "\x71\x62\x01\x5b",
+ .data_len = 4,
+ .tag = "\x4d\xac\x25\x5d",
+ .tag_len = 4,
+ },
+ {
+ .name = "NIST SP 800-38C Example 2",
+ .key = "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f",
+ .key_len = 16,
+ .nonce = "\x10\x11\x12\x13\x14\x15\x16\x17",
+ .nonce_len = 8,
+ .ad = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+ .ad_len = 16,
+ .ptext = "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f",
+ .ctext = "\xd2\xa1\xf0\xe0\x51\xea\x5f\x62"
+ "\x08\x1a\x77\x92\x07\x3d\x59\x3d",
+ .data_len = 16,
+ .tag = "\x1f\xc6\x4f\xbf\xac\xcd",
+ .tag_len = 6,
+ },
+ {
+ .name = "NIST SP 800-38C Example 3",
+ .key = "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f",
+ .key_len = 16,
+ .nonce = "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b",
+ .nonce_len = 12,
+ .ad = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13",
+ .ad_len = 20,
+ .ptext = "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37",
+ .ctext = "\xe3\xb2\x01\xa9\xf5\xb7\x1a\x7a"
+ "\x9b\x1c\xea\xec\xcd\x97\xe7\x0b"
+ "\x61\x76\xaa\xd9\xa4\x42\x8a\xa5",
+ .data_len = 24,
+ .tag = "\x48\x43\x92\xfb\xc1\xb0\x99\x51",
+ .tag_len = 8,
+ },
+};
+
+static void test_aes_ccm_one_test_vector(struct kunit *test,
+ const struct aes_ccm_testvec *tv)
+{
+ u8 *ctext = alloc_buf(test, tv->data_len);
+ u8 *decrypted = alloc_buf(test, tv->data_len);
+ u8 *tag = alloc_buf(test, tv->tag_len);
+ struct aes_ccm_key key;
+ int err;
+
+ err = aes_ccm_preparekey(&key, tv->key, tv->key_len, tv->tag_len);
+ KUNIT_ASSERT_EQ_MSG(test, 0, err, "Failed to prepare key for %s",
+ tv->name);
+
+ err = aes_ccm_encrypt(ctext, tv->ptext, tv->data_len, tag, tv->ad,
+ tv->ad_len, tv->nonce, tv->nonce_len, &key);
+ KUNIT_ASSERT_EQ_MSG(test, 0, err, "Encryption failed for %s", tv->name);
+ KUNIT_ASSERT_MEMEQ_MSG(test, tv->ctext, ctext, tv->data_len,
+ "Wrong ciphertext for %s", tv->name);
+ KUNIT_ASSERT_MEMEQ_MSG(test, tag, tv->tag, tv->tag_len,
+ "Wrong tag for %s", tv->name);
+
+ err = aes_ccm_decrypt(decrypted, ctext, tv->data_len, tag, tv->ad,
+ tv->ad_len, tv->nonce, tv->nonce_len, &key);
+ KUNIT_ASSERT_EQ_MSG(test, 0, err, "Decryption failed for %s", tv->name);
+ KUNIT_ASSERT_MEMEQ_MSG(test, tv->ptext, decrypted, tv->data_len,
+ "Wrong plaintext for %s", tv->name);
+}
+
+static void test_aes_ccm_test_vectors(struct kunit *test)
+{
+ for (size_t i = 0; i < ARRAY_SIZE(aes_ccm_testvecs); i++)
+ test_aes_ccm_one_test_vector(test, &aes_ccm_testvecs[i]);
+}
+
+/*
+ * Test NIST SP 800-38C Example 4, which uses a deterministically-generated
+ * 65536-byte associated data string.
+ */
+static void test_aes_ccm_nist_sp800_38c_example4(struct kunit *test)
+{
+ struct aes_ccm_testvec tv = {
+ .name = "NIST SP 800-38C Example 4",
+ .key_len = 16,
+ .nonce_len = 13,
+ .ad_len = 65536,
+ .ctext = "\x69\x91\x5d\xad\x1e\x84\xc6\x37"
+ "\x6a\x68\xc2\x96\x7e\x4d\xab\x61"
+ "\x5a\xe0\xfd\x1f\xae\xc4\x4c\xc4"
+ "\x84\x82\x85\x29\x46\x3c\xcf\x72",
+ .data_len = 32,
+ .tag = "\xb4\xac\x6b\xec\x93\xe8\x59\x8e"
+ "\x7f\x0d\xad\xbc\xea\x5b",
+ .tag_len = 14,
+ };
+ u8 *key, *nonce, *ad, *ptext;
+
+ key = alloc_buf(test, tv.key_len);
+ for (size_t i = 0; i < tv.key_len; i++)
+ key[i] = 0x40 + i;
+
+ nonce = alloc_guarded_buf(test, tv.nonce_len);
+ for (size_t i = 0; i < tv.nonce_len; i++)
+ nonce[i] = 0x10 + i;
+
+ ad = alloc_guarded_buf(test, tv.ad_len);
+ for (size_t i = 0; i < tv.ad_len; i++)
+ ad[i] = (u8)i;
+
+ ptext = alloc_guarded_buf(test, tv.data_len);
+ for (size_t i = 0; i < tv.data_len; i++)
+ ptext[i] = 0x20 + i;
+
+ tv.key = key;
+ tv.nonce = nonce;
+ tv.ad = ad;
+ tv.ptext = ptext;
+
+ test_aes_ccm_one_test_vector(test, &tv);
+}
+
+static const size_t aes_ccm_valid_key_lens[] = { 16, 24, 32 };
+#define AEAD_MAX_KEY_LEN 32
+#define AEAD_VALID_KEY_LENS aes_ccm_valid_key_lens
+
+static const size_t aes_ccm_valid_nonce_lens[] = { 7, 8, 9, 10, 11, 12, 13 };
+#define AEAD_MAX_NONCE_LEN 13
+#define AEAD_VALID_NONCE_LENS aes_ccm_valid_nonce_lens
+
+static const size_t aes_ccm_valid_tag_lens[] = { 4, 6, 8, 10, 12, 14, 16 };
+#define AEAD_MAX_TAG_LEN 16
+#define AEAD_VALID_TAG_LENS aes_ccm_valid_tag_lens
+
+#define AEAD_KEY aes_ccm_key
+#define AEAD_CTX aes_ccm_ctx
+#define AEAD_PREPAREKEY aes_ccm_preparekey
+#define AEAD_ENCRYPT aes_ccm_encrypt
+#define AEAD_DECRYPT aes_ccm_decrypt
+
+#define AEAD_INIT aes_ccm_init
+#define AEAD_AUTH_UPDATE aes_ccm_auth_update
+#define AEAD_ENCRYPT_UPDATE aes_ccm_encrypt_update
+#define AEAD_DECRYPT_UPDATE aes_ccm_decrypt_update
+#define AEAD_ENCRYPT_FINAL aes_ccm_encrypt_final
+#define AEAD_DECRYPT_FINAL aes_ccm_decrypt_final
+
+/* This value was generated by gen-aead-testvecs.py. */
+static const u8 aes_ccm_monte_carlo_checksum[BLAKE2S_HASH_SIZE] = {
+ 0x70, 0x1c, 0xde, 0xa4, 0xe2, 0x03, 0x50, 0xb2, 0xf5, 0x9e, 0x61,
+ 0x66, 0xe4, 0xe5, 0x13, 0x1a, 0x00, 0x95, 0x34, 0x03, 0xb7, 0x61,
+ 0x2c, 0xdb, 0xc3, 0x15, 0x36, 0x84, 0x93, 0x7f, 0xb4, 0x5b,
+};
+#define AEAD_MONTE_CARLO_CHECKSUM aes_ccm_monte_carlo_checksum
+
+#include "aead-test-template.h"
+
+/*
+ * Test that for each AES-CCM nonce length, the message length is validated
+ * against the correct corresponding maximum message length.
+ */
+static void test_aes_ccm_data_len_too_large(struct kunit *test)
+{
+ static const struct {
+ size_t nonce_len;
+ u64 max_data_len;
+ } lens[] = {
+ /* clang-format off */
+ { 7, 0xffffffffffffffff }, /* U64_MAX */
+ { 8, 0xffffffffffffff },
+ { 9, 0xffffffffffff },
+ { 10, 0xffffffffff },
+ { 11, 0xffffffff },
+ { 12, 0xffffff },
+ { 13, 0xffff },
+ /* clang-format on */
+ };
+ u8 nonce[13] = {};
+ u8 raw_key[AES_KEYSIZE_256] = {};
+ int err;
+ struct aes_ccm_key *key = alloc_buf(test, sizeof(*key));
+ struct aes_ccm_ctx ctx;
+
+ err = aes_ccm_preparekey(key, raw_key, sizeof(raw_key), 16);
+ KUNIT_ASSERT_EQ(test, 0, err);
+
+ for (size_t i = 0; i < ARRAY_SIZE(lens); i++) {
+ size_t nonce_len = lens[i].nonce_len;
+ u64 max_data_len = lens[i].max_data_len;
+
+ /* data_len <= max_data_len should be accepted. */
+ err = aes_ccm_init(&ctx, 0, 0, nonce, nonce_len, key);
+ KUNIT_ASSERT_EQ_MSG(
+ test, 0, err,
+ "data_len=0 wasn't accepted with nonce_len=%zu",
+ nonce_len);
+ err = aes_ccm_init(&ctx, max_data_len, 0, nonce, nonce_len,
+ key);
+ KUNIT_ASSERT_EQ_MSG(
+ test, 0, err,
+ "data_len=%llu wasn't accepted with nonce_len=%zu",
+ max_data_len, nonce_len);
+
+ /* data_len > max_data_len should be rejected. */
+ if (max_data_len == U64_MAX)
+ continue;
+ err = aes_ccm_init(&ctx, max_data_len + 1, 0, nonce, nonce_len,
+ key);
+ KUNIT_ASSERT_EQ_MSG(
+ test, -EOVERFLOW, err,
+ "data_len=%llu wasn't rejected with -EOVERFLOW with nonce_len=%zu (aes_ccm_init)",
+ max_data_len + 1, nonce_len);
+ if (max_data_len + 1 <= SIZE_MAX) {
+ err = aes_ccm_encrypt(NULL, NULL, max_data_len + 1,
+ NULL, NULL, 0, nonce, nonce_len,
+ key);
+ KUNIT_ASSERT_EQ_MSG(
+ test, -EOVERFLOW, err,
+ "data_len=%llu wasn't rejected with -EOVERFLOW with nonce_len=%zu (aes_ccm_encrypt)",
+ max_data_len + 1, nonce_len);
+ err = aes_ccm_decrypt(NULL, NULL, max_data_len + 1,
+ NULL, NULL, 0, nonce, nonce_len,
+ key);
+ KUNIT_ASSERT_EQ_MSG(
+ test, -EOVERFLOW, err,
+ "data_len=%llu wasn't rejected with -EOVERFLOW with nonce_len=%zu (aes_ccm_decrypt)",
+ max_data_len + 1, nonce_len);
+ }
+ err = aes_ccm_init(&ctx, U64_MAX, 0, nonce, nonce_len, key);
+ KUNIT_ASSERT_EQ_MSG(
+ test, -EOVERFLOW, err,
+ "data_len=U64_MAX wasn't rejected with -EOVERFLOW with nonce_len=%zu (aes_ccm_init)",
+ nonce_len);
+ }
+}
+
+static struct kunit_case aes_ccm_test_cases[] = {
+ KUNIT_CASE(test_aes_ccm_test_vectors),
+ KUNIT_CASE(test_aes_ccm_nist_sp800_38c_example4),
+ KUNIT_CASE(test_aes_ccm_data_len_too_large),
+ AEAD_KUNIT_CASES,
+ {},
+};
+
+static struct kunit_suite aes_ccm_test_suite = {
+ .name = "aes_ccm",
+ .test_cases = aes_ccm_test_cases,
+};
+kunit_test_suite(aes_ccm_test_suite);
+
+MODULE_DESCRIPTION("KUnit tests and benchmark for AES-CCM");
+MODULE_LICENSE("GPL");
diff --git a/lib/crypto/tests/aes_gcm_kunit.c b/lib/crypto/tests/aes_gcm_kunit.c
new file mode 100644
index 000000000000..6959d86b316a
--- /dev/null
+++ b/lib/crypto/tests/aes_gcm_kunit.c
@@ -0,0 +1,472 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * KUnit test suite for AES-GCM
+ *
+ * Copyright 2026 Google LLC
+ */
+#include <crypto/aes-gcm.h>
+#include <crypto/blake2s.h>
+#include "test-utils.h"
+
+/* The kernel's AES-GCM implementation supports only 12-byte nonces. */
+#define AES_GCM_NONCE_LEN 12
+
+/*
+ * AES-GCM test vectors from the original paper "The Galois/Counter Mode of
+ * Operation (GCM)" by McGrew & Viega. Vectors with nonce lengths other than 12
+ * bytes are excluded.
+ */
+static const struct aes_gcm_testvec {
+ const char *name;
+ const char *key;
+ size_t key_len;
+ const char *nonce;
+ size_t nonce_len;
+ const char *ad;
+ size_t ad_len;
+ const char *ptext;
+ const char *ctext;
+ size_t data_len;
+ const char *tag;
+ size_t tag_len;
+} aes_gcm_testvecs[] = {
+ /* AES-128 Test Vectors */
+ {
+ .name = "McGrew & Viega Test Case 1",
+ .key = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .key_len = 16,
+ .nonce = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00",
+ .nonce_len = 12,
+ .ptext = "",
+ .ctext = "",
+ .data_len = 0,
+ .ad = "",
+ .ad_len = 0,
+ .tag = "\x58\xe2\xfc\xce\xfa\x7e\x30\x61"
+ "\x36\x7f\x1d\x57\xa4\xe7\x45\x5a",
+ .tag_len = 16,
+ },
+ {
+ .name = "McGrew & Viega Test Case 2",
+ .key = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .key_len = 16,
+ .nonce = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00",
+ .nonce_len = 12,
+ .ptext = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .ctext = "\x03\x88\xda\xce\x60\xb6\xa3\x92"
+ "\xf3\x28\xc2\xb9\x71\xb2\xfe\x78",
+ .data_len = 16,
+ .ad = "",
+ .ad_len = 0,
+ .tag = "\xab\x6e\x47\xd4\x2c\xec\x13\xbd"
+ "\xf5\x3a\x67\xb2\x12\x57\xbd\xdf",
+ .tag_len = 16,
+ },
+ {
+ .name = "McGrew & Viega Test Case 3",
+ .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
+ "\x6d\x6a\x8f\x94\x67\x30\x83\x08",
+ .key_len = 16,
+ .nonce = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
+ "\xde\xca\xf8\x88",
+ .nonce_len = 12,
+ .ptext = "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
+ "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
+ "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
+ "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
+ "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
+ "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
+ "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
+ "\xba\x63\x7b\x39\x1a\xaf\xd2\x55",
+ .ctext = "\x42\x83\x1e\xc2\x21\x77\x74\x24"
+ "\x4b\x72\x21\xb7\x84\xd0\xd4\x9c"
+ "\xe3\xaa\x21\x2f\x2c\x02\xa4\xe0"
+ "\x35\xc1\x7e\x23\x29\xac\xa1\x2e"
+ "\x21\xd5\x14\xb2\x54\x66\x93\x1c"
+ "\x7d\x8f\x6a\x5a\xac\x84\xaa\x05"
+ "\x1b\xa3\x0b\x39\x6a\x0a\xac\x97"
+ "\x3d\x58\xe0\x91\x47\x3f\x59\x85",
+ .data_len = 64,
+ .ad = "",
+ .ad_len = 0,
+ .tag = "\x4d\x5c\x2a\xf3\x27\xcd\x64\xa6"
+ "\x2c\xf3\x5a\xbd\x2b\xa6\xfa\xb4",
+ .tag_len = 16,
+ },
+ {
+ .name = "McGrew & Viega Test Case 4",
+ .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
+ "\x6d\x6a\x8f\x94\x67\x30\x83\x08",
+ .key_len = 16,
+ .nonce = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
+ "\xde\xca\xf8\x88",
+ .nonce_len = 12,
+ .ptext = "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
+ "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
+ "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
+ "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
+ "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
+ "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
+ "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
+ "\xba\x63\x7b\x39",
+ .ctext = "\x42\x83\x1e\xc2\x21\x77\x74\x24"
+ "\x4b\x72\x21\xb7\x84\xd0\xd4\x9c"
+ "\xe3\xaa\x21\x2f\x2c\x02\xa4\xe0"
+ "\x35\xc1\x7e\x23\x29\xac\xa1\x2e"
+ "\x21\xd5\x14\xb2\x54\x66\x93\x1c"
+ "\x7d\x8f\x6a\x5a\xac\x84\xaa\x05"
+ "\x1b\xa3\x0b\x39\x6a\x0a\xac\x97"
+ "\x3d\x58\xe0\x91",
+ .data_len = 60,
+ .ad = "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
+ "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
+ "\xab\xad\xda\xd2",
+ .ad_len = 20,
+ .tag = "\x5b\xc9\x4f\xbc\x32\x21\xa5\xdb"
+ "\x94\xfa\xe9\x5a\xe7\x12\x1a\x47",
+ .tag_len = 16,
+ },
+
+ /* AES-192 Test Vectors */
+ {
+ .name = "McGrew & Viega Test Case 7",
+ .key = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .key_len = 24,
+ .nonce = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00",
+ .nonce_len = 12,
+ .ptext = "",
+ .ctext = "",
+ .data_len = 0,
+ .ad = "",
+ .ad_len = 0,
+ .tag = "\xcd\x33\xb2\x8a\xc7\x73\xf7\x4b"
+ "\xa0\x0e\xd1\xf3\x12\x57\x24\x35",
+ .tag_len = 16,
+ },
+ {
+ .name = "McGrew & Viega Test Case 8",
+ .key = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .key_len = 24,
+ .nonce = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00",
+ .nonce_len = 12,
+ .ptext = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .ctext = "\x98\xe7\x24\x7c\x07\xf0\xfe\x41"
+ "\x1c\x26\x7e\x43\x84\xb0\xf6\x00",
+ .data_len = 16,
+ .ad = "",
+ .ad_len = 0,
+ .tag = "\x2f\xf5\x8d\x80\x03\x39\x27\xab"
+ "\x8e\xf4\xd4\x58\x75\x14\xf0\xfb",
+ .tag_len = 16,
+ },
+ {
+ .name = "McGrew & Viega Test Case 9",
+ .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
+ "\x6d\x6a\x8f\x94\x67\x30\x83\x08"
+ "\xfe\xff\xe9\x92\x86\x65\x73\x1c",
+ .key_len = 24,
+ .nonce = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
+ "\xde\xca\xf8\x88",
+ .nonce_len = 12,
+ .ptext = "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
+ "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
+ "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
+ "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
+ "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
+ "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
+ "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
+ "\xba\x63\x7b\x39\x1a\xaf\xd2\x55",
+ .ctext = "\x39\x80\xca\x0b\x3c\x00\xe8\x41"
+ "\xeb\x06\xfa\xc4\x87\x2a\x27\x57"
+ "\x85\x9e\x1c\xea\xa6\xef\xd9\x84"
+ "\x62\x85\x93\xb4\x0c\xa1\xe1\x9c"
+ "\x7d\x77\x3d\x00\xc1\x44\xc5\x25"
+ "\xac\x61\x9d\x18\xc8\x4a\x3f\x47"
+ "\x18\xe2\x44\x8b\x2f\xe3\x24\xd9"
+ "\xcc\xda\x27\x10\xac\xad\xe2\x56",
+ .data_len = 64,
+ .ad = "",
+ .ad_len = 0,
+ .tag = "\x99\x24\xa7\xc8\x58\x73\x36\xbf"
+ "\xb1\x18\x02\x4d\xb8\x67\x4a\x14",
+ .tag_len = 16,
+ },
+ {
+ .name = "McGrew & Viega Test Case 10",
+ .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
+ "\x6d\x6a\x8f\x94\x67\x30\x83\x08"
+ "\xfe\xff\xe9\x92\x86\x65\x73\x1c",
+ .key_len = 24,
+ .nonce = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
+ "\xde\xca\xf8\x88",
+ .nonce_len = 12,
+ .ptext = "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
+ "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
+ "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
+ "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
+ "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
+ "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
+ "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
+ "\xba\x63\x7b\x39",
+ .ctext = "\x39\x80\xca\x0b\x3c\x00\xe8\x41"
+ "\xeb\x06\xfa\xc4\x87\x2a\x27\x57"
+ "\x85\x9e\x1c\xea\xa6\xef\xd9\x84"
+ "\x62\x85\x93\xb4\x0c\xa1\xe1\x9c"
+ "\x7d\x77\x3d\x00\xc1\x44\xc5\x25"
+ "\xac\x61\x9d\x18\xc8\x4a\x3f\x47"
+ "\x18\xe2\x44\x8b\x2f\xe3\x24\xd9"
+ "\xcc\xda\x27\x10",
+ .data_len = 60,
+ .ad = "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
+ "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
+ "\xab\xad\xda\xd2",
+ .ad_len = 20,
+ .tag = "\x25\x19\x49\x8e\x80\xf1\x47\x8f"
+ "\x37\xba\x55\xbd\x6d\x27\x61\x8c",
+ .tag_len = 16,
+ },
+
+ /* AES-256 Test Vectors */
+ {
+ .name = "McGrew & Viega Test Case 13",
+ .key = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .key_len = 32,
+ .nonce = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00",
+ .nonce_len = 12,
+ .ptext = "",
+ .ctext = "",
+ .data_len = 0,
+ .ad = "",
+ .ad_len = 0,
+ .tag = "\x53\x0f\x8a\xfb\xc7\x45\x36\xb9"
+ "\xa9\x63\xb4\xf1\xc4\xcb\x73\x8b",
+ .tag_len = 16,
+ },
+ {
+ .name = "McGrew & Viega Test Case 14",
+ .key = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .key_len = 32,
+ .nonce = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00",
+ .nonce_len = 12,
+ .ptext = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .ctext = "\xce\xa7\x40\x3d\x4d\x60\x6b\x6e"
+ "\x07\x4e\xc5\xd3\xba\xf3\x9d\x18",
+ .data_len = 16,
+ .ad = "",
+ .ad_len = 0,
+ .tag = "\xd0\xd1\xc8\xa7\x99\x99\x6b\xf0"
+ "\x26\x5b\x98\xb5\xd4\x8a\xb9\x19",
+ .tag_len = 16,
+ },
+ {
+ .name = "McGrew & Viega Test Case 15",
+ .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
+ "\x6d\x6a\x8f\x94\x67\x30\x83\x08"
+ "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
+ "\x6d\x6a\x8f\x94\x67\x30\x83\x08",
+ .key_len = 32,
+ .nonce = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
+ "\xde\xca\xf8\x88",
+ .nonce_len = 12,
+ .ptext = "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
+ "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
+ "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
+ "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
+ "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
+ "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
+ "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
+ "\xba\x63\x7b\x39\x1a\xaf\xd2\x55",
+ .ctext = "\x52\x2d\xc1\xf0\x99\x56\x7d\x07"
+ "\xf4\x7f\x37\xa3\x2a\x84\x42\x7d"
+ "\x64\x3a\x8c\xdc\xbf\xe5\xc0\xc9"
+ "\x75\x98\xa2\xbd\x25\x55\xd1\xaa"
+ "\x8c\xb0\x8e\x48\x59\x0d\xbb\x3d"
+ "\xa7\xb0\x8b\x10\x56\x82\x88\x38"
+ "\xc5\xf6\x1e\x63\x93\xba\x7a\x0a"
+ "\xbc\xc9\xf6\x62\x89\x80\x15\xad",
+ .data_len = 64,
+ .ad = "",
+ .ad_len = 0,
+ .tag = "\xb0\x94\xda\xc5\xd9\x34\x71\xbd"
+ "\xec\x1a\x50\x22\x70\xe3\xcc\x6c",
+ .tag_len = 16,
+ },
+ {
+ .name = "McGrew & Viega Test Case 16",
+ .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
+ "\x6d\x6a\x8f\x94\x67\x30\x83\x08"
+ "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
+ "\x6d\x6a\x8f\x94\x67\x30\x83\x08",
+ .key_len = 32,
+ .nonce = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
+ "\xde\xca\xf8\x88",
+ .nonce_len = 12,
+ .ptext = "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
+ "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
+ "\x86\xa7\xa9\x53\x15\x34\xf7\xda"
+ "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
+ "\x1c\x3c\x0c\x95\x95\x68\x09\x53"
+ "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
+ "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
+ "\xba\x63\x7b\x39",
+ .ctext = "\x52\x2d\xc1\xf0\x99\x56\x7d\x07"
+ "\xf4\x7f\x37\xa3\x2a\x84\x42\x7d"
+ "\x64\x3a\x8c\xdc\xbf\xe5\xc0\xc9"
+ "\x75\x98\xa2\xbd\x25\x55\xd1\xaa"
+ "\x8c\xb0\x8e\x48\x59\x0d\xbb\x3d"
+ "\xa7\xb0\x8b\x10\x56\x82\x88\x38"
+ "\xc5\xf6\x1e\x63\x93\xba\x7a\x0a"
+ "\xbc\xc9\xf6\x62",
+ .data_len = 60,
+ .ad = "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
+ "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
+ "\xab\xad\xda\xd2",
+ .ad_len = 20,
+ .tag = "\x76\xfc\x6e\xce\x0f\x4e\x17\x68"
+ "\xcd\xdf\x88\x53\xbb\x2d\x55\x1b",
+ .tag_len = 16,
+ },
+};
+
+static void test_aes_gcm_one_test_vector(struct kunit *test,
+ const struct aes_gcm_testvec *tv)
+{
+ u8 *ctext = alloc_buf(test, tv->data_len);
+ u8 *decrypted = alloc_buf(test, tv->data_len);
+ u8 *tag = alloc_buf(test, tv->tag_len);
+ struct aes_gcm_key key;
+ int err;
+
+ KUNIT_ASSERT_EQ(test, AES_GCM_NONCE_LEN, tv->nonce_len);
+
+ err = aes_gcm_preparekey(&key, tv->key, tv->key_len, tv->tag_len);
+ KUNIT_ASSERT_EQ_MSG(test, 0, err, "Failed to prepare key for %s",
+ tv->name);
+
+ aes_gcm_encrypt(ctext, tv->ptext, tv->data_len, tag, tv->ad, tv->ad_len,
+ tv->nonce, &key);
+ KUNIT_ASSERT_MEMEQ_MSG(test, tv->ctext, ctext, tv->data_len,
+ "Wrong ciphertext for %s", tv->name);
+ KUNIT_ASSERT_MEMEQ_MSG(test, tag, tv->tag, tv->tag_len,
+ "Wrong tag for %s", tv->name);
+
+ err = aes_gcm_decrypt(decrypted, ctext, tv->data_len, tag, tv->ad,
+ tv->ad_len, tv->nonce, &key);
+ KUNIT_ASSERT_EQ_MSG(test, 0, err, "Decryption failed for %s", tv->name);
+ KUNIT_ASSERT_MEMEQ_MSG(test, tv->ptext, decrypted, tv->data_len,
+ "Wrong plaintext for %s", tv->name);
+}
+
+static void test_aes_gcm_test_vectors(struct kunit *test)
+{
+ for (size_t i = 0; i < ARRAY_SIZE(aes_gcm_testvecs); i++)
+ test_aes_gcm_one_test_vector(test, &aes_gcm_testvecs[i]);
+}
+
+static int aes_gcm_init_test(struct aes_gcm_ctx *ctx, u64 data_len, u64 ad_len,
+ const u8 *nonce, size_t nonce_len,
+ const struct aes_gcm_key *key)
+{
+ if (nonce_len != AES_GCM_NONCE_LEN)
+ return -EINVAL;
+ /*
+ * Ignore data_len and ad_len. Incremental AES-GCM doesn't need them at
+ * initialization time.
+ */
+ aes_gcm_init(ctx, nonce, key);
+ return 0;
+}
+
+static int aes_gcm_encrypt_test(u8 *dst, const u8 *src, size_t data_len,
+ u8 *authtag, const u8 *ad, size_t ad_len,
+ const u8 *nonce, size_t nonce_len,
+ const struct aes_gcm_key *key)
+{
+ if (nonce_len != AES_GCM_NONCE_LEN)
+ return -EINVAL;
+ /* aes_gcm_encrypt() returns void. */
+ aes_gcm_encrypt(dst, src, data_len, authtag, ad, ad_len, nonce, key);
+ return 0;
+}
+
+static int aes_gcm_decrypt_test(u8 *dst, const u8 *src, size_t data_len,
+ const u8 *authtag, const u8 *ad, size_t ad_len,
+ const u8 *nonce, size_t nonce_len,
+ const struct aes_gcm_key *key)
+{
+ if (nonce_len != AES_GCM_NONCE_LEN)
+ return -EINVAL;
+ return aes_gcm_decrypt(dst, src, data_len, authtag, ad, ad_len, nonce,
+ key);
+}
+
+static const size_t aes_gcm_valid_key_lens[] = { 16, 24, 32 };
+#define AEAD_MAX_KEY_LEN 32
+#define AEAD_VALID_KEY_LENS aes_gcm_valid_key_lens
+
+static const size_t aes_gcm_valid_nonce_lens[] = { AES_GCM_NONCE_LEN };
+#define AEAD_MAX_NONCE_LEN AES_GCM_NONCE_LEN
+#define AEAD_VALID_NONCE_LENS aes_gcm_valid_nonce_lens
+
+static const size_t aes_gcm_valid_tag_lens[] = { 4, 8, 12, 13, 14, 15, 16 };
+#define AEAD_MAX_TAG_LEN 16
+#define AEAD_VALID_TAG_LENS aes_gcm_valid_tag_lens
+
+#define AEAD_KEY aes_gcm_key
+#define AEAD_CTX aes_gcm_ctx
+#define AEAD_PREPAREKEY aes_gcm_preparekey
+#define AEAD_ENCRYPT aes_gcm_encrypt_test
+#define AEAD_DECRYPT aes_gcm_decrypt_test
+
+#define AEAD_INIT aes_gcm_init_test
+#define AEAD_AUTH_UPDATE aes_gcm_auth_update
+#define AEAD_ENCRYPT_UPDATE aes_gcm_encrypt_update
+#define AEAD_DECRYPT_UPDATE aes_gcm_decrypt_update
+#define AEAD_ENCRYPT_FINAL aes_gcm_encrypt_final
+#define AEAD_DECRYPT_FINAL aes_gcm_decrypt_final
+
+/* This value was generated by gen-aead-testvecs.py. */
+static const u8 aes_gcm_monte_carlo_checksum[BLAKE2S_HASH_SIZE] = {
+ 0x6d, 0xd0, 0x6e, 0x6b, 0xde, 0x3e, 0x92, 0x9f, 0xae, 0x1f, 0xf1,
+ 0x84, 0x99, 0x5a, 0x9e, 0x7b, 0xfe, 0x20, 0x9e, 0x22, 0x7c, 0x5f,
+ 0x15, 0xb3, 0x59, 0x89, 0xd0, 0xb7, 0x74, 0x5d, 0xd2, 0xa5,
+};
+#define AEAD_MONTE_CARLO_CHECKSUM aes_gcm_monte_carlo_checksum
+
+#include "aead-test-template.h"
+
+static struct kunit_case aes_gcm_test_cases[] = {
+ KUNIT_CASE(test_aes_gcm_test_vectors),
+ AEAD_KUNIT_CASES,
+ {},
+};
+
+static struct kunit_suite aes_gcm_test_suite = {
+ .name = "aes_gcm",
+ .test_cases = aes_gcm_test_cases,
+};
+kunit_test_suite(aes_gcm_test_suite);
+
+MODULE_DESCRIPTION("KUnit tests and benchmark for AES-GCM");
+MODULE_LICENSE("GPL");
diff --git a/lib/crypto/tests/blake2b_kunit.c b/lib/crypto/tests/blake2b_kunit.c
index bc0be7da1e76..e2ce6cf3a99d 100644
--- a/lib/crypto/tests/blake2b_kunit.c
+++ b/lib/crypto/tests/blake2b_kunit.c
@@ -41,9 +41,9 @@ static void blake2b_init_default(struct blake2b_ctx *ctx)
static void test_blake2b_all_key_and_hash_lens(struct kunit *test)
{
const size_t data_len = 100;
- u8 *data = &test_buf[0];
- u8 *key = data + data_len;
- u8 *hash = key + BLAKE2B_KEY_SIZE;
+ u8 *data = alloc_buf(test, data_len);
+ u8 *key = alloc_buf(test, BLAKE2B_KEY_SIZE);
+ u8 *hash = alloc_buf(test, BLAKE2B_HASH_SIZE);
struct blake2b_ctx main_ctx;
u8 main_hash[BLAKE2B_HASH_SIZE];
@@ -68,11 +68,13 @@ static void test_blake2b_all_key_and_hash_lens(struct kunit *test)
static void test_blake2b_with_guarded_key_buf(struct kunit *test)
{
const size_t data_len = 100;
+ u8 *data = alloc_buf(test, data_len);
+ u8 *guarded_key_buf = alloc_guarded_buf(test, BLAKE2B_KEY_SIZE);
- rand_bytes(test_buf, data_len);
+ rand_bytes(data, data_len);
for (int key_len = 0; key_len <= BLAKE2B_KEY_SIZE; key_len++) {
u8 key[BLAKE2B_KEY_SIZE];
- u8 *guarded_key = &test_buf[TEST_BUF_LEN - key_len];
+ u8 *guarded_key = &guarded_key_buf[BLAKE2B_KEY_SIZE - key_len];
u8 hash1[BLAKE2B_HASH_SIZE];
u8 hash2[BLAKE2B_HASH_SIZE];
struct blake2b_ctx ctx;
@@ -80,14 +82,13 @@ static void test_blake2b_with_guarded_key_buf(struct kunit *test)
rand_bytes(key, key_len);
memcpy(guarded_key, key, key_len);
- blake2b(key, key_len, test_buf, data_len,
- hash1, BLAKE2B_HASH_SIZE);
- blake2b(guarded_key, key_len, test_buf, data_len,
- hash2, BLAKE2B_HASH_SIZE);
+ blake2b(key, key_len, data, data_len, hash1, BLAKE2B_HASH_SIZE);
+ blake2b(guarded_key, key_len, data, data_len, hash2,
+ BLAKE2B_HASH_SIZE);
KUNIT_ASSERT_MEMEQ(test, hash1, hash2, BLAKE2B_HASH_SIZE);
blake2b_init_key(&ctx, BLAKE2B_HASH_SIZE, guarded_key, key_len);
- blake2b_update(&ctx, test_buf, data_len);
+ blake2b_update(&ctx, data, data_len);
blake2b_final(&ctx, hash2);
KUNIT_ASSERT_MEMEQ(test, hash1, hash2, BLAKE2B_HASH_SIZE);
}
@@ -100,14 +101,16 @@ static void test_blake2b_with_guarded_key_buf(struct kunit *test)
static void test_blake2b_with_guarded_out_buf(struct kunit *test)
{
const size_t data_len = 100;
+ u8 *data = alloc_buf(test, data_len);
+ u8 *out_buf = alloc_guarded_buf(test, BLAKE2B_HASH_SIZE);
- rand_bytes(test_buf, data_len);
+ rand_bytes(data, data_len);
for (int out_len = 1; out_len <= BLAKE2B_HASH_SIZE; out_len++) {
u8 hash[BLAKE2B_HASH_SIZE];
- u8 *guarded_hash = &test_buf[TEST_BUF_LEN - out_len];
+ u8 *guarded_hash = &out_buf[BLAKE2B_HASH_SIZE - out_len];
- blake2b(NULL, 0, test_buf, data_len, hash, out_len);
- blake2b(NULL, 0, test_buf, data_len, guarded_hash, out_len);
+ blake2b(NULL, 0, data, data_len, hash, out_len);
+ blake2b(NULL, 0, data, data_len, guarded_hash, out_len);
KUNIT_ASSERT_MEMEQ(test, hash, guarded_hash, out_len);
}
}
@@ -124,8 +127,6 @@ static struct kunit_case blake2b_test_cases[] = {
static struct kunit_suite blake2b_test_suite = {
.name = "blake2b",
.test_cases = blake2b_test_cases,
- .suite_init = hash_suite_init,
- .suite_exit = hash_suite_exit,
};
kunit_test_suite(blake2b_test_suite);
diff --git a/lib/crypto/tests/blake2s_kunit.c b/lib/crypto/tests/blake2s_kunit.c
index 6832d9aa7b82..682f695f8a09 100644
--- a/lib/crypto/tests/blake2s_kunit.c
+++ b/lib/crypto/tests/blake2s_kunit.c
@@ -41,9 +41,9 @@ static void blake2s_init_default(struct blake2s_ctx *ctx)
static void test_blake2s_all_key_and_hash_lens(struct kunit *test)
{
const size_t data_len = 100;
- u8 *data = &test_buf[0];
- u8 *key = data + data_len;
- u8 *hash = key + BLAKE2S_KEY_SIZE;
+ u8 *data = alloc_buf(test, data_len);
+ u8 *key = alloc_buf(test, BLAKE2S_KEY_SIZE);
+ u8 *hash = alloc_buf(test, BLAKE2S_HASH_SIZE);
struct blake2s_ctx main_ctx;
u8 main_hash[BLAKE2S_HASH_SIZE];
@@ -68,11 +68,13 @@ static void test_blake2s_all_key_and_hash_lens(struct kunit *test)
static void test_blake2s_with_guarded_key_buf(struct kunit *test)
{
const size_t data_len = 100;
+ u8 *data = alloc_buf(test, data_len);
+ u8 *guarded_key_buf = alloc_guarded_buf(test, BLAKE2S_KEY_SIZE);
- rand_bytes(test_buf, data_len);
+ rand_bytes(data, data_len);
for (int key_len = 0; key_len <= BLAKE2S_KEY_SIZE; key_len++) {
u8 key[BLAKE2S_KEY_SIZE];
- u8 *guarded_key = &test_buf[TEST_BUF_LEN - key_len];
+ u8 *guarded_key = &guarded_key_buf[BLAKE2S_KEY_SIZE - key_len];
u8 hash1[BLAKE2S_HASH_SIZE];
u8 hash2[BLAKE2S_HASH_SIZE];
struct blake2s_ctx ctx;
@@ -80,14 +82,13 @@ static void test_blake2s_with_guarded_key_buf(struct kunit *test)
rand_bytes(key, key_len);
memcpy(guarded_key, key, key_len);
- blake2s(key, key_len, test_buf, data_len,
- hash1, BLAKE2S_HASH_SIZE);
- blake2s(guarded_key, key_len, test_buf, data_len,
- hash2, BLAKE2S_HASH_SIZE);
+ blake2s(key, key_len, data, data_len, hash1, BLAKE2S_HASH_SIZE);
+ blake2s(guarded_key, key_len, data, data_len, hash2,
+ BLAKE2S_HASH_SIZE);
KUNIT_ASSERT_MEMEQ(test, hash1, hash2, BLAKE2S_HASH_SIZE);
blake2s_init_key(&ctx, BLAKE2S_HASH_SIZE, guarded_key, key_len);
- blake2s_update(&ctx, test_buf, data_len);
+ blake2s_update(&ctx, data, data_len);
blake2s_final(&ctx, hash2);
KUNIT_ASSERT_MEMEQ(test, hash1, hash2, BLAKE2S_HASH_SIZE);
}
@@ -100,14 +101,16 @@ static void test_blake2s_with_guarded_key_buf(struct kunit *test)
static void test_blake2s_with_guarded_out_buf(struct kunit *test)
{
const size_t data_len = 100;
+ u8 *data = alloc_buf(test, data_len);
+ u8 *out_buf = alloc_guarded_buf(test, BLAKE2S_HASH_SIZE);
- rand_bytes(test_buf, data_len);
+ rand_bytes(data, data_len);
for (int out_len = 1; out_len <= BLAKE2S_HASH_SIZE; out_len++) {
u8 hash[BLAKE2S_HASH_SIZE];
- u8 *guarded_hash = &test_buf[TEST_BUF_LEN - out_len];
+ u8 *guarded_hash = &out_buf[BLAKE2S_HASH_SIZE - out_len];
- blake2s(NULL, 0, test_buf, data_len, hash, out_len);
- blake2s(NULL, 0, test_buf, data_len, guarded_hash, out_len);
+ blake2s(NULL, 0, data, data_len, hash, out_len);
+ blake2s(NULL, 0, data, data_len, guarded_hash, out_len);
KUNIT_ASSERT_MEMEQ(test, hash, guarded_hash, out_len);
}
}
@@ -124,8 +127,6 @@ static struct kunit_case blake2s_test_cases[] = {
static struct kunit_suite blake2s_test_suite = {
.name = "blake2s",
.test_cases = blake2s_test_cases,
- .suite_init = hash_suite_init,
- .suite_exit = hash_suite_exit,
};
kunit_test_suite(blake2s_test_suite);
diff --git a/lib/crypto/tests/chacha20poly1305_kunit.c b/lib/crypto/tests/chacha20poly1305_kunit.c
index 97a68fab88a7..d5504d0f4ad7 100644
--- a/lib/crypto/tests/chacha20poly1305_kunit.c
+++ b/lib/crypto/tests/chacha20poly1305_kunit.c
@@ -11,7 +11,7 @@
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/kernel.h>
-#include <linux/slab.h>
+#include "test-utils.h"
struct chacha20poly1305_testvec {
const u8 *input, *output, *assoc, *nonce, *key;
@@ -8890,11 +8890,8 @@ static void test_chacha20poly1305(struct kunit *test)
bool ret;
struct scatterlist sg_src[3];
- computed_output = kunit_kmalloc(test, MAXIMUM_TEST_BUFFER_LEN,
- GFP_KERNEL);
- input = kunit_kmalloc(test, MAXIMUM_TEST_BUFFER_LEN, GFP_KERNEL);
- KUNIT_ASSERT_NOT_NULL(test, computed_output);
- KUNIT_ASSERT_NOT_NULL(test, input);
+ computed_output = alloc_buf(test, MAXIMUM_TEST_BUFFER_LEN);
+ input = alloc_buf(test, MAXIMUM_TEST_BUFFER_LEN);
for (i = 0; i < ARRAY_SIZE(chacha20poly1305_enc_vectors); ++i) {
memset(computed_output, 0, MAXIMUM_TEST_BUFFER_LEN);
diff --git a/lib/crypto/tests/ghash_kunit.c b/lib/crypto/tests/ghash_kunit.c
index 68b3837a3607..4d7aa79b3cb2 100644
--- a/lib/crypto/tests/ghash_kunit.c
+++ b/lib/crypto/tests/ghash_kunit.c
@@ -39,17 +39,18 @@ static void ghash_withtestkey(const u8 *data, size_t len,
*/
static void test_ghash_allones_key_and_message(struct kunit *test)
{
+ const size_t max_len = 4096;
+ u8 *data = alloc_buf(test, max_len);
struct ghash_key key;
struct ghash_ctx hashofhashes_ctx;
u8 hash[GHASH_BLOCK_SIZE];
- static_assert(TEST_BUF_LEN >= 4096);
- memset(test_buf, 0xff, 4096);
+ memset(data, 0xff, max_len);
- ghash_preparekey(&key, test_buf);
+ ghash_preparekey(&key, data);
ghash_init(&hashofhashes_ctx, &key);
- for (size_t len = 0; len <= 4096; len += 16) {
- ghash(&key, test_buf, len, hash);
+ for (size_t len = 0; len <= max_len; len += 16) {
+ ghash(&key, data, len, hash);
ghash_update(&hashofhashes_ctx, hash, sizeof(hash));
}
ghash_final(&hashofhashes_ctx, hash);
@@ -68,7 +69,7 @@ static void check_key_consistency(struct kunit *test,
const struct ghash_key *key1,
const struct ghash_key *key2)
{
- u8 *data = test_buf;
+ u8 *data = alloc_buf(test, MAX_LEN_FOR_KEY_CHECK);
u8 hash1[GHASH_BLOCK_SIZE];
u8 hash2[GHASH_BLOCK_SIZE];
@@ -88,10 +89,10 @@ static void check_key_consistency(struct kunit *test,
static void test_ghash_with_guarded_key(struct kunit *test)
{
u8 raw_key[GHASH_BLOCK_SIZE];
- u8 *guarded_raw_key = &test_buf[TEST_BUF_LEN - sizeof(raw_key)];
+ u8 *guarded_raw_key = alloc_guarded_buf(test, sizeof(raw_key));
struct ghash_key key1, key2;
struct ghash_key *guarded_key =
- (struct ghash_key *)&test_buf[TEST_BUF_LEN - sizeof(key1)];
+ alloc_guarded_buf(test, sizeof(*guarded_key));
/* Prepare with regular buffers. */
rand_bytes(raw_key, sizeof(raw_key));
@@ -116,14 +117,14 @@ static void test_ghash_with_minimally_aligned_key(struct kunit *test)
{
u8 raw_key[GHASH_BLOCK_SIZE];
struct ghash_key key;
+ const size_t align = __alignof__(struct ghash_key);
+ u8 *key_buf = alloc_buf(test, sizeof(struct ghash_key) + 3 * align);
struct ghash_key *minaligned_key =
- (struct ghash_key *)&test_buf[MAX_LEN_FOR_KEY_CHECK +
- __alignof__(struct ghash_key)];
+ (struct ghash_key *)(PTR_ALIGN(key_buf, 2 * align) + align);
- KUNIT_ASSERT_TRUE(test, IS_ALIGNED((uintptr_t)minaligned_key,
- __alignof__(struct ghash_key)));
- KUNIT_ASSERT_TRUE(test, !IS_ALIGNED((uintptr_t)minaligned_key,
- 2 * __alignof__(struct ghash_key)));
+ KUNIT_ASSERT_TRUE(test, IS_ALIGNED((uintptr_t)minaligned_key, align));
+ KUNIT_ASSERT_TRUE(test,
+ !IS_ALIGNED((uintptr_t)minaligned_key, 2 * align));
rand_bytes(raw_key, sizeof(raw_key));
ghash_preparekey(&key, raw_key);
@@ -164,12 +165,7 @@ static int ghash_suite_init(struct kunit_suite *suite)
rand_bytes_seeded_from_len(raw_key, sizeof(raw_key));
ghash_preparekey(&test_key, raw_key);
- return hash_suite_init(suite);
-}
-
-static void ghash_suite_exit(struct kunit_suite *suite)
-{
- hash_suite_exit(suite);
+ return 0;
}
static struct kunit_case ghash_test_cases[] = {
@@ -186,7 +182,6 @@ static struct kunit_suite ghash_test_suite = {
.name = "ghash",
.test_cases = ghash_test_cases,
.suite_init = ghash_suite_init,
- .suite_exit = ghash_suite_exit,
};
kunit_test_suite(ghash_test_suite);
diff --git a/lib/crypto/tests/hash-test-template.h b/lib/crypto/tests/hash-test-template.h
index 61b43e62779f..bb6eaa509d0f 100644
--- a/lib/crypto/tests/hash-test-template.h
+++ b/lib/crypto/tests/hash-test-template.h
@@ -7,93 +7,7 @@
*/
#include <kunit/run-in-irq-context.h>
#include <kunit/test.h>
-#include <linux/vmalloc.h>
-
-/* test_buf is a guarded buffer, i.e. &test_buf[TEST_BUF_LEN] is not mapped. */
-#define TEST_BUF_LEN 16384
-static u8 *test_buf;
-
-static u8 *orig_test_buf;
-
-static u64 random_seed;
-
-/*
- * This is a simple linear congruential generator. It is used only for testing,
- * which does not require cryptographically secure random numbers. A hard-coded
- * algorithm is used instead of <linux/prandom.h> so that it matches the
- * algorithm used by the test vector generation script. This allows the input
- * data in random test vectors to be concisely stored as just the seed.
- */
-static u32 rand32(void)
-{
- random_seed = (random_seed * 25214903917 + 11) & ((1ULL << 48) - 1);
- return random_seed >> 16;
-}
-
-static void rand_bytes(u8 *out, size_t len)
-{
- for (size_t i = 0; i < len; i++)
- out[i] = rand32();
-}
-
-static void rand_bytes_seeded_from_len(u8 *out, size_t len)
-{
- random_seed = len;
- rand_bytes(out, len);
-}
-
-static bool rand_bool(void)
-{
- return rand32() % 2;
-}
-
-/* Generate a random length, preferring small lengths. */
-static size_t rand_length(size_t max_len)
-{
- size_t len;
-
- switch (rand32() % 3) {
- case 0:
- len = rand32() % 128;
- break;
- case 1:
- len = rand32() % 3072;
- break;
- default:
- len = rand32();
- break;
- }
- return len % (max_len + 1);
-}
-
-static size_t rand_offset(size_t max_offset)
-{
- return min(rand32() % 128, max_offset);
-}
-
-static int hash_suite_init(struct kunit_suite *suite)
-{
- /*
- * Allocate the test buffer using vmalloc() with a page-aligned length
- * so that it is immediately followed by a guard page. This allows
- * buffer overreads to be detected, even in assembly code.
- */
- size_t alloc_len = round_up(TEST_BUF_LEN, PAGE_SIZE);
-
- orig_test_buf = vmalloc(alloc_len);
- if (!orig_test_buf)
- return -ENOMEM;
-
- test_buf = orig_test_buf + alloc_len - TEST_BUF_LEN;
- return 0;
-}
-
-static void hash_suite_exit(struct kunit_suite *suite)
-{
- vfree(orig_test_buf);
- orig_test_buf = NULL;
- test_buf = NULL;
-}
+#include "test-utils.h"
/*
* Test the hash function against a list of test vectors.
@@ -104,14 +18,16 @@ static void hash_suite_exit(struct kunit_suite *suite)
*/
static void test_hash_test_vectors(struct kunit *test)
{
+ const size_t max_len = 16384;
+ u8 *data = alloc_buf(test, max_len);
+
for (size_t i = 0; i < ARRAY_SIZE(hash_testvecs); i++) {
size_t data_len = hash_testvecs[i].data_len;
u8 actual_hash[HASH_SIZE];
- KUNIT_ASSERT_LE(test, data_len, TEST_BUF_LEN);
- rand_bytes_seeded_from_len(test_buf, data_len);
-
- HASH(test_buf, data_len, actual_hash);
+ KUNIT_ASSERT_LE(test, data_len, max_len);
+ rand_bytes_seeded_from_len(data, data_len);
+ HASH(data, data_len, actual_hash);
KUNIT_ASSERT_MEMEQ_MSG(
test, actual_hash, hash_testvecs[i].digest, HASH_SIZE,
"Wrong result with test vector %zu; data_len=%zu", i,
@@ -127,14 +43,15 @@ static void test_hash_test_vectors(struct kunit *test)
*/
static void test_hash_all_lens_up_to_4096(struct kunit *test)
{
+ const size_t max_len = 4096;
+ u8 *data = alloc_buf(test, max_len);
struct HASH_CTX ctx;
u8 hash[HASH_SIZE];
- static_assert(TEST_BUF_LEN >= 4096);
- rand_bytes_seeded_from_len(test_buf, 4096);
+ rand_bytes_seeded_from_len(data, max_len);
HASH_INIT(&ctx);
- for (size_t len = 0; len <= 4096; len++) {
- HASH(test_buf, len, hash);
+ for (size_t len = 0; len <= max_len; len++) {
+ HASH(data, len, hash);
HASH_UPDATE(&ctx, hash, HASH_SIZE);
}
HASH_FINAL(&ctx, hash);
@@ -147,6 +64,9 @@ static void test_hash_all_lens_up_to_4096(struct kunit *test)
*/
static void test_hash_incremental_updates(struct kunit *test)
{
+ const size_t max_len = 16384;
+ u8 *data = alloc_guarded_buf(test, max_len);
+
for (int i = 0; i < 1000; i++) {
size_t total_len, offset;
struct HASH_CTX ctx;
@@ -155,12 +75,12 @@ static void test_hash_incremental_updates(struct kunit *test)
size_t num_parts = 0;
size_t remaining_len, cur_offset;
- total_len = rand_length(TEST_BUF_LEN);
- offset = rand_offset(TEST_BUF_LEN - total_len);
- rand_bytes(&test_buf[offset], total_len);
+ total_len = rand_length(max_len);
+ offset = rand_offset(max_len - total_len);
+ rand_bytes(&data[offset], total_len);
/* Compute the hash value in one shot. */
- HASH(&test_buf[offset], total_len, hash1);
+ HASH(&data[offset], total_len, hash1);
/*
* Compute the hash value incrementally, using a randomly
@@ -172,13 +92,13 @@ static void test_hash_incremental_updates(struct kunit *test)
while (rand_bool()) {
size_t part_len = rand_length(remaining_len);
- HASH_UPDATE(&ctx, &test_buf[cur_offset], part_len);
+ HASH_UPDATE(&ctx, &data[cur_offset], part_len);
num_parts++;
cur_offset += part_len;
remaining_len -= part_len;
}
if (remaining_len != 0 || rand_bool()) {
- HASH_UPDATE(&ctx, &test_buf[cur_offset], remaining_len);
+ HASH_UPDATE(&ctx, &data[cur_offset], remaining_len);
num_parts++;
}
HASH_FINAL(&ctx, hash2);
@@ -197,11 +117,13 @@ static void test_hash_incremental_updates(struct kunit *test)
*/
static void test_hash_buffer_overruns(struct kunit *test)
{
- const size_t max_tested_len = TEST_BUF_LEN - sizeof(struct HASH_CTX);
- void *const buf_end = &test_buf[TEST_BUF_LEN];
+ const size_t buf_len = 16384;
+ u8 *buf = alloc_guarded_buf(test, buf_len);
+ void *const buf_end = &buf[buf_len];
+ const size_t max_tested_len = buf_len - sizeof(struct HASH_CTX);
struct HASH_CTX *guarded_ctx = buf_end - sizeof(*guarded_ctx);
- rand_bytes(test_buf, TEST_BUF_LEN);
+ rand_bytes(buf, buf_len);
for (int i = 0; i < 100; i++) {
size_t len = rand_length(max_tested_len);
@@ -215,14 +137,14 @@ static void test_hash_buffer_overruns(struct kunit *test)
HASH_FINAL(&ctx, hash);
/* Check for overruns of the hash value buffer. */
- HASH(test_buf, len, buf_end - HASH_SIZE);
+ HASH(buf, len, buf_end - HASH_SIZE);
HASH_INIT(&ctx);
- HASH_UPDATE(&ctx, test_buf, len);
+ HASH_UPDATE(&ctx, buf, len);
HASH_FINAL(&ctx, buf_end - HASH_SIZE);
- /* Check for overuns of the hash context. */
+ /* Check for overruns of the hash context. */
HASH_INIT(guarded_ctx);
- HASH_UPDATE(guarded_ctx, test_buf, len);
+ HASH_UPDATE(guarded_ctx, buf, len);
HASH_FINAL(guarded_ctx, hash);
}
}
@@ -233,30 +155,32 @@ static void test_hash_buffer_overruns(struct kunit *test)
*/
static void test_hash_overlaps(struct kunit *test)
{
- const size_t max_tested_len = TEST_BUF_LEN - HASH_SIZE;
+ const size_t buf_len = 16384;
+ u8 *buf = alloc_guarded_buf(test, buf_len);
+ const size_t max_tested_len = buf_len - HASH_SIZE;
struct HASH_CTX ctx;
u8 hash[HASH_SIZE];
- rand_bytes(test_buf, TEST_BUF_LEN);
+ rand_bytes(buf, buf_len);
for (int i = 0; i < 100; i++) {
size_t len = rand_length(max_tested_len);
size_t offset = HASH_SIZE + rand_offset(max_tested_len - len);
bool left_end = rand_bool();
- u8 *ovl_hash = left_end ? &test_buf[offset] :
- &test_buf[offset + len - HASH_SIZE];
+ u8 *ovl_hash = left_end ? &buf[offset] :
+ &buf[offset + len - HASH_SIZE];
- HASH(&test_buf[offset], len, hash);
- HASH(&test_buf[offset], len, ovl_hash);
+ HASH(&buf[offset], len, hash);
+ HASH(&buf[offset], len, ovl_hash);
KUNIT_ASSERT_MEMEQ_MSG(
test, hash, ovl_hash, HASH_SIZE,
"Overlap test 1 failed with len=%zu offset=%zu left_end=%d",
len, offset, left_end);
/* Repeat the above test, but this time use init+update+final */
- HASH(&test_buf[offset], len, hash);
+ HASH(&buf[offset], len, hash);
HASH_INIT(&ctx);
- HASH_UPDATE(&ctx, &test_buf[offset], len);
+ HASH_UPDATE(&ctx, &buf[offset], len);
HASH_FINAL(&ctx, ovl_hash);
KUNIT_ASSERT_MEMEQ_MSG(
test, hash, ovl_hash, HASH_SIZE,
@@ -264,10 +188,10 @@ static void test_hash_overlaps(struct kunit *test)
len, offset, left_end);
/* Test modifying the source data after it was used. */
- HASH(&test_buf[offset], len, hash);
+ HASH(&buf[offset], len, hash);
HASH_INIT(&ctx);
- HASH_UPDATE(&ctx, &test_buf[offset], len);
- rand_bytes(&test_buf[offset], len);
+ HASH_UPDATE(&ctx, &buf[offset], len);
+ rand_bytes(&buf[offset], len);
HASH_FINAL(&ctx, ovl_hash);
KUNIT_ASSERT_MEMEQ_MSG(
test, hash, ovl_hash, HASH_SIZE,
@@ -282,20 +206,22 @@ static void test_hash_overlaps(struct kunit *test)
*/
static void test_hash_alignment_consistency(struct kunit *test)
{
+ const size_t max_len = 16384;
+ u8 *data = alloc_guarded_buf(test, max_len);
u8 hash1[128 + HASH_SIZE];
u8 hash2[128 + HASH_SIZE];
for (int i = 0; i < 100; i++) {
- size_t len = rand_length(TEST_BUF_LEN);
- size_t data_offs1 = rand_offset(TEST_BUF_LEN - len);
- size_t data_offs2 = rand_offset(TEST_BUF_LEN - len);
+ size_t len = rand_length(max_len);
+ size_t data_offs1 = rand_offset(max_len - len);
+ size_t data_offs2 = rand_offset(max_len - len);
size_t hash_offs1 = rand_offset(128);
size_t hash_offs2 = rand_offset(128);
- rand_bytes(&test_buf[data_offs1], len);
- HASH(&test_buf[data_offs1], len, &hash1[hash_offs1]);
- memmove(&test_buf[data_offs2], &test_buf[data_offs1], len);
- HASH(&test_buf[data_offs2], len, &hash2[hash_offs2]);
+ rand_bytes(&data[data_offs1], len);
+ HASH(&data[data_offs1], len, &hash1[hash_offs1]);
+ memmove(&data[data_offs2], &data[data_offs1], len);
+ HASH(&data[data_offs2], len, &hash2[hash_offs2]);
KUNIT_ASSERT_MEMEQ_MSG(
test, &hash1[hash_offs1], &hash2[hash_offs2], HASH_SIZE,
"Alignment consistency test failed with len=%zu data_offs=(%zu,%zu) hash_offs=(%zu,%zu)",
@@ -308,11 +234,14 @@ static void test_hash_ctx_zeroization(struct kunit *test)
{
static const u8 zeroes[sizeof(struct HASH_CTX)];
struct HASH_CTX ctx;
+ const size_t data_len = 128;
+ u8 *data = alloc_buf(test, data_len);
+ u8 hash[HASH_SIZE];
- rand_bytes(test_buf, 128);
+ rand_bytes(data, data_len);
HASH_INIT(&ctx);
- HASH_UPDATE(&ctx, test_buf, 128);
- HASH_FINAL(&ctx, test_buf);
+ HASH_UPDATE(&ctx, data, data_len);
+ HASH_FINAL(&ctx, hash);
KUNIT_ASSERT_MEMEQ_MSG(test, &ctx, zeroes, sizeof(ctx),
"Hash context was not zeroized by finalization");
}
@@ -321,6 +250,7 @@ static void test_hash_ctx_zeroization(struct kunit *test)
#define IRQ_TEST_NUM_BUFFERS 3 /* matches max concurrency level */
struct hash_irq_test1_state {
+ u8 *data;
u8 expected_hashes[IRQ_TEST_NUM_BUFFERS][HASH_SIZE];
atomic_t seqno;
};
@@ -336,7 +266,8 @@ static bool hash_irq_test1_func(void *state_)
u32 i = (u32)atomic_inc_return(&state->seqno) % IRQ_TEST_NUM_BUFFERS;
u8 actual_hash[HASH_SIZE];
- HASH(&test_buf[i * IRQ_TEST_DATA_LEN], IRQ_TEST_DATA_LEN, actual_hash);
+ HASH(&state->data[i * IRQ_TEST_DATA_LEN], IRQ_TEST_DATA_LEN,
+ actual_hash);
return memcmp(actual_hash, state->expected_hashes[i], HASH_SIZE) == 0;
}
@@ -346,12 +277,14 @@ static bool hash_irq_test1_func(void *state_)
*/
static void test_hash_interrupt_context_1(struct kunit *test)
{
+ const size_t total_data_len = IRQ_TEST_NUM_BUFFERS * IRQ_TEST_DATA_LEN;
struct hash_irq_test1_state state = {};
/* Prepare some test messages and compute the expected hash of each. */
- rand_bytes(test_buf, IRQ_TEST_NUM_BUFFERS * IRQ_TEST_DATA_LEN);
+ state.data = alloc_buf(test, total_data_len);
+ rand_bytes(state.data, total_data_len);
for (int i = 0; i < IRQ_TEST_NUM_BUFFERS; i++)
- HASH(&test_buf[i * IRQ_TEST_DATA_LEN], IRQ_TEST_DATA_LEN,
+ HASH(&state.data[i * IRQ_TEST_DATA_LEN], IRQ_TEST_DATA_LEN,
state.expected_hashes[i]);
kunit_run_irq_test(test, hash_irq_test1_func, 100000, &state);
@@ -365,6 +298,8 @@ struct hash_irq_test2_hash_ctx {
};
struct hash_irq_test2_state {
+ u8 *data;
+ size_t data_len;
struct hash_irq_test2_hash_ctx ctxs[IRQ_TEST_NUM_BUFFERS];
u8 expected_hash[HASH_SIZE];
u16 update_lens[32];
@@ -397,7 +332,7 @@ static bool hash_irq_test2_func(void *state_)
ctx->step++;
} else if (ctx->step < state->num_steps - 1) {
/* Update step */
- HASH_UPDATE(&ctx->hash_ctx, &test_buf[ctx->offset],
+ HASH_UPDATE(&ctx->hash_ctx, &state->data[ctx->offset],
state->update_lens[ctx->step - 1]);
ctx->offset += state->update_lens[ctx->step - 1];
ctx->step++;
@@ -405,7 +340,7 @@ static bool hash_irq_test2_func(void *state_)
/* Final step */
u8 actual_hash[HASH_SIZE];
- if (WARN_ON_ONCE(ctx->offset != TEST_BUF_LEN))
+ if (WARN_ON_ONCE(ctx->offset != state->data_len))
ret = false;
HASH_FINAL(&ctx->hash_ctx, actual_hash);
if (memcmp(actual_hash, state->expected_hash, HASH_SIZE) != 0)
@@ -426,20 +361,23 @@ static bool hash_irq_test2_func(void *state_)
*/
static void test_hash_interrupt_context_2(struct kunit *test)
{
+ const size_t data_len = 16384;
struct hash_irq_test2_state *state;
- int remaining = TEST_BUF_LEN;
+ size_t remaining = data_len;
state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, state);
+ state->data_len = data_len;
+ state->data = alloc_buf(test, data_len);
- rand_bytes(test_buf, TEST_BUF_LEN);
- HASH(test_buf, TEST_BUF_LEN, state->expected_hash);
+ rand_bytes(state->data, data_len);
+ HASH(state->data, data_len, state->expected_hash);
/*
* Generate a list of update lengths to use. Ensure that it contains
* multiple entries but is limited to a maximum length.
*/
- static_assert(TEST_BUF_LEN / 4096 > 1);
+ KUNIT_ASSERT_GT(test, data_len / 4096, 1);
for (state->num_steps = 0;
state->num_steps < ARRAY_SIZE(state->update_lens) - 1 && remaining;
state->num_steps++) {
@@ -485,21 +423,23 @@ static void test_hash_interrupt_context_2(struct kunit *test)
*/
static void test_hmac(struct kunit *test)
{
+ const size_t max_data_len = 4096;
+ const size_t max_key_len = 293;
+ const size_t outer_key_len = 32;
+ u8 *data = alloc_guarded_buf(test, max_data_len);
+ u8 *raw_key = alloc_guarded_buf(test, max_key_len);
static const u8 zeroes[sizeof(struct HMAC_CTX)];
- u8 *raw_key;
struct HMAC_KEY key;
struct HMAC_CTX ctx;
u8 mac[HASH_SIZE];
u8 mac2[HASH_SIZE];
- static_assert(TEST_BUF_LEN >= 4096 + 293);
- rand_bytes_seeded_from_len(test_buf, 4096);
- raw_key = &test_buf[4096];
+ rand_bytes_seeded_from_len(data, max_data_len);
+ rand_bytes_seeded_from_len(raw_key, outer_key_len);
- rand_bytes_seeded_from_len(raw_key, 32);
- HMAC_PREPAREKEY(&key, raw_key, 32);
+ HMAC_PREPAREKEY(&key, raw_key, outer_key_len);
HMAC_INIT(&ctx, &key);
- for (size_t data_len = 0; data_len <= 4096; data_len++) {
+ for (size_t data_len = 0; data_len <= max_data_len; data_len++) {
/*
* Cycle through key lengths as well. Somewhat arbitrarily go
* up to 293, which is somewhat larger than the largest hash
@@ -507,17 +447,17 @@ static void test_hmac(struct kunit *test)
* hashed down to one block); going higher would not be useful.
* To reduce correlation with data_len, use a prime number here.
*/
- size_t key_len = data_len % 293;
+ size_t key_len = data_len % max_key_len;
- HMAC_UPDATE(&ctx, test_buf, data_len);
+ HMAC_UPDATE(&ctx, data, data_len);
rand_bytes_seeded_from_len(raw_key, key_len);
- HMAC_USINGRAWKEY(raw_key, key_len, test_buf, data_len, mac);
+ HMAC_USINGRAWKEY(raw_key, key_len, data, data_len, mac);
HMAC_UPDATE(&ctx, mac, HASH_SIZE);
/* Verify that HMAC() is consistent with HMAC_USINGRAWKEY(). */
HMAC_PREPAREKEY(&key, raw_key, key_len);
- HMAC(&key, test_buf, data_len, mac2);
+ HMAC(&key, data, data_len, mac2);
KUNIT_ASSERT_MEMEQ_MSG(
test, mac, mac2, HASH_SIZE,
"HMAC gave different results with raw and prepared keys");
@@ -540,14 +480,17 @@ static void benchmark_hash(struct kunit *test)
1, 16, 64, 127, 128, 200, 256,
511, 512, 1024, 3173, 4096, 16384,
};
+ const size_t max_len = 16384;
+ u8 *data = alloc_buf(test, max_len);
u8 hash[HASH_SIZE];
if (!IS_ENABLED(CONFIG_CRYPTO_LIB_BENCHMARK))
kunit_skip(test, "not enabled");
/* Warm-up */
- for (size_t i = 0; i < 10000000; i += TEST_BUF_LEN)
- HASH(test_buf, TEST_BUF_LEN, hash);
+ memset(data, 0, max_len);
+ for (size_t i = 0; i < 10000000; i += max_len)
+ HASH(data, max_len, hash);
for (size_t i = 0; i < ARRAY_SIZE(lens_to_test); i++) {
size_t len = lens_to_test[i];
@@ -555,11 +498,11 @@ static void benchmark_hash(struct kunit *test)
size_t num_iters = 10000000 / (len + 128);
u64 t;
- KUNIT_ASSERT_LE(test, len, TEST_BUF_LEN);
+ KUNIT_ASSERT_LE(test, len, max_len);
preempt_disable();
t = ktime_get_ns();
for (size_t j = 0; j < num_iters; j++)
- HASH(test_buf, len, hash);
+ HASH(data, len, hash);
t = ktime_get_ns() - t;
preempt_enable();
kunit_info(test, "len=%zu: %llu MB/s", len,
diff --git a/lib/crypto/tests/md5_kunit.c b/lib/crypto/tests/md5_kunit.c
index 38bd52c25ae3..1598f8585b45 100644
--- a/lib/crypto/tests/md5_kunit.c
+++ b/lib/crypto/tests/md5_kunit.c
@@ -30,8 +30,6 @@ static struct kunit_case hash_test_cases[] = {
static struct kunit_suite hash_test_suite = {
.name = "md5",
.test_cases = hash_test_cases,
- .suite_init = hash_suite_init,
- .suite_exit = hash_suite_exit,
};
kunit_test_suite(hash_test_suite);
diff --git a/lib/crypto/tests/mldsa_kunit.c b/lib/crypto/tests/mldsa_kunit.c
index 67f8f93e3dc6..ec64e10c97f2 100644
--- a/lib/crypto/tests/mldsa_kunit.c
+++ b/lib/crypto/tests/mldsa_kunit.c
@@ -8,6 +8,7 @@
#include <kunit/test.h>
#include <linux/random.h>
#include <linux/unaligned.h>
+#include "test-utils.h"
#define Q 8380417 /* The prime q = 2^23 - 2^13 + 1 */
@@ -60,14 +61,6 @@ static void do_mldsa_and_assert_success(struct kunit *test,
KUNIT_ASSERT_EQ(test, err, 0);
}
-static u8 *kunit_kmemdup_or_fail(struct kunit *test, const u8 *src, size_t len)
-{
- u8 *dst = kunit_kmalloc(test, len, GFP_KERNEL);
-
- KUNIT_ASSERT_NOT_NULL(test, dst);
- return memcpy(dst, src, len);
-}
-
/*
* Test that changing coefficients in a valid signature's z vector results in
* the following behavior from mldsa_verify():
@@ -83,7 +76,7 @@ static u8 *kunit_kmemdup_or_fail(struct kunit *test, const u8 *src, size_t len)
static void test_mldsa_z_range(struct kunit *test,
const struct mldsa_testvector *tv)
{
- u8 *sig = kunit_kmemdup_or_fail(test, tv->sig, tv->sig_len);
+ u8 *sig = memdup_buf(test, tv->sig, tv->sig_len);
const int lambda = params[tv->alg].lambda;
const s32 gamma1 = params[tv->alg].gamma1;
const int beta = params[tv->alg].beta;
@@ -146,7 +139,7 @@ static void test_mldsa_bad_hints(struct kunit *test,
{
const int omega = params[tv->alg].omega;
const int k = params[tv->alg].k;
- u8 *sig = kunit_kmemdup_or_fail(test, tv->sig, tv->sig_len);
+ u8 *sig = memdup_buf(test, tv->sig, tv->sig_len);
/* Pointer to the encoded hint vector in the signature */
u8 *hintvec = &sig[tv->sig_len - omega - k];
u8 h;
@@ -202,9 +195,9 @@ static void test_mldsa_mutation(struct kunit *test,
const int msg_len = tv->msg_len;
const int pk_len = tv->pk_len;
const int num_iter = 200;
- u8 *sig = kunit_kmemdup_or_fail(test, tv->sig, sig_len);
- u8 *msg = kunit_kmemdup_or_fail(test, tv->msg, msg_len);
- u8 *pk = kunit_kmemdup_or_fail(test, tv->pk, pk_len);
+ u8 *sig = memdup_buf(test, tv->sig, sig_len);
+ u8 *msg = memdup_buf(test, tv->msg, msg_len);
+ u8 *pk = memdup_buf(test, tv->pk, pk_len);
/* Initially the signature is valid. */
do_mldsa_and_assert_success(test, tv);
diff --git a/lib/crypto/tests/nh_kunit.c b/lib/crypto/tests/nh_kunit.c
index a8a3c3f345cb..49e0fb3dd294 100644
--- a/lib/crypto/tests/nh_kunit.c
+++ b/lib/crypto/tests/nh_kunit.c
@@ -5,14 +5,13 @@
#include <crypto/nh.h>
#include <kunit/test.h>
#include "nh-testvecs.h"
+#include "test-utils.h"
static void test_nh(struct kunit *test)
{
- u32 *key = kunit_kmalloc(test, NH_KEY_BYTES, GFP_KERNEL);
+ u32 *key = memdup_buf(test, nh_test_key, NH_KEY_BYTES);
__le64 hash[NH_NUM_PASSES];
- KUNIT_ASSERT_NOT_NULL(test, key);
- memcpy(key, nh_test_key, NH_KEY_BYTES);
le32_to_cpu_array(key, NH_KEY_WORDS);
nh(key, nh_test_msg, 16, hash);
diff --git a/lib/crypto/tests/poly1305_kunit.c b/lib/crypto/tests/poly1305_kunit.c
index 7ac191bd96b6..f3cb6245bc29 100644
--- a/lib/crypto/tests/poly1305_kunit.c
+++ b/lib/crypto/tests/poly1305_kunit.c
@@ -46,12 +46,7 @@ static void poly1305_withtestkey(const u8 *data, size_t len,
static int poly1305_suite_init(struct kunit_suite *suite)
{
rand_bytes_seeded_from_len(test_key, POLY1305_KEY_SIZE);
- return hash_suite_init(suite);
-}
-
-static void poly1305_suite_exit(struct kunit_suite *suite)
-{
- hash_suite_exit(suite);
+ return 0;
}
/*
@@ -81,19 +76,20 @@ static void poly1305_suite_exit(struct kunit_suite *suite)
*/
static void test_poly1305_allones_keys_and_message(struct kunit *test)
{
+ const size_t max_len = 4096;
+ u8 *data = alloc_buf(test, max_len);
struct poly1305_desc_ctx mac_ctx, macofmacs_ctx;
u8 mac[POLY1305_DIGEST_SIZE];
- static_assert(TEST_BUF_LEN >= 4096);
- memset(test_buf, 0xff, 4096);
+ memset(data, 0xff, max_len);
- poly1305_init(&mac_ctx, test_buf);
- poly1305_init(&macofmacs_ctx, test_buf);
+ poly1305_init(&mac_ctx, data);
+ poly1305_init(&macofmacs_ctx, data);
for (int i = 0; i < 32; i++) {
- for (size_t len = 0; len <= 4096; len += 16) {
+ for (size_t len = 0; len <= max_len; len += 16) {
struct poly1305_desc_ctx tmp_ctx;
- poly1305_update(&mac_ctx, test_buf, len);
+ poly1305_update(&mac_ctx, data, len);
tmp_ctx = mac_ctx;
poly1305_final(&tmp_ctx, mac);
poly1305_update(&macofmacs_ctx, mac,
@@ -157,7 +153,6 @@ static struct kunit_suite poly1305_test_suite = {
.name = "poly1305",
.test_cases = poly1305_test_cases,
.suite_init = poly1305_suite_init,
- .suite_exit = poly1305_suite_exit,
};
kunit_test_suite(poly1305_test_suite);
diff --git a/lib/crypto/tests/polyval_kunit.c b/lib/crypto/tests/polyval_kunit.c
index d1f53a690ab8..2835929e890c 100644
--- a/lib/crypto/tests/polyval_kunit.c
+++ b/lib/crypto/tests/polyval_kunit.c
@@ -66,17 +66,18 @@ static void test_polyval_rfc8452_testvec(struct kunit *test)
*/
static void test_polyval_allones_key_and_message(struct kunit *test)
{
+ const size_t max_len = 4096;
+ u8 *data = alloc_buf(test, max_len);
struct polyval_key key;
struct polyval_ctx hashofhashes_ctx;
u8 hash[POLYVAL_BLOCK_SIZE];
- static_assert(TEST_BUF_LEN >= 4096);
- memset(test_buf, 0xff, 4096);
+ memset(data, 0xff, max_len);
- polyval_preparekey(&key, test_buf);
+ polyval_preparekey(&key, data);
polyval_init(&hashofhashes_ctx, &key);
- for (size_t len = 0; len <= 4096; len += 16) {
- polyval(&key, test_buf, len, hash);
+ for (size_t len = 0; len <= max_len; len += 16) {
+ polyval(&key, data, len, hash);
polyval_update(&hashofhashes_ctx, hash, sizeof(hash));
}
polyval_final(&hashofhashes_ctx, hash);
@@ -95,7 +96,7 @@ static void check_key_consistency(struct kunit *test,
const struct polyval_key *key1,
const struct polyval_key *key2)
{
- u8 *data = test_buf;
+ u8 *data = alloc_buf(test, MAX_LEN_FOR_KEY_CHECK);
u8 hash1[POLYVAL_BLOCK_SIZE];
u8 hash2[POLYVAL_BLOCK_SIZE];
@@ -115,10 +116,10 @@ static void check_key_consistency(struct kunit *test,
static void test_polyval_with_guarded_key(struct kunit *test)
{
u8 raw_key[POLYVAL_BLOCK_SIZE];
- u8 *guarded_raw_key = &test_buf[TEST_BUF_LEN - sizeof(raw_key)];
+ u8 *guarded_raw_key = alloc_guarded_buf(test, sizeof(raw_key));
struct polyval_key key1, key2;
struct polyval_key *guarded_key =
- (struct polyval_key *)&test_buf[TEST_BUF_LEN - sizeof(key1)];
+ alloc_guarded_buf(test, sizeof(*guarded_key));
/* Prepare with regular buffers. */
rand_bytes(raw_key, sizeof(raw_key));
@@ -137,21 +138,20 @@ static void test_polyval_with_guarded_key(struct kunit *test)
/*
* Test that polyval_key only needs to be aligned to
* __alignof__(struct polyval_key), i.e. 8 bytes. The assembly code may prefer
- * 16-byte or higher alignment, but it musn't require it.
+ * 16-byte or higher alignment, but it mustn't require it.
*/
static void test_polyval_with_minimally_aligned_key(struct kunit *test)
{
u8 raw_key[POLYVAL_BLOCK_SIZE];
struct polyval_key key;
+ const size_t align = __alignof__(struct polyval_key);
+ u8 *key_buf = alloc_buf(test, sizeof(struct polyval_key) + 3 * align);
struct polyval_key *minaligned_key =
- (struct polyval_key *)&test_buf[MAX_LEN_FOR_KEY_CHECK +
- __alignof__(struct polyval_key)];
+ (struct polyval_key *)(PTR_ALIGN(key_buf, 2 * align) + align);
- KUNIT_ASSERT_TRUE(test, IS_ALIGNED((uintptr_t)minaligned_key,
- __alignof__(struct polyval_key)));
+ KUNIT_ASSERT_TRUE(test, IS_ALIGNED((uintptr_t)minaligned_key, align));
KUNIT_ASSERT_TRUE(test,
- !IS_ALIGNED((uintptr_t)minaligned_key,
- 2 * __alignof__(struct polyval_key)));
+ !IS_ALIGNED((uintptr_t)minaligned_key, 2 * align));
rand_bytes(raw_key, sizeof(raw_key));
polyval_preparekey(&key, raw_key);
@@ -192,12 +192,7 @@ static int polyval_suite_init(struct kunit_suite *suite)
rand_bytes_seeded_from_len(raw_key, sizeof(raw_key));
polyval_preparekey(&test_key, raw_key);
- return hash_suite_init(suite);
-}
-
-static void polyval_suite_exit(struct kunit_suite *suite)
-{
- hash_suite_exit(suite);
+ return 0;
}
static struct kunit_case polyval_test_cases[] = {
@@ -215,7 +210,6 @@ static struct kunit_suite polyval_test_suite = {
.name = "polyval",
.test_cases = polyval_test_cases,
.suite_init = polyval_suite_init,
- .suite_exit = polyval_suite_exit,
};
kunit_test_suite(polyval_test_suite);
diff --git a/lib/crypto/tests/sha1_kunit.c b/lib/crypto/tests/sha1_kunit.c
index 24ba8d5669c8..27286afaa407 100644
--- a/lib/crypto/tests/sha1_kunit.c
+++ b/lib/crypto/tests/sha1_kunit.c
@@ -30,8 +30,6 @@ static struct kunit_case hash_test_cases[] = {
static struct kunit_suite hash_test_suite = {
.name = "sha1",
.test_cases = hash_test_cases,
- .suite_init = hash_suite_init,
- .suite_exit = hash_suite_exit,
};
kunit_test_suite(hash_test_suite);
diff --git a/lib/crypto/tests/sha224_kunit.c b/lib/crypto/tests/sha224_kunit.c
index 962ad46b9c99..bcf8b90f9ae2 100644
--- a/lib/crypto/tests/sha224_kunit.c
+++ b/lib/crypto/tests/sha224_kunit.c
@@ -30,8 +30,6 @@ static struct kunit_case hash_test_cases[] = {
static struct kunit_suite hash_test_suite = {
.name = "sha224",
.test_cases = hash_test_cases,
- .suite_init = hash_suite_init,
- .suite_exit = hash_suite_exit,
};
kunit_test_suite(hash_test_suite);
diff --git a/lib/crypto/tests/sha256_kunit.c b/lib/crypto/tests/sha256_kunit.c
index 5dccdee79693..17daa09adfe7 100644
--- a/lib/crypto/tests/sha256_kunit.c
+++ b/lib/crypto/tests/sha256_kunit.c
@@ -4,6 +4,7 @@
*/
#include <crypto/sha2.h>
#include "sha256-testvecs.h"
+#include "test-utils.h"
/* Generate the HASH_KUNIT_CASES using hash-test-template.h. */
#define HASH sha256
@@ -22,26 +23,6 @@
#define HMAC_USINGRAWKEY hmac_sha256_usingrawkey
#include "hash-test-template.h"
-static void free_guarded_buf(void *buf)
-{
- vfree(buf);
-}
-
-/*
- * Allocate a KUnit-managed buffer that has length @len bytes immediately
- * followed by an unmapped page, and assert that the allocation succeeds.
- */
-static void *alloc_guarded_buf(struct kunit *test, size_t len)
-{
- size_t full_len = round_up(len, PAGE_SIZE);
- void *buf = vmalloc(full_len);
-
- KUNIT_ASSERT_NOT_NULL(test, buf);
- KUNIT_ASSERT_EQ(test, 0,
- kunit_add_action_or_reset(test, free_guarded_buf, buf));
- return buf + full_len - len;
-}
-
/*
* Test for sha256_finup_2x(). Specifically, choose various data lengths and
* salt lengths, and for each one, verify that sha256_finup_2x() produces the
@@ -105,19 +86,20 @@ static void test_sha256_finup_2x(struct kunit *test)
static void test_sha256_finup_2x_defaultctx(struct kunit *test)
{
const size_t data_len = 128;
+ u8 *data = alloc_buf(test, 2 * data_len);
struct sha256_ctx ctx;
u8 hash1_a[SHA256_DIGEST_SIZE];
u8 hash2_a[SHA256_DIGEST_SIZE];
u8 hash1_b[SHA256_DIGEST_SIZE];
u8 hash2_b[SHA256_DIGEST_SIZE];
- rand_bytes(test_buf, 2 * data_len);
+ rand_bytes(data, 2 * data_len);
sha256_init(&ctx);
- sha256_finup_2x(&ctx, test_buf, &test_buf[data_len], data_len, hash1_a,
+ sha256_finup_2x(&ctx, data, &data[data_len], data_len, hash1_a,
hash2_a);
- sha256_finup_2x(NULL, test_buf, &test_buf[data_len], data_len, hash1_b,
+ sha256_finup_2x(NULL, data, &data[data_len], data_len, hash1_b,
hash2_b);
KUNIT_ASSERT_MEMEQ(test, hash1_a, hash1_b, SHA256_DIGEST_SIZE);
@@ -131,18 +113,19 @@ static void test_sha256_finup_2x_defaultctx(struct kunit *test)
static void test_sha256_finup_2x_hugelen(struct kunit *test)
{
const size_t data_len = 4 * SHA256_BLOCK_SIZE;
+ u8 *data = alloc_buf(test, data_len);
struct sha256_ctx ctx = {};
u8 expected_hash[SHA256_DIGEST_SIZE];
u8 hash[SHA256_DIGEST_SIZE];
- rand_bytes(test_buf, data_len);
+ rand_bytes(data, data_len);
for (size_t align = 0; align < SHA256_BLOCK_SIZE; align++) {
sha256_init(&ctx);
ctx.ctx.bytecount = 0x123456789abcd00 + align;
- sha256_finup_2x(&ctx, test_buf, test_buf, data_len, hash, hash);
+ sha256_finup_2x(&ctx, data, data, data_len, hash, hash);
- sha256_update(&ctx, test_buf, data_len);
+ sha256_update(&ctx, data, data_len);
sha256_final(&ctx, expected_hash);
KUNIT_ASSERT_MEMEQ(test, hash, expected_hash,
@@ -161,6 +144,7 @@ static void benchmark_sha256_finup_2x(struct kunit *test)
static const size_t salt_lens_to_test[] = { 0, 32, 64 };
const size_t data_len = 4096;
const size_t num_iters = 4096;
+ u8 *data = alloc_buf(test, data_len * 2);
struct sha256_ctx ctx;
u8 hash1[SHA256_DIGEST_SIZE];
u8 hash2[SHA256_DIGEST_SIZE];
@@ -170,12 +154,12 @@ static void benchmark_sha256_finup_2x(struct kunit *test)
if (!sha256_finup_2x_is_optimized())
kunit_skip(test, "not relevant");
- rand_bytes(test_buf, data_len * 2);
+ rand_bytes(data, data_len * 2);
/* Warm-up */
for (size_t i = 0; i < num_iters; i++)
- sha256_finup_2x(NULL, &test_buf[0], &test_buf[data_len],
- data_len, hash1, hash2);
+ sha256_finup_2x(NULL, &data[0], &data[data_len], data_len,
+ hash1, hash2);
for (size_t i = 0; i < ARRAY_SIZE(salt_lens_to_test); i++) {
size_t salt_len = salt_lens_to_test[i];
@@ -186,12 +170,12 @@ static void benchmark_sha256_finup_2x(struct kunit *test)
* not measured; we're just interested in sha256_finup_2x().
*/
sha256_init(&ctx);
- sha256_update(&ctx, test_buf, salt_len);
+ sha256_update(&ctx, data, salt_len);
preempt_disable();
t0 = ktime_get_ns();
for (size_t j = 0; j < num_iters; j++)
- sha256_finup_2x(&ctx, &test_buf[0], &test_buf[data_len],
+ sha256_finup_2x(&ctx, &data[0], &data[data_len],
data_len, hash1, hash2);
t1 = ktime_get_ns();
preempt_enable();
@@ -215,8 +199,6 @@ static struct kunit_case hash_test_cases[] = {
static struct kunit_suite hash_test_suite = {
.name = "sha256",
.test_cases = hash_test_cases,
- .suite_init = hash_suite_init,
- .suite_exit = hash_suite_exit,
};
kunit_test_suite(hash_test_suite);
diff --git a/lib/crypto/tests/sha384_kunit.c b/lib/crypto/tests/sha384_kunit.c
index e1ef5c995bb6..76409822d965 100644
--- a/lib/crypto/tests/sha384_kunit.c
+++ b/lib/crypto/tests/sha384_kunit.c
@@ -30,8 +30,6 @@ static struct kunit_case hash_test_cases[] = {
static struct kunit_suite hash_test_suite = {
.name = "sha384",
.test_cases = hash_test_cases,
- .suite_init = hash_suite_init,
- .suite_exit = hash_suite_exit,
};
kunit_test_suite(hash_test_suite);
diff --git a/lib/crypto/tests/sha3_kunit.c b/lib/crypto/tests/sha3_kunit.c
index ed5fbe80337f..81b113079755 100644
--- a/lib/crypto/tests/sha3_kunit.c
+++ b/lib/crypto/tests/sha3_kunit.c
@@ -273,12 +273,10 @@ static void test_shake_all_lens_up_to_4096(struct kunit *test)
{
struct sha3_ctx main_ctx;
const size_t max_len = 4096;
- u8 *const in = test_buf;
- u8 *const out = &test_buf[TEST_BUF_LEN - max_len];
+ u8 *const in = alloc_buf(test, max_len);
+ u8 *const out = alloc_buf(test, max_len);
u8 main_hash[SHA3_256_DIGEST_SIZE];
- KUNIT_ASSERT_LE(test, 2 * max_len, TEST_BUF_LEN);
-
rand_bytes_seeded_from_len(in, max_len);
for (int alg = 0; alg < 2; alg++) {
sha3_256_init(&main_ctx);
@@ -309,12 +307,8 @@ static void test_shake_all_lens_up_to_4096(struct kunit *test)
static void test_shake_multiple_squeezes(struct kunit *test)
{
const size_t max_len = 512;
- u8 *ref_out;
-
- KUNIT_ASSERT_GE(test, TEST_BUF_LEN, 2 * max_len);
-
- ref_out = kunit_kzalloc(test, max_len, GFP_KERNEL);
- KUNIT_ASSERT_NOT_NULL(test, ref_out);
+ u8 *buf = alloc_buf(test, max_len);
+ u8 *ref_out = alloc_buf(test, max_len);
for (int i = 0; i < 2000; i++) {
const int alg = rand32() % 2;
@@ -322,8 +316,8 @@ static void test_shake_multiple_squeezes(struct kunit *test)
const size_t out_len = rand_length(max_len);
const size_t in_offs = rand_offset(max_len - in_len);
const size_t out_offs = rand_offset(max_len - out_len);
- u8 *const in = &test_buf[in_offs];
- u8 *const out = &test_buf[out_offs];
+ u8 *const in = &buf[in_offs];
+ u8 *const out = &buf[out_offs];
struct shake_ctx ctx;
size_t remaining_len, j, num_parts;
@@ -368,16 +362,12 @@ static void test_shake_multiple_squeezes(struct kunit *test)
static void test_shake_with_guarded_bufs(struct kunit *test)
{
const size_t max_len = 512;
- u8 *reg_buf;
-
- KUNIT_ASSERT_GE(test, TEST_BUF_LEN, max_len);
-
- reg_buf = kunit_kzalloc(test, max_len, GFP_KERNEL);
- KUNIT_ASSERT_NOT_NULL(test, reg_buf);
+ u8 *buf = alloc_guarded_buf(test, max_len);
+ u8 *reg_buf = alloc_buf(test, max_len);
for (int alg = 0; alg < 2; alg++) {
for (size_t len = 0; len <= max_len; len++) {
- u8 *guarded_buf = &test_buf[TEST_BUF_LEN - len];
+ u8 *guarded_buf = &buf[max_len - len];
rand_bytes(reg_buf, len);
memcpy(guarded_buf, reg_buf, len);
@@ -413,8 +403,6 @@ static struct kunit_case sha3_test_cases[] = {
static struct kunit_suite sha3_test_suite = {
.name = "sha3",
.test_cases = sha3_test_cases,
- .suite_init = hash_suite_init,
- .suite_exit = hash_suite_exit,
};
kunit_test_suite(sha3_test_suite);
diff --git a/lib/crypto/tests/sha512_kunit.c b/lib/crypto/tests/sha512_kunit.c
index 8923e2d7d3d4..e03926c24403 100644
--- a/lib/crypto/tests/sha512_kunit.c
+++ b/lib/crypto/tests/sha512_kunit.c
@@ -30,8 +30,6 @@ static struct kunit_case hash_test_cases[] = {
static struct kunit_suite hash_test_suite = {
.name = "sha512",
.test_cases = hash_test_cases,
- .suite_init = hash_suite_init,
- .suite_exit = hash_suite_exit,
};
kunit_test_suite(hash_test_suite);
diff --git a/lib/crypto/tests/sm3_kunit.c b/lib/crypto/tests/sm3_kunit.c
index dc8136acdff6..1cba384946e9 100644
--- a/lib/crypto/tests/sm3_kunit.c
+++ b/lib/crypto/tests/sm3_kunit.c
@@ -22,8 +22,6 @@ static struct kunit_case sm3_test_cases[] = {
static struct kunit_suite sm3_test_suite = {
.name = "sm3",
.test_cases = sm3_test_cases,
- .suite_init = hash_suite_init,
- .suite_exit = hash_suite_exit,
};
kunit_test_suite(sm3_test_suite);
diff --git a/lib/crypto/tests/test-utils.h b/lib/crypto/tests/test-utils.h
new file mode 100644
index 000000000000..73ca21f9176e
--- /dev/null
+++ b/lib/crypto/tests/test-utils.h
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Test utility functions shared by the crypto library tests.
+ *
+ * For now this is simply a header that's included into the KUnit test suites
+ * that need it. If this gets too large it could be made its own translation
+ * unit and libcrypto_test_utils module, but that seems overkill for now.
+ */
+#ifndef LIB_CRYPTO_TEST_UTILS_H
+#define LIB_CRYPTO_TEST_UTILS_H
+
+#include <kunit/test.h>
+#include <linux/math.h>
+#include <linux/minmax.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+
+static u64 random_seed;
+
+static __maybe_unused void action_free_guarded_buf(void *buf)
+{
+ vfree(buf);
+}
+
+/*
+ * Allocate a KUnit-managed buffer that has length @size bytes (> 0) immediately
+ * followed by an unmapped page, and assert that the allocation succeeds.
+ */
+static __maybe_unused void *alloc_guarded_buf(struct kunit *test, size_t size)
+{
+ size_t full_size = round_up(size, PAGE_SIZE);
+ void *buf = vmalloc(full_size);
+
+ KUNIT_ASSERT_NOT_NULL(test, buf);
+ KUNIT_ASSERT_EQ(test, 0,
+ kunit_add_action_or_reset(test, action_free_guarded_buf,
+ buf));
+ return buf + full_size - size;
+}
+
+static __maybe_unused void *alloc_buf(struct kunit *test, size_t size)
+{
+ void *buf = kunit_kmalloc(test, size, GFP_KERNEL);
+
+ KUNIT_ASSERT_NOT_NULL(test, buf);
+ return buf;
+}
+
+static __maybe_unused void *memdup_buf(struct kunit *test, const void *src,
+ size_t size)
+{
+ void *dst = alloc_buf(test, size);
+
+ return memcpy(dst, src, size);
+}
+
+/*
+ * This is a simple linear congruential generator. It is used only for testing,
+ * which does not require cryptographically secure random numbers. A hard-coded
+ * algorithm is used instead of <linux/prandom.h> so that it matches the
+ * algorithm used by the test vector generation script. This allows the input
+ * data in random test vectors to be concisely stored as just the seed.
+ */
+static __maybe_unused u32 rand32(void)
+{
+ random_seed = (random_seed * 25214903917 + 11) & ((1ULL << 48) - 1);
+ return random_seed >> 16;
+}
+
+static __maybe_unused void rand_bytes(u8 *out, size_t len)
+{
+ for (size_t i = 0; i < len; i++)
+ out[i] = rand32();
+}
+
+static __maybe_unused void rand_bytes_seeded_from_len(u8 *out, size_t len)
+{
+ random_seed = len;
+ rand_bytes(out, len);
+}
+
+static __maybe_unused bool rand_bool(void)
+{
+ return rand32() % 2;
+}
+
+/* Generate a random length, preferring small lengths. */
+static __maybe_unused size_t rand_length(size_t max_len)
+{
+ size_t len;
+
+ switch (rand32() % 3) {
+ case 0:
+ len = rand32() % 128;
+ break;
+ case 1:
+ len = rand32() % 3072;
+ break;
+ default:
+ len = rand32();
+ break;
+ }
+ return len % (max_len + 1);
+}
+
+static __maybe_unused size_t rand_offset(size_t max_offset)
+{
+ return min(rand32() % 128, max_offset);
+}
+
+#endif /* LIB_CRYPTO_TEST_UTILS_H */
diff --git a/lib/embedded-cmdline.S b/lib/embedded-cmdline.S
new file mode 100644
index 000000000000..bda81b4a42be
--- /dev/null
+++ b/lib/embedded-cmdline.S
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Embed the build-time-rendered bootconfig "kernel" subtree as a flat
+ * cmdline string. setup_arch() prepends this to boot_command_line on
+ * architectures that select ARCH_SUPPORTS_CMDLINE_FROM_BOOTCONFIG.
+ *
+ * Copyright (c) 2026 Meta Platforms, Inc. and affiliates
+ * Copyright (c) 2026 Breno Leitao <leitao@debian.org>
+ */
+ .section .init.rodata.embed_cmdline, "a", %progbits
+ .global embedded_kernel_cmdline
+embedded_kernel_cmdline:
+ .incbin "lib/embedded_cmdline.bin"
+ .byte 0
+ .global embedded_kernel_cmdline_end
+embedded_kernel_cmdline_end:
diff --git a/lib/find_bit_benchmark.c b/lib/find_bit_benchmark.c
index 00d9dc61cd46..05305e655f99 100644
--- a/lib/find_bit_benchmark.c
+++ b/lib/find_bit_benchmark.c
@@ -149,6 +149,21 @@ static int __init test_find_next_and_bit(const void *bitmap,
return 0;
}
+static int __init
+test_bitmap_find_next_zero_area_off(unsigned long *bitmap, unsigned long len)
+{
+ unsigned long i, cnt;
+ ktime_t time;
+
+ time = ktime_get();
+ for (cnt = i = 0; i < BITMAP_LEN; cnt++)
+ i = bitmap_find_next_zero_area_off(bitmap, BITMAP_LEN, i, 8, 0, 0) + 1;
+ time = ktime_get() - time;
+ pr_err("bitmap_find_next_zero_area_off:%7llu ns, %6ld iterations\n", time, cnt);
+
+ return 0;
+}
+
static int __init find_bit_test(void)
{
unsigned long nbits = BITMAP_LEN / SPARSE;
@@ -158,6 +173,7 @@ static int __init find_bit_test(void)
get_random_bytes(bitmap, sizeof(bitmap));
get_random_bytes(bitmap2, sizeof(bitmap2));
+ test_bitmap_find_next_zero_area_off(bitmap, BITMAP_LEN);
test_find_next_bit(bitmap, BITMAP_LEN);
test_find_next_zero_bit(bitmap, BITMAP_LEN);
test_find_last_bit(bitmap, BITMAP_LEN);
@@ -181,6 +197,7 @@ static int __init find_bit_test(void)
__set_bit(get_random_u32_below(BITMAP_LEN), bitmap2);
}
+ test_bitmap_find_next_zero_area_off(bitmap, BITMAP_LEN);
test_find_next_bit(bitmap, BITMAP_LEN);
test_find_next_zero_bit(bitmap, BITMAP_LEN);
test_find_last_bit(bitmap, BITMAP_LEN);
diff --git a/lib/fonts/fonts.c b/lib/fonts/fonts.c
index f5d5333450a0..4fc66722d00d 100644
--- a/lib/fonts/fonts.c
+++ b/lib/fonts/fonts.c
@@ -178,6 +178,37 @@ unsigned int font_data_size(font_data_t *fd)
}
EXPORT_SYMBOL_GPL(font_data_size);
+static unsigned int font_data_num_glyphs(font_data_t *fd, unsigned int width, unsigned int height)
+{
+ return font_data_size(fd) / font_glyph_size(width, height);
+}
+
+/**
+ * font_data_glyph_buf() - Returns the glyph for a specific character as raw bytes
+ * @fd: The font data
+ * @width: The glyph width in bits per scanline
+ * @vpitch: The number of scanlines per glyph
+ * @c: The character
+ *
+ * Glyphs start at fixed intervals within the font data. font_data_glyph_buf()
+ * returns the glyph shape of the specified character. If no such glyph
+ * exists in the font, it returns NULL.
+ *
+ * Returns:
+ * The character's raw glyph shape, or NULL if no glyph exists for the character. The
+ * provided buffer is read-only.
+ */
+const unsigned char *font_data_glyph_buf(font_data_t *fd,
+ unsigned int width, unsigned int vpitch,
+ unsigned int c)
+{
+ if (c >= font_data_num_glyphs(fd, width, vpitch))
+ return NULL;
+
+ return font_data_buf(fd) + font_glyph_size(width, vpitch) * c;
+}
+EXPORT_SYMBOL_GPL(font_data_glyph_buf);
+
/**
* font_data_is_equal - Compares font data for equality
* @lhs: Left-hand side font data
diff --git a/lib/glob.c b/lib/glob.c
index 7aca76c25bcb..c80d9dd736b4 100644
--- a/lib/glob.c
+++ b/lib/glob.c
@@ -11,6 +11,9 @@
MODULE_DESCRIPTION("glob(7) matching");
MODULE_LICENSE("Dual MIT/GPL");
+static bool __pure glob_match_str(char const *pat, char const *str,
+ char const *str_end);
+
/**
* glob_match - Shell-style pattern matching, like !fnmatch(pat, str, 0)
* @pat: Shell-style pattern to match, e.g. "*.[ch]".
@@ -41,6 +44,29 @@ MODULE_LICENSE("Dual MIT/GPL");
*/
bool __pure glob_match(char const *pat, char const *str)
{
+ return glob_match_str(pat, str, NULL);
+}
+EXPORT_SYMBOL(glob_match);
+
+/**
+ * glob_match_len - glob match against a length-bounded string
+ * @pat: Shell-style pattern to match.
+ * @str: String to match. Need not be NUL-terminated.
+ * @len: Number of bytes of @str that may be read.
+ *
+ * Like glob_match(), but @str is only read up to @len bytes, so it can be
+ * used on buffers that are not NUL-terminated (e.g. trace event fields).
+ * A NUL byte within @len still terminates the string.
+ */
+bool __pure glob_match_len(char const *pat, char const *str, size_t len)
+{
+ return glob_match_str(pat, str, str + len);
+}
+EXPORT_SYMBOL(glob_match_len);
+
+static bool __pure glob_match_str(char const *pat, char const *str,
+ char const *str_end)
+{
/*
* Backtrack to previous * on mismatch and retry starting one
* character later in the string. Because * matches all characters
@@ -55,9 +81,11 @@ bool __pure glob_match(char const *pat, char const *str)
* on mismatch, or true after matching the trailing nul bytes.
*/
for (;;) {
- unsigned char c = *str++;
+ unsigned char c = (str_end && str >= str_end) ? '\0' : *str;
unsigned char d = *pat++;
+ str++;
+
switch (d) {
case '?': /* Wildcard: anything but nul */
if (c == '\0')
@@ -125,4 +153,3 @@ backtrack:
}
}
}
-EXPORT_SYMBOL(glob_match);
diff --git a/lib/interval_tree_test.c b/lib/interval_tree_test.c
index eba2d3e28980..b0b07270ce7c 100644
--- a/lib/interval_tree_test.c
+++ b/lib/interval_tree_test.c
@@ -140,13 +140,13 @@ static int intersection_range_check(void)
intxn1 = bitmap_alloc(nnodes, GFP_KERNEL);
if (!intxn1) {
- WARN_ON_ONCE("Failed to allocate intxn1\n");
+ WARN_ONCE(1, "Failed to allocate intxn1\n");
return -ENOMEM;
}
intxn2 = bitmap_alloc(nnodes, GFP_KERNEL);
if (!intxn2) {
- WARN_ON_ONCE("Failed to allocate intxn2\n");
+ WARN_ONCE(1, "Failed to allocate intxn2\n");
bitmap_free(intxn1);
return -ENOMEM;
}
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
index 273919b16161..6665372ecf71 100644
--- a/lib/iov_iter.c
+++ b/lib/iov_iter.c
@@ -1491,6 +1491,7 @@ void iov_iter_restore(struct iov_iter *i, struct iov_iter_state *state)
i->__iov -= state->nr_segs - i->nr_segs;
i->nr_segs = state->nr_segs;
}
+EXPORT_SYMBOL_FOR_MODULES(iov_iter_restore, "vmw_vsock_virtio_transport_common");
/*
* Extract a list of contiguous pages from an ITER_FOLIOQ iterator. This does
@@ -1568,6 +1569,7 @@ static ssize_t iov_iter_extract_xarray_pages(struct iov_iter *i,
struct folio *folio;
unsigned int nr = 0, offset;
loff_t pos = i->xarray_start + i->iov_offset;
+ bool will_alloc = !*pages;
XA_STATE(xas, i->xarray, pos >> PAGE_SHIFT);
offset = pos & ~PAGE_MASK;
@@ -1595,6 +1597,14 @@ static ssize_t iov_iter_extract_xarray_pages(struct iov_iter *i,
}
rcu_read_unlock();
+ if (!nr) {
+ if (will_alloc) {
+ kvfree(*pages);
+ *pages = NULL;
+ }
+ return 0;
+ }
+
maxsize = min_t(size_t, nr * PAGE_SIZE - offset, maxsize);
iov_iter_advance(i, maxsize);
return maxsize;
@@ -1625,9 +1635,11 @@ static ssize_t iov_iter_extract_bvec_pages(struct iov_iter *i,
}
bi.bi_idx = 0;
bi.bi_size = maxsize;
- bi.bi_bvec_done = skip;
+ bi.bi_offset = skip;
maxpages = want_pages_array(pages, maxsize, skip, maxpages);
+ if (!maxpages)
+ return -ENOMEM;
while (bi.bi_size && bi.bi_idx < i->nr_segs) {
struct bio_vec bv = bvec_iter_bvec(i->bvec, bi);
@@ -1745,6 +1757,7 @@ static ssize_t iov_iter_extract_user_pages(struct iov_iter *i,
unsigned long addr;
unsigned int gup_flags = 0;
size_t offset;
+ bool will_alloc = !*pages;
int res;
if (i->data_source == ITER_DEST)
@@ -1761,8 +1774,14 @@ static ssize_t iov_iter_extract_user_pages(struct iov_iter *i,
if (!maxpages)
return -ENOMEM;
res = pin_user_pages_fast(addr, maxpages, gup_flags, *pages);
- if (unlikely(res <= 0))
+ if (unlikely(res <= 0)) {
+ if (will_alloc) {
+ kvfree(*pages);
+ *pages = NULL;
+ }
return res;
+ }
+
maxsize = min_t(size_t, maxsize, res * PAGE_SIZE - offset);
iov_iter_advance(i, maxsize);
return maxsize;
@@ -1886,6 +1905,8 @@ static unsigned int get_contig_folio_len(struct page **pages,
* @max_size: maximum size to extract from @iter
* @nr_vecs: number of vectors in @bv (on in and output)
* @max_vecs: maximum vectors in @bv, including those filled before calling
+ * @mem_align_mask: reject with -EINVAL if the source address or
+ * length is not aligned to this mask
* @extraction_flags: flags to qualify request
*
* Like iov_iter_extract_pages(), but returns physically contiguous ranges
@@ -1897,14 +1918,19 @@ static unsigned int get_contig_folio_len(struct page **pages,
*/
ssize_t iov_iter_extract_bvecs(struct iov_iter *iter, struct bio_vec *bv,
size_t max_size, unsigned short *nr_vecs,
- unsigned short max_vecs, iov_iter_extraction_t extraction_flags)
+ unsigned short max_vecs, unsigned mem_align_mask,
+ iov_iter_extraction_t extraction_flags)
{
+ unsigned long start = (unsigned long)iter_iov_addr(iter);
unsigned short entries_left = max_vecs - *nr_vecs;
unsigned short nr_pages, i = 0;
size_t left, offset, len;
struct page **pages;
ssize_t size;
+ if ((start | iter_iov_len(iter)) & mem_align_mask)
+ return -EINVAL;
+
/*
* Move page array up in the allocated memory for the bio vecs as far as
* possible so that we can start filling biovecs from the beginning
diff --git a/lib/kobject.c b/lib/kobject.c
index 9c9ff0f5175f..e7b010a989fb 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -823,9 +823,11 @@ static ssize_t kobj_attr_show(struct kobject *kobj, struct attribute *attr,
struct kobj_attribute *kattr;
ssize_t ret = -EIO;
- kattr = container_of(attr, struct kobj_attribute, attr);
+ kattr = container_of_const(attr, struct kobj_attribute, attr);
if (kattr->show)
ret = kattr->show(kobj, kattr, buf);
+ else if (kattr->show_const)
+ ret = kattr->show_const(kobj, kattr, buf);
return ret;
}
@@ -835,9 +837,11 @@ static ssize_t kobj_attr_store(struct kobject *kobj, struct attribute *attr,
struct kobj_attribute *kattr;
ssize_t ret = -EIO;
- kattr = container_of(attr, struct kobj_attribute, attr);
+ kattr = container_of_const(attr, struct kobj_attribute, attr);
if (kattr->store)
ret = kattr->store(kobj, kattr, buf, count);
+ else if (kattr->store_const)
+ ret = kattr->store_const(kobj, kattr, buf, count);
return ret;
}
diff --git a/lib/kstrtox.c b/lib/kstrtox.c
index edc4eb7c1bca..bac1c057e1b0 100644
--- a/lib/kstrtox.c
+++ b/lib/kstrtox.c
@@ -17,6 +17,7 @@
#include <linux/export.h>
#include <linux/kstrtox.h>
#include <linux/math64.h>
+#include <linux/overflow.h>
#include <linux/types.h>
#include <linux/uaccess.h>
@@ -45,6 +46,7 @@ const char *_parse_integer_fixup_radix(const char *s, unsigned int *base)
* @base: Radix
* @p: Where to store result
* @max_chars: Maximum amount of characters to convert
+ * @init: Initial value of the multiply-accumulate result
*
* Convert non-negative integer string representation in explicitly given
* radix to an integer. If overflow occurs, value at @p is set to ULLONG_MAX.
@@ -56,12 +58,12 @@ const char *_parse_integer_fixup_radix(const char *s, unsigned int *base)
*/
noinline
unsigned int _parse_integer_limit(const char *s, unsigned int base, unsigned long long *p,
- size_t max_chars)
+ size_t max_chars, unsigned long long init)
{
unsigned int rv, overflow = 0;
unsigned long long res;
- res = 0;
+ res = init;
for (rv = 0; rv < max_chars; rv++, s++) {
unsigned int c = *s;
unsigned int lc = _tolower(c);
@@ -94,12 +96,6 @@ unsigned int _parse_integer_limit(const char *s, unsigned int base, unsigned lon
return rv | overflow;
}
-noinline
-unsigned int _parse_integer(const char *s, unsigned int base, unsigned long long *p)
-{
- return _parse_integer_limit(s, base, p, INT_MAX);
-}
-
static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res)
{
unsigned long long _res;
@@ -399,6 +395,109 @@ int kstrtobool(const char *s, bool *res)
}
EXPORT_SYMBOL(kstrtobool);
+static int _kstrtoudec64(const char *s, unsigned int scale, u64 *res)
+{
+ unsigned int rv_int, rv_frac;
+ u64 _res = 0;
+
+ rv_int = _parse_integer(s, 10, &_res);
+ if (rv_int & KSTRTOX_OVERFLOW)
+ return -ERANGE;
+ s += rv_int;
+
+ if (*s == '.')
+ s++; /* skip decimal point */
+
+ rv_frac = _parse_integer(s, 10, &_res, scale, _res);
+ if (rv_frac & KSTRTOX_OVERFLOW)
+ return -ERANGE;
+ s += rv_frac;
+
+ /*
+ * Check input beyond rv_int and rv_frac to cover cases like ".5" with
+ * scale 0, which is considered a valid input, being parsed as 0.
+ */
+ if (!rv_int && !rv_frac && !isdigit(*s))
+ return -EINVAL;
+
+ while (isdigit(*s)) /* truncate digits */
+ s++;
+
+ if (*s == '\n')
+ s++;
+ if (*s)
+ return -EINVAL;
+
+ if (_res && ((scale - rv_frac) > 19 /* log10(2^64) = 19.26 */ ||
+ check_mul_overflow(_res, int_pow(10, scale - rv_frac), &_res)))
+ return -ERANGE;
+
+ *res = _res;
+ return 0;
+}
+
+/**
+ * kstrtoudec64() - Convert a string to an unsigned 64-bit scaled decimal value.
+ * @s: The start of the string. The string must be null-terminated, and may also
+ * include a single newline before its terminating null. The first character
+ * may also be a plus sign, but not a minus sign.
+ * @scale: The number of digits to the right of the decimal point.
+ * @res: Where to write the result of the conversion on success.
+ *
+ * For example, a scale of 3 with input "123.45" results in 123450. Note that
+ * trailing zeros in the fractional part input to match the scale are not
+ * required. Also, digits beyond the specified scale are ignored.
+ *
+ * Return: 0 on success, -ERANGE on overflow and -EINVAL on parsing error.
+ */
+noinline
+int kstrtoudec64(const char *s, unsigned int scale, u64 *res)
+{
+ if (s[0] == '+')
+ s++;
+ return _kstrtoudec64(s, scale, res);
+}
+EXPORT_SYMBOL(kstrtoudec64);
+
+/**
+ * kstrtodec64() - Convert a string to a signed 64-bit scaled decimal value.
+ * @s: The start of the string. The string must be null-terminated, and may also
+ * include a single newline before its terminating null. The first character
+ * may also be a plus sign or a minus sign.
+ * @scale: The number of digits to the right of the decimal point.
+ * @res: Where to write the result of the conversion on success.
+ *
+ * For example, a scale of 4 with input "-3.141592" results in -31415. Note
+ * that digits beyond the specified scale are ignored. Also, trailing zeros in
+ * the fractional part input to match the scale are not required.
+ *
+ * Return: 0 on success, -ERANGE on overflow and -EINVAL on parsing error.
+ */
+noinline
+int kstrtodec64(const char *s, unsigned int scale, s64 *res)
+{
+ u64 tmp;
+ int rv;
+
+ if (s[0] == '-') {
+ rv = _kstrtoudec64(s + 1, scale, &tmp);
+ if (rv < 0)
+ return rv;
+ if ((s64)-tmp > 0)
+ return -ERANGE;
+ *res = -tmp;
+ } else {
+ rv = kstrtoudec64(s, scale, &tmp);
+ if (rv < 0)
+ return rv;
+ if ((s64)tmp < 0)
+ return -ERANGE;
+ *res = tmp;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(kstrtodec64);
+
/*
* Since "base" would be a nonsense argument, this open-codes the
* _from_user helper instead of using the helper macro below.
diff --git a/lib/kstrtox.h b/lib/kstrtox.h
index 158c400ca865..73dee79fd8ed 100644
--- a/lib/kstrtox.h
+++ b/lib/kstrtox.h
@@ -2,10 +2,23 @@
#ifndef _LIB_KSTRTOX_H
#define _LIB_KSTRTOX_H
+#include <linux/args.h>
+
#define KSTRTOX_OVERFLOW (1U << 31)
const char *_parse_integer_fixup_radix(const char *s, unsigned int *base);
unsigned int _parse_integer_limit(const char *s, unsigned int base, unsigned long long *res,
- size_t max_chars);
-unsigned int _parse_integer(const char *s, unsigned int base, unsigned long long *res);
+ size_t max_chars, unsigned long long init);
+
+#define _parse_integer0(s, base, res, ...) \
+ _parse_integer_limit(s, base, res, INT_MAX, 0)
+
+#define _parse_integer1(s, base, res, max_chars, ...) \
+ _parse_integer_limit(s, base, res, max_chars, 0)
+
+#define _parse_integer2(s, base, res, max_chars, init, ...) \
+ _parse_integer_limit(s, base, res, max_chars, init)
+
+#define _parse_integer(s, base, res, ...) \
+ CONCATENATE(_parse_integer, COUNT_ARGS(__VA_ARGS__))(s, base, res, __VA_ARGS__)
#endif
diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
index 2e8a6b71a2ab..204e02b10eba 100644
--- a/lib/kunit/Makefile
+++ b/lib/kunit/Makefile
@@ -11,6 +11,7 @@ kunit-objs += test.o \
attributes.o \
device.o \
platform.o \
+ fwnode.o \
bug.o
ifeq ($(CONFIG_KUNIT_DEBUGFS),y)
diff --git a/lib/kunit/debugfs.c b/lib/kunit/debugfs.c
index 9c326f1837bd..442b2ceb955b 100644
--- a/lib/kunit/debugfs.c
+++ b/lib/kunit/debugfs.c
@@ -76,18 +76,30 @@ static int debugfs_print_results(struct seq_file *seq, void *v)
seq_puts(seq, "KTAP version 1\n");
seq_puts(seq, "1..1\n");
- /* Print suite header because it is not stored in the test logs. */
- seq_puts(seq, KUNIT_SUBTEST_INDENT "KTAP version 1\n");
- seq_printf(seq, KUNIT_SUBTEST_INDENT "# Subtest: %s\n", suite->name);
- seq_printf(seq, KUNIT_SUBTEST_INDENT "1..%zd\n", kunit_suite_num_test_cases(suite));
-
- kunit_suite_for_each_test_case(suite, test_case)
- debugfs_print_result(seq, test_case->log);
+ if (suite->status != KUNIT_SKIPPED) {
+ /* Print suite header because it is not stored in the test logs. */
+ seq_puts(seq,
+ KUNIT_SUBTEST_INDENT "KTAP version 1\n");
+ seq_printf(seq,
+ KUNIT_SUBTEST_INDENT "# Subtest: %s\n",
+ suite->name);
+ seq_printf(seq,
+ KUNIT_SUBTEST_INDENT "1..%zd\n",
+ kunit_suite_num_test_cases(suite));
+
+ kunit_suite_for_each_test_case(suite, test_case)
+ debugfs_print_result(seq, test_case->log);
+ }
debugfs_print_result(seq, suite->log);
- seq_printf(seq, "%s %d %s\n",
- kunit_status_to_ok_not_ok(success), 1, suite->name);
+ if (suite->status != KUNIT_SKIPPED)
+ seq_printf(seq, "%s %d %s\n",
+ kunit_status_to_ok_not_ok(success), 1, suite->name);
+ else
+ seq_printf(seq, "%s %d %s # SKIP %s\n",
+ kunit_status_to_ok_not_ok(success), 1, suite->name,
+ suite->status_comment);
return 0;
}
diff --git a/lib/kunit/fwnode.c b/lib/kunit/fwnode.c
new file mode 100644
index 000000000000..a58ce0984d76
--- /dev/null
+++ b/lib/kunit/fwnode.c
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Qualcomm Technologies, Inc. and/or its subsidiaries
+ */
+
+#include <kunit/fwnode.h>
+#include <kunit/test.h>
+
+#include <linux/fwnode.h>
+#include <linux/property.h>
+
+KUNIT_DEFINE_ACTION_WRAPPER(fwnode_remove_software_node_wrapper,
+ fwnode_remove_software_node,
+ struct fwnode_handle *);
+
+/**
+ * kunit_fwnode_create_software_node() - Create a kunit-managed software node
+ * @test: Test context
+ * @properties: Properties to use to create the new software node
+ * @parent: Parent of this software node
+ *
+ * Create a test-managed software node and return its firmware node handle.
+ * The software node is removed after the test case completes.
+ *
+ * Returns:
+ * Firmware node handle of the newly created software node or IS_ERR() on
+ * failure.
+ */
+struct fwnode_handle *
+kunit_fwnode_create_software_node(struct kunit *test,
+ const struct property_entry *properties,
+ const struct fwnode_handle *parent)
+{
+ struct fwnode_handle *fwnode;
+ int ret;
+
+ fwnode = fwnode_create_software_node(properties, parent);
+ if (IS_ERR(fwnode))
+ return fwnode;
+
+ ret = kunit_add_action_or_reset(test, fwnode_remove_software_node_wrapper,
+ fwnode);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return fwnode;
+}
+EXPORT_SYMBOL_GPL(kunit_fwnode_create_software_node);
+
+KUNIT_DEFINE_ACTION_WRAPPER(software_node_unregister_wrapper,
+ software_node_unregister,
+ const struct software_node *);
+
+/**
+ * kunit_software_node_register() - Register a kunit-managed software node
+ * @test: Test context
+ * @swnode: Software node to register
+ *
+ * Register a test-managed software node and return its firmware node handle.
+ * The software node is unregistered after the test case completes.
+ *
+ * Returns:
+ * Firmware node handle of the registered software node or IS_ERR() on failure.
+ */
+struct fwnode_handle *
+kunit_software_node_register(struct kunit *test,
+ const struct software_node *swnode)
+{
+ struct fwnode_handle *fwnode;
+ int ret;
+
+ ret = software_node_register(swnode);
+ if (ret)
+ return ERR_PTR(ret);
+
+ fwnode = software_node_fwnode(swnode);
+ if (WARN_ON(!fwnode))
+ return ERR_PTR(-ENOENT);
+
+ ret = kunit_add_action_or_reset(test, software_node_unregister_wrapper,
+ (void *)swnode);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return fwnode;
+}
+EXPORT_SYMBOL_GPL(kunit_software_node_register);
+
+KUNIT_DEFINE_ACTION_WRAPPER(software_node_unregister_node_group_wrapper,
+ software_node_unregister_node_group,
+ const struct software_node *const *);
+
+/**
+ * kunit_software_node_register_node_group() - Register a kunit-managed software node group
+ * @test: Test context
+ * @nodes: Software node group to register
+ *
+ * Register a test-managed software node group. The nodes are unregistered
+ * after the test case completes.
+ *
+ * Returns:
+ * 0 on success, negative error number on failure.
+ */
+int kunit_software_node_register_node_group(struct kunit *test,
+ const struct software_node *const *nodes)
+{
+ int ret;
+
+ ret = software_node_register_node_group(nodes);
+ if (ret)
+ return ret;
+
+ return kunit_add_action_or_reset(test, software_node_unregister_node_group_wrapper,
+ (void *)nodes);
+}
+EXPORT_SYMBOL_GPL(kunit_software_node_register_node_group);
+
+KUNIT_DEFINE_ACTION_WRAPPER(device_remove_software_node_wrapper,
+ device_remove_software_node,
+ struct device *);
+
+/**
+ * kunit_device_add_software_node() - Assign a kunit-managed software node to a device
+ * @test: Test context
+ * @dev: Device to assign the software node for
+ * @node: The software node to assign
+ *
+ * Make @node the secondary firmware node of @dev. If @dev has no primary
+ * firmware node, @node will become the primary node. The software node will
+ * be automatically removed from @dev when the test case completes.
+ *
+ * Returns:
+ * 0 on success, negative error number on failure.
+ */
+int kunit_device_add_software_node(struct kunit *test, struct device *dev,
+ const struct software_node *node)
+{
+ int ret;
+
+ ret = device_add_software_node(dev, node);
+ if (ret)
+ return ret;
+
+ return kunit_add_action_or_reset(test, device_remove_software_node_wrapper, dev);
+}
+EXPORT_SYMBOL_GPL(kunit_device_add_software_node);
diff --git a/lib/kunit/kunit-example-test.c b/lib/kunit/kunit-example-test.c
index 0bae7b7ca0b0..b8ded54fa46d 100644
--- a/lib/kunit/kunit-example-test.c
+++ b/lib/kunit/kunit-example-test.c
@@ -591,5 +591,34 @@ static struct kunit_suite example_init_test_suite = {
*/
kunit_test_init_section_suites(&example_init_test_suite);
+/*
+ * This test should always be skipped.
+ */
+static void example_skip_suite_test(struct kunit *test)
+{
+ /* This line should never be seen */
+ KUNIT_FAIL(test, "You should not see a this.");
+}
+
+static struct kunit_case example_skip_suite_test_cases[] = {
+ KUNIT_CASE(example_skip_suite_test),
+ {}
+};
+
+static int example_skip_suite_init(struct kunit_suite *suite)
+{
+ kunit_mark_skipped(suite, "Test suite expected to be skipped");
+ return 0;
+}
+
+static struct kunit_suite example_test_skip_suite = {
+ .name = "example_skip_suite",
+ .suite_init = example_skip_suite_init,
+ .test_cases = example_skip_suite_test_cases,
+};
+
+/* This registers a test suite that will be skipped */
+kunit_test_suite(example_test_skip_suite);
+
MODULE_DESCRIPTION("Example KUnit test suite");
MODULE_LICENSE("GPL v2");
diff --git a/lib/kunit/string-stream.c b/lib/kunit/string-stream.c
index 0d8f1b30559b..51ba40ebf19f 100644
--- a/lib/kunit/string-stream.c
+++ b/lib/kunit/string-stream.c
@@ -9,6 +9,7 @@
#include <kunit/static_stub.h>
#include <kunit/test.h>
#include <linux/list.h>
+#include <linux/seq_buf.h>
#include <linux/slab.h>
#include "string-stream.h"
@@ -74,7 +75,8 @@ int string_stream_vadd(struct string_stream *stream,
/* Append newline if necessary. */
if (frag_container->fragment[result_len - 1] != '\n')
- result_len = strlcat(frag_container->fragment, "\n", buf_len);
+ result_len += strscpy(frag_container->fragment + result_len,
+ "\n", buf_len - result_len);
} else {
result_len = vsnprintf(frag_container->fragment, buf_len, fmt, args);
}
@@ -118,15 +120,18 @@ char *string_stream_get_string(struct string_stream *stream)
{
struct string_stream_fragment *frag_container;
size_t buf_len = stream->length + 1; /* +1 for null byte. */
+ struct seq_buf sb;
char *buf;
buf = kzalloc(buf_len, stream->gfp);
if (!buf)
return NULL;
+ seq_buf_init(&sb, buf, buf_len);
+
spin_lock(&stream->lock);
list_for_each_entry(frag_container, &stream->fragments, node)
- strlcat(buf, frag_container->fragment, buf_len);
+ seq_buf_puts(&sb, frag_container->fragment);
spin_unlock(&stream->lock);
return buf;
diff --git a/lib/kunit/test.c b/lib/kunit/test.c
index 99773e000e1b..09e3dabfac0c 100644
--- a/lib/kunit/test.c
+++ b/lib/kunit/test.c
@@ -214,12 +214,18 @@ enum kunit_status kunit_suite_has_succeeded(struct kunit_suite *suite)
const struct kunit_case *test_case;
enum kunit_status status = KUNIT_SKIPPED;
+ if (suite->status == KUNIT_SKIPPED)
+ return KUNIT_SKIPPED;
+
if (suite->suite_init_err)
return KUNIT_FAILURE;
kunit_suite_for_each_test_case(suite, test_case) {
- if (test_case->status == KUNIT_FAILURE)
+ if (test_case->status == KUNIT_FAILURE) {
+ /* Update the kunit_suite status also */
+ suite->status = KUNIT_FAILURE;
return KUNIT_FAILURE;
+ }
else if (test_case->status == KUNIT_SUCCESS)
status = KUNIT_SUCCESS;
}
@@ -795,12 +801,20 @@ int kunit_run_tests(struct kunit_suite *suite)
/* Taint the kernel so we know we've run tests. */
add_taint(TAINT_TEST, LOCKDEP_STILL_OK);
+ if (suite->status == KUNIT_SKIPPED)
+ goto suite_end;
+
if (suite->suite_init) {
suite->suite_init_err = suite->suite_init(suite);
if (suite->suite_init_err) {
+ suite->status = KUNIT_FAILURE;
kunit_err(suite, KUNIT_SUBTEST_INDENT
"# failed to initialize (%d)", suite->suite_init_err);
goto suite_end;
+
+ } else if (suite->status == KUNIT_SKIPPED) {
+ /* Skip this kunit suite */
+ goto suite_end;
}
}
@@ -825,6 +839,7 @@ static void kunit_init_suite(struct kunit_suite *suite)
kunit_debugfs_create_suite(suite);
suite->status_comment[0] = '\0';
suite->suite_init_err = 0;
+ suite->status = KUNIT_SUCCESS;
if (suite->log)
string_stream_clear(suite->log);
diff --git a/lib/locking-selftest.c b/lib/locking-selftest.c
index bfafe1204c7b..c3d976c801bb 100644
--- a/lib/locking-selftest.c
+++ b/lib/locking-selftest.c
@@ -1429,7 +1429,7 @@ static int unexpected_testcase_failures;
static void dotest(void (*testcase_fn)(void), int expected, int lockclass_mask)
{
- int saved_preempt_count = preempt_count();
+ long saved_preempt_count = preempt_count();
#ifdef CONFIG_PREEMPT_RT
int saved_mgd_count = current->migration_disabled;
int saved_rcu_count = current->rcu_read_lock_nesting;
diff --git a/lib/lockref.c b/lib/lockref.c
index 5d8e3ef3860e..9b3dd688d8cd 100644
--- a/lib/lockref.c
+++ b/lib/lockref.c
@@ -131,7 +131,7 @@ EXPORT_SYMBOL(lockref_put_or_lock);
void lockref_mark_dead(struct lockref *lockref)
{
assert_spin_locked(&lockref->lock);
- lockref->count = -128;
+ lockref->count = __LOCKREF_DEAD_VAL;
}
EXPORT_SYMBOL(lockref_mark_dead);
diff --git a/lib/maple_tree.c b/lib/maple_tree.c
index e52876435b77..1aba6cced713 100644
--- a/lib/maple_tree.c
+++ b/lib/maple_tree.c
@@ -261,6 +261,12 @@ static inline bool mas_is_underflow(struct ma_state *mas)
return mas->status == ma_underflow;
}
+static inline void mas_make_walkable(struct ma_state *mas)
+{
+ if (!mas_is_active(mas) && !mas_is_start(mas))
+ mas->status = ma_start;
+}
+
static __always_inline struct maple_node *mte_to_node(
const struct maple_enode *entry)
{
@@ -356,11 +362,6 @@ static __always_inline bool mte_is_root(const struct maple_enode *node)
return ma_is_root(mte_to_node(node));
}
-static inline bool mas_is_root_limits(const struct ma_state *mas)
-{
- return !mas->min && mas->max == ULONG_MAX;
-}
-
static __always_inline bool mt_is_alloc(struct maple_tree *mt)
{
return (mt->ma_flags & MT_FLAGS_ALLOC_RANGE);
@@ -456,46 +457,6 @@ enum maple_type mas_parent_type(struct ma_state *mas, struct maple_enode *enode)
}
/*
- * mas_set_parent() - Set the parent node and encode the slot
- * @mas: The maple state
- * @enode: The encoded maple node.
- * @parent: The encoded maple node that is the parent of @enode.
- * @slot: The slot that @enode resides in @parent.
- *
- * Slot number is encoded in the enode->parent bit 3-6 or 2-6, depending on the
- * parent type.
- */
-static inline
-void mas_set_parent(struct ma_state *mas, struct maple_enode *enode,
- const struct maple_enode *parent, unsigned char slot)
-{
- unsigned long val = (unsigned long)parent;
- unsigned long shift;
- unsigned long type;
- enum maple_type p_type = mte_node_type(parent);
-
- MAS_BUG_ON(mas, p_type == maple_dense);
- MAS_BUG_ON(mas, p_type == maple_leaf_64);
-
- switch (p_type) {
- case maple_range_64:
- case maple_arange_64:
- shift = MAPLE_PARENT_SLOT_SHIFT;
- type = MAPLE_PARENT_RANGE64;
- break;
- default:
- case maple_dense:
- case maple_leaf_64:
- shift = type = 0;
- break;
- }
-
- val &= ~MAPLE_NODE_MASK; /* Clear all node metadata in parent */
- val |= (slot << shift) | type;
- mte_to_node(enode)->parent = ma_parent_ptr(val);
-}
-
-/*
* mte_parent_slot() - get the parent slot of @enode.
* @enode: The encoded maple node.
*
@@ -877,6 +838,42 @@ static inline void ma_set_meta_gap(struct maple_node *mn, enum maple_type mt,
}
/*
+ * mas_set_parent_slots() - Bulk operation to set many slot parent pointers
+ * @mas: The maple state
+ * @parent: The encoded maple node that is the parent of @enode.
+ * @slot: The slot that of the @enode.
+ * @start_slot: The offset into @slot
+ * @count: The number of slots to set (eg: exclusive)
+ */
+static inline
+void mas_set_parent_slots(struct ma_state *mas, struct maple_enode *parent,
+ void __rcu **slots, unsigned char start_slot, unsigned char count)
+{
+ unsigned long val;
+ unsigned long shift;
+ unsigned long type;
+ enum maple_type p_type = mte_node_type(parent);
+ unsigned char i;
+
+ MAS_BUG_ON(mas, p_type != maple_range_64 &&
+ p_type != maple_arange_64);
+
+ shift = MAPLE_PARENT_SLOT_SHIFT;
+ type = MAPLE_PARENT_RANGE64;
+
+ val = (unsigned long)parent;
+ val &= ~MAPLE_NODE_MASK;
+
+ for (i = 0; i < count; i++) {
+ unsigned long pval = val | ((start_slot + i) << shift) | type;
+ struct maple_enode *child;
+
+ child = mt_slot_locked(mas->tree, slots, i);
+ mte_to_node(child)->parent = ma_parent_ptr(pval);
+ }
+}
+
+/*
* mat_add() - Add a @dead_enode to the ma_topiary of a list of dead nodes.
* @mat: the ma_topiary, a linked list of dead nodes.
* @dead_enode: the node to be marked as dead and added to the tail of the list
@@ -1153,6 +1150,79 @@ static inline void mas_free(struct ma_state *mas, struct maple_enode *used)
ma_free_rcu(mte_to_node(used));
}
+
+#ifdef CONFIG_LOCKDEP
+static struct lockdep_map *mas_lockdep_map(struct ma_state *mas)
+{
+ struct maple_tree *mt = mas->tree;
+
+ if (mt_external_lock(mt))
+ return mt->ma_external_lock;
+
+ return &(mt->ma_lock).dep_map;
+}
+
+#endif
+
+static void mas_lock_check(struct ma_state *mas)
+{
+#ifdef CONFIG_LOCKDEP
+ struct lockdep_map *map;
+ u32 seq;
+
+ if (!mas_is_active(mas))
+ return;
+
+#ifdef CONFIG_RCU_STRICT_GRACE_PERIOD
+ if (!mt_locked(mas->tree)) {
+ if (mt_in_rcu(mas->tree))
+ WARN_ON_ONCE(poll_state_synchronize_rcu(mas->rcu_gp));
+ }
+#endif /* CONFIG_RCU_STRICT_GRACE_PERIOD */
+
+ map = mas_lockdep_map(mas);
+ if (!map)
+ return;
+
+ seq = lock_sequence(map);
+ if (seq != UINT_MAX && mas->ld_seq != UINT_MAX)
+ WARN_ON_ONCE(mas->ld_seq != seq);
+#endif /* CONFIG_LOCKDEP */
+
+}
+
+static void mas_init_lock_check(struct ma_state *mas)
+{
+#ifdef CONFIG_LOCKDEP
+ struct lockdep_map *map;
+#ifdef CONFIG_RCU_STRICT_GRACE_PERIOD
+ if (!mt_locked(mas->tree)) {
+ if (mt_in_rcu(mas->tree))
+ mas->rcu_gp = get_state_synchronize_rcu();
+ return;
+ }
+#endif /* CONFIG_RCU_STRICT_GRACE_PERIOD */
+
+ map = mas_lockdep_map(mas);
+ if (map) /* Update regardless of lock state */
+ mas->ld_seq = lock_sequence(map);
+#endif /* CONFIG_LOCKDEP */
+
+}
+
+static void mas_may_init_lock_check(struct ma_state *mas)
+{
+#ifdef CONFIG_LOCKDEP
+#ifdef CONFIG_RCU_STRICT_GRACE_PERIOD
+ if (mas_is_start(mas) || mas_is_paused(mas)) {
+ mas_init_lock_check(mas);
+ return;
+ }
+#endif /* CONFIG_RCU_STRICT_GRACE_PERIOD */
+ mas_lock_check(mas);
+#endif /* CONFIG_LOCKDEP */
+}
+
/*
* mas_start() - Sets up maple state for operations.
* @mas: The maple state.
@@ -1171,6 +1241,7 @@ static inline struct maple_enode *mas_start(struct ma_state *mas)
if (likely(mas_is_start(mas))) {
struct maple_enode *root;
+ mas_init_lock_check(mas);
mas->min = 0;
mas->max = ULONG_MAX;
@@ -1501,14 +1572,26 @@ ascend:
goto ascend;
}
+static __always_inline void mas_update_gap_known(struct ma_state *mas,
+ unsigned long gap)
+{
+ unsigned char pslot;
+ unsigned long p_gap;
+
+ pslot = mte_parent_slot(mas->node);
+ p_gap = ma_gaps(mte_parent(mas->node),
+ mas_parent_type(mas, mas->node))[pslot];
+
+ if (p_gap != gap)
+ mas_parent_gap(mas, pslot, gap);
+}
+
/*
* mas_update_gap() - Update a nodes gaps and propagate up if necessary.
* @mas: the maple state.
*/
static inline void mas_update_gap(struct ma_state *mas)
{
- unsigned char pslot;
- unsigned long p_gap;
unsigned long max_gap;
if (!mt_is_alloc(mas->tree))
@@ -1518,13 +1601,7 @@ static inline void mas_update_gap(struct ma_state *mas)
return;
max_gap = mas_max_gap(mas);
-
- pslot = mte_parent_slot(mas->node);
- p_gap = ma_gaps(mte_parent(mas->node),
- mas_parent_type(mas, mas->node))[pslot];
-
- if (p_gap != max_gap)
- mas_parent_gap(mas, pslot, max_gap);
+ mas_update_gap_known(mas, max_gap);
}
/*
@@ -1540,14 +1617,10 @@ static inline void mas_adopt_children(struct ma_state *mas,
struct maple_node *node = mte_to_node(parent);
void __rcu **slots = ma_slots(node, type);
unsigned long *pivots = ma_pivots(node, type);
- struct maple_enode *child;
- unsigned char offset;
+ unsigned char end;
- offset = ma_data_end(node, type, pivots, mas->max);
- do {
- child = mas_slot_locked(mas, slots, offset);
- mas_set_parent(mas, child, parent, offset);
- } while (offset--);
+ end = ma_data_end(node, type, pivots, mas->max);
+ mas_set_parent_slots(mas, parent, slots, 0, end + 1);
}
/*
@@ -1929,15 +2002,10 @@ unsigned long node_copy(struct ma_state *mas, struct maple_node *src,
s_slots = ma_slots(src, s_mt) + start;
s_pivots = ma_pivots(src, s_mt) + start;
memcpy(d_slots, s_slots, size * sizeof(void __rcu *));
- if (!ma_is_leaf(d_mt) && s_mt == maple_copy) {
- struct maple_enode *edst = mt_mk_node(dst, d_mt);
-
- for (int i = 0; i < size; i++)
- mas_set_parent(mas,
- mt_slot_locked(mas->tree, d_slots, i),
- edst, d_start + i);
- }
+ if (!ma_is_leaf(d_mt) && s_mt == maple_copy)
+ mas_set_parent_slots(mas, mt_mk_node(dst, d_mt),
+ d_slots, d_start, size);
d_gaps = ma_gaps(dst, d_mt);
if (d_gaps) {
@@ -2081,8 +2149,8 @@ static inline void mas_wmb_replace(struct ma_state *mas, struct maple_copy *cp)
mas->node = mt_slot_locked(mas->tree, cp->slot, 0);
/* Insert the new data in the tree */
mas_topiary_replace(mas, old_enode, cp->height);
- if (!mte_is_leaf(mas->node))
- mas_update_gap(mas);
+ if (mt_is_alloc(mas->tree) && !mte_is_root(mas->node))
+ mas_update_gap_known(mas, cp->gap[0]);
mtree_range_walk(mas);
}
@@ -2928,13 +2996,6 @@ static inline void mas_extend_spanning_null(struct ma_wr_state *l_wr_mas,
if (r_mas->last < r_wr_mas->r_max)
r_mas->last = r_wr_mas->r_max;
r_mas->offset++;
- } else if ((r_mas->last == r_wr_mas->r_max) &&
- (r_mas->last < r_mas->max) &&
- !mas_slot_locked(r_mas, r_wr_mas->slots, r_mas->offset + 1)) {
- r_mas->last = mas_safe_pivot(r_mas, r_wr_mas->pivots,
- r_wr_mas->type, r_mas->offset + 1);
- r_mas->offset++;
- r_wr_mas->r_max = r_mas->last;
}
}
@@ -3125,7 +3186,7 @@ static void mas_wr_spanning_store(struct ma_wr_state *wr_mas)
static inline void mas_wr_node_store(struct ma_wr_state *wr_mas)
{
unsigned char dst_offset, offset_end;
- unsigned char copy_size, node_pivots;
+ unsigned char copy_size, node_pivots, node_slots;
struct maple_node reuse, *newnode;
unsigned long *dst_pivots;
void __rcu **dst_slots;
@@ -3138,6 +3199,7 @@ static inline void mas_wr_node_store(struct ma_wr_state *wr_mas)
in_rcu = mt_in_rcu(mas->tree);
offset_end = wr_mas->offset_end;
node_pivots = mt_pivots[wr_mas->type];
+ node_slots = mt_slots[wr_mas->type];
/* Assume last adds an entry */
new_end = mas->end + 1 - offset_end + mas->offset;
if (mas->last == wr_mas->end_piv) {
@@ -3149,7 +3211,6 @@ static inline void mas_wr_node_store(struct ma_wr_state *wr_mas)
if (in_rcu) {
newnode = mas_pop_node(mas);
} else {
- memset(&reuse, 0, sizeof(struct maple_node));
newnode = &reuse;
}
@@ -3193,7 +3254,21 @@ static inline void mas_wr_node_store(struct ma_wr_state *wr_mas)
dst_pivots[new_end] = mas->max;
done:
- mas_leaf_set_meta(newnode, maple_leaf_64, new_end);
+ if (!in_rcu && new_end + 2 < node_slots) {
+ unsigned char clear_from = new_end + 1;
+
+ /*
+ * Note that the last slot is never cleared, since the metadata
+ * will be stored there or it has a value.
+ */
+ memset(dst_slots + clear_from, 0,
+ sizeof(void __rcu *) * (node_slots - clear_from));
+ if (clear_from < node_pivots)
+ memset(dst_pivots + clear_from, 0,
+ sizeof(unsigned long) * (node_pivots - clear_from));
+ }
+
+ mas_leaf_set_meta(newnode, wr_mas->type, new_end);
if (in_rcu) {
struct maple_enode *old_enode = mas->node;
@@ -3218,7 +3293,7 @@ static inline void mas_wr_slot_store(struct ma_wr_state *wr_mas)
void __rcu **slots = wr_mas->slots;
bool gap = false;
- gap |= !mt_slot_locked(mas->tree, slots, offset);
+ gap |= !wr_mas->content;
gap |= !mt_slot_locked(mas->tree, slots, offset + 1);
if (wr_mas->offset_end - offset == 1) {
@@ -3595,7 +3670,7 @@ set_content:
/**
* mas_prealloc_calc() - Calculate number of nodes needed for a
- * given store oepration
+ * given store operation
* @wr_mas: The maple write state
* @entry: The entry to store into the tree
*
@@ -3661,6 +3736,9 @@ static inline enum store_type mas_wr_store_type(struct ma_wr_state *wr_mas)
{
struct ma_state *mas = wr_mas->mas;
unsigned char new_end;
+ bool appending;
+ bool one_slot;
+ bool in_rcu;
if (unlikely(mas_is_none(mas) || mas_is_ptr(mas)))
return wr_store_root;
@@ -3680,21 +3758,30 @@ static inline enum store_type mas_wr_store_type(struct ma_wr_state *wr_mas)
return wr_new_root;
new_end = mas_wr_new_end(wr_mas);
+ in_rcu = mt_in_rcu(mas->tree);
+ appending = mas->offset == mas->end;
+ one_slot = wr_mas->offset_end - mas->offset == 1;
+
/* Potential spanning rebalance collapsing a node */
if (new_end < mt_min_slots[wr_mas->type]) {
if (!mte_is_root(mas->node))
return wr_rebalance;
+ if (!in_rcu) {
+ if (appending)
+ return wr_append;
+ else if (mas->end == new_end && one_slot)
+ return wr_slot_store;
+ }
return wr_node_store;
}
if (new_end >= mt_slots[wr_mas->type])
return wr_split_store;
- if (!mt_in_rcu(mas->tree) && (mas->offset == mas->end))
+ if (!in_rcu && appending)
return wr_append;
- if ((new_end == mas->end) && (!mt_in_rcu(mas->tree) ||
- (wr_mas->offset_end - mas->offset == 1)))
+ if (new_end == mas->end && (!in_rcu || one_slot))
return wr_slot_store;
return wr_node_store;
@@ -3793,35 +3880,40 @@ int mas_alloc_cyclic(struct ma_state *mas, unsigned long *startp,
void *entry, unsigned long range_lo, unsigned long range_hi,
unsigned long *next, gfp_t gfp)
{
- unsigned long min = range_lo;
- int ret = 0;
-
- range_lo = max(min, *next);
- ret = mas_empty_area(mas, range_lo, range_hi, 1);
- if ((mas->tree->ma_flags & MT_FLAGS_ALLOC_WRAPPED) && ret == 0) {
- mas->tree->ma_flags &= ~MT_FLAGS_ALLOC_WRAPPED;
- ret = 1;
- }
- if (ret < 0 && range_lo > min) {
- mas_reset(mas);
- ret = mas_empty_area(mas, min, range_hi, 1);
- if (ret == 0)
- ret = 1;
- }
- if (ret < 0)
- return ret;
+ int ret;
+ unsigned long min;
+ min = range_lo;
do {
+ range_lo = max(min, *next);
+ ret = mas_empty_area(mas, range_lo, range_hi, 1);
+ if (ret < 0 && range_lo > min) {
+ mas_reset(mas);
+ ret = mas_empty_area(mas, min, range_hi, 1);
+ if (ret == 0)
+ ret = 1;
+ }
+ if (ret < 0)
+ goto out;
+
mas_insert(mas, entry);
} while (mas_nomem(mas, gfp));
- if (mas_is_err(mas))
- return xa_err(mas->node);
+ if (mas_is_err(mas)) {
+ ret = xa_err(mas->node);
+ goto out;
+ }
+
+ if ((mas->tree->ma_flags & MT_FLAGS_ALLOC_WRAPPED) && ret == 0) {
+ mas->tree->ma_flags &= ~MT_FLAGS_ALLOC_WRAPPED;
+ ret = 1;
+ }
*startp = mas->index;
*next = *startp + 1;
if (*next == 0)
mas->tree->ma_flags |= MT_FLAGS_ALLOC_WRAPPED;
+out:
mas_destroy(mas);
return ret;
}
@@ -4360,8 +4452,8 @@ void *mas_walk(struct ma_state *mas)
{
void *entry;
- if (!mas_is_active(mas) && !mas_is_start(mas))
- mas->status = ma_start;
+ mas_may_init_lock_check(mas);
+ mas_make_walkable(mas);
retry:
entry = mas_state_walk(mas);
if (mas_is_start(mas)) {
@@ -4831,6 +4923,7 @@ void *mas_store(struct ma_state *mas, void *entry)
{
MA_WR_STATE(wr_mas, mas, entry);
+ mas_may_init_lock_check(mas);
trace_ma_write(TP_FCT, mas, 0, entry);
#ifdef CONFIG_DEBUG_MAPLE_TREE
if (MAS_WARN_ON(mas, mas->index > mas->last))
@@ -4889,6 +4982,7 @@ int mas_store_gfp(struct ma_state *mas, void *entry, gfp_t gfp)
MA_WR_STATE(wr_mas, mas, entry);
int ret = 0;
+ mas_may_init_lock_check(mas);
retry:
mas_wr_preallocate(&wr_mas, entry);
if (unlikely(mas_nomem(mas, gfp))) {
@@ -4919,6 +5013,7 @@ void mas_store_prealloc(struct ma_state *mas, void *entry)
{
MA_WR_STATE(wr_mas, mas, entry);
+ mas_lock_check(mas);
if (mas->store_type == wr_store_root) {
mas_wr_prealloc_setup(&wr_mas);
goto store;
@@ -4951,6 +5046,7 @@ int mas_preallocate(struct ma_state *mas, void *entry, gfp_t gfp)
{
MA_WR_STATE(wr_mas, mas, entry);
+ mas_may_init_lock_check(mas);
mas_wr_prealloc_setup(&wr_mas);
mas->store_type = mas_wr_store_type(&wr_mas);
mas_prealloc_calc(&wr_mas, entry);
@@ -4997,6 +5093,7 @@ static void mas_may_activate(struct ma_state *mas)
mas->status = ma_start;
} else {
mas->status = ma_active;
+ mas_lock_check(mas);
}
}
@@ -5074,6 +5171,7 @@ void *mas_next(struct ma_state *mas, unsigned long max)
{
void *entry = NULL;
+ mas_may_init_lock_check(mas);
if (mas_next_setup(mas, max, &entry))
return entry;
@@ -5097,6 +5195,7 @@ void *mas_next_range(struct ma_state *mas, unsigned long max)
{
void *entry = NULL;
+ mas_may_init_lock_check(mas);
if (mas_next_setup(mas, max, &entry))
return entry;
@@ -5205,6 +5304,7 @@ void *mas_prev(struct ma_state *mas, unsigned long min)
{
void *entry = NULL;
+ mas_may_init_lock_check(mas);
if (mas_prev_setup(mas, min, &entry))
return entry;
@@ -5228,6 +5328,7 @@ void *mas_prev_range(struct ma_state *mas, unsigned long min)
{
void *entry = NULL;
+ mas_may_init_lock_check(mas);
if (mas_prev_setup(mas, min, &entry))
return entry;
@@ -5274,6 +5375,7 @@ EXPORT_SYMBOL_GPL(mt_prev);
*/
void mas_pause(struct ma_state *mas)
{
+ mas_lock_check(mas);
mas->status = ma_pause;
mas->node = NULL;
}
@@ -5382,6 +5484,7 @@ void *mas_find(struct ma_state *mas, unsigned long max)
{
void *entry = NULL;
+ mas_may_init_lock_check(mas);
if (mas_find_setup(mas, max, &entry))
return entry;
@@ -5409,6 +5512,7 @@ void *mas_find_range(struct ma_state *mas, unsigned long max)
{
void *entry = NULL;
+ mas_may_init_lock_check(mas);
if (mas_find_setup(mas, max, &entry))
return entry;
@@ -5428,7 +5532,6 @@ EXPORT_SYMBOL_GPL(mas_find_range);
static bool mas_find_rev_setup(struct ma_state *mas, unsigned long min,
void **entry)
{
-
switch (mas->status) {
case ma_active:
goto active;
@@ -5521,6 +5624,7 @@ void *mas_find_rev(struct ma_state *mas, unsigned long min)
{
void *entry = NULL;
+ mas_may_init_lock_check(mas);
if (mas_find_rev_setup(mas, min, &entry))
return entry;
@@ -5547,6 +5651,7 @@ void *mas_find_range_rev(struct ma_state *mas, unsigned long min)
{
void *entry = NULL;
+ mas_may_init_lock_check(mas);
if (mas_find_rev_setup(mas, min, &entry))
return entry;
@@ -5564,6 +5669,11 @@ EXPORT_SYMBOL_GPL(mas_find_range_rev);
* Searches for @mas->index, sets @mas->index and @mas->last to the range and
* erases that range.
*
+ * Note that erase requires allocations and will use GFP_KERNEL | __GFP_NOFAIL
+ * to do so if necessary. If the allocation fails, the internal lock will be
+ * dropped to retry. An externally locked tree must be protected by a lock that
+ * allows blocking for this API.
+ *
* Return: the entry that was erased or %NULL, @mas->index and @mas->last are updated.
*/
void *mas_erase(struct ma_state *mas)
@@ -5572,25 +5682,25 @@ void *mas_erase(struct ma_state *mas)
unsigned long index = mas->index;
MA_WR_STATE(wr_mas, mas, NULL);
- if (!mas_is_active(mas) || !mas_is_start(mas))
- mas->status = ma_start;
+ /*
+ * In low memory situations, the allocation is retried with the gfp flag
+ * GFP_KERNEL | __GFP_NOFAIL. The internal spinlock is dropped in
+ * mas_nomem_nofail(), however the external lock is not dropped.
+ */
+ if (mt_external_lock(mas->tree))
+ might_alloc(GFP_KERNEL);
+ mas_make_walkable(mas);
write_retry:
entry = mas_state_walk(mas);
if (!entry)
- return NULL;
+ goto out;
/* Must reset to ensure spanning writes of last slot are detected */
mas_reset(mas);
mas_wr_preallocate(&wr_mas, NULL);
- if (mas_nomem(mas, GFP_KERNEL)) {
- /* in case the range of entry changed when unlocked */
- mas->index = mas->last = index;
+ if (mas_nomem_nofail(mas, index, index))
goto write_retry;
- }
-
- if (mas_is_err(mas))
- goto out;
mas_wr_store_entry(&wr_mas);
out:
@@ -5601,10 +5711,11 @@ EXPORT_SYMBOL_GPL(mas_erase);
/**
* mas_nomem() - Check if there was an error allocating and do the allocation
- * if necessary If there are allocations, then free them.
+ * if necessary.
+ *
* @mas: The maple state
* @gfp: The GFP_FLAGS to use for allocations
- * Return: true on allocation, false otherwise.
+ * Return: False on no memory. True otherwise (partial success as well)
*/
bool mas_nomem(struct ma_state *mas, gfp_t gfp)
__must_hold(mas->tree->ma_lock)
@@ -5612,6 +5723,10 @@ bool mas_nomem(struct ma_state *mas, gfp_t gfp)
if (likely(mas->node != MA_ERROR(-ENOMEM)))
return false;
+ /* Allocations can fail, don't do this. */
+ WARN_ON_ONCE(!gfpflags_allow_blocking(gfp) &&
+ mt_external_lock(mas->tree));
+
if (gfpflags_allow_blocking(gfp) && !mt_external_lock(mas->tree)) {
mtree_unlock(mas->tree);
mas_alloc_nodes(mas, gfp);
@@ -5620,10 +5735,49 @@ bool mas_nomem(struct ma_state *mas, gfp_t gfp)
mas_alloc_nodes(mas, gfp);
}
+ /*
+ * Return false on zero forward progress. Partial allocations are kept
+ * so the retry path will attempt to get the rest. The failure should
+ * not happen as we try our best to reclaim. The user would need an
+ * external lock with a non-blocking gfp in a low memory situation.
+ */
if (!mas->sheaf && !mas->alloc)
return false;
- mas->status = ma_start;
+ mas_reset(mas);
+ return true;
+}
+
+/**
+ * mas_nomem_nofail() - Retry allocations with __GFP_NOFAIL, if the maple state
+ * has stored the -ENOMEM error.
+ * @mas: The maple state
+ * @index: The start of the range for the @mas reset
+ * @last: The end of the range for the @mas reset
+ *
+ * Return: false if @mas isn't in an -ENOMEM state. True if the allocation
+ * happens, the state is reset. The internal lock will be dropped and external
+ * locks must allow blocking.
+ */
+bool mas_nomem_nofail(struct ma_state *mas, unsigned long index,
+ unsigned long last)
+ __must_hold(mas->tree->ma_lock)
+{
+ gfp_t gfp;
+
+ if (likely(mas->node != MA_ERROR(-ENOMEM)))
+ return false;
+
+ gfp = GFP_KERNEL | __GFP_NOFAIL;
+ if (!mt_external_lock(mas->tree)) {
+ mtree_unlock(mas->tree);
+ mas_alloc_nodes(mas, gfp);
+ mtree_lock(mas->tree);
+ } else {
+ mas_alloc_nodes(mas, gfp);
+ }
+
+ mas_set_range(mas, index, last);
return true;
}
@@ -5913,6 +6067,10 @@ EXPORT_SYMBOL(mtree_alloc_rrange);
* Erasing is the same as a walk to an entry then a store of a NULL to that
* ENTIRE range. In fact, it is implemented as such using the advanced API.
*
+ * Note that erase requires allocations and will use GFP_KERNEL | __GFP_NOFAIL
+ * to do so if necessary. If the allocation fails, the internal lock will be
+ * dropped to retry.
+ *
* Return: The entry stored at the @index or %NULL
*/
void *mtree_erase(struct maple_tree *mt, unsigned long index)
@@ -5922,6 +6080,7 @@ void *mtree_erase(struct maple_tree *mt, unsigned long index)
MA_STATE(mas, mt, index, index);
trace_ma_op(TP_FCT, &mas);
+ might_alloc(GFP_KERNEL);
mtree_lock(mt);
entry = mas_erase(&mas);
mtree_unlock(mt);
@@ -6447,7 +6606,7 @@ static void mt_dump_range(unsigned long min, unsigned long max,
{
static const char spaces[] = " ";
- switch(format) {
+ switch (format) {
case mt_dump_hex:
if (min == max)
pr_info("%.*s%lx: ", depth * 2, spaces, min);
@@ -6489,7 +6648,7 @@ static void mt_dump_range64(const struct maple_tree *mt, void *entry,
pr_cont(" contents: ");
for (i = 0; i < MAPLE_RANGE64_SLOTS - 1; i++) {
- switch(format) {
+ switch (format) {
case mt_dump_hex:
pr_cont(PTR_FMT " %lX ", node->slot[i], node->pivot[i]);
break;
@@ -6517,7 +6676,7 @@ static void mt_dump_range64(const struct maple_tree *mt, void *entry,
if (last == max)
break;
if (last > max) {
- switch(format) {
+ switch (format) {
case mt_dump_hex:
pr_err("node " PTR_FMT " last (%lx) > max (%lx) at pivot %d!\n",
node, last, max, i);
@@ -6576,7 +6735,7 @@ static void mt_dump_arange64(const struct maple_tree *mt, void *entry,
if (last == max)
break;
if (last > max) {
- switch(format) {
+ switch (format) {
case mt_dump_hex:
pr_err("node " PTR_FMT " last (%lx) > max (%lx) at pivot %d!\n",
node, last, max, i);
diff --git a/lib/math/div64.c b/lib/math/div64.c
index d1e92ea24fce..0b10ded09a9b 100644
--- a/lib/math/div64.c
+++ b/lib/math/div64.c
@@ -158,6 +158,21 @@ u64 div64_u64(u64 dividend, u64 divisor)
EXPORT_SYMBOL(div64_u64);
#endif
+#ifndef div64_s64_rem
+s64 div64_s64_rem(s64 dividend, s64 divisor, s64 *remainder)
+{
+ s64 quot, t, rem;
+
+ quot = div64_u64_rem(abs(dividend), abs(divisor), (u64 *)&rem);
+ t = dividend >> 63;
+ *remainder = (rem ^ t) - t;
+ t = (dividend ^ divisor) >> 63;
+
+ return (quot ^ t) - t;
+}
+EXPORT_SYMBOL(div64_s64_rem);
+#endif
+
#ifndef div64_s64
s64 div64_s64(s64 dividend, s64 divisor)
{
diff --git a/lib/math/test_mul_u64_u64_div_u64.c b/lib/math/test_mul_u64_u64_div_u64.c
index 338d014f0c73..d12dc05938fb 100644
--- a/lib/math/test_mul_u64_u64_div_u64.c
+++ b/lib/math/test_mul_u64_u64_div_u64.c
@@ -157,6 +157,7 @@ static void __exit test_exit(void)
#define __div64_32 __div64_32
#define div_s64_rem div_s64_rem
#define div64_u64_rem div64_u64_rem
+#define div64_s64_rem div64_s64_rem
#define div64_u64 div64_u64
#define div64_s64 div64_s64
#define iter_div_u64_rem iter_div_u64_rem
diff --git a/lib/math/tests/Makefile b/lib/math/tests/Makefile
index 13dc96e48408..85e1ad59f29d 100644
--- a/lib/math/tests/Makefile
+++ b/lib/math/tests/Makefile
@@ -4,5 +4,6 @@ obj-$(CONFIG_GCD_KUNIT_TEST) += gcd_kunit.o
obj-$(CONFIG_INT_LOG_KUNIT_TEST) += int_log_kunit.o
obj-$(CONFIG_INT_POW_KUNIT_TEST) += int_pow_kunit.o
obj-$(CONFIG_INT_SQRT_KUNIT_TEST) += int_sqrt_kunit.o
+obj-$(CONFIG_POLYNOMIAL_KUNIT_TEST) += polynomial_kunit.o
obj-$(CONFIG_PRIME_NUMBERS_KUNIT_TEST) += prime_numbers_kunit.o
obj-$(CONFIG_RATIONAL_KUNIT_TEST) += rational_kunit.o
diff --git a/lib/math/tests/polynomial_kunit.c b/lib/math/tests/polynomial_kunit.c
new file mode 100644
index 000000000000..ef443b57fc12
--- /dev/null
+++ b/lib/math/tests/polynomial_kunit.c
@@ -0,0 +1,270 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <kunit/test.h>
+#include <linux/polynomial.h>
+
+struct polynomial_test_param {
+ const struct polynomial *poly;
+ long data;
+ long expected;
+ const char *name;
+};
+
+/* f(x) = 5 */
+static const struct polynomial poly_constant = {
+ .total_divider = 1,
+ .terms = {
+ {0, 5, 1, 1},
+ }
+};
+
+/* f(x) = 2x^2 + 3x + 5 */
+static const struct polynomial poly_simple = {
+ .total_divider = 1,
+ .terms = {
+ {2, 2, 1, 1},
+ {1, 3, 1, 1},
+ {0, 5, 1, 1},
+ }
+};
+
+/* f(x) = -5x + 100 */
+static const struct polynomial poly_negative_coef = {
+ .total_divider = 1,
+ .terms = {
+ {1, -5, 1, 1},
+ {0, 100, 1, 1},
+ }
+};
+
+/* f(x) = (150x + 50) / 10 */
+static const struct polynomial poly_total_divider = {
+ .total_divider = 10,
+ .terms = {
+ {1, 150, 1, 1},
+ {0, 50, 1, 1},
+ }
+};
+
+/*
+ * f(x) = x / 2
+ * divider=2 applied once per multiply: mult_frac(coef, data, 2) = coef*data/2
+ */
+static const struct polynomial poly_step_divider = {
+ .total_divider = 1,
+ .terms = {
+ {1, 1, 2, 1},
+ {0, 0, 1, 1},
+ }
+};
+
+/*
+ * f(x) = (100/500) * x^2 = 0.2 * x^2
+ * Encoded as coef=100, divider=10, divider_leftover=5:
+ * denom = 10^2 * 5 = 500
+ */
+static const struct polynomial poly_leftover = {
+ .total_divider = 1,
+ .terms = {
+ {2, 100, 10, 5},
+ {0, 0, 1, 1},
+ }
+};
+
+/*
+ * f(x) = 2x^3 (single high-degree term, no constant)
+ * Used to exercise the power loop alone.
+ */
+static const struct polynomial poly_cubic = {
+ .total_divider = 1,
+ .terms = {
+ {3, 2, 1, 1},
+ {0, 0, 1, 1},
+ }
+};
+
+/*
+ * f(x) = 4x + 1 with a zero-coefficient quadratic term.
+ * The deg-2 term contributes nothing regardless of input.
+ */
+static const struct polynomial poly_zero_coef = {
+ .total_divider = 1,
+ .terms = {
+ {2, 0, 1, 1},
+ {1, 4, 1, 1},
+ {0, 1, 1, 1},
+ }
+};
+
+/*
+ * f(x) = 9 with total_divider = 0.
+ * The implementation treats 0 as 1 via `total_divider ?: 1`, so the
+ * result must equal the constant term unchanged.
+ */
+static const struct polynomial poly_zero_total_divider = {
+ .total_divider = 0,
+ .terms = {
+ {0, 9, 1, 1},
+ }
+};
+
+
+static const struct polynomial_test_param test_params[] = {
+ {
+ .poly = &poly_constant,
+ .data = 0,
+ .expected = 5,
+ .name = "Constant polynomial at x=0",
+ },
+ {
+ .poly = &poly_constant,
+ .data = 42,
+ .expected = 5,
+ .name = "Constant polynomial is independent of input",
+ },
+ {
+ .poly = &poly_simple,
+ .data = 0,
+ .expected = 5, /* zero input collapses all power terms */
+ .name = "Zero input yields constant term only",
+ },
+ {
+ .poly = &poly_simple,
+ .data = 10,
+ .expected = 235, /* 2*100 + 3*10 + 5 */
+ .name = "Simple quadratic at x=10",
+ },
+ {
+ .poly = &poly_negative_coef,
+ .data = 10,
+ .expected = 50, /* -5*10 + 100 */
+ .name = "Negative coefficient at x=10",
+ },
+ {
+ .poly = &poly_negative_coef,
+ .data = 20,
+ .expected = 0, /* -5*20 + 100 = 0 */
+ .name = "Negative coefficient result is zero",
+ },
+ {
+ .poly = &poly_total_divider,
+ .data = 3,
+ .expected = 50, /* (150*3 + 50) / 10 = 500/10 */
+ .name = "total_divider scales the final sum",
+ },
+ {
+ .poly = &poly_step_divider,
+ .data = 100,
+ .expected = 50, /* 1*100/2 */
+ .name = "Per-step divider halves input",
+ },
+ {
+ .poly = &poly_leftover,
+ .data = 30,
+ .expected = 180, /* 100*30^2 / (10^2 * 5) = 90000/500 */
+ .name = "divider_leftover with quadratic term",
+ },
+ /* Boundary: unit and negative-unit input */
+ {
+ /*
+ * data=1: each mult_frac(tmp, 1, divider) strips one factor of
+ * divider from coef per degree, so coef is left-shifted right
+ * until intermediate precision is exhausted.
+ * 2*1 + 3*1 + 5 = 10
+ */
+ .poly = &poly_simple,
+ .data = 1,
+ .expected = 10,
+ .name = "Boundary: data=1 (unit input)",
+ },
+ {
+ /*
+ * data=-1: even degrees produce positive contributions,
+ * odd degrees produce negative ones.
+ * 2*(-1)^2 + 3*(-1) + 5 = 2 - 3 + 5 = 4
+ */
+ .poly = &poly_simple,
+ .data = -1,
+ .expected = 4,
+ .name = "Boundary: data=-1 (negative unit input)",
+ },
+
+ /* Boundary: negative non-trivial input */
+ {
+ /*
+ * 2*(-3)^2 + 3*(-3) + 5 = 18 - 9 + 5 = 14
+ * Verifies sign handling for negative data across all degrees.
+ */
+ .poly = &poly_simple,
+ .data = -3,
+ .expected = 14,
+ .name = "Boundary: negative data with quadratic",
+ },
+
+ /* Boundary: total_divider = 0 is treated as 1 */
+ {
+ .poly = &poly_zero_total_divider,
+ .data = 42,
+ .expected = 9,
+ .name = "Boundary: total_divider=0 defaults to 1",
+ },
+
+ /* Boundary: zero-coefficient high-degree term */
+ {
+ /*
+ * The deg-2 term has coef=0, so it contributes 0 regardless
+ * of data. Result: 0 + 4*10 + 1 = 41
+ */
+ .poly = &poly_zero_coef,
+ .data = 10,
+ .expected = 41,
+ .name = "Boundary: zero-coefficient term is inert",
+ },
+
+ /* Boundary: single high-degree term, no constant */
+ {
+ /* 2 * 5^3 = 250; also verifies the loop terminates on deg-0 */
+ .poly = &poly_cubic,
+ .data = 5,
+ .expected = 250,
+ .name = "Boundary: single cubic term",
+ },
+ {
+ /* 2 * (-2)^3 = -16; odd power preserves sign of negative data */
+ .poly = &poly_cubic,
+ .data = -2,
+ .expected = -16,
+ .name = "Boundary: single cubic term, negative data",
+ },
+
+};
+
+static void get_desc(const struct polynomial_test_param *param, char *desc)
+{
+ strscpy(desc, param->name, KUNIT_PARAM_DESC_SIZE);
+}
+
+KUNIT_ARRAY_PARAM(polynomial, test_params, get_desc);
+
+static void polynomial_calc_test(struct kunit *test)
+{
+ const struct polynomial_test_param *param = test->param_value;
+
+ KUNIT_EXPECT_EQ(test, polynomial_calc(param->poly, param->data),
+ param->expected);
+}
+
+static struct kunit_case polynomial_test_cases[] = {
+ KUNIT_CASE_PARAM(polynomial_calc_test, polynomial_gen_params),
+ {}
+};
+
+static struct kunit_suite polynomial_test_suite = {
+ .name = "math-polynomial",
+ .test_cases = polynomial_test_cases,
+};
+
+kunit_test_suites(&polynomial_test_suite);
+
+MODULE_DESCRIPTION("math.polynomial_calc KUnit test suite");
+MODULE_LICENSE("GPL");
diff --git a/lib/nmi_backtrace.c b/lib/nmi_backtrace.c
index a3bfa9360b23..f39c9eca8888 100644
--- a/lib/nmi_backtrace.c
+++ b/lib/nmi_backtrace.c
@@ -19,6 +19,7 @@
#include <linux/stringify.h>
#include <linux/nmi.h>
#include <linux/cpu.h>
+#include <linux/export.h>
#include <linux/sched/debug.h>
#ifdef arch_trigger_cpumask_backtrace
@@ -129,4 +130,10 @@ bool nmi_cpu_backtrace(struct pt_regs *regs)
return false;
}
NOKPROBE_SYMBOL(nmi_cpu_backtrace);
+
+void cpumask_backtrace(const cpumask_t *mask, int exclude_cpu)
+{
+ arch_trigger_cpumask_backtrace(mask, exclude_cpu);
+}
+EXPORT_SYMBOL_GPL(cpumask_backtrace);
#endif
diff --git a/lib/percpu-refcount.c b/lib/percpu-refcount.c
index 97772e42b9b2..f8d90689af9f 100644
--- a/lib/percpu-refcount.c
+++ b/lib/percpu-refcount.c
@@ -289,7 +289,7 @@ static void __percpu_ref_switch_mode(struct percpu_ref *ref,
* @confirm_switch: optional confirmation callback
*
* There's no reason to use this function for the usual reference counting.
- * Use percpu_ref_kill[_and_confirm]().
+ * Use percpu_ref_kill() or percpu_ref_kill_and_confirm().
*
* Schedule switching of @ref to atomic mode. All its percpu counts will
* be collected to the main atomic counter. On completion, when all CPUs
diff --git a/lib/raid/Kconfig b/lib/raid/Kconfig
index 978cd6ba08ac..01f007b2522c 100644
--- a/lib/raid/Kconfig
+++ b/lib/raid/Kconfig
@@ -29,6 +29,12 @@ config XOR_KUNIT_TEST
This is intended to help people writing architecture-specific
optimized versions. If unsure, say N.
+config XOR_BENCHMARK
+ bool "Benchmark for xor_gen"
+ depends on XOR_KUNIT_TEST
+ help
+ Include benchmarks in the KUnit test suite for xor_gen.
+
config RAID6_PQ
tristate
@@ -54,6 +60,12 @@ config RAID6_PQ_KUNIT_TEST
This is intended to help people writing architecture-specific
optimized versions. If unsure, say N.
+config RAID6_PQ_KUNIT_BENCHMARK
+ bool "Benchmark for RAID6 PQ"
+ depends on RAID6_PQ_KUNIT_TEST
+ help
+ Include benchmarks in the KUnit test suite for raid P/Q generation.
+
config RAID6_PQ_BENCHMARK
bool "Automatically choose fastest RAID6 PQ functions"
depends on RAID6_PQ
diff --git a/lib/raid/raid6/Makefile b/lib/raid/raid6/Makefile
index 038d6c74d1ba..5cdb7223de2a 100644
--- a/lib/raid/raid6/Makefile
+++ b/lib/raid/raid6/Makefile
@@ -1,5 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
+CONTEXT_ANALYSIS := y
+
ccflags-y += -I $(src)
ifeq ($(CONFIG_RAID6_PQ_ARCH),y)
diff --git a/lib/raid/raid6/algos.c b/lib/raid/raid6/algos.c
index 6f5c89ab2b17..011aa9d0eb3c 100644
--- a/lib/raid/raid6/algos.c
+++ b/lib/raid/raid6/algos.c
@@ -152,40 +152,37 @@ void raid6_recov_datap(int disks, size_t bytes, int faila, void **ptrs)
}
EXPORT_SYMBOL_GPL(raid6_recov_datap);
-#define RAID6_TIME_JIFFIES_LG2 4
-#define RAID6_TEST_DISKS 8
+#define BENCH_SIZE SZ_4K
+#define NR_SRCS 8
+#define NR_DISKS (NR_SRCS + 2)
+#define REPS 800U
-static int raid6_choose_gen(void *(*const dptrs)[RAID6_TEST_DISKS],
- const int disks)
+static int raid6_choose_gen(void *dptrs[NR_DISKS], const int disks)
{
- /* work on the second half of the disks */
- int start = (disks >> 1) - 1, stop = disks - 3;
const struct raid6_calls *best = NULL;
unsigned long bestgenperf = 0;
unsigned int i;
for (i = 0; i < raid6_nr_algos; i++) {
const struct raid6_calls *algo = raid6_algos[i];
- unsigned long perf = 0, j0, j1;
+ unsigned long perf = 0;
+ u64 t;
+ int i;
preempt_disable();
- j0 = jiffies;
- while ((j1 = jiffies) == j0)
- cpu_relax();
- while (time_before(jiffies,
- j1 + (1<<RAID6_TIME_JIFFIES_LG2))) {
- algo->gen_syndrome(disks, PAGE_SIZE, *dptrs);
- perf++;
- }
+ t = ktime_get_ns();
+ for (i = 0; i < REPS; i++)
+ algo->gen_syndrome(disks, BENCH_SIZE, dptrs);
+ t = max(ktime_get_ns() - t, 1);
preempt_enable();
+ /* bytes/ns == GB/s, multiply by 1000 to get MB/s [not MiB/s] */
+ perf = div64_u64((u64)BENCH_SIZE * REPS * NR_SRCS * 1000, t);
if (perf > bestgenperf) {
bestgenperf = perf;
best = algo;
}
- pr_info("raid6: %-8s gen() %5ld MB/s\n", algo->name,
- (perf * HZ * (disks-2)) >>
- (20 - PAGE_SHIFT + RAID6_TIME_JIFFIES_LG2));
+ pr_info("raid6: %-8s gen() %5lu MB/s\n", algo->name, perf);
}
if (!best) {
@@ -197,28 +194,24 @@ static int raid6_choose_gen(void *(*const dptrs)[RAID6_TEST_DISKS],
static_call_update(raid6_xor_syndrome_impl, best->xor_syndrome);
pr_info("raid6: using algorithm %s gen() %ld MB/s\n",
- best->name,
- (bestgenperf * HZ * (disks - 2)) >>
- (20 - PAGE_SHIFT + RAID6_TIME_JIFFIES_LG2));
+ best->name, bestgenperf);
if (best->xor_syndrome) {
- unsigned long perf = 0, j0, j1;
+ /* work on the second half of the disks */
+ int start = (disks / 2) - 1, stop = disks - 3;
+ u64 t;
preempt_disable();
- j0 = jiffies;
- while ((j1 = jiffies) == j0)
- cpu_relax();
- while (time_before(jiffies,
- j1 + (1 << RAID6_TIME_JIFFIES_LG2))) {
- best->xor_syndrome(disks, start, stop,
- PAGE_SIZE, *dptrs);
- perf++;
- }
+ t = ktime_get_ns();
+ for (i = 0; i < REPS; i++)
+ best->xor_syndrome(disks, start, stop, BENCH_SIZE,
+ dptrs);
+ t = max(ktime_get_ns() - t, 1);
preempt_enable();
- pr_info("raid6: .... xor() %ld MB/s, rmw enabled\n",
- (perf * HZ * (disks - 2)) >>
- (20 - PAGE_SHIFT + RAID6_TIME_JIFFIES_LG2 + 1));
+ pr_info("raid6: .... xor() %llu MB/s, rmw enabled\n",
+ div64_u64((u64)BENCH_SIZE * REPS * NR_SRCS / 2 * 1000,
+ t));
}
return 0;
@@ -230,24 +223,20 @@ static int raid6_choose_gen(void *(*const dptrs)[RAID6_TEST_DISKS],
static int __init raid6_select_algo(void)
{
- const int disks = RAID6_TEST_DISKS;
+ const int disks = NR_DISKS;
+ void *dptrs[NR_DISKS];
char *disk_ptr, *p;
- void *dptrs[RAID6_TEST_DISKS];
int i, cycle;
int error;
if (!IS_ENABLED(CONFIG_RAID6_PQ_BENCHMARK) || raid6_nr_algos == 1) {
pr_info("raid6: skipped pq benchmark and selected %s\n",
raid6_algos[raid6_nr_algos - 1]->name);
- static_call_update(raid6_gen_syndrome_impl,
- raid6_algos[raid6_nr_algos - 1]->gen_syndrome);
- static_call_update(raid6_xor_syndrome_impl,
- raid6_algos[raid6_nr_algos - 1]->xor_syndrome);
return 0;
}
/* prepare the buffer and fill it circularly with gfmul table */
- disk_ptr = kmalloc(PAGE_SIZE * RAID6_TEST_DISKS, GFP_KERNEL);
+ disk_ptr = kmalloc_array(NR_DISKS, BENCH_SIZE, GFP_KERNEL);
if (!disk_ptr) {
pr_err("raid6: Yikes! No memory available.\n");
return -ENOMEM;
@@ -255,19 +244,19 @@ static int __init raid6_select_algo(void)
p = disk_ptr;
for (i = 0; i < disks; i++)
- dptrs[i] = p + PAGE_SIZE * i;
+ dptrs[i] = p + BENCH_SIZE * i;
- cycle = ((disks - 2) * PAGE_SIZE) / 65536;
+ cycle = ((disks - 2) * BENCH_SIZE) / 65536;
for (i = 0; i < cycle; i++) {
memcpy(p, raid6_gfmul, 65536);
p += 65536;
}
- if ((disks - 2) * PAGE_SIZE % 65536)
- memcpy(p, raid6_gfmul, (disks - 2) * PAGE_SIZE % 65536);
+ if ((disks - 2) * BENCH_SIZE % 65536)
+ memcpy(p, raid6_gfmul, (disks - 2) * BENCH_SIZE % 65536);
/* select raid gen_syndrome function */
- error = raid6_choose_gen(&dptrs, disks);
+ error = raid6_choose_gen(dptrs, disks);
kfree(disk_ptr);
@@ -329,13 +318,34 @@ static int __init raid6_init(void)
static_call_update(raid6_recov_datap_impl, raid6_recov_algo->datap);
pr_info("raid6: using %s recovery algorithm\n", raid6_recov_algo->name);
+ /*
+ * Pick the last registered implementation as the temporary default until
+ * calibration happens.
+ */
+ static_call_update(raid6_gen_syndrome_impl,
+ raid6_algos[raid6_nr_algos - 1]->gen_syndrome);
+ static_call_update(raid6_xor_syndrome_impl,
+ raid6_algos[raid6_nr_algos - 1]->xor_syndrome);
+
+#ifdef MODULE
return raid6_select_algo();
+#else
+ return 0;
+#endif
}
static void __exit raid6_exit(void)
{
}
+/*
+ * When built-in we must register the default implementation before md
+ * initializes, but we don't want calibration to run that early as that
+ * would delay the boot process.
+ */
+#ifndef MODULE
+device_initcall(raid6_select_algo);
+#endif
subsys_initcall(raid6_init);
module_exit(raid6_exit);
MODULE_LICENSE("GPL");
diff --git a/lib/raid/raid6/riscv/recov_rvv.c b/lib/raid/raid6/riscv/recov_rvv.c
index 2305940276dd..78e158a3e332 100644
--- a/lib/raid/raid6/riscv/recov_rvv.c
+++ b/lib/raid/raid6/riscv/recov_rvv.c
@@ -8,6 +8,7 @@
#include <linux/raid/pq.h>
#include "algos.h"
#include "rvv.h"
+#include "pq_arch.h"
static void __raid6_2data_recov_rvv(int bytes, u8 *p, u8 *q, u8 *dp,
u8 *dq, const u8 *pbmul,
diff --git a/lib/raid/raid6/riscv/rvv.c b/lib/raid/raid6/riscv/rvv.c
index 75c9dafedb28..4ac50606f3dc 100644
--- a/lib/raid/raid6/riscv/rvv.c
+++ b/lib/raid/raid6/riscv/rvv.c
@@ -10,6 +10,7 @@
*/
#include "rvv.h"
+#include "pq_arch.h"
#ifdef __riscv_vector
#error "This code must be built without compiler support for vector"
diff --git a/lib/raid/raid6/tests/raid6_kunit.c b/lib/raid/raid6/tests/raid6_kunit.c
index 9f3e671a1224..7d0a1ec98001 100644
--- a/lib/raid/raid6/tests/raid6_kunit.c
+++ b/lib/raid/raid6/tests/raid6_kunit.c
@@ -18,6 +18,7 @@ MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
#define RAID6_KUNIT_MAX_BUFFERS 64 /* Including P and Q */
#define RAID6_KUNIT_MAX_FAILURES 2
#define RAID6_KUNIT_MAX_BYTES PAGE_SIZE
+#define RAID6_KUNIT_ALLOC_BYTES SZ_16K
static struct rnd_state rng;
static void *test_buffers[RAID6_KUNIT_MAX_BUFFERS];
@@ -229,6 +230,68 @@ static void raid6_test(struct kunit *test)
raid6_test_one(test);
}
+static void raid6_benchmark(struct kunit *test)
+{
+ static const unsigned int nr_to_test[] = {
+ 4, 5, 6, 7, 8, 10, 12, 15, 16, 32,
+ };
+ static const unsigned int len_to_test[] = {
+ SZ_4K, SZ_16K,
+ };
+ unsigned int i, j, l;
+ u64 t;
+
+ if (!IS_ENABLED(CONFIG_RAID6_PQ_KUNIT_BENCHMARK))
+ kunit_skip(test, "not enabled");
+
+ /* warm-up */
+ for (i = 0; i < ARRAY_SIZE(nr_to_test); i++) {
+ for (j = 0; j < ARRAY_SIZE(len_to_test); j++) {
+ for (l = 0; l < 10; l++) {
+ raid6_gen_syndrome(nr_to_test[i],
+ len_to_test[j], test_buffers);
+ }
+ }
+ }
+
+ /*
+ * Preferably this would be a loop over len_to_test, but the kunit
+ * logging always adds a newline to each logged format string.
+ */
+ static_assert(ARRAY_SIZE(len_to_test) == 2);
+ kunit_info(test, " \t%5u bytes\t%5u bytes\n",
+ len_to_test[0], len_to_test[1]);
+
+ for (i = 0; i < ARRAY_SIZE(nr_to_test); i++) {
+ unsigned int nr = nr_to_test[i];
+ u64 speed[ARRAY_SIZE(len_to_test)];
+
+ KUNIT_ASSERT_LE(test, nr, RAID6_KUNIT_MAX_BUFFERS);
+
+ for (j = 0; j < ARRAY_SIZE(len_to_test); j++) {
+ unsigned int len = len_to_test[j];
+ const unsigned long num_iters = 1000;
+
+ KUNIT_ASSERT_GT(test, len, 0);
+ KUNIT_ASSERT_LE(test, len, RAID6_KUNIT_ALLOC_BYTES);
+
+ preempt_disable();
+ t = ktime_get_ns();
+ for (l = 0; l < num_iters; l++)
+ raid6_gen_syndrome(nr_to_test[i],
+ len_to_test[j], test_buffers);
+ t = max(ktime_get_ns() - t, 1);
+ preempt_enable();
+
+ speed[j] = div64_u64((u64)len * num_iters * nr, t);
+ }
+
+ static_assert(ARRAY_SIZE(len_to_test) == 2);
+ kunit_info(test, "%3u disks:\t%5llu GB/s\t%5llu GB/s\n",
+ nr, speed[0], speed[1]);
+ }
+}
+
static const void *raid6_gen_params(struct kunit *test, const void *prev,
char *desc)
{
@@ -256,6 +319,7 @@ next_algo:
static struct kunit_case raid6_test_cases[] = {
KUNIT_CASE_PARAM(raid6_test, raid6_gen_params),
+ KUNIT_CASE(raid6_benchmark),
{},
};
@@ -270,7 +334,7 @@ static int raid6_suite_init(struct kunit_suite *suite)
* so that it is immediately followed by a guard page. This allows
* buffer overreads to be detected, even in assembly code.
*/
- test_buflen = round_up(RAID6_KUNIT_MAX_BYTES, PAGE_SIZE);
+ test_buflen = round_up(RAID6_KUNIT_ALLOC_BYTES, PAGE_SIZE);
for (i = 0; i < RAID6_KUNIT_MAX_FAILURES; i++) {
test_recov_buffers[i] = vmalloc(test_buflen);
if (!test_recov_buffers[i])
diff --git a/lib/raid/xor/Makefile b/lib/raid/xor/Makefile
index e8ecec3c09f9..9b0fad459cdb 100644
--- a/lib/raid/xor/Makefile
+++ b/lib/raid/xor/Makefile
@@ -1,5 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
+CONTEXT_ANALYSIS := y
+
ccflags-y += -I $(src)
obj-$(CONFIG_XOR_BLOCKS) += xor.o
diff --git a/lib/raid/xor/tests/Makefile b/lib/raid/xor/tests/Makefile
index 661e8f6ffd1f..1cce833cd7fd 100644
--- a/lib/raid/xor/tests/Makefile
+++ b/lib/raid/xor/tests/Makefile
@@ -1,3 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
+CONTEXT_ANALYSIS := y
+
obj-$(CONFIG_XOR_KUNIT_TEST) += xor_kunit.o
diff --git a/lib/raid/xor/tests/xor_kunit.c b/lib/raid/xor/tests/xor_kunit.c
index 0c2a3a420bf9..1fb30b2c7c47 100644
--- a/lib/raid/xor/tests/xor_kunit.c
+++ b/lib/raid/xor/tests/xor_kunit.c
@@ -85,7 +85,7 @@ static void xor_test(struct kunit *test)
xor_generate_random_data();
/*
- * If we're not using the entire buffer size, inject randomize
+ * If we're not using the entire buffer size, inject randomized
* alignment into the buffer.
*/
max_alignment = XOR_KUNIT_MAX_BYTES - len;
@@ -125,8 +125,70 @@ static void xor_test(struct kunit *test)
}
}
+static void xor_benchmark(struct kunit *test)
+{
+ static const unsigned int nr_to_test[] = {
+ 4, 5, 6, 7, 8, 10, 12, 15, 16, 32,
+ };
+ static const unsigned int len_to_test[] = {
+ SZ_4K, SZ_16K,
+ };
+ unsigned int i, j, l;
+ u64 t;
+
+ if (!IS_ENABLED(CONFIG_XOR_BENCHMARK))
+ kunit_skip(test, "not enabled");
+
+ /* warm-up */
+ for (i = 0; i < ARRAY_SIZE(nr_to_test); i++) {
+ for (j = 0; j < ARRAY_SIZE(len_to_test); j++) {
+ for (l = 0; l < 10; l++) {
+ xor_gen(test_dest, test_buffers, nr_to_test[i],
+ len_to_test[j]);
+ }
+ }
+ }
+
+ /*
+ * Preferably this would be a loop over len_to_test, but the kunit
+ * logging always adds a newline to each logged format string.
+ */
+ static_assert(ARRAY_SIZE(len_to_test) == 2);
+ kunit_info(test, " \t%5u bytes\t%5u bytes\n",
+ len_to_test[0], len_to_test[1]);
+
+ for (i = 0; i < ARRAY_SIZE(nr_to_test); i++) {
+ unsigned int nr = nr_to_test[i];
+ u64 speed[ARRAY_SIZE(len_to_test)];
+
+ KUNIT_ASSERT_LE(test, nr, XOR_KUNIT_MAX_BUFFERS);
+
+ for (j = 0; j < ARRAY_SIZE(len_to_test); j++) {
+ unsigned int len = len_to_test[j];
+ const unsigned long num_iters = 1000;
+
+ KUNIT_ASSERT_GT(test, len, 0);
+ KUNIT_ASSERT_LE(test, len, XOR_KUNIT_MAX_BYTES);
+
+ preempt_disable();
+ t = ktime_get_ns();
+ for (l = 0; l < num_iters; l++)
+ xor_gen(test_dest, test_buffers, nr, len);
+ t = max(ktime_get_ns() - t, 1);
+ preempt_enable();
+
+ speed[j] = div64_u64((u64)len * num_iters * nr, t);
+ }
+
+ static_assert(ARRAY_SIZE(len_to_test) == 2);
+ kunit_info(test, "%3u disks:\t%5llu GB/s\t%5llu GB/s\n",
+ nr, speed[0], speed[1]);
+ }
+}
+
static struct kunit_case xor_test_cases[] = {
KUNIT_CASE(xor_test),
+ KUNIT_CASE(xor_benchmark),
{},
};
diff --git a/lib/raid/xor/xor-core.c b/lib/raid/xor/xor-core.c
index 50931fbf0324..f9d61b096b11 100644
--- a/lib/raid/xor/xor-core.c
+++ b/lib/raid/xor/xor-core.c
@@ -10,7 +10,6 @@
#include <linux/gfp.h>
#include <linux/slab.h>
#include <linux/raid/xor.h>
-#include <linux/jiffies.h>
#include <linux/preempt.h>
#include <linux/static_call.h>
#include "xor_impl.h"
@@ -73,59 +72,56 @@ void __init xor_force(struct xor_block_template *tmpl)
forced_template = tmpl;
}
-#define BENCH_SIZE 4096
+#define BENCH_SIZE SZ_4K
+#define NR_SRCS 4
#define REPS 800U
-static void __init
-do_xor_speed(struct xor_block_template *tmpl, void *b1, void *b2)
+static void __init do_xor_speed(struct xor_block_template *tmpl, void *dest,
+ void *srcs[NR_SRCS])
{
- int speed;
- unsigned long reps;
- ktime_t min, start, t0;
- void *srcs[1] = { b2 };
+ u64 t;
+ int i;
preempt_disable();
-
- reps = 0;
- t0 = ktime_get();
- /* delay start until time has advanced */
- while ((start = ktime_get()) == t0)
- cpu_relax();
- do {
+ t = ktime_get_ns();
+ for (i = 0; i < REPS; i++) {
mb(); /* prevent loop optimization */
- tmpl->xor_gen(b1, srcs, 1, BENCH_SIZE);
+ tmpl->xor_gen(dest, srcs, NR_SRCS, BENCH_SIZE);
mb();
- } while (reps++ < REPS || (t0 = ktime_get()) == start);
- min = ktime_sub(t0, start);
-
+ }
+ t = max(ktime_get_ns() - t, 1);
preempt_enable();
- // bytes/ns == GB/s, multiply by 1000 to get MB/s [not MiB/s]
- speed = (1000 * reps * BENCH_SIZE) / (unsigned int)ktime_to_ns(min);
- tmpl->speed = speed;
+ /* bytes/ns == GB/s, multiply by 1000 to get MB/s [not MiB/s] */
+ tmpl->speed = div64_u64((u64)BENCH_SIZE * REPS * NR_SRCS * 1000, t);
- pr_info(" %-16s: %5d MB/sec\n", tmpl->name, speed);
+ pr_info(" %-16s: %5d MB/sec\n", tmpl->name, tmpl->speed);
}
static int __init calibrate_xor_blocks(void)
{
- void *b1, *b2;
struct xor_block_template *f, *fastest;
+ void *srcs[NR_SRCS];
+ void *buf, *dest;
+ int i;
if (forced_template)
return 0;
- b1 = kmalloc(PAGE_SIZE * 4, GFP_KERNEL);
- if (!b1) {
+ buf = kmalloc(BENCH_SIZE * (NR_SRCS + 1), GFP_KERNEL);
+ if (!buf) {
pr_warn("xor: Yikes! No memory available.\n");
return -ENOMEM;
}
- b2 = b1 + 2*PAGE_SIZE + BENCH_SIZE;
+ get_random_bytes(buf, BENCH_SIZE * (NR_SRCS + 1));
+ dest = buf;
+ for (i = 0; i < NR_SRCS; i++)
+ srcs[i] = buf + (i + 1) * BENCH_SIZE;
pr_info("xor: measuring software checksum speed\n");
fastest = template_list;
for (f = template_list; f; f = f->next) {
- do_xor_speed(f, b1, b2);
+ do_xor_speed(f, dest, srcs);
if (f->speed > fastest->speed)
fastest = f;
}
@@ -133,9 +129,10 @@ static int __init calibrate_xor_blocks(void)
pr_info("xor: using function: %s (%d MB/sec)\n",
fastest->name, fastest->speed);
- kfree(b1);
+ kfree(buf);
return 0;
}
+#undef NR_SRCS
#ifdef CONFIG_XOR_BLOCKS_ARCH
#include "xor_arch.h" /* $SRCARCH/xor_arch.h */
diff --git a/lib/random32.c b/lib/random32.c
index 24e7acd9343f..dad90219c351 100644
--- a/lib/random32.c
+++ b/lib/random32.c
@@ -41,6 +41,7 @@
#include <linux/bitops.h>
#include <linux/slab.h>
#include <linux/unaligned.h>
+#include <kunit/visibility.h>
/**
* prandom_u32_state - seeded pseudo-random number generator.
@@ -92,7 +93,14 @@ void prandom_bytes_state(struct rnd_state *state, void *buf, size_t bytes)
}
EXPORT_SYMBOL(prandom_bytes_state);
-static void prandom_warmup(struct rnd_state *state)
+/*
+ * Only declared here so that it has a prototype when made
+ * non-static for KUnit testing (avoids -Wmissing-prototypes).
+ */
+#if IS_ENABLED(CONFIG_KUNIT)
+void prandom_warmup(struct rnd_state *state);
+#endif
+VISIBLE_IF_KUNIT void prandom_warmup(struct rnd_state *state)
{
/* Calling RNG ten times to satisfy recurrence condition */
prandom_u32_state(state);
@@ -106,6 +114,7 @@ static void prandom_warmup(struct rnd_state *state)
prandom_u32_state(state);
prandom_u32_state(state);
}
+EXPORT_SYMBOL_IF_KUNIT(prandom_warmup);
void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state)
{
@@ -125,176 +134,3 @@ void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state)
}
}
EXPORT_SYMBOL(prandom_seed_full_state);
-
-#ifdef CONFIG_RANDOM32_SELFTEST
-static struct prandom_test1 {
- u32 seed;
- u32 result;
-} test1[] = {
- { 1U, 3484351685U },
- { 2U, 2623130059U },
- { 3U, 3125133893U },
- { 4U, 984847254U },
-};
-
-static struct prandom_test2 {
- u32 seed;
- u32 iteration;
- u32 result;
-} test2[] = {
- /* Test cases against taus113 from GSL library. */
- { 931557656U, 959U, 2975593782U },
- { 1339693295U, 876U, 3887776532U },
- { 1545556285U, 961U, 1615538833U },
- { 601730776U, 723U, 1776162651U },
- { 1027516047U, 687U, 511983079U },
- { 416526298U, 700U, 916156552U },
- { 1395522032U, 652U, 2222063676U },
- { 366221443U, 617U, 2992857763U },
- { 1539836965U, 714U, 3783265725U },
- { 556206671U, 994U, 799626459U },
- { 684907218U, 799U, 367789491U },
- { 2121230701U, 931U, 2115467001U },
- { 1668516451U, 644U, 3620590685U },
- { 768046066U, 883U, 2034077390U },
- { 1989159136U, 833U, 1195767305U },
- { 536585145U, 996U, 3577259204U },
- { 1008129373U, 642U, 1478080776U },
- { 1740775604U, 939U, 1264980372U },
- { 1967883163U, 508U, 10734624U },
- { 1923019697U, 730U, 3821419629U },
- { 442079932U, 560U, 3440032343U },
- { 1961302714U, 845U, 841962572U },
- { 2030205964U, 962U, 1325144227U },
- { 1160407529U, 507U, 240940858U },
- { 635482502U, 779U, 4200489746U },
- { 1252788931U, 699U, 867195434U },
- { 1961817131U, 719U, 668237657U },
- { 1071468216U, 983U, 917876630U },
- { 1281848367U, 932U, 1003100039U },
- { 582537119U, 780U, 1127273778U },
- { 1973672777U, 853U, 1071368872U },
- { 1896756996U, 762U, 1127851055U },
- { 847917054U, 500U, 1717499075U },
- { 1240520510U, 951U, 2849576657U },
- { 1685071682U, 567U, 1961810396U },
- { 1516232129U, 557U, 3173877U },
- { 1208118903U, 612U, 1613145022U },
- { 1817269927U, 693U, 4279122573U },
- { 1510091701U, 717U, 638191229U },
- { 365916850U, 807U, 600424314U },
- { 399324359U, 702U, 1803598116U },
- { 1318480274U, 779U, 2074237022U },
- { 697758115U, 840U, 1483639402U },
- { 1696507773U, 840U, 577415447U },
- { 2081979121U, 981U, 3041486449U },
- { 955646687U, 742U, 3846494357U },
- { 1250683506U, 749U, 836419859U },
- { 595003102U, 534U, 366794109U },
- { 47485338U, 558U, 3521120834U },
- { 619433479U, 610U, 3991783875U },
- { 704096520U, 518U, 4139493852U },
- { 1712224984U, 606U, 2393312003U },
- { 1318233152U, 922U, 3880361134U },
- { 855572992U, 761U, 1472974787U },
- { 64721421U, 703U, 683860550U },
- { 678931758U, 840U, 380616043U },
- { 692711973U, 778U, 1382361947U },
- { 677703619U, 530U, 2826914161U },
- { 92393223U, 586U, 1522128471U },
- { 1222592920U, 743U, 3466726667U },
- { 358288986U, 695U, 1091956998U },
- { 1935056945U, 958U, 514864477U },
- { 735675993U, 990U, 1294239989U },
- { 1560089402U, 897U, 2238551287U },
- { 70616361U, 829U, 22483098U },
- { 368234700U, 731U, 2913875084U },
- { 20221190U, 879U, 1564152970U },
- { 539444654U, 682U, 1835141259U },
- { 1314987297U, 840U, 1801114136U },
- { 2019295544U, 645U, 3286438930U },
- { 469023838U, 716U, 1637918202U },
- { 1843754496U, 653U, 2562092152U },
- { 400672036U, 809U, 4264212785U },
- { 404722249U, 965U, 2704116999U },
- { 600702209U, 758U, 584979986U },
- { 519953954U, 667U, 2574436237U },
- { 1658071126U, 694U, 2214569490U },
- { 420480037U, 749U, 3430010866U },
- { 690103647U, 969U, 3700758083U },
- { 1029424799U, 937U, 3787746841U },
- { 2012608669U, 506U, 3362628973U },
- { 1535432887U, 998U, 42610943U },
- { 1330635533U, 857U, 3040806504U },
- { 1223800550U, 539U, 3954229517U },
- { 1322411537U, 680U, 3223250324U },
- { 1877847898U, 945U, 2915147143U },
- { 1646356099U, 874U, 965988280U },
- { 805687536U, 744U, 4032277920U },
- { 1948093210U, 633U, 1346597684U },
- { 392609744U, 783U, 1636083295U },
- { 690241304U, 770U, 1201031298U },
- { 1360302965U, 696U, 1665394461U },
- { 1220090946U, 780U, 1316922812U },
- { 447092251U, 500U, 3438743375U },
- { 1613868791U, 592U, 828546883U },
- { 523430951U, 548U, 2552392304U },
- { 726692899U, 810U, 1656872867U },
- { 1364340021U, 836U, 3710513486U },
- { 1986257729U, 931U, 935013962U },
- { 407983964U, 921U, 728767059U },
-};
-
-static void prandom_state_selftest_seed(struct rnd_state *state, u32 seed)
-{
-#define LCG(x) ((x) * 69069U) /* super-duper LCG */
- state->s1 = __seed(LCG(seed), 2U);
- state->s2 = __seed(LCG(state->s1), 8U);
- state->s3 = __seed(LCG(state->s2), 16U);
- state->s4 = __seed(LCG(state->s3), 128U);
-}
-
-static int __init prandom_state_selftest(void)
-{
- int i, j, errors = 0, runs = 0;
- bool error = false;
-
- for (i = 0; i < ARRAY_SIZE(test1); i++) {
- struct rnd_state state;
-
- prandom_state_selftest_seed(&state, test1[i].seed);
- prandom_warmup(&state);
-
- if (test1[i].result != prandom_u32_state(&state))
- error = true;
- }
-
- if (error)
- pr_warn("prandom: seed boundary self test failed\n");
- else
- pr_info("prandom: seed boundary self test passed\n");
-
- for (i = 0; i < ARRAY_SIZE(test2); i++) {
- struct rnd_state state;
-
- prandom_state_selftest_seed(&state, test2[i].seed);
- prandom_warmup(&state);
-
- for (j = 0; j < test2[i].iteration - 1; j++)
- prandom_u32_state(&state);
-
- if (test2[i].result != prandom_u32_state(&state))
- errors++;
-
- runs++;
- cond_resched();
- }
-
- if (errors)
- pr_warn("prandom: %d/%d self tests failed\n", errors, runs);
- else
- pr_info("prandom: %d self tests passed\n", runs);
- return 0;
-}
-core_initcall(prandom_state_selftest);
-#endif
diff --git a/lib/region_alloc_benchmark.c b/lib/region_alloc_benchmark.c
new file mode 100644
index 000000000000..e88b4cf55c62
--- /dev/null
+++ b/lib/region_alloc_benchmark.c
@@ -0,0 +1,217 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Benchmark bitmap, IDA and Maple Tree allocation of variable-sized regions. */
+
+#include <linux/bitmap.h>
+#include <linux/idr.h>
+#include <linux/kernel.h>
+#include <linux/maple_tree.h>
+#include <linux/module.h>
+#include <linux/printk.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/xarray.h>
+
+#define REGION_MAX_SIZE 32
+
+static unsigned long *bitmap __initdata;
+/* One more request guarantees that even an all-ones trace reaches ENOSPC. */
+static u8 *reg_sz __initdata;
+static unsigned long *reg_idx __initdata;
+static unsigned long capacities[64] = { 1000000, 100000, 10000, 1000, 100, 10 };
+static unsigned int cap_cnt = 6;
+
+module_param_array(capacities, ulong, &cap_cnt, 0400);
+MODULE_PARM_DESC(capacities, "Region capacities to benchmark");
+
+static unsigned long __init benchmark_bitmap(unsigned long cap)
+{
+ unsigned long cnt, idx;
+ ktime_t alloc_time, free_time;
+ size_t sz;
+
+ bitmap_zero(bitmap, cap);
+ alloc_time = ktime_get();
+ for (cnt = 0; cnt <= cap; cnt++) {
+ idx = bitmap_find_next_zero_area(bitmap, cap, 0, reg_sz[cnt], 0);
+ if (idx >= cap)
+ break;
+
+ reg_idx[cnt] = idx;
+ bitmap_set(bitmap, idx, reg_sz[cnt]);
+ }
+ alloc_time = ktime_get() - alloc_time;
+
+ idx = cnt;
+
+ free_time = ktime_get();
+ while (idx--)
+ bitmap_clear(bitmap, reg_idx[idx], reg_sz[idx]);
+ free_time = ktime_get() - free_time;
+
+ WARN_ON(!bitmap_empty(bitmap, cap));
+
+ sz = BITS_TO_LONGS(cap) * sizeof(unsigned long);
+ pr_err("Bitmap %12llu %12llu %8lu %8lu %10zu\n",
+ alloc_time, free_time, cnt, cap, sz);
+
+ return cnt;
+}
+
+static size_t __init ida_size(unsigned long nr_ids)
+{
+ unsigned long entries = DIV_ROUND_UP(nr_ids, IDA_BITMAP_BITS);
+ unsigned long bitmaps = nr_ids / IDA_BITMAP_BITS;
+ unsigned long nodes = 0;
+
+ if (nr_ids % IDA_BITMAP_BITS > BITS_PER_XA_VALUE)
+ bitmaps++;
+
+ while (entries > 1) {
+ entries = DIV_ROUND_UP(entries, XA_CHUNK_SIZE);
+ nodes += entries;
+ }
+
+ return sizeof(struct ida) +
+ bitmaps * sizeof(struct ida_bitmap) +
+ nodes * sizeof(struct xa_node);
+}
+
+static unsigned long __init benchmark_ida(unsigned long cap)
+{
+ struct ida ida = IDA_INIT(ida);
+ unsigned long cnt, idx, off, nr_ids = 0;
+ ktime_t alloc_time, free_time;
+ int id = -ENOSPC;
+
+ alloc_time = ktime_get();
+ for (cnt = 0; cnt <= cap; cnt++) {
+ for (off = 0; off < reg_sz[cnt]; off++) {
+ id = ida_alloc_max(&ida, cap - 1, GFP_KERNEL);
+ if (id < 0)
+ break;
+
+ if (!off)
+ reg_idx[cnt] = id;
+ }
+ if (id < 0) {
+ while (off--)
+ ida_free(&ida, reg_idx[cnt] + off);
+ break;
+ }
+ WARN_ON(id != reg_idx[cnt] + reg_sz[cnt] - 1);
+ nr_ids += reg_sz[cnt];
+ }
+ alloc_time = ktime_get() - alloc_time;
+
+ WARN_ON(id != -ENOSPC);
+
+ idx = cnt;
+
+ free_time = ktime_get();
+ while (idx--) {
+ for (off = 0; off < reg_sz[idx]; off++)
+ ida_free(&ida, reg_idx[idx] + off);
+ }
+ free_time = ktime_get() - free_time;
+
+ WARN_ON(!ida_is_empty(&ida));
+
+ pr_err("IDA %12llu %12llu %8lu %8lu %10zu\n",
+ alloc_time, free_time, cnt, cap, ida_size(nr_ids));
+
+ ida_destroy(&ida);
+ return cnt;
+}
+
+static unsigned long __init benchmark_maple_tree(unsigned long cap)
+{
+ struct maple_tree mt = MTREE_INIT(mt, MT_FLAGS_ALLOC_RANGE);
+ unsigned long cnt, idx;
+ ktime_t alloc_time, free_time;
+ size_t sz;
+ int ret;
+
+ alloc_time = ktime_get();
+ for (cnt = 0; cnt <= cap; cnt++) {
+ ret = mtree_alloc_range(&mt, &idx, xa_mk_value(cnt + 1),
+ reg_sz[cnt], 0, cap - 1, GFP_KERNEL);
+ if (ret)
+ break;
+
+ reg_idx[cnt] = idx;
+ }
+ alloc_time = ktime_get() - alloc_time;
+
+ WARN_ON(ret != -EBUSY);
+
+ idx = cnt;
+
+ free_time = ktime_get();
+ while (idx--)
+ mtree_erase(&mt, reg_idx[idx]);
+ free_time = ktime_get() - free_time;
+
+ WARN_ON(!mtree_empty(&mt));
+
+ /* Minimum storage assuming fully occupied allocation-range leaf nodes. */
+ sz = sizeof(mt) + DIV_ROUND_UP(cnt, MAPLE_ARANGE64_SLOTS) * sizeof(struct maple_node);
+ pr_err("Maple %12llu %12llu %8lu %8lu %10zu\n",
+ alloc_time, free_time, cnt, cap, sz);
+
+ mtree_destroy(&mt);
+ return cnt;
+}
+
+static int __init region_alloc_benchmark(void)
+{
+ unsigned long bitmap_count, ida_count, maple_count;
+ unsigned long i, max_cap = 0;
+ int ret = -ENOMEM;
+
+ for (i = 0; i < cap_cnt; i++) {
+ if (capacities[i] == 0) {
+ pr_err("capacity must be nonzero\n");
+ return -EINVAL;
+ }
+ max_cap = max(max_cap, capacities[i]);
+ }
+
+ bitmap = kvmalloc_array(BITS_TO_LONGS(max_cap), sizeof(*bitmap), GFP_KERNEL);
+ reg_sz = kvmalloc_array(max_cap + 1, sizeof(*reg_sz), GFP_KERNEL);
+ reg_idx = kvmalloc_array(max_cap, sizeof(*reg_idx), GFP_KERNEL);
+ if (!bitmap || !reg_sz || !reg_idx)
+ goto out;
+
+ pr_err("\nStart testing bitmap vs IDA vs Maple Tree region allocation\n");
+ pr_err("memory: bitmap is exact; IDA and Maple Tree are lower bounds\n");
+ pr_err("Type alloc (ns) free (ns) regions capacity memory (B)\n");
+
+ for (i = 0; i < cap_cnt; i++) {
+ unsigned long idx, max_size;
+
+ max_size = min(REGION_MAX_SIZE, capacities[i] / 10) ? : 1;
+ for (idx = 0; idx <= capacities[i]; idx++)
+ reg_sz[idx] = get_random_u32_below(max_size) + 1;
+
+ bitmap_count = benchmark_bitmap(capacities[i]);
+ maple_count = benchmark_maple_tree(capacities[i]);
+ ida_count = benchmark_ida(capacities[i]);
+
+ WARN_ON(bitmap_count != ida_count);
+ WARN_ON(bitmap_count != maple_count);
+ }
+
+ /* Return an error so the benchmark can run repeatedly without rmmod. */
+ pr_info("Region allocation benchmark complete\n");
+ ret = -EAGAIN;
+out:
+ kvfree(reg_idx);
+ kvfree(reg_sz);
+ kvfree(bitmap);
+ return ret;
+}
+module_init(region_alloc_benchmark);
+
+MODULE_AUTHOR("Yury Norov <ynorov@nvidia.com>");
+MODULE_DESCRIPTION("Benchmark bitmap, IDA and Maple Tree region allocation");
+MODULE_LICENSE("GPL");
diff --git a/lib/rhashtable.c b/lib/rhashtable.c
index 40cfb38ac919..6362896e4f09 100644
--- a/lib/rhashtable.c
+++ b/lib/rhashtable.c
@@ -14,6 +14,7 @@
#include <linux/atomic.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/irq_work.h>
#include <linux/log2.h>
#include <linux/sched.h>
#include <linux/rculist.h>
@@ -25,6 +26,7 @@
#include <linux/rhashtable.h>
#include <linux/err.h>
#include <linux/export.h>
+#include <linux/workqueue.h>
#define HASH_DEFAULT_SIZE 64UL
#define HASH_MIN_SIZE 4U
@@ -878,6 +880,7 @@ int rhashtable_walk_start_check(struct rhashtable_iter *iter)
iter->walker.tbl = rht_dereference_rcu(ht->tbl, ht);
iter->slot = 0;
iter->skip = 0;
+ iter->p = NULL;
return -EAGAIN;
}
@@ -1260,7 +1263,7 @@ static void rhashtable_free_one(struct rhashtable *ht, struct rhash_head *obj,
list = container_of(obj, struct rhlist_head, rhead);
do {
obj = &list->rhead;
- list = rht_dereference(list->next, ht);
+ list = rcu_dereference_raw(list->next);
free_fn(rht_obj(ht, obj), arg);
} while (list);
}
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index b7fe91ef35b8..6ea40d2e6247 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -1366,6 +1366,7 @@ static ssize_t extract_xarray_to_sg(struct iov_iter *iter,
sg_max--;
maxsize -= len;
+ start += len;
ret += len;
if (maxsize <= 0 || sg_max == 0)
break;
diff --git a/lib/seq_buf.c b/lib/seq_buf.c
index b59488fa8135..a92093f346da 100644
--- a/lib/seq_buf.c
+++ b/lib/seq_buf.c
@@ -321,7 +321,7 @@ int seq_buf_path(struct seq_buf *s, const struct path *path, const char *esc)
if (size) {
char *p = d_path(path, buf, size);
if (!IS_ERR(p)) {
- char *end = mangle_path(buf, p, esc);
+ char *end = seq_mangle_path(buf, p, esc);
if (end)
res = end - buf;
}
diff --git a/lib/string.c b/lib/string.c
index a4e8ad23577d..a3778d5aab4a 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -821,7 +821,8 @@ void *memchr_inv(const void *start, int c, size_t bytes)
{
u8 value = c;
u64 value64;
- unsigned int words, prefix;
+ size_t words;
+ unsigned int prefix;
if (bytes <= 16)
return check_bytes8(start, value, bytes);
diff --git a/lib/test-kstrtox.c b/lib/test-kstrtox.c
index 811128d0df16..9255234752db 100644
--- a/lib/test-kstrtox.c
+++ b/lib/test-kstrtox.c
@@ -709,6 +709,182 @@ static void __init test_kstrtos8_fail(void)
TEST_FAIL(kstrtos8, s8, "%hhd", test_s8_fail);
}
+static void __init test_kstrtoudec64_ok(void)
+{
+ DECLARE_TEST_OK(u64, struct test_udec64);
+ static DEFINE_TEST_OK(struct test_udec64, test_udec64_ok) = {
+ /* basic: integer.fraction, exact digits */
+ {"0.0", 1, 0},
+ {"1.5", 1, 15},
+ {"1.234", 3, 1234},
+ {"42.0", 1, 420},
+ /* zero */
+ {"0.0", 1, 0},
+ {"0.000", 3, 0},
+ /* integer only */
+ {"0", 1, 0},
+ {"42", 3, 42000},
+ {"123.", 2, 12300},
+ {"1", 1, 10},
+ /* fractional only (leading dot) */
+ {".5", 1, 5},
+ {".5", 0, 0},
+ {".123", 3, 123},
+ {".001", 3, 1},
+ /* zero padding: fewer fractional digits than scale */
+ {"1.2", 3, 1200},
+ {"1.2", 6, 1200000},
+ {"0.01", 3, 10},
+ {"0.1", 9, 100000000ULL},
+ {"0.01", 9, 10000000},
+ /* truncation: more fractional digits than scale */
+ {"1.23456", 3, 1234},
+ {"3.1415926535", 6, 3141592},
+ {"0.999999999", 3, 999},
+ {"1.99", 1, 19},
+ {"1.234", 0, 1},
+ /* trailing newline */
+ {"1.5\n", 1, 15},
+ {"42\n", 3, 42000},
+ /* plus sign */
+ {"+1.5", 1, 15},
+ {"+.5", 1, 5},
+ /* scale progression */
+ {"1.", 0, 1},
+ {"1.0", 1, 10},
+ {"1.00", 2, 100},
+ {"1.000", 3, 1000},
+ {"1.000000", 6, 1000000},
+ {"1.000000000", 9, 1000000000ULL},
+ /* max limit check */
+ {"18446744073.709551615", 9, ULLONG_MAX},
+ {"18446744073709.551615", 6, ULLONG_MAX},
+ {"0.18446744073709551615", 20, ULLONG_MAX},
+ /* scale > 19: representable when integer part is small */
+ {"0.00000000000000000001", 20, 1},
+ {"0.1", 20, 10000000000000000000ULL},
+ {"0.00000000000000000000001", 23, 1},
+ /* truncation with scale > 19 */
+ {"0.0000000000000000000012345", 23, 123},
+ /* truncation with many excess digits */
+ {"0.00000000000000000000000000000000423", 34, 42},
+ {"1.99999999999999999999999999999999999", 3, 1999},
+ };
+ TEST_OK(kstrtoudec64, u64, "%llu", test_udec64_ok);
+}
+
+static void __init test_kstrtoudec64_fail(void)
+{
+ static DEFINE_TEST_FAIL(test_udec64_fail) = {
+ /* empty / whitespace */
+ {"", 3},
+ {"\n", 3},
+ /* minus sign (unsigned) */
+ {"-1.5", 1},
+ {"-0.5", 1},
+ /* only a decimal point */
+ {".", 3},
+ {".", 0},
+ /* only a sign */
+ {"+", 3},
+ /* non-digit characters */
+ {"abc", 3},
+ {"1.2x", 3},
+ /* leading/trailing space */
+ {" 1.5", 1},
+ {"1.5 ", 1},
+ /* overflow */
+ {"18446744073710.551615", 6},
+ {"99999999999999999999", 1},
+ /* overflow with scale > 19 */
+ {"1.0", 21},
+ {"0.2", 20},
+ {"0.18446744073709551616", 20},
+ {"1", 20},
+ };
+ TEST_FAIL(kstrtoudec64, u64, "%llu", test_udec64_fail);
+}
+
+static void __init test_kstrtodec64_ok(void)
+{
+ DECLARE_TEST_OK(s64, struct test_dec64);
+ static DEFINE_TEST_OK(struct test_dec64, test_dec64_ok) = {
+ /* basic positive */
+ {"0.0", 1, 0},
+ {"1.5", 1, 15},
+ {"1.234", 3, 1234},
+ /* basic negative */
+ {"-1.5", 1, -15},
+ {"-1.234", 3, -1234},
+ {"-0.5", 1, -5},
+ {"-0.001", 3, -1},
+ /* zero (signed) */
+ {"-0", 1, 0},
+ {"-0.0", 1, 0},
+ {"0.000", 3, 0},
+ /* integer only */
+ {"42", 3, 42000},
+ {"-42", 3, -42000},
+ /* fractional only */
+ {".5", 1, 5},
+ {"-.5", 1, -5},
+ /* zero padding */
+ {"1.2", 3, 1200},
+ {"-1.2", 3, -1200},
+ {"0.01", 3, 10},
+ {"-0.01", 3, -10},
+ /* truncation */
+ {"1.23456", 3, 1234},
+ {"-1.23456", 3, -1234},
+ {"0.999999999", 3, 999},
+ {"-0.999999999", 3, -999},
+ /* trailing newline */
+ {"1.5\n", 1, 15},
+ {"-1.5\n", 1, -15},
+ /* plus sign */
+ {"+1.5", 1, 15},
+ /* limits */
+ {"9223372036.854775807", 9, LLONG_MAX},
+ {"-9223372036.854775808", 9, LLONG_MIN},
+ /* scale > 19 */
+ {"0.0", 20, 0},
+ {"-0.0", 20, 0},
+ {"0.00000000000000000001", 20, 1},
+ {"-0.00000000000000000001", 20, -1},
+ {"0.009223372036854775807", 21, LLONG_MAX},
+ {"-0.009223372036854775808", 21, LLONG_MIN},
+ };
+ TEST_OK(kstrtodec64, s64, "%lld", test_dec64_ok);
+}
+
+static void __init test_kstrtodec64_fail(void)
+{
+ static DEFINE_TEST_FAIL(test_dec64_fail) = {
+ /* empty / whitespace */
+ {"", 3},
+ {"\n", 3},
+ /* no digits after dot */
+ {".", 3},
+ {"-.", 3},
+ /* no digits at all */
+ {"+", 3},
+ {"-", 3},
+ /* non-digit characters */
+ {"abc", 3},
+ {"-1.2x", 3},
+ /* signed overflow */
+ {"9223372036.854775808", 9},
+ {"-9223372036.854775809", 9},
+ {"99999999999999999999", 1},
+ /* signed overflow with scale > 19 */
+ {"0.1", 20},
+ {"-0.1", 20},
+ {"0.09223372036854775808", 20},
+ {"-0.09223372036854775809", 20},
+ };
+ TEST_FAIL(kstrtodec64, s64, "%lld", test_dec64_fail);
+}
+
static int __init test_kstrtox_init(void)
{
test_kstrtoull_ok();
@@ -735,6 +911,12 @@ static int __init test_kstrtox_init(void)
test_kstrtou8_fail();
test_kstrtos8_ok();
test_kstrtos8_fail();
+
+ test_kstrtoudec64_ok();
+ test_kstrtoudec64_fail();
+ test_kstrtodec64_ok();
+ test_kstrtodec64_fail();
+
return -EINVAL;
}
module_init(test_kstrtox_init);
diff --git a/lib/test_bitmap.c b/lib/test_bitmap.c
index 69813c10e6c0..56bd23059b26 100644
--- a/lib/test_bitmap.c
+++ b/lib/test_bitmap.c
@@ -234,6 +234,43 @@ static void __init test_find_nth_bit(void)
}
}
+static void __init
+test_bitmap_find_next_zero_area_off(void)
+{
+ DECLARE_BITMAP(bmap, 192);
+
+ bitmap_set(bmap, 0, 192);
+
+ bitmap_clear(bmap, 0, 8);
+ __clear_bit(50, bmap);
+ bitmap_clear(bmap, 60, 18);
+ __set_bit(69, bmap);
+ __clear_bit(80, bmap);
+ bitmap_clear(bmap, 100, 10);
+ __clear_bit(120, bmap);
+ bitmap_clear(bmap, 145, 8);
+ bitmap_clear(bmap, 160, 32);
+
+ expect_eq_uint(0,
+ bitmap_find_next_zero_area_off(bmap, 192, 0, 8, 0, 0));
+ expect_eq_uint(0,
+ bitmap_find_next_zero_area_off(bmap, 192, 0, 8, 3, 0));
+ expect_eq_uint(163,
+ bitmap_find_next_zero_area_off(bmap, 192, 0, 8, 3, 1));
+ expect_eq_uint(60,
+ bitmap_find_next_zero_area_off(bmap, 192, 1, 8, 0, 0));
+ expect_eq_uint(160,
+ bitmap_find_next_zero_area_off(bmap, 192, 1, 8, 7, 0));
+ expect_eq_uint(60,
+ bitmap_find_next_zero_area_off(bmap, 192, 1, 8, 7, 4));
+ expect_eq_uint(100,
+ bitmap_find_next_zero_area_off(bmap, 192, 0, 10, 0, 0));
+ expect_eq_uint(160,
+ bitmap_find_next_zero_area_off(bmap, 192, 0, 32, 0, 0));
+ expect_eq_uint(1,
+ !!(bitmap_find_next_zero_area_off(bmap, 192, 0, 33, 0, 0) >= 192));
+}
+
static void __init test_fill_set(void)
{
DECLARE_BITMAP(bmap, 1024);
@@ -392,6 +429,7 @@ static void __init test_bitmap_sg(void)
/* Scatter/gather relationship */
bitmap_zero(bmap_tmp, 100);
+ bitmap_zero(bmap_res, 100);
bitmap_gather(bmap_tmp, bmap_scatter, sg_mask, nbits);
bitmap_scatter(bmap_res, bmap_tmp, sg_mask, nbits);
expect_eq_bitmap(bmap_scatter, bmap_res, 100);
@@ -1559,6 +1597,7 @@ static void __init selftest(void)
test_for_each_clear_bitrange_from();
test_for_each_set_clump8();
test_for_each_set_bit_wrap();
+ test_bitmap_find_next_zero_area_off();
}
KSTM_MODULE_LOADERS(test_bitmap);
diff --git a/lib/test_fortify/Makefile b/lib/test_fortify/Makefile
index 399cae880e1d..44cd5df41a81 100644
--- a/lib/test_fortify/Makefile
+++ b/lib/test_fortify/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
ccflags-y := $(call cc-disable-warning,fortify-source)
+ccflags-y += $(call cc-disable-warning,stringop-overread)
quiet_cmd_test_fortify = TEST $@
cmd_test_fortify = $(CONFIG_SHELL) $(src)/test_fortify.sh \
diff --git a/lib/test_hmm.c b/lib/test_hmm.c
index 9c59d1ceb5b5..6911daa9f854 100644
--- a/lib/test_hmm.c
+++ b/lib/test_hmm.c
@@ -389,6 +389,67 @@ out:
return ret;
}
+static int dmirror_range_fault_unlocked(struct dmirror *dmirror,
+ struct hmm_range *range,
+ unsigned long timeout)
+{
+ int ret;
+
+ while (true) {
+ ret = hmm_range_fault_unlocked_timeout(range, timeout);
+ if (ret)
+ goto out;
+
+ mutex_lock(&dmirror->mutex);
+ if (mmu_interval_read_retry(range->notifier,
+ range->notifier_seq)) {
+ mutex_unlock(&dmirror->mutex);
+ continue;
+ }
+ break;
+ }
+
+ ret = dmirror_do_fault(dmirror, range);
+
+ mutex_unlock(&dmirror->mutex);
+out:
+ return ret;
+}
+
+static int dmirror_fault_unlocked(struct dmirror *dmirror,
+ unsigned long start,
+ unsigned long end, bool write,
+ unsigned long timeout)
+{
+ struct mm_struct *mm = dmirror->notifier.mm;
+ unsigned long addr;
+ unsigned long pfns[32];
+ struct hmm_range range = {
+ .notifier = &dmirror->notifier,
+ .hmm_pfns = pfns,
+ .pfn_flags_mask = 0,
+ .default_flags =
+ HMM_PFN_REQ_FAULT | (write ? HMM_PFN_REQ_WRITE : 0),
+ .dev_private_owner = dmirror->mdevice,
+ };
+ int ret = 0;
+
+ if (!mmget_not_zero(mm))
+ return -EFAULT;
+
+ for (addr = start; addr < end; addr = range.end) {
+ range.start = addr;
+ range.end = min(addr + (ARRAY_SIZE(pfns) << PAGE_SHIFT), end);
+
+ ret = dmirror_range_fault_unlocked(dmirror, &range, timeout);
+ if (ret)
+ break;
+ }
+
+ mmput(mm);
+ return ret;
+}
+
static int dmirror_fault(struct dmirror *dmirror, unsigned long start,
unsigned long end, bool write)
{
@@ -407,7 +468,7 @@ static int dmirror_fault(struct dmirror *dmirror, unsigned long start,
/* Since the mm is for the mirrored process, get a reference first. */
if (!mmget_not_zero(mm))
- return 0;
+ return -EFAULT;
for (addr = start; addr < end; addr = range.end) {
range.start = addr;
@@ -488,6 +549,48 @@ static int dmirror_read(struct dmirror *dmirror, struct hmm_dmirror_cmd *cmd)
return ret;
}
+static int dmirror_read_unlocked(struct dmirror *dmirror,
+ struct hmm_dmirror_cmd *cmd,
+ unsigned long timeout)
+{
+ struct dmirror_bounce bounce;
+ unsigned long start, end;
+ unsigned long size = cmd->npages << PAGE_SHIFT;
+ int ret;
+
+ start = cmd->addr;
+ end = start + size;
+ if (end < start)
+ return -EINVAL;
+
+ ret = dmirror_bounce_init(&bounce, start, size);
+ if (ret)
+ return ret;
+
+ while (1) {
+ mutex_lock(&dmirror->mutex);
+ ret = dmirror_do_read(dmirror, start, end, &bounce);
+ mutex_unlock(&dmirror->mutex);
+ if (ret != -ENOENT)
+ break;
+
+ start = cmd->addr + (bounce.cpages << PAGE_SHIFT);
+ ret = dmirror_fault_unlocked(dmirror, start, end, false, timeout);
+ if (ret)
+ break;
+ cmd->faults++;
+ }
+
+ if (ret == 0) {
+ if (copy_to_user(u64_to_user_ptr(cmd->ptr), bounce.ptr,
+ bounce.size))
+ ret = -EFAULT;
+ }
+ cmd->cpages = bounce.cpages;
+ dmirror_bounce_fini(&bounce);
+ return ret;
+}
+
static int dmirror_do_write(struct dmirror *dmirror, unsigned long start,
unsigned long end, struct dmirror_bounce *bounce)
{
@@ -581,7 +684,7 @@ static int dmirror_allocate_chunk(struct dmirror_device *mdevice,
devmem->pagemap.type = MEMORY_DEVICE_PRIVATE;
break;
case HMM_DMIRROR_MEMORY_DEVICE_COHERENT:
- devmem->pagemap.range.start = (MINOR(mdevice->cdevice.dev) - 2) ?
+ devmem->pagemap.range.start = (MINOR(mdevice->device.devt) - 2) ?
spm_addr_dev0 :
spm_addr_dev1;
devmem->pagemap.range.end = devmem->pagemap.range.start +
@@ -1048,10 +1151,9 @@ static vm_fault_t dmirror_devmem_fault_alloc_and_copy(struct migrate_vma *args,
if (!dpage && !order)
return VM_FAULT_OOM;
- pr_debug("migrating from sys to dev pfn src: 0x%lx pfn dst: 0x%lx\n",
- page_to_pfn(spage), page_to_pfn(dpage));
-
if (dpage) {
+ pr_debug("migrating from dev to sys pfn src: 0x%lx pfn dst: 0x%lx\n",
+ page_to_pfn(spage), page_to_pfn(dpage));
lock_page(dpage);
*dst |= migrate_pfn(page_to_pfn(dpage));
}
@@ -1209,16 +1311,10 @@ static int dmirror_migrate_to_device(struct dmirror *dmirror,
if (!mmget_not_zero(mm))
return -EINVAL;
- ret = -ENOMEM;
src_pfns = kvcalloc(PTRS_PER_PTE, sizeof(*src_pfns),
GFP_KERNEL | __GFP_NOFAIL);
- if (!src_pfns)
- goto free_mem;
-
dst_pfns = kvcalloc(PTRS_PER_PTE, sizeof(*dst_pfns),
GFP_KERNEL | __GFP_NOFAIL);
- if (!dst_pfns)
- goto free_mem;
ret = 0;
mmap_read_lock(mm);
@@ -1572,7 +1668,9 @@ static long dmirror_fops_unlocked_ioctl(struct file *filp,
dmirror->flags = cmd.npages;
ret = 0;
break;
-
+ case HMM_DMIRROR_READ_UNLOCKED:
+ ret = dmirror_read_unlocked(dmirror, &cmd, 0);
+ break;
default:
return -EINVAL;
}
diff --git a/lib/test_hmm_uapi.h b/lib/test_hmm_uapi.h
index f94c6d457338..ea9b0ec404fb 100644
--- a/lib/test_hmm_uapi.h
+++ b/lib/test_hmm_uapi.h
@@ -38,6 +38,7 @@ struct hmm_dmirror_cmd {
#define HMM_DMIRROR_CHECK_EXCLUSIVE _IOWR('H', 0x06, struct hmm_dmirror_cmd)
#define HMM_DMIRROR_RELEASE _IOWR('H', 0x07, struct hmm_dmirror_cmd)
#define HMM_DMIRROR_FLAGS _IOWR('H', 0x08, struct hmm_dmirror_cmd)
+#define HMM_DMIRROR_READ_UNLOCKED _IOWR('H', 0x09, struct hmm_dmirror_cmd)
#define HMM_DMIRROR_FLAG_FAIL_ALLOC (1ULL << 0)
diff --git a/lib/test_sysctl.c b/lib/test_sysctl.c
index c02aa9c868f2..909cfcf76dbf 100644
--- a/lib/test_sysctl.c
+++ b/lib/test_sysctl.c
@@ -7,7 +7,7 @@
/*
* This module provides an interface to the proc sysctl interfaces. This
- * driver requires CONFIG_PROC_SYSCTL. It will not normally be loaded by the
+ * driver requires CONFIG_SYSCTL. It will not normally be loaded by the
* system unless explicitly requested by name. You can also build this driver
* into your kernel.
*/
diff --git a/lib/tests/Makefile b/lib/tests/Makefile
index 4ead57602eac..3cac3b63a752 100644
--- a/lib/tests/Makefile
+++ b/lib/tests/Makefile
@@ -41,8 +41,7 @@ obj-$(CONFIG_MEMCPY_KUNIT_TEST) += memcpy_kunit.o
obj-$(CONFIG_MIN_HEAP_KUNIT_TEST) += min_heap_kunit.o
CFLAGS_overflow_kunit.o = $(call cc-disable-warning, tautological-constant-out-of-range-compare)
obj-$(CONFIG_OVERFLOW_KUNIT_TEST) += overflow_kunit.o
-# GCC < 12.1 can miscompile errptr() test when branch profiling is enabled.
-CFLAGS_printf_kunit.o += -DDISABLE_BRANCH_PROFILING
+obj-$(CONFIG_PRANDOM_KUNIT_TEST) += random32_kunit.o
obj-$(CONFIG_PRINTF_KUNIT_TEST) += printf_kunit.o
obj-$(CONFIG_RANDSTRUCT_KUNIT_TEST) += randstruct_kunit.o
obj-$(CONFIG_SCANF_KUNIT_TEST) += scanf_kunit.o
diff --git a/lib/tests/blackhole_dev_kunit.c b/lib/tests/blackhole_dev_kunit.c
index 06834ab35f43..fa3e0533038d 100644
--- a/lib/tests/blackhole_dev_kunit.c
+++ b/lib/tests/blackhole_dev_kunit.c
@@ -46,7 +46,7 @@ static void test_blackholedev(struct kunit *test)
uh = (struct udphdr *)skb_push(skb, sizeof(struct udphdr));
skb_set_transport_header(skb, 0);
uh->source = uh->dest = htons(UDP_PORT);
- uh->len = htons(data_len);
+ udp_set_len_short(uh, data_len);
uh->check = 0;
/* (Network) IPv6 */
ip6h = (struct ipv6hdr *)skb_push(skb, sizeof(struct ipv6hdr));
diff --git a/lib/tests/kunit_iov_iter.c b/lib/tests/kunit_iov_iter.c
index 1e6fce9cb255..d9690ba1db88 100644
--- a/lib/tests/kunit_iov_iter.c
+++ b/lib/tests/kunit_iov_iter.c
@@ -283,7 +283,7 @@ static void __init iov_kunit_copy_to_bvec(struct kunit *test)
struct page **spages, **bpages;
u8 *scratch, *buffer;
size_t bufsize, npages, size, copied;
- int i, b, patt;
+ int i, patt;
bufsize = 0x100000;
npages = bufsize / PAGE_SIZE;
@@ -306,10 +306,9 @@ static void __init iov_kunit_copy_to_bvec(struct kunit *test)
KUNIT_EXPECT_EQ(test, iter.nr_segs, 0);
/* Build the expected image in the scratch buffer. */
- b = 0;
patt = 0;
memset(scratch, 0, bufsize);
- for (pr = bvec_test_ranges; pr->from >= 0; pr++, b++) {
+ for (pr = bvec_test_ranges; pr->from >= 0; pr++) {
u8 *p = scratch + pr->page * PAGE_SIZE;
for (i = pr->from; i < pr->to; i++)
diff --git a/lib/tests/random32_kunit.c b/lib/tests/random32_kunit.c
new file mode 100644
index 000000000000..0b4af2b09c01
--- /dev/null
+++ b/lib/tests/random32_kunit.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Test cases for random32 functions.
+ */
+
+#include <linux/prandom.h>
+#include <kunit/test.h>
+
+/* prandom_warmup() is static in lib/random32.c; exposed for testing only. */
+void prandom_warmup(struct rnd_state *state);
+
+static const struct prandom_test1 {
+ u32 seed;
+ u32 result;
+} test1[] = {
+ { 1U, 3484351685U },
+ { 2U, 2623130059U },
+ { 3U, 3125133893U },
+ { 4U, 984847254U },
+};
+
+static const struct prandom_test2 {
+ u32 seed;
+ u32 iteration;
+ u32 result;
+} test2[] = {
+ /* Test cases against taus113 from GSL library. */
+ { 931557656U, 959U, 2975593782U },
+ { 1339693295U, 876U, 3887776532U },
+ { 1545556285U, 961U, 1615538833U },
+ { 601730776U, 723U, 1776162651U },
+ { 1027516047U, 687U, 511983079U },
+ { 416526298U, 700U, 916156552U },
+ { 1395522032U, 652U, 2222063676U },
+ { 366221443U, 617U, 2992857763U },
+ { 1539836965U, 714U, 3783265725U },
+ { 556206671U, 994U, 799626459U },
+ { 684907218U, 799U, 367789491U },
+ { 2121230701U, 931U, 2115467001U },
+ { 1668516451U, 644U, 3620590685U },
+ { 768046066U, 883U, 2034077390U },
+ { 1989159136U, 833U, 1195767305U },
+ { 536585145U, 996U, 3577259204U },
+ { 1008129373U, 642U, 1478080776U },
+ { 1740775604U, 939U, 1264980372U },
+ { 1967883163U, 508U, 10734624U },
+ { 1923019697U, 730U, 3821419629U },
+ { 442079932U, 560U, 3440032343U },
+ { 1961302714U, 845U, 841962572U },
+ { 2030205964U, 962U, 1325144227U },
+ { 1160407529U, 507U, 240940858U },
+ { 635482502U, 779U, 4200489746U },
+ { 1252788931U, 699U, 867195434U },
+ { 1961817131U, 719U, 668237657U },
+ { 1071468216U, 983U, 917876630U },
+ { 1281848367U, 932U, 1003100039U },
+ { 582537119U, 780U, 1127273778U },
+ { 1973672777U, 853U, 1071368872U },
+ { 1896756996U, 762U, 1127851055U },
+ { 847917054U, 500U, 1717499075U },
+ { 1240520510U, 951U, 2849576657U },
+ { 1685071682U, 567U, 1961810396U },
+ { 1516232129U, 557U, 3173877U },
+ { 1208118903U, 612U, 1613145022U },
+ { 1817269927U, 693U, 4279122573U },
+ { 1510091701U, 717U, 638191229U },
+ { 365916850U, 807U, 600424314U },
+ { 399324359U, 702U, 1803598116U },
+ { 1318480274U, 779U, 2074237022U },
+ { 697758115U, 840U, 1483639402U },
+ { 1696507773U, 840U, 577415447U },
+ { 2081979121U, 981U, 3041486449U },
+ { 955646687U, 742U, 3846494357U },
+ { 1250683506U, 749U, 836419859U },
+ { 595003102U, 534U, 366794109U },
+ { 47485338U, 558U, 3521120834U },
+ { 619433479U, 610U, 3991783875U },
+ { 704096520U, 518U, 4139493852U },
+ { 1712224984U, 606U, 2393312003U },
+ { 1318233152U, 922U, 3880361134U },
+ { 855572992U, 761U, 1472974787U },
+ { 64721421U, 703U, 683860550U },
+ { 678931758U, 840U, 380616043U },
+ { 692711973U, 778U, 1382361947U },
+ { 677703619U, 530U, 2826914161U },
+ { 92393223U, 586U, 1522128471U },
+ { 1222592920U, 743U, 3466726667U },
+ { 358288986U, 695U, 1091956998U },
+ { 1935056945U, 958U, 514864477U },
+ { 735675993U, 990U, 1294239989U },
+ { 1560089402U, 897U, 2238551287U },
+ { 70616361U, 829U, 22483098U },
+ { 368234700U, 731U, 2913875084U },
+ { 20221190U, 879U, 1564152970U },
+ { 539444654U, 682U, 1835141259U },
+ { 1314987297U, 840U, 1801114136U },
+ { 2019295544U, 645U, 3286438930U },
+ { 469023838U, 716U, 1637918202U },
+ { 1843754496U, 653U, 2562092152U },
+ { 400672036U, 809U, 4264212785U },
+ { 404722249U, 965U, 2704116999U },
+ { 600702209U, 758U, 584979986U },
+ { 519953954U, 667U, 2574436237U },
+ { 1658071126U, 694U, 2214569490U },
+ { 420480037U, 749U, 3430010866U },
+ { 690103647U, 969U, 3700758083U },
+ { 1029424799U, 937U, 3787746841U },
+ { 2012608669U, 506U, 3362628973U },
+ { 1535432887U, 998U, 42610943U },
+ { 1330635533U, 857U, 3040806504U },
+ { 1223800550U, 539U, 3954229517U },
+ { 1322411537U, 680U, 3223250324U },
+ { 1877847898U, 945U, 2915147143U },
+ { 1646356099U, 874U, 965988280U },
+ { 805687536U, 744U, 4032277920U },
+ { 1948093210U, 633U, 1346597684U },
+ { 392609744U, 783U, 1636083295U },
+ { 690241304U, 770U, 1201031298U },
+ { 1360302965U, 696U, 1665394461U },
+ { 1220090946U, 780U, 1316922812U },
+ { 447092251U, 500U, 3438743375U },
+ { 1613868791U, 592U, 828546883U },
+ { 523430951U, 548U, 2552392304U },
+ { 726692899U, 810U, 1656872867U },
+ { 1364340021U, 836U, 3710513486U },
+ { 1986257729U, 931U, 935013962U },
+ { 407983964U, 921U, 728767059U },
+};
+
+static void prandom_state_test_seed(struct rnd_state *state, u32 seed)
+{
+#define LCG(x) ((x) * 69069U) /* super-duper LCG */
+ state->s1 = __seed(LCG(seed), 2U);
+ state->s2 = __seed(LCG(state->s1), 8U);
+ state->s3 = __seed(LCG(state->s2), 16U);
+ state->s4 = __seed(LCG(state->s3), 128U);
+}
+
+static void test_prandom_seed_boundary(struct kunit *test)
+{
+ int i;
+ struct rnd_state state;
+
+ for (i = 0; i < ARRAY_SIZE(test1); i++) {
+ prandom_state_test_seed(&state, test1[i].seed);
+ prandom_warmup(&state);
+ KUNIT_EXPECT_EQ(test, test1[i].result, prandom_u32_state(&state));
+ }
+}
+
+static void test_prandom_taus113(struct kunit *test)
+{
+ int i, j;
+ struct rnd_state state;
+
+ for (i = 0; i < ARRAY_SIZE(test2); i++) {
+ prandom_state_test_seed(&state, test2[i].seed);
+ prandom_warmup(&state);
+
+ for (j = 0; j < test2[i].iteration - 1; j++)
+ prandom_u32_state(&state);
+
+ KUNIT_EXPECT_EQ(test, test2[i].result, prandom_u32_state(&state));
+ }
+}
+
+static struct kunit_case prandom_test_cases[] = {
+ KUNIT_CASE(test_prandom_seed_boundary),
+ KUNIT_CASE(test_prandom_taus113),
+ {}
+};
+
+static struct kunit_suite prandom_test_suite = {
+ .name = "prandom",
+ .test_cases = prandom_test_cases,
+};
+
+kunit_test_suite(prandom_test_suite);
+
+MODULE_DESCRIPTION("KUnit test for prandom");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
diff --git a/lib/tests/slub_kunit.c b/lib/tests/slub_kunit.c
index fa6d31dbca16..e3b63f0338d5 100644
--- a/lib/tests/slub_kunit.c
+++ b/lib/tests/slub_kunit.c
@@ -8,6 +8,7 @@
#include <linux/rcupdate.h>
#include <linux/delay.h>
#include <linux/perf_event.h>
+#include <linux/kprobes.h>
#include "../mm/slab.h"
static struct kunit_resource resource;
@@ -161,7 +162,10 @@ static void test_kmalloc_redzone_access(struct kunit *test)
}
struct test_kfree_rcu_struct {
- struct rcu_head rcu;
+ union {
+ struct rcu_head rcu;
+ struct kvfree_rcu_head kvrcu;
+ };
};
static void test_kfree_rcu(struct kunit *test)
@@ -292,19 +296,76 @@ static void test_krealloc_redzone_zeroing(struct kunit *test)
kmem_cache_destroy(s);
}
-#ifdef CONFIG_PERF_EVENTS
+#if defined(CONFIG_PERF_EVENTS) || (defined(CONFIG_KPROBES) && defined(CONFIG_SMP))
#define NR_ITERATIONS 1000
#define NR_OBJECTS 1000
-static void *objects[NR_OBJECTS];
+static struct test_kfree_rcu_struct *objects[NR_OBJECTS];
struct test_nolock_context {
struct kunit *test;
int callback_count;
int alloc_ok;
int alloc_fail;
+#ifdef CONFIG_PERF_EVENTS
struct perf_event *event;
+#endif
+#if defined(CONFIG_KPROBES) && defined(CONFIG_SMP)
+ struct kprobe kprobe;
+#endif
};
+static void test_kmalloc_and_friends(void)
+{
+ int i, j;
+ bool can_use_kfree_rcu = !IS_BUILTIN(CONFIG_SLUB_KUNIT_TEST);
+
+ for (i = 0; i < NR_ITERATIONS; i++) {
+ for (j = 0; j < NR_OBJECTS; j++) {
+ gfp_t gfp = (i & 1) ? GFP_KERNEL : GFP_KERNEL_ACCOUNT;
+
+ objects[j] = kmalloc_obj(*objects[j], gfp);
+ if (!objects[j]) {
+ j--;
+ while (j >= 0)
+ kfree(objects[j--]);
+ return;
+ }
+ }
+
+ for (j = 0; j < NR_OBJECTS; j++) {
+ if (can_use_kfree_rcu && (i & 2))
+ kfree_rcu(objects[j], rcu);
+ else
+ kfree(objects[j]);
+ }
+ }
+}
+
+static void test_nolock(struct test_nolock_context *ctx)
+{
+ struct test_kfree_rcu_struct *objp;
+ gfp_t gfp;
+ bool can_use_kfree_rcu = !IS_BUILTIN(CONFIG_SLUB_KUNIT_TEST);
+
+ /* __GFP_ACCOUNT to test kmalloc_nolock() in alloc_slab_obj_exts() */
+ gfp = (ctx->callback_count & 1) ? 0 : __GFP_ACCOUNT;
+ objp = kmalloc_nolock(sizeof(*objp), gfp, NUMA_NO_NODE);
+
+ if (objp)
+ ctx->alloc_ok++;
+ else
+ ctx->alloc_fail++;
+
+ if (can_use_kfree_rcu && (ctx->callback_count & 2))
+ kfree_rcu_nolock(objp, kvrcu);
+ else
+ kfree_nolock(objp);
+
+ ctx->callback_count++;
+}
+#endif
+
+#ifdef CONFIG_PERF_EVENTS
static struct perf_event_attr hw_attr = {
.type = PERF_TYPE_HARDWARE,
.config = PERF_COUNT_HW_CPU_CYCLES,
@@ -315,67 +376,91 @@ static struct perf_event_attr hw_attr = {
.sample_freq = 100000,
};
-static void overflow_handler_test_kmalloc_kfree_nolock(struct perf_event *event,
- struct perf_sample_data *data,
- struct pt_regs *regs)
+static void overflow_handler_test_nolock(struct perf_event *event,
+ struct perf_sample_data *data,
+ struct pt_regs *regs)
{
- void *objp;
- gfp_t gfp;
struct test_nolock_context *ctx = event->overflow_handler_context;
- /* __GFP_ACCOUNT to test kmalloc_nolock() in alloc_slab_obj_exts() */
- gfp = (ctx->callback_count % 2) ? 0 : __GFP_ACCOUNT;
- objp = kmalloc_nolock(64, gfp, NUMA_NO_NODE);
-
- if (objp)
- ctx->alloc_ok++;
- else
- ctx->alloc_fail++;
-
- kfree_nolock(objp);
- ctx->callback_count++;
+ test_nolock(ctx);
}
-static void test_kmalloc_kfree_nolock(struct kunit *test)
+static bool enable_perf_events(struct test_nolock_context *ctx)
{
- int i, j;
- struct test_nolock_context ctx = { .test = test };
struct perf_event *event;
- bool alloc_fail = false;
event = perf_event_create_kernel_counter(&hw_attr, -1, current,
- overflow_handler_test_kmalloc_kfree_nolock,
- &ctx);
+ overflow_handler_test_nolock,
+ ctx);
+
if (IS_ERR(event))
- kunit_skip(test, "Failed to create perf event");
- ctx.event = event;
- perf_event_enable(ctx.event);
- for (i = 0; i < NR_ITERATIONS; i++) {
- for (j = 0; j < NR_OBJECTS; j++) {
- gfp_t gfp = (i % 2) ? GFP_KERNEL : GFP_KERNEL_ACCOUNT;
+ return false;
- objects[j] = kmalloc(64, gfp);
- if (!objects[j]) {
- j--;
- while (j >= 0)
- kfree(objects[j--]);
- alloc_fail = true;
- goto cleanup;
- }
- }
- for (j = 0; j < NR_OBJECTS; j++)
- kfree(objects[j]);
- }
+ ctx->event = event;
+ perf_event_enable(ctx->event);
+ return true;
+}
+
+static void disable_perf_events(struct test_nolock_context *ctx)
+{
+ kunit_info(ctx->test, "HW perf events: callback_count: %d, alloc_ok: %d, alloc_fail: %d\n",
+ ctx->callback_count, ctx->alloc_ok, ctx->alloc_fail);
+
+ perf_event_disable(ctx->event);
+ perf_event_release_kernel(ctx->event);
+}
+
+static void test_kmalloc_nolock_and_friends_perf(struct kunit *test)
+{
+ struct test_nolock_context ctx = { .test = test };
-cleanup:
- perf_event_disable(ctx.event);
- perf_event_release_kernel(ctx.event);
+ if (!enable_perf_events(&ctx))
+ kunit_skip(test, "Failed to enable perf event, skipping");
- kunit_info(test, "callback_count: %d, alloc_ok: %d, alloc_fail: %d\n",
- ctx.callback_count, ctx.alloc_ok, ctx.alloc_fail);
+ test_kmalloc_and_friends();
- if (alloc_fail)
- kunit_skip(test, "Allocation failed");
+ disable_perf_events(&ctx);
+ KUNIT_EXPECT_EQ(test, 0, slab_errors);
+}
+#endif
+
+#if defined(CONFIG_KPROBES) && defined(CONFIG_SMP)
+static int slab_kprobe_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+ struct test_nolock_context *ctx;
+
+ ctx = container_of(p, struct test_nolock_context, kprobe);
+ test_nolock(ctx);
+ return 0;
+}
+
+static bool register_slab_kprobes(struct test_nolock_context *ctx)
+{
+ ctx->kprobe.symbol_name = "slab_attach_kprobe_locked";
+ ctx->kprobe.pre_handler = slab_kprobe_pre_handler;
+
+ if (register_kprobe(&ctx->kprobe))
+ return false;
+ return true;
+}
+
+static void unregister_slab_kprobes(struct test_nolock_context *ctx)
+{
+ kunit_info(ctx->test, "kprobes: callback_count: %d, alloc_ok: %d, alloc_fail: %d\n",
+ ctx->callback_count, ctx->alloc_ok, ctx->alloc_fail);
+ unregister_kprobe(&ctx->kprobe);
+}
+
+static void test_kmalloc_nolock_and_friends_kprobe(struct kunit *test)
+{
+ struct test_nolock_context ctx = { .test = test };
+
+ if (!register_slab_kprobes(&ctx))
+ kunit_skip(test, "Failed to register kprobe, skipping");
+
+ test_kmalloc_and_friends();
+
+ unregister_slab_kprobes(&ctx);
KUNIT_EXPECT_EQ(test, 0, slab_errors);
}
#endif
@@ -405,7 +490,10 @@ static struct kunit_case test_cases[] = {
KUNIT_CASE(test_leak_destroy),
KUNIT_CASE(test_krealloc_redzone_zeroing),
#ifdef CONFIG_PERF_EVENTS
- KUNIT_CASE_SLOW(test_kmalloc_kfree_nolock),
+ KUNIT_CASE_SLOW(test_kmalloc_nolock_and_friends_perf),
+#endif
+#if defined(CONFIG_KPROBES) && defined(CONFIG_SMP)
+ KUNIT_CASE_SLOW(test_kmalloc_nolock_and_friends_kprobe),
#endif
{}
};
diff --git a/lib/tests/test_ratelimit.c b/lib/tests/test_ratelimit.c
index 33cea5f3d28b..e244f8cd47d7 100644
--- a/lib/tests/test_ratelimit.c
+++ b/lib/tests/test_ratelimit.c
@@ -68,7 +68,6 @@ static void test_ratelimit_smoke(struct kunit *test)
static struct ratelimit_state stressrl = RATELIMIT_STATE_INIT_FLAGS("stressrl", HZ / 10, 3,
RATELIMIT_MSG_ON_RELEASE);
-static int doneflag;
static const int stress_duration = 2 * HZ;
struct stress_kthread {
@@ -84,9 +83,8 @@ static int test_ratelimit_stress_child(void *arg)
struct stress_kthread *sktp = arg;
set_user_nice(current, MAX_NICE);
- WARN_ON_ONCE(!sktp->tp);
- while (!READ_ONCE(doneflag)) {
+ while (!kthread_should_stop()) {
sktp->nattempts++;
if (___ratelimit(&stressrl, __func__))
sktp->nunlimited++;
@@ -105,26 +103,37 @@ static void test_ratelimit_stress(struct kunit *test)
const int n_stress_kthread = cpumask_weight(cpu_online_mask);
struct stress_kthread skt = { 0 };
struct stress_kthread *sktp = kzalloc_objs(*sktp, n_stress_kthread);
+ int n_started = 0;
- KUNIT_EXPECT_NOT_NULL_MSG(test, sktp, "Memory allocation failure");
+ KUNIT_ASSERT_NOT_NULL_MSG(test, sktp, "Memory allocation failure");
for (i = 0; i < n_stress_kthread; i++) {
sktp[i].tp = kthread_run(test_ratelimit_stress_child, &sktp[i], "%s/%i",
"test_ratelimit_stress_child", i);
- KUNIT_EXPECT_NOT_NULL_MSG(test, sktp, "kthread creation failure");
+ if (IS_ERR(sktp[i].tp)) {
+ KUNIT_FAIL(test, "kthread_run failed: %ld", PTR_ERR(sktp[i].tp));
+ goto out_stop;
+ }
+ n_started++;
pr_alert("Spawned test_ratelimit_stress_child %d\n", i);
}
schedule_timeout_idle(stress_duration);
- WRITE_ONCE(doneflag, 1);
- for (i = 0; i < n_stress_kthread; i++) {
+
+out_stop:
+ for (i = 0; i < n_started; i++) {
kthread_stop(sktp[i].tp);
skt.nattempts += sktp[i].nattempts;
skt.nunlimited += sktp[i].nunlimited;
skt.nlimited += sktp[i].nlimited;
skt.nmissed += sktp[i].nmissed;
}
- KUNIT_ASSERT_EQ_MSG(test, skt.nunlimited + skt.nlimited, skt.nattempts,
- "Outcomes not equal to attempts");
- KUNIT_ASSERT_EQ_MSG(test, skt.nlimited, skt.nmissed, "Misses not equal to limits");
+ if (n_started == n_stress_kthread) {
+ KUNIT_ASSERT_EQ_MSG(test, skt.nunlimited + skt.nlimited, skt.nattempts,
+ "Outcomes not equal to attempts");
+ KUNIT_ASSERT_EQ_MSG(test, skt.nlimited, skt.nmissed,
+ "Misses not equal to limits");
+ }
+
+ kfree(sktp);
}
static struct kunit_case ratelimit_test_cases[] = {
diff --git a/lib/ucs2_string.c b/lib/ucs2_string.c
index dfb4f2358cab..1f7dd4eb640a 100644
--- a/lib/ucs2_string.c
+++ b/lib/ucs2_string.c
@@ -6,18 +6,18 @@
unsigned long
ucs2_strnlen(const ucs2_char_t *s, size_t maxlength)
{
- unsigned long length = 0;
+ unsigned long length = 0;
- while (*s++ != 0 && length < maxlength)
- length++;
- return length;
+ while (length < maxlength && *s++ != 0)
+ length++;
+ return length;
}
EXPORT_SYMBOL(ucs2_strnlen);
unsigned long
ucs2_strlen(const ucs2_char_t *s)
{
- return ucs2_strnlen(s, ~0UL);
+ return ucs2_strnlen(s, ~0UL);
}
EXPORT_SYMBOL(ucs2_strlen);
@@ -28,7 +28,7 @@ EXPORT_SYMBOL(ucs2_strlen);
unsigned long
ucs2_strsize(const ucs2_char_t *data, unsigned long maxlength)
{
- return ucs2_strnlen(data, maxlength/sizeof(ucs2_char_t)) * sizeof(ucs2_char_t);
+ return ucs2_strnlen(data, maxlength/sizeof(ucs2_char_t)) * sizeof(ucs2_char_t);
}
EXPORT_SYMBOL(ucs2_strsize);
@@ -87,19 +87,19 @@ EXPORT_SYMBOL(ucs2_strscpy);
int
ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len)
{
- while (1) {
- if (len == 0)
- return 0;
- if (*a < *b)
- return -1;
- if (*a > *b)
- return 1;
- if (*a == 0) /* implies *b == 0 */
- return 0;
- a++;
- b++;
- len--;
- }
+ while (1) {
+ if (len == 0)
+ return 0;
+ if (*a < *b)
+ return -1;
+ if (*a > *b)
+ return 1;
+ if (*a == 0) /* implies *b == 0 */
+ return 0;
+ a++;
+ b++;
+ len--;
+ }
}
EXPORT_SYMBOL(ucs2_strncmp);
diff --git a/lib/vdso/Kconfig b/lib/vdso/Kconfig
index db87ba34ef19..597f5f0f9681 100644
--- a/lib/vdso/Kconfig
+++ b/lib/vdso/Kconfig
@@ -1,12 +1,11 @@
# SPDX-License-Identifier: GPL-2.0
-config HAVE_GENERIC_VDSO
+config VDSO_DATASTORE
bool
-if HAVE_GENERIC_VDSO
-
config GENERIC_GETTIMEOFDAY
bool
+ select VDSO_DATASTORE
help
This is a generic implementation of gettimeofday vdso.
Each architecture that enables this feature has to
@@ -21,7 +20,6 @@ config GENERIC_VDSO_OVERFLOW_PROTECT
config VDSO_GETRANDOM
bool
+ select VDSO_DATASTORE
help
Selected by architectures that support vDSO getrandom().
-
-endif
diff --git a/lib/vdso/Makefile b/lib/vdso/Makefile
index 405f743253d7..ac304def42d6 100644
--- a/lib/vdso/Makefile
+++ b/lib/vdso/Makefile
@@ -1,3 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_HAVE_GENERIC_VDSO) += datastore.o
+obj-$(CONFIG_VDSO_DATASTORE) += datastore.o
diff --git a/lib/vdso/datastore.c b/lib/vdso/datastore.c
index 17d37b82ebc6..1426bf4e0c12 100644
--- a/lib/vdso/datastore.c
+++ b/lib/vdso/datastore.c
@@ -29,10 +29,11 @@ struct vdso_arch_data *vdso_k_arch_data __ro_after_init =
(void *)&vdso_initdata[VDSO_ARCH_PAGES_START * PAGE_SIZE];
#endif /* CONFIG_ARCH_HAS_VDSO_ARCH_DATA */
+static struct page *vdso_data_pages __ro_after_init;
+
void __init vdso_setup_data_pages(void)
{
unsigned int order = get_order(VDSO_NR_PAGES * PAGE_SIZE);
- struct page *pages;
/*
* Allocate the data pages dynamically. SPARC does not support mapping
@@ -42,24 +43,24 @@ void __init vdso_setup_data_pages(void)
* Do not use folios. In time namespaces the pages are mapped in a different order
* to userspace, which is not handled by the folio optimizations in finish_fault().
*/
- pages = alloc_pages(GFP_KERNEL, order);
- if (!pages)
+ vdso_data_pages = alloc_pages(GFP_KERNEL, order);
+ if (!vdso_data_pages)
panic("Unable to allocate VDSO storage pages");
/* The pages are mapped one-by-one into userspace and each one needs to be refcounted. */
- split_page(pages, order);
+ split_page(vdso_data_pages, order);
/* Move the data already written by other subsystems to the new pages */
- memcpy(page_address(pages), vdso_initdata, VDSO_NR_PAGES * PAGE_SIZE);
+ memcpy(page_address(vdso_data_pages), vdso_initdata, VDSO_NR_PAGES * PAGE_SIZE);
if (IS_ENABLED(CONFIG_GENERIC_GETTIMEOFDAY))
- vdso_k_time_data = page_address(pages + VDSO_TIME_PAGE_OFFSET);
+ vdso_k_time_data = page_address(vdso_data_pages + VDSO_TIME_PAGE_OFFSET);
if (IS_ENABLED(CONFIG_VDSO_GETRANDOM))
- vdso_k_rng_data = page_address(pages + VDSO_RNG_PAGE_OFFSET);
+ vdso_k_rng_data = page_address(vdso_data_pages + VDSO_RNG_PAGE_OFFSET);
if (IS_ENABLED(CONFIG_ARCH_HAS_VDSO_ARCH_DATA))
- vdso_k_arch_data = page_address(pages + VDSO_ARCH_PAGES_START);
+ vdso_k_arch_data = page_address(vdso_data_pages + VDSO_ARCH_PAGES_START);
}
static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,
@@ -67,27 +68,28 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,
{
struct page *page, *timens_page;
+ if (unlikely(vmf->flags & FAULT_FLAG_REMOTE))
+ return VM_FAULT_SIGBUS;
+
+ page = vdso_data_pages + vmf->pgoff;
timens_page = find_timens_vvar_page(vma);
switch (vmf->pgoff) {
case VDSO_TIME_PAGE_OFFSET:
- if (!IS_ENABLED(CONFIG_GENERIC_GETTIMEOFDAY))
- return VM_FAULT_SIGBUS;
- page = virt_to_page(vdso_k_time_data);
- if (timens_page) {
- /*
- * Fault in VVAR page too, since it will be accessed
- * to get clock data anyway.
- */
- unsigned long addr;
- vm_fault_t err;
-
- addr = vmf->address + VDSO_TIMENS_PAGE_OFFSET * PAGE_SIZE;
- err = vmf_insert_page(vma, addr, page);
- if (unlikely(err & VM_FAULT_ERROR))
- return err;
- page = timens_page;
- }
+ if (!IS_ENABLED(CONFIG_GENERIC_GETTIMEOFDAY) || !timens_page)
+ break;
+ /*
+ * Fault in VVAR page too, since it will be accessed
+ * to get clock data anyway.
+ */
+ unsigned long addr;
+ vm_fault_t err;
+
+ addr = vmf->address + VDSO_TIMENS_PAGE_OFFSET * PAGE_SIZE;
+ err = vmf_insert_page(vma, addr, page);
+ if (unlikely(err & VM_FAULT_ERROR))
+ return err;
+ page = timens_page;
break;
case VDSO_TIMENS_PAGE_OFFSET:
/*
@@ -98,18 +100,11 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,
* See also the comment near timens_setup_vdso_data().
*/
if (!IS_ENABLED(CONFIG_TIME_NS) || !timens_page)
- return VM_FAULT_SIGBUS;
- page = virt_to_page(vdso_k_time_data);
+ break;
+ page = vdso_data_pages + VDSO_TIME_PAGE_OFFSET;
break;
case VDSO_RNG_PAGE_OFFSET:
- if (!IS_ENABLED(CONFIG_VDSO_GETRANDOM))
- return VM_FAULT_SIGBUS;
- page = virt_to_page(vdso_k_rng_data);
- break;
case VDSO_ARCH_PAGES_START ... VDSO_ARCH_PAGES_END:
- if (!IS_ENABLED(CONFIG_ARCH_HAS_VDSO_ARCH_DATA))
- return VM_FAULT_SIGBUS;
- page = virt_to_page(vdso_k_arch_data) + vmf->pgoff - VDSO_ARCH_PAGES_START;
break;
default:
return VM_FAULT_SIGBUS;
@@ -128,7 +123,7 @@ const struct vm_special_mapping vdso_vvar_mapping = {
struct vm_area_struct *vdso_install_vvar_mapping(struct mm_struct *mm, unsigned long addr)
{
return _install_special_mapping(mm, addr, VDSO_NR_PAGES * PAGE_SIZE,
- VM_READ | VM_MAYREAD | VM_IO | VM_DONTDUMP |
+ VM_READ | VM_MAYREAD | VM_DONTDUMP |
VM_MIXEDMAP | VM_SEALED_SYSMAP,
&vdso_vvar_mapping);
}
diff --git a/lib/vdso/getrandom.c b/lib/vdso/getrandom.c
index 7e29005aa208..2851afa9154f 100644
--- a/lib/vdso/getrandom.c
+++ b/lib/vdso/getrandom.c
@@ -8,6 +8,7 @@
#include <vdso/datapage.h>
#include <vdso/getrandom.h>
#include <vdso/limits.h>
+#include <vdso/page.h>
#include <vdso/unaligned.h>
#include <asm/barrier.h>
#include <asm/vdso/getrandom.h>
@@ -18,11 +19,6 @@
/* Bring in default accessors */
#include <vdso/vsyscall.h>
-#undef PAGE_SIZE
-#undef PAGE_MASK
-#define PAGE_SIZE (1UL << CONFIG_PAGE_SHIFT)
-#define PAGE_MASK (~(PAGE_SIZE - 1))
-
#define MEMCPY_AND_ZERO_SRC(type, dst, src, len) do { \
while (len >= sizeof(type)) { \
__put_unaligned_t(type, __get_unaligned_t(type, src), dst); \
diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c
index e0f289d3d110..f7a591aba59f 100644
--- a/lib/vdso/gettimeofday.c
+++ b/lib/vdso/gettimeofday.c
@@ -12,6 +12,8 @@
#include <vdso/time32.h>
#include <vdso/time64.h>
+#include <uapi/linux/unistd.h>
+
/*
* The generic vDSO implementation requires that gettimeofday.h
* provides:
@@ -23,6 +25,8 @@
*/
#include <asm/vdso/gettimeofday.h>
+#include <linux/build_bug.h>
+
/* Bring in default accessors */
#include <vdso/vsyscall.h>
@@ -323,6 +327,8 @@ __cvdso_clock_gettime32_data(const struct vdso_time_data *vd, clockid_t clock,
struct __kernel_timespec ts;
bool ok;
+ BUILD_BUG_ON(!IS_ENABLED(CONFIG_COMPAT_32BIT_TIME));
+
ok = __cvdso_clock_gettime_common(vd, clock, &ts);
if (unlikely(!ok))
@@ -348,6 +354,12 @@ __cvdso_gettimeofday_data(const struct vdso_time_data *vd,
{
const struct vdso_clock *vc = vd->clock_data;
+#ifndef __NR_gettimeofday
+ BUILD_BUG();
+#endif
+
+ BUILD_BUG_ON(sizeof(tv->tv_sec) != 8 && !IS_ENABLED(CONFIG_COMPAT_32BIT_TIME));
+
if (likely(tv != NULL)) {
struct __kernel_timespec ts;
@@ -382,6 +394,12 @@ __cvdso_time_data(const struct vdso_time_data *vd, __kernel_old_time_t *time)
const struct vdso_clock *vc = vd->clock_data;
__kernel_old_time_t t;
+#ifndef __NR_time
+ BUILD_BUG();
+#endif
+
+ BUILD_BUG_ON(sizeof(*time) != 8 && !IS_ENABLED(CONFIG_COMPAT_32BIT_TIME));
+
if (vdso_is_timens_clock(vc)) {
vd = vdso_timens_data(vd);
vc = vd->clock_data;
@@ -471,6 +489,8 @@ __cvdso_clock_getres_time32_data(const struct vdso_time_data *vd, clockid_t cloc
struct __kernel_timespec ts;
bool ok;
+ BUILD_BUG_ON(!IS_ENABLED(CONFIG_COMPAT_32BIT_TIME));
+
ok = __cvdso_clock_getres_common(vd, clock, &ts);
if (unlikely(!ok))
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 2bc6ef483576..1d95ab9314bf 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -86,7 +86,7 @@ static unsigned long long simple_strntoull(const char *startp, char **endp, unsi
cp = _parse_integer_fixup_radix(startp, &base);
prefix_chars = cp - startp;
if (prefix_chars < max_chars) {
- rv = _parse_integer_limit(cp, base, &result, max_chars - prefix_chars);
+ rv = _parse_integer(cp, base, &result, max_chars - prefix_chars);
/* FIXME */
cp += (rv & ~KSTRTOX_OVERFLOW);
} else {
@@ -2360,6 +2360,9 @@ void __init hash_pointers_finalize(bool slub_debug)
static int __init hash_pointers_mode_parse(char *str)
{
+ /* Avoid stale no_hash_pointers state when hash_pointers overrides it */
+ no_hash_pointers = false;
+
if (!str) {
pr_warn("Hash pointers mode empty; falling back to auto.\n");
hash_pointers_mode = HASH_PTR_AUTO;
@@ -2369,6 +2372,7 @@ static int __init hash_pointers_mode_parse(char *str)
} else if (strcmp(str, "never") == 0) {
pr_info("Hash pointers mode set to never.\n");
hash_pointers_mode = HASH_PTR_NEVER;
+ no_hash_pointers = true;
} else if (strcmp(str, "always") == 0) {
pr_info("Hash pointers mode set to always.\n");
hash_pointers_mode = HASH_PTR_ALWAYS;
diff --git a/lib/xarray.c b/lib/xarray.c
index 9a8b4916540c..bfe7bef80f34 100644
--- a/lib/xarray.c
+++ b/lib/xarray.c
@@ -1053,6 +1053,9 @@ void xas_split_alloc(struct xa_state *xas, void *entry, unsigned int order,
if (xas->xa_shift + XA_CHUNK_SHIFT > order)
return;
+ if (xas->xa->xa_flags & XA_FLAGS_ACCOUNT)
+ gfp |= __GFP_ACCOUNT;
+
do {
struct xa_node *node;
diff --git a/lib/xz/xz_dec_bcj.c b/lib/xz/xz_dec_bcj.c
index cc49a300a5b2..88922323f96e 100644
--- a/lib/xz/xz_dec_bcj.c
+++ b/lib/xz/xz_dec_bcj.c
@@ -466,7 +466,7 @@ static void bcj_flush(struct xz_dec_bcj *s, struct xz_buf *b)
{
size_t copy_size;
- copy_size = min_t(size_t, s->temp.filtered, b->out_size - b->out_pos);
+ copy_size = min(s->temp.filtered, b->out_size - b->out_pos);
memcpy(b->out + b->out_pos, s->temp.buf, copy_size);
b->out_pos += copy_size;
diff --git a/lib/xz/xz_dec_lzma2.c b/lib/xz/xz_dec_lzma2.c
index 4b783ac94e71..46c2df6ad6f5 100644
--- a/lib/xz/xz_dec_lzma2.c
+++ b/lib/xz/xz_dec_lzma2.c
@@ -135,14 +135,16 @@ struct lzma_dec {
uint32_t rep2;
uint32_t rep3;
- /* Types of the most recently seen LZMA symbols */
- enum lzma_state state;
-
/*
* Length of a match. This is updated so that dict_repeat can
- * be called again to finish repeating the whole match.
+ * be called again to finish repeating the whole match. This is
+ * size_t because a pointer to this is passed to dict_repeat,
+ * and there it's nicer to have size_t instead of uint32_t.
*/
- uint32_t len;
+ size_t len;
+
+ /* Types of the most recently seen LZMA symbols */
+ enum lzma_state state;
/*
* LZMA properties or related bit masks (number of literal
@@ -228,13 +230,13 @@ struct lzma2_dec {
enum lzma2_seq next_sequence;
/* Uncompressed size of LZMA chunk (2 MiB at maximum) */
- uint32_t uncompressed;
+ size_t uncompressed;
/*
* Compressed size of LZMA chunk or compressed/uncompressed
* size of uncompressed chunk (64 KiB at maximum)
*/
- uint32_t compressed;
+ size_t compressed;
/*
* True if dictionary reset is needed. This is false before
@@ -269,11 +271,11 @@ struct xz_dec_lzma2 {
struct lzma_dec lzma;
/*
- * Temporary buffer which holds small number of input bytes between
+ * Temporary buffer which holds a small number of input bytes between
* decoder calls. See lzma2_lzma() for details.
*/
struct {
- uint32_t size;
+ size_t size;
uint8_t buf[3 * LZMA_IN_REQUIRED];
} temp;
};
@@ -320,7 +322,7 @@ static inline bool dict_has_space(const struct dictionary *dict)
* still empty. This special case is needed for single-call decoding to
* avoid writing a '\0' to the end of the destination buffer.
*/
-static inline uint32_t dict_get(const struct dictionary *dict, uint32_t dist)
+static inline uint32_t dict_get(const struct dictionary *dict, size_t dist)
{
size_t offset = dict->pos - dist - 1;
@@ -346,15 +348,15 @@ static inline void dict_put(struct dictionary *dict, uint8_t byte)
* invalid, false is returned. On success, true is returned and *len is
* updated to indicate how many bytes were left to be repeated.
*/
-static bool dict_repeat(struct dictionary *dict, uint32_t *len, uint32_t dist)
+static bool dict_repeat(struct dictionary *dict, size_t *len, size_t dist)
{
size_t back;
- uint32_t left;
+ size_t left;
if (dist >= dict->full || dist >= dict->size)
return false;
- left = min_t(size_t, dict->limit - dict->pos, *len);
+ left = min(dict->limit - dict->pos, *len);
*len -= left;
back = dict->pos - dist - 1;
@@ -375,7 +377,7 @@ static bool dict_repeat(struct dictionary *dict, uint32_t *len, uint32_t dist)
/* Copy uncompressed data as is from input to dictionary and output buffers. */
static void dict_uncompressed(struct dictionary *dict, struct xz_buf *b,
- uint32_t *left)
+ size_t *left)
{
size_t copy_size;
@@ -433,7 +435,7 @@ static void dict_uncompressed(struct dictionary *dict, struct xz_buf *b,
* enough space in b->out. This is guaranteed because caller uses dict_limit()
* before decoding data into the dictionary.
*/
-static uint32_t dict_flush(struct dictionary *dict, struct xz_buf *b)
+static size_t dict_flush(struct dictionary *dict, struct xz_buf *b)
{
size_t copy_size = dict->pos - dict->start;
@@ -755,8 +757,8 @@ static bool lzma_main(struct xz_dec_lzma2 *s)
uint32_t pos_state;
/*
- * If the dictionary was reached during the previous call, try to
- * finish the possibly pending repeat in the dictionary.
+ * If the dictionary write limit was reached during the previous call,
+ * try to finish the possibly pending repeat in the dictionary.
*/
if (dict_has_space(&s->dict) && s->lzma.len > 0)
dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0);
@@ -878,7 +880,7 @@ static bool lzma_props(struct xz_dec_lzma2 *s, uint8_t props)
static bool lzma2_lzma(struct xz_dec_lzma2 *s, struct xz_buf *b)
{
size_t in_avail;
- uint32_t tmp;
+ size_t tmp;
in_avail = b->in_size - b->in_pos;
if (s->temp.size > 0 || s->lzma2.compressed == 0) {
@@ -976,7 +978,7 @@ enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s, struct xz_buf *b)
* an uncompressed chunk
* 0x02 Uncompressed chunk (no dictionary reset)
*
- * Highest three bits (s->control & 0xE0):
+ * Highest three bits (tmp & 0xE0):
* 0xE0 Dictionary reset, new properties and state
* reset, followed by LZMA compressed chunk
* 0xC0 New properties and state reset, followed
@@ -988,7 +990,7 @@ enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s, struct xz_buf *b)
* 0x80 LZMA chunk (no dictionary or state reset)
*
* For LZMA compressed chunks, the lowest five bits
- * (s->control & 1F) are the highest bits of the
+ * (tmp & 1F) are the highest bits of the
* uncompressed size (bits 16-20).
*
* A new LZMA2 stream must begin with a dictionary
@@ -1046,25 +1048,23 @@ enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s, struct xz_buf *b)
case SEQ_UNCOMPRESSED_1:
s->lzma2.uncompressed
- += (uint32_t)b->in[b->in_pos++] << 8;
+ += (size_t)b->in[b->in_pos++] << 8;
s->lzma2.sequence = SEQ_UNCOMPRESSED_2;
break;
case SEQ_UNCOMPRESSED_2:
s->lzma2.uncompressed
- += (uint32_t)b->in[b->in_pos++] + 1;
+ += (size_t)b->in[b->in_pos++] + 1;
s->lzma2.sequence = SEQ_COMPRESSED_0;
break;
case SEQ_COMPRESSED_0:
- s->lzma2.compressed
- = (uint32_t)b->in[b->in_pos++] << 8;
+ s->lzma2.compressed = (size_t)b->in[b->in_pos++] << 8;
s->lzma2.sequence = SEQ_COMPRESSED_1;
break;
case SEQ_COMPRESSED_1:
- s->lzma2.compressed
- += (uint32_t)b->in[b->in_pos++] + 1;
+ s->lzma2.compressed += (size_t)b->in[b->in_pos++] + 1;
s->lzma2.sequence = s->lzma2.next_sequence;
break;
@@ -1091,16 +1091,15 @@ enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s, struct xz_buf *b)
case SEQ_LZMA_RUN:
/*
* Set dictionary limit to indicate how much we want
- * to be encoded at maximum. Decode new data into the
+ * to be decoded at maximum. Decode new data into the
* dictionary. Flush the new data from dictionary to
* b->out. Check if we finished decoding this chunk.
* In case the dictionary got full but we didn't fill
* the output buffer yet, we may run this loop
* multiple times without changing s->lzma2.sequence.
*/
- dict_limit(&s->dict, min_t(size_t,
- b->out_size - b->out_pos,
- s->lzma2.uncompressed));
+ dict_limit(&s->dict, min(b->out_size - b->out_pos,
+ s->lzma2.uncompressed));
if (!lzma2_lzma(s, b))
return XZ_DATA_ERROR;
@@ -1260,8 +1259,8 @@ enum xz_ret xz_dec_microlzma_run(struct xz_dec_microlzma *s_ptr,
s->dict.end = b->out_size - b->out_pos;
while (true) {
- dict_limit(&s->dict, min_t(size_t, b->out_size - b->out_pos,
- s->lzma2.uncompressed));
+ dict_limit(&s->dict, min(b->out_size - b->out_pos,
+ s->lzma2.uncompressed));
if (!lzma2_lzma(s, b))
return XZ_DATA_ERROR;
diff --git a/lib/xz/xz_dec_stream.c b/lib/xz/xz_dec_stream.c
index 59bfd54ffee7..0bed6daefac2 100644
--- a/lib/xz/xz_dec_stream.c
+++ b/lib/xz/xz_dec_stream.c
@@ -155,8 +155,8 @@ static const uint8_t check_sizes[16] = {
*/
static bool fill_temp(struct xz_dec *s, struct xz_buf *b)
{
- size_t copy_size = min_t(size_t,
- b->in_size - b->in_pos, s->temp.size - s->temp.pos);
+ size_t copy_size = min(b->in_size - b->in_pos,
+ s->temp.size - s->temp.pos);
memcpy(s->temp.buf + s->temp.pos, b->in + b->in_pos, copy_size);
b->in_pos += copy_size;
diff --git a/lib/xz/xz_lzma2.h b/lib/xz/xz_lzma2.h
index d2632b7dfb9c..a612ce4fd450 100644
--- a/lib/xz/xz_lzma2.h
+++ b/lib/xz/xz_lzma2.h
@@ -143,7 +143,7 @@ static inline bool lzma_state_is_literal(enum lzma_state state)
* Get the index of the appropriate probability array for decoding
* the distance slot.
*/
-static inline uint32_t lzma_get_dist_state(uint32_t len)
+static inline size_t lzma_get_dist_state(size_t len)
{
return len < DIST_STATES + MATCH_LEN_MIN
? len - MATCH_LEN_MIN : DIST_STATES - 1;