fix: harden release profile, drop dead struct fields (v0.6.18)
Security-audit follow-up. The release profile had silently drifted from the hardened profile (v0.6.12): v0.6.14 bundled lto fat->thin, strip true->false, and debug=true into an unrelated refactor — a debug aid for the suspend/resume SIGSEGV hunt. That crash is fixed (v0.6.17), so restore lto=fat + strip=true and drop the debug symbols, which on a security-critical auth binary only ease reverse-engineering of the auth path and bloat the binary. Also remove two vestigial struct fields the audit surfaced: never read, no behavior change. - LockscreenHandles.password_entry: the entry is fully wired via internal closures before the handles return; no caller read the field. - User.uid: superseded by getuid() (root check) and username lookups.
This commit is contained in:
Generated
+1
-1
@@ -575,7 +575,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "moonlock"
|
name = "moonlock"
|
||||||
version = "0.6.17"
|
version = "0.6.18"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gdk-pixbuf",
|
"gdk-pixbuf",
|
||||||
"gdk4",
|
"gdk4",
|
||||||
|
|||||||
+3
-4
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "moonlock"
|
name = "moonlock"
|
||||||
version = "0.6.17"
|
version = "0.6.18"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
description = "A secure Wayland lockscreen with GTK4, PAM and fingerprint support"
|
description = "A secure Wayland lockscreen with GTK4, PAM and fingerprint support"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
@@ -28,7 +28,6 @@ tempfile = "3"
|
|||||||
glib-build-tools = "0.22"
|
glib-build-tools = "0.22"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = "thin"
|
lto = "fat"
|
||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
strip = false
|
strip = true
|
||||||
debug = true
|
|
||||||
|
|||||||
@@ -2,6 +2,13 @@
|
|||||||
|
|
||||||
Architectural and design decisions for Moonlock, in reverse chronological order.
|
Architectural and design decisions for Moonlock, in reverse chronological order.
|
||||||
|
|
||||||
|
## 2026-06-17 – Restore hardened release profile after the crash hunt (v0.6.18)
|
||||||
|
|
||||||
|
- **Who**: ClaudeCode, Dom
|
||||||
|
- **Why**: A security audit found the `[profile.release]` in `Cargo.toml` had silently drifted from the hardened profile decided on 2026-04-24 (`lto = "fat"`, `strip = true`). Git blame traced the drift to v0.6.14 (commit `85cf039`, "refactor: power-confirm via PowerAction table"): `lto` was reverted `fat`→`thin`, `strip` flipped `true`→`false`, and `debug = true` was added — all bundled into an unrelated refactor commit, with no commit-message mention and no entry here. The pattern (no strip + debug symbols + faster thin LTO) was a debug aid for the suspend/resume SIGSEGV hunt that ran v0.6.9–v0.6.17, giving symbolized coredump backtraces. That crash is fixed as of v0.6.17, so the debug profile has outlived its purpose, while shipping debug symbols on a security-critical auth binary eases reverse-engineering of the auth path and bloats the binary.
|
||||||
|
- **Tradeoffs**: Restoring `lto = "fat"` roughly doubles release build time (~30 s → ~60 s) for better cross-crate inlining; acceptable for a binary compiled once per release. Dropping `strip = false` + `debug = true` means field coredumps are no longer symbolized out of the box — a deliberate trade now that the crash is resolved; debug symbols can be re-enabled temporarily if a new crash needs hunting. Not chosen: keeping `lto = "fat"` but retaining the debug symbols — rejected because the symbols' only justification (the crash hunt) is gone.
|
||||||
|
- **How**: `Cargo.toml` `[profile.release]` restored to `lto = "fat"`, `strip = true`, with the `debug = true` line removed; `codegen-units = 1` unchanged. Verified via `file target/release/moonlock` reporting a stripped binary.
|
||||||
|
|
||||||
## 2026-06-02 – Real fix for the unlock SIGSEGV: quit in ::unlocked, never destroy windows ourselves (v0.6.17)
|
## 2026-06-02 – Real fix for the unlock SIGSEGV: quit in ::unlocked, never destroy windows ourselves (v0.6.17)
|
||||||
|
|
||||||
- **Who**: ClaudeCode, Dom
|
- **Who**: ClaudeCode, Dom
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ use crate::users;
|
|||||||
pub struct LockscreenHandles {
|
pub struct LockscreenHandles {
|
||||||
pub window: gtk::ApplicationWindow,
|
pub window: gtk::ApplicationWindow,
|
||||||
pub fp_label: gtk::Label,
|
pub fp_label: gtk::Label,
|
||||||
pub password_entry: gtk::PasswordEntry,
|
|
||||||
pub unlock_callback: Rc<dyn Fn()>,
|
pub unlock_callback: Rc<dyn Fn()>,
|
||||||
pub username: String,
|
pub username: String,
|
||||||
state: Rc<RefCell<LockscreenState>>,
|
state: Rc<RefCell<LockscreenState>>,
|
||||||
@@ -67,7 +66,6 @@ pub fn create_lockscreen_window(
|
|||||||
return LockscreenHandles {
|
return LockscreenHandles {
|
||||||
window,
|
window,
|
||||||
fp_label,
|
fp_label,
|
||||||
password_entry: gtk::PasswordEntry::new(),
|
|
||||||
unlock_callback,
|
unlock_callback,
|
||||||
username: String::new(),
|
username: String::new(),
|
||||||
state: Rc::new(RefCell::new(LockscreenState {
|
state: Rc::new(RefCell::new(LockscreenState {
|
||||||
@@ -357,7 +355,6 @@ pub fn create_lockscreen_window(
|
|||||||
LockscreenHandles {
|
LockscreenHandles {
|
||||||
window,
|
window,
|
||||||
fp_label,
|
fp_label,
|
||||||
password_entry: password_entry.clone(),
|
|
||||||
unlock_callback,
|
unlock_callback,
|
||||||
username: user.username,
|
username: user.username,
|
||||||
state: state.clone(),
|
state: state.clone(),
|
||||||
|
|||||||
+1
-2
@@ -12,7 +12,6 @@ pub struct User {
|
|||||||
pub username: String,
|
pub username: String,
|
||||||
pub display_name: String,
|
pub display_name: String,
|
||||||
pub home: PathBuf,
|
pub home: PathBuf,
|
||||||
pub uid: u32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_current_user() -> Option<User> {
|
pub fn get_current_user() -> Option<User> {
|
||||||
@@ -29,7 +28,7 @@ pub fn get_current_user() -> Option<User> {
|
|||||||
let first = gecos.split(',').next().unwrap_or("");
|
let first = gecos.split(',').next().unwrap_or("");
|
||||||
if first.is_empty() { nix_user.name.clone() } else { first.to_string() }
|
if first.is_empty() { nix_user.name.clone() } else { first.to_string() }
|
||||||
} else { nix_user.name.clone() };
|
} else { nix_user.name.clone() };
|
||||||
Some(User { username: nix_user.name, display_name, home: nix_user.dir, uid: uid.as_raw() })
|
Some(User { username: nix_user.name, display_name, home: nix_user.dir })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_avatar_path(home: &Path, username: &str) -> Option<PathBuf> {
|
pub fn get_avatar_path(home: &Path, username: &str) -> Option<PathBuf> {
|
||||||
|
|||||||
Reference in New Issue
Block a user