Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 78 additions & 25 deletions linuxkm/Kbuild
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,18 @@ endif

ccflags-y = $(WOLFSSL_CFLAGS) $(WOLFSSL_CFLAGS_NO_VECTOR_INSNS)

# Retpoline mitigation for Spectre v2 was added in 4.15, but under knob
# CONFIG_RETPOLINE, and return thunk mitigation for retbleed was added
# in 5.19, but under knob CONFIG_RETHUNK. The current knob names were
# merged in 6.9; alias to current names so one set of conditionals
# serves both.
CONFIG_MITIGATION_RETPOLINE ?= $(CONFIG_RETPOLINE)
CONFIG_MITIGATION_RETHUNK ?= $(CONFIG_RETHUNK)

ifeq "$(ENABLED_LINUXKM_PIE)" "yes"
ifdef CONFIG_CFI_CLANG
$(error CONFIG_CFI_CLANG is not compatible with ENABLED_LINUXKM_PIE.)
endif
# note, we need -fno-stack-protector to avoid references to
# "__stack_chk_fail" from the wolfCrypt container.
PIE_FLAGS := -DWC_CONTAINERIZE_THIS -fno-stack-protector -fno-toplevel-reorder
Expand Down Expand Up @@ -206,44 +217,86 @@ ifeq "$(ENABLED_LINUXKM_PIE)" "yes"
ifeq "$(KERNEL_ARCH_X86)" "yes"
PIE_FLAGS += -mcmodel=small

# eliminate external references to __x86_return_thunk and
# __x86_indirect_thunk_foo implementations. _all_ references must be
# eliminated, not just those in PIE objects, otherwise some kernels will
# eliminate external references to __x86_return_thunk (via
# -mfunction-return=thunk-inline) and __x86_indirect_thunk_foo (via
# -mindirect-branch=thunk-inline). _all_ references must be eliminated,
# not just those in PIE objects, otherwise some kernels will
# false-positively complain about unpatched thunks.
ifeq "$(CONFIG_MITIGATION_RETPOLINE)" "y"
PIE_SUPPORT_FLAGS += -mfunction-return=thunk-inline
else
PIE_SUPPORT_FLAGS += -mfunction-return=keep
endif
ifeq "$(CONFIG_MITIGATION_RETHUNK)" "y"
PIE_SUPPORT_FLAGS += -mindirect-branch=thunk-inline
else
PIE_SUPPORT_FLAGS += -mindirect-branch=keep
endif

NO_EXTERNAL_THUNKS := y

OBJECT_FILES_NON_STANDARD := y
endif
ifeq "$(KERNEL_ARCH)" "arm"
PIE_FLAGS += -fno-unwind-tables
PIE_FLAGS += -fno-unwind-tables
endif
ifeq "$(KERNEL_ARCH)" "mips"
PIE_FLAGS += -mabicalls
PIE_FLAGS += -mabicalls
endif
ccflags-y += $(PIE_SUPPORT_FLAGS)
$(WOLFCRYPT_PIE_FILES): ccflags-y += $(PIE_FLAGS)
$(WOLFCRYPT_PIE_FILES): ccflags-remove-y += -pg \
$(call cc-option,-ftrivial-auto-var-init=zero)
$(call cc-option,-ftrivial-auto-var-init=zero)
endif

# An explicit FORCE_GLOBAL_OBJTOOL_OFF is refused outright with clang -- the
# thunk repair below is gcc-only.
ifdef CONFIG_CC_IS_CLANG
ifdef FORCE_GLOBAL_OBJTOOL_OFF
$(error FORCE_GLOBAL_OBJTOOL_OFF is not supported with clang.)
endif
endif

