Blame SOURCES/0001-tabrmd-options-fix-memory-leak.patch

cbf305
From ff90674fd801dd369231a20c47ebef0d08402e9e Mon Sep 17 00:00:00 2001
cbf305
From: William Roberts <william.c.roberts@intel.com>
cbf305
Date: Tue, 12 Jan 2021 14:12:48 -0600
cbf305
Subject: [PATCH 1/6] tabrmd-options: fix memory leak
cbf305
cbf305
The tabrmd_options_t structure is initialized with static char *
cbf305
strings. These strings can be replaced by g_option_context_parse().
cbf305
However, g_option_context_parse() replaces the string with allocated
cbf305
memory and thus needs a call to g_free. Either one would need to keep
cbf305
track if glib allocated the string and conditionally free it, or just
cbf305
set all the strings to glib allocated strings. This patch takes the
cbf305
approach of always allocating the option strings.
cbf305
cbf305
Fixes leaks like:
cbf305
==2677142==ERROR: LeakSanitizer: detected memory leaks
cbf305
cbf305
Direct leak of 9 byte(s) in 1 object(s) allocated from:
cbf305
    #8 0x7fbd1acd5da1 in g_option_context_parse (/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x5eda1)
cbf305
    #9 0x4cc438 in parse_opts /home/wcrobert/workspace/tpm2-abrmd/src/tabrmd-options.c:103:10
cbf305
    #10 0x4c7ffe in main /home/wcrobert/workspace/tpm2-abrmd/src/tabrmd.c:41:10
cbf305
    #11 0x7fbd1a8770b2 in __libc_start_main /build/glibc-ZN95T4/glibc-2.31/csu/../csu/libc-start.c:308:16
cbf305
    #12 0x42004d in _start (/home/wcrobert/workspace/tpm2-abrmd/src/tpm2-abrmd+0x42004d)
cbf305
cbf305
Signed-off-by: William Roberts <william.c.roberts@intel.com>
cbf305
---
cbf305
 src/tabrmd-init.c    |  2 ++
cbf305
 src/tabrmd-options.c | 53 +++++++++++++++++++++++++++++++++++++++-----
cbf305
 src/tabrmd-options.h | 11 +++++----
cbf305
 src/tabrmd.c         |  4 +++-
cbf305
 4 files changed, 59 insertions(+), 11 deletions(-)
cbf305
cbf305
diff --git a/src/tabrmd-init.c b/src/tabrmd-init.c
cbf305
index 2ad7539..58e0103 100644
cbf305
--- a/src/tabrmd-init.c
cbf305
+++ b/src/tabrmd-init.c
cbf305
@@ -99,6 +99,8 @@ gmain_data_cleanup (gmain_data_t *data)
cbf305
     if (data->loop != NULL) {
cbf305
         main_loop_quit (data->loop);
cbf305
     }
cbf305
+
cbf305
+    tabrmd_options_free(&data->options);
cbf305
 }
cbf305
 /*
cbf305
  * This function initializes and configures all of the long-lived objects
cbf305
diff --git a/src/tabrmd-options.c b/src/tabrmd-options.c
cbf305
index 0dd7b87..22f249c 100644
cbf305
--- a/src/tabrmd-options.c
cbf305
+++ b/src/tabrmd-options.c
cbf305
@@ -16,6 +16,12 @@
cbf305
 #define G_OPTION_FLAG_NONE 0
cbf305
 #endif
cbf305
 
cbf305
+#define SET_STR_IF_NULL(var, value) \
cbf305
+    do { \
cbf305
+        var = var == NULL ? g_strdup(value) : var; \
cbf305
+        g_assert(var); \
cbf305
+    } while(0)
cbf305
+
cbf305
 /*
cbf305
  * This is a GOptionArgFunc callback invoked from the GOption processor from
cbf305
  * the parse_opts function below. It will be called when the daemon is
cbf305
@@ -36,6 +42,22 @@ show_version (const gchar  *option_name,
cbf305
     g_print ("tpm2-abrmd version %s\n", VERSION);
cbf305
     exit (0);
cbf305
 }
cbf305
+
cbf305
+/**
cbf305
+ * Frees internal memory associated with a tabrmd_options_t struct.
cbf305
+ * @param opts
cbf305
+ *  The options to free, note it doesn't free opts itself.
cbf305
+ */
cbf305
+void
cbf305
+tabrmd_options_free(tabrmd_options_t *opts)
cbf305
+{
cbf305
+    g_assert(opts);
cbf305
+
cbf305
+    g_clear_pointer(&opts->dbus_name, g_free);
cbf305
+    g_clear_pointer(&opts->prng_seed_file, g_free);
cbf305
+    g_clear_pointer(&opts->tcti_conf, g_free);
cbf305
+}
cbf305
+
cbf305
 /**
cbf305
  * This function parses the parameter argument vector and populates the
cbf305
  * parameter 'options' structure with data needed to configure the tabrmd.
cbf305
@@ -51,7 +73,7 @@ parse_opts (gint argc,
cbf305
             gchar *argv[],
cbf305
             tabrmd_options_t *options)
cbf305
 {
cbf305
-    gchar *logger_name = "stdout";
cbf305
+    gchar *logger_name = NULL;
cbf305
     GOptionContext *ctx;
cbf305
     GError *err = NULL;
cbf305
     gboolean session_bus = FALSE;
cbf305
@@ -105,33 +127,52 @@ parse_opts (gint argc,
cbf305
         return FALSE;
cbf305
     }
cbf305
     g_option_context_free (ctx);
cbf305
+
cbf305
+    /*
cbf305
+     * Set unset STRING options to defaults, we do this so we can free allocated
cbf305
+     * string options with gfree, having a mix of const and allocated ptr's
cbf305
+     * causes leaks
cbf305
+     */
cbf305
+    SET_STR_IF_NULL(options->dbus_name, TABRMD_DBUS_NAME_DEFAULT);
cbf305
+    SET_STR_IF_NULL(options->prng_seed_file, TABRMD_ENTROPY_SRC_DEFAULT);
cbf305
+    SET_STR_IF_NULL(options->tcti_conf, TABRMD_TCTI_CONF_DEFAULT);
cbf305
+    SET_STR_IF_NULL(logger_name, "stdout");
cbf305
+
cbf305
     /* select the bus type, default to G_BUS_TYPE_SESSION */
