mcap/modules/Secure_Memory/module.jai

77 lines
2.2 KiB
Plaintext

// Secure memory overwrite primitives, extracted from Basic so that allocators can depend on
// wiping without dragging in the rest of Basic. Apart from libsodium it imports Basic.
//
// USE_SODIUM routes the wipe through libsodium's sodium_memzero, the portable way to get a
// store the optimizer is not permitted to elide. Without it, x64 wipes with inline assembly the
// optimizer leaves alone, and other CPUs (arm64) with a plain loop it is allowed to remove.
//
// In this template it defaults to false, so the build needs no libsodium. Module parameters
// only reach a module from the main program, and Basic's arenas import this one directly, so
// this default is what they get. If the app keeps secrets in memory, add the jai-sodium module
// to modules/ and set the default back to true.
#module_parameters () (USE_SODIUM := false, LOAD_TESTS := false);
Basic :: #import "Basic"; // assert
#if USE_SODIUM {
Sodium :: #import "jai-sodium";
// Byte counts are signed ints throughout this module; libsodium wants an unsigned length.
secure_memzero :: inline (memory: *void, count: int) {
if count <= 0 return;
Sodium.sodium_memzero(memory, count.(u64,no_check));
}
}
#if LOAD_TESTS {
#load "tests/secure_memory_tests.jai";
}
// Wipe_Function :: #type (memory: *void, count: int);
// Macros for ease-of-use
secure_overwrite :: (s: string) #expand {
memory_secure_overwrite(s.data, s.count);
}
secure_overwrite :: (a: []$T) #expand {
memory_secure_overwrite(a.data, a.count * size_of(T));
}
secure_overwrite :: (memory: *$T) #expand {
memory_secure_overwrite(memory, size_of(T));
}
secure_overwrite :: (memory: *$T, count: int) #expand {
memory_secure_overwrite(memory, count);
}
// sodium_memzero only zeroes, so a non-zero fill still takes the rep stos / loop path.
memory_secure_overwrite :: inline (memory: *void, count: int, value: u8 = 0) {
Basic.assert(count >= 0);
if count <= 0 return;
#if USE_SODIUM {
if value == 0 {
secure_memzero(memory, count);
return;
}
}
#if CPU == .X64 {
#asm {
memory === di;
value === a;
count === c;
rep_stos.b memory, value, count;
}
} else {
memu8 := cast(*u8) memory;
for 0..count-1 {
memu8[it] = value;
}
}
}