# On some kernels/configs, objtool runs and warns on the linked libwolfssl.o,
# ignoring the below "OBJECT_FILES_NON_STANDARD := y" annotations. This
# mechanism, activated with "make KBUILD_EXTRA_FLAGS=FORCE_GLOBAL_OBJTOOL_OFF=1",
# inhibits objtool completely. This may be necessary on modules compiled with
# assembly accelerations and/or ENABLED_LINUXKM_PIE.
# Similar to scripts/Makefile.lib delay-objtool: disable objtool on the kernels
# that run it on the linked object, ignoring OBJECT_FILES_NON_STANDARD. (Parse
# order prevents testing delay-objtool itself here: Makefile.build includes this
# file before Makefile.lib.) Auto-disablement is a gcc-only remedy, unavailable
# on clang, and objtool is mandatory to CONFIG_LTO_CLANG in any case.
ifndef CONFIG_CC_IS_CLANG
ifneq ($(or $(CONFIG_X86_KERNEL_IBT),$(CONFIG_KLP_BUILD)),)
ifeq "$(ENABLED_LINUXKM_PIE)" "yes"
FORCE_GLOBAL_OBJTOOL_OFF := y
else ifeq "$(ENABLED_ASM)" "yes"
FORCE_GLOBAL_OBJTOOL_OFF := y
endif
endif
endif

# objtool disablement can be manually activated with "make
# KBUILD_EXTRA_FLAGS=FORCE_GLOBAL_OBJTOOL_OFF=1"
ifdef FORCE_GLOBAL_OBJTOOL_OFF
undefine CONFIG_OBJTOOL
# On <5.19, the knob is named CONFIG_STACK_VALIDATION.
undefine CONFIG_STACK_VALIDATION
NO_EXTERNAL_THUNKS := y
endif

ifdef NO_EXTERNAL_THUNKS
ifeq "$(KERNEL_ARCH_X86)" "yes"
ifdef CONFIG_CC_IS_CLANG
# clang has no inline-thunk codegen (-mfunction-return accepts
# only keep/thunk-extern, and -mindirect-branch is a gcc-only
# spelling), so external thunk references are ineliminable when
# the mitigations are configured.
ifneq "$(CONFIG_MITIGATION_RETHUNK)$(CONFIG_MITIGATION_RETPOLINE)" ""
$(error NO_EXTERNAL_THUNKS requires gcc when retpoline/rethunk is configured.)
endif
else
ifeq "$(CONFIG_MITIGATION_RETHUNK)" "y"
PIE_SUPPORT_FLAGS += -mfunction-return=thunk-inline
else
PIE_SUPPORT_FLAGS += -mfunction-return=keep
endif
ifeq "$(CONFIG_MITIGATION_RETPOLINE)" "y"
PIE_SUPPORT_FLAGS += -mindirect-branch=thunk-inline -mindirect-branch-register
else
PIE_SUPPORT_FLAGS += -mindirect-branch=keep
endif
endif
endif
endif

ccflags-y += $(PIE_SUPPORT_FLAGS)

