improvements spurred by peer review for 20260204-linuxkm-fips-hash:

configure.ac: add --enable-kernel-verbose-debug and --enable-kernel-stack-debug;

linuxkm/Makefile:
* add QFLAG and VFLAG setup, and pass their values appropriately;
* add missing `@set -e` and `-Wall -Wextra` to the linuxkm-fips-hash recipe;
* use +$(MAKE), not @$(MAKE), for proper dry run recursion.

linuxkm/README.md: update to reflect new goodies, and generally revise+extend remarks.

linuxkm/linuxkm-fips-hash-wrapper.sh: add copyright header; pass through extra caller arguments to ./linuxkm-fips-hash.

linuxkm/linuxkm-fips-hash.c:
* add copyright header;
* fix code around user_coreKey;
* add explicit wolfCrypt_Cleanup() and cleanup of mod_fd and mod_map at end;
* remove unused reloc_tab_len
* fix a couple -Wsign-compares;
* add missing fprintf arguments
* properly set ret = -1 in a couple failure paths.

linuxkm/linuxkm_wc_port.h: set WOLFSSL_LINUXKM_VERBOSE_DEBUG when WOLFSSL_KERNEL_VERBOSE_DEBUG, and recognize WOLFSSL_KERNEL_STACK_DEBUG as a synonym for WC_LINUXKM_STACK_DEBUG.

