[glib/mcatanzaro/gnutls-hmac: 1/2] dlopen GnuTLS instead of linking directly




commit fff10630e7d4751448945a52f1794000f86aed21
Author: Michael Catanzaro <mcatanzaro redhat com>
Date:   Wed Jun 16 20:35:00 2021 -0500

    dlopen GnuTLS instead of linking directly
    
    I'd like to enable our GnuTLS GHmac patchset in Fedora in order to
    ensure it is receiving sufficient real-world testing, since we've
    discovered several bugs thus far. Problem is Fedora has one requirement
    that RHEL does not: it needs to build glib as a static lib. This is
    needed by QEMU in Fedora for complicated technical reasons that I don't
    understand. However, nothing in RHEL needs it. This means we failed to
    notice that glib2-static is broken in RHEL, because there is no
    gnutls-static! We could fix this by adding a gnutls-static package, but
    that seems like overkill, and adding more static libraries where they're
    not truly necessary is not the direction we want to move in anyway. So
    instead, let's just dlopen GnuTLS to sidestep this problem entirely.
    
    This would not be a good solution for upstream, but upstream has made
    clear that this patchset is already non-upstreamable, so it will be fine
    for our purposes.

 glib/ghmac-gnutls.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 glib/ghmac.c        |   2 +-
 glib/meson.build    |   2 +-
 meson.build         |   6 ++--
 4 files changed, 102 insertions(+), 9 deletions(-)
---
diff --git a/glib/ghmac-gnutls.c b/glib/ghmac-gnutls.c
index 9fb775f89..1800fc2e0 100644
--- a/glib/ghmac-gnutls.c
+++ b/glib/ghmac-gnutls.c
@@ -19,8 +19,8 @@
 
 #include "config.h"
 
+#include <dlfcn.h>
 #include <string.h>
-#include <gnutls/crypto.h>
 
 #include "ghmac.h"
 
@@ -31,13 +31,16 @@
 #include "gstrfuncs.h"
 #include "gchecksumprivate.h"
 #include "gtestutils.h"
+#include "gthread.h"
 #include "gtypes.h"
 #include "glibintl.h"
 
-#ifndef HAVE_GNUTLS
+#ifndef USE_GNUTLS
 #error "build configuration error"
 #endif
 
+typedef gpointer gnutls_hmac_hd_t;
+
 struct _GHmac
 {
   int ref_count;
@@ -46,15 +49,107 @@ struct _GHmac
   gchar *digest_str;
 };
 