ifdef KERNEL_EXTRA_CFLAGS_REMOVE
ccflags-remove-y += $(KERNEL_EXTRA_CFLAGS_REMOVE)
endif
Expand Down Expand Up @@ -352,9 +405,9 @@ RENAME_PIE_TEXT_AND_DATA_SECTIONS := \
cd "$(obj)" || exit $$?; \
for file in $(WOLFCRYPT_PIE_FILES); do \
$(OBJCOPY) $$($(READELF) --sections --wide "$$file" | \
$(AWK) ' \
$(AWK) ' \
{ \
if (match($$0, "^ *\\[ *[0-9]+\\] +\\.(text|rodata|data|bss)(\\.[^ ]+)? ", a)) \
if (match($$0, "^ *\\[ *[0-9]+\\] +\\.(text|rodata|data|bss)(\\.[^ ]+)? ", a)) \
{ \
printf("--rename-section .%s%s=.%s_wolfcrypt ", \
a[1], a[2], a[1]); \
Expand All @@ -364,7 +417,7 @@ RENAME_PIE_TEXT_AND_DATA_SECTIONS := \
printf("--rename-section .%s.%s=.%s_wolfcrypt ", a[1], a[2], a[2]); \
} \
}') "$$file" || exit $$?; \
done; \
done; \
{ $(READELF) --sections --syms --wide $(WOLFCRYPT_PIE_FILES) | \
$(AWK) -v obj="$(obj)" ' \
/^File:/ { \
Expand Down
33 changes: 26 additions & 7 deletions wolfcrypt/benchmark/benchmark.c
Original file line number Diff line number Diff line change
Expand Up @@ -12847,12 +12847,11 @@ static void bench_frodokem_keygen(int type, const char* name, int keySize,
do {
/* while free pending slots in queue, submit ops */
for (times = 0; times < agreeTimes || pending > 0; times++) {
wc_FrodoKemKey_Free(key);
ret = wc_FrodoKemKey_Init(key, type, HEAP_HINT, INVALID_DEVID);
if (ret != 0)
goto exit;

ret = wc_FrodoKemKey_MakeKey(key, &gRng);
wc_FrodoKemKey_Free(key);
if (ret != 0)
goto exit;
RECORD_MULTI_VALUE_STATS();
Expand Down Expand Up @@ -12882,6 +12881,7 @@ static void bench_frodokem_keygen(int type, const char* name, int keySize,
static void bench_frodokem_encap(int type, const char* name, int keySize,
FrodoKemKey* key1, FrodoKemKey* key2)
{
#ifndef WOLFSSL_FRODOKEM_NO_MAKE_KEY
int ret = 0, times, count, pending = 0;
double start;
const char**desc = bench_desc_words[lng_index];
Expand All @@ -12898,6 +12898,14 @@ static void bench_frodokem_encap(int type, const char* name, int keySize,
WC_ALLOC_VAR(ss, byte, FRODOKEM_MAX_LENSEC, HEAP_HINT);
WC_ALLOC_VAR(pub, byte, FRODOKEM_MAX_PUBLIC_KEY_SIZE, HEAP_HINT);

ret = wc_FrodoKemKey_Init(key1, type, HEAP_HINT, INVALID_DEVID);
if (ret != 0)
goto exit;

ret = wc_FrodoKemKey_MakeKey(key1, &gRng);
if (ret != 0)
goto exit;

ret = wc_FrodoKemKey_PublicKeySize(key1, &pubLen);
if (ret != 0) {
goto exit;
Expand Down Expand Up @@ -12977,6 +12985,9 @@ static void bench_frodokem_encap(int type, const char* name, int keySize,

exit:

wc_FrodoKemKey_Free(key2);
wc_FrodoKemKey_Free(key1);

WC_FREE_VAR(ct, HEAP_HINT);
WC_FREE_VAR(ss, HEAP_HINT);
WC_FREE_VAR(pub, HEAP_HINT);
Expand All @@ -12985,6 +12996,13 @@ static void bench_frodokem_encap(int type, const char* name, int keySize,
printf("error: bench_frodokem_encap() failed with code %d.\n", ret);

return;
#else
(void)type;
(void)name;
(void)keySize;
(void)key1;
(void)key2;
#endif /* !WOLFSSL_FRODOKEM_NO_MAKE_KEY */
}
#endif

Expand Down Expand Up @@ -13055,10 +13073,14 @@ void bench_frodokem(int type)
}
#endif

/* Zero the key objects so the wc_FrodoKemKey_Free calls below are safe even
* if a benchmark helper returns before initializing its key. */
/* Zero the key objects so wc_FrodoKemKey_Free calls are safe even
* if a benchmark helper cleans up before initializing its key. */
XMEMSET(key1, 0, sizeof(*key1));
XMEMSET(key2, 0, sizeof(*key2));
#ifdef WOLF_CRYPTO_CB
key1->devId = INVALID_DEVID;
key2->devId = INVALID_DEVID;
#endif

for (v = 0; v < sizeof(mods) / sizeof(mods[0]); v++) {
int mod = mods[v];
Expand All @@ -13078,9 +13100,6 @@ void bench_frodokem(int type)
#endif
}

wc_FrodoKemKey_Free(key2);
wc_FrodoKemKey_Free(key1);

WC_FREE_VAR_EX(key1, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
WC_FREE_VAR_EX(key2, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
}
Expand Down
1 change: 1 addition & 0 deletions wolfcrypt/test/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -78533,6 +78533,7 @@ static wc_test_ret_t slhdsa_init_fail_free_test(void)
#define SLHDSA_TEST_CERT_SHA2_128S
#endif
#if !defined(NO_ASN) && !defined(NO_CERTS) && \
!defined(WOLFSSL_NO_MALLOC) && \
(defined(SLHDSA_TEST_CERT_SHAKE128S) || \
defined(SLHDSA_TEST_CERT_SHA2_128S))
#define SLHDSA_TEST_CERT
Expand Down
6 changes: 4 additions & 2 deletions wolfssl/wolfcrypt/memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -331,8 +331,10 @@ WOLFSSL_LOCAL void wc_MemZero_Add(const char* name, const void* addr,
WOLFSSL_LOCAL void wc_MemZero_Check(void* addr, size_t len);
#endif

#ifndef WOLFSSL_NO_FORCE_ZERO
WOLFSSL_API void wc_ForceZero(void *mem, size_t len);
#ifdef WOLFSSL_NO_FORCE_ZERO
#define wc_ForceZero ForceZero
#else
WOLFSSL_API void wc_ForceZero(void *mem, size_t len);
#endif

#ifndef WOLFSSL_NO_CONST_CMP
Expand Down
57 changes: 44 additions & 13 deletions wolfssl/wolfcrypt/wc_compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,16 @@

#define wc_AesGcmEncrypt wc_AesGcmEncrypt_compat_shim

/* Reachable (via types.h) before memory.h's body when an application
* includes memory.h first: its include guard defers the body, so declare
* the exported zeroizer here for the inline shims below. Redeclaration
* with identical tokens is harmless. */
#ifdef WOLFSSL_NO_FORCE_ZERO
#define wc_ForceZero ForceZero
#else
WOLFSSL_API void wc_ForceZero(void *mem, size_t len);
#endif

#ifdef WOLFSSL_AESGCM_STREAM

static WC_INLINE int wc_AesGcmEncrypt_compat_shim(Aes* aes, byte* out, const byte* in, word32 sz,
Expand All @@ -84,12 +94,24 @@
return BAD_FUNC_ARG;
#endif
ret = wc_AesGcmInit(aes, NULL /* key */, 0 /* len */, iv, ivSz);
if (ret)
return ret;
ret = wc_AesGcmEncryptUpdate(aes, out, in, sz, authIn, authInSz);
if (ret)
return ret;
return wc_AesGcmEncryptFinal(aes, authTag, authTagSz);
if (ret == 0)
ret = wc_AesGcmEncryptUpdate(aes, out, in, sz, authIn, authInSz);
if (ret == 0)
ret = wc_AesGcmEncryptFinal(aes, authTag, authTagSz);
if (ret != 0) {
Comment thread
douzzer marked this conversation as resolved.
Resolved
/* Match the native one-shot's failure contract: no ciphertext and no
* tag escape a failed operation, whichever stage failed. On the
* Init/Update failure paths authTag was never written, so there this
* is contract uniformity rather than leak repair. */
if (out != NULL)
wc_ForceZero(out, sz);
Comment thread
Copilot marked this conversation as resolved.
Resolved
if (authTag != NULL)
wc_ForceZero(authTag,
authTagSz > WC_AES_BLOCK_SIZE
? WC_AES_BLOCK_SIZE
: authTagSz);
}
return ret;
}

#else /* ! WOLFSSL_AESGCM_STREAM */
Expand All @@ -109,13 +131,22 @@
return BAD_LENGTH_E;

ret = wc_AesGcmSetExtIV(aes, iv, ivSz);
if (ret != 0)
return ret;
ret = wc_AesGcmEncrypt_ex(aes, out, in, sz, scratch, ivSz, authTag,
authTagSz, authIn, authInSz);
if (ret != 0)
return ret;
return wc_AesGcmSetExtIV(aes, iv, ivSz);
if (ret == 0)
ret = wc_AesGcmEncrypt_ex(aes, out, in, sz, scratch, ivSz, authTag,
authTagSz, authIn, authInSz);
if (ret == 0)
ret = wc_AesGcmSetExtIV(aes, iv, ivSz);
if (ret != 0) {
/* Match above ISO-19790 wipe--this arm airdropped into old-FIPS. */
if (out != NULL)
wc_ForceZero(out, sz);
if (authTag != NULL)
wc_ForceZero(authTag,
authTagSz > WC_AES_BLOCK_SIZE
? WC_AES_BLOCK_SIZE
: authTagSz);
}
return ret;
}
#endif /* ! WOLFSSL_AESGCM_STREAM */
#endif /* HAVE_FIPS && HAVE_AESGCM && */
Expand Down
Loading