diff options
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | Makefile | 48 | ||||
| -rw-r--r-- | argon2/hash.c | 61 | ||||
| -rw-r--r-- | common.h | 33 | ||||
| -rw-r--r-- | config-fuzz-clang.mk | 14 | ||||
| -rw-r--r-- | librecrypt.h | 110 | ||||
| -rw-r--r-- | librecrypt_add_algorithm.3 | 3 | ||||
| -rw-r--r-- | librecrypt_add_algorithm.c | 22 | ||||
| -rw-r--r-- | librecrypt_chain_length.c | 17 | ||||
| -rw-r--r-- | librecrypt_check_settings_.c | 2 | ||||
| -rw-r--r-- | librecrypt_crypt.3 | 3 | ||||
| -rw-r--r-- | librecrypt_crypt.c | 35 | ||||
| -rw-r--r-- | librecrypt_decompose_chain.c | 34 | ||||
| -rw-r--r-- | librecrypt_decompose_chain1.c | 22 | ||||
| -rw-r--r-- | librecrypt_encode.3 | 25 | ||||
| -rw-r--r-- | librecrypt_encode.c | 29 | ||||
| -rw-r--r-- | librecrypt_hash.3 | 3 | ||||
| -rw-r--r-- | librecrypt_hash.c | 21 | ||||
| -rw-r--r-- | librecrypt_hash_.c | 35 | ||||
| -rw-r--r-- | librecrypt_hash_binary.3 | 3 | ||||
| -rw-r--r-- | librecrypt_next_algorithm.c | 25 | ||||
| -rw-r--r-- | librecrypt_settings_prefix.c | 21 | ||||
| -rw-r--r-- | libtest/common.h | 2 | ||||
| -rw-r--r-- | libtest/globals.c | 4 | ||||
| -rw-r--r-- | libtest/libtest.h | 2 | ||||
| -rw-r--r-- | libtest/libtest_alloc.c | 58 | ||||
| -rw-r--r-- | libtest/libtest_free.c | 10 | ||||
| -rw-r--r-- | libtest/mmap.c | 2 |
28 files changed, 554 insertions, 92 deletions
@@ -14,3 +14,5 @@ *.gcov *.gcno *.gcda +*.f +*.fo @@ -19,19 +19,28 @@ LIB_VERSION = $(LIB_MAJOR).$(LIB_MINOR) LIB_NAME = recrypt -OBJ_PUBLIC =\ +OBJ_PUBLIC_FUZZ =\ librecrypt_settings_prefix.o\ + +OBJ_PUBLIC_NO_FUZZ =\ librecrypt_chain_length.o\ librecrypt_decompose_chain.o\ librecrypt_decompose_chain1.o\ - librecrypt_next_algorithm.o\ - librecrypt_encode.o\ - librecrypt_decode.o\ - librecrypt_get_encoding.o\ + librecrypt_next_algorithm.o + +OBJ_PUBLIC_NO_FUZZ =\ librecrypt_wipe.o\ librecrypt_wipe_str.o\ librecrypt_equal_binary.o\ - librecrypt_equal.o\ + librecrypt_equal.o + +OBJ_PUBLIC =\ + $(OBJ_PUBLIC_FUZZ)\ + $(OBJ_PUBLIC_DONT_FUZZ)\ + $(OBJ_PUBLIC_NO_FUZZ)\ + librecrypt_encode.o\ + librecrypt_decode.o\ + librecrypt_get_encoding.o\ librecrypt_realise_salts.o\ librecrypt_make_settings.o\ librecrypt_hash_binary.o\ @@ -63,6 +72,8 @@ HDR =\ LOBJ = $(OBJ:.o=.lo) TOBJ = $(OBJ:.o=.to) TEST = $(OBJ:.o=.t) +FOBJ = $(OBJ_PUBLIC_FUZZ:.o=.fo) +FUZZ = $(OBJ_PUBLIC_FUZZ:.o=.f) MAN3 = $(OBJ_PUBLIC:.o=.3) MAN7 = librecrypt.7 @@ -70,9 +81,9 @@ all: include argon2/suffix.mk -ALL_CFLAGS = $(CFLAGS) $(CFLAGS_MODULES) -ALL_CPPFLAGS = $(CPPFLAGS) $(CPPFLAGS_MODULES) -ALL_LDFLAGS = $(LDFLAGS) $(LDFLAGS_MODULES) +ALL_CPPFLAGS = $(CPPFLAGS) $(CPPFLAGS_MODULES) $(FUZZED_CPPFLAGS) +ALL_CFLAGS = $(CFLAGS) $(CFLAGS_MODULES) $(FUZZED_CFLAGS) +ALL_LDFLAGS = $(LDFLAGS) $(LDFLAGS_MODULES) $(FUZZED_LDFLAGS) TEST_INCLUDE_PREFIX = libtest/ include libtest/config.mk @@ -83,6 +94,7 @@ $(OBJ): $(HDR) $(LOBJ): $(HDR) $(TOBJ): $(HDR) libtest/libtest.h $(TEST): $(HDR) librecrypt.a libtest/libtest.a libtest/libtest.h +$(FUZZ): $(HDR) librecrypt.a libtest/libtest.a libtest/libtest.h .c.o: $(CC) -c -o $@ $< $(ALL_CFLAGS) $(COV_CFLAGS) $(ALL_CPPFLAGS) $(COV_CPPFLAGS) @@ -96,6 +108,12 @@ $(TEST): $(HDR) librecrypt.a libtest/libtest.a libtest/libtest.h .to.t: $(CC) -o $@ $< librecrypt.a libtest/libtest.a $(G) $(ALL_LDFLAGS) $(TEST_LDFLAGS) $(COV_LDFLAGS) +.c.fo: + $(CC) -DTEST -DFUZZ -c -o $@ $< $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(FUZZ_CFLAGS) $(FUZZ_CPPFLAGS) + +.fo.f: + $(CC) -o $@ $< librecrypt.a libtest/libtest.a $(G) $(ALL_LDFLAGS) $(TEST_LDFLAGS) $(FUZZ_LDFLAGS) + librecrypt.a: $(OBJ) @rm -f -- $@ $(AR) rc $@ $(OBJ) @@ -117,6 +135,12 @@ check: $(TEST) # (specially to use valgrind(1)) may limit what the test code # is able to test +fuzz: $(FUZZ) + @set -ex;\ + for f in $(FUZZ); do\ + $(FUZZ_PREFIX) ./$$f $(FUZZ_SUFFIX);\ + done + install: librecrypt.a librecrypt.$(LIBEXT) mkdir -p -- "$(DESTDIR)$(PREFIX)/lib" mkdir -p -- "$(DESTDIR)$(PREFIX)/include" @@ -144,10 +168,10 @@ clean: +cd libtest && $(MAKE) clean -rm -f -- *.o *.a *.lo *.su *.so *.so.* *.dll *.dylib -rm -f -- *.gch *.gcov *.gcno *.gcda *.$(LIBEXT) - -rm -f -- *.to *.t + -rm -f -- *.to *.t *.fo *.f .SUFFIXES: -.SUFFIXES: .lo .o .c .to .t +.SUFFIXES: .lo .o .c .to .t .fo .f -.PHONY: all check install uninstall clean +.PHONY: all check fuzz install uninstall clean .PHONY: libtest/libtest.a diff --git a/argon2/hash.c b/argon2/hash.c index 9c65e6a..a40e54c 100644 --- a/argon2/hash.c +++ b/argon2/hash.c @@ -74,7 +74,7 @@ librecrypt__argon2__hash(char *restrict out_buffer, size_t size, const char *phr /* Decode salt */ if (!salt_encoded) /* this would be if asterisk-notation is used, but it is not */ abort(); /* $covered$ */ - r = librecrypt_decode(NULL, 0u, salt_encoded, saltlen, BASE64); + r = librecrypt_decode(NULL, 0u, salt_encoded, (size_t)saltlen, BASE64); if (r < 0) return -1; /* $covered$ (impossible) */ if (r > 0) { @@ -90,7 +90,7 @@ librecrypt__argon2__hash(char *restrict out_buffer, size_t size, const char *phr salt = malloc((size_t)r); if (!salt) return -1; - if (librecrypt_decode(salt, (size_t)r, salt_encoded, saltlen, BASE64) != r) + if (librecrypt_decode(salt, (size_t)r, salt_encoded, (size_t)saltlen, BASE64) != r) abort(); /* $covered$ (impossible) */ saltlen = (uintmax_t)r; } @@ -116,6 +116,19 @@ librecrypt__argon2__hash(char *restrict out_buffer, size_t size, const char *phr /* Argon2 may require a larger buffer to work with for the hash than it outputs */ scratch_size = libar2_hash_buf_size(¶ms); +#if SIZE_MAX > UINT32_MAX + /* $covered{$ (impossible) */ + if (!scratch_size) { + errno = ENOMEM; + goto fail; + } + /* $covered}$ */ +#else + if (!scratch_size) { + errno = ENOMEM; + goto fail; + } +#endif if (scratch_size > size) { scratch = malloc(scratch_size); if (!scratch) @@ -123,8 +136,12 @@ librecrypt__argon2__hash(char *restrict out_buffer, size_t size, const char *phr } /* Calculate hash */ +#ifndef FUZZ if (libar2_hash(scratch ? scratch : out_buffer, REMOVE_CONST(phrase), len, ¶ms, &ctx)) goto fail; +#else + memset(scratch ? scratch : out_buffer, '5', scratch_size); +#endif if (scratch && out_buffer) memcpy(out_buffer, scratch, MIN(params.hashlen, size)); @@ -146,7 +163,7 @@ fail: free(scratch); } if (salt) { - librecrypt_wipe(salt, saltlen); + librecrypt_wipe(salt, (size_t)saltlen); free(salt); } errno = saved_errno; @@ -198,7 +215,6 @@ check(const char *phrase, const char *settings, const char *hash, size_t hashlen EXPECT(!memcmp(expected, buf, MIN(i, hashlen))); CANARY_X_CHECK(buf, MIN(i, hashlen), scratchsize); } - } @@ -266,6 +282,11 @@ check(const char *phrase, const char *settings, const char *hash, size_t hashlen } while (0) +#define phony librecrypt_test_phony__ +extern void *volatile librecrypt_test_phony__; +void *volatile librecrypt_test_phony__ = (void *)(uintptr_t)4096u; + + int main(void) { @@ -277,6 +298,38 @@ main(void) #define GET_SCRATCH_SIZE(HASHLEN) ((HASHLEN) > 64u ? ((HASHLEN) + 63u) & ~31u : (HASHLEN)) #if defined(SUPPORT_ARGON2I) +# if SIZE_MAX > UINT32_MAX + errno = 0; + EXPECT(librecrypt__argon2__hash(NULL, 0u, phony, (size_t)UINT32_MAX + 1u, "$argon2i$m=256,t=2,p=1$c29tZXNhbHQ$", + sizeof("$argon2i$m=256,t=2,p=1$c29tZXNhbHQ$"), NULL) == -1); + EXPECT(errno == EINVAL); +#else + if (libtest_have_custom_malloc()) { + char conf[256]; + int r; + + r = snprintf(conf, sizeof(conf), "$argon2i$m=256,t=2,p=1$c29tZXNhbHQ$%*zu", (size_t)UINT32_MAX); + assert(r > 0); + assert(r < sizeof(conf)); + libtest_set_alloc_failure_in(1u); + errno = 0; + EXPECT(librecrypt__argon2__hash(NULL, 0u, NULL, 0u, conf, strlen(conf), NULL) == -1); + EXPECT(errno == ENOMEM); + EXPECT(libtest_get_alloc_failure_in() == 0u); + libtest_set_alloc_failure_in(0u); + + r = snprintf(conf, sizeof(conf), "$argon2i$m=256,t=2,p=1$c29tZXNhbHQ$%*zu", (size_t)UINT32_MAX + 1u); + assert(r > 0); + assert(r < sizeof(conf)); + libtest_set_alloc_failure_in(1u); + errno = 0; + EXPECT(librecrypt__argon2__hash(NULL, 0u, NULL, 0u, conf, strlen(conf), NULL) == -1); + EXPECT(errno == ENOMEM); + EXPECT(libtest_get_alloc_failure_in() == 1u); + libtest_set_alloc_failure_in(0u); + } + +# endif CHECK("password", "$argon2i$" "m=256,t=2,p=1$c29tZXNhbHQ$", 32, "/U3YPXYsSb3q9XxHvc0MLxur+GP960kN9j7emXX8zwY"); CHECK("password", "$argon2i$v=19$m=256,t=2,p=1$c29tZXNhbHQ$", 32, "iekCn0Y3spW+sCcFanM2xBT63UP2sghkUoHLIUpWRS8"); CHECK_BAD("$argon2i$"); @@ -1,4 +1,19 @@ /* See LICENSE file for copyright and license details. */ +#if defined(__clang__) +# pragma clang diagnostic ignored "-Wunsafe-buffer-usage" /* completely broken */ +# pragma clang diagnostic ignored "-Wpadded" /* don't care */ +# pragma clang diagnostic ignored "-Wdisabled-macro-expansion" /* glibc issue */ +# pragma clang diagnostic ignored "-Wc11-extensions" /* glibc issue */ +# pragma clang diagnostic ignored "-Wpre-c11-compat" /* glibc issue */ +# pragma clang diagnostic ignored "-Wunknown-warning-option" /* ignoring -Wsuggest-attribute=const|pure */ +# pragma clang diagnostic ignored "-Wimplicit-void-ptr-cast" /* C++ warning, and we are in internal files */ +# pragma clang diagnostic ignored "-Wc++-keyword" /* C++ warning, and we are in internal files */ +# pragma clang diagnostic ignored "-Wc++-unterminated-string-initialization" /* Stupid C++ warning, and we are in internal files */ +#endif +#if defined(__GNUC__) +# pragma GCC diagnostic ignored "-Winline" +#endif + #include "librecrypt.h" #if defined(__linux__) # include <sys/auxv.h> @@ -15,20 +30,6 @@ #include <unistd.h> -#if defined(__clang__) -# pragma clang diagnostic ignored "-Wunsafe-buffer-usage" /* completely broken */ -# pragma clang diagnostic ignored "-Wpadded" /* don't care */ -# pragma clang diagnostic ignored "-Wdisabled-macro-expansion" /* glibc issue */ -# pragma clang diagnostic ignored "-Wc11-extensions" /* glibc issue */ -# pragma clang diagnostic ignored "-Wunknown-warning-option" /* ignoring -Wsuggest-attribute=const|pure */ -# pragma clang diagnostic ignored "-Wimplicit-void-ptr-cast" /* C++ warning, and we are in internal files */ -# pragma clang diagnostic ignored "-Wc++-keyword" /* C++ warning, and we are in internal files */ -#endif -#if defined(__GNUC__) -# pragma GCC diagnostic ignored "-Winline" -#endif - - #if defined(__GNUC__) # define HIDDEN __attribute__((__visibility__("hidden"))) # define CONST __attribute__((__const__)) @@ -40,8 +41,8 @@ #endif #define NONSTRING -#if defined(__GNUC__) && !defined(__clang__) -# if __GNUC__ >= 8 +#if defined(__GNUC__) +# if __GNUC__ >= 8 || defined(__clang__) # undef NONSTRING # define NONSTRING __attribute__((__nonstring__)) # endif diff --git a/config-fuzz-clang.mk b/config-fuzz-clang.mk new file mode 100644 index 0000000..f5a1898 --- /dev/null +++ b/config-fuzz-clang.mk @@ -0,0 +1,14 @@ +CONFIGFILE_PROPER = config.mk +include $(CONFIGFILE_PROPER) + +CC = $(CC_PREFIX)clang -std=c99 + +SANITIZE = $(CLANG_SANITIZE) +FUZZ_CFLAGS = -fsanitize=fuzzer +FUZZ_LDFLAGS = -fsanitize=fuzzer +FUZZED_CPPFLAGS = -DFUZZ + +all: fuzz + +# These configurations will modify the library code +# so that it doesn't perform password hashing !!!!! diff --git a/librecrypt.h b/librecrypt.h index 5ffb111..48d2ff7 100644 --- a/librecrypt.h +++ b/librecrypt.h @@ -276,8 +276,18 @@ librecrypt_next_algorithm(char **hash) * @param lut The encoding alphabet, consisting of 64 characters, * repeated 4 times * @param pad The padding character to use at the end; the NUL byte if none - * @return The number of bytes that would have been written to `out_buffer`, - * excluding the terminating NUL byte, if `size` was sufficiently large + * @return len_out The number of bytes that would have been written to `out_buffer`, + * excluding the terminating NUL byte, if `size` was sufficiently + * large; `SIZE_MAX` is returned on failure + * + * @throws EOVERFLOW The for value `*len_out` cannot be represented + * because it is greater than `SIZE_MAX` (`len` is + * too great) + * + * Despite being used as the failure indicator, `SIZE_MAX` + * is a legal return value on successful, is and returned + * (without modifying `errno`) when `pad` is the NUL byte + * and `len` is (`SIZE_MAX` - 3) / 4 * 3 + 2 * * On successful completion, the N bytes is written to * `out_buffer` where N is the lesser of `size` and 1 in @@ -607,18 +617,19 @@ ssize_t librecrypt_make_settings(char *out_buffer, size_t size, const char *algo * @return The number of bytes that would have been written to `out_buffer` * if `size` was sufficiently large; -1 on failure * - * @throws EINVAL `reserved` is non-`NULL` (this case will be removed - * once `reserved` as being used by the library) - * @throws EINVAL `settings` is invalid (invalid algorithm configuration, - * invalid configuration syntax, or the output from one - * chained hash algorithm cannot be input the next algorithm - * in the chain (either because of format or length issues)) - * @throws EINVAL `settings` uses asterisk-encoding to specify random salts - * @throws ERANGE `len` is too large or too small for the the selected - * initial algorithm in the algorithm chain - * @throws ENOMEM Failed to allocate internal scratch memory - * @throws ENOSYS A selected hash algorithm is either not recognised - * disabled at compile-time + * @throws EINVAL `reserved` is non-`NULL` (this case will be removed + * once `reserved` as being used by the library) + * @throws EINVAL `settings` is invalid (invalid algorithm configuration, + * invalid configuration syntax, or the output from one + * chained hash algorithm cannot be input the next algorithm + * in the chain (either because of format or length issues)) + * @throws EINVAL `settings` uses asterisk-encoding to specify random salts + * @throws ERANGE `len` is too large or too small for the the selected + * initial algorithm in the algorithm chain + * @throws EOVERFLOW The expected return value is greater than {SSIZE_MAX} + * @throws ENOMEM Failed to allocate internal scratch memory + * @throws ENOSYS A selected hash algorithm is either not recognised + * disabled at compile-time * * Any encountered `EINTR` is ignored * @@ -659,18 +670,19 @@ ssize_t librecrypt_hash_binary(char *restrict out_buffer, size_t size, const cha * if `size` was sufficiently large, excluding a terminating * NUL byte; -1 on failure * - * @throws EINVAL `reserved` is non-`NULL` (this case will be removed - * once `reserved` as being used by the library) - * @throws EINVAL `settings` is invalid (invalid algorithm configuration, - * invalid configuration syntax, or the output from one - * chained hash algorithm cannot be input the next algorithm - * in the chain (either because of format or length issues)) - * @throws EINVAL `settings` uses asterisk-encoding to specify random salts - * @throws ERANGE `len` is too large or too small for the the selected - * initial algorithm in the algorithm chain - * @throws ENOMEM Failed to allocate internal scratch memory - * @throws ENOSYS A selected hash algorithm is either not recognised - * disabled at compile-time + * @throws EINVAL `reserved` is non-`NULL` (this case will be removed + * once `reserved` as being used by the library) + * @throws EINVAL `settings` is invalid (invalid algorithm configuration, + * invalid configuration syntax, or the output from one + * chained hash algorithm cannot be input the next algorithm + * in the chain (either because of format or length issues)) + * @throws EINVAL `settings` uses asterisk-encoding to specify random salts + * @throws ERANGE `len` is too large or too small for the the selected + * initial algorithm in the algorithm chain + * @throws EOVERFLOW The expected return value is greater than {SSIZE_MAX} + * @throws ENOMEM Failed to allocate internal scratch memory + * @throws ENOSYS A selected hash algorithm is either not recognised + * disabled at compile-time * * Any encountered `EINTR` is ignored * @@ -716,17 +728,18 @@ ssize_t librecrypt_hash(char *restrict out_buffer, size_t size, const char *phra * if `size` was sufficiently large, excluding a terminating * NUL byte; -1 on failure * - * @throws EINVAL `reserved` is non-`NULL` (this case will be removed - * once `reserved` as being used by the library) - * @throws EINVAL `settings` is invalid (invalid algorithm configuration, - * invalid configuration syntax, or the output from one - * chained hash algorithm cannot be input the next algorithm - * in the chain (either because of format or length issues)) - * @throws ERANGE `len` is too large or too small for the the selected - * initial algorithm in the algorithm chain - * @throws ENOMEM Failed to allocate internal scratch memory - * @throws ENOSYS A selected hash algorithm is either not recognised - * disabled at compile-time + * @throws EINVAL `reserved` is non-`NULL` (this case will be removed + * once `reserved` as being used by the library) + * @throws EINVAL `settings` is invalid (invalid algorithm configuration, + * invalid configuration syntax, or the output from one + * chained hash algorithm cannot be input the next algorithm + * in the chain (either because of format or length issues)) + * @throws ERANGE `len` is too large or too small for the the selected + * initial algorithm in the algorithm chain + * @throws EOVERFLOW The expected return value is greater than {SSIZE_MAX} + * @throws ENOMEM Failed to allocate internal scratch memory + * @throws ENOSYS A selected hash algorithm is either not recognised + * disabled at compile-time * * Any encountered `EINTR` is ignored * @@ -813,17 +826,18 @@ int librecrypt_test_supported(const char *phrase, size_t len, int text, const ch * if `size` was sufficiently large, excluding a terminating * NUL byte; -1 on failure * - * @throws EINVAL `reserved` is non-`NULL` (this case will be removed - * once `reserved` as being used by the library) - * @throws EINVAL `settings` is invalid (invalid algorithm configuration, - * invalid configuration syntax, or the output from one - * chained hash algorithm cannot be input the next algorithm - * in the chain (either because of format or length issues)) - * @throws ERANGE `len` is too large or too small for the the selected - * initial algorithm in the algorithm chain - * @throws ENOMEM Failed to allocate internal scratch memory - * @throws ENOSYS A selected hash algorithm is either not recognised - * disabled at compile-time + * @throws EINVAL `reserved` is non-`NULL` (this case will be removed + * once `reserved` as being used by the library) + * @throws EINVAL `settings` is invalid (invalid algorithm configuration, + * invalid configuration syntax, or the output from one + * chained hash algorithm cannot be input the next algorithm + * in the chain (either because of format or length issues)) + * @throws ERANGE `len` is too large or too small for the the selected + * initial algorithm in the algorithm chain + * @throws EOVERFLOW The expected return value is greater than {SSIZE_MAX}. + * @throws ENOMEM Failed to allocate internal scratch memory + * @throws ENOSYS A selected hash algorithm is either not recognised + * disabled at compile-time * * On successful completion, the N bytes is written to * `out_buffer` where N is the lesser of `size` and 1 in diff --git a/librecrypt_add_algorithm.3 b/librecrypt_add_algorithm.3 index 2c7b365..8eaabfd 100644 --- a/librecrypt_add_algorithm.3 +++ b/librecrypt_add_algorithm.3 @@ -97,6 +97,9 @@ is invalid. .B ERANGE The selected initial algorithm requires a different password length. .TP +.B EOVERFLOW +The expected return value is greater than {SSIZE_MAX}. +.TP .B ENOMEM Failed to allocate internal scratch memory. .TP diff --git a/librecrypt_add_algorithm.c b/librecrypt_add_algorithm.c index 4c6520e..ad21ec4 100644 --- a/librecrypt_add_algorithm.c +++ b/librecrypt_add_algorithm.c @@ -62,6 +62,8 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, const char *augend, cons r_int = snprintf(out_buffer, size + 1u, "*%zu", hashsize2); if (r_int < 2) abort(); /* $covered$ (impossible reliably) */ + if (ret > SIZE_MAX - (size_t)r_int) + abort(); /* $covered$ (impossible) */ ret += (size_t)r_int; } else { out_buffer[0u] = '\0'; @@ -79,11 +81,19 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, const char *augend, cons r_int = snprintf(NULL, 0u, "*%zu", hashsize2); if (r_int < 2) abort(); /* $covered$ (impossible reliably) */ + if (ret > SIZE_MAX - (size_t)r_int) + abort(); /* $covered$ (impossible) */ ret += (size_t)r_int; out: if (nul_term) out_buffer[0u] = '\0'; } + if (ret > (size_t)SSIZE_MAX) { + /* $covered{$ (manually) */ + errno = EOVERFLOW; + return -1; + /* $covered}$ */ + } return (ssize_t)ret; } @@ -96,7 +106,9 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, const char *augend, cons r_int = 0; } - /* Measure `augent` and '>' in output */ + /* Measure `augend` and '>' in output */ + if (prefix1 > SIZE_MAX - 1u - (size_t)r_int) + abort(); /* $covered$ (impossible) */ ret = prefix1 + (size_t)r_int + 1u; /* Decode the hash from base-64 to binary */ @@ -160,6 +172,14 @@ librecrypt_add_algorithm(char *out_buffer, size_t size, const char *augend, cons abort(); /* $covered$ (impossible) */ return -1; } + if (ret > (size_t)(SSIZE_MAX - r)) { + /* $covered{$ (manually) */ + librecrypt_wipe(phrase, phraselen); + free(phrase); + errno = EOVERFLOW; + return -1; + /* $covered}$ */ + } ret += (size_t)r; librecrypt_wipe(phrase, phraselen); diff --git a/librecrypt_chain_length.c b/librecrypt_chain_length.c index e43aaf9..364186a 100644 --- a/librecrypt_chain_length.c +++ b/librecrypt_chain_length.c @@ -7,6 +7,7 @@ extern inline size_t librecrypt_chain_length(const char *hash); #else +# ifndef FUZZ int @@ -29,4 +30,20 @@ main(void) } +# else + + +extern volatile size_t discarded_return_value; +volatile size_t discarded_return_value; + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + (void) size; + discarded_return_value = librecrypt_chain_length((const void *)data); + return 0; +} + + +# endif #endif diff --git a/librecrypt_check_settings_.c b/librecrypt_check_settings_.c index 2c544b2..0cfed69 100644 --- a/librecrypt_check_settings_.c +++ b/librecrypt_check_settings_.c @@ -75,7 +75,7 @@ check_uint(const char *settings, size_t *off, size_t len, char min_first_digit, * @param max The most allowed number of bytes * @param allow_empty Whether the empty string is allowed * (no encoded bytes and no asterisk-notation) - * @param lut Alphabet reverse lookup table, shall map any valid + * @param dlut Alphabet reverse lookup table, shall map any valid * character (except the padding character) to the value * of that character in the encoding alphabet, and map * any other character to the value `0xFF` diff --git a/librecrypt_crypt.3 b/librecrypt_crypt.3 index 0237862..fd4b03a 100644 --- a/librecrypt_crypt.3 +++ b/librecrypt_crypt.3 @@ -93,6 +93,9 @@ is invalid. is too large or too small for the selected initial algorithm. .TP +.B EOVERFLOW +The expected return value is greater than {SSIZE_MAX}. +.TP .B ENOMEM Failed to allocate internal scratch memory. .TP diff --git a/librecrypt_crypt.c b/librecrypt_crypt.c index d116f87..893c96f 100644 --- a/librecrypt_crypt.c +++ b/librecrypt_crypt.c @@ -98,7 +98,7 @@ check(const char *phrase, const char *settings, const char *chain, size_t chain_ int main(void) { - char buf[1024], buf2[1024]; + char buf[1024], buf2[1024], conf[256]; ssize_t r; SET_UP_ALARM(); @@ -111,6 +111,39 @@ main(void) #define GET_SCRATCH_SIZE(HASHLEN) ((HASHLEN) > 64u ? ((HASHLEN) + 63u) & ~31u : (HASHLEN)) #if defined(SUPPORT_ARGON2I) + r = snprintf(conf, sizeof(conf), "$argon2i$m=256,t=8,p=1$AAAABBBBCCCC$*%zu", SIZE_MAX / 4u * 3u + 3u); + assert(r > 0 && (size_t)r < sizeof(conf)); + errno = 0; + EXPECT(librecrypt_crypt(NULL, 0u, NULL, 0u, conf, NULL) == -1); +# if SIZE_MAX > UINT32_MAX + EXPECT(errno == EINVAL); +# else + EXPECT(errno == EOVERFLOW); + if (libtest_have_custom_malloc()) { + libtest_pretend_allocation_successful = 1; + errno = 0; + EXPECT(librecrypt_crypt(buf, sizeof(buf), NULL, 0u, conf, NULL) == -1); + libtest_pretend_allocation_successful = 0; + EXPECT(errno == EOVERFLOW); + } +# endif + +# if SIZE_MAX == UINT32_MAX + r = snprintf(conf, sizeof(conf), "$argon2i$m=256,t=8,p=1$AAAABBBBCCCC$*%zu", (SIZE_MAX / 4u * 3u) / 2u); + assert(r > 0 && (size_t)r < sizeof(conf)); + errno = 0; + EXPECT(librecrypt_crypt(NULL, 0u, NULL, 0u, conf, NULL) == -1); + EXPECT(errno == EOVERFLOW); +# endif + +# if SIZE_MAX == UINT32_MAX + r = snprintf(conf, sizeof(conf), "$argon2i$m=256,t=8,p=1$AAAABBBBCCCC$*%zu", SIZE_MAX / 4u * 3u); + assert(r > 0 && (size_t)r < sizeof(conf)); + errno = 0; + EXPECT(librecrypt_crypt(NULL, 0u, NULL, 0u, conf, NULL) == -1); + EXPECT(errno == EOVERFLOW); +# endif + CHECK("password", "$argon2i$" "m=256,t=2,p=1$c29tZXNhbHQ$", 32, 1, "/U3YPXYsSb3q9XxHvc0MLxur+GP960kN9j7emXX8zwY"); CHECK("password", "$argon2i$v=19$m=256,t=2,p=1$c29tZXNhbHQ$", 32, 1, "iekCn0Y3spW+sCcFanM2xBT63UP2sghkUoHLIUpWRS8"); CHECK_BAD("$argon2i$"); diff --git a/librecrypt_decompose_chain.c b/librecrypt_decompose_chain.c index 9db1d6c..aa69b85 100644 --- a/librecrypt_decompose_chain.c +++ b/librecrypt_decompose_chain.c @@ -7,6 +7,7 @@ extern inline size_t librecrypt_decompose_chain(char *hash, char **chain_out_arr #else +# ifndef FUZZ #define HASH_1 "a$b" @@ -182,4 +183,37 @@ main(void) } +# else + + +extern volatile size_t discarded_return_value; +volatile size_t discarded_return_value; + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + char **chain, *hash; + size_t chain_size; + if (!size) + return 0; + chain_size = (size_t)*data++; + size -= 1u; + if (chain_size) { + chain = malloc(chain_size * sizeof(*chain)); + assert(chain); + } else { + chain = NULL; + } + hash = malloc(size + 1u); + assert(hash); + memcpy(hash, data, size); + hash[size] = '\0'; + discarded_return_value = librecrypt_decompose_chain(hash, chain, chain_size); + free(hash); + free(chain); + return 0; +} + + +# endif #endif diff --git a/librecrypt_decompose_chain1.c b/librecrypt_decompose_chain1.c index 6fc8a63..a084c13 100644 --- a/librecrypt_decompose_chain1.c +++ b/librecrypt_decompose_chain1.c @@ -7,6 +7,7 @@ extern inline size_t librecrypt_decompose_chain1(char *hash); #else +# ifndef FUZZ #define CHECK(IN, OUT, N)\ @@ -43,4 +44,25 @@ main(void) } +# else + + +extern volatile size_t discarded_return_value; +volatile size_t discarded_return_value; + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + char *hash; + hash = malloc(size + 1u); + assert(hash); + memcpy(hash, data, size); + hash[size] = '\0'; + discarded_return_value = librecrypt_decompose_chain1(hash); + free(hash); + return 0; +} + + +# endif #endif diff --git a/librecrypt_encode.3 b/librecrypt_encode.3 index 95862f8..c38b59a 100644 --- a/librecrypt_encode.3 +++ b/librecrypt_encode.3 @@ -57,10 +57,23 @@ function returns the number of bytes that would have been written to .IR out_buffer , excluding the terminating null byte. +On failure, +.I SIZE_MAX +is returned and +.IR errno +is set to describe the error. .SH ERRORS The .BR librecrypt_encode () +function will fail if: +.TP +.B EOVERFLOW +.I ascii +uses an invalid encoding. + +The +.BR librecrypt_encode () function cannot fail. .SH ATTRIBUTES @@ -81,6 +94,18 @@ T} Async-signal safety AS-Safe .TE .sp +.SH NOTES +The value +.I SIZE_MAX +can be returned on both success and failure. +.I errno +is only modified on failure. For practical +purposes, applications can treat +.I SIZE_MAX +as indicating an +.I ENOMEM +failure. + .SH HISTORY The .BR librecrypt_encode () diff --git a/librecrypt_encode.c b/librecrypt_encode.c index ec371cc..df16895 100644 --- a/librecrypt_encode.c +++ b/librecrypt_encode.c @@ -27,7 +27,12 @@ librecrypt_encode(char *out_buffer, size_t size, const void *binary, size_t len, * 3 bytes (24 bits) requires 4 base-64 characters (24 bits) exactly */ q = len / 3u; r = len % 3u; - n = q * 4u + (!r ? 0u : pad ? 4u : r + 1u); + n = !r ? 0u : pad ? 4u : r + 1u; + if (q > (SIZE_MAX - n) / 4u) { + errno = EOVERFLOW; + return SIZE_MAX; + } + n += q * 4u; /* Just return the encoding length if no output is requested */ if (!size) @@ -126,6 +131,11 @@ librecrypt_encode(char *out_buffer, size_t size, const void *binary, size_t len, NONSTRING static const char lut[256u] = MAKE_ENCODING_LUT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"); +#define phony librecrypt_test_phony__ +extern void *volatile librecrypt_test_phony__; +void *volatile librecrypt_test_phony__ = (void *)(uintptr_t)4096u; + + #define CHECK(BINARY, ASCII)\ check((BINARY), sizeof(BINARY) - 1u, (ASCII), sizeof(ASCII) - 1u) @@ -193,6 +203,23 @@ main(void) CHECK("zy[]y21 !", "enlbXXkyMSAh"); CHECK("{~|~}~~~\x7f\x7f", "e358fn1+fn5/fw"); +#if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wstringop-overflow=" +#endif + + EXPECT(librecrypt_encode(NULL, 0u, phony, (SIZE_MAX - 3u) / 4u * 3u + 1u, lut, '\0') == SIZE_MAX - 1u); + errno = 0; + EXPECT(librecrypt_encode(NULL, 0u, phony, (SIZE_MAX - 3u) / 4u * 3u + 2u, lut, '\0') == SIZE_MAX); + EXPECT(errno == 0); + errno = 0; + EXPECT(librecrypt_encode(NULL, 0u, phony, (SIZE_MAX - 3u) / 4u * 3u + 3u, lut, '\0') == SIZE_MAX); + EXPECT(errno == EOVERFLOW); + +#if defined(__GNUC__) +# pragma GCC diagnostic pop +#endif + STOP_RESOURCE_TEST(); return 0; } diff --git a/librecrypt_hash.3 b/librecrypt_hash.3 index 5bf32ea..9c864fe 100644 --- a/librecrypt_hash.3 +++ b/librecrypt_hash.3 @@ -97,6 +97,9 @@ uses asterisk-encoding to specify random salts. is too large or too small for the selected initial algorithm. .TP +.B EOVERFLOW +The expected return value is greater than {SSIZE_MAX}. +.TP .B ENOMEM Failed to allocate internal scratch memory. .TP diff --git a/librecrypt_hash.c b/librecrypt_hash.c index 69b8dcf..050e0c1 100644 --- a/librecrypt_hash.c +++ b/librecrypt_hash.c @@ -119,11 +119,32 @@ check(const char *phrase, const char *settings, const char *chain, const char *h int main(void) { + char conf[256]; + int r; + SET_UP_ALARM(); INIT_RESOURCE_TEST(); #define GET_SCRATCH_SIZE(HASHLEN) ((HASHLEN) > 64u ? ((HASHLEN) + 63u) & ~31u : (HASHLEN)) #if defined(SUPPORT_ARGON2I) + r = snprintf(conf, sizeof(conf), "$argon2i$m=256,t=8,p=1$AAAABBBBCCCC$*%zu", SIZE_MAX / 4u * 3u + 3u); + assert(r > 0 && (size_t)r < sizeof(conf)); + errno = 0; + EXPECT(librecrypt_hash(NULL, 0u, NULL, 0u, conf, NULL) == -1); +# if SIZE_MAX > UINT32_MAX + EXPECT(errno == EINVAL); +# else + EXPECT(errno == EOVERFLOW); + if (libtest_have_custom_malloc()) { + char buf[1024]; + libtest_pretend_allocation_successful = 1; + errno = 0; + EXPECT(librecrypt_hash(buf, sizeof(buf), NULL, 0u, conf, NULL) == -1); + libtest_pretend_allocation_successful = 0; + EXPECT(errno == EOVERFLOW); + } +# endif + CHECK("password", "$argon2i$" "m=256,t=2,p=1$c29tZXNhbHQ$", 32, 1, "/U3YPXYsSb3q9XxHvc0MLxur+GP960kN9j7emXX8zwY"); CHECK("password", "$argon2i$v=19$m=256,t=2,p=1$c29tZXNhbHQ$", 32, 1, "iekCn0Y3spW+sCcFanM2xBT63UP2sghkUoHLIUpWRS8"); CHECK_BAD("$argon2i$"); diff --git a/librecrypt_hash_.c b/librecrypt_hash_.c index 473b738..cc1ae93 100644 --- a/librecrypt_hash_.c +++ b/librecrypt_hash_.c @@ -142,8 +142,7 @@ next: digit = (size_t)(settings[i] - '0'); if (hash_size > (SIZE_MAX - digit) / 10u) goto einval; - hash_size *= 10u; - hash_size += digit; + hash_size = hash_size * 10u + digit; } if (!hash_size) goto einval; @@ -173,7 +172,9 @@ next: remainder = hash_size % 4u; if (remainder == 1u) goto einval; - hash_size = quotient * 3u + (remainder ? remainder - 1u : 0u); + hash_size = quotient * 3u; + if (remainder) + hash_size += remainder - 1u; } /* For `librecrypt_crypt`: copy hash configurations to output */ @@ -187,6 +188,8 @@ next: if (min) memcpy(out_buffer, settings, min); out_buffer = &out_buffer[min]; + if (ret > SIZE_MAX - prefix) + abort(); /* $covered$ (impossible) */ ret += prefix; } @@ -198,6 +201,7 @@ next: free(phrase_scratches[phrase_scratch_i]); phrase_scratches[phrase_scratch_i] = NULL; phrase_scratch_sizes[phrase_scratch_i] = 0u; + errno = ENOMEM; goto fail; } phrase_scratches[phrase_scratch_i] = new; @@ -233,6 +237,8 @@ next: if (action == BINARY_HASH) { /* Binary output: we already have the has in binary, * so yes add the length to the return value */ + if (ret != 0u) + abort(); /* $covered$ (impossible) */ ret += hash_size; } else if (!size) { /* ASCII hash but not output: just calculate the @@ -244,6 +250,8 @@ next: else ascii_len += 1u; /* 3n+m bytes: 4n+m+1 chars, unless m=0 */ } + if (hash_size / 3u > (SIZE_MAX - ascii_len) / 4u) + goto eoverflow; /* $covered$ (on 32-bit, impossible on wider) */ ascii_len += hash_size / 3u * 4u; goto include_ascii; } else { @@ -252,10 +260,18 @@ next: ascii_len = librecrypt_encode(out_buffer, size, size < hash_size ? phrase_scratches[phrase_scratch_i] : out_buffer, hash_size, algo->encoding_lut, algo->strict_pad ? algo->pad : '\0'); + /* SIZE_MAX could mean success, however we will + * fail when convert `ret` from size_t to ssize_t, + * so we can treat SIZE_MAX as failure even when + * it's a success */ + if (ascii_len == SIZE_MAX) + goto eoverflow; /* $covered$ (manually) */ include_ascii: min = size ? MIN(size - 1u, ascii_len) : 0u; out_buffer = &out_buffer[min]; size -= min; + if (ret > SIZE_MAX - ascii_len) + goto eoverflow; /* $covered$ (on 32-bit) */ ret += ascii_len; } } else { @@ -275,6 +291,8 @@ next: /* For `librecrypt_crypt`: add '>' to the password hash string */ if (action == ASCII_CRYPT) { + if (ret == SIZE_MAX) + abort(); /* $covered$ (impossible) */ ret += 1u; if (size > 1u) { *out_buffer++ = LIBRECRYPT_ALGORITHM_LINK_DELIMITER; @@ -304,8 +322,19 @@ next: if (size && action != BINARY_HASH) out_buffer[0] = '\0'; + if (ret > (size_t)SSIZE_MAX) { + /* $covered{$ (manually) */ + errno = EOVERFLOW; + return -1; + /* $covered}$ */ + } return (ssize_t)ret; + /* $covered{$ (since we have covered gotos to this label) */ +eoverflow: + errno = EOVERFLOW; + goto fail; + /* $covered}$ */ einval: errno = EINVAL; fail: diff --git a/librecrypt_hash_binary.3 b/librecrypt_hash_binary.3 index 720b82d..855906a 100644 --- a/librecrypt_hash_binary.3 +++ b/librecrypt_hash_binary.3 @@ -100,6 +100,9 @@ uses asterisk-encoding to specify random salts. is too large or too small for the selected initial algorithm. .TP +.B EOVERFLOW +The expected return value is greater than {SSIZE_MAX}. +.TP .B ENOMEM Failed to allocate internal scratch memory. .TP diff --git a/librecrypt_next_algorithm.c b/librecrypt_next_algorithm.c index 937a2f8..831f52e 100644 --- a/librecrypt_next_algorithm.c +++ b/librecrypt_next_algorithm.c @@ -7,6 +7,7 @@ extern inline char *librecrypt_next_algorithm(char **hash); #else +# ifndef FUZZ static void @@ -85,4 +86,28 @@ main(void) } +# else + + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + char *hash, *r; + size_t sum = 0u; + hash = malloc(size + 1u); + assert(hash); + memcpy(hash, data, size); + hash[size] = '\0'; + for (;;) { + r = librecrypt_next_algorithm(&hash); + if (!r) + break; + sum += strlen(r) + 1u; + } + EXPECT(sum == size + 1u); + return 0; +} + + +# endif #endif diff --git a/librecrypt_settings_prefix.c b/librecrypt_settings_prefix.c index a2a75f9..0d78c23 100644 --- a/librecrypt_settings_prefix.c +++ b/librecrypt_settings_prefix.c @@ -55,6 +55,7 @@ out: #else +# ifndef FUZZ #define CHECK_NULL(PREFIX, SUFFIX)\ @@ -154,4 +155,24 @@ main(void) } +# else + + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + char *hash; + size_t r; + hash = malloc(size + 1u); + assert(hash); + memcpy(hash, data, size); + hash[size] = '\0'; + r = librecrypt_settings_prefix(hash, &(size_t){0u}); + EXPECT(librecrypt_settings_prefix(hash, NULL) == r); + free(hash); + return 0; +} + + +# endif #endif diff --git a/libtest/common.h b/libtest/common.h index ab59bab..d6557b1 100644 --- a/libtest/common.h +++ b/libtest/common.h @@ -160,6 +160,8 @@ extern struct meminfo libtest_allocs_head; extern struct meminfo libtest_allocs_tail; extern int libtest_allocs_list_inited; extern atomic_flag libtest_allocs_list_spinlock; +extern void *libtest_pretend_list[128]; +extern size_t libtest_npretends; extern _Thread_local int libtest_zero_on_alloc; extern _Thread_local int libtest_expect_zeroed; diff --git a/libtest/globals.c b/libtest/globals.c index e5229a1..6e79402 100644 --- a/libtest/globals.c +++ b/libtest/globals.c @@ -25,10 +25,14 @@ volatile int libtest_mmap_is_custom = -1; volatile int libtest_munmap_is_custom = -1; volatile int libtest_mremap_is_custom = -1; +volatile int libtest_pretend_allocation_successful = 0; + struct meminfo libtest_allocs_head; struct meminfo libtest_allocs_tail; int libtest_allocs_list_inited = 0; atomic_flag libtest_allocs_list_spinlock = ATOMIC_FLAG_INIT; +void *libtest_pretend_list[128]; +size_t libtest_npretends = 0u; _Thread_local int libtest_zero_on_alloc = 0; _Thread_local int libtest_expect_zeroed = 0; diff --git a/libtest/libtest.h b/libtest/libtest.h index e4b4098..6eadd6f 100644 --- a/libtest/libtest.h +++ b/libtest/libtest.h @@ -437,6 +437,8 @@ size_t libtest_get_alloc_failure_in(void); void libtest_set_alloc_failure_in(size_t n); +extern volatile int libtest_pretend_allocation_successful; + extern const unsigned char *volatile libtest_random_pattern; extern volatile size_t libtest_random_pattern_length; extern volatile size_t libtest_random_pattern_offset; diff --git a/libtest/libtest_alloc.c b/libtest/libtest_alloc.c index 96aa132..022881a 100644 --- a/libtest/libtest_alloc.c +++ b/libtest/libtest_alloc.c @@ -53,8 +53,8 @@ mmap_anon(size_t size) } -void * -libtest_alloc(struct meminfo *meminfo) +static void * +try_alloc(struct meminfo *meminfo) { static _Thread_local int recursion_guard = 0; void *base_ptr, *ret_ptr; @@ -206,6 +206,60 @@ libtest_alloc(struct meminfo *meminfo) } +void * +libtest_alloc(struct meminfo *meminfo) +{ + void *ptr; + size_t reqsize; + ptr = try_alloc(meminfo); + if (!ptr && libtest_pretend_allocation_successful) { + reqsize = meminfo->requested_alloc_size; + meminfo->requested_alloc_size = 0u; + ptr = try_alloc(meminfo); + assert(ptr != NULL); + meminfo->requested_alloc_size = reqsize; + GET_MEMINFO(ptr)->requested_alloc_size = reqsize; + SPINLOCK(libtest_allocs_list_spinlock); + if (libtest_npretends >= ELEMSOF(libtest_pretend_list)) + SPINUNLOCK(libtest_allocs_list_spinlock); + assert(libtest_npretends < ELEMSOF(libtest_pretend_list)); + libtest_pretend_list[libtest_npretends++] = ptr; + SPINUNLOCK(libtest_allocs_list_spinlock); + } + return ptr; +} + + +void * +(memset)(void *s, int c, size_t n) +{ + unsigned char *us = s, uc = (unsigned char)c; + size_t i; + + SPINLOCK(libtest_allocs_list_spinlock); + for (i = 0u; i < libtest_npretends; i++) { + if (libtest_pretend_list[i] == s) { + /* We only do this for pointers in the pretend list + * because we must know that it is actually a + * pointer created with libtest_alloc, and not + * mmap(2) or stack-allocated or statically + * allocated buffer; and that's why libtest_pretend_list + * exist instead of being inferred or a flag. */ + if (n > GET_MEMINFO(s)->usable_alloc_size) + n = GET_MEMINFO(s)->usable_alloc_size; + break; + } + } + SPINUNLOCK(libtest_allocs_list_spinlock); + + for (i = 0u; i < n; i++) + us[i] = uc; + + return us; +} + + + #else diff --git a/libtest/libtest_free.c b/libtest/libtest_free.c index 5592e0a..d46218e 100644 --- a/libtest/libtest_free.c +++ b/libtest/libtest_free.c @@ -39,12 +39,18 @@ libtest_free(void *ptr, enum libtest_zero_check zero_checking) assert(mem->origin != FROM_MMAP_ANON); /* Delist allocation */ + SPINLOCK(libtest_allocs_list_spinlock); if (!libtest_kill_malloc_tracking) { - SPINLOCK(libtest_allocs_list_spinlock); mem->prev->next = mem->next; mem->next->prev = mem->prev; - SPINUNLOCK(libtest_allocs_list_spinlock); } + for (i = 0u; i < libtest_npretends; i++) { + if (libtest_pretend_list[i] == ptr) { + libtest_pretend_list[i] = libtest_pretend_list[--libtest_npretends]; + break; + } + } + SPINUNLOCK(libtest_allocs_list_spinlock); /* Check memory is zeroed */ if (zero_checking && libtest_expect_zeroed && !mem->accept_leakage) { diff --git a/libtest/mmap.c b/libtest/mmap.c index c3b3067..3bd3cb3 100644 --- a/libtest/mmap.c +++ b/libtest/mmap.c @@ -8,7 +8,7 @@ #ifdef SYS_mmap2 -# define IF_MMAP2(A) (A) +# define IF_MMAP2(A) do { A; } while (0) #else # define IF_MMAP2(A) ((void)0) #endif |
