utils: add a generic mlock function with a destructor

Introduces a generic utility function to replace the repeated pattern of
sodium_mlock() + tal_add_destructor()
This commit is contained in:
Sangbida Chaudhuri
2025-10-24 13:57:50 +10:30
committed by Rusty Russell
parent 310405761a
commit 463712f3b7
7 changed files with 27 additions and 33 deletions

View File

@@ -28,11 +28,6 @@
#define PASSPHRASE_HASH_LEN 32
#define HSM_SECRET_PLAIN_SIZE 32
void destroy_secret(struct secret *secret)
{
sodium_munlock(secret->data, sizeof(secret->data));
}
/* Helper function to validate a mnemonic string */
static bool validate_mnemonic(const char *mnemonic, enum hsm_secret_error *err)
{
@@ -70,9 +65,7 @@ struct secret *get_encryption_key(const tal_t *ctx, const char *passphrase)
}
/* Don't swap the encryption key ! */
if (sodium_mlock(secret->data, sizeof(secret->data)) != 0)
return tal_free(secret);
tal_add_destructor(secret, destroy_secret);
mlock_tal_memory(secret);
/* Now derive the key. */
if (crypto_pwhash(secret->data, sizeof(secret->data), passphrase, strlen(passphrase), salt,
@@ -254,10 +247,6 @@ static struct hsm_secret *extract_encrypted_secret(const tal_t *ctx,
/* Attempt decryption */
struct secret temp_secret;
decrypt_success = decrypt_hsm_secret(encryption_key, hsm_secret, &temp_secret);
/* Clear encryption key immediately after use */
destroy_secret(encryption_key);
if (!decrypt_success) {
*err = HSM_SECRET_ERR_WRONG_PASSPHRASE;
return tal_free(hsms);
@@ -389,11 +378,6 @@ bool encrypt_legacy_hsm_secret(const struct secret *encryption_key,
return true;
}
static void destroy_passphrase(char *passphrase)
{
sodium_munlock(passphrase, tal_bytelen(passphrase));
}
/* Disable terminal echo if needed */
static bool disable_echo(struct termios *saved_term)
{
@@ -457,11 +441,7 @@ const char *read_stdin_pass(const tal_t *ctx, enum hsm_secret_error *err)
return NULL;
}
/* Memory locking is mandatory: failure means we're on an insecure system */
if (sodium_mlock(input, tal_bytelen(input)) != 0)
abort();
tal_add_destructor(input, destroy_passphrase);
mlock_tal_memory(input);
if (echo_disabled)
restore_echo(&saved_term);

View File

@@ -158,12 +158,6 @@ bool derive_seed_hash(const char *mnemonic, const char *passphrase, struct sha25
*/
int is_legacy_hsm_secret_encrypted(const char *path);
/**
* Zero and unlock a secret's memory.
* @secret - the secret to destroy
*/
void destroy_secret(struct secret *secret);
/**
* Convert hsm_secret_type enum to human-readable string.
* @type - the hsm_secret_type to convert

View File

@@ -10,6 +10,7 @@
#include <common/utils.h>
#include <errno.h>
#include <locale.h>
#include <sodium.h>
const tal_t *wally_tal_ctx = NULL;
secp256k1_context *secp256k1_ctx;
@@ -92,6 +93,18 @@ u8 *tal_hexdata(const tal_t *ctx, const void *str, size_t len)
return data;
}
static void destroy_munlock(const tal_t *ptr)
{
sodium_munlock((void *)ptr, tal_bytelen(ptr));
}
void mlock_tal_memory(const tal_t *ptr)
{
if (sodium_mlock((void *)ptr, tal_bytelen(ptr)) != 0)
abort();
tal_add_destructor(ptr, destroy_munlock);
}
bool tal_arr_eq_(const void *a, const void *b, size_t unused)
{
return memeq(a, tal_bytelen(a), b, tal_bytelen(b));

View File

@@ -53,6 +53,16 @@ char *tal_hex(const tal_t *ctx, const tal_t *data);
/* Allocate and fill a buffer with the data of this hex string. */
u8 *tal_hexdata(const tal_t *ctx, const void *str, size_t len);
/**
* mlock_tal_memory - lock a tal-allocated memory with sodium_mlock.
* @ptr - the tal-allocated memory to lock
*
* This is a generic function to replace the pattern of sodium_mlock + tal_add_destructor.
*
* Aborts on failure (memory locking is mandatory for security).
*/
void mlock_tal_memory(const tal_t *ptr);
/* Note: p is never a complex expression, otherwise this multi-evaluates! */
#define tal_arr_expand(p, s) \
do { \

View File

@@ -455,7 +455,7 @@ static void load_hsm(const char *passphrase)
hsm_secret->mnemonic = tal_steal(hsm_secret, hsms->mnemonic);
/*~ Don't swap this secret data to disk for security. */
sodium_mlock(hsm_secret->secret_data, tal_bytelen(hsm_secret->secret_data));
mlock_tal_memory(hsm_secret->secret_data);
}
/*~ We have a pre-init call in developer mode, to set dev flags */

View File

@@ -2477,7 +2477,7 @@ u8 *hsmd_init(const u8 *secret_data, size_t secret_len, const u64 hsmd_version,
/*~ Store the secret (32 or 64 bytes) - use NULL context for persistence */
secretstuff.bip32_seed = notleak(tal_dup_arr(NULL, u8, secret_data, secret_len, 0));
sodium_mlock(secretstuff.bip32_seed, tal_bytelen(secretstuff.bip32_seed));
mlock_tal_memory(secretstuff.bip32_seed);
assert(bip32_key_version.bip32_pubkey_version == BIP32_VER_MAIN_PUBLIC
|| bip32_key_version.bip32_pubkey_version == BIP32_VER_TEST_PUBLIC);

View File

@@ -223,9 +223,6 @@ static void encrypt_hsm(const char *hsm_secret_path)
if (!encrypt_legacy_hsm_secret(encryption_key, &legacy_secret, encrypted_hsm_secret))
errx(ERROR_LIBSODIUM, "Could not encrypt the hsm_secret seed.");
/* Securely discard the encryption key */
destroy_secret(encryption_key);
/* Create a backup file, "just in case". */
rename(hsm_secret_path, backup);
fd = open(hsm_secret_path, O_CREAT|O_EXCL|O_WRONLY, 0400);