linuxkm/linuxkm_memory.c and linuxkm/linuxkm_memory.h: add brief explanatory comments.
This commit is contained in:
Daniel Pouzzner
2026-02-19 17:42:01 -06:00
parent f376ae210e
commit db7a04a626
9 changed files with 227 additions and 50 deletions
+20 -2
View File
@@ -131,16 +131,34 @@ then
fi
# Kernel module benchmark
ENABLED_KERNEL_BENCHMARKS=""
AC_ARG_ENABLE([kernel-benchmarks],
[AS_HELP_STRING([--enable-kernel-benchmarks],[Enable crypto benchmarking autorun at module load time for kernel module (default: disabled)])],
[ENABLED_KERNEL_BENCHMARKS=$enableval])
[ENABLED_KERNEL_BENCHMARKS=$enableval],
[ENABLED_KERNEL_BENCHMARKS="no"])
if test "$ENABLED_KERNEL_BENCHMARKS" = "yes"
then
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_KERNEL_BENCHMARKS"
fi
AC_SUBST([ENABLED_KERNEL_BENCHMARKS])
AC_ARG_ENABLE([kernel-verbose-debug],
[AS_HELP_STRING([--enable-kernel-verbose-debug],[Enable supplementary runtime debugging messages for kernel module (default: disabled)])],
[ENABLED_KERNEL_VERBOSE_DEBUG=$enableval],
[ENABLED_KERNEL_VERBOSE_DEBUG="no"])
if test "$ENABLED_KERNEL_VERBOSE_DEBUG" = "yes"
then
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_KERNEL_VERBOSE_DEBUG"
fi
AC_ARG_ENABLE([kernel-stack-debug],
[AS_HELP_STRING([--enable-kernel-stack-debug],[Enable runtime reporting of stack usage in kernel module (default: disabled)])],
[ENABLED_KERNEL_STACK_DEBUG=$enableval],
[ENABLED_KERNEL_STACK_DEBUG="no"])
if test "$ENABLED_KERNEL_STACK_DEBUG" = "yes"
then
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_KERNEL_STACK_DEBUG"
fi
# Linux Kernel Module options (more options later)
AC_ARG_ENABLE([linuxkm],
[AS_HELP_STRING([--enable-linuxkm],[Enable Linux Kernel Module (default: disabled)])],
+16 -7
View File
@@ -21,6 +21,14 @@
.ONESHELL:
SHELL=bash
ifeq "$(quiet)" "silent_"
QFLAG := --quiet
else ifeq "$(V)" "1"
VFLAG := --verbose
else
QFLAG := --quiet
endif
ifndef LIBWOLFSSL_NAME
LIBWOLFSSL_NAME := libwolfssl
endif
@@ -355,34 +363,35 @@ libwolfssl-user-build/src/.libs/libwolfssl.so:
@echo > user_settings_asm.h
@echo -n 'Configuring libwolfssl.so...'
@unset WOLFSSL_CFLAGS WOLFCRYPT_PIE_FILES ASFLAGS_FPUSIMD_ENABLE ASFLAGS_FPU_DISABLE_SIMD_ENABLE src_libwolfssl_la_OBJECTS WOLFSSL_ASFLAGS AM_CFLAGS WOLFSSL_OBJ_FILES ENABLED_LINUXKM_LKCAPI_REGISTER EXTRA_LDFLAGS CC LD
@./configure --quiet --disable-jobserver --enable-cryptonly --enable-fips="$$FIPS_FLAVOR" CFLAGS='-DWC_SYM_RELOC_TABLES_SUPPORT -DWOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE -DWOLFSSL_USER_SETTINGS -DWOLFSSL_USER_SETTINGS_ASM'
@./configure $(QFLAG) $(VFLAG) --disable-jobserver --enable-cryptonly --enable-fips="$$FIPS_FLAVOR" CFLAGS='-DWC_SYM_RELOC_TABLES_SUPPORT -DWOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE -DWOLFSSL_USER_SETTINGS -DWOLFSSL_USER_SETTINGS_ASM'
@echo ' done.'
@echo -n 'Compiling and linking libwolfssl.so...'
@$(MAKE) >/dev/null
+$(MAKE) $(QFLAG) >/dev/null
@echo ' done.'
@echo -n 'Fixing FIPS hash...'
@userhash=$$(wolfcrypt/test/testwolfcrypt 2>&1 | sed -n -E 's/^hash = (.+)$$/\1/p')
@if [[ -z "$$userhash" ]]; then echo ' FIPS hash not found!' >&2; exit 1; fi
@find wolfcrypt/src -name '*fips_test*o' -delete
@$(MAKE) EXTRA_CFLAGS=-DWOLFCRYPT_FIPS_CORE_HASH_VALUE="$$userhash"
+$(MAKE) $(QFLAG) EXTRA_CFLAGS=-DWOLFCRYPT_FIPS_CORE_HASH_VALUE="$$userhash"
@echo ' done.'
linuxkm-fips-hash: libwolfssl-user-build/src/.libs/libwolfssl.so linuxkm-fips-hash.c
@set -e
@echo -n 'Compiling linuxkm-fips-hash...'
# note direct invocation of cc -- we are compiling for the build host, not the target host.
@cc -I'$(MODULE_TOP)/libwolfssl-user-build' -o linuxkm-fips-hash linuxkm/linuxkm-fips-hash.c -L '$(MODULE_TOP)/libwolfssl-user-build/src/.libs' -Wl,-rpath-link='$(MODULE_TOP)/libwolfssl-user-build/src/.libs' -Wl,-rpath='$(MODULE_TOP)/libwolfssl-user-build/src/.libs' -lwolfssl
@cc -Wall -Wextra -O2 -I'$(MODULE_TOP)/libwolfssl-user-build' -o linuxkm-fips-hash linuxkm/linuxkm-fips-hash.c -L '$(MODULE_TOP)/libwolfssl-user-build/src/.libs' -Wl,-rpath-link='$(MODULE_TOP)/libwolfssl-user-build/src/.libs' -Wl,-rpath='$(MODULE_TOP)/libwolfssl-user-build/src/.libs' -lwolfssl
@echo ' done.'
.PHONY: module-with-matching-fips-hash
module-with-matching-fips-hash: $(LIBWOLFSSL_NAME).ko linuxkm-fips-hash
@set -e
./linuxkm-fips-hash-wrapper.sh "$<"
$(MAKE) -C . '$(LIBWOLFSSL_NAME).ko.signed'
@./linuxkm-fips-hash-wrapper.sh "$<" $(QFLAG) $(VFLAG)
+$(MAKE) $(QFLAG) -C . '$(LIBWOLFSSL_NAME).ko.signed'
.PHONY: module-with-matching-fips-hash-no-sign
module-with-matching-fips-hash-no-sign: $(LIBWOLFSSL_NAME).ko linuxkm-fips-hash
@set -e
./linuxkm-fips-hash-wrapper.sh "$<"
@./linuxkm-fips-hash-wrapper.sh "$<"
$(LIBWOLFSSL_NAME).ko.signed: $(LIBWOLFSSL_NAME).ko
ifdef FORCE_NO_MODULE_SIG
+85 -31
View File
@@ -12,6 +12,7 @@ when wolfCrypt-FIPS is used, this provides a simple recipe for FIPS-compliant
kernels.
Supported features:
- crypto acceleration: AES-NI, AVX, etc.
- kernel crypto API registration (wolfCrypt algs appear as drivers in `/proc/crypto`.).
- `CONFIG_CRYPTO_FIPS`, and crypto-manager self-tests.
@@ -22,16 +23,24 @@ Supported features:
## Building and Installing
Build linuxkm with:
Build `libwolfssl.ko` with:
```sh
$ ./configure --enable-linuxkm --with-linux-source=/usr/src/linux
$ make -j module
```
note: replace `/usr/src/linux` with a path to your fully configured and built
Note: Replace `/usr/src/linux` with a path to your fully configured and built
target kernel source tree.
If building from a FIPS kernel module bundle, build `libwolfssl.ko` with:
```sh
$ ./configure --enable-fips=fips_flavor --enable-linuxkm --with-linux-source=/usr/src/linux
$ make -j module-with-matching-fips-hash
```
Note: Replace `fips_flavor` with the correct value.
Assuming you are targeting your native system, install with:
```sh
@@ -39,54 +48,99 @@ $ sudo make install
$ sudo modprobe libwolfssl
```
### options
### Key additional Linux kernel module configuration options
| option | description |
| :------------------------------- | :----------------------------------------- |
| `--enable-linuxkm-lkcapi-register` | Register wolfcrypt algs with linux kernel crypto API. <br> Optional value is 'all', 'all-kconfig', 'none', or a comma separated list of algs. |
| `--enable-all-crypto` | Enable extra crypto algorithms |
| `--enable-intelasm` | x86/amd64 crypto acceleration |
| `--enable-cryptonly` | Omit TLS/DTLS implementation (normally recommended) |
### Additional configuration options for verification, performance evaluation, and troubleshooting
| option | description |
| :------------------------------- | :----------------------------------------- |
| `--enable-crypttests` | Run `wolfcrypt_test()` at module load (not recommended for production) |
| `--enable-kernel-benchmarks` | Run crypto benchmark at module load (_not appropriate for production_) |
| `--enable-kernel-verbose-debug` | Extra runtime diagnostic and informational messages |
| `--enable-kernel-stack-debug` | Report stack usage during module startup |
| `--enable-debug-trace-errcodes` | Profuse debug logging (_not appropriate for production_) |
| `--enable-debug-trace-errcodes=backtrace` | Even more profuse debug logging (_not appropriate for production_) |
| linuxkm option | description |
| :------------------------------- | :--------------------------------------- |
| --enable-linuxkm-lkcapi-register | Register wolfcrypt algs with linux kernel <br> crypto API. Options are 'all', 'none', or <br> comma separated list of algs. |
| --enable-linuxkm-pie | Enable relocatable object build of module|
| --enable-linuxkm-benchmarks | Run crypto benchmark at module load |
## Kernel Patches
The dir `linuxkm/patches` contains a patch to the linux kernel CRNG. The
The `linuxkm/patches` directory in the source distribution contains a patch to the linux kernel CRNG. The
CRNG provides the implementation for `/dev/random`, `/dev/urandom`, and
`getrandom()`.
`getrandom()`, and for internal RNG APIs such as `get_random_bytes()`,
`get_random_u32()`, etc.
The patch applies to these two sources:
The patch updates these two sources
- `drivers/char/random.c`
- `include/linux/random.h`
It adds a callback facility to the core kernel code that allows `libwolfssl.ko`
to register FIPS-compliant algorithms in place of the native implementation
(which is based on non-FIPS ChaCha20 and blake2s algorithms). When `libwolfssl.ko` is configured with
`--enable-linuxkm-lkcapi-register` and loaded into a patched kernel, it
automatically registers the FIPS callbacks. At startup, the module will report
to use FIPS-compliant algorithms, instead of chacha and blake2s.
Patches are provided for several kernel versions, ranging from `5.10.x` to
`6.15`.
### patch procedure
1. Ensure kernel src tree is clean before patching:
```sh
cd ~/kernelsrc/
make mrproper
```
libwolfssl: kernel global random_bytes handlers installed.
```
2. Verify patches will apply clean with a dry run check:
Additionally, `/proc/crypto` will advertise that the FIPS DRBG is installed at
highest priority "-with-global-replace":
```ini
name : stdrng
driver : sha2-256-drbg-nopr-wolfcrypt-fips-140-3-with-global-replace
module : libwolfssl
priority : 100000
refcnt : 2
selftest : passed
internal : no
fips : yes
type : rng
seedsize : 0
```
```sh
patch -p1 --dry-run <~/wolfssl-5.8.2/linuxkm/patches/6.12/WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS-6v12.patch
Patches are provided for several kernel versions, ranging from `5.10.x` to
`6.15`, with the most recent patchset tested nightly with the latest Linux
release and RC kernels, and with the latest linux-next snapshot. Use the
patchset with the most recent target kernel version not greater than that of the
kernel you're targeting.
### Patch procedure
1. Verify that the patcheset applies cleanly, using a dry run:
```console
$ cd ~/kernelsrc/
$ patch -p1 --dry-run < ~/wolfssl-5.8.2/linuxkm/patches/6.12/WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS-6v12.patch
checking file drivers/char/random.c
checking file include/linux/random.h
```
3. Finally patch the kernel:
2. Optionally, clean the kernel src tree before patching:
```sh
patch -p1 <~/wolfssl-5.8.2/linuxkm/patches/6.12/WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS-6v12.patch
```console
$ make mrproper
```
3. Patch the kernel:
```console
$ patch -p1 < ~/wolfssl-5.8.2/linuxkm/patches/6.12/WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS-6v12.patch
patching file drivers/char/random.c
patching file include/linux/random.h
```
4. Build kernel.
4. Build and optionally install the patched kernel:
```console
$ make -j
# make modules_install
# make install
```
+23 -1
View File
@@ -1,8 +1,30 @@
#!/bin/bash
# linuxkm-fips-hash-wrapper.sh -- Wrapper for linuxkm-fips-hash -- looks up the
# fencepost values using readelf, and assembles the argument list from them.
#
# Copyright (C) 2006-2026 wolfSSL Inc.
#
# This file is part of wolfSSL.
#
# wolfSSL is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# wolfSSL is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
set -o noclobber -o nounset -o pipefail -o errexit
mod_path=$1
shift
readarray -t fenceposts < <(readelf --wide --sections --symbols "$mod_path" | awk '
BEGIN {
@@ -64,4 +86,4 @@ BEGIN {
}
}')
./linuxkm-fips-hash "${fenceposts[@]}" --mod-path "$mod_path" --in-place --quiet
./linuxkm-fips-hash "${fenceposts[@]}" --mod-path "$mod_path" --in-place "$@"
+52 -7
View File
@@ -1,3 +1,29 @@
/* linuxkm-fips-hash.c
*
* A utility to compute the correct FIPS integrity hash for a fully linked
* libwolfssl.ko kernel module, and to optionally update the module in place.
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
/* See linuxkm-fips-hash-wrapper.sh for argument setup example. */
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
@@ -31,7 +57,6 @@
#define FIPS_IN_CORE_VERIFY_SZ FIPS_IN_CORE_DIGEST_SIZE
#endif
static const char *user_coreKey;
#ifdef WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE
extern const char coreKey[FIPS_IN_CORE_KEY_SZ*2 + 1];
#endif
@@ -67,10 +92,10 @@ int main(int argc, char **argv)
char new_verifyCore[new_verifyCore_size];
const char *progname = strchr(argv[0], '/') ? strrchr(argv[0], '/') + 1 : argv[0];
const char *mod_path = NULL;
const char *user_coreKey = NULL;
int mod_fd;
struct stat st;
byte *mod_map = NULL;
word32 reloc_tab_len;
byte *mod_map = MAP_FAILED;
struct wc_reloc_counts reloc_counts;
int inplace = 0;
int quiet = 0;
@@ -248,11 +273,11 @@ int main(int argc, char **argv)
}
if ((seg_map.reloc_tab_start >= seg_map.reloc_tab_end) ||
(seg_map.reloc_tab_end >= st.st_size) ||
(seg_map.reloc_tab_end >= (unsigned long)st.st_size) ||
(seg_map.reloc_tab_len_start >= seg_map.reloc_tab_len_end) ||
(seg_map.reloc_tab_len_end >= st.st_size))
(seg_map.reloc_tab_len_end >= (unsigned long)st.st_size))
{
fprintf(stderr, "%s: supplied reloc_tab fencepost(s) are out of bounds.\n", progname, mod_path, st.st_size);
fprintf(stderr, "%s: supplied reloc_tab fencepost(s) are out of bounds for supplied module %s with length %lu.\n", progname, mod_path, (unsigned long)st.st_size);
exit(1);
}
@@ -294,6 +319,7 @@ int main(int argc, char **argv)
if (seg_map.verifyCore_end - seg_map.verifyCore_start != new_verifyCore_size) {
fprintf(stderr, "%s: unexpected verifyCore length %zu.\n", progname, (size_t)(seg_map.verifyCore_end - seg_map.verifyCore_start));
ret = -1;
goto out;
}
@@ -302,7 +328,7 @@ int main(int argc, char **argv)
ret = wc_fips_generate_hash(
&seg_map,
FIPS_IN_CORE_DIGEST_SIZE,
coreKey,
user_coreKey,
&hmac,
(wc_fips_verifyCore_hmac_setkey_fn)hmac_setkey_cb,
(wc_fips_verifyCore_hmac_update_fn)hmac_update_cb,
@@ -322,6 +348,7 @@ int main(int argc, char **argv)
if (new_verifyCore_size < sizeof new_verifyCore) {
fprintf(stderr, "%s: wc_fips_generate_hash() returned unexpected verifyCore length %u.\n", progname, new_verifyCore_size);
ret = -1;
goto out;
}
@@ -338,17 +365,35 @@ int main(int argc, char **argv)
fprintf(stderr, "%s: munmap: %m\n", progname);
exit(1);
}
mod_map = MAP_FAILED;
ret = close(mod_fd);
if (ret < 0) {
fprintf(stderr, "%s: close: %m\n", progname);
exit(1);
}
mod_fd = -1;
printf("FIPS integrity hash updated successfully.\n");
}
out:
wc_HmacFree(&hmac);
wolfCrypt_Cleanup();
if (mod_map != MAP_FAILED) {
if (munmap(mod_map, st.st_size) < 0) {
fprintf(stderr, "%s: munmap: %m\n", progname);
if (ret == 0)
ret = -1;
}
}
if (mod_fd >= 0) {
if (close(mod_fd) < 0) {
fprintf(stderr, "%s: close: %m\n", progname);
if (ret == 0)
ret = -1;
}
}
if (ret)
exit(1);
+19
View File
@@ -513,6 +513,25 @@ ssize_t wc_reloc_normalize_text(
#define FIPS_IN_CORE_VERIFY_SZ FIPS_IN_CORE_DIGEST_SIZE
#endif
/* wc_fips_generate_hash() is the high level entry point to the supplementary
* FIPS integrity hash calculation facility, used for offline hash calculation
* (particularly for kernel module builds), and for the
* WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE mechanism in the kernel module.
*
* The seg_map describes the layout of the module, including its precomputed
* relocation table and its FIPS fenceposts. For
* WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE, seg_map is a static const in
* module_hooks.c, but for offline calculation, readelf is used in
* linuxkm-fips-hash-wrapper.sh to extract the values to pass to
* linuxkm-fips-hash.
*
* The HMAC callback pointers are generic, but have wolfCrypt-like argument
* structure -- for live WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE calls, they
* point to wrappers around native Linux kernel implementations, but for
* linuxkm-fips-hash, they point to wrappers around native wolfCrypt
* implementations.
*/
int wc_fips_generate_hash(
const struct wc_reloc_table_segments *seg_map,
word32 digest_size,
+6
View File
@@ -78,6 +78,8 @@ struct __attribute__((packed)) wc_reloc_table_ent {
#if defined(WC_SYM_RELOC_TABLES) || defined(WC_SYM_RELOC_TABLES_SUPPORT)
/* full ELF fencepost representation, to allow wc_reloc_normalize_text() */
struct wc_reloc_table_segments {
unsigned long start;
unsigned long end;
@@ -164,6 +166,10 @@ struct wc_reloc_counts {
#elif defined(HAVE_FIPS)
/* barebones FIPS fencepost representation -- no provision for
* wc_reloc_normalize_text()
*/
struct wc_reloc_table_segments {
unsigned long start;
unsigned long end;
+5 -1
View File
@@ -24,6 +24,10 @@
#ifndef LINUXKM_WC_PORT_H
#define LINUXKM_WC_PORT_H
#if defined(WOLFSSL_KERNEL_VERBOSE_DEBUG) && !defined(WOLFSSL_LINUXKM_VERBOSE_DEBUG)
#define WOLFSSL_LINUXKM_VERBOSE_DEBUG
#endif
#include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0)
@@ -1439,7 +1443,7 @@
#endif /* WC_SYM_RELOC_TABLES */
#ifdef WC_LINUXKM_STACK_DEBUG
#if defined(WOLFSSL_KERNEL_STACK_DEBUG) || defined(WC_LINUXKM_STACK_DEBUG)
#ifndef CONFIG_THREAD_INFO_IN_TASK
#error WC_LINUXKM_STACK_DEBUG requires CONFIG_THREAD_INFO_IN_TASK
+1 -1
View File
@@ -1518,7 +1518,7 @@ extern const unsigned int wolfCrypt_FIPS_ro_end[];
static int linux_fips_hmac_setkey(struct shash_desc *desc, const byte *key, word32 key_len) {
int ret = crypto_shash_setkey(desc->tfm, key, key_len);
if (ret) {
pr_err("ERROR: crypto_ahash_setkey failed: err %d\n", ret);
pr_err("ERROR: crypto_shash_setkey failed: err %d\n", ret);
return BAD_STATE_E;
}