diff options
author | Geoff Greer <geoff@greer.fm> | 2017-12-13 00:30:43 -0800 |
---|---|---|
committer | Geoff Greer <geoff@greer.fm> | 2017-12-14 19:53:11 -0800 |
commit | 1312db8b43bd1b688f7e62b541b6f9c616e275e7 (patch) | |
tree | 1941c8873e1ed0c4cdbf14d26ee33718992508ff /swaylock/main.c | |
parent | Merge pull request #1446 from kon14/patch-1 (diff) | |
download | sway-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.
Diffstat (limited to 'swaylock/main.c')
-rw-r--r-- | swaylock/main.c | 55 |
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 | ||
59 | char *password; | 60 | char password[1024]; |
60 | int password_size; | ||
61 | enum line_source line_source = LINE_SOURCE_DEFAULT; | 61 | enum line_source line_source = LINE_SOURCE_DEFAULT; |
62 | 62 | ||
63 | struct lock_config *init_config() { | 63 | struct 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 | /** | 130 | void 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 | |||
133 | bool verify_password() { | 139 | bool 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 | ||
152 | void notify_key(enum wl_keyboard_key_state state, xkb_keysym_t sym, uint32_t code, uint32_t codepoint) { | 158 | void 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) { |