summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Geoff Greer <geoff@greer.fm>2017-12-13 00:30:43 -0800
committerLibravatar Geoff Greer <geoff@greer.fm>2017-12-14 19:53:11 -0800
commit1312db8b43bd1b688f7e62b541b6f9c616e275e7 (patch)
tree1941c8873e1ed0c4cdbf14d26ee33718992508ff
parentMerge pull request #1446 from kon14/patch-1 (diff)
downloadsway-1312db8b43bd1b688f7e62b541b6f9c616e275e7.tar.gz
sway-1312db8b43bd1b688f7e62b541b6f9c616e275e7.tar.zst
sway-1312db8b43bd1b688f7e62b541b6f9c616e275e7.zip
Swaylock: Clear password buffer after use.
After a user enters or clears a password, try to overwrite the buffer containing it. That way it's not sitting around in RAM for something else to read later. Also, mlock() the password buffer so that it is never swapped out. This also replaces the dynamically allocated buffer with a static char[1024]. Any characters past that are discarded until the user hits enter or escape.
-rw-r--r--swaylock/main.c55
1 files changed, 25 insertions, 30 deletions
diff --git a/swaylock/main.c b/swaylock/main.c
index c2615951..f1c75e22 100644
--- a/swaylock/main.c
+++ b/swaylock/main.c
@@ -7,6 +7,7 @@
7#include <stdio.h> 7#include <stdio.h>
8#include <stdlib.h> 8#include <stdlib.h>
9#include <string.h> 9#include <string.h>
10#include <sys/mman.h>
10#include <sys/types.h> 11#include <sys/types.h>
11#include <pwd.h> 12#include <pwd.h>
12#include <getopt.h> 13#include <getopt.h>
@@ -56,8 +57,7 @@ void sway_terminate(int exit_code) {
56 exit(exit_code); 57 exit(exit_code);
57} 58}
58 59
59char *password; 60char password[1024];
60int password_size;
61enum line_source line_source = LINE_SOURCE_DEFAULT; 61enum line_source line_source = LINE_SOURCE_DEFAULT;
62 62
63struct lock_config *init_config() { 63struct lock_config *init_config() {
@@ -115,7 +115,7 @@ int function_conversation(int num_msg, const struct pam_message **msg,
115 switch (msg[i]->msg_style) { 115 switch (msg[i]->msg_style) {
116 case PAM_PROMPT_ECHO_OFF: 116 case PAM_PROMPT_ECHO_OFF:
117 case PAM_PROMPT_ECHO_ON: 117 case PAM_PROMPT_ECHO_ON:
118 pam_reply[i].resp = password; 118 pam_reply[i].resp = strdup(password); // PAM clears and frees this
119 break; 119 break;
120 120
121 case PAM_ERROR_MSG: 121 case PAM_ERROR_MSG:
@@ -127,9 +127,15 @@ int function_conversation(int num_msg, const struct pam_message **msg,
127 return PAM_SUCCESS; 127 return PAM_SUCCESS;
128} 128}
129 129
130/** 130void clear_password_buffer() {
131 * Note: PAM will free() 'password' during the process 131 // Use volatile keyword so so compiler can't optimize this out.
132 */ 132 volatile char *pw = password;
133 volatile char zero = '\0';
134 for (size_t i = 0; i < sizeof(password); ++i) {
135 pw[i] = zero;
136 }
137}
138
133bool verify_password() { 139bool verify_password() {
134 struct passwd *passwd = getpwuid(getuid()); 140 struct passwd *passwd = getpwuid(getuid());
135 char *username = passwd->pw_name; 141 char *username = passwd->pw_name;
@@ -151,8 +157,7 @@ bool verify_password() {
151 157
152void notify_key(enum wl_keyboard_key_state state, xkb_keysym_t sym, uint32_t code, uint32_t codepoint) { 158void notify_key(enum wl_keyboard_key_state state, xkb_keysym_t sym, uint32_t code, uint32_t codepoint) {
153 int redraw_screen = 0; 159 int redraw_screen = 0;
154 char *password_realloc; 160 size_t i;
155 int i;
156 161
157 if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { 162 if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
158 switch (sym) { 163 switch (sym) {
@@ -165,14 +170,14 @@ void notify_key(enum wl_keyboard_key_state state, xkb_keysym_t sym, uint32_t cod
165 wl_dispatch_events(); 170 wl_dispatch_events();
166 171
167 if (verify_password()) { 172 if (verify_password()) {
173 clear_password_buffer();
168 exit(0); 174 exit(0);
169 } 175 }
170 176
171 render_data.auth_state = AUTH_STATE_INVALID; 177 render_data.auth_state = AUTH_STATE_INVALID;
172 redraw_screen = 1; 178 redraw_screen = 1;
173 179
174 password_size = 1024; 180 clear_password_buffer();
175 password = malloc(password_size);
176 password[0] = '\0'; 181 password[0] = '\0';
177 break; 182 break;
178 case XKB_KEY_BackSpace: 183 case XKB_KEY_BackSpace:
@@ -207,9 +212,7 @@ void notify_key(enum wl_keyboard_key_state state, xkb_keysym_t sym, uint32_t cod
207 render_data.auth_state = AUTH_STATE_BACKSPACE; 212 render_data.auth_state = AUTH_STATE_BACKSPACE;
208 redraw_screen = 1; 213 redraw_screen = 1;
209 214
210 password_size = 1024; 215 clear_password_buffer();
211 free(password);
212 password = malloc(password_size);
213 password[0] = '\0'; 216 password[0] = '\0';
214 break; 217 break;
215 } 218 }
@@ -218,22 +221,10 @@ void notify_key(enum wl_keyboard_key_state state, xkb_keysym_t sym, uint32_t cod
218 render_data.auth_state = AUTH_STATE_INPUT; 221 render_data.auth_state = AUTH_STATE_INPUT;
219 redraw_screen = 1; 222 redraw_screen = 1;
220 i = strlen(password); 223 i = strlen(password);
221 if (i + 1 == password_size) { 224 if (i + 1 < sizeof(password)) {
222 password_size += 1024; 225 password[i] = (char)codepoint;
223 password_realloc = realloc(password, password_size); 226 password[i + 1] = '\0';
224 // reset password if realloc fails.
225 if (password_realloc == NULL) {
226 password_size = 1024;
227 free(password);
228 password = malloc(password_size);
229 password[0] = '\0';
230 break;
231 } else {
232 password = password_realloc;
233 }
234 } 227 }
235 password[i] = (char)codepoint;
236 password[i + 1] = '\0';
237 break; 228 break;
238 } 229 }
239 if (redraw_screen) { 230 if (redraw_screen) {
@@ -535,8 +526,12 @@ int main(int argc, char **argv) {
535 sway_abort("Unsupported scaling mode: %s", scaling_mode_str); 526 sway_abort("Unsupported scaling mode: %s", scaling_mode_str);
536 } 527 }
537 528
538 password_size = 1024; 529#ifdef __linux__
539 password = malloc(password_size); 530 // Most non-linux platforms require root to mlock()
531 if (mlock(password, sizeof(password)) != 0) {
532 sway_abort("Unable to mlock() password memory.");
533 }
534#endif
540 password[0] = '\0'; 535 password[0] = '\0';
541 render_data.surfaces = create_list(); 536 render_data.surfaces = create_list();
542 if (!socket_path) { 537 if (!socket_path) {