Blame SOURCES/libgcrypt-1.10.0-fips-integrity.patch

e35e9c
From beb5d6df5c5785db7c32a24a5d2a351cb964bfbc Mon Sep 17 00:00:00 2001
e35e9c
From: Clemens Lang via Gcrypt-devel <gcrypt-devel@lists.gnupg.org>
e35e9c
Date: Mon, 14 Feb 2022 18:49:59 +0100
e35e9c
Subject: [PATCH] fips: Use ELF header to find hmac file offset
e35e9c
e35e9c
* src/fips.c [ENABLE_HMAC_BINARY_CHECK] (hmac256_check): Use ELF headers
e35e9c
  to locate the file offset for the HMAC in addition to information from
e35e9c
  the loader
e35e9c
e35e9c
--
e35e9c
e35e9c
The previous method of locating the offset of the .rodata1 section in
e35e9c
the ELF file on disk used information obtained from the loader. This
e35e9c
computed the address of the value in memory at runtime, but the offset
e35e9c
in the file can be different. Specifically, the old code computed
e35e9c
a value relative to ElfW(Phdr).p_vaddr, but the offset in the file is
e35e9c
relative to ElfW(Phdr).p_offset. These values can differ, so the
e35e9c
computed address at runtime must be translated into a file offset
e35e9c
relative to p_offset.
e35e9c
e35e9c
This is largely cosmetic, since the text section that should contain the
e35e9c
HMAC usually has both p_vaddr and p_offset set to 0.
e35e9c
e35e9c
Signed-off-by: Clemens Lang <cllang@redhat.com>
e35e9c
---
e35e9c
 README     |  3 ++-
e35e9c
 src/fips.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++-----
e35e9c
 2 files changed, 69 insertions(+), 7 deletions(-)
e35e9c
e35e9c
diff --git a/README b/README
e35e9c
index 3b465c1b..4d7697dd 100644
e35e9c
--- a/README
e35e9c
+++ b/README
e35e9c
@@ -157,7 +157,8 @@
e35e9c
      --enable-hmac-binary-check
e35e9c
                      Include support to check the binary at runtime
e35e9c
                      against a HMAC checksum.  This works only in FIPS
e35e9c
-                     mode and on systems providing the dladdr function.
e35e9c
+                     mode on systems providing the dladdr function and using
e35e9c
+                     the ELF binary format.
e35e9c
 
e35e9c
      --with-fips-module-version=version
e35e9c
                      Specify a string used as a module version for FIPS
e35e9c
diff --git a/src/fips.c b/src/fips.c
e35e9c
index 391b94f1..c40274d9 100644
e35e9c
--- a/src/fips.c
e35e9c
+++ b/src/fips.c
e35e9c
@@ -25,6 +25,8 @@
e35e9c
 #include <string.h>
e35e9c
 #ifdef ENABLE_HMAC_BINARY_CHECK
e35e9c
 # include <dlfcn.h>
e35e9c
+# include <elf.h>
e35e9c
+# include <limits.h>
e35e9c
 # include <link.h>
e35e9c
 #endif
e35e9c
 #ifdef HAVE_SYSLOG
e35e9c
@@ -594,6 +596,57 @@ run_random_selftests (void)
e35e9c
 static const unsigned char __attribute__ ((section (".rodata1")))
e35e9c
 hmac_for_the_implementation[HMAC_LEN];
e35e9c
 
e35e9c
+/**
e35e9c
+ * Determine the offset of the given virtual address in the ELF file opened as
e35e9c
+ * fp and return it in offset. Rewinds fp to the beginning on success.
e35e9c
+ */
e35e9c
+static gpg_error_t
e35e9c
+get_file_offset (FILE *fp, unsigned long paddr, unsigned long *offset)
e35e9c
+{
e35e9c
+  ElfW (Ehdr) ehdr;
e35e9c
+  ElfW (Phdr) phdr;
e35e9c
+  uint16_t e_phidx;
e35e9c
+
e35e9c
+  // read the ELF header
e35e9c
+  if (0 != fseek (fp, 0, SEEK_SET))
e35e9c
+    return gpg_error_from_syserror ();
e35e9c
+  if (1 != fread (&ehdr, sizeof (ehdr), 1, fp))
e35e9c
+    return gpg_error_from_syserror ();
e35e9c
+
e35e9c
+  // the section header entry size should match the size of the shdr struct
e35e9c
+  if (ehdr.e_phentsize != sizeof (phdr))
e35e9c
+    return gpg_error (GPG_ERR_INV_OBJ);
e35e9c
+  if (ehdr.e_phoff == 0)
e35e9c
+    return gpg_error (GPG_ERR_INV_OBJ);
e35e9c
+
e35e9c
+  // jump to the first program header
e35e9c
+  if (0 != fseek (fp, ehdr.e_phoff, SEEK_SET))
e35e9c
+    return gpg_error_from_syserror ();
e35e9c
+
e35e9c
+  // iterate over the program headers, compare their virtual addresses with the
e35e9c
+  // address we are looking for, and if the program header matches, calculate
e35e9c
+  // the offset of the given paddr in the file using the program header's
e35e9c
+  // p_offset field.
e35e9c
+  for (e_phidx = 0; e_phidx < ehdr.e_phnum; e_phidx++)
e35e9c
+    {
e35e9c
+      if (1 != fread (&phdr, sizeof (phdr), 1, fp))
e35e9c
+        return gpg_error_from_syserror ();
e35e9c
+      if (phdr.p_type == PT_LOAD && phdr.p_vaddr <= paddr
e35e9c
+          && phdr.p_vaddr + phdr.p_memsz > paddr)
e35e9c
+        {
e35e9c
+          // found section, compute the offset of paddr in the file
e35e9c
+          *offset = phdr.p_offset + (paddr - phdr.p_vaddr);
e35e9c
+
e35e9c
+          if (0 != fseek (fp, 0, SEEK_SET))
e35e9c
+            return gpg_error_from_syserror ();
e35e9c
+          return 0;
e35e9c
+        }
e35e9c
+    }
e35e9c
+
e35e9c
+  // section not found in the file
e35e9c
+  return gpg_error (GPG_ERR_INV_OBJ);
e35e9c
+}
e35e9c
+
e35e9c
 static gpg_error_t
e35e9c
 hmac256_check (const char *filename, const char *key, struct link_map *lm)
