Use mlock for password buffer
This commit is contained in:
parent
fad5bc2f61
commit
bdeb891378
4
comm.c
4
comm.c
@ -5,6 +5,7 @@
|
|||||||
#include "comm.h"
|
#include "comm.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "swaylock.h"
|
#include "swaylock.h"
|
||||||
|
#include "password-buffer.h"
|
||||||
|
|
||||||
static int comm[2][2] = {{-1, -1}, {-1, -1}};
|
static int comm[2][2] = {{-1, -1}, {-1, -1}};
|
||||||
|
|
||||||
@ -19,9 +20,8 @@ ssize_t read_comm_request(char **buf_ptr) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
swaylock_log(LOG_DEBUG, "received pw check request");
|
swaylock_log(LOG_DEBUG, "received pw check request");
|
||||||
char *buf = malloc(size);
|
char *buf = password_buffer_create(size);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
swaylock_log_errno(LOG_ERROR, "failed to malloc pw buffer");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
size_t offs = 0;
|
size_t offs = 0;
|
||||||
|
9
include/password-buffer.h
Normal file
9
include/password-buffer.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#ifndef _SWAY_PASSWORD_BUFFER_H
|
||||||
|
#define _SWAY_PASSWORD_BUFFER_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
char *password_buffer_create(size_t size);
|
||||||
|
void password_buffer_destroy(char *buffer, size_t size);
|
||||||
|
|
||||||
|
#endif
|
@ -67,7 +67,8 @@ struct swaylock_args {
|
|||||||
|
|
||||||
struct swaylock_password {
|
struct swaylock_password {
|
||||||
size_t len;
|
size_t len;
|
||||||
char buffer[1024];
|
size_t buffer_len;
|
||||||
|
char *buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct swaylock_state {
|
struct swaylock_state {
|
||||||
|
10
main.c
10
main.c
@ -20,6 +20,7 @@
|
|||||||
#include "comm.h"
|
#include "comm.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "loop.h"
|
#include "loop.h"
|
||||||
|
#include "password-buffer.h"
|
||||||
#include "pool-buffer.h"
|
#include "pool-buffer.h"
|
||||||
#include "seat.h"
|
#include "seat.h"
|
||||||
#include "swaylock.h"
|
#include "swaylock.h"
|
||||||
@ -1187,13 +1188,12 @@ int main(int argc, char **argv) {
|
|||||||
state.args.colors.line = state.args.colors.ring;
|
state.args.colors.line = state.args.colors.ring;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __linux__
|
state.password.len = 0;
|
||||||
// Most non-linux platforms require root to mlock()
|
state.password.buffer_len = 1024;
|
||||||
if (mlock(state.password.buffer, sizeof(state.password.buffer)) != 0) {
|
state.password.buffer = password_buffer_create(state.password.buffer_len);
|
||||||
swaylock_log(LOG_ERROR, "Unable to mlock() password memory.");
|
if (!state.password.buffer) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
wl_list_init(&state.surfaces);
|
wl_list_init(&state.surfaces);
|
||||||
state.xkb.context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
state.xkb.context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||||
|
@ -127,6 +127,7 @@ sources = [
|
|||||||
'loop.c',
|
'loop.c',
|
||||||
'main.c',
|
'main.c',
|
||||||
'password.c',
|
'password.c',
|
||||||
|
'password-buffer.c',
|
||||||
'pool-buffer.c',
|
'pool-buffer.c',
|
||||||
'render.c',
|
'render.c',
|
||||||
'seat.c',
|
'seat.c',
|
||||||
|
9
pam.c
9
pam.c
@ -7,6 +7,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "comm.h"
|
#include "comm.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "password-buffer.h"
|
||||||
#include "swaylock.h"
|
#include "swaylock.h"
|
||||||
|
|
||||||
static char *pw_buf = NULL;
|
static char *pw_buf = NULL;
|
||||||
@ -96,6 +97,9 @@ void run_pw_backend_child(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int pam_status = pam_authenticate(auth_handle, 0);
|
int pam_status = pam_authenticate(auth_handle, 0);
|
||||||
|
password_buffer_destroy(pw_buf, size);
|
||||||
|
pw_buf = NULL;
|
||||||
|
|
||||||
bool success = pam_status == PAM_SUCCESS;
|
bool success = pam_status == PAM_SUCCESS;
|
||||||
if (!success) {
|
if (!success) {
|
||||||
swaylock_log(LOG_ERROR, "pam_authenticate failed: %s",
|
swaylock_log(LOG_ERROR, "pam_authenticate failed: %s",
|
||||||
@ -103,13 +107,8 @@ void run_pw_backend_child(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!write_comm_reply(success)) {
|
if (!write_comm_reply(success)) {
|
||||||
clear_buffer(pw_buf, size);
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_buffer(pw_buf, size);
|
|
||||||
free(pw_buf);
|
|
||||||
pw_buf = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pam_setcred(auth_handle, PAM_REFRESH_CRED);
|
pam_setcred(auth_handle, PAM_REFRESH_CRED);
|
||||||
|
81
password-buffer.c
Normal file
81
password-buffer.c
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#include "password-buffer.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "swaylock.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
static bool mlock_supported = true;
|
||||||
|
static long int page_size = 0;
|
||||||
|
|
||||||
|
static long int get_page_size() {
|
||||||
|
if (!page_size) {
|
||||||
|
page_size = sysconf(_SC_PAGESIZE);
|
||||||
|
}
|
||||||
|
return page_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// password_buffer_lock expects addr to be page alligned
|
||||||
|
static bool password_buffer_lock(char *addr, size_t size) {
|
||||||
|
int retries = 5;
|
||||||
|
while (mlock(addr, size) != 0 && retries > 0) {
|
||||||
|
switch (errno) {
|
||||||
|
case EAGAIN:
|
||||||
|
retries--;
|
||||||
|
if (retries == 0) {
|
||||||
|
swaylock_log(LOG_ERROR, "mlock() supported but failed too often.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EPERM:
|
||||||
|
swaylock_log_errno(LOG_ERROR, "Unable to mlock() password memory: Unsupported!");
|
||||||
|
mlock_supported = false;
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
swaylock_log_errno(LOG_ERROR, "Unable to mlock() password memory.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// password_buffer_unlock expects addr to be page alligned
|
||||||
|
static bool password_buffer_unlock(char *addr, size_t size) {
|
||||||
|
if (mlock_supported) {
|
||||||
|
if (munlock(addr, size) != 0) {
|
||||||
|
swaylock_log_errno(LOG_ERROR, "Unable to munlock() password memory.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *password_buffer_create(size_t size) {
|
||||||
|
void *buffer;
|
||||||
|
int result = posix_memalign(&buffer, get_page_size(), size);
|
||||||
|
if (result) {
|
||||||
|
//posix_memalign doesn't set errno according to the man page
|
||||||
|
errno = result;
|
||||||
|
swaylock_log_errno(LOG_ERROR, "failed to alloc password buffer");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!password_buffer_lock(buffer, size)) {
|
||||||
|
free(buffer);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void password_buffer_destroy(char *buffer, size_t size) {
|
||||||
|
clear_buffer(buffer, size);
|
||||||
|
password_buffer_unlock(buffer, size);
|
||||||
|
free(buffer);
|
||||||
|
}
|
@ -22,7 +22,7 @@ void clear_buffer(char *buf, size_t size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void clear_password_buffer(struct swaylock_password *pw) {
|
void clear_password_buffer(struct swaylock_password *pw) {
|
||||||
clear_buffer(pw->buffer, sizeof(pw->buffer));
|
clear_buffer(pw->buffer, pw->buffer_len);
|
||||||
pw->len = 0;
|
pw->len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ static bool backspace(struct swaylock_password *pw) {
|
|||||||
|
|
||||||
static void append_ch(struct swaylock_password *pw, uint32_t codepoint) {
|
static void append_ch(struct swaylock_password *pw, uint32_t codepoint) {
|
||||||
size_t utf8_size = utf8_chsize(codepoint);
|
size_t utf8_size = utf8_chsize(codepoint);
|
||||||
if (pw->len + utf8_size + 1 >= sizeof(pw->buffer)) {
|
if (pw->len + utf8_size + 1 >= pw->buffer_len) {
|
||||||
// TODO: Display error
|
// TODO: Display error
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
11
shadow.c
11
shadow.c
@ -11,6 +11,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#include "comm.h"
|
#include "comm.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "password-buffer.h"
|
||||||
#include "swaylock.h"
|
#include "swaylock.h"
|
||||||
|
|
||||||
void initialize_pw_backend(int argc, char **argv) {
|
void initialize_pw_backend(int argc, char **argv) {
|
||||||
@ -81,23 +82,19 @@ void run_pw_backend_child(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char *c = crypt(buf, encpw);
|
char *c = crypt(buf, encpw);
|
||||||
|
password_buffer_destroy(buf, size);
|
||||||
|
buf = NULL;
|
||||||
|
|
||||||
if (c == NULL) {
|
if (c == NULL) {
|
||||||
swaylock_log_errno(LOG_ERROR, "crypt failed");
|
swaylock_log_errno(LOG_ERROR, "crypt failed");
|
||||||
clear_buffer(buf, size);
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
bool success = strcmp(c, encpw) == 0;
|
bool success = strcmp(c, encpw) == 0;
|
||||||
|
|
||||||
if (!write_comm_reply(success)) {
|
if (!write_comm_reply(success)) {
|
||||||
clear_buffer(buf, size);
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't want to keep it in memory longer than necessary,
|
|
||||||
// so clear *before* sleeping.
|
|
||||||
clear_buffer(buf, size);
|
|
||||||
free(buf);
|
|
||||||
|
|
||||||
sleep(2);
|
sleep(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user