File lightdm-use-fine-grained-memory-locking.patch of Package lightdm

# HG changeset patch
# User Michael Terry <michael.terry@canonical.com>
# Date 1359392941 18000
# Branch precise-mlock
# Node ID 5b070d44540db1caad11c998a8678aafb1a2f4a5
# Parent ce5521d07555b291eb3a9cdc56a13e634dd951a9
Use libgcrypt to selectively secure password memory instead of the big-hammer approach of mlockall

diff --git a/src/Makefile.am b/src/Makefile.am
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -95,6 +95,7 @@ lightdm_CFLAGS = \
 
 lightdm_LDADD = \
 	$(LIGHTDM_LIBS) \
+	-lgcrypt \
 	-lpam
 
 pkglibexec_PROGRAMS = lightdm-guest-session-wrapper
diff --git a/src/greeter.c b/src/greeter.c
--- a/src/greeter.c
+++ b/src/greeter.c
@@ -15,6 +15,7 @@
 #include <string.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <gcrypt.h>
 
 #include "greeter.h"
 #include "ldm-marshal.h"
@@ -40,6 +41,7 @@ struct GreeterPrivate
     /* Buffer for data read from greeter */
     guint8 *read_buffer;
     gsize n_read;
+    gboolean use_secure_memory;
   
     /* Hints for the greeter */
     GHashTable *hints;
@@ -105,6 +107,7 @@ greeter_new (Session *session, const gch
     greeter->priv->session = g_object_ref (session);
     greeter->priv->pam_service = g_strdup (pam_service);
     greeter->priv->autologin_pam_service = g_strdup (autologin_pam_service);
+    greeter->priv->use_secure_memory = config_get_boolean (config_get_instance (), "LightDM", "lock-memory");
 
     return greeter;
 }
@@ -121,6 +124,33 @@ greeter_set_hint (Greeter *greeter, cons
     g_hash_table_insert (greeter->priv->hints, g_strdup (name), g_strdup (value));
 }
 
+static void *
+secure_malloc (Greeter *greeter, size_t n)
+{
+    if (greeter->priv->use_secure_memory)
+        return gcry_malloc_secure (n);
+    else
+        return g_malloc (n);
+}
+
+static void *
+secure_realloc (Greeter *greeter, void *ptr, size_t n)
+{
+    if (greeter->priv->use_secure_memory)
+        return gcry_realloc (ptr, n);
+    else
+        return g_realloc (ptr, n);
+}
+
+static void
+secure_free (Greeter *greeter, void *ptr)
+{
+    if (greeter->priv->use_secure_memory)
+        return gcry_free (ptr);
+    else
+        return g_free (ptr);
+}
+
 static guint32
 int_length ()
 {
@@ -259,6 +289,7 @@ pam_messages_cb (Session *session, Greet
         struct pam_response *response;
         response = calloc (messages_length, sizeof (struct pam_response));
         session_respond (greeter->priv->authentication_session, response);
+        free (response);
     }
 }
 
@@ -490,12 +521,18 @@ handle_continue_authentication (Greeter 
         int msg_style = messages[i].msg_style;
         if (msg_style == PAM_PROMPT_ECHO_OFF || msg_style == PAM_PROMPT_ECHO_ON)
         {
-            response[i].resp = strdup (secrets[j]); // FIXME: Need to convert from UTF-8
+            size_t secret_length = strlen (secrets[j]) + 1;
+            response[i].resp = secure_malloc (greeter, secret_length);
+            memcpy (response[i].resp, secrets[j], secret_length); // FIXME: Need to convert from UTF-8
             j++;
         }
     }
 
     session_respond (greeter->priv->authentication_session, response);
+
+    for (i = 0; i < messages_length; i++)
+        secure_free (greeter, response[i].resp);
+    free (response);
 }
 
 static void
@@ -587,7 +624,7 @@ read_int (Greeter *greeter, gsize *offse
 }
 
 static gchar *