e35e9c
 {
e35e9c
@@ -603,6 +656,7 @@ hmac256_check (const char *filename, const char *key, struct link_map *lm)
e35e9c
   size_t buffer_size, nread;
e35e9c
   char *buffer;
e35e9c
   unsigned long paddr;
e35e9c
+  unsigned long offset = 0;
e35e9c
   unsigned long off = 0;
e35e9c
 
e35e9c
   paddr = (unsigned long)hmac_for_the_implementation - lm->l_addr;
e35e9c
@@ -611,6 +665,13 @@ hmac256_check (const char *filename, const char *key, struct link_map *lm)
e35e9c
   if (!fp)
e35e9c
     return gpg_error (GPG_ERR_INV_OBJ);
e35e9c
 
e35e9c
+  err = get_file_offset (fp, paddr, &offset);
e35e9c
+  if (err)
e35e9c
+    {
e35e9c
+      fclose (fp);
e35e9c
+      return err;
e35e9c
+    }
e35e9c
+
e35e9c
   err = _gcry_md_open (&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
e35e9c
   if (err)
e35e9c
     {
e35e9c
@@ -651,14 +712,14 @@ hmac256_check (const char *filename, const char *key, struct link_map *lm)
e35e9c
       nread = fread (buffer+HMAC_LEN, 1, buffer_size, fp);
e35e9c
       if (nread < buffer_size)
e35e9c
         {
e35e9c
-          if (off - HMAC_LEN <= paddr && paddr <= off + nread)
e35e9c
-            memset (buffer + HMAC_LEN + paddr - off, 0, HMAC_LEN);
e35e9c
+          if (off - HMAC_LEN <= offset && offset <= off + nread)
e35e9c
+            memset (buffer + HMAC_LEN + offset - off, 0, HMAC_LEN);
e35e9c
           _gcry_md_write (hd, buffer, nread+HMAC_LEN);
e35e9c
           break;
e35e9c
         }
e35e9c
 
e35e9c
-      if (off - HMAC_LEN <= paddr && paddr <= off + nread)
e35e9c
-        memset (buffer + HMAC_LEN + paddr - off, 0, HMAC_LEN);
e35e9c
+      if (off - HMAC_LEN <= offset && offset <= off + nread)
e35e9c
+        memset (buffer + HMAC_LEN + offset - off, 0, HMAC_LEN);
e35e9c
       _gcry_md_write (hd, buffer, nread);
e35e9c
       memcpy (buffer, buffer+buffer_size, HMAC_LEN);
e35e9c
       off += nread;
e35e9c
@@ -694,8 +755,8 @@ check_binary_integrity (void)
e35e9c
   const char *key = KEY_FOR_BINARY_CHECK;
e35e9c
   void *extra_info;
e35e9c
 
e35e9c
-  if (!dladdr1 (hmac_for_the_implementation,
e35e9c
-                &info, &extra_info, RTLD_DL_LINKMAP))
e35e9c
+  if (!dladdr1 (hmac_for_the_implementation, &info, &extra_info,
e35e9c
+                RTLD_DL_LINKMAP))
e35e9c
     err = gpg_error_from_syserror ();
e35e9c
   else
e35e9c
     err = hmac256_check (info.dli_fname, key, extra_info);
e35e9c
-- 
e35e9c
2.39.0
e35e9c
e35e9c
e35e9c
From 521500624b4b11538d206137205e2a511dad7072 Mon Sep 17 00:00:00 2001
e35e9c
From: NIIBE Yutaka <gniibe@fsij.org>
e35e9c
Date: Tue, 15 Feb 2022 20:38:02 +0900
e35e9c
Subject: [PATCH] fips: Fix previous commit.
e35e9c
e35e9c
--
e35e9c
e35e9c
Coding style fix.
e35e9c
e35e9c
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
e35e9c
---
e35e9c
 src/fips.c | 64 +++++++++++++++++++++++++++---------------------------
e35e9c
 1 file changed, 32 insertions(+), 32 deletions(-)
e35e9c
e35e9c
diff --git a/src/fips.c b/src/fips.c
e35e9c
index c40274d9..f16bce8b 100644
e35e9c
--- a/src/fips.c
e35e9c
+++ b/src/fips.c
e35e9c
@@ -596,54 +596,55 @@ run_random_selftests (void)
e35e9c
 static const unsigned char __attribute__ ((section (".rodata1")))
e35e9c
 hmac_for_the_implementation[HMAC_LEN];
e35e9c
 
e35e9c
-/**
e35e9c
- * Determine the offset of the given virtual address in the ELF file opened as
e35e9c
- * fp and return it in offset. Rewinds fp to the beginning on success.
e35e9c
+/*
e35e9c
+ * In the ELF file opened as FP, determine the offset of the given
e35e9c
+ * virtual address ADDR and return it in OFFSET.  Rewinds FP to the
e35e9c
+ * beginning on success.
e35e9c
  */
e35e9c
 static gpg_error_t
e35e9c
-get_file_offset (FILE *fp, unsigned long paddr, unsigned long *offset)
e35e9c
+get_file_offset (FILE *fp, unsigned long addr, unsigned long *offset)
e35e9c
 {
e35e9c
   ElfW (Ehdr) ehdr;
e35e9c
   ElfW (Phdr) phdr;
e35e9c
   uint16_t e_phidx;
e35e9c
 
e35e9c
-  // read the ELF header
e35e9c
-  if (0 != fseek (fp, 0, SEEK_SET))
e35e9c
+  /* Read the ELF header */
e35e9c
+  if (fseek (fp, 0, SEEK_SET) != 0)
e35e9c
     return gpg_error_from_syserror ();
e35e9c
-  if (1 != fread (&ehdr, sizeof (ehdr), 1, fp))
e35e9c
+  if (fread (&ehdr, sizeof (ehdr), 1, fp) != 1)
e35e9c
     return gpg_error_from_syserror ();
e35e9c
 
e35e9c
-  // the section header entry size should match the size of the shdr struct
e35e9c
+  /* The program header entry size should match the size of the phdr struct */
e35e9c
   if (ehdr.e_phentsize != sizeof (phdr))
e35e9c
     return gpg_error (GPG_ERR_INV_OBJ);
e35e9c
   if (ehdr.e_phoff == 0)
e35e9c
     return gpg_error (GPG_ERR_INV_OBJ);
e35e9c
 
e35e9c
-  // jump to the first program header
e35e9c
-  if (0 != fseek (fp, ehdr.e_phoff, SEEK_SET))
e35e9c
+  /* Jump to the first program header */
e35e9c
+  if (fseek (fp, ehdr.e_phoff, SEEK_SET) != 0)
e35e9c
     return gpg_error_from_syserror ();
e35e9c
 
e35e9c
-  // iterate over the program headers, compare their virtual addresses with the
e35e9c
-  // address we are looking for, and if the program header matches, calculate
e35e9c
-  // the offset of the given paddr in the file using the program header's
e35e9c
-  // p_offset field.
e35e9c
+  /* Iterate over the program headers, compare their virtual addresses
e35e9c
+     with the address we are looking for, and if the program header
e35e9c
+     matches, calculate the offset of the given ADDR in the file using
e35e9c
+     the program header's p_offset field.  */
e35e9c
   for (e_phidx = 0; e_phidx < ehdr.e_phnum; e_phidx++)
e35e9c
     {
e35e9c
-      if (1 != fread (&phdr, sizeof (phdr), 1, fp))
e35e9c
+      if (fread (&phdr, sizeof (phdr), 1, fp) != 1)
e35e9c
         return gpg_error_from_syserror ();
e35e9c
-      if (phdr.p_type == PT_LOAD && phdr.p_vaddr <= paddr
e35e9c
-          && phdr.p_vaddr + phdr.p_memsz > paddr)
e35e9c
+      if (phdr.p_type == PT_LOAD
e35e9c
+          && phdr.p_vaddr <= addr && addr < phdr.p_vaddr + phdr.p_memsz)
e35e9c
         {
e35e9c
-          // found section, compute the offset of paddr in the file
e35e9c
-          *offset = phdr.p_offset + (paddr - phdr.p_vaddr);
e35e9c
+          /* Found segment, compute the offset of ADDR in the file */
e35e9c
+          *offset = phdr.p_offset + (addr - phdr.p_vaddr);
e35e9c
 
e35e9c
-          if (0 != fseek (fp, 0, SEEK_SET))
e35e9c
+          if (fseek (fp, 0, SEEK_SET) != 0)
e35e9c
             return gpg_error_from_syserror ();
e35e9c
           return 0;
e35e9c
         }
e35e9c
     }
e35e9c
 
e35e9c
-  // section not found in the file
e35e9c
+  /* Segment not found in the file */
e35e9c
   return gpg_error (GPG_ERR_INV_OBJ);
e35e9c
 }
e35e9c
 
e35e9c
@@ -655,17 +656,16 @@ hmac256_check (const char *filename, const char *key, struct link_map *lm)
e35e9c
   gcry_md_hd_t hd;
e35e9c
   size_t buffer_size, nread;
e35e9c
   char *buffer;
e35e9c
-  unsigned long paddr;
e35e9c
+  unsigned long addr;
e35e9c
   unsigned long offset = 0;
e35e9c
-  unsigned long off = 0;
e35e9c
-
e35e9c
-  paddr = (unsigned long)hmac_for_the_implementation - lm->l_addr;
e35e9c
+  unsigned long pos = 0;
e35e9c
 
e35e9c
+  addr = (unsigned long)hmac_for_the_implementation - lm->l_addr;
e35e9c
   fp = fopen (filename, "rb");
e35e9c
   if (!fp)
e35e9c
     return gpg_error (GPG_ERR_INV_OBJ);
e35e9c
 
e35e9c
-  err = get_file_offset (fp, paddr, &offset);
e35e9c
+  err = get_file_offset (fp, addr, &offset);
e35e9c
   if (err)
e35e9c
     {
e35e9c
       fclose (fp);
e35e9c
@@ -698,7 +698,7 @@ hmac256_check (const char *filename, const char *key, struct link_map *lm)
e35e9c
     }
e35e9c
 
e35e9c
   nread = fread (buffer, 1, HMAC_LEN, fp);
e35e9c
-  off += nread;
e35e9c
+  pos += nread;
e35e9c
   if (nread < HMAC_LEN)
e35e9c
     {
e35e9c
       xfree (buffer);
e35e9c
@@ -712,17 +712,17 @@ hmac256_check (const char *filename, const char *key, struct link_map *lm)
e35e9c
       nread = fread (buffer+HMAC_LEN, 1, buffer_size, fp);
e35e9c
       if (nread < buffer_size)
e35e9c
         {
e35e9c
-          if (off - HMAC_LEN <= offset && offset <= off + nread)
e35e9c
-            memset (buffer + HMAC_LEN + offset - off, 0, HMAC_LEN);
e35e9c
+          if (pos - HMAC_LEN <= offset && offset <= pos + nread)
e35e9c
+            memset (buffer + HMAC_LEN + offset - pos, 0, HMAC_LEN);
e35e9c
           _gcry_md_write (hd, buffer, nread+HMAC_LEN);
e35e9c
           break;
e35e9c
         }
e35e9c
 
e35e9c
-      if (off - HMAC_LEN <= offset && offset <= off + nread)
e35e9c
-        memset (buffer + HMAC_LEN + offset - off, 0, HMAC_LEN);
e35e9c
+      if (pos - HMAC_LEN <= offset && offset <= pos + nread)
e35e9c
+        memset (buffer + HMAC_LEN + offset - pos, 0, HMAC_LEN);
e35e9c
       _gcry_md_write (hd, buffer, nread);
e35e9c
       memcpy (buffer, buffer+buffer_size, HMAC_LEN);
e35e9c
-      off += nread;
e35e9c
+      pos += nread;
e35e9c
     }
e35e9c
 
e35e9c
   if (ferror (fp))
e35e9c
-- 
e35e9c
2.39.1
e35e9c
e35e9c
e35e9c
From 9dcf9305962b90febdf2d7cc73b49feadbf6a01f Mon Sep 17 00:00:00 2001
e35e9c
From: NIIBE Yutaka <gniibe@fsij.org>
e35e9c
Date: Wed, 16 Feb 2022 14:06:02 +0900
e35e9c
Subject: [PATCH] fips: Integrity check improvement, with only loadable
e35e9c
 segments.
e35e9c
e35e9c
* configure.ac (READELF): Check the tool.
e35e9c
* src/Makefile.am (libgcrypt.so.hmac): Use genhmac.sh with hmac256.
e35e9c
* src/fips.c (get_file_offsets): Rename from get_file_offset.
e35e9c
Determine the OFFSET2 at the end of loadable segments, too.
e35e9c
Add fixup of the ELF header to exclude section information.
e35e9c
(hmac256_check): Finish scanning at the end of loadble segments.
e35e9c
* src/genhmac.sh: New.
e35e9c
e35e9c
--
e35e9c
e35e9c
This change fixes the build with ld.gold.
e35e9c
e35e9c
GnuPG-bug-id: 5835
e35e9c
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
e35e9c
---
e35e9c
 configure.ac    |  1 +
e35e9c
 src/Makefile.am |  4 +--
e35e9c
 src/fips.c      | 73 +++++++++++++++++++++++++++++--------------
e35e9c
 src/genhmac.sh  | 83 +++++++++++++++++++++++++++++++++++++++++++++++++
e35e9c
 4 files changed, 136 insertions(+), 25 deletions(-)
e35e9c
 create mode 100755 src/genhmac.sh
e35e9c
e35e9c
diff --git a/configure.ac b/configure.ac
e35e9c
index f0f1637f..ea01f5a6 100644
e35e9c
--- a/configure.ac
e35e9c
+++ b/configure.ac
e35e9c
@@ -579,6 +579,7 @@ else
e35e9c
     AC_DEFINE(ENABLE_HMAC_BINARY_CHECK,1,
e35e9c
               [Define to support an HMAC based integrity check])
e35e9c
     AC_CHECK_TOOL(OBJCOPY, [objcopy])
e35e9c
+    AC_CHECK_TOOL(READELF, [readelf])
e35e9c
     if test "$use_hmac_binary_check" != yes ; then
e35e9c
         DEF_HMAC_BINARY_CHECK=-DKEY_FOR_BINARY_CHECK="'\"$use_hmac_binary_check\"'"
e35e9c
     fi
e35e9c
diff --git a/src/Makefile.am b/src/Makefile.am
e35e9c
index 018d5761..72100671 100644
e35e9c
--- a/src/Makefile.am
e35e9c
+++ b/src/Makefile.am
e35e9c
@@ -24,7 +24,7 @@ pkgconfigdir = $(libdir)/pkgconfig
e35e9c
 pkgconfig_DATA = libgcrypt.pc
e35e9c
 
e35e9c
 EXTRA_DIST = libgcrypt-config.in libgcrypt.m4 libgcrypt.vers \
e35e9c
-             gcrypt.h.in libgcrypt.def libgcrypt.pc.in
e35e9c
+             gcrypt.h.in libgcrypt.def libgcrypt.pc.in genhmac.sh
e35e9c
 
e35e9c
 bin_SCRIPTS = libgcrypt-config
e35e9c
 m4datadir = $(datadir)/aclocal
e35e9c
@@ -149,7 +149,7 @@ libgcrypt.la.done: libgcrypt.so.hmac
e35e9c
 	@touch libgcrypt.la.done
e35e9c
 
e35e9c
 libgcrypt.so.hmac: hmac256 libgcrypt.la
e35e9c
-	./hmac256 --stdkey --binary  < .libs/libgcrypt.so > $@
e35e9c
+	READELF=$(READELF) AWK=$(AWK) $(srcdir)/genhmac.sh > $@
e35e9c
 else !USE_HMAC_BINARY_CHECK
e35e9c
 libgcrypt.la.done: libgcrypt.la
e35e9c
 	@touch libgcrypt.la.done
e35e9c
diff --git a/src/fips.c b/src/fips.c
e35e9c
index f16bce8b..134d0eae 100644
e35e9c
--- a/src/fips.c
e35e9c
+++ b/src/fips.c
e35e9c
@@ -598,50 +598,68 @@ hmac_for_the_implementation[HMAC_LEN];
e35e9c
 
e35e9c
 /*
e35e9c
  * In the ELF file opened as FP, determine the offset of the given
e35e9c
- * virtual address ADDR and return it in OFFSET.  Rewinds FP to the
e35e9c
+ * virtual address ADDR and return it in R_OFFSET1.  Determine the
e35e9c
+ * offset of last loadable section in R_OFFSET2.  Rewinds FP to the
e35e9c
  * beginning on success.
e35e9c
  */
e35e9c
 static gpg_error_t
e35e9c
-get_file_offset (FILE *fp, unsigned long addr, unsigned long *offset)
e35e9c
+get_file_offsets (FILE *fp, unsigned long addr, ElfW (Ehdr) *ehdr_p,
e35e9c
+                  unsigned long *r_offset1, unsigned long *r_offset2)
e35e9c
 {
e35e9c
-  ElfW (Ehdr) ehdr;
e35e9c
   ElfW (Phdr) phdr;
e35e9c
   uint16_t e_phidx;
e35e9c
+  long pos = 0;
e35e9c
 
e35e9c
   /* Read the ELF header */
e35e9c
   if (fseek (fp, 0, SEEK_SET) != 0)
e35e9c
     return gpg_error_from_syserror ();
e35e9c
-  if (fread (&ehdr, sizeof (ehdr), 1, fp) != 1)
e35e9c
+  if (fread (ehdr_p, sizeof (*ehdr_p), 1, fp) != 1)
e35e9c
     return gpg_error_from_syserror ();
e35e9c
 
e35e9c
+  /* Fix up the ELF header, clean all section information.  */
e35e9c
+  ehdr_p->e_shoff = 0;
e35e9c
+  ehdr_p->e_shentsize = 0;
e35e9c
+  ehdr_p->e_shnum = 0;
e35e9c
+  ehdr_p->e_shstrndx = 0;
e35e9c
+
e35e9c
   /* The program header entry size should match the size of the phdr struct */
e35e9c
-  if (ehdr.e_phentsize != sizeof (phdr))
e35e9c
+  if (ehdr_p->e_phentsize != sizeof (phdr))
e35e9c
     return gpg_error (GPG_ERR_INV_OBJ);
e35e9c
-  if (ehdr.e_phoff == 0)
e35e9c
+  if (ehdr_p->e_phoff == 0)
e35e9c
     return gpg_error (GPG_ERR_INV_OBJ);
e35e9c
 
e35e9c
   /* Jump to the first program header */
e35e9c
-  if (fseek (fp, ehdr.e_phoff, SEEK_SET) != 0)
e35e9c
+  if (fseek (fp, ehdr_p->e_phoff, SEEK_SET) != 0)
e35e9c
     return gpg_error_from_syserror ();
e35e9c
 
e35e9c
   /* Iterate over the program headers, compare their virtual addresses
e35e9c
      with the address we are looking for, and if the program header
e35e9c
      matches, calculate the offset of the given ADDR in the file using
e35e9c
      the program header's p_offset field.  */
e35e9c
-  for (e_phidx = 0; e_phidx < ehdr.e_phnum; e_phidx++)
e35e9c
+  for (e_phidx = 0; e_phidx < ehdr_p->e_phnum; e_phidx++)
e35e9c
     {
e35e9c
       if (fread (&phdr, sizeof (phdr), 1, fp) != 1)
e35e9c
         return gpg_error_from_syserror ();
e35e9c
-      if (phdr.p_type == PT_LOAD
e35e9c
-          && phdr.p_vaddr <= addr && addr < phdr.p_vaddr + phdr.p_memsz)
e35e9c
-        {
e35e9c
-          /* Found segment, compute the offset of ADDR in the file */
e35e9c
-          *offset = phdr.p_offset + (addr - phdr.p_vaddr);
e35e9c
 
e35e9c
-          if (fseek (fp, 0, SEEK_SET) != 0)
e35e9c
-            return gpg_error_from_syserror ();
e35e9c
-          return 0;
e35e9c
-        }
e35e9c
+      if (phdr.p_type == PT_PHDR)
e35e9c
+        continue;
e35e9c
+
e35e9c
+      if (phdr.p_type != PT_LOAD)
e35e9c
+        break;
e35e9c
+
e35e9c
+      pos = phdr.p_offset + phdr.p_filesz;
e35e9c
+      if (phdr.p_vaddr <= addr && addr < phdr.p_vaddr + phdr.p_memsz)
e35e9c
+        /* Found segment, compute the offset of ADDR in the file */
e35e9c
+        *r_offset1 = phdr.p_offset + (addr - phdr.p_vaddr);
e35e9c
+    }
e35e9c
+
e35e9c
+  if (*r_offset1)
e35e9c
+    {
e35e9c
+      if (fseek (fp, 0, SEEK_SET) != 0)
e35e9c
+        return gpg_error_from_syserror ();
e35e9c
+
e35e9c
+      *r_offset2 = (unsigned long)pos;
e35e9c
+      return 0;
e35e9c
     }
e35e9c
 
e35e9c
   /* Segment not found in the file */
e35e9c
@@ -657,15 +675,17 @@ hmac256_check (const char *filename, const char *key, struct link_map *lm)
e35e9c
   size_t buffer_size, nread;
e35e9c
   char *buffer;
e35e9c
   unsigned long addr;
e35e9c
-  unsigned long offset = 0;
e35e9c
+  unsigned long offset1 = 0;
e35e9c
+  unsigned long offset2 = 0;
e35e9c
   unsigned long pos = 0;
e35e9c
+  ElfW (Ehdr) ehdr;
e35e9c
 
e35e9c
   addr = (unsigned long)hmac_for_the_implementation - lm->l_addr;
e35e9c
   fp = fopen (filename, "rb");
e35e9c
   if (!fp)
e35e9c
     return gpg_error (GPG_ERR_INV_OBJ);
e35e9c
 
e35e9c
-  err = get_file_offset (fp, addr, &offset);
e35e9c
+  err = get_file_offsets (fp, addr, &ehdr, &offset1, &offset2);
e35e9c
   if (err)
e35e9c
     {
e35e9c
       fclose (fp);
e35e9c
@@ -710,16 +730,23 @@ hmac256_check (const char *filename, const char *key, struct link_map *lm)
e35e9c
   while (1)
e35e9c
     {
e35e9c
       nread = fread (buffer+HMAC_LEN, 1, buffer_size, fp);
e35e9c
+      if (pos + nread >= offset2)
e35e9c
+        nread = offset2 - pos;
e35e9c
+
e35e9c
+      /* Copy, fixed ELF header at the beginning.  */
e35e9c
+      if (pos - HMAC_LEN == 0)
e35e9c
+        memcpy (buffer, &ehdr, sizeof (ehdr));
e35e9c
+
e35e9c
       if (nread < buffer_size)
e35e9c
         {
e35e9c
-          if (pos - HMAC_LEN <= offset && offset <= pos + nread)
e35e9c
-            memset (buffer + HMAC_LEN + offset - pos, 0, HMAC_LEN);
e35e9c
+          if (pos - HMAC_LEN <= offset1 && offset1 <= pos + nread)
e35e9c
+            memset (buffer + HMAC_LEN + offset1 - pos, 0, HMAC_LEN);
e35e9c
           _gcry_md_write (hd, buffer, nread+HMAC_LEN);
e35e9c
           break;
e35e9c
         }
e35e9c
 
e35e9c
-      if (pos - HMAC_LEN <= offset && offset <= pos + nread)
e35e9c
-        memset (buffer + HMAC_LEN + offset - pos, 0, HMAC_LEN);
e35e9c
+      if (pos - HMAC_LEN <= offset1 && offset1 <= pos + nread)
e35e9c
+        memset (buffer + HMAC_LEN + offset1 - pos, 0, HMAC_LEN);
e35e9c
       _gcry_md_write (hd, buffer, nread);
e35e9c
       memcpy (buffer, buffer+buffer_size, HMAC_LEN);
e35e9c
       pos += nread;
e35e9c
diff --git a/src/genhmac.sh b/src/genhmac.sh
e35e9c
new file mode 100755
e35e9c
index 00000000..bb33b9c6
e35e9c
--- /dev/null
e35e9c
+++ b/src/genhmac.sh
e35e9c
@@ -0,0 +1,83 @@
e35e9c
+#! /bin/sh
e35e9c
+
e35e9c
+#
e35e9c
+# genhmac.sh - Build tool to generate hmac hash
e35e9c
+#
e35e9c
+# Copyright (C) 2022  g10 Code GmbH
e35e9c
+#
e35e9c
+# This file is part of libgcrypt.
e35e9c
+#
e35e9c
+# libgcrypt is free software; you can redistribute it and/or
e35e9c
+# modify it under the terms of the GNU Lesser General Public License
e35e9c
+# as published by the Free Software Foundation; either version 2.1 of
e35e9c
+# the License, or (at your option) any later version.
e35e9c
+#
e35e9c
+# libgcrypt is distributed in the hope that it will be useful, but
e35e9c
+# WITHOUT ANY WARRANTY; without even the implied warranty of
e35e9c
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
e35e9c
+# Lesser General Public License for more details.
e35e9c
+#
e35e9c
+# You should have received a copy of the GNU Lesser General Public
e35e9c
+# License along with this program; if not, see <https://www.gnu.org/licenses/>.
e35e9c
+#
e35e9c
+
e35e9c
+set -e
e35e9c
+
e35e9c
+#
e35e9c
+# Following variables should be defined to invoke this script
e35e9c
+#
e35e9c
+#   READELF
e35e9c
+#   AWK
e35e9c
+#
e35e9c
+
e35e9c
+AWK_VERSION_OUTPUT=$($AWK 'BEGIN { print PROCINFO["version"] }')
e35e9c
+if test -n "$AWK_VERSION_OUTPUT"; then
e35e9c
+    # It's GNU awk, which supports PROCINFO.
e35e9c
+    AWK_OPTION=--non-decimal-data
e35e9c
+fi
e35e9c
+
e35e9c
+FILE=.libs/libgcrypt.so
e35e9c
+
e35e9c
+#
e35e9c
+# Fixup the ELF header to clean up section information
e35e9c
+#
e35e9c
+printf '%b' '\002' > 2.bin
e35e9c
+dd ibs=1 skip=4 count=1 if=$FILE status=none > class-byte.bin
e35e9c
+if cmp class-byte.bin 2.bin; then
e35e9c
+    CLASS=64
e35e9c
+    HEADER_SIZE=64
e35e9c
+else
e35e9c
+    CLASS=32
e35e9c
+    HEADER_SIZE=52
e35e9c
+fi
e35e9c
+
e35e9c
+if test $CLASS -eq 64; then
e35e9c
+    dd ibs=1         count=40 if=$FILE     status=none
e35e9c
+    dd ibs=1         count=8  if=/dev/zero status=none
e35e9c
+    dd ibs=1 skip=48 count=10 if=$FILE     status=none
e35e9c
+    dd ibs=1         count=6  if=/dev/zero status=none
e35e9c
+else
e35e9c
+    dd ibs=1         count=32 if=$FILE     status=none
e35e9c
+    dd ibs=1         count=4  if=/dev/zero status=none
e35e9c
+    dd ibs=1 skip=36 count=10 if=$FILE     status=none
e35e9c
+    dd ibs=1         count=6  if=/dev/zero status=none
e35e9c
+fi > header-fixed.bin
e35e9c
+
e35e9c
+# Compute the end of loadable segment.
e35e9c
+#
e35e9c
+# This require computation in hexadecimal, and GNU awk needs
e35e9c
+# --non-decimal-data option
e35e9c
+#
e35e9c
+OFFSET=$($READELF --wide --program-headers $FILE | \
e35e9c
+         $AWK $AWK_OPTION "/^  LOAD/ { offset=\$2+\$5-$HEADER_SIZE }\
e35e9c
+END { print offset}")
e35e9c
+
e35e9c
+#
e35e9c
+# Feed the header fixed and loadable segments to HMAC256
e35e9c
+# to generate hmac hash of the FILE
e35e9c
+#
e35e9c
+(cat header-fixed.bin; \
e35e9c
+ dd ibs=1 skip=$HEADER_SIZE count=$OFFSET if=$FILE status=none) \
e35e9c
+ | ./hmac256 --stdkey --binary
e35e9c
+
e35e9c
+rm -f 2.bin class-byte.bin header-fixed.bin
e35e9c
-- 
e35e9c
2.39.1
e35e9c
e35e9c
e35e9c
From a340e980388243ceae6df57d101036f3f2a955be Mon Sep 17 00:00:00 2001
e35e9c
From: NIIBE Yutaka <gniibe@fsij.org>
e35e9c
Date: Wed, 16 Feb 2022 20:08:15 +0900
e35e9c
Subject: [PATCH] fips: More portable integrity check.
e35e9c
e35e9c
* src/Makefile.am (EXTRA_DIST): Change the name of the script.
e35e9c
(libgcrypt.la.done): Invoce OBJCOPY with --add-section.
e35e9c
(libgcrypt.so.hmac): Specify ECHO_N.
e35e9c
* src/fips.c (get_file_offset): Rename from get_file_offsets.
e35e9c
Find the note section and return the value in HMAC.
e35e9c
(hmac256_check): Simplify by HMAC from the note section, not loaded.
e35e9c
(check_binary_integrity): Use dladdr instead of dladdr1.
e35e9c
* src/gen-note-integrity.sh: Rename from genhmac.sh.
e35e9c
Generate ElfN_Nhdr, and then the hmac.
e35e9c
e35e9c
--
e35e9c
e35e9c
The idea of use of .note is by Daiki Ueno.
e35e9c
    https://gitlab.com/dueno/integrity-notes
e35e9c
e35e9c
Further, instead of NOTE segment loaded onto memory, use noload
e35e9c
section in the file.
e35e9c
e35e9c
Thanks to Clemens Lang for initiating this direction of improvement.
e35e9c
e35e9c
The namespace "FDO" would need to be changed.
e35e9c
e35e9c
GnuPG-bug-id: 5835
e35e9c
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
e35e9c
---
e35e9c
 src/Makefile.am                           |   8 +-
e35e9c
 src/fips.c                                | 167 +++++++++++++---------
e35e9c
 src/{genhmac.sh => gen-note-integrity.sh} |  34 ++++-
e35e9c
 3 files changed, 134 insertions(+), 75 deletions(-)
e35e9c
 rename src/{genhmac.sh => gen-note-integrity.sh} (78%)
e35e9c
e35e9c
diff --git a/src/Makefile.am b/src/Makefile.am
e35e9c
index 72100671..b8bb187a 100644
e35e9c
--- a/src/Makefile.am
e35e9c
+++ b/src/Makefile.am
e35e9c
@@ -24,7 +24,7 @@ pkgconfigdir = $(libdir)/pkgconfig
e35e9c
 pkgconfig_DATA = libgcrypt.pc
e35e9c
 
e35e9c
 EXTRA_DIST = libgcrypt-config.in libgcrypt.m4 libgcrypt.vers \
e35e9c
-             gcrypt.h.in libgcrypt.def libgcrypt.pc.in genhmac.sh
e35e9c
+             gcrypt.h.in libgcrypt.def libgcrypt.pc.in gen-note-integrity.sh
e35e9c
 
e35e9c
 bin_SCRIPTS = libgcrypt-config
e35e9c
 m4datadir = $(datadir)/aclocal
e35e9c
@@ -143,13 +143,15 @@ if USE_HMAC_BINARY_CHECK
e35e9c
 CLEANFILES += libgcrypt.so.hmac
e35e9c
 
e35e9c
 libgcrypt.la.done: libgcrypt.so.hmac
e35e9c
-	$(OBJCOPY) --update-section .rodata1=libgcrypt.so.hmac \
e35e9c
+	$(OBJCOPY) --add-section .note.fdo.integrity=libgcrypt.so.hmac \
e35e9c
+	  --set-section-flags .note.fdo.integrity=noload,readonly \
e35e9c
 	  .libs/libgcrypt.so .libs/libgcrypt.so.new
e35e9c
 	mv -f .libs/libgcrypt.so.new .libs/libgcrypt.so.*.*
e35e9c
 	@touch libgcrypt.la.done
e35e9c
 
e35e9c
 libgcrypt.so.hmac: hmac256 libgcrypt.la
e35e9c
-	READELF=$(READELF) AWK=$(AWK) $(srcdir)/genhmac.sh > $@
e35e9c
+	ECHO_N=$(ECHO_N) READELF=$(READELF) AWK=$(AWK) \
e35e9c
+	$(srcdir)/gen-note-integrity.sh > $@
e35e9c
 else !USE_HMAC_BINARY_CHECK
e35e9c
 libgcrypt.la.done: libgcrypt.la
e35e9c
 	@touch libgcrypt.la.done
e35e9c
diff --git a/src/fips.c b/src/fips.c
e35e9c
index 134d0eae..d798d577 100644
e35e9c
--- a/src/fips.c
e35e9c
+++ b/src/fips.c
e35e9c
@@ -593,22 +593,20 @@ run_random_selftests (void)
e35e9c
 # endif
e35e9c
 #define HMAC_LEN 32
e35e9c
 
e35e9c
-static const unsigned char __attribute__ ((section (".rodata1")))
e35e9c
-hmac_for_the_implementation[HMAC_LEN];
e35e9c
-
e35e9c
 /*
e35e9c
- * In the ELF file opened as FP, determine the offset of the given
e35e9c
- * virtual address ADDR and return it in R_OFFSET1.  Determine the
e35e9c
- * offset of last loadable section in R_OFFSET2.  Rewinds FP to the
e35e9c
- * beginning on success.
e35e9c
+ * In the ELF file opened as FP, fill the ELF header to the pointer
e35e9c
+ * EHDR_P, determine the offset of last loadable segment in R_OFFSET.
e35e9c
+ * Also, find the section which contains the hmac value and return it
e35e9c
+ * in HMAC.  Rewinds FP to the beginning on success.
e35e9c
  */
e35e9c
 static gpg_error_t
e35e9c
-get_file_offsets (FILE *fp, unsigned long addr, ElfW (Ehdr) *ehdr_p,
e35e9c
-                  unsigned long *r_offset1, unsigned long *r_offset2)
e35e9c
+get_file_offset (FILE *fp, ElfW (Ehdr) *ehdr_p,
e35e9c
+                 unsigned long *r_offset, unsigned char hmac[HMAC_LEN])
e35e9c
 {
e35e9c
   ElfW (Phdr) phdr;
e35e9c
-  uint16_t e_phidx;
e35e9c
-  long pos = 0;
e35e9c
+  ElfW (Shdr) shdr;
e35e9c
+  int i;
e35e9c
+  unsigned long off_segment = 0;
e35e9c
 
e35e9c
   /* Read the ELF header */
e35e9c
   if (fseek (fp, 0, SEEK_SET) != 0)
e35e9c
@@ -616,12 +614,6 @@ get_file_offsets (FILE *fp, unsigned long addr, ElfW (Ehdr) *ehdr_p,
e35e9c
   if (fread (ehdr_p, sizeof (*ehdr_p), 1, fp) != 1)
e35e9c
     return gpg_error_from_syserror ();
e35e9c
 
e35e9c
-  /* Fix up the ELF header, clean all section information.  */
e35e9c
-  ehdr_p->e_shoff = 0;
e35e9c
-  ehdr_p->e_shentsize = 0;
e35e9c
-  ehdr_p->e_shnum = 0;
e35e9c
-  ehdr_p->e_shstrndx = 0;
e35e9c
-
e35e9c
   /* The program header entry size should match the size of the phdr struct */
e35e9c
   if (ehdr_p->e_phentsize != sizeof (phdr))
e35e9c
     return gpg_error (GPG_ERR_INV_OBJ);
e35e9c
@@ -632,11 +624,9 @@ get_file_offsets (FILE *fp, unsigned long addr, ElfW (Ehdr) *ehdr_p,
e35e9c
   if (fseek (fp, ehdr_p->e_phoff, SEEK_SET) != 0)
e35e9c
     return gpg_error_from_syserror ();
e35e9c
 
e35e9c
-  /* Iterate over the program headers, compare their virtual addresses
e35e9c
-     with the address we are looking for, and if the program header
e35e9c
-     matches, calculate the offset of the given ADDR in the file using
e35e9c
-     the program header's p_offset field.  */
e35e9c
-  for (e_phidx = 0; e_phidx < ehdr_p->e_phnum; e_phidx++)
e35e9c
+  /* Iterate over the program headers, determine the last loadable
e35e9c
+     segment.  */
e35e9c
+  for (i = 0; i < ehdr_p->e_phnum; i++)
e35e9c
     {
e35e9c
       if (fread (&phdr, sizeof (phdr), 1, fp) != 1)
e35e9c
         return gpg_error_from_syserror ();
e35e9c
@@ -647,45 +637,100 @@ get_file_offsets (FILE *fp, unsigned long addr, ElfW (Ehdr) *ehdr_p,
e35e9c
       if (phdr.p_type != PT_LOAD)
e35e9c
         break;
e35e9c
 
e35e9c
-      pos = phdr.p_offset + phdr.p_filesz;
e35e9c
-      if (phdr.p_vaddr <= addr && addr < phdr.p_vaddr + phdr.p_memsz)
e35e9c
-        /* Found segment, compute the offset of ADDR in the file */
e35e9c
-        *r_offset1 = phdr.p_offset + (addr - phdr.p_vaddr);
e35e9c
+      off_segment = phdr.p_offset + phdr.p_filesz;
e35e9c
     }
e35e9c
 
e35e9c
-  if (*r_offset1)
e35e9c
+  if (!off_segment)
e35e9c
+    /* The segment not found in the file */
e35e9c
+    return gpg_error (GPG_ERR_INV_OBJ);
e35e9c
+
e35e9c
+  /* The section header entry size should match the size of the shdr struct */
e35e9c
+  if (ehdr_p->e_shentsize != sizeof (shdr))
e35e9c
+    return gpg_error (GPG_ERR_INV_OBJ);
e35e9c
+  if (ehdr_p->e_shoff == 0)
e35e9c
+    return gpg_error (GPG_ERR_INV_OBJ);
e35e9c
+
e35e9c
+  /* Jump to the first section header */
e35e9c
+  if (fseek (fp, ehdr_p->e_shoff, SEEK_SET) != 0)
e35e9c
+    return gpg_error_from_syserror ();
e35e9c
+
e35e9c
+  /* Iterate over the section headers, determine the note section,
e35e9c
+     read the hmac value.  */
e35e9c
+  for (i = 0; i < ehdr_p->e_shnum; i++)
e35e9c
     {
e35e9c
-      if (fseek (fp, 0, SEEK_SET) != 0)
e35e9c
+      long off;
e35e9c
+
e35e9c
+      if (fread (&shdr, sizeof (shdr), 1, fp) != 1)
e35e9c
         return gpg_error_from_syserror ();
e35e9c
 
e35e9c
-      *r_offset2 = (unsigned long)pos;
e35e9c
-      return 0;
e35e9c
+      off = ftell (fp);
e35e9c
+      if (shdr.sh_type == SHT_NOTE && shdr.sh_flags == 0 && shdr.sh_size == 48)
e35e9c
+        {
e35e9c
+          const char header_of_the_note[] = {
e35e9c
+            0x04, 0x00, 0x00, 0x00,
e35e9c
+            0x20, 0x00, 0x00, 0x00,
e35e9c
+            0xca, 0xfe, 0x2a, 0x8e,
e35e9c
+            'F', 'D', 'O', 0x00
e35e9c
+          };
e35e9c
+          unsigned char header[16];
e35e9c
+
e35e9c
+          /* Jump to the note section.  */
e35e9c
+          if (fseek (fp, shdr.sh_offset, SEEK_SET) != 0)
e35e9c
+            return gpg_error_from_syserror ();
e35e9c
+
e35e9c
+          if (fread (header, sizeof (header), 1, fp) != 1)
e35e9c
+            return gpg_error_from_syserror ();
e35e9c
+
e35e9c
+          if (!memcmp (header, header_of_the_note, 16))
e35e9c
+            {
e35e9c
+              /* Found.  Read the hmac value into HMAC.  */
e35e9c
+              if (fread (hmac, HMAC_LEN, 1, fp) != 1)
e35e9c
+                return gpg_error_from_syserror ();
e35e9c
+              break;
e35e9c
+            }
e35e9c
+
e35e9c
+          /* Back to the next section header.  */
e35e9c
+          if (fseek (fp, off, SEEK_SET) != 0)
e35e9c
+            return gpg_error_from_syserror ();
e35e9c
+        }
e35e9c
     }
e35e9c
 
e35e9c
-  /* Segment not found in the file */
e35e9c
-  return gpg_error (GPG_ERR_INV_OBJ);
e35e9c
+  if (i == ehdr_p->e_shnum)
e35e9c
+    /* The note section not found.  */
e35e9c
+    return gpg_error (GPG_ERR_INV_OBJ);
e35e9c
+
e35e9c
+  /* Fix up the ELF header, clean all section information.  */
e35e9c
+  ehdr_p->e_shoff = 0;
e35e9c
+  ehdr_p->e_shentsize = 0;
e35e9c
+  ehdr_p->e_shnum = 0;
e35e9c
+  ehdr_p->e_shstrndx = 0;
e35e9c
+
e35e9c
+  *r_offset = off_segment;
e35e9c
+  if (fseek (fp, 0, SEEK_SET) != 0)
e35e9c
+    return gpg_error_from_syserror ();
e35e9c
+
e35e9c
+  return 0;
e35e9c
 }
e35e9c
 
e35e9c
 static gpg_error_t
e35e9c
-hmac256_check (const char *filename, const char *key, struct link_map *lm)
e35e9c
+hmac256_check (const char *filename, const char *key)
e35e9c
 {
e35e9c
   gpg_error_t err;
e35e9c
   FILE *fp;
e35e9c
   gcry_md_hd_t hd;
e35e9c
-  size_t buffer_size, nread;
e35e9c
+  const size_t buffer_size = 32768;
e35e9c
+  size_t nread;
e35e9c
   char *buffer;
e35e9c
-  unsigned long addr;
e35e9c
-  unsigned long offset1 = 0;
e35e9c
-  unsigned long offset2 = 0;
e35e9c
+  unsigned long offset = 0;
e35e9c
   unsigned long pos = 0;
e35e9c
   ElfW (Ehdr) ehdr;
e35e9c
+  unsigned char hmac[HMAC_LEN];
e35e9c
 
e35e9c
-  addr = (unsigned long)hmac_for_the_implementation - lm->l_addr;
e35e9c
   fp = fopen (filename, "rb");
e35e9c
   if (!fp)
e35e9c
     return gpg_error (GPG_ERR_INV_OBJ);
e35e9c
 
e35e9c
-  err = get_file_offsets (fp, addr, &ehdr, &offset1, &offset2);
e35e9c
+  err = get_file_offset (fp, &ehdr, &offset, hmac);
e35e9c
   if (err)
e35e9c
     {
e35e9c
       fclose (fp);
e35e9c
@@ -707,8 +752,7 @@ hmac256_check (const char *filename, const char *key, struct link_map *lm)
e35e9c
       return err;
e35e9c
     }
e35e9c
 
e35e9c
-  buffer_size = 32768;
e35e9c
-  buffer = xtrymalloc (buffer_size + HMAC_LEN);
e35e9c
+  buffer = xtrymalloc (buffer_size);
e35e9c
   if (!buffer)
e35e9c
     {
e35e9c
       err = gpg_error_from_syserror ();
e35e9c
@@ -717,38 +761,21 @@ hmac256_check (const char *filename, const char *key, struct link_map *lm)
e35e9c
       return err;
e35e9c
     }
e35e9c
 
e35e9c
-  nread = fread (buffer, 1, HMAC_LEN, fp);
e35e9c
-  pos += nread;
e35e9c
-  if (nread < HMAC_LEN)
e35e9c
-    {
e35e9c
-      xfree (buffer);
e35e9c
-      fclose (fp);
e35e9c
-      _gcry_md_close (hd);
e35e9c
-      return gpg_error (GPG_ERR_TOO_SHORT);
e35e9c
-    }
e35e9c
-
e35e9c
   while (1)
e35e9c
     {
e35e9c
-      nread = fread (buffer+HMAC_LEN, 1, buffer_size, fp);
e35e9c
-      if (pos + nread >= offset2)
e35e9c
-        nread = offset2 - pos;
e35e9c
+      nread = fread (buffer, 1, buffer_size, fp);
e35e9c
+      if (pos + nread >= offset)
e35e9c
+        nread = offset - pos;
e35e9c
 
e35e9c
-      /* Copy, fixed ELF header at the beginning.  */
e35e9c
-      if (pos - HMAC_LEN == 0)
e35e9c
+      /* Copy the fixed ELF header at the beginning.  */
e35e9c
+      if (pos == 0)
e35e9c
         memcpy (buffer, &ehdr, sizeof (ehdr));
e35e9c
 
e35e9c
+      _gcry_md_write (hd, buffer, nread);
e35e9c
+
e35e9c
       if (nread < buffer_size)
e35e9c
-        {
e35e9c
-          if (pos - HMAC_LEN <= offset1 && offset1 <= pos + nread)
e35e9c
-            memset (buffer + HMAC_LEN + offset1 - pos, 0, HMAC_LEN);
e35e9c
-          _gcry_md_write (hd, buffer, nread+HMAC_LEN);
e35e9c
-          break;
e35e9c
-        }
e35e9c
+        break;
e35e9c
 
e35e9c
-      if (pos - HMAC_LEN <= offset1 && offset1 <= pos + nread)
e35e9c
-        memset (buffer + HMAC_LEN + offset1 - pos, 0, HMAC_LEN);
e35e9c
-      _gcry_md_write (hd, buffer, nread);
e35e9c
-      memcpy (buffer, buffer+buffer_size, HMAC_LEN);
e35e9c
       pos += nread;
e35e9c
     }
e35e9c
 
e35e9c
@@ -759,7 +786,7 @@ hmac256_check (const char *filename, const char *key, struct link_map *lm)
e35e9c
       unsigned char *digest;
e35e9c
 
e35e9c
       digest = _gcry_md_read (hd, 0);
e35e9c
-      if (!memcmp (digest, hmac_for_the_implementation, HMAC_LEN))
e35e9c
+      if (!memcmp (digest, hmac, HMAC_LEN))
e35e9c
         /* Success.  */
e35e9c
         err = 0;
e35e9c
       else
e35e9c
@@ -780,13 +807,11 @@ check_binary_integrity (void)
e35e9c
   gpg_error_t err;
e35e9c
   Dl_info info;
e35e9c
   const char *key = KEY_FOR_BINARY_CHECK;
e35e9c
-  void *extra_info;
e35e9c
 
e35e9c
-  if (!dladdr1 (hmac_for_the_implementation, &info, &extra_info,
e35e9c
-                RTLD_DL_LINKMAP))
e35e9c
+  if (!dladdr (hmac256_check, &info))
e35e9c
     err = gpg_error_from_syserror ();
e35e9c
   else
e35e9c
-    err = hmac256_check (info.dli_fname, key, extra_info);
e35e9c
+    err = hmac256_check (info.dli_fname, key);
e35e9c
 
e35e9c
   reporter ("binary", 0, NULL, err? gpg_strerror (err):NULL);
e35e9c
 #ifdef HAVE_SYSLOG
e35e9c
diff --git a/src/genhmac.sh b/src/gen-note-integrity.sh
e35e9c
similarity index 78%
e35e9c
rename from src/genhmac.sh
e35e9c
rename to src/gen-note-integrity.sh
e35e9c
index bb33b9c6..969fdca6 100755
e35e9c
--- a/src/genhmac.sh
e35e9c
+++ b/src/gen-note-integrity.sh
e35e9c
@@ -1,7 +1,7 @@
e35e9c
 #! /bin/sh
e35e9c
 
e35e9c
 #
e35e9c
-# genhmac.sh - Build tool to generate hmac hash
e35e9c
+# gen-note-integrity.sh - Build tool to generate hmac hash section
e35e9c
 #
e35e9c
 # Copyright (C) 2022  g10 Code GmbH
e35e9c
 #
e35e9c
@@ -28,8 +28,40 @@ set -e
e35e9c
 #
e35e9c
 #   READELF
e35e9c
 #   AWK
e35e9c
+#   ECHO_N
e35e9c
 #
e35e9c
 
e35e9c
+######## Emit ElfN_Nhdr for note.fdo.integrity ########
e35e9c
+
e35e9c
+NOTE_NAME="FDO"
e35e9c
+
e35e9c
+# n_namesz = 4 including NUL
e35e9c
+printf '%b' '\004'
e35e9c
+printf '%b' '\000'
e35e9c
+printf '%b' '\000'
e35e9c
+printf '%b' '\000'
e35e9c
+
e35e9c
+# n_descsz = 32
e35e9c
+printf '%b' '\040'
e35e9c
+printf '%b' '\000'
e35e9c
+printf '%b' '\000'
e35e9c
+printf '%b' '\000'
e35e9c
+
e35e9c
+# n_type: NT_FDO_INTEGRITY=0xCAFE2A8E
e35e9c
+printf '%b' '\312'
e35e9c
+printf '%b' '\376'
e35e9c
+printf '%b' '\052'
e35e9c
+printf '%b' '\216'
e35e9c
+
e35e9c
+# the name
e35e9c
+echo $ECHO_N $NOTE_NAME
e35e9c
+printf '%b' '\000'
e35e9c
+
e35e9c
+# Here comes the alignment.  As the size of name is 4, it's none.
e35e9c
+# NO PADDING HERE.
e35e9c
+
e35e9c
+######## Rest is to generate hmac hash ########
e35e9c
+
e35e9c
 AWK_VERSION_OUTPUT=$($AWK 'BEGIN { print PROCINFO["version"] }')
e35e9c
 if test -n "$AWK_VERSION_OUTPUT"; then
e35e9c
     # It's GNU awk, which supports PROCINFO.
e35e9c
-- 
e35e9c
2.39.1
e35e9c
e35e9c