Merge branch 'asan'

Enables AddressSanitizer in most CI builds that don't use leak-detective.
For custom builds it can easily be enabled via --enable-asan.
This commit is contained in:
Tobias Brunner
2022-09-16 15:28:16 +02:00
19 changed files with 182 additions and 71 deletions
+7
View File
@@ -0,0 +1,7 @@
leak:EVP_CIPHER_fetch
leak:EVP_KEYEXCH_fetch
leak:EVP_KEYMGMT_fetch
leak:EVP_RAND_fetch
leak:OSSL_DECODER_do_all_provided
leak:OSSL_ENCODER_do_all_provided
leak:OSSL_PROVIDER_load
+27 -1
View File
@@ -1,5 +1,5 @@
#
# Copyright (C) 2007-2017 Tobias Brunner
# Copyright (C) 2007-2022 Tobias Brunner
# Copyright (C) 2006-2022 Andreas Steffen
# Copyright (C) 2006-2014 Martin Willi
#
@@ -327,6 +327,7 @@ ARG_ENABL_SET([tss-trousers], [enable the use of the TrouSerS Trusted Software
ARG_ENABL_SET([tss-tss2], [enable the use of the TSS 2.0 Trusted Software Stack])
# compile options
ARG_ENABL_SET([asan], [enable build with AddressSanitizer (ASan).])
ARG_ENABL_SET([coverage], [enable lcov coverage report generation.])
ARG_ENABL_SET([git-version], [use output of 'git describe' as version information in executables.])
ARG_ENABL_SET([leak-detective], [enable malloc hooks to find memory leaks.])
@@ -1378,6 +1379,27 @@ if test x$fuzzing = xtrue; then
esac
fi
if test x$asan = xtrue; then
# adding this here and not earlier or passed to the script avoids issues
# e.g. with libpthread (libasan provides stubs for its functions but no full
# implementation so configure does not detect that -lpthread is required
# when GCC is used, clang always adds -lpthread)
CFLAGS="$CFLAGS -fsanitize=address -fno-omit-frame-pointer"
# this is necessary so AddressSanitizer can resolve symbols e.g. for
# C++ exceptions that are used in libbotan
if test x$botan = xtrue; then
LDFLAGS="$LDFLAGS -lstdc++"
fi
if test x$openssl = xtrue; then
# we need to suppress some leaks with OpenSSL 3 as we don't deinitialze
# it properly
AC_SUBST(LSAN_OPTIONS, [suppressions=\${abs_top_srcdir}/.lsan.suppressions])
# use this instead of AM_TESTS_ENVIRONMENT as we don't use the parallel
# test harness
AC_SUBST(TESTS_ENVIRONMENT, ['export LSAN_OPTIONS="$(LSAN_OPTIONS)";'])
fi
fi
if test x$ruby_gems = xtrue; then
AC_PATH_PROG([GEM], [gem], [], [$PATH:/bin:/usr/bin:/usr/local/bin])
if test x$GEM = x; then
@@ -1448,9 +1470,13 @@ fi
# modify CFLAGS as needed, do this late so we don't affect configure checks
CFLAGS="$CFLAGS -include $(pwd)/config.h"
AC_MSG_CHECKING([for use of -Werror and additional warnings])
WARN_CFLAGS=
if test x$warnings = xtrue; then
WARN_CFLAGS="-Werror -Wall -Wextra"
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
fi
# disable some warnings, whether explicitly enabled above or by default
# these are not compatible with our custom printf specifiers
+17 -2
View File
@@ -91,12 +91,12 @@ build_tss2()
build_openssl()
{
SSL_REV=3.0.2
SSL_REV=3.0.5
SSL_PKG=openssl-$SSL_REV
SSL_DIR=$DEPS_BUILD_DIR/$SSL_PKG
SSL_SRC=https://www.openssl.org/source/$SSL_PKG.tar.gz
SSL_INS=$DEPS_PREFIX/ssl
SSL_OPT="shared no-tls no-dtls no-ssl3 no-zlib no-comp no-idea no-psk no-srp
SSL_OPT="-d shared no-tls no-dtls no-ssl3 no-zlib no-comp no-idea no-psk no-srp
no-stdio no-tests enable-rfc3779 enable-ec_nistp_64_gcc_128"
if test -d "$SSL_DIR"; then
@@ -471,6 +471,21 @@ CONFIG="$CONFIG
--enable-monolithic=${MONOLITHIC-no}
--enable-leak-detective=${LEAK_DETECTIVE-no}"
case "$TEST" in
coverage|freebsd|fuzzing|sonarcloud|win*)
# don't use AddressSanitizer if it's not available or causes conflicts
CONFIG="$CONFIG --disable-asan"
;;
*)
if [ "$ID" = "ubuntu" -a "$VERSION_ID" = "18.04" ]; then
# the libstdc++ workaround for libbotan doesn't work on Ubuntu 18.04
CONFIG="$CONFIG --disable-asan"
elif [ "$LEAK_DETECTIVE" != "yes" ]; then
CONFIG="$CONFIG --enable-asan"
fi
;;
esac
echo "$ ./autogen.sh"
./autogen.sh || exit $?
echo "$ CC=$CC CFLAGS=\"$CFLAGS\" ./configure $CONFIG"
@@ -1411,7 +1411,7 @@ static void netlink_find_offload_feature(const char *ifname)
.cmd = ETHTOOL_GSSET_INFO,
.sset_mask = 1ULL << ETH_SS_FEATURES,
);
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
strncpy(ifr.ifr_name, ifname, IFNAMSIZ-1);
ifr.ifr_name[IFNAMSIZ-1] = '\0';
ifr.ifr_data = (void*)sset_info;
@@ -1427,7 +1427,7 @@ static void netlink_find_offload_feature(const char *ifname)
.cmd = ETHTOOL_GSTRINGS,
.string_set = ETH_SS_FEATURES,
);
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
strncpy(ifr.ifr_name, ifname, IFNAMSIZ-1);
ifr.ifr_name[IFNAMSIZ-1] = '\0';
ifr.ifr_data = (void*)cmd;
@@ -1486,7 +1486,7 @@ static bool netlink_detect_offload(const char *ifname)
.cmd = ETHTOOL_GFEATURES,
.size = netlink_hw_offload.total_blocks,
);
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
strncpy(ifr.ifr_name, ifname, IFNAMSIZ-1);
ifr.ifr_name[IFNAMSIZ-1] = '\0';
ifr.ifr_data = (void*)cmd;
@@ -1778,8 +1778,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
}
algo->alg_key_len = data->enc_key.len * 8;
algo->alg_icv_len = icv_size;
strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name));
algo->alg_name[sizeof(algo->alg_name) - 1] = '\0';
strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name)-1);
algo->alg_name[sizeof(algo->alg_name)-1] = '\0';
memcpy(algo->alg_key, data->enc_key.ptr, data->enc_key.len);
break;
}
@@ -1805,8 +1805,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
goto failed;
}
algo->alg_key_len = data->enc_key.len * 8;
strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name));
algo->alg_name[sizeof(algo->alg_name) - 1] = '\0';
strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name)-1);
algo->alg_name[sizeof(algo->alg_name)-1] = '\0';
memcpy(algo->alg_key, data->enc_key.ptr, data->enc_key.len);
}
}
@@ -1862,8 +1862,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
}
algo->alg_key_len = data->int_key.len * 8;
algo->alg_trunc_len = trunc_len;
strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name));
algo->alg_name[sizeof(algo->alg_name) - 1] = '\0';
strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name)-1);
algo->alg_name[sizeof(algo->alg_name)-1] = '\0';
memcpy(algo->alg_key, data->int_key.ptr, data->int_key.len);
}
else
@@ -1877,8 +1877,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
goto failed;
}
algo->alg_key_len = data->int_key.len * 8;
strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name));
algo->alg_name[sizeof(algo->alg_name) - 1] = '\0';
strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name)-1);
algo->alg_name[sizeof(algo->alg_name)-1] = '\0';
memcpy(algo->alg_key, data->int_key.ptr, data->int_key.len);
}
}
@@ -1904,8 +1904,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
goto failed;
}
algo->alg_key_len = 0;
strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name));
algo->alg_name[sizeof(algo->alg_name) - 1] = '\0';
strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name)-1);
algo->alg_name[sizeof(algo->alg_name)-1] = '\0';
}
if (data->encap)
@@ -1126,7 +1126,7 @@ static void process_link(private_kernel_netlink_net_t *this,
);
this->ifaces->insert_last(this->ifaces, entry);
}
strncpy(entry->ifname, name, IFNAMSIZ);
strncpy(entry->ifname, name, IFNAMSIZ-1);
entry->ifname[IFNAMSIZ-1] = '\0';
entry->usable = charon->kernel->is_interface_usable(charon->kernel,
name);
@@ -40,7 +40,7 @@ install-exec-local: dist/vici-$(PYTHON_PACKAGE_VERSION)-py$(PYTHON_VERSION).egg
endif
if USE_TOX
TESTS_ENVIRONMENT = export TOX=$(TOX);
TESTS_ENVIRONMENT += export TOX=$(TOX);
AM_TESTS_FD_REDIRECT = 1>&2
TESTS = tox.sh
endif
+8 -2
View File
@@ -449,7 +449,10 @@ METHOD(ike_rekey_t, collide, bool,
"ignore");
break;
}
DESTROY_IF(&this->collision->public.task);
if (this->collision)
{
this->collision->public.task.destroy(&this->collision->public.task);
}
this->collision = rekey;
return TRUE;
}
@@ -478,7 +481,10 @@ static void cleanup(private_ike_rekey_t *this)
cur_sa = charon->bus->get_sa(charon->bus);
DESTROY_IF(this->new_sa);
charon->bus->set_sa(charon->bus, cur_sa);
DESTROY_IF(&this->collision->public.task);
if (this->collision)
{
this->collision->public.task.destroy(&this->collision->public.task);
}
}
METHOD(task_t, migrate, void,
@@ -22,7 +22,7 @@
#include <bio/bio_reader.h>
#include <bio/bio_writer.h>
/**
/*
* FIXME: Since we don't have the server side yet, this is kind of a hack!!!
*/
@@ -37,15 +37,18 @@ static bool add_notify(listener_t *listener, ike_sa_t *ike_sa,
{
message->add_notify(message, FALSE, IKEV2_MESSAGE_ID_SYNC_SUPPORTED,
chunk_empty);
free(listener);
return FALSE;
}
return TRUE;
}
#define add_notify_to_ike_auth() ({ \
listener_t _notify_listener = { \
listener_t *_notify_listener; \
INIT(_notify_listener, \
.message = add_notify, \
}; \
exchange_test_helper->add_listener(exchange_test_helper, &_notify_listener); \
); \
exchange_test_helper->add_listener(exchange_test_helper, _notify_listener); \
})
/**
@@ -178,6 +178,8 @@ bool exchange_test_asserts_message(listener_t *listener, ike_sa_t *ike_sa,
assert_message_rule(this, message, &this->rules[i]);
}
}
free(this->rules);
free(this);
return FALSE;
}
return TRUE;
@@ -350,16 +350,18 @@ bool exchange_test_asserts_message(listener_t *this, ike_sa_t *ike_sa,
#define _assert_payload(dir, c, ...) ({ \
listener_message_rule_t _rules[] = { __VA_ARGS__ }; \
listener_message_assert_t _listener = { \
listener_message_assert_t *_listener; \
INIT(_listener, \
.listener = { .message = exchange_test_asserts_message, }, \
.file = __FILE__, \
.line = __LINE__, \
.incoming = streq(dir, "IN") ? TRUE : FALSE, \
.count = c, \
.rules = _rules, \
.rules = malloc(sizeof(_rules)), \
.num_rules = countof(_rules), \
}; \
exchange_test_helper->add_listener(exchange_test_helper, &_listener.listener); \
); \
memcpy(_listener->rules, _rules, sizeof(_rules)); \
exchange_test_helper->add_listener(exchange_test_helper, &_listener->listener); \
})
/**
+1 -17
View File
@@ -199,25 +199,9 @@ TESTS = imcv_tests
check_PROGRAMS = $(TESTS)
imcv_tests_SOURCES = \
ita/ita_attr_command.c \
pa_tnc/pa_tnc_attr_manager.c \
seg/seg_env.c seg/seg_contract.c \
seg/seg_contract_manager.c \
swid_gen/swid_gen.c \
swima/swima_data_model.c \
swima/swima_event.c \
swima/swima_events.c \
swima/swima_record.c \
swima/swima_inventory.c \
swima/swima_collector.c \
suites/test_imcv_seg.c \
suites/test_imcv_swima.c \
ietf/ietf_attr_pa_tnc_error.c \
ietf/swima/ietf_swima_attr_req.c \
ietf/swima/ietf_swima_attr_sw_inv.c \
ietf/swima/ietf_swima_attr_sw_ev.c \
tcg/seg/tcg_seg_attr_seg_env.c \
imcv.c imcv_tests.h imcv_tests.c
imcv_tests.h imcv_tests.c
imcv_tests_CFLAGS = \
-I$(top_srcdir)/src/libimcv \
+2 -2
View File
@@ -432,7 +432,7 @@ static bool init_tun(private_tun_device_t *this, const char *name_tmpl)
}
/* get a control identifier for the utun kernel extension */
strncpy(info.ctl_name, UTUN_CONTROL_NAME, strlen(UTUN_CONTROL_NAME));
strncpy(info.ctl_name, UTUN_CONTROL_NAME, sizeof(info.ctl_name)-1);
if (ioctl(this->tunfd, CTLIOCGINFO, &info) < 0)
{
DBG1(DBG_LIB, "failed to ioctl tundevice: %s", strerror(errno));
@@ -466,7 +466,7 @@ static bool init_tun(private_tun_device_t *this, const char *name_tmpl)
struct ifreq ifr;
strncpy(this->if_name, name_tmpl ?: "tun%d", IFNAMSIZ);
strncpy(this->if_name, name_tmpl ?: "tun%d", IFNAMSIZ-1);
this->if_name[IFNAMSIZ-1] = '\0';
this->tunfd = open("/dev/net/tun", O_RDWR);
+3 -1
View File
@@ -142,9 +142,11 @@ static __m128i _mm_shuffle_i01(__m128i a, __m128i b)
static void expand192(__m128i *key, __m128i *schedule)
{
__m128i t1, t2, t3;
u_char buf[16] = {};
schedule[0] = t1 = _mm_loadu_si128(key);
t2 = t3 = _mm_loadu_si128(key + 1);
memcpy(buf, key + 1, 8);
t2 = t3 = _mm_loadu_si128((__m128i*)buf);
t2 = assist192(_mm_aeskeygenassist_si128(t2, 0x1), t2, &t1);
schedule[1] = _mm_shuffle_i00(t3, t1);
@@ -45,7 +45,7 @@ struct private_gcrypt_crypter_t {
/**
* are we using counter mode?
*/
bool ctr_mode;
int mode;
/**
* counter state
@@ -62,13 +62,17 @@ struct private_gcrypt_crypter_t {
*/
static bool set_iv(private_gcrypt_crypter_t *this, chunk_t iv)
{
if (this->ctr_mode)
if (this->mode == GCRY_CIPHER_MODE_CTR)
{
memcpy(this->ctr.iv, iv.ptr, sizeof(this->ctr.iv));
this->ctr.counter = htonl(1);
return gcry_cipher_setctr(this->h, &this->ctr, sizeof(this->ctr)) == 0;
}
return gcry_cipher_setiv(this->h, iv.ptr, iv.len) == 0;
if (iv.len)
{
return gcry_cipher_setiv(this->h, iv.ptr, iv.len) == 0;
}
return TRUE;
}
METHOD(crypter_t, decrypt, bool,
@@ -108,7 +112,7 @@ METHOD(crypter_t, get_block_size, size_t,
{
size_t len = 0;
if (this->ctr_mode)
if (this->mode == GCRY_CIPHER_MODE_CTR)
{ /* counter mode does not need any padding */
return 1;
}
@@ -121,9 +125,14 @@ METHOD(crypter_t, get_iv_size, size_t,
{
size_t len = 0;
if (this->ctr_mode)
switch (this->mode)
{
return sizeof(this->ctr.iv);
case GCRY_CIPHER_MODE_CTR:
return sizeof(this->ctr.iv);
case GCRY_CIPHER_MODE_ECB:
return 0;
default:
break;
}
gcry_cipher_algo_info(this->alg, GCRYCTL_GET_BLKLEN, NULL, &len);
return len;
@@ -135,7 +144,7 @@ METHOD(crypter_t, get_key_size, size_t,
size_t len = 0;
gcry_cipher_algo_info(this->alg, GCRYCTL_GET_KEYLEN, NULL, &len);
if (this->ctr_mode)
if (this->mode == GCRY_CIPHER_MODE_CTR)
{
return len + sizeof(this->ctr.nonce);
}
@@ -145,7 +154,7 @@ METHOD(crypter_t, get_key_size, size_t,
METHOD(crypter_t, set_key, bool,
private_gcrypt_crypter_t *this, chunk_t key)
{
if (this->ctr_mode)
if (this->mode == GCRY_CIPHER_MODE_CTR)
{
/* last 4 bytes are the nonce */
memcpy(this->ctr.nonce, key.ptr + key.len - sizeof(this->ctr.nonce),
@@ -308,7 +317,7 @@ gcrypt_crypter_t *gcrypt_crypter_create(encryption_algorithm_t algo,
},
},
.alg = gcrypt_alg,
.ctr_mode = mode == GCRY_CIPHER_MODE_CTR,
.mode = mode,
);
err = gcry_cipher_open(&this->h, gcrypt_alg, mode, 0);
+40 -13
View File
@@ -125,12 +125,27 @@ END_TEST
* clear
*/
ADDRESS_SANITIZER_EXCLUDE
static bool cleared(u_char *ptr)
{
int i;
for (i = 0; i < 64; i += 2)
{
if (ptr[i] != 0 && ptr[i] == i &&
ptr[i+1] != 0 && ptr[i+1] == i+1)
{
return FALSE;
}
}
return TRUE;
}
START_TEST(test_chunk_clear)
{
chunk_t chunk;
u_char *ptr;
int i;
bool cleared = TRUE;
chunk = chunk_empty;
chunk_clear(&chunk);
@@ -147,17 +162,8 @@ START_TEST(test_chunk_clear)
* test directly, as it might allocate data at the freed area. comparing
* two bytes at once reduces the chances of conflicts if memory got
* overwritten already */
for (i = 0; i < 64; i += 2)
{
if (ptr[i] != 0 && ptr[i] == i &&
ptr[i+1] != 0 && ptr[i+1] == i+1)
{
cleared = FALSE;
break;
}
}
ck_assert(cleared(ptr));
assert_chunk_empty(chunk);
ck_assert(cleared);
}
END_TEST
@@ -199,6 +205,27 @@ END_TEST
* chunk_create_cat
*/
ADDRESS_SANITIZER_EXCLUDE
bool chunk_equals_nosan(chunk_t a, chunk_t b)
{
int i;
/* cant use memcmp() or any function using it, as that is again
* sanitize-checked */
if (a.len != b.len)
{
return FALSE;
}
for (i = 0; i < b.len; i++)
{
if (a.ptr[i] != b.ptr[i])
{
return FALSE;
}
}
return TRUE;
}
START_TEST(test_chunk_create_cat)
{
chunk_t foo, bar;
@@ -236,8 +263,8 @@ START_TEST(test_chunk_create_cat)
ck_assert_int_eq(c.len, 6);
ck_assert(chunk_equals(c, chunk_from_str("foobar")));
/* check memory area of cleared chunk */
ck_assert(!chunk_equals(foo, chunk_create(ptra, 3)));
ck_assert(!chunk_equals(bar, chunk_create(ptrb, 3)));
ck_assert(!chunk_equals_nosan(foo, chunk_create(ptra, 3)));
ck_assert(!chunk_equals_nosan(bar, chunk_create(ptrb, 3)));
}
END_TEST
@@ -1214,6 +1214,8 @@ START_TEST(test_cancel_point)
}
END_TEST
/* not sure why AddressSanitizer complains here, pointer looks fine */
ADDRESS_SANITIZER_EXCLUDE
static void close_fd_ptr(void *fd)
{
close(*(int*)fd);
@@ -1253,6 +1255,8 @@ static void cancellation_read()
}
}
/* the AddressSaniziter complains about the fd_set here for some reason */
ADDRESS_SANITIZER_EXCLUDE
static void cancellation_select()
{
int sv[2];
+2
View File
@@ -50,6 +50,7 @@ static void destroy_case(test_case_t *tcase)
{
array_destroy(tcase->functions);
array_destroy(tcase->fixtures);
free(tcase);
}
/**
@@ -738,6 +739,7 @@ static bool run_case(test_case_t *tcase, test_runner_init_t init, char *cfg,
array_destroy(failures);
array_destroy(warnings);
DESTROY_IF(iterations);
free(times);
return passed == array_count(tcase->functions);
}
+17
View File
@@ -112,6 +112,23 @@ void utils_deinit();
#define BUILD_ASSERT_ARRAY(a) \
BUILD_ASSERT(!__builtin_types_compatible_p(typeof(a), typeof(&(a)[0])))
/**
* LLVM/Clang __has_feature support
*/
#ifndef __has_feature
# define __has_feature(x) 0
#endif
/**
* Address santizer support
*/
#if __has_feature(address_sanitizer) || \
(defined(__GNUC__) && defined(__SANITIZE_ADDRESS__))
# define ADDRESS_SANITIZER_EXCLUDE __attribute__((no_sanitize_address))
#else
# define ADDRESS_SANITIZER_EXCLUDE
#endif
/**
* Debug macro to follow control flow
*/
+6 -1
View File
@@ -647,6 +647,11 @@ static void run_echo_client(echo_server_config_t *config)
server->destroy(server);
}
/**
* Data for echo test
*/
static chunk_t echo_data = chunk_from_chars(0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08);
/**
* Create server/peer configuration
*/
@@ -660,7 +665,7 @@ static echo_server_config_t *create_config(tls_version_t version, uint16_t port,
.addr = "127.0.0.1",
.port = port,
.cauth = cauth,
.data = chunk_from_chars(0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08),
.data = echo_data,
);
return config;
}