diff options
| author | Douglas Bagnall <douglas.bagnall@catalyst.net.nz> | 2025-10-30 16:01:36 +0100 |
|---|---|---|
| committer | Andreas Schneider <asn@cryptomilk.org> | 2025-11-11 13:46:42 +0000 |
| commit | 2b17c9816d4373eba365de803eec10435ea038d4 (patch) | |
| tree | dfaad16ccaf8eda64b587d38e97bebe8aaa77324 /lib/replace | |
| parent | ef08be24e9114b4477cc2b3f7a28a816ec66802c (diff) | |
| download | samba-2b17c9816d4373eba365de803eec10435ea038d4.tar.gz samba-2b17c9816d4373eba365de803eec10435ea038d4.tar.bz2 samba-2b17c9816d4373eba365de803eec10435ea038d4.zip | |
lib:replace: Add test for memset_explicit()
Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>
Diffstat (limited to 'lib/replace')
| -rw-r--r-- | lib/replace/tests/test_memset_explicit.c | 99 | ||||
| -rw-r--r-- | lib/replace/wscript | 5 |
2 files changed, 104 insertions, 0 deletions
diff --git a/lib/replace/tests/test_memset_explicit.c b/lib/replace/tests/test_memset_explicit.c new file mode 100644 index 00000000000..4e56d7a9aee --- /dev/null +++ b/lib/replace/tests/test_memset_explicit.c @@ -0,0 +1,99 @@ +#include <stdarg.h> +#include <stddef.h> +#include <stdint.h> +#include <setjmp.h> +#include <cmocka.h> + +#include "lib/replace/replace.h" + + +/* + * To check that a memset_explicit string is being memset when it + * appears unused, we meed to be sneaky in our check -- otherwise the + * check counts as a use. + * + * We are sneaky by using a function that seens to take an int + * argument which is really a pointer, and we hide that it is a + * pointer by masking it. + * + * For these tests we don't use talloc because the talloc magic gets + * in the way a little bit. + */ + +#define MASK 0x12345678 + +__attribute__((noinline)) +static void check_memset_explicit(intmax_t p, const char *expected, size_t len) +{ + size_t i; + char *secret = (char *) (p ^ MASK); + for (i = 0; i < len; i++) { + assert_int_equal(secret[i], expected[i]); + } +} + + +__attribute__((noinline)) +static char *get_secret(off_t offset) +{ + char * secret = malloc(7 + offset); + memset(secret, 0, 7 + offset); + memcpy(secret + offset, "secret", 7); + /* avoiding *this* being elided */ + print_message("secret is '%s'\n", secret); + asm(""); + return secret; +} + + +static void test_memset_explicit(void ** state) +{ + uintptr_t p; + char zeros[7] = {0}; + char *secret = get_secret(0); + p = ((uintptr_t)secret) ^ MASK; + memset_explicit(secret, 'o', 3); + check_memset_explicit(p, "oooret", 7); + memset_explicit(secret, 0, 7); + check_memset_explicit(p, zeros, 7); + free(secret); +} + +static void test_memset_explicit_double_alloc(void ** state) +{ + size_t i, found; + uintptr_t p, q; + char *secret = get_secret(20); + p = (uintptr_t)secret ^ MASK; + memset_explicit(secret, 'x', 23); + free(secret); + /* + * Now we malloc the same size again, and hope we got the + * block we just freed. + */ + found = 0; + for (i = 0; i < 1000; i++) { + secret = malloc(27); + q = (uintptr_t)secret ^ MASK; + if (q == p) { + q = (uintptr_t)(secret + 20) ^ MASK; + check_memset_explicit(q, "xxxret", 7); + found ++; + } + free(secret); + } + print_message("found freed pointer %zu/1000 times \n", + found); +} + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_memset_explicit), + cmocka_unit_test(test_memset_explicit_double_alloc), + }; + if (! isatty(1)) { + cmocka_set_message_output(CM_OUTPUT_SUBUNIT); + } + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/lib/replace/wscript b/lib/replace/wscript index 1a78bf55f2a..1318f887c77 100644 --- a/lib/replace/wscript +++ b/lib/replace/wscript @@ -973,6 +973,11 @@ def build(bld): deps='replace replace-test', install=False) + bld.SAMBA_BINARY('test_memset_explicit', + source='tests/test_memset_explicit.c', + deps='cmocka replace', + for_selftest=True) + # build replacements for stdint.h and stdbool.h if needed bld.SAMBA_GENERATOR('replace_stdint_h', rule='cp ${SRC} ${TGT}', |
