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

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