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

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