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.
This commit is contained in:
Jeffrey Paul 2025-07-22 12:46:16 +02:00
parent e5d7407c79
commit 8e3530a510

View File

@ -205,20 +205,26 @@ func readSecurePassphrase(prompt string) (*memguard.LockedBuffer, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer passphraseBuffer1.Destroy()
// Read confirmation passphrase // Read confirmation passphrase
passphraseBuffer2, err := secret.ReadPassphrase("Confirm passphrase: ") passphraseBuffer2, err := secret.ReadPassphrase("Confirm passphrase: ")
if err != nil { if err != nil {
passphraseBuffer1.Destroy()
return nil, fmt.Errorf("failed to read passphrase confirmation: %w", err) return nil, fmt.Errorf("failed to read passphrase confirmation: %w", err)
} }
defer passphraseBuffer2.Destroy()
// Compare passphrases // Compare passphrases
if passphraseBuffer1.String() != passphraseBuffer2.String() { if passphraseBuffer1.String() != passphraseBuffer2.String() {
passphraseBuffer1.Destroy()
passphraseBuffer2.Destroy()
return nil, fmt.Errorf("passphrases do not match") return nil, fmt.Errorf("passphrases do not match")
} }
// Create a new buffer with the confirmed passphrase // Clean up the second buffer, we'll return the first
return memguard.NewBufferFromBytes(passphraseBuffer1.Bytes()), nil passphraseBuffer2.Destroy()
// Return the first buffer (caller is responsible for destroying it)
return passphraseBuffer1, nil
} }