+typedef enum
+{
+  GNUTLS_MAC_MD5 = 2,
+  GNUTLS_MAC_SHA1 = 3,
+  GNUTLS_MAC_SHA256 = 6,
+  GNUTLS_MAC_SHA384 = 7,
+  GNUTLS_MAC_SHA512 = 8,
+} gnutls_mac_algorithm_t;
+
+/* Why are we dlopening GnuTLS instead of linking to it directly? Because we
+ * want to be able to build GLib as a static library without depending on a
+ * static build of GnuTLS. QEMU depends on static linking with GLib, but Fedora
+ * does not ship a static build of GnuTLS, and this allows us to avoid changing
+ * that.
+ */
+static int              (*gnutls_hmac_init)   (gnutls_hmac_hd_t *dig, gnutls_mac_algorithm_t algorithm, 
const void *key, size_t keylen);
+static gnutls_hmac_hd_t (*gnutls_hmac_copy)   (gnutls_hmac_hd_t handle);
+static void             (*gnutls_hmac_deinit) (gnutls_hmac_hd_t handle, void *digest);
+static int              (*gnutls_hmac)        (gnutls_hmac_hd_t handle, const void *ptext, size_t ptext_len);
+static void             (*gnutls_hmac_output) (gnutls_hmac_hd_t handle, void *digest);
+static const char *     (*gnutls_strerror)    (int error);
+
+static gsize gnutls_initialize_attempted = 0;
+static gboolean gnutls_initialize_successful = FALSE;
+
+static void
+initialize_gnutls (void)
+{
+  gpointer libgnutls;
+
+  libgnutls = dlopen ("libgnutls.so.30", RTLD_LAZY | RTLD_GLOBAL);
+  if (!libgnutls)
+    {
+      g_warning ("Cannot use GHmac: failed to load libgnutls.so.30: %s", dlerror ());
+      return;
+    }
+
+  gnutls_hmac_init = dlsym (libgnutls, "gnutls_hmac_init");
+  if (!gnutls_hmac_init)
+    {
+      g_warning ("Cannot use GHmac: failed to load gnutls_hmac_init: %s", dlerror ());
+      return;
+    }
+
+  gnutls_hmac_copy = dlsym (libgnutls, "gnutls_hmac_copy");
+  if (!gnutls_hmac_copy)
+    {
+      g_warning ("Cannot use GHmac: failed to load gnutls_hmac_copy: %s", dlerror ());
+      return;
+    }
+
+  gnutls_hmac_deinit = dlsym (libgnutls, "gnutls_hmac_deinit");
+  if (!gnutls_hmac_deinit)
+    {
+      g_warning ("Cannot use GHmac: failed to load gnutls_hmac_deinit: %s", dlerror ());
+      return;
+    }
+
+  gnutls_hmac = dlsym (libgnutls, "gnutls_hmac");
+  if (!gnutls_hmac)
+    {
+      g_warning ("Cannot use GHmac: failed to load gnutls_hmac: %s", dlerror ());
+      return;
+    }
+
+  gnutls_hmac_output = dlsym (libgnutls, "gnutls_hmac_output");
+  if (!gnutls_hmac_output)
+    {
+      g_warning ("Cannot use GHmac: failed to load gnutls_hmac_output: %s", dlerror ());
+      return;
+    }
+
+  gnutls_strerror = dlsym (libgnutls, "gnutls_strerror");
+  if (!gnutls_strerror)
+    {
+      g_warning ("Cannot use GHmac: failed to load gnutls_strerror: %s", dlerror ());
+      return;
+    }
+
+  gnutls_initialize_successful = TRUE;
+}
+
 GHmac *
 g_hmac_new (GChecksumType  digest_type,
             const guchar  *key,
             gsize          key_len)
 {
   gnutls_mac_algorithm_t algo;
-  GHmac *hmac = g_new0 (GHmac, 1);
+  GHmac *hmac;
   int ret;
 
+  if (g_once_init_enter (&gnutls_initialize_attempted))
+    {
+      initialize_gnutls ();
+      g_once_init_leave (&gnutls_initialize_attempted, 1);
+    }
+
+  if (!gnutls_initialize_successful)
+    return NULL;
+
+  hmac = g_new0 (GHmac, 1);
   hmac->ref_count = 1;
   hmac->digest_type = digest_type;
 
diff --git a/glib/ghmac.c b/glib/ghmac.c
index 0e39ea40a..2d9be91b8 100644
--- a/glib/ghmac.c
+++ b/glib/ghmac.c
@@ -33,7 +33,7 @@
 #include "gtypes.h"
 #include "glibintl.h"
 
-#ifdef HAVE_GNUTLS
+#ifdef USE_GNUTLS
 #error "build configuration error"
 #endif
 
diff --git a/glib/meson.build b/glib/meson.build
index 1f6bb35d1..f4041e50c 100644
--- a/glib/meson.build
+++ b/glib/meson.build
@@ -374,7 +374,7 @@ libglib = library('glib-2.0',
   # intl.lib is not compatible with SAFESEH
   link_args : [noseh_link_args, glib_link_flags, win32_ldflags],
   include_directories : configinc,
-  dependencies : [pcre, thread_dep, librt] + libgnutls_dep + libintl_deps + libiconv + platform_deps + 
[gnulib_libm_dependency, libm] + [libsysprof_capture_dep],
+  dependencies : [pcre, thread_dep, librt] + libintl_deps + libiconv + platform_deps + 
[gnulib_libm_dependency, libm] + [libsysprof_capture_dep] + [libdl_dep],
   c_args : glib_c_args,
   objc_args : glib_c_args,
 )
diff --git a/meson.build b/meson.build
index 98f8925a2..bbe26e4e4 100644
--- a/meson.build
+++ b/meson.build
@@ -2095,11 +2095,9 @@ if host_system == 'linux'
   glib_conf.set('HAVE_LIBMOUNT', libmount_dep.found())
 endif
 
-# gnutls is used optionally by ghmac
-libgnutls_dep = []
+# gnutls is used optionally by GHmac
 if get_option('gnutls')
-  libgnutls_dep = [dependency('gnutls', version : '>=3.6.9', required : true)]
-  glib_conf.set('HAVE_GNUTLS', 1)
+  glib_conf.set('USE_GNUTLS', 1)
 endif
 
 if host_system == 'windows'


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]