From e3fb77c051239a4b3a68a3177e5a7d3f4338466c Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Fri, 10 Feb 2012 17:41:32 +0100 Subject: [PATCH] Use non-pageable memory for gnome-keyring passwords * Use a ClutterTextBuffer that allocates non-pageable memory to hold passwords for gnome-keyring, ssh, gpg * Requires gcr 3.3.5 https://bugzilla.gnome.org/show_bug.cgi?id=652460 --- src/Makefile.am | 2 + src/shell-keyring-prompt.c | 17 ++- src/shell-secure-text-buffer.c | 199 +++++++++++++++++++++++++++++++++ src/shell-secure-text-buffer.h | 42 +++++++ 4 files changed, 259 insertions(+), 1 deletion(-) create mode 100644 src/shell-secure-text-buffer.c create mode 100644 src/shell-secure-text-buffer.h diff --git a/src/Makefile.am b/src/Makefile.am index 6ff7e6185..b1f74a0f6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -165,6 +165,8 @@ libgnome_shell_la_SOURCES = \ shell-polkit-authentication-agent.c \ shell-screenshot.c \ shell-screen-grabber.c \ + shell-secure-text-buffer.c \ + shell-secure-text-buffer.h \ shell-slicer.c \ shell-stack.c \ shell-tp-client.c \ diff --git a/src/shell-keyring-prompt.c b/src/shell-keyring-prompt.c index 977a48b01..e7a658844 100644 --- a/src/shell-keyring-prompt.c +++ b/src/shell-keyring-prompt.c @@ -23,6 +23,7 @@ #include "config.h" #include "shell-keyring-prompt.h" +#include "shell-secure-text-buffer.h" #define GCR_API_SUBJECT_TO_CHANGE #include @@ -617,11 +618,17 @@ void shell_keyring_prompt_set_password_actor (ShellKeyringPrompt *self, ClutterText *password_actor) { + ClutterTextBuffer *buffer; + g_return_if_fail (SHELL_IS_KEYRING_PROMPT (self)); g_return_if_fail (password_actor == NULL || CLUTTER_IS_TEXT (password_actor)); if (password_actor) { + buffer = shell_secure_text_buffer_new (); + clutter_text_set_buffer (password_actor, buffer); + g_object_unref (buffer); + g_signal_connect (password_actor, "text-changed", G_CALLBACK (on_password_changed), self); g_object_ref (password_actor); } @@ -646,11 +653,19 @@ void shell_keyring_prompt_set_confirm_actor (ShellKeyringPrompt *self, ClutterText *confirm_actor) { + ClutterTextBuffer *buffer; + g_return_if_fail (SHELL_IS_KEYRING_PROMPT (self)); g_return_if_fail (confirm_actor == NULL || CLUTTER_IS_TEXT (confirm_actor)); if (confirm_actor) - g_object_ref (confirm_actor); + { + buffer = shell_secure_text_buffer_new (); + clutter_text_set_buffer (confirm_actor, buffer); + g_object_unref (buffer); + + g_object_ref (confirm_actor); + } if (self->confirm_actor) g_object_unref (self->confirm_actor); self->confirm_actor = confirm_actor; diff --git a/src/shell-secure-text-buffer.c b/src/shell-secure-text-buffer.c new file mode 100644 index 000000000..a221c88ec --- /dev/null +++ b/src/shell-secure-text-buffer.c @@ -0,0 +1,199 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* shell-secure-text-buffer.c - secure memory clutter text buffer + + Copyright (C) 2009 Stefan Walter + Copyright (C) 2012 Red Hat Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Stef Walter +*/ + +#include "config.h" + +#include "shell-secure-text-buffer.h" + +#define GCR_API_SUBJECT_TO_CHANGE +#include + +#include + +typedef struct _ShellSecureTextBuffer ShellSecureTextBuffer; +typedef struct _ShellSecureTextBufferClass ShellSecureTextBufferClass; + +struct _ShellSecureTextBuffer { + ClutterTextBuffer parent; + gchar *text; + gsize text_size; + gsize text_bytes; + guint text_chars; +}; + +struct _ShellSecureTextBufferClass { + ClutterTextBufferClass parent_class; +}; + +/* Initial size of buffer, in bytes */ +#define MIN_SIZE 16 + +G_DEFINE_TYPE (ShellSecureTextBuffer, shell_secure_text_buffer, CLUTTER_TYPE_TEXT_BUFFER); + +static const gchar * +shell_secure_text_buffer_real_get_text (ClutterTextBuffer *buffer, + gsize *n_bytes) +{ + ShellSecureTextBuffer *self = SHELL_SECURE_TEXT_BUFFER (buffer); + if (n_bytes) + *n_bytes = self->text_bytes; + if (!self->text) + return ""; + return self->text; +} + +static guint +shell_secure_text_buffer_real_get_length (ClutterTextBuffer *buffer) +{ + ShellSecureTextBuffer *self = SHELL_SECURE_TEXT_BUFFER (buffer); + return self->text_chars; +} + +static guint +shell_secure_text_buffer_real_insert_text (ClutterTextBuffer *buffer, + guint position, + const gchar *chars, + guint n_chars) +{ + ShellSecureTextBuffer *self = SHELL_SECURE_TEXT_BUFFER (buffer); + gsize n_bytes; + gsize at; + + n_bytes = g_utf8_offset_to_pointer (chars, n_chars) - chars; + + /* Need more memory */ + if (n_bytes + self->text_bytes + 1 > self->text_size) + { + /* Calculate our new buffer size */ + while (n_bytes + self->text_bytes + 1 > self->text_size) + { + if (self->text_size == 0) + { + self->text_size = MIN_SIZE; + } + else + { + if (2 * self->text_size < CLUTTER_TEXT_BUFFER_MAX_SIZE) + { + self->text_size *= 2; + } + else + { + self->text_size = CLUTTER_TEXT_BUFFER_MAX_SIZE; + if (n_bytes > self->text_size - self->text_bytes - 1) + { + n_bytes = self->text_size - self->text_bytes - 1; + n_bytes = g_utf8_find_prev_char (chars, chars + n_bytes + 1) - chars; + n_chars = g_utf8_strlen (chars, n_bytes); + } + break; + } + } + } + self->text = gcr_secure_memory_realloc (self->text, self->text_size); + } + + /* Actual text insertion */ + at = g_utf8_offset_to_pointer (self->text, position) - self->text; + g_memmove (self->text + at + n_bytes, self->text + at, self->text_bytes - at); + memcpy (self->text + at, chars, n_bytes); + + /* Book keeping */ + self->text_bytes += n_bytes; + self->text_chars += n_chars; + self->text[self->text_bytes] = '\0'; + + clutter_text_buffer_emit_inserted_text (buffer, position, chars, n_chars); + return n_chars; +} + +static guint +shell_secure_text_buffer_real_delete_text (ClutterTextBuffer *buffer, + guint position, + guint n_chars) +{ + ShellSecureTextBuffer *self = SHELL_SECURE_TEXT_BUFFER (buffer); + gsize start, end; + + if (position > self->text_chars) + position = self->text_chars; + if (position + n_chars > self->text_chars) + n_chars = self->text_chars - position; + + if (n_chars > 0) + { + start = g_utf8_offset_to_pointer (self->text, position) - self->text; + end = g_utf8_offset_to_pointer (self->text, position + n_chars) - self->text; + + g_memmove (self->text + start, self->text + end, self->text_bytes + 1 - end); + self->text_chars -= n_chars; + self->text_bytes -= (end - start); + + clutter_text_buffer_emit_deleted_text (buffer, position, n_chars); + } + + return n_chars; +} + +static void +shell_secure_text_buffer_init (ShellSecureTextBuffer *self) +{ + +} + +static void +shell_secure_text_buffer_finalize (GObject *obj) +{ + ShellSecureTextBuffer *self = SHELL_SECURE_TEXT_BUFFER (obj); + + if (self->text) + { + gcr_secure_memory_strfree (self->text); + self->text = NULL; + self->text_bytes = self->text_size = 0; + self->text_chars = 0; + } + + G_OBJECT_CLASS (shell_secure_text_buffer_parent_class)->finalize (obj); +} + +static void +shell_secure_text_buffer_class_init (ShellSecureTextBufferClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + ClutterTextBufferClass *buffer_class = CLUTTER_TEXT_BUFFER_CLASS (klass); + + gobject_class->finalize = shell_secure_text_buffer_finalize; + + buffer_class->get_text = shell_secure_text_buffer_real_get_text; + buffer_class->get_length = shell_secure_text_buffer_real_get_length; + buffer_class->insert_text = shell_secure_text_buffer_real_insert_text; + buffer_class->delete_text = shell_secure_text_buffer_real_delete_text; +} + +ClutterTextBuffer * +shell_secure_text_buffer_new (void) +{ + return g_object_new (SHELL_TYPE_SECURE_TEXT_BUFFER, NULL); +} diff --git a/src/shell-secure-text-buffer.h b/src/shell-secure-text-buffer.h new file mode 100644 index 000000000..196b425f1 --- /dev/null +++ b/src/shell-secure-text-buffer.h @@ -0,0 +1,42 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* shell-secure-text-buffer.h - secure memory clutter text buffer + + Copyright (C) 2009 Stefan Walter + Copyright (C) 2012 Red Hat Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Stef Walter +*/ + +#ifndef __SHELL_SECURE_TEXT_BUFFER_H__ +#define __SHELL_SECURE_TEXT_BUFFER_H__ + +#include + +G_BEGIN_DECLS + +#define SHELL_TYPE_SECURE_TEXT_BUFFER (shell_secure_text_buffer_get_type ()) +#define SHELL_SECURE_TEXT_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_SECURE_TEXT_BUFFER, ShellSecureTextBuffer)) +#define SHELL_IS_SECURE_TEXT_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_TYPE_SECURE_TEXT_BUFFER)) + +GType shell_secure_text_buffer_get_type (void) G_GNUC_CONST; + +ClutterTextBuffer * shell_secure_text_buffer_new (void); + +G_END_DECLS + +#endif /* __SHELL_SECURE_TEXT_BUFFER_H__ */