aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README14
-rw-r--r--argon2/make_settings.c4
-rw-r--r--librecrypt.716
-rw-r--r--librecrypt.h4
-rw-r--r--librecrypt_add_algorithm.34
-rw-r--r--librecrypt_add_algorithm.c161
-rw-r--r--librecrypt_fill_with_random_.c2
-rw-r--r--librecrypt_hash_.c2
-rw-r--r--librecrypt_make_settings.c14
-rw-r--r--libtest/common.h6
-rw-r--r--libtest/globals.c6
-rw-r--r--libtest/libtest.h13
-rw-r--r--libtest/libtest_fd_tracking.c11
-rw-r--r--libtest/libtest_free.c10
-rw-r--r--libtest/libtest_print_backtrace.c6
15 files changed, 228 insertions, 45 deletions
diff --git a/README b/README
index 2ad40fe..60b1050 100644
--- a/README
+++ b/README
@@ -100,5 +100,19 @@ DESCRIPTION
Get encoding alphabet for the last algorithm in a
chain.
+NOTES
+ Using librecrypt_add_algorithm(3) to hash existing password
+ hashes should be used as a transitional mitigation strategy
+ when replaing an old password hash function. Once the password
+ is available in clear text, it should be hashed anew using
+ only the new password hash function: this will both increase
+ security and reducing login it, allowing for stronger hash
+ function configurations. This is especially important if the
+ password is actually a key and longer than the old hash. It
+ is also a good idea to force password reset, and lock any
+ account that hasn't reset its password, because it is
+ possibly that the old password hashes has been leaked and it
+ will force a fresh hashing even one counts that seldom log in.
+
SEE ALSO
crypt(3), crypt(5)
diff --git a/argon2/make_settings.c b/argon2/make_settings.c
index 396c48d..9efb58f 100644
--- a/argon2/make_settings.c
+++ b/argon2/make_settings.c
@@ -309,8 +309,8 @@ check_aborts(ssize_t (*gen)(char *, size_t, const char *, size_t, uintmax_t,
{
#define SHORTTEXT "------------------------------------------------------------------------"
#define LONGTEXT SHORTTEXT SHORTTEXT SHORTTEXT SHORTTEXT SHORTTEXT SHORTTEXT SHORTTEXT
- EXPECT_ABORT(discarded_ssize = (*gen)(NULL, 0, "argon2i$", 0u, 0u, 0, NULL, NULL));
- EXPECT_ABORT(discarded_ssize = (*gen)(NULL, 0, "$argon2"LONGTEXT"$", 0u, 0u, 0, NULL, NULL));
+ EXPECT_ABORT(discarded_ssize = (*gen)(NULL, 0u, "argon2i$", 0u, 0u, 0, NULL, NULL));
+ EXPECT_ABORT(discarded_ssize = (*gen)(NULL, 0u, "$argon2"LONGTEXT"$", 0u, 0u, 0, NULL, NULL));
}
diff --git a/librecrypt.7 b/librecrypt.7
index 7c577a4..d576658 100644
--- a/librecrypt.7
+++ b/librecrypt.7
@@ -123,6 +123,22 @@ binary.
Get encoding alphabet for the last algorithm in a
chain.
+.SH NOTES
+Using
+.BR librecrypt_add_algorithm (3)
+to hash existing password
+hashes should be used as a transitional mitigation strategy
+when replaing an old password hash function. Once the password
+is available in clear text, it should be hashed anew using
+only the new password hash function: this will both increase
+security and reducing login it, allowing for stronger hash
+function configurations. This is especially important if the
+password is actually a key and longer than the old hash. It
+is also a good idea to force password reset, and lock any
+account that hasn't reset its password, because it is
+possibly that the old password hashes has been leaked and it
+will force a fresh hashing even one counts that seldom log in.
+
.SH SEE ALSO
.BR crypt (3),
.BR crypt (5)
diff --git a/librecrypt.h b/librecrypt.h
index 5218152..550dacc 100644
--- a/librecrypt.h
+++ b/librecrypt.h
@@ -800,9 +800,9 @@ int librecrypt_test_supported(const char *phrase, size_t len, int text, const ch
*
* This function is MT-Safe but AS-Unsafe
*/
-LIBRECRYPT_WRITE_MEM__(1, 2) LIBRECRYPT_READ_WRITE_STR__(3) LIBRECRYPT_READ_STR__(4)
+LIBRECRYPT_WRITE_MEM__(1, 2) LIBRECRYPT_READ_STR__(3) LIBRECRYPT_READ_STR__(4)
LIBRECRYPT_NONNULL_I__(3) LIBRECRYPT_NONNULL_I__(4) LIBRECRYPT_WUR__
-ssize_t librecrypt_add_algorithm(char *out_buffer, size_t size, char *augend,
+ssize_t librecrypt_add_algorithm(char *out_buffer, size_t size, const char *augend,
const char *restrict augment, void *reserved);
diff --git a/librecrypt_add_algorithm.3 b/librecrypt_add_algorithm.3
index 0bb6566..2c7b365 100644
--- a/librecrypt_add_algorithm.3
+++ b/librecrypt_add_algorithm.3
@@ -6,8 +6,8 @@ librecrypt_add_algorithm - Append an algorithm chain to a password hash string
.nf
#include <librecrypt.h>
-ssize_t \fBlibrecrypt_add_algorithm\fP(char *restrict \fIout_buffer\fP, size_t \fIsize\fP,
- char *\fIaugend\fP, const char *restrict \fIaugment\fP,
+ssize_t \fBlibrecrypt_add_algorithm\fP(char *\fIout_buffer\fP, size_t \fIsize\fP,
+ const char *\fIaugend\fP, const char *restrict \fIaugment\fP,
void *\fIreserved\fP);
.fi
.PP
diff --git a/librecrypt_add_algorithm.c b/librecrypt_add_algorithm.c
index 10a2174..4fa5b94 100644
--- a/librecrypt_add_algorithm.c
+++ b/librecrypt_add_algorithm.c
@@ -9,7 +9,7 @@
ssize_t
-librecrypt_add_algorithm(char *out_buffer, size_t size, char *augend, const char *restrict augment, void *reserved)
+librecrypt_add_algorithm(char *out_buffer, size_t size, const char *augend, const char *restrict augment, void *reserved)
{
size_t prefix1, prefix2, min, ret, len, phraselen;
size_t hashsize1, hashsize2;
@@ -18,15 +18,6 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, char *augend, const char
const unsigned char *lut;
ssize_t r;
-#define COPY_PREFIX()\
- do {\
- min = prefix1 < size ? prefix1 : size;\
- if (out_buffer != augend)\
- memmove(out_buffer, augend, min);\
- out_buffer = &out_buffer[min];\
- size -= min;\
- } while (0)
-
/* Reserve space for NUL-termination */
if (size) {
nul_term = 1;
@@ -39,7 +30,7 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, char *augend, const char
prefix1 = librecrypt_settings_prefix(augend, &hashsize1);
prefix2 = librecrypt_settings_prefix(augment, &hashsize2);
- /* If `augend` specifies as hash size rather than a hash, include it as the prefix */
+ /* If `augend` specifies a hash size rather than a hash, include it as the prefix */
if (augend[prefix1] == '*') {
prefix1 += strlen(&augend[prefix1]);
hashsize1 = 0u;
@@ -54,7 +45,11 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, char *augend, const char
}
ret = prefix1 + 1u + prefix2;
if (size) {
- COPY_PREFIX();
+ min = prefix1 < size ? prefix1 : size;
+ if (out_buffer != augend)
+ memmove(out_buffer, augend, min);
+ out_buffer = &out_buffer[min];
+ size -= min;
if (size) {
*out_buffer++ = LIBRECRYPT_ALGORITHM_LINK_DELIMITER;
size -= 1u;
@@ -64,25 +59,30 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, char *augend, const char
if (hashsize2) {
r_int = snprintf(&out_buffer[min], size + 1u, "*%zu", hashsize2);
if (r_int < 2)
- abort();
+ abort(); /* $covered$ (impossible reliably) */
ret += (size_t)r_int;
} else {
out_buffer[min] = '\0';
}
} else {
- r_int = snprintf(NULL, 0, "*%zu", hashsize2);
+ if (!hashsize2)
+ goto out;
+ r_int = snprintf(NULL, 0u, "*%zu", hashsize2);
if (r_int < 2)
- abort();
+ abort(); /* $covered$ (impossible reliably) */
ret += (size_t)r_int;
+ out:
+ if (nul_term)
+ out_buffer[0u] = '\0';
}
return (ssize_t)ret;
}
/* Measure size of hash size specification for `augend` */
if (hashsize1) {
- r_int = snprintf(NULL, 0, "*%zu", hashsize1);
+ r_int = snprintf(NULL, 0u, "*%zu", hashsize1);
if (r_int < 2)
- abort();
+ abort(); /* $covered$ (impossible reliably) */
} else {
r_int = 0;
}
@@ -91,7 +91,7 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, char *augend, const char
ret = prefix1 + (size_t)r_int + 1u;
/* Decode the hash from base-64 to binary */
- if (size <= ret + prefix2 + 1u) {
+ if (size <= ret + prefix2) {
/* If the new hash doesn't fit, don't bother;
* hash sizes are independent of password size */
phrase = NULL;
@@ -106,7 +106,7 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, char *augend, const char
return -1;
/* Measure old binary hash */
- r = librecrypt_decode(NULL, 0, &augend[prefix1], len, lut, pad, strict_pad);
+ r = librecrypt_decode(NULL, 0u, &augend[prefix1], len, lut, pad, strict_pad);
if (r <= 0) {
if (!r)
abort();
@@ -123,10 +123,18 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, char *augend, const char
}
/* Chain the hash algorithms: write `augent` */
- COPY_PREFIX();
- if (hashsize1 && size)
+ min = prefix1 < size ? prefix1 : size;
+ if (out_buffer != augend)
+ memmove(out_buffer, augend, min);
+ out_buffer = &out_buffer[min];
+ size -= min;
+ if (hashsize1 && size) {
if (snprintf(out_buffer, size + 1u, "*%zu", hashsize1) != r_int)
- abort();
+ abort(); /* $covered$ (impossible reliably) */
+ min = (size_t)r_int < size ? (size_t)r_int : size;
+ out_buffer = &out_buffer[min];
+ size -= min;
+ }
/* Chain the hash algorithms: write '>' */
if (size) {
@@ -135,7 +143,7 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, char *augend, const char
}
/* Chain the hash algorithms: write `augment` and hash */
- r = librecrypt_crypt(out_buffer, size + (nul_term ? 1u : 0u), phrase, phraselen, augment, reserved);
+ r = librecrypt_crypt(out_buffer, nul_term ? size + 1u : 0u, phrase, phraselen, augment, reserved);
if (r <= 0) {
librecrypt_wipe(phrase, phraselen);
free(phrase);
@@ -157,13 +165,118 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, char *augend, const char
int
main(void)
{
+#define SALT1 "ABCDabcdABCDabcdABCDabcdABCDabcdABCDabcdABCDabcdABCDabcdABCDabcd"
+#define SALT2 "0123abcd0123ABCD0123abcd0123ABCD0123abcd0123ABCD0123abcd0123ABCD"
+#define HASH1 "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTYVWXYZ/+"
+#define ASTRA "*48"
+
+ char buf[1024], phrase[sizeof(buf)], expected[sizeof(buf)], pad;
+ size_t i, min, phraselen;
+ int strict_pad;
+ const void *lut;
+ ssize_t r;
+
SET_UP_ALARM();
INIT_RESOURCE_TEST();
+#define CHECK(AUGEND, AUGMENT, RESULT)\
+ do {\
+ r = librecrypt_add_algorithm(buf, sizeof(buf), (AUGEND), (AUGMENT), NULL);\
+ EXPECT(r > 0);\
+ EXPECT((size_t)r == strlen(RESULT));\
+ assert((size_t)r < sizeof(buf) + 1u);\
+ EXPECT(!buf[r]);\
+ EXPECT(!memcmp(buf, (RESULT), (size_t)r));\
+ \
+ for (i = (size_t)r + 2u;; i--) {\
+ memset(buf, 99, sizeof(buf));\
+ EXPECT(librecrypt_add_algorithm(buf, i, (AUGEND), (AUGMENT), NULL) == r);\
+ if (!i)\
+ break;\
+ min = i - 1u < (size_t)r ? i - 1u : (size_t)r;\
+ EXPECT(!buf[min]);\
+ EXPECT(!memcmp(buf, (RESULT), min));\
+ }\
+ \
+ EXPECT(librecrypt_add_algorithm(NULL, 0u, (AUGEND), (AUGMENT), NULL) == r);\
+ \
+ assert(sizeof(buf) > strlen(AUGEND));\
+ stpcpy(buf, (AUGEND));\
+ \
+ EXPECT(librecrypt_add_algorithm(buf, sizeof(buf), buf, (AUGMENT), NULL) == r);\
+ EXPECT(!buf[r]);\
+ EXPECT(!memcmp(buf, (RESULT), (size_t)r));\
+ \
+ for (i = (size_t)r + 2u;; i--) {\
+ stpcpy(buf, (AUGEND));\
+ EXPECT(librecrypt_add_algorithm(buf, i, buf, (AUGMENT), NULL) == r);\
+ if (!i)\
+ break;\
+ min = i - 1u < (size_t)r ? i - 1u : (size_t)r;\
+ EXPECT(!buf[min]);\
+ EXPECT(!memcmp(buf, (RESULT), min));\
+ }\
+ } while (0)
+
+#if defined(SUPPORT_ARGON2I) && defined(SUPPORT_ARGON2D)
+
+ CHECK("$argon2d$v=16$m=8,t=1,p=1$*16$*40", "$argon2i$v=19$m=16,t=4,p=2$*18$*50",
+ "$argon2d$v=16$m=8,t=1,p=1$*16$*40>" "$argon2i$v=19$m=16,t=4,p=2$*18$*50");
+
+ CHECK("$argon2d$m=8,t=1,p=1$"SALT1"$*40", "$argon2i$m=8,t=4,p=2$"SALT2"$*50",
+ "$argon2d$m=8,t=1,p=1$"SALT1"$*40>" "$argon2i$m=8,t=4,p=2$"SALT2"$*50");
+
+ CHECK("$argon2d$m=8,t=1,p=1$"SALT1"$", "$argon2i$m=8,t=4,p=2$"SALT2"$",
+ "$argon2d$m=8,t=1,p=1$"SALT1"$>" "$argon2i$m=8,t=4,p=2$"SALT2"$");
+
+ CHECK("$argon2d$m=8,t=1,p=1$"SALT1"$*40", "$argon2i$m=8,t=4,p=2$"SALT2"$",
+ "$argon2d$m=8,t=1,p=1$"SALT1"$*40>" "$argon2i$m=8,t=4,p=2$"SALT2"$");
+
+ CHECK("$argon2d$m=8,t=1,p=1$"SALT1"$", "$argon2i$m=8,t=4,p=2$"SALT2"$*50",
+ "$argon2d$m=8,t=1,p=1$"SALT1"$>" "$argon2i$m=8,t=4,p=2$"SALT2"$*50");
+
+ CHECK("$argon2d$m=8,t=1,p=1$*16$", "$argon2i$m=8,t=4,p=2$"SALT2"$",
+ "$argon2d$m=8,t=1,p=1$*16$>" "$argon2i$m=8,t=4,p=2$"SALT2"$");
+
+ CHECK("$argon2d$m=8,t=1,p=1$*16$*50", "$argon2i$m=8,t=4,p=2$"SALT2"$",
+ "$argon2d$m=8,t=1,p=1$*16$*50>" "$argon2i$m=8,t=4,p=2$"SALT2"$");
+
+ CHECK("$argon2d$m=8,t=1,p=1$*16$", "$argon2i$m=8,t=4,p=2$"SALT2"$*60",
+ "$argon2d$m=8,t=1,p=1$*16$>" "$argon2i$m=8,t=4,p=2$"SALT2"$*60");
+
+ CHECK("$argon2d$m=8,t=1,p=1$"SALT1"$", "$argon2i$m=8,t=4,p=2$*20$",
+ "$argon2d$m=8,t=1,p=1$"SALT1"$>" "$argon2i$m=8,t=4,p=2$*20$");
+
+ CHECK("$argon2d$m=8,t=1,p=1$"SALT1"$*32", "$argon2i$m=8,t=4,p=2$*20$",
+ "$argon2d$m=8,t=1,p=1$"SALT1"$*32>" "$argon2i$m=8,t=4,p=2$*20$");
+
+ CHECK("$argon2d$m=8,t=1,p=1$"SALT1"$", "$argon2i$m=8,t=4,p=2$*20$*32",
+ "$argon2d$m=8,t=1,p=1$"SALT1"$>" "$argon2i$m=8,t=4,p=2$*20$*32");
+
+ lut = librecrypt_get_encoding("$argon2d$", sizeof("$argon2d$") - 1u, &pad, &strict_pad, 1);
+ assert(lut);
+ r = librecrypt_decode(phrase, sizeof(phrase), HASH1, strlen(HASH1), lut, pad, strict_pad);
+ assert(r > 0 && (size_t)r <= sizeof(phrase));
+ phraselen = (size_t)r;
+ stpcpy(expected, "$argon2d$m=8,t=1,p=1$"SALT1"$"ASTRA">$argon2i$m=8,t=4,p=1$"SALT2"$");
+ r = librecrypt_hash(&expected[strlen(expected)], sizeof(expected) - strlen(expected),
+ phrase, phraselen, "$argon2i$m=8,t=4,p=1$"SALT2"$*32", NULL);
+ assert(r > 0 && (size_t)r < sizeof(expected) - strlen(expected));
+ assert(!expected[strlen(expected) + (size_t)r]);
+ CHECK("$argon2d$m=8,t=1,p=1$"SALT1"$"HASH1, "$argon2i$m=8,t=4,p=1$"SALT2"$*32", expected);
+ CHECK("$argon2d$m=8,t=1,p=1$"SALT1"$"HASH1,
+ "$argon2i$m=8,t=4,p=1$"SALT2"$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", expected);
+
+#endif
+
STOP_RESOURCE_TEST();
return 0;
}
#endif
-/* TODO test */
+/* TODO test with hash but asterisk-salt on augend */
+/* TODO test with asterisk-salt on augment */
+/* TODO test with empty salt */
+/* TODO test with salts that are not multiple of 4 base64 characters */
+/* TODO test with hashes that are not multiple of 4 base64 characters */
diff --git a/librecrypt_fill_with_random_.c b/librecrypt_fill_with_random_.c
index 0d8dc78..1361652 100644
--- a/librecrypt_fill_with_random_.c
+++ b/librecrypt_fill_with_random_.c
@@ -99,7 +99,7 @@ main(void)
INIT_RESOURCE_TEST();
/* Check zero-request */
- EXPECT(librecrypt_fill_with_random_(NULL, 0, NULL, NULL) == 0);
+ EXPECT(librecrypt_fill_with_random_(NULL, 0u, NULL, NULL) == 0);
/* Check default RNG */
EXPECT(librecrypt_fill_with_random_(buf1, sizeof(buf1), NULL, NULL) == 0);
diff --git a/librecrypt_hash_.c b/librecrypt_hash_.c
index 14c709b..05f1743 100644
--- a/librecrypt_hash_.c
+++ b/librecrypt_hash_.c
@@ -397,7 +397,7 @@ main(void)
/* target settings_scratch */
errno = 0;
libtest_set_alloc_failure_in(1u);
- EXPECT(librecrypt_hash_(NULL, 0, "hello", 5u, ARGON2ID_PREFIX"*1000$", NULL, ASCII_CRYPT) == -1);
+ EXPECT(librecrypt_hash_(NULL, 0u, "hello", 5u, ARGON2ID_PREFIX"*1000$", NULL, ASCII_CRYPT) == -1);
EXPECT(errno == ENOMEM);
EXPECT(libtest_get_alloc_failure_in() == 0u);
diff --git a/librecrypt_make_settings.c b/librecrypt_make_settings.c
index 3efca4c..7688061 100644
--- a/librecrypt_make_settings.c
+++ b/librecrypt_make_settings.c
@@ -80,19 +80,19 @@ main(void)
INIT_RESOURCE_TEST();
errno = 0;
- EXPECT(librecrypt_make_settings(NULL, 0, ">", 0u, 0u, 0, NULL, NULL) == -1);
+ EXPECT(librecrypt_make_settings(NULL, 0u, ">", 0u, 0u, 0, NULL, NULL) == -1);
EXPECT(errno == EINVAL);
errno = 0;
- EXPECT(librecrypt_make_settings(NULL, 0, "$argon2id$>", 0u, 0u, 0, NULL, NULL) == -1);
+ EXPECT(librecrypt_make_settings(NULL, 0u, "$argon2id$>", 0u, 0u, 0, NULL, NULL) == -1);
EXPECT(errno == EINVAL);
errno = 0;
- EXPECT(librecrypt_make_settings(NULL, 0, ">$argon2id$", 0u, 0u, 0, NULL, NULL) == -1);
+ EXPECT(librecrypt_make_settings(NULL, 0u, ">$argon2id$", 0u, 0u, 0, NULL, NULL) == -1);
EXPECT(errno == EINVAL);
errno = 0;
- EXPECT(librecrypt_make_settings(NULL, 0, "$argon2id$>$argon2id$", 0u, 0u, 0, NULL, NULL) == -1);
+ EXPECT(librecrypt_make_settings(NULL, 0u, "$argon2id$>$argon2id$", 0u, 0u, 0, NULL, NULL) == -1);
EXPECT(errno == EINVAL);
errno = 0;
- EXPECT(librecrypt_make_settings(NULL, 0, "$~no~such~algorithm~$", 0u, 0u, 0, NULL, NULL) == -1);
+ EXPECT(librecrypt_make_settings(NULL, 0u, "$~no~such~algorithm~$", 0u, 0u, 0, NULL, NULL) == -1);
EXPECT(errno == ENOSYS);
#if defined(SUPPORT_ARGON2I)
@@ -136,7 +136,7 @@ main(void)
#endif
if (any_supported) {
- EXPECT(librecrypt_make_settings(NULL, 0, NULL, 0u, 0u, 0, NULL, NULL) > 0);
+ EXPECT(librecrypt_make_settings(NULL, 0u, NULL, 0u, 0u, 0, NULL, NULL) > 0);
EXPECT(librecrypt_make_settings(buf, sizeof(buf), NULL, 0u, 0u, 0, NULL, NULL) > 0);
if (any_salted) {
@@ -169,7 +169,7 @@ main(void)
EXPECT(strcmp(buf, buf2));
} else {
errno = 0;
- EXPECT(librecrypt_make_settings(NULL, 0, NULL, 0u, 0u, 0, NULL, NULL) == -1);
+ EXPECT(librecrypt_make_settings(NULL, 0u, NULL, 0u, 0u, 0, NULL, NULL) == -1);
EXPECT(errno == ENOSYS);
}
diff --git a/libtest/common.h b/libtest/common.h
index 54456d2..e4344a9 100644
--- a/libtest/common.h
+++ b/libtest/common.h
@@ -157,9 +157,9 @@ extern struct meminfo libtest_allocs_tail;
extern int libtest_allocs_list_inited;
extern atomic_flag libtest_allocs_list_spinlock;
-extern int libtest_zero_on_alloc;
-extern int libtest_expect_zeroed;
-extern int libtest_malloc_accept_leakage;
+extern _Thread_local int libtest_zero_on_alloc;
+extern _Thread_local int libtest_expect_zeroed;
+extern _Thread_local int libtest_malloc_accept_leakage;
extern _Thread_local size_t libtest_malloc_internal_usage;
extern _Thread_local size_t libtest_kill_malloc_tracking;
diff --git a/libtest/globals.c b/libtest/globals.c
index cf8164e..e5229a1 100644
--- a/libtest/globals.c
+++ b/libtest/globals.c
@@ -30,9 +30,9 @@ struct meminfo libtest_allocs_tail;
int libtest_allocs_list_inited = 0;
atomic_flag libtest_allocs_list_spinlock = ATOMIC_FLAG_INIT;
-int libtest_zero_on_alloc = 0;
-int libtest_expect_zeroed = 0;
-int libtest_malloc_accept_leakage = 1;
+_Thread_local int libtest_zero_on_alloc = 0;
+_Thread_local int libtest_expect_zeroed = 0;
+_Thread_local int libtest_malloc_accept_leakage = 1;
_Thread_local size_t libtest_malloc_internal_usage = 0u;
_Thread_local size_t libtest_kill_malloc_tracking = 0u;
diff --git a/libtest/libtest.h b/libtest/libtest.h
index 8f44114..e4b4098 100644
--- a/libtest/libtest.h
+++ b/libtest/libtest.h
@@ -7,18 +7,27 @@
/**
* Start tracking resources which `libtest_check_no_leaks`
* will detect if they are not released
+ *
+ * Memory resource tracking will only be started for the
+ * calling thread
*/
void libtest_start_tracking(void);
/**
* Stop tracking resources, so that `libtest_check_no_leaks`
* will not detect if they are not released
+ *
+ * Memory resource tracking will only be stop for the
+ * calling thread
*/
void libtest_stop_tracking(void);
/**
* Check for resource leaks
*
+ * Memory leaks are detected for all threads with
+ * tracking enabled, not just the calling thread
+ *
* Any leak will be printed to standard error
*
* @return 1 if there was no leaks, 0 otherwise
@@ -30,6 +39,8 @@ int libtest_check_no_leaks(void);
* Make all overriden memory allocation functions
* full the usable memory area with null bytes,
* or disable this feature
+ *
+ * The setting applies only to the calling thread
*
* @param enabled 1 to enable, 0 to disable
*/
@@ -40,6 +51,8 @@ void libtest_force_zero_on_alloc(int enabled);
* check that the entire usable memory area is filled
* with null bytes, or disable this feature
*
+ * The setting applies only to the calling thread
+ *
* @param enabled 1 to enable, 0 to disable
*/
void libtest_expect_zeroed_on_free(int enabled);
diff --git a/libtest/libtest_fd_tracking.c b/libtest/libtest_fd_tracking.c
index d3c766c..25cea8f 100644
--- a/libtest/libtest_fd_tracking.c
+++ b/libtest/libtest_fd_tracking.c
@@ -11,6 +11,9 @@ struct fd {
static size_t nopened = 0u;
static struct fd *opened = NULL;
+static atomic_flag spinlock = ATOMIC_FLAG_INIT;
+static int tracking_state = -1;
+
static int
cmp_fd(const void *av, const void *bv)
@@ -60,6 +63,14 @@ libtest_fd_tracking(int action)
int accept_memleak = libtest_malloc_accept_leakage;
size_t i, j;
char *path;
+ int old_tracking_state;
+
+ SPINLOCK(spinlock);
+ old_tracking_state = tracking_state;
+ tracking_state = action;
+ SPINUNLOCK(spinlock);
+ if (old_tracking_state == action)
+ return 1;
/* so libtest doesn't complain about us not zeroing before freeing,
* and so it will not report memory leaks in fprintf from our
diff --git a/libtest/libtest_free.c b/libtest/libtest_free.c
index 3e84ba6..bdc214b 100644
--- a/libtest/libtest_free.c
+++ b/libtest/libtest_free.c
@@ -57,6 +57,16 @@ libtest_free(void *ptr, enum libtest_zero_check zero_checking)
break;
}
}
+ if (!memory_zeroed && mem->backtrace) {
+ libtest_malloc_internal_usage++;
+ inside_free = 1;
+ fprintf(stderr, "Memory not zeroed out before deallocation: %p\n", ptr);
+#ifdef WITH_BACKTRACE
+ libtest_print_backtrace(stderr, "\tAllocated at ", "\t at ",
+ 0u, mem->backtrace, NULL);
+#endif
+ inside_free = 0;
+ }
assert(memory_zeroed);
}
diff --git a/libtest/libtest_print_backtrace.c b/libtest/libtest_print_backtrace.c
index e595131..7bc465c 100644
--- a/libtest/libtest_print_backtrace.c
+++ b/libtest/libtest_print_backtrace.c
@@ -19,6 +19,7 @@ libtest_print_backtrace(FILE *fp, const char *prefix, const char *indent, size_t
unw_context_t context;
Dwarf_Addr ip;
size_t i;
+ unsigned int old_alarm;
#if defined(HAVE_LINE_INFO)
Dwfl_Callbacks callbacks;
char *debuginfo_path = NULL;
@@ -32,6 +33,9 @@ libtest_print_backtrace(FILE *fp, const char *prefix, const char *indent, size_t
if (recursion_guard)
return;
+
+ old_alarm = alarm(1u);
+
saved_errno = errno;
recursion_guard = 1;
libtest_malloc_internal_usage++;
@@ -121,6 +125,8 @@ out:
libtest_malloc_internal_usage--;
recursion_guard = 0;
errno = saved_errno;
+
+ alarm(old_alarm);
}