77 lines
2.2 KiB
Plaintext
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;
|
|
}
|
|
}
|
|
|
|
}
|