cbf305
     options->bus = session_bus ? G_BUS_TYPE_SESSION : G_BUS_TYPE_SYSTEM;
cbf305
-    if (set_logger (logger_name) == -1) {
cbf305
+    gint ret = set_logger (logger_name);
cbf305
+    if (ret == -1) {
cbf305
         g_critical ("Unknown logger: %s, try --help\n", logger_name);
cbf305
-        return FALSE;
cbf305
+        g_free(logger_name);
cbf305
+        goto error;
cbf305
     }
cbf305
+    g_free(logger_name);
cbf305
+
cbf305
     if (options->max_connections < 1 ||
cbf305
         options->max_connections > TABRMD_CONNECTION_MAX)
cbf305
     {
cbf305
         g_critical ("maximum number of connections must be between 1 "
cbf305
                     "and %d", TABRMD_CONNECTION_MAX);
cbf305
-        return FALSE;
cbf305
+        goto error;
cbf305
     }
cbf305
     if (options->max_sessions < 1 ||
cbf305
         options->max_sessions > TABRMD_SESSIONS_MAX_DEFAULT)
cbf305
     {
cbf305
         g_critical ("max-sessions must be between 1 and %d",
cbf305
                     TABRMD_SESSIONS_MAX_DEFAULT);
cbf305
-        return FALSE;
cbf305
+        goto error;
cbf305
     }
cbf305
     if (options->max_transients < 1 ||
cbf305
         options->max_transients > TABRMD_TRANSIENT_MAX)
cbf305
     {
cbf305
         g_critical ("max-trans-obj parameter must be between 1 and %d",
cbf305
                     TABRMD_TRANSIENT_MAX);
cbf305
-        return FALSE;
cbf305
+        goto error;
cbf305
     }
cbf305
     g_warning ("tcti_conf after: \"%s\"", options->tcti_conf);
cbf305
     return TRUE;
cbf305
+
cbf305
+error:
cbf305
+    tabrmd_options_free(options);
cbf305
+    return FALSE;
cbf305
 }
cbf305
diff --git a/src/tabrmd-options.h b/src/tabrmd-options.h
cbf305
index 4994920..d6bcfe9 100644
cbf305
--- a/src/tabrmd-options.h
cbf305
+++ b/src/tabrmd-options.h
cbf305
@@ -15,10 +15,10 @@
cbf305
     .max_connections = TABRMD_CONNECTIONS_MAX_DEFAULT, \
cbf305
     .max_transients = TABRMD_TRANSIENT_MAX_DEFAULT, \
cbf305
     .max_sessions = TABRMD_SESSIONS_MAX_DEFAULT, \
cbf305
-    .dbus_name = TABRMD_DBUS_NAME_DEFAULT, \
cbf305
-    .prng_seed_file = TABRMD_ENTROPY_SRC_DEFAULT, \
cbf305
+    .dbus_name = NULL, \
cbf305
+    .prng_seed_file = NULL, \
cbf305
     .allow_root = FALSE, \
cbf305
-    .tcti_conf = TABRMD_TCTI_CONF_DEFAULT, \
cbf305
+    .tcti_conf = NULL, \
cbf305
 }
cbf305
 
cbf305
 typedef struct tabrmd_options {
cbf305
@@ -28,7 +28,7 @@ typedef struct tabrmd_options {
cbf305
     guint           max_transients;
cbf305
     guint           max_sessions;
cbf305
     gchar          *dbus_name;
cbf305
-    const gchar    *prng_seed_file;
cbf305
+    gchar          *prng_seed_file;
cbf305
     gboolean        allow_root;
cbf305
     gchar          *tcti_conf;
cbf305
 } tabrmd_options_t;
cbf305
@@ -38,4 +38,7 @@ parse_opts (gint argc,
cbf305
             gchar *argv[],
cbf305
             tabrmd_options_t *options);
cbf305
 
cbf305
+void
cbf305
+tabrmd_options_free(tabrmd_options_t *opts);
cbf305
+
cbf305
 #endif /* TABRMD_OPTIONS_H */
cbf305
diff --git a/src/tabrmd.c b/src/tabrmd.c
cbf305
index 7c93e90..e015de3 100644
cbf305
--- a/src/tabrmd.c
cbf305
+++ b/src/tabrmd.c
cbf305
@@ -43,7 +43,8 @@ main (int argc, char *argv[])
cbf305
     }
cbf305
     if (geteuid() == 0 && ! gmain_data.options.allow_root) {
cbf305
         g_print ("Refusing to run as root. Pass --allow-root if you know what you are doing.\n");
cbf305
-        return 1;
cbf305
+        ret = 1;
cbf305
+        goto out;
cbf305
     }
cbf305
 
cbf305
     g_mutex_init (&gmain_data.init_mutex);
cbf305
@@ -63,6 +64,7 @@ main (int argc, char *argv[])
cbf305
     if (ret == 0 && gmain_data.ipc_disconnected) {
cbf305
         ret = EX_IOERR;
cbf305
     }
cbf305
+out:
cbf305
     gmain_data_cleanup (&gmain_data);
cbf305
     return ret;
cbf305
 }
cbf305
-- 
cbf305
2.34.3
cbf305