fix: audit fix — reduce password copies in memory (v0.8.4)
- attempt_login takes Zeroizing<String> by value, eliminating the redundant Zeroizing::new(password.to_string()) that doubled the Rust-owned copy. - Clear password_entry's internal buffer immediately after extracting the password, shortening the window during which the GTK GString persists in non-zeroizable libc memory.
This commit is contained in:
parent
48d363bb18
commit
35f1a17cdf
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -575,7 +575,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "moongreet"
|
name = "moongreet"
|
||||||
version = "0.8.3"
|
version = "0.8.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gdk-pixbuf",
|
"gdk-pixbuf",
|
||||||
"gdk4",
|
"gdk4",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "moongreet"
|
name = "moongreet"
|
||||||
version = "0.8.3"
|
version = "0.8.4"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
description = "A greetd greeter for Wayland with GTK4 and Layer Shell"
|
description = "A greetd greeter for Wayland with GTK4 and Layer Shell"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|||||||
@ -1,5 +1,12 @@
|
|||||||
# Decisions
|
# Decisions
|
||||||
|
|
||||||
|
## 2026-04-24 – Audit fix: shrink password-in-memory window (v0.8.4)
|
||||||
|
|
||||||
|
- **Who**: ClaudeCode, Dom
|
||||||
|
- **Why**: Security audit flagged the GTK password path as holding more copies of the plaintext password in memory than necessary. `attempt_login` wrapped the already-`Zeroizing<String>` caller value into a second `Zeroizing<String>` (`password.to_string()`), and the GTK `GString` backing `entry.text()` persisted in libc malloc'd memory until the allocator reused the page.
|
||||||
|
- **Tradeoffs**: The GTK `GString` and the libc `strdup` copy on the PAM FFI boundary remain non-zeroizable — this is an inherent GTK/libc limitation, already documented in CLAUDE.md. This change reduces the Rust-owned copies to one and clears the `PasswordEntry` text field immediately after extraction to shorten the GTK-side window.
|
||||||
|
- **How**: (1) `attempt_login` now takes `password: Zeroizing<String>` by value instead of `&str`, moving ownership into the `spawn_blocking` closure. (2) The redundant `Zeroizing::new(password.to_string())` inside `attempt_login` is removed. (3) `password_entry.set_text("")` is called right after the password is extracted from the activate handler, shortening the lifetime of the GTK-internal buffer.
|
||||||
|
|
||||||
## 2026-04-21 – Ship polkit rule in moongreet instead of moonarch (v0.8.3)
|
## 2026-04-21 – Ship polkit rule in moongreet instead of moonarch (v0.8.3)
|
||||||
|
|
||||||
- **Who**: ClaudeCode, Dom
|
- **Who**: ClaudeCode, Dom
|
||||||
|
|||||||
@ -493,6 +493,10 @@ pub fn create_greeter_window(
|
|||||||
let Some(user) = user else { return };
|
let Some(user) = user else { return };
|
||||||
|
|
||||||
let password = Zeroizing::new(entry.text().to_string());
|
let password = Zeroizing::new(entry.text().to_string());
|
||||||
|
// Clear the GTK entry's internal buffer as early as possible. GTK allocates
|
||||||
|
// the backing `GString` via libc malloc, which `zeroize` cannot reach — the
|
||||||
|
// best we can do is shorten the window during which it resides in memory.
|
||||||
|
entry.set_text("");
|
||||||
|
|
||||||
let session = get_selected_session(&session_dropdown, &sessions_rc);
|
let session = get_selected_session(&session_dropdown, &sessions_rc);
|
||||||
let Some(session) = session else {
|
let Some(session) = session else {
|
||||||
@ -502,7 +506,7 @@ pub fn create_greeter_window(
|
|||||||
|
|
||||||
attempt_login(
|
attempt_login(
|
||||||
&user,
|
&user,
|
||||||
&password,
|
password,
|
||||||
&session,
|
&session,
|
||||||
strings,
|
strings,
|
||||||
&state,
|
&state,
|
||||||
@ -953,7 +957,7 @@ fn set_login_sensitive(
|
|||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn attempt_login(
|
fn attempt_login(
|
||||||
user: &User,
|
user: &User,
|
||||||
password: &str,
|
password: Zeroizing<String>,
|
||||||
session: &Session,
|
session: &Session,
|
||||||
strings: &'static Strings,
|
strings: &'static Strings,
|
||||||
state: &Rc<RefCell<GreeterState>>,
|
state: &Rc<RefCell<GreeterState>>,
|
||||||
@ -992,7 +996,6 @@ fn attempt_login(
|
|||||||
set_login_sensitive(password_entry, session_dropdown, false);
|
set_login_sensitive(password_entry, session_dropdown, false);
|
||||||
|
|
||||||
let username = user.username.clone();
|
let username = user.username.clone();
|
||||||
let password = Zeroizing::new(password.to_string());
|
|
||||||
let exec_cmd = session.exec_cmd.clone();
|
let exec_cmd = session.exec_cmd.clone();
|
||||||
let session_name = session.name.clone();
|
let session_name = session.name.clone();
|
||||||
let greetd_sock = state.borrow().greetd_sock.clone();
|
let greetd_sock = state.borrow().greetd_sock.clone();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user