[PATCH 2/2] fips: Fix self-check compiled with clang

Clemens Lang cllang at redhat.com
Fri Feb 11 16:57:23 CET 2022


* src/fips.c [ENABLE_HMAC_BINARY_CHECK] (hmac256_check): Prevent
  constant propagation of a 0 HMAC value.

--

clang 13 assumes that the static const unsigned char[32]
hmac_for_the_implementation is zero, propagates this constant into its
use in hmac256_check and replaces with invocation of memcmp(3) with
assembly instructions that compare the computed digest with 0.

clang is able to make this assumption, because a 0-initialized static
const variable should never change its value, but this assumption is
invalid as soon as objcpy(1) changes the HMAC in the binary.

Add a volatile specifier to prevent this optimization. Note that this
requires casting away the volatile keyword in some invocations where
function signature does not support it.

Signed-off-by: Clemens Lang <cllang at redhat.com>
---
 src/fips.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/src/fips.c b/src/fips.c
index 193af36b..fabc5158 100644
--- a/src/fips.c
+++ b/src/fips.c
@@ -592,7 +592,10 @@ run_random_selftests (void)
 # endif
 #define HMAC_LEN 32
 
-static const unsigned char __attribute__ ((section (".rodata1")))
+/* Compilers can and will constant-propagate this as 0 when reading if it is
+ * not declared volatile. Since this value will be changed using objcopy(1)
+ * after compilation, this can cause the HMAC verification to fail. */
+static const volatile unsigned char __attribute__ ((section (".rodata1")))
 hmac_for_the_implementation[HMAC_LEN];
 
 /**
@@ -805,10 +808,16 @@ hmac256_check (const char *filename, const char *key)
     err = gpg_error (GPG_ERR_INV_HANDLE);
   else
     {
+      unsigned char hmac[HMAC_LEN];
       unsigned char *digest;
+      size_t idx;
+
+      // memcpy(3) does not accept volatile pointers
+      for (idx = 0; idx < HMAC_LEN; idx++)
+        hmac[idx] = hmac_for_the_implementation[idx];
 
       digest = _gcry_md_read (hd, 0);
-      if (!memcmp (digest, hmac_for_the_implementation, HMAC_LEN))
+      if (!memcmp (digest, hmac, HMAC_LEN))
         /* Success.  */
         err = 0;
       else
@@ -830,7 +839,7 @@ check_binary_integrity (void)
   Dl_info info;
   const char *key = KEY_FOR_BINARY_CHECK;
 
-  if (!dladdr (hmac_for_the_implementation, &info))
+  if (!dladdr ((const char *)hmac_for_the_implementation, &info))
     err = gpg_error_from_syserror ();
   else
     err = hmac256_check (info.dli_fname, key);
-- 
2.34.1




More information about the Gcrypt-devel mailing list