summaryrefslogtreecommitdiff
path: root/i3lock.c
diff options
context:
space:
mode:
authorMichael Stapelberg <michael@stapelberg.de>2012-01-03 16:17:58 +0000
committerMichael Stapelberg <michael@stapelberg.de>2012-01-03 18:06:59 +0000
commit52f96e78f26b86e4a0e6ec7d98eb454d6ff508ae (patch)
tree45d8ceba033895647ff8143a748a782386f5960b /i3lock.c
parent2dd03ce7db306e42aa938abef4d2e6227b26db59 (diff)
Lock the password buffer in memory, clear it in RAM after verifying
Diffstat (limited to 'i3lock.c')
-rw-r--r--i3lock.c30
1 files changed, 28 insertions, 2 deletions
diff --git a/i3lock.c b/i3lock.c
index d236adf..a056091 100644
--- a/i3lock.c
+++ b/i3lock.c
@@ -24,6 +24,7 @@
#include <string.h>
#include <math.h>
#include <ev.h>
+#include <sys/mman.h>
#ifndef NOLIBCAIRO
@@ -51,7 +52,7 @@ static xcb_key_symbols_t *symbols;
static xcb_screen_t *scr;
static pam_handle_t *pam_handle;
static int input_position = 0;
-/* holds the password you enter (in UTF-8) */
+/* Holds the password you enter (in UTF-8). */
static char password[512];
static bool modeswitch_active = false;
static bool iso_level3_shift_active = false;
@@ -92,6 +93,23 @@ static bool tile = false;
#endif
/*
+ * Clears the memory which stored the password to be a bit safer against
+ * cold-boot attacks.
+ *
+ */
+static void clear_password_memory() {
+ /* A volatile pointer to the password buffer to prevent the compiler from
+ * optimizing this out. */
+ volatile char *vpassword = password;
+ for (int c = 0; c < sizeof(password); c++)
+ /* We store a non-random pattern which consists of the (irrelevant)
+ * index plus (!) the value of the beep variable. This prevents the
+ * compiler from optimizing the calls away, since the value of 'beep'
+ * is not known at compile-time. */
+ vpassword[c] = c + (int)beep;
+}
+
+/*
* Draws global image with fill color onto a pixmap with the given
* resolution and returns it.
*
@@ -330,6 +348,7 @@ static void input_done() {
if (pam_authenticate(pam_handle, 0) == PAM_SUCCESS) {
printf("successfully authenticated\n");
+ clear_password_memory();
exit(0);
}
@@ -458,6 +477,7 @@ static void handle_key_press(xcb_key_press_event_t *event) {
input_done();
case XK_Escape:
input_position = 0;
+ clear_password_memory();
password[input_position] = '\0';
return;
@@ -809,7 +829,13 @@ int main(int argc, char *argv[]) {
/* Initialize PAM */
ret = pam_start("i3lock", username, &conv, &pam_handle);
if (ret != PAM_SUCCESS)
- errx(EXIT_FAILURE, "PAM: %s\n", pam_strerror(pam_handle, ret));
+ errx(EXIT_FAILURE, "PAM: %s", pam_strerror(pam_handle, ret));
+
+ /* Lock the area where we store the password in memory, we don’t want it to
+ * be swapped to disk. Since Linux 2.6.9, this does not require any
+ * privileges, just enough bytes in the RLIMIT_MEMLOCK limit. */
+ if (mlock(password, sizeof(password)) != 0)
+ err(EXIT_FAILURE, "Could not lock page in memory, check RLIMIT_MEMLOCK");
/* Initialize connection to X11 */
if ((conn = xcb_connect(NULL, &screen)) == NULL ||