From 8e3530a510004bd946493cebda9c167388607509 Mon Sep 17 00:00:00 2001 From: sneak Date: Tue, 22 Jul 2025 12:46:16 +0200 Subject: [PATCH] Fix use-after-free crash in readSecurePassphrase The function was using defer to destroy password buffers, which caused the buffers to be freed before the function returned. This led to a SIGBUS error when trying to access the destroyed buffer's memory. Changed to manual memory management to ensure buffers are only destroyed when no longer needed, and the first buffer is returned directly to the caller who is responsible for destroying it. --- internal/cli/init.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/internal/cli/init.go b/internal/cli/init.go index 4b237c8..1167f7c 100644 --- a/internal/cli/init.go +++ b/internal/cli/init.go @@ -205,20 +205,26 @@ func readSecurePassphrase(prompt string) (*memguard.LockedBuffer, error) { if err != nil { return nil, err } - defer passphraseBuffer1.Destroy() // Read confirmation passphrase passphraseBuffer2, err := secret.ReadPassphrase("Confirm passphrase: ") if err != nil { + passphraseBuffer1.Destroy() + return nil, fmt.Errorf("failed to read passphrase confirmation: %w", err) } - defer passphraseBuffer2.Destroy() // Compare passphrases if passphraseBuffer1.String() != passphraseBuffer2.String() { + passphraseBuffer1.Destroy() + passphraseBuffer2.Destroy() + return nil, fmt.Errorf("passphrases do not match") } - // Create a new buffer with the confirmed passphrase - return memguard.NewBufferFromBytes(passphraseBuffer1.Bytes()), nil + // Clean up the second buffer, we'll return the first + passphraseBuffer2.Destroy() + + // Return the first buffer (caller is responsible for destroying it) + return passphraseBuffer1, nil }