-read_string (Greeter *greeter, gsize *offset)
+read_string_full (Greeter *greeter, gsize *offset, void* (*alloc_fn)(size_t n))
 {
     guint32 length;
     gchar *value;
@@ -599,7 +636,7 @@ read_string (Greeter *greeter, gsize *of
         return g_strdup ("");
     }
 
-    value = g_malloc (sizeof (gchar *) * (length + 1));
+    value = (*alloc_fn) (sizeof (gchar *) * (length + 1));
     memcpy (value, greeter->priv->read_buffer + *offset, length);
     value[length] = '\0';
     *offset += length;
@@ -607,6 +644,21 @@ read_string (Greeter *greeter, gsize *of
     return value;
 }
 
+static gchar *
+read_string (Greeter *greeter, gsize *offset)
+{
+    return read_string_full (greeter, offset, g_malloc);
+}
+
+static gchar *
+read_secret (Greeter *greeter, gsize *offset)
+{
+    if (greeter->priv->use_secure_memory)
+        return read_string_full (greeter, offset, gcry_malloc_secure);
+    else
+        return read_string_full (greeter, offset, g_malloc);
+}
+
 static gboolean
 read_cb (GIOChannel *source, GIOCondition condition, gpointer data)
 {
@@ -654,7 +706,7 @@ read_cb (GIOChannel *source, GIOConditio
         n_to_read = read_int (greeter, &offset);
         if (n_to_read > 0)
         {
-            greeter->priv->read_buffer = g_realloc (greeter->priv->read_buffer, HEADER_SIZE + n_to_read);
+            greeter->priv->read_buffer = secure_realloc (greeter, greeter->priv->read_buffer, HEADER_SIZE + n_to_read);
             read_cb (source, condition, greeter);
             return TRUE;
         }
@@ -690,10 +742,12 @@ read_cb (GIOChannel *source, GIOConditio
         n_secrets = read_int (greeter, &offset);
         secrets = g_malloc (sizeof (gchar *) * (n_secrets + 1));
         for (i = 0; i < n_secrets; i++)
-            secrets[i] = read_string (greeter, &offset);
+            secrets[i] = read_secret (greeter, &offset);
         secrets[i] = NULL;
         handle_continue_authentication (greeter, secrets);
-        g_strfreev (secrets);
+        for (i = 0; i < n_secrets; i++)
+            secure_free (greeter, secrets[i]);
+        g_free (secrets);
         break;
     case GREETER_MESSAGE_CANCEL_AUTHENTICATION:
         handle_cancel_authentication (greeter);
@@ -796,7 +850,7 @@ static void
 greeter_init (Greeter *greeter)
 {
     greeter->priv = G_TYPE_INSTANCE_GET_PRIVATE (greeter, GREETER_TYPE, GreeterPrivate);
-    greeter->priv->read_buffer = g_malloc (HEADER_SIZE);
+    greeter->priv->read_buffer = secure_malloc (greeter, HEADER_SIZE);
     greeter->priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
 }
 
@@ -811,7 +865,7 @@ greeter_finalize (GObject *object)
     g_object_unref (self->priv->session);
     g_free (self->priv->pam_service);
     g_free (self->priv->autologin_pam_service);
-    g_free (self->priv->read_buffer);
+    secure_free (self, self->priv->read_buffer);
     g_hash_table_unref (self->priv->hints);
     g_free (self->priv->remote_session);
     if (self->priv->authentication_session)
diff --git a/src/lightdm.c b/src/lightdm.c
--- a/src/lightdm.c
+++ b/src/lightdm.c
@@ -19,7 +19,6 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/stat.h>
-#include <sys/mman.h>
 
 #include "configuration.h"
 #include "opensuse-sysconfig.h"
@@ -1194,12 +1193,6 @@ main (int argc, char **argv)
                              NULL,
                              NULL);
 
-    if (config_get_boolean (config_get_instance (), "LightDM", "lock-memory"))
-    {
-        /* Protect memory from being paged to disk, as we deal with passwords */
-        mlockall (MCL_CURRENT | MCL_FUTURE);
-    }
-
     if (getuid () != 0)
         g_debug ("Running in user mode");
     if (getenv ("DISPLAY"))
diff --git a/src/session-child.c b/src/session-child.c
--- a/src/session-child.c
+++ b/src/session-child.c
@@ -67,7 +67,7 @@ read_data (void *buf, size_t count)
 }
 
 static gchar *
-read_string ()
+read_string_full (void* (*alloc_fn)(size_t n))
 {
     int length;
     char *value;
@@ -82,13 +82,19 @@ read_string ()
         return NULL;
     }
   
-    value = g_malloc (sizeof (char) * (length + 1));
+    value = (*alloc_fn) (sizeof (char) * (length + 1));
     read_data (value, length);
     value[length] = '\0';      
 
     return value;
 }
 
+static gchar *
+read_string ()
+{
+    return read_string_full (g_malloc);
+}
+
 static int
 pam_conv_cb (int msg_length, const struct pam_message **msg, struct pam_response **resp, void *app_data)
 {
@@ -139,7 +145,9 @@ pam_conv_cb (int msg_length, const struc
     for (i = 0; i < msg_length; i++)
     {
         struct pam_response *r = &response[i];
-        r->resp = read_string ();
+        // callers of this function inside pam will expect to be able to call
+        // free() on the strings we give back.  So alloc with malloc.
+        r->resp = read_string_full (malloc);
         read_data (&r->resp_retcode, sizeof (r->resp_retcode));
     }
 
openSUSE Build Service is sponsored by