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 "log.h"
|
||||
#include "swaylock.h"
|
||||
#include "password-buffer.h"
|
||||
|
||||
static int comm[2][2] = {{-1, -1}, {-1, -1}};
|
||||
|
||||
@ -19,9 +20,8 @@ ssize_t read_comm_request(char **buf_ptr) {
|
||||
return -1;
|
||||
}
|
||||
swaylock_log(LOG_DEBUG, "received pw check request");
|
||||
char *buf = malloc(size);
|
||||
char *buf = password_buffer_create(size);
|
||||
if (!buf) {
|
||||
swaylock_log_errno(LOG_ERROR, "failed to malloc pw buffer");
|
||||
return -1;
|
||||
}
|
||||
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 {
|
||||
size_t len;
|
||||
char buffer[1024];
|
||||
size_t buffer_len;
|
||||
char *buffer;
|
||||
};
|
||||
|
||||
struct swaylock_state {
|
||||
|
10
main.c
10
main.c
@ -20,6 +20,7 @@
|
||||
#include "comm.h"
|
||||
#include "log.h"
|
||||
#include "loop.h"
|
||||
#include "password-buffer.h"
|
||||
#include "pool-buffer.h"
|
||||
#include "seat.h"
|
||||
#include "swaylock.h"
|
||||
@ -1187,13 +1188,12 @@ int main(int argc, char **argv) {
|
||||
state.args.colors.line = state.args.colors.ring;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
// Most non-linux platforms require root to mlock()
|
||||
if (mlock(state.password.buffer, sizeof(state.password.buffer)) != 0) {
|
||||
swaylock_log(LOG_ERROR, "Unable to mlock() password memory.");
|
||||
state.password.len = 0;
|
||||
state.password.buffer_len = 1024;
|
||||
state.password.buffer = password_buffer_create(state.password.buffer_len);
|
||||
if (!state.password.buffer) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
#endif
|
||||
|
||||
wl_list_init(&state.surfaces);
|
||||
state.xkb.context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||
|
@ -127,6 +127,7 @@ sources = [
|
||||
'loop.c',
|
||||
'main.c',
|
||||
'password.c',
|
||||
'password-buffer.c',
|
||||
'pool-buffer.c',
|
||||
'render.c',
|
||||
'seat.c',
|
||||
|
9
pam.c
9
pam.c
@ -7,6 +7,7 @@
|
||||
#include <unistd.h>
|
||||
#include "comm.h"
|
||||
#include "log.h"
|
||||
#include "password-buffer.h"
|
||||
#include "swaylock.h"
|
||||
|
||||
static char *pw_buf = NULL;
|
||||
@ -96,6 +97,9 @@ void run_pw_backend_child(void) {
|
||||
}
|
||||
|
||||
int pam_status = pam_authenticate(auth_handle, 0);
|
||||
password_buffer_destroy(pw_buf, size);
|
||||
pw_buf = NULL;
|
||||
|
||||
bool success = pam_status == PAM_SUCCESS;
|
||||
if (!success) {
|
||||
swaylock_log(LOG_ERROR, "pam_authenticate failed: %s",
|
||||
@ -103,13 +107,8 @@ void run_pw_backend_child(void) {
|
||||
}
|
||||
|
||||
if (!write_comm_reply(success)) {
|
||||
clear_buffer(pw_buf, size);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
clear_buffer(pw_buf, size);
|
||||
free(pw_buf);
|
||||
pw_buf = NULL;
|
||||
}
|
||||
|
||||
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) {
|
||||
clear_buffer(pw->buffer, sizeof(pw->buffer));
|
||||
clear_buffer(pw->buffer, pw->buffer_len);
|
||||
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) {
|
||||
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
|
||||
return;
|
||||
}
|
||||
|
11
shadow.c
11
shadow.c
@ -11,6 +11,7 @@
|
||||
#endif
|
||||
#include "comm.h"
|
||||
#include "log.h"
|
||||
#include "password-buffer.h"
|
||||
#include "swaylock.h"
|
||||
|
||||
void initialize_pw_backend(int argc, char **argv) {
|
||||
@ -81,23 +82,19 @@ void run_pw_backend_child(void) {
|
||||
}
|
||||
|
||||
char *c = crypt(buf, encpw);
|
||||
password_buffer_destroy(buf, size);
|
||||
buf = NULL;
|
||||
|
||||
if (c == NULL) {
|
||||
swaylock_log_errno(LOG_ERROR, "crypt failed");
|
||||
clear_buffer(buf, size);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
bool success = strcmp(c, encpw) == 0;
|
||||
|
||||
if (!write_comm_reply(success)) {
|
||||
clear_buffer(buf, size);
|
||||
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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user