diff --git a/wolfcrypt/src/misc.c b/wolfcrypt/src/misc.c index 1642f9b1ca..efc14e4926 100644 --- a/wolfcrypt/src/misc.c +++ b/wolfcrypt/src/misc.c @@ -693,10 +693,12 @@ WC_MISC_STATIC WC_INLINE void xorbuf(void* buf, const void* mask, word32 count) with zeros. It ensures compiler optimization doesn't skip it. */ WC_MISC_STATIC WC_INLINE void ForceZero(void* mem, size_t len) { - byte *zb = (byte *)mem; - unsigned long *zl; + /* Volatile pointers prevent dead-store elimination. + * WC_BARRIER() prevents compiler reordering. */ + volatile byte *zb = (volatile byte *)mem; + volatile unsigned long *zl; - XFENCE(); + WC_BARRIER(); while ((wc_ptr_t)zb & (wc_ptr_t)(sizeof(unsigned long) - 1U)) { if (len == 0) @@ -705,21 +707,21 @@ WC_MISC_STATIC WC_INLINE void ForceZero(void* mem, size_t len) --len; } - zl = (unsigned long *)zb; + zl = (volatile unsigned long *)zb; while (len >= sizeof(unsigned long)) { *zl++ = 0; len -= sizeof(unsigned long); } - zb = (byte *)zl; + zb = (volatile byte *)zl; while (len) { *zb++ = 0; --len; } - XFENCE(); + WC_BARRIER(); } #endif diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index e346fc47f4..bce5d1ebad 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -772,6 +772,9 @@ typedef struct testVector { #ifndef WC_TEST_EXPORT_SUBTESTS WOLFSSL_TEST_SUBROUTINE wc_test_ret_t macro_test(void); +#ifndef WOLFSSL_NO_FORCE_ZERO +WOLFSSL_TEST_SUBROUTINE wc_test_ret_t forcezero_test(void); +#endif WOLFSSL_TEST_SUBROUTINE wc_test_ret_t error_test(void); WOLFSSL_TEST_SUBROUTINE wc_test_ret_t base64_test(void); WOLFSSL_TEST_SUBROUTINE wc_test_ret_t base16_test(void); @@ -2409,6 +2412,13 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\ else TEST_PASS("macro test passed!\n"); +#ifndef WOLFSSL_NO_FORCE_ZERO + if ( (ret = forcezero_test()) != 0) + TEST_FAIL("forcezero test failed!\n", ret); + else + TEST_PASS("forcezero test passed!\n"); +#endif + if ( (ret = error_test()) != 0) TEST_FAIL("error test failed!\n", ret); else @@ -4097,6 +4107,46 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t macro_test(void) return ret; } +#ifndef WOLFSSL_NO_FORCE_ZERO +WOLFSSL_TEST_SUBROUTINE wc_test_ret_t forcezero_test(void) +{ + /* Test unaligned offsets and lengths. Oversized buffer prevents OOB writes. */ + byte buf[64]; + static const size_t offsets[] = { 0, 1, 2, 3, 7 }; + static const size_t lens[] = { 0, 1, 3, 7, 8, 9, 16, 31 }; + size_t oi, li; + + ForceZero(NULL, 0); + + for (oi = 0; oi < XELEM_CNT(offsets); oi++) { + for (li = 0; li < XELEM_CNT(lens); li++) { + size_t off = offsets[oi]; + size_t len = lens[li]; + size_t i; + + XMEMSET(buf, 0xA5, sizeof(buf)); + ForceZero(buf + off, len); + + for (i = 0; i < len; i++) { + if (buf[off + i] != 0x00) + return WC_TEST_RET_ENC_NC; + } + /* bytes outside [off, off+len) must be untouched */ + for (i = 0; i < off; i++) { + if (buf[i] != (byte)0xA5) + return WC_TEST_RET_ENC_NC; + } + for (i = off + len; i < sizeof(buf); i++) { + if (buf[i] != (byte)0xA5) + return WC_TEST_RET_ENC_NC; + } + } + } + + return 0; +} +#endif + WOLFSSL_TEST_SUBROUTINE wc_test_ret_t error_test(void) { const char* errStr; diff --git a/wolfcrypt/test/test.h b/wolfcrypt/test/test.h index eab78ac9ce..b4f9b38b2c 100644 --- a/wolfcrypt/test/test.h +++ b/wolfcrypt/test/test.h @@ -115,6 +115,9 @@ wc_static_assert(-(long)MIN_CODE_E < 0x7ffL); #endif extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t macro_test(void); +#ifndef WOLFSSL_NO_FORCE_ZERO +extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t forcezero_test(void); +#endif extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t error_test(void); extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t base64_test(void); extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t base16_test(void); diff --git a/wolfssl/wolfcrypt/wc_port.h b/wolfssl/wolfcrypt/wc_port.h index e84b724ae0..fd8ec4e147 100644 --- a/wolfssl/wolfcrypt/wc_port.h +++ b/wolfssl/wolfcrypt/wc_port.h @@ -1919,14 +1919,15 @@ WOLFSSL_ABI WOLFSSL_API int wolfCrypt_Cleanup(void); #endif #ifdef WOLF_C99 - /* use alternate keyword for compatibility with -std=c99 */ - #define XASM_VOLATILE(a) __asm__ volatile(a) + /* -std=c99 compat; "memory" clobber creates a compiler barrier. */ + #define XASM_VOLATILE(a) __asm__ volatile(a ::: "memory") #elif defined(__IAR_SYSTEMS_ICC__) #define XASM_VOLATILE(a) asm volatile(a) #elif defined(__KEIL__) - #define XASM_VOLATILE(a) __asm volatile(a) + #define XASM_VOLATILE(a) __asm volatile(a ::: "memory") #else - #define XASM_VOLATILE(a) __asm__ __volatile__(a) + /* "memory" clobber strengthens XFENCE() into a full compiler barrier. */ + #define XASM_VOLATILE(a) __asm__ __volatile__(a ::: "memory") #endif #ifndef WOLFSSL_NO